Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 31 Oct 2011 23:14:20 +0000 (16:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 31 Oct 2011 23:14:20 +0000 (16:14 -0700)
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: (54 commits)
  [S390] Remove error checking from copy_oldmem_page()
  [S390] qdio: prevent dsci access without adapter interrupts
  [S390] irqstats: split IPI interrupt accounting
  [S390] add missing __tlb_flush_global() for !CONFIG_SMP
  [S390] sparse: fix sparse symbol shadow warning
  [S390] sparse: fix sparse NULL pointer warnings
  [S390] sparse: fix sparse warnings with __user pointers
  [S390] sparse: fix sparse warnings in math-emu
  [S390] sparse: fix sparse warnings about missing prototypes
  [S390] sparse: fix sparse ANSI-C warnings
  [S390] sparse: fix sparse static warnings
  [S390] sparse: fix access past end of array warnings
  [S390] dasd: prevent path verification before resume
  [S390] qdio: remove multicast polling
  [S390] qdio: reset outbound SBAL error states
  [S390] qdio: EQBS retry after CCQ 96
  [S390] qdio: add timestamp for last queue scan time
  [S390] Introduce get_clock_fast()
  [S390] kvm: Handle diagnose 0x10 (release pages)
  [S390] take mmap_sem when walking guest page table
  ...

775 files changed:
Documentation/ABI/testing/debugfs-ideapad [new file with mode: 0644]
Documentation/ABI/testing/sysfs-platform-ideapad-laptop
Documentation/DocBook/media/dvb/dvbproperty.xml
Documentation/DocBook/media/dvb/intro.xml
Documentation/DocBook/media/v4l/compat.xml
Documentation/DocBook/media/v4l/dev-subdev.xml
Documentation/DocBook/media/v4l/v4l2.xml
Documentation/DocBook/media/v4l/vidioc-dqevent.xml
Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
Documentation/dvb/get_dvb_firmware
Documentation/dvb/it9137.txt [new file with mode: 0644]
Documentation/fb/udlfb.txt
Documentation/feature-removal-schedule.txt
Documentation/i2c/smbus-protocol
Documentation/kernel-parameters.txt
Documentation/networking/LICENSE.qlcnic
Documentation/video4linux/CARDLIST.tm6000 [new file with mode: 0644]
Documentation/video4linux/gspca.txt
Documentation/video4linux/omap3isp.txt
Documentation/video4linux/v4l2-controls.txt
Documentation/virtual/kvm/api.txt
MAINTAINERS
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-am3517evm.c
arch/arm/mach-omap2/board-apollon.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-omap3stalker.c
arch/arm/mach-omap2/board-omap3touchbook.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-rx51.c
arch/arm/mach-omap2/display.c
arch/arm/mach-omap2/iommu2.c
arch/arm/mach-omap2/twl-common.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/include/plat/iommu.h
arch/arm/plat-omap/include/plat/iommu2.h
arch/arm/plat-omap/include/plat/iopgtable.h [new file with mode: 0644]
arch/arm/plat-omap/include/plat/iovmm.h
arch/arm/plat-omap/iommu-debug.c [deleted file]
arch/arm/plat-omap/iommu.c [deleted file]
arch/arm/plat-omap/iopgtable.h [deleted file]
arch/arm/plat-omap/iovmm.c [deleted file]
arch/ia64/kvm/kvm-ia64.c
arch/microblaze/include/asm/dma-mapping.h
arch/microblaze/include/asm/elf.h
arch/microblaze/include/asm/system.h
arch/microblaze/include/asm/uaccess.h
arch/microblaze/kernel/cpu/cpuinfo.c
arch/microblaze/kernel/dma.c
arch/microblaze/kernel/exceptions.c
arch/microblaze/kernel/process.c
arch/microblaze/kernel/ptrace.c
arch/microblaze/kernel/timer.c
arch/microblaze/lib/Makefile
arch/microblaze/lib/uaccess_old.S
arch/microblaze/lib/ucmpdi2.c [new file with mode: 0644]
arch/powerpc/include/asm/kvm.h
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/include/asm/kvm_book3s_asm.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kvm/44x.c
arch/powerpc/kvm/Makefile
arch/powerpc/kvm/book3s_32_sr.S
arch/powerpc/kvm/book3s_64_mmu.c
arch/powerpc/kvm/book3s_64_slb.S
arch/powerpc/kvm/book3s_emulate.c
arch/powerpc/kvm/book3s_exports.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_rm_mmu.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_interrupts.S
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/book3s_pr_papr.c [new file with mode: 0644]
arch/powerpc/kvm/book3s_rmhandlers.S
arch/powerpc/kvm/book3s_segment.S
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/e500.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/platforms/512x/mpc512x_shared.c
arch/powerpc/platforms/85xx/p1022_ds.c
arch/powerpc/platforms/86xx/mpc8610_hpcd.c
arch/powerpc/sysdev/fsl_soc.h
arch/s390/include/asm/kvm_host.h
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/sigp.c
arch/sparc/kernel/visemul.c
arch/sparc/lib/memcpy.S
arch/x86/include/asm/apicdef.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/kvm_emulate.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/vmx.h
arch/x86/kvm/emulate.c
arch/x86/kvm/i8254.c
arch/x86/kvm/i8259.c
arch/x86/kvm/irq.h
arch/x86/kvm/kvm_cache_regs.h
arch/x86/kvm/kvm_timer.h
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h
arch/x86/kvm/mmu.c
arch/x86/kvm/mmu_audit.c
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/svm.c
arch/x86/kvm/trace.h
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
drivers/edac/amd64_edac.c
drivers/edac/mce_amd.c
drivers/edac/mce_amd.h
drivers/i2c/algos/i2c-algo-bit.c
drivers/i2c/algos/i2c-algo-pca.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/scx200_acb.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/ati_remote.c [deleted file]
drivers/iommu/Kconfig
drivers/iommu/Makefile
drivers/iommu/amd_iommu.c
drivers/iommu/intel-iommu.c
drivers/iommu/iommu.c
drivers/iommu/msm_iommu.c
drivers/iommu/omap-iommu-debug.c [new file with mode: 0644]
drivers/iommu/omap-iommu.c [new file with mode: 0644]
drivers/iommu/omap-iovmm.c [new file with mode: 0644]
drivers/md/raid10.c
drivers/media/common/saa7146_core.c
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_hlp.c
drivers/media/common/saa7146_i2c.c
drivers/media/common/saa7146_vbi.c
drivers/media/common/saa7146_video.c
drivers/media/common/tuners/Makefile
drivers/media/common/tuners/mt20xx.c
drivers/media/common/tuners/mxl5005s.c
drivers/media/common/tuners/tda18212.c
drivers/media/common/tuners/tda18212_priv.h [deleted file]
drivers/media/common/tuners/tda18271-common.c
drivers/media/common/tuners/tda18271-fe.c
drivers/media/common/tuners/tda18271-priv.h
drivers/media/common/tuners/tda827x.c
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/common/tuners/tuner-xc2028.h
drivers/media/dvb/b2c2/Makefile
drivers/media/dvb/bt8xx/Makefile
drivers/media/dvb/ddbridge/Makefile
drivers/media/dvb/ddbridge/ddbridge-core.c
drivers/media/dvb/dm1105/Makefile
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/a800.c
drivers/media/dvb/dvb-usb/af9005-fe.c
drivers/media/dvb/dvb-usb/af9005.c
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/anysee.h
drivers/media/dvb/dvb-usb/au6610.c
drivers/media/dvb/dvb-usb/az6027.c
drivers/media/dvb/dvb-usb/ce6230.c
drivers/media/dvb/dvb-usb/cinergyT2-core.c
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/dibusb-mb.c
drivers/media/dvb/dvb-usb/dibusb-mc.c
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/dtt200u.c
drivers/media/dvb/dvb-usb/dtv5100.c
drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb-init.c
drivers/media/dvb/dvb-usb/dvb-usb-urb.c
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/dvb-usb/ec168.c
drivers/media/dvb/dvb-usb/friio.c
drivers/media/dvb/dvb-usb/gl861.c
drivers/media/dvb/dvb-usb/gp8psk-fe.c
drivers/media/dvb/dvb-usb/gp8psk.c
drivers/media/dvb/dvb-usb/it913x.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/lmedm04.c
drivers/media/dvb/dvb-usb/m920x.c
drivers/media/dvb/dvb-usb/mxl111sf-gpio.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/mxl111sf-gpio.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/mxl111sf-i2c.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/mxl111sf-i2c.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/mxl111sf-phy.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/mxl111sf-phy.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/mxl111sf-reg.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/mxl111sf-tuner.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/mxl111sf-tuner.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/mxl111sf.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/mxl111sf.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/nova-t-usb2.c
drivers/media/dvb/dvb-usb/opera1.c
drivers/media/dvb/dvb-usb/pctv452e.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/technisat-usb2.c
drivers/media/dvb/dvb-usb/ttusb2.c
drivers/media/dvb/dvb-usb/umt-010.c
drivers/media/dvb/dvb-usb/usb-urb.c
drivers/media/dvb/dvb-usb/vp702x.c
drivers/media/dvb/dvb-usb/vp7045.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/a8293.c [new file with mode: 0644]
drivers/media/dvb/frontends/a8293.h [new file with mode: 0644]
drivers/media/dvb/frontends/cxd2820r.h
drivers/media/dvb/frontends/cxd2820r_c.c
drivers/media/dvb/frontends/cxd2820r_core.c
drivers/media/dvb/frontends/cxd2820r_priv.h
drivers/media/dvb/frontends/cxd2820r_t.c
drivers/media/dvb/frontends/cxd2820r_t2.c
drivers/media/dvb/frontends/dib0070.c
drivers/media/dvb/frontends/dib0090.c
drivers/media/dvb/frontends/dib7000m.c
drivers/media/dvb/frontends/dib7000p.c
drivers/media/dvb/frontends/dib8000.c
drivers/media/dvb/frontends/dib9000.c
drivers/media/dvb/frontends/dibx000_common.c
drivers/media/dvb/frontends/dibx000_common.h
drivers/media/dvb/frontends/drxd_hard.c
drivers/media/dvb/frontends/drxk_hard.c
drivers/media/dvb/frontends/it913x-fe-priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/it913x-fe.c [new file with mode: 0644]
drivers/media/dvb/frontends/it913x-fe.h [new file with mode: 0644]
drivers/media/dvb/frontends/lnbp22.c [new file with mode: 0644]
drivers/media/dvb/frontends/lnbp22.h [new file with mode: 0644]
drivers/media/dvb/frontends/stb0899_algo.c
drivers/media/dvb/frontends/stb0899_drv.c
drivers/media/dvb/frontends/stv0288.c
drivers/media/dvb/frontends/stv090x.c
drivers/media/dvb/frontends/tda10048.c
drivers/media/dvb/frontends/tda10048.h
drivers/media/dvb/frontends/tda10071.c [new file with mode: 0644]
drivers/media/dvb/frontends/tda10071.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda10071_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda18271c2dd.c
drivers/media/dvb/mantis/Makefile
drivers/media/dvb/mantis/hopper_cards.c
drivers/media/dvb/mantis/mantis_cards.c
drivers/media/dvb/mantis/mantis_common.h
drivers/media/dvb/mantis/mantis_dma.c
drivers/media/dvb/mantis/mantis_vp1041.c
drivers/media/dvb/ngene/Makefile
drivers/media/dvb/pluto2/Makefile
drivers/media/dvb/pt1/Makefile
drivers/media/dvb/siano/Makefile
drivers/media/dvb/ttpci/Makefile
drivers/media/dvb/ttpci/av7110_v4l.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.h
drivers/media/dvb/ttpci/ttpci-eeprom.c
drivers/media/dvb/ttpci/ttpci-eeprom.h
drivers/media/dvb/ttusb-budget/Makefile
drivers/media/dvb/ttusb-dec/Makefile
drivers/media/radio/Makefile
drivers/media/radio/radio-si4713.c
drivers/media/radio/radio-wl1273.c
drivers/media/radio/si470x/radio-si470x-usb.c
drivers/media/radio/wl128x/fmdrv_v4l2.c
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/ati_remote.c [new file with mode: 0644]
drivers/media/rc/ene_ir.c
drivers/media/rc/ene_ir.h
drivers/media/rc/imon.c
drivers/media/rc/ir-lirc-codec.c
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-ati-x10.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-medion-x10.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
drivers/media/rc/keymaps/rc-snapstream-firefly.c [new file with mode: 0644]
drivers/media/rc/mceusb.c
drivers/media/rc/rc-core-priv.h
drivers/media/rc/rc-main.c
drivers/media/rc/redrat3.c
drivers/media/rc/winbond-cir.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adp1653.c
drivers/media/video/adv7175.c
drivers/media/video/atmel-isi.c
drivers/media/video/au0828/Makefile
drivers/media/video/bt819.c
drivers/media/video/bt8xx/Makefile
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-gpio.c
drivers/media/video/bt8xx/bttv-i2c.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/bt8xx/bttv-risc.c
drivers/media/video/bt8xx/bttv-vbi.c
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/cx18/Makefile
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-mailbox.c
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx231xx/Makefile
drivers/media/video/cx23885/Kconfig
drivers/media/video/cx23885/Makefile
drivers/media/video/cx23885/cx23885-alsa.c [new file with mode: 0644]
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-i2c.c
drivers/media/video/cx23885/cx23885-reg.h
drivers/media/video/cx23885/cx23885-vbi.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx23885/cx23888-ir.c
drivers/media/video/cx25840/Makefile
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-ir.c
drivers/media/video/cx88/Makefile
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/davinci/vpbe_display.c
drivers/media/video/davinci/vpbe_osd.c
drivers/media/video/em28xx/Kconfig
drivers/media/video/em28xx/Makefile
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/et61x251/et61x251.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/et61x251/et61x251_tas5130d1b.c
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/benq.c
drivers/media/video/gspca/conex.c
drivers/media/video/gspca/cpia1.c
drivers/media/video/gspca/etoms.c
drivers/media/video/gspca/finepix.c
drivers/media/video/gspca/gl860/Makefile
drivers/media/video/gspca/gl860/gl860.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/jeilinj.c
drivers/media/video/gspca/kinect.c
drivers/media/video/gspca/konica.c
drivers/media/video/gspca/m5602/Makefile
drivers/media/video/gspca/m5602/m5602_core.c
drivers/media/video/gspca/m5602/m5602_mt9m111.c
drivers/media/video/gspca/m5602/m5602_ov7660.c
drivers/media/video/gspca/m5602/m5602_ov9650.c
drivers/media/video/gspca/m5602/m5602_po1030.c
drivers/media/video/gspca/m5602/m5602_s5k4aa.c
drivers/media/video/gspca/m5602/m5602_s5k83a.c
drivers/media/video/gspca/mars.c
drivers/media/video/gspca/mr97310a.c
drivers/media/video/gspca/nw80x.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/ov534.c
drivers/media/video/gspca/ov534_9.c
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/pac7302.c
drivers/media/video/gspca/pac7311.c
drivers/media/video/gspca/se401.c
drivers/media/video/gspca/sn9c2028.c
drivers/media/video/gspca/sn9c20x.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca1528.c
drivers/media/video/gspca/spca500.c
drivers/media/video/gspca/spca501.c
drivers/media/video/gspca/spca505.c
drivers/media/video/gspca/spca508.c
drivers/media/video/gspca/spca561.c
drivers/media/video/gspca/sq905.c
drivers/media/video/gspca/sq905c.c
drivers/media/video/gspca/sq930x.c
drivers/media/video/gspca/stk014.c
drivers/media/video/gspca/stv0680.c
drivers/media/video/gspca/stv06xx/Makefile
drivers/media/video/gspca/stv06xx/stv06xx.c
drivers/media/video/gspca/stv06xx/stv06xx.h
drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/topro.c [new file with mode: 0644]
drivers/media/video/gspca/vc032x.c
drivers/media/video/gspca/vicam.c
drivers/media/video/gspca/w996Xcf.c
drivers/media/video/gspca/xirlink_cit.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/hdpvr/Makefile
drivers/media/video/hexium_gemini.c
drivers/media/video/hexium_orion.c
drivers/media/video/ivtv/Makefile
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/m5mols/m5mols_core.c
drivers/media/video/marvell-ccic/mcam-core.c
drivers/media/video/marvell-ccic/mmp-driver.c
drivers/media/video/mem2mem_testdev.c
drivers/media/video/msp3400-driver.c
drivers/media/video/msp3400-driver.h
drivers/media/video/msp3400-kthreads.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9p031.c [new file with mode: 0644]
drivers/media/video/mt9t001.c [new file with mode: 0644]
drivers/media/video/mx3_camera.c
drivers/media/video/mxb.c
drivers/media/video/noon010pc30.c
drivers/media/video/omap/omap_vout.c
drivers/media/video/omap3isp/Makefile
drivers/media/video/omap3isp/isp.c
drivers/media/video/omap3isp/isp.h
drivers/media/video/omap3isp/ispccdc.c
drivers/media/video/omap3isp/ispccp2.c
drivers/media/video/omap3isp/ispqueue.c
drivers/media/video/omap3isp/ispstat.c
drivers/media/video/omap3isp/ispvideo.c
drivers/media/video/pvrusb2/Makefile
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-hdw.h
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/s5p-fimc/Makefile
drivers/media/video/s5p-fimc/fimc-capture.c
drivers/media/video/s5p-fimc/fimc-core.c
drivers/media/video/s5p-fimc/fimc-core.h
drivers/media/video/s5p-fimc/fimc-mdevice.c [new file with mode: 0644]
drivers/media/video/s5p-fimc/fimc-mdevice.h [new file with mode: 0644]
drivers/media/video/s5p-fimc/fimc-reg.c
drivers/media/video/s5p-fimc/mipi-csis.c
drivers/media/video/s5p-fimc/regs-fimc.h
drivers/media/video/s5p-mfc/s5p_mfc.c
drivers/media/video/s5p-mfc/s5p_mfc_dec.c
drivers/media/video/s5p-mfc/s5p_mfc_enc.c
drivers/media/video/s5p-mfc/s5p_mfc_opr.c
drivers/media/video/s5p-tv/Kconfig
drivers/media/video/s5p-tv/hdmi_drv.c
drivers/media/video/s5p-tv/mixer.h
drivers/media/video/s5p-tv/mixer_grp_layer.c
drivers/media/video/s5p-tv/mixer_reg.c
drivers/media/video/s5p-tv/mixer_video.c
drivers/media/video/s5p-tv/mixer_vp_layer.c
drivers/media/video/s5p-tv/regs-hdmi.h
drivers/media/video/s5p-tv/regs-mixer.h
drivers/media/video/s5p-tv/sdo_drv.c
drivers/media/video/saa7115.c
drivers/media/video/saa7134/Makefile
drivers/media/video/saa7164/Makefile
drivers/media/video/saa7164/saa7164-cards.c
drivers/media/video/saa7164/saa7164-dvb.c
drivers/media/video/saa7164/saa7164.h
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sr030pc30.c
drivers/media/video/stk-webcam.c
drivers/media/video/tlg2300/Makefile
drivers/media/video/tm6000/Kconfig [new file with mode: 0644]
drivers/media/video/tm6000/Makefile [new file with mode: 0644]
drivers/media/video/tm6000/tm6000-alsa.c [new file with mode: 0644]
drivers/media/video/tm6000/tm6000-cards.c [new file with mode: 0644]
drivers/media/video/tm6000/tm6000-core.c [new file with mode: 0644]
drivers/media/video/tm6000/tm6000-dvb.c [new file with mode: 0644]
drivers/media/video/tm6000/tm6000-i2c.c [new file with mode: 0644]
drivers/media/video/tm6000/tm6000-input.c [new file with mode: 0644]
drivers/media/video/tm6000/tm6000-regs.h [new file with mode: 0644]
drivers/media/video/tm6000/tm6000-stds.c [new file with mode: 0644]
drivers/media/video/tm6000/tm6000-usb-isoc.h [new file with mode: 0644]
drivers/media/video/tm6000/tm6000-video.c [new file with mode: 0644]
drivers/media/video/tm6000/tm6000.h [new file with mode: 0644]
drivers/media/video/tvaudio.c
drivers/media/video/tvp5150_reg.h
drivers/media/video/tvp7002.c
drivers/media/video/usbvision/Makefile
drivers/media/video/uvc/uvc_driver.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-ctrls.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/v4l2-mem2mem.c
drivers/media/video/v4l2-subdev.c
drivers/media/video/videobuf2-core.c
drivers/media/video/videobuf2-dma-contig.c
drivers/media/video/videobuf2-dma-sg.c
drivers/media/video/videobuf2-memops.c
drivers/media/video/vivi.c
drivers/media/video/vpx3220.c
drivers/media/video/zr364xx.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/altera-stapl/Kconfig [new file with mode: 0644]
drivers/misc/altera-stapl/Makefile [new file with mode: 0644]
drivers/misc/altera-stapl/altera-comp.c [new file with mode: 0644]
drivers/misc/altera-stapl/altera-exprt.h [new file with mode: 0644]
drivers/misc/altera-stapl/altera-jtag.c [new file with mode: 0644]
drivers/misc/altera-stapl/altera-jtag.h [new file with mode: 0644]
drivers/misc/altera-stapl/altera-lpt.c [new file with mode: 0644]
drivers/misc/altera-stapl/altera.c [new file with mode: 0644]
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bonding.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/i825xx/Kconfig
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/descs.h
drivers/net/ethernet/stmicro/stmmac/norm_desc.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/platform/x86/Kconfig
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/hp_accel.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_scu_ipcutil.c
drivers/platform/x86/samsung-laptop.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/topstar-laptop.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/wmi.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/altera-stapl/Kconfig [deleted file]
drivers/staging/altera-stapl/Makefile [deleted file]
drivers/staging/altera-stapl/altera-comp.c [deleted file]
drivers/staging/altera-stapl/altera-exprt.h [deleted file]
drivers/staging/altera-stapl/altera-jtag.c [deleted file]
drivers/staging/altera-stapl/altera-jtag.h [deleted file]
drivers/staging/altera-stapl/altera-lpt.c [deleted file]
drivers/staging/altera-stapl/altera.c [deleted file]
drivers/staging/altera-stapl/altera.h [deleted file]
drivers/staging/dt3155v4l/dt3155v4l.c
drivers/staging/tm6000/CARDLIST [deleted file]
drivers/staging/tm6000/Kconfig [deleted file]
drivers/staging/tm6000/Makefile [deleted file]
drivers/staging/tm6000/README [deleted file]
drivers/staging/tm6000/TODO [deleted file]
drivers/staging/tm6000/tm6000-alsa.c [deleted file]
drivers/staging/tm6000/tm6000-cards.c [deleted file]
drivers/staging/tm6000/tm6000-core.c [deleted file]
drivers/staging/tm6000/tm6000-dvb.c [deleted file]
drivers/staging/tm6000/tm6000-i2c.c [deleted file]
drivers/staging/tm6000/tm6000-input.c [deleted file]
drivers/staging/tm6000/tm6000-regs.h [deleted file]
drivers/staging/tm6000/tm6000-stds.c [deleted file]
drivers/staging/tm6000/tm6000-usb-isoc.h [deleted file]
drivers/staging/tm6000/tm6000-video.c [deleted file]
drivers/staging/tm6000/tm6000.h [deleted file]
drivers/staging/xgifb/XGI_main_26.c
drivers/video/68328fb.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/acornfb.c
drivers/video/arkfb.c
drivers/video/atmel_lcdfb.c
drivers/video/aty/radeon_base.c
drivers/video/au1100fb.c
drivers/video/au1100fb.h
drivers/video/au1200fb.c
drivers/video/backlight/adp8860_bl.c
drivers/video/backlight/adp8870_bl.c
drivers/video/bf54x-lq043fb.c
drivers/video/bfin-lq035q1-fb.c
drivers/video/bfin-t350mcqb-fb.c
drivers/video/bfin_adv7393fb.c
drivers/video/carminefb.c
drivers/video/controlfb.c
drivers/video/da8xx-fb.c
drivers/video/fb-puv3.c
drivers/video/fb_defio.c
drivers/video/fbmem.c
drivers/video/fbmon.c
drivers/video/fbsysfs.c
drivers/video/fsl-diu-fb.c
drivers/video/g364fb.c
drivers/video/grvga.c [new file with mode: 0644]
drivers/video/gxt4500.c
drivers/video/hgafb.c
drivers/video/imsttfb.c
drivers/video/intelfb/intelfbhw.c
drivers/video/mb862xx/mb862xx-i2c.c
drivers/video/mb862xx/mb862xxfbdrv.c
drivers/video/modedb.c
drivers/video/msm/mddi.c
drivers/video/msm/mdp.c
drivers/video/mx3fb.c
drivers/video/mxsfb.c
drivers/video/neofb.c
drivers/video/nuc900fb.c
drivers/video/omap/Kconfig
drivers/video/omap/Makefile
drivers/video/omap/lcd_2430sdp.c [deleted file]
drivers/video/omap/lcd_apollon.c [deleted file]
drivers/video/omap/lcd_h4.c [deleted file]
drivers/video/omap/lcd_ldp.c [deleted file]
drivers/video/omap/lcd_omap3beagle.c [deleted file]
drivers/video/omap/lcd_omap3evm.c [deleted file]
drivers/video/omap/lcd_overo.c [deleted file]
drivers/video/omap2/displays/Kconfig
drivers/video/omap2/displays/Makefile
drivers/video/omap2/displays/panel-dvi.c [new file with mode: 0644]
drivers/video/omap2/displays/panel-generic-dpi.c
drivers/video/omap2/displays/panel-n8x0.c [new file with mode: 0644]
drivers/video/omap2/displays/panel-picodlp.c [new file with mode: 0644]
drivers/video/omap2/displays/panel-picodlp.h [new file with mode: 0644]
drivers/video/omap2/displays/panel-taal.c
drivers/video/omap2/dss/Kconfig
drivers/video/omap2/dss/Makefile
drivers/video/omap2/dss/core.c
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/dispc.h
drivers/video/omap2/dss/display.c
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss.c
drivers/video/omap2/dss/dss.h
drivers/video/omap2/dss/dss_features.c
drivers/video/omap2/dss/dss_features.h
drivers/video/omap2/dss/hdmi.c
drivers/video/omap2/dss/hdmi.h [deleted file]
drivers/video/omap2/dss/hdmi_omap4_panel.c [deleted file]
drivers/video/omap2/dss/hdmi_panel.c [new file with mode: 0644]
drivers/video/omap2/dss/manager.c
drivers/video/omap2/dss/overlay.c
drivers/video/omap2/dss/rfbi.c
drivers/video/omap2/dss/sdi.c
drivers/video/omap2/dss/ti_hdmi.h [new file with mode: 0644]
drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c [new file with mode: 0644]
drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h [new file with mode: 0644]
drivers/video/omap2/dss/venc.c
drivers/video/omap2/omapfb/Kconfig
drivers/video/omap2/omapfb/omapfb-main.c
drivers/video/omap2/omapfb/omapfb-sysfs.c
drivers/video/platinumfb.c
drivers/video/pm2fb.c
drivers/video/pm3fb.c
drivers/video/ps3fb.c
drivers/video/pxa3xx-gcu.c
drivers/video/pxafb.c
drivers/video/s3c-fb.c
drivers/video/s3c2410fb.c
drivers/video/s3fb.c
drivers/video/sa1100fb.c
drivers/video/savage/savagefb_driver.c
drivers/video/sh_mobile_hdmi.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sh_mobile_lcdcfb.h
drivers/video/sh_mobile_meram.c
drivers/video/sh_mobile_meram.h [deleted file]
drivers/video/sis/sis_main.c
drivers/video/skeletonfb.c
drivers/video/sm501fb.c
drivers/video/smscufx.c [new file with mode: 0644]
drivers/video/tmiofb.c
drivers/video/tridentfb.c
drivers/video/udlfb.c
drivers/video/valkyriefb.c
drivers/video/vfb.c
drivers/video/vga16fb.c
drivers/video/via/dvi.c
drivers/video/via/dvi.h
drivers/video/via/global.c
drivers/video/via/global.h
drivers/video/via/hw.c
drivers/video/via/hw.h
drivers/video/via/lcd.c
drivers/video/via/lcd.h
drivers/video/via/share.h
drivers/video/via/via-core.c
drivers/video/via/via_modesetting.c
drivers/video/via/via_modesetting.h
drivers/video/via/viafbdev.c
drivers/video/via/viamode.c
drivers/video/via/viamode.h
drivers/video/vt8500lcdfb.c
drivers/video/vt8623fb.c
drivers/video/xilinxfb.c
include/linux/device.h
include/linux/dvb/frontend.h
include/linux/dvb/version.h
include/linux/fsl-diu-fb.h
include/linux/i2c.h
include/linux/if_vlan.h
include/linux/iommu.h
include/linux/kvm.h
include/linux/kvm_host.h
include/linux/omap3isp.h
include/linux/usb/Kbuild
include/linux/videodev2.h
include/media/m5mols.h
include/media/mt9p031.h [new file with mode: 0644]
include/media/mt9t001.h [new file with mode: 0644]
include/media/omap3isp.h [new file with mode: 0644]
include/media/rc-core.h
include/media/rc-map.h
include/media/s5p_fimc.h
include/media/saa7146.h
include/media/v4l2-chip-ident.h
include/media/v4l2-ctrls.h
include/media/v4l2-mediabus.h
include/media/videobuf2-core.h
include/media/videobuf2-dma-contig.h
include/misc/altera.h [new file with mode: 0644]
include/net/inet_timewait_sock.h
include/net/ipv6.h
include/video/omap-panel-dvi.h [new file with mode: 0644]
include/video/omap-panel-n8x0.h [new file with mode: 0644]
include/video/omap-panel-nokia-dsi.h
include/video/omap-panel-picodlp.h [new file with mode: 0644]
include/video/omapdss.h
include/video/sh_mobile_lcdc.h
include/video/udlfb.h
lib/dma-debug.c
net/8021q/vlan_core.c
net/batman-adv/translation-table.c
net/batman-adv/types.h
net/core/dev.c
net/dccp/ipv6.c
net/ipv4/tcp_minisocks.c
net/ipv6/addrconf.c
net/ipv6/inet6_connection_sock.c
net/ipv6/ip6_output.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/sctp/ipv6.c
virt/kvm/assigned-dev.c
virt/kvm/coalesced_mmio.c
virt/kvm/coalesced_mmio.h
virt/kvm/eventfd.c
virt/kvm/ioapic.c
virt/kvm/iommu.c
virt/kvm/kvm_main.c

diff --git a/Documentation/ABI/testing/debugfs-ideapad b/Documentation/ABI/testing/debugfs-ideapad
new file mode 100644 (file)
index 0000000..7079c0b
--- /dev/null
@@ -0,0 +1,19 @@
+What:          /sys/kernel/debug/ideapad/cfg
+Date:          Sep 2011
+KernelVersion: 3.2
+Contact:       Ike Panhc <ike.pan@canonical.com>
+Description:
+
+cfg shows the return value of _CFG method in VPC2004 device. It tells machine
+capability and what graphic component within the machine.
+
+
+What:          /sys/kernel/debug/ideapad/status
+Date:          Sep 2011
+KernelVersion: 3.2
+Contact:       Ike Panhc <ike.pan@canonical.com>
+Description:
+
+status shows infos we can read and tells its meaning and value.
+
+
index ff53183..814b013 100644 (file)
@@ -5,19 +5,4 @@ Contact:       "Ike Panhc <ike.pan@canonical.com>"
 Description:
                Control the power of camera module. 1 means on, 0 means off.
 
-What:          /sys/devices/platform/ideapad/cfg
-Date:          Jun 2011
-KernelVersion: 3.1
-Contact:       "Ike Panhc <ike.pan@canonical.com>"
-Description:
-               Ideapad capability bits.
-               Bit 8-10: 1 - Intel graphic only
-                         2 - ATI graphic only
-                         3 - Nvidia graphic only
-                         4 - Intel and ATI graphic
-                         5 - Intel and Nvidia graphic
-               Bit 16: Bluetooth exist (1 for exist)
-               Bit 17: 3G exist (1 for exist)
-               Bit 18: Wifi exist (1 for exist)
-               Bit 19: Camera exist (1 for exist)
 
index 207e1a5..3bc8a61 100644 (file)
@@ -352,6 +352,7 @@ typedef enum fe_delivery_system {
        SYS_CMMB,
        SYS_DAB,
        SYS_DVBT2,
+       SYS_TURBO,
 } fe_delivery_system_t;
 </programlisting>
                </section>
@@ -809,6 +810,8 @@ typedef enum fe_hierarchy {
                        <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-VOLTAGE"><constant>DTV_VOLTAGE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TONE"><constant>DTV_TONE</constant></link></para></listitem>
                </itemizedlist>
                <para>Future implementations might add those two missing parameters:</para>
                <itemizedlist mark='opencircle'>
@@ -818,25 +821,18 @@ typedef enum fe_hierarchy {
        </section>
        <section id="dvbs2-params">
                <title>DVB-S2 delivery system</title>
-               <para>The following parameters are valid for DVB-S2:</para>
+               <para>In addition to all parameters valid for DVB-S, DVB-S2 supports the following parameters:</para>
                <itemizedlist mark='opencircle'>
-                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-VOLTAGE"><constant>DTV_VOLTAGE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-TONE"><constant>DTV_TONE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-PILOT"><constant>DTV_PILOT</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-ROLLOFF"><constant>DTV_ROLLOFF</constant></link></para></listitem>
                </itemizedlist>
-               <para>Future implementations might add those two missing parameters:</para>
+       </section>
+       <section id="turbo-params">
+               <title>Turbo code delivery system</title>
+               <para>In addition to all parameters valid for DVB-S, turbo code supports the following parameters:</para>
                <itemizedlist mark='opencircle'>
-                       <listitem><para><link linkend="DTV-DISEQC-MASTER"><constant>DTV_DISEQC_MASTER</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-DISEQC-SLAVE-REPLY"><constant>DTV_DISEQC_SLAVE_REPLY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
                </itemizedlist>
        </section>
        <section id="isdbs-params">
index c75dc7c..170064a 100644 (file)
@@ -205,7 +205,7 @@ a partial path like:</para>
 additional include file <emphasis
 role="tt">linux/dvb/version.h</emphasis> exists, which defines the
 constant <emphasis role="tt">DVB_API_VERSION</emphasis>. This document
-describes <emphasis role="tt">DVB_API_VERSION&#x00A0;3</emphasis>.
+describes <emphasis role="tt">DVB_API_VERSION 5.4</emphasis>.
 </para>
 
 </section>
index ce1004a..91410b6 100644 (file)
@@ -2370,6 +2370,14 @@ that used it. It was originally scheduled for removal in 2.6.35.
         </listitem>
       </orderedlist>
     </section>
+    <section>
+      <title>V4L2 in Linux 3.2</title>
+      <orderedlist>
+        <listitem>
+         <para>V4L2_CTRL_FLAG_VOLATILE was added to signal volatile controls to userspace.</para>
+        </listitem>
+      </orderedlist>
+    </section>
 
     <section id="other">
       <title>Relation of V4L2 to other Linux multimedia APIs</title>
index 05c8fef..0916a73 100644 (file)
 
       <para>When satisfied with the try results, applications can set the active
       formats by setting the <structfield>which</structfield> argument to
-      <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. Active formats are changed
+      <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. Active formats are changed
       exactly as try formats by drivers. To avoid modifying the hardware state
       during format negotiation, applications should negotiate try formats first
       and then modify the active settings using the try formats returned during
index 0d05e87..40132c2 100644 (file)
@@ -127,6 +127,13 @@ structs, ioctls) must be noted in more detail in the history chapter
 (compat.xml), along with the possible impact on existing drivers and
 applications. -->
 
+      <revision>
+       <revnumber>3.2</revnumber>
+       <date>2011-08-26</date>
+       <authorinitials>hv</authorinitials>
+       <revremark>Added V4L2_CTRL_FLAG_VOLATILE.</revremark>
+      </revision>
+
       <revision>
        <revnumber>3.1</revnumber>
        <date>2011-06-27</date>
@@ -410,7 +417,7 @@ and discussions on the V4L mailing list.</revremark>
 </partinfo>
 
 <title>Video for Linux Two API Specification</title>
- <subtitle>Revision 3.1</subtitle>
+ <subtitle>Revision 3.2</subtitle>
 
   <chapter id="common">
     &sub-common;
index 7769642..e8714aa 100644 (file)
            <entry>Event data for event V4L2_EVENT_CTRL.
             </entry>
          </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-event-frame-sync;</entry>
+            <entry><structfield>frame</structfield></entry>
+           <entry>Event data for event V4L2_EVENT_FRAME_SYNC.</entry>
+         </row>
          <row>
            <entry></entry>
            <entry>__u8</entry>
       </tgroup>
     </table>
 
+    <table frame="none" pgwide="1" id="v4l2-event-vsync">
+      <title>struct <structname>v4l2_event_vsync</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>field</structfield></entry>
+           <entry>The upcoming field. See &v4l2-field;.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-event-ctrl">
+      <title>struct <structname>v4l2_event_ctrl</structname></title>
+      <tgroup cols="4">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>changes</structfield></entry>
+           <entry></entry>
+           <entry>A bitmask that tells what has changed. See <xref linkend="changes-flags" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry></entry>
+           <entry>The type of the control. See &v4l2-ctrl-type;.</entry>
+         </row>
+         <row>
+           <entry>union (anonymous)</entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__s32</entry>
+           <entry><structfield>value</structfield></entry>
+           <entry>The 32-bit value of the control for 32-bit control types.
+               This is 0 for string controls since the value of a string
+               cannot be passed using &VIDIOC-DQEVENT;.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__s64</entry>
+           <entry><structfield>value64</structfield></entry>
+           <entry>The 64-bit value of the control for 64-bit control types.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry></entry>
+           <entry>The control flags. See <xref linkend="control-flags" />.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>minimum</structfield></entry>
+           <entry></entry>
+           <entry>The minimum value of the control. See &v4l2-queryctrl;.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>maximum</structfield></entry>
+           <entry></entry>
+           <entry>The maximum value of the control. See &v4l2-queryctrl;.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>step</structfield></entry>
+           <entry></entry>
+           <entry>The step value of the control. See &v4l2-queryctrl;.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>default_value</structfield></entry>
+           <entry></entry>
+           <entry>The default value value of the control. See &v4l2-queryctrl;.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-event-frame-sync">
+      <title>struct <structname>v4l2_event_frame_sync</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>frame_sequence</structfield></entry>
+           <entry>
+             The sequence number of the frame being received.
+           </entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="changes-flags">
+      <title>Changes</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_EVENT_CTRL_CH_VALUE</constant></entry>
+           <entry>0x0001</entry>
+           <entry>This control event was triggered because the value of the control
+               changed. Special case: if a button control is pressed, then this
+               event is sent as well, even though there is not explicit value
+               associated with a button control.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_CTRL_CH_FLAGS</constant></entry>
+           <entry>0x0002</entry>
+           <entry>This control event was triggered because the control flags
+               changed.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
   </refsect1>
   <refsect1>
     &return-value;
index 677ea64..0ac0057 100644 (file)
@@ -406,6 +406,15 @@ flag is typically present for relative controls or action controls where
 writing a value will cause the device to carry out a given action
 (&eg; motor control) but no meaningful value can be returned.</entry>
          </row>
+         <row>
+           <entry><constant>V4L2_CTRL_FLAG_VOLATILE</constant></entry>
+           <entry>0x0080</entry>
+           <entry>This control is volatile, which means that the value of the control
+changes continuously. A typical example would be the current gain value if the device
+is in auto-gain mode. In such a case the hardware calculates the gain value based on
+the lighting conditions which can change over time. Note that setting a new value for
+a volatile control will have no effect. The new value will just be ignored.</entry>
+         </row>
        </tbody>
       </tgroup>
     </table>
index 69c0d8a..5c70b61 100644 (file)
                field of the oldest event.</para>
            </entry>
          </row>
+         <row>
+           <entry><constant>V4L2_EVENT_FRAME_SYNC</constant></entry>
+           <entry>4</entry>
+           <entry>
+             <para>Triggered immediately when the reception of a
+             frame has begun. This event has a
+             &v4l2-event-frame-sync; associated with it.</para>
+
+             <para>If the hardware needs to be stopped in the case of a
+             buffer underrun it might not be able to generate this event.
+             In such cases the <structfield>frame_sequence</structfield>
+             field in &v4l2-event-frame-sync; will not be incremented. This
+             causes two consecutive frame sequence numbers to have n times
+             frame interval in between them.</para>
+           </entry>
+         </row>
          <row>
            <entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry>
            <entry>0x08000000</entry>
       </tgroup>
     </table>
 
-    <table frame="none" pgwide="1" id="v4l2-event-vsync">
-      <title>struct <structname>v4l2_event_vsync</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>field</structfield></entry>
-           <entry>The upcoming field. See &v4l2-field;.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-event-ctrl">
-      <title>struct <structname>v4l2_event_ctrl</structname></title>
-      <tgroup cols="4">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>changes</structfield></entry>
-           <entry></entry>
-           <entry>A bitmask that tells what has changed. See <xref linkend="changes-flags" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>The type of the control. See &v4l2-ctrl-type;.</entry>
-         </row>
-         <row>
-           <entry>union (anonymous)</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__s32</entry>
-           <entry><structfield>value</structfield></entry>
-           <entry>The 32-bit value of the control for 32-bit control types.
-               This is 0 for string controls since the value of a string
-               cannot be passed using &VIDIOC-DQEVENT;.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__s64</entry>
-           <entry><structfield>value64</structfield></entry>
-           <entry>The 64-bit value of the control for 64-bit control types.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry></entry>
-           <entry>The control flags. See <xref linkend="control-flags" />.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>minimum</structfield></entry>
-           <entry></entry>
-           <entry>The minimum value of the control. See &v4l2-queryctrl;.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>maximum</structfield></entry>
-           <entry></entry>
-           <entry>The maximum value of the control. See &v4l2-queryctrl;.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>step</structfield></entry>
-           <entry></entry>
-           <entry>The step value of the control. See &v4l2-queryctrl;.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>default_value</structfield></entry>
-           <entry></entry>
-           <entry>The default value value of the control. See &v4l2-queryctrl;.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="changes-flags">
-      <title>Changes</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_EVENT_CTRL_CH_VALUE</constant></entry>
-           <entry>0x0001</entry>
-           <entry>This control event was triggered because the value of the control
-               changed. Special case: if a button control is pressed, then this
-               event is sent as well, even though there is not explicit value
-               associated with a button control.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_CTRL_CH_FLAGS</constant></entry>
-           <entry>0x0002</entry>
-           <entry>This control event was triggered because the control flags
-               changed.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
   </refsect1>
   <refsect1>
     &return-value;
index c466f58..e67be7a 100755 (executable)
@@ -27,7 +27,8 @@ use IO::Handle;
                "or51211", "or51132_qam", "or51132_vsb", "bluebird",
                "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
                "af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
-               "lme2510c_s7395_old", "drxk", "drxk_terratec_h5");
+               "lme2510c_s7395_old", "drxk", "drxk_terratec_h5", "tda10071",
+               "it9135" );
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -575,19 +576,10 @@ sub ngene {
 }
 
 sub az6027{
-    my $file = "AZ6027_Linux_Driver.tar.gz";
-    my $url = "http://linux.terratec.de/files/$file";
     my $firmware = "dvb-usb-az6027-03.fw";
+    my $url = "http://linux.terratec.de/files/TERRATEC_S7/$firmware";
 
-    wgetfile($file, $url);
-
-    #untar
-    if( system("tar xzvf $file $firmware")){
-        die "failed to untar firmware";
-    }
-    if( system("rm $file")){
-        die ("unable to remove unnecessary files");
-    }
+    wgetfile($firmware, $url);
 
     $firmware;
 }
@@ -665,6 +657,41 @@ sub drxk_terratec_h5 {
     "$fwfile"
 }
 
+sub it9135 {
+    my $url = "http://kworld.server261.com/kworld/CD/ITE_TiVme/V1.00/";
+    my $zipfile = "Driver_V10.323.1.0412.100412.zip";
+    my $hash = "79b597dc648698ed6820845c0c9d0d37";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
+    my $drvfile = "Driver_V10.323.1.0412.100412/Data/x86/IT9135BDA.sys";
+    my $fwfile = "dvb-usb-it9137-01.fw";
+
+    checkstandard();
+
+    wgetfile($zipfile, $url . $zipfile);
+    verify($zipfile, $hash);
+    unzip($zipfile, $tmpdir);
+    extract("$tmpdir/$drvfile", 69632, 5731, "$fwfile");
+
+    "$fwfile"
+}
+
+sub tda10071 {
+    my $sourcefile = "PCTV_460e_reference.zip";
+    my $url = "ftp://ftp.pctvsystems.com/TV/driver/PCTV%2070e%2080e%20100e%20320e%20330e%20800e/";
+    my $hash = "4403de903bf2593464c8d74bbc200a57";
+    my $fwfile = "dvb-fe-tda10071.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url . $sourcefile);
+    verify($sourcefile, $hash);
+    unzip($sourcefile, $tmpdir);
+    extract("$tmpdir/PCTV\ 70e\ 80e\ 100e\ 320e\ 330e\ 800e/32\ bit/emOEM.sys", 0x67d38, 40504, $fwfile);
+
+    "$fwfile";
+}
+
 # ---------------------------------------------------------------
 # Utilities
 
diff --git a/Documentation/dvb/it9137.txt b/Documentation/dvb/it9137.txt
new file mode 100644 (file)
index 0000000..9e6726e
--- /dev/null
@@ -0,0 +1,9 @@
+To extract firmware for Kworld UB499-2T (id 1b80:e409) you need to copy the
+following file(s) to this directory.
+
+IT9135BDA.sys Dated Mon 22 Mar 2010 02:20:08 GMT
+
+extract using dd
+dd if=IT9135BDA.sys ibs=1 skip=69632 count=5731 of=dvb-usb-it9137-01.fw
+
+copy to default firmware location.
index 7fdde2a..57d2f29 100644 (file)
@@ -87,23 +87,38 @@ Special configuration for udlfb is usually unnecessary. There are a few
 options, however.
 
 From the command line, pass options to modprobe
-modprobe udlfb defio=1 console=1
+modprobe udlfb fb_defio=0 console=1 shadow=1
 
-Or for permanent option, create file like /etc/modprobe.d/options with text
-options udlfb defio=1 console=1
+Or modify options on the fly at /sys/module/udlfb/parameters directory via
+sudo nano fb_defio
+change the parameter in place, and save the file.
 
-Accepted options:
+Unplug/replug USB device to apply with new settings
+
+Or for permanent option, create file like /etc/modprobe.d/udlfb.conf with text
+options udlfb fb_defio=0 console=1 shadow=1
+
+Accepted boolean options:
 
 fb_defio       Make use of the fb_defio (CONFIG_FB_DEFERRED_IO) kernel
                module to track changed areas of the framebuffer by page faults.
-               Standard fbdev applications that use mmap but that do not
-               report damage, may be able to work with this enabled.
-               Disabled by default because of overhead and other issues.
-
-console                Allow fbcon to attach to udlfb provided framebuffers. This
-               is disabled by default because fbcon will aggressively consume
-               the first framebuffer it finds, which isn't usually what the
-               user wants in the case of USB displays.
+               Standard fbdev applications that use mmap but that do not
+               report damage, should be able to work with this enabled.
+               Disable when running with X server that supports reporting
+               changed regions via ioctl, as this method is simpler,
+               more stable, and higher performance.
+               default: fb_defio=1
+
+console        Allow fbcon to attach to udlfb provided framebuffers.
+               Can be disabled if fbcon and other clients
+               (e.g. X with --shared-vt) are in conflict.
+               default: console=1
+
+shadow         Allocate a 2nd framebuffer to shadow what's currently across
+               the USB bus in device memory. If any pixels are unchanged,
+               do not transmit. Spends host memory to save USB transfers.
+               Enabled by default. Only disable on very low memory systems.
+               default: shadow=1
 
 Sysfs Attributes
 ================
index d5ac362..7c799fc 100644 (file)
@@ -495,29 +495,6 @@ Who:       Jean Delvare <khali@linux-fr.org>
 
 ----------------------------
 
-What:  Support for UVCIOC_CTRL_ADD in the uvcvideo driver
-When:  3.2
-Why:   The information passed to the driver by this ioctl is now queried
-       dynamically from the device.
-Who:   Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-
-----------------------------
-
-What:  Support for UVCIOC_CTRL_MAP_OLD in the uvcvideo driver
-When:  3.2
-Why:   Used only by applications compiled against older driver versions.
-       Superseded by UVCIOC_CTRL_MAP which supports V4L2 menu controls.
-Who:   Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-
-----------------------------
-
-What:  Support for UVCIOC_CTRL_GET and UVCIOC_CTRL_SET in the uvcvideo driver
-When:  3.2
-Why:   Superseded by the UVCIOC_CTRL_QUERY ioctl.
-Who:   Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-
-----------------------------
-
 What:  Support for driver specific ioctls in the pwc driver (everything
        defined in media/pwc-ioctl.h)
 When:  3.3
index 7c19d1a..49f5b68 100644 (file)
@@ -88,6 +88,10 @@ byte. But this time, the data is a complete word (16 bits).
 
 S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
 
+Note the convenience function i2c_smbus_read_word_swapped is
+available for reads where the two data bytes are the other way
+around (not SMBus compliant, but very popular.)
+
 
 SMBus Write Byte:  i2c_smbus_write_byte_data()
 ==============================================
@@ -108,6 +112,10 @@ specified through the Comm byte.
 
 S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
 
+Note the convenience function i2c_smbus_write_word_swapped is
+available for writes where the two data bytes are the other way
+around (not SMBus compliant, but very popular.)
+
 
 SMBus Process Call:  i2c_smbus_process_call()
 =============================================
index 1fbe362..661efd4 100644 (file)
@@ -1201,6 +1201,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        [KVM,Intel] Disable FlexPriority feature (TPR shadow).
                        Default is 1 (enabled)
 
+       kvm-intel.nested=
+                       [KVM,Intel] Enable VMX nesting (nVMX).
+                       Default is 0 (disabled)
+
        kvm-intel.unrestricted_guest=
                        [KVM,Intel] Disable unrestricted guest feature
                        (virtualized real and unpaged mode) on capable
index 29ad4b1..e7fb2c6 100644 (file)
@@ -1,61 +1,22 @@
-Copyright (c) 2009-2010 QLogic Corporation
+Copyright (c) 2009-2011 QLogic Corporation
 QLogic Linux qlcnic NIC Driver
 
-This program includes a device driver for Linux 2.6 that may be
-distributed with QLogic hardware specific firmware binary file.
 You may modify and redistribute the device driver code under the
 GNU General Public License (a copy of which is attached hereto as
 Exhibit A) published by the Free Software Foundation (version 2).
 
-You may redistribute the hardware specific firmware binary file
-under the following terms:
-
-       1. Redistribution of source code (only if applicable),
-          must retain the above copyright notice, this list of
-          conditions and the following disclaimer.
-
-       2. Redistribution in binary form must reproduce the above
-          copyright notice, this list of conditions and the
-          following disclaimer in the documentation and/or other
-          materials provided with the distribution.
-
-       3. The name of QLogic Corporation may not be used to
-          endorse or promote products derived from this software
-          without specific prior written permission
-
-REGARDLESS OF WHAT LICENSING MECHANISM IS USED OR APPLICABLE,
-THIS PROGRAM IS PROVIDED BY QLOGIC CORPORATION "AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-USER ACKNOWLEDGES AND AGREES THAT USE OF THIS PROGRAM WILL NOT
-CREATE OR GIVE GROUNDS FOR A LICENSE BY IMPLICATION, ESTOPPEL, OR
-OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS (PATENT, COPYRIGHT,
-TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) EMBODIED IN
-ANY OTHER QLOGIC HARDWARE OR SOFTWARE EITHER SOLELY OR IN
-COMBINATION WITH THIS PROGRAM.
-
 
 EXHIBIT A
 
-                   GNU GENERAL PUBLIC LICENSE
-                      Version 2, June 1991
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
 
  Copyright (C) 1989, 1991 Free Software Foundation, Inc.
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
-                           Preamble
+                           Preamble
 
   The licenses for most software are designed to take away your
 freedom to share and change it.  By contrast, the GNU General Public
@@ -105,7 +66,7 @@ patent must be licensed for everyone's free use or not licensed at all.
   The precise terms and conditions for copying, distribution and
 modification follow.
 
-                   GNU GENERAL PUBLIC LICENSE
+                   GNU GENERAL PUBLIC LICENSE
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
   0. This License applies to any program or other work which contains
@@ -304,7 +265,7 @@ make exceptions for this.  Our decision will be guided by the two goals
 of preserving the free status of all derivatives of our free software and
 of promoting the sharing and reuse of software generally.
 
-                           NO WARRANTY
+                           NO WARRANTY
 
   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
diff --git a/Documentation/video4linux/CARDLIST.tm6000 b/Documentation/video4linux/CARDLIST.tm6000
new file mode 100644 (file)
index 0000000..b5edce4
--- /dev/null
@@ -0,0 +1,16 @@
+  1 -> Generic tm5600 board                   (tm5600)          [6000:0001]
+  2 -> Generic tm6000 board                   (tm6000)          [6000:0001]
+  3 -> Generic tm6010 board                   (tm6010)          [6000:0002]
+  4 -> 10Moons UT821                          (tm5600)          [6000:0001]
+  5 -> 10Moons UT330                          (tm5600)
+  6 -> ADSTech Dual TV                        (tm6000)          [06e1:f332]
+  7 -> FreeCom and similar                    (tm6000)          [14aa:0620]
+  8 -> ADSTech Mini Dual TV                   (tm6000)          [06e1:b339]
+  9 -> Hauppauge WinTV HVR-900H/USB2 Stick    (tm6010)          [2040:6600,2040:6601,2040:6610,2040:6611]
+ 10 -> Beholder Wander                        (tm6010)          [6000:dec0]
+ 11 -> Beholder Voyager                       (tm6010)          [6000:dec1]
+ 12 -> TerraTec Cinergy Hybrid XE/Cinergy Hybrid Stick (tm6010) [0ccd:0086,0ccd:00a5]
+ 13 -> TwinHan TU501                          (tm6010)          [13d3:3240,13d3:3241,13d3:3243,13d3:3264]
+ 14 -> Beholder Wander Lite                   (tm6010)          [6000:dec2]
+ 15 -> Beholder Voyager Lite                  (tm6010)          [6000:dec3]
+
index 5bfa9a7..b15e29f 100644 (file)
@@ -8,6 +8,7 @@ xxxx            vend:prod
 ----
 spca501                0000:0000       MystFromOri Unknown Camera
 spca508                0130:0130       Clone Digital Webcam 11043
+zc3xx          03f0:1b07       HP Premium Starter Cam
 m5602          0402:5602       ALi Video Camera Controller
 spca501                040a:0002       Kodak DVC-325
 spca500                040a:0300       Kodak EZ200
@@ -190,6 +191,7 @@ ov519               05a9:0519       OV519 Microphone
 ov519          05a9:0530       OmniVision
 ov519          05a9:2800       OmniVision SuperCAM
 ov519          05a9:4519       Webcam Classic
+ov534_9                05a9:8065       OmniVision test kit ov538+ov9712
 ov519          05a9:8519       OmniVision
 ov519          05a9:a511       D-Link USB Digital Video Camera
 ov519          05a9:a518       D-Link DSB-C310 Webcam
@@ -199,6 +201,8 @@ gl860               05e3:0503       Genesys Logic PC Camera
 gl860          05e3:f191       Genesys Logic PC Camera
 spca561                060b:a001       Maxell Compact Pc PM3
 zc3xx          0698:2003       CTX M730V built in
+topro          06a2:0003       TP6800 PC Camera, CmoX CX0342 webcam
+topro          06a2:6810       Creative Qmax
 nw80x          06a5:0000       Typhoon Webcam 100 USB
 nw80x          06a5:d001       Divio based webcams
 nw80x          06a5:d800       Divio Chicony TwinkleCam, Trust SpaceCam
index 69be2c7..5dd1439 100644 (file)
@@ -70,10 +70,11 @@ Events
 The OMAP 3 ISP driver does support the V4L2 event interface on CCDC and
 statistics (AEWB, AF and histogram) subdevs.
 
-The CCDC subdev produces V4L2_EVENT_OMAP3ISP_HS_VS type event on HS_VS
-interrupt which is used to signal frame start. The event is triggered exactly
-when the reception of the first line of the frame starts in the CCDC module.
-The event can be subscribed on the CCDC subdev.
+The CCDC subdev produces V4L2_EVENT_FRAME_SYNC type event on HS_VS
+interrupt which is used to signal frame start. Earlier version of this
+driver used V4L2_EVENT_OMAP3ISP_HS_VS for this purpose. The event is
+triggered exactly when the reception of the first line of the frame starts
+in the CCDC module. The event can be subscribed on the CCDC subdev.
 
 (When using parallel interface one must pay account to correct configuration
 of the VS signal polarity. This is automatically correct when using the serial
index 9346fc8..26aa057 100644 (file)
@@ -285,11 +285,11 @@ implement g_volatile_ctrl like this:
 Note that you use the 'new value' union as well in g_volatile_ctrl. In general
 controls that need to implement g_volatile_ctrl are read-only controls.
 
-To mark a control as volatile you have to set the is_volatile flag:
+To mark a control as volatile you have to set V4L2_CTRL_FLAG_VOLATILE:
 
        ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...);
        if (ctrl)
-               ctrl->is_volatile = 1;
+               ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
 
 For try/s_ctrl the new values (i.e. as passed by the user) are filled in and
 you can modify them in try_ctrl or set them in s_ctrl. The 'cur' union
@@ -367,8 +367,7 @@ Driver specific controls can be created using v4l2_ctrl_new_custom():
 The last argument is the priv pointer which can be set to driver-specific
 private data.
 
-The v4l2_ctrl_config struct also has fields to set the is_private and is_volatile
-flags.
+The v4l2_ctrl_config struct also has a field to set the is_private flag.
 
 If the name field is not set, then the framework will assume this is a standard
 control and will fill in the name, type and flags fields accordingly.
@@ -496,18 +495,20 @@ Handling autogain/gain-type Controls with Auto Clusters
 
 A common type of control cluster is one that handles 'auto-foo/foo'-type
 controls. Typical examples are autogain/gain, autoexposure/exposure,
-autowhitebalance/red balance/blue balance. In all cases you have one controls
+autowhitebalance/red balance/blue balance. In all cases you have one control
 that determines whether another control is handled automatically by the hardware,
 or whether it is under manual control from the user.
 
 If the cluster is in automatic mode, then the manual controls should be
-marked inactive. When the volatile controls are read the g_volatile_ctrl
-operation should return the value that the hardware's automatic mode set up
-automatically.
+marked inactive and volatile. When the volatile controls are read the
+g_volatile_ctrl operation should return the value that the hardware's automatic
+mode set up automatically.
 
 If the cluster is put in manual mode, then the manual controls should become
-active again and the is_volatile flag should be ignored (so g_volatile_ctrl is
-no longer called while in manual mode).
+active again and the volatile flag is cleared (so g_volatile_ctrl is no longer
+called while in manual mode). In addition just before switching to manual mode
+the current values as determined by the auto mode are copied as the new manual
+values.
 
 Finally the V4L2_CTRL_FLAG_UPDATE should be set for the auto control since
 changing that control affects the control flags of the manual controls.
@@ -520,7 +521,11 @@ void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
 
 The first two arguments are identical to v4l2_ctrl_cluster. The third argument
 tells the framework which value switches the cluster into manual mode. The
-last argument will optionally set the is_volatile flag for the non-auto controls.
+last argument will optionally set V4L2_CTRL_FLAG_VOLATILE for the non-auto controls.
+If it is false, then the manual controls are never volatile. You would typically
+use that if the hardware does not give you the option to read back to values as
+determined by the auto mode (e.g. if autogain is on, the hardware doesn't allow
+you to obtain the current gain value).
 
 The first control of the cluster is assumed to be the 'auto' control.
 
@@ -681,16 +686,6 @@ if there are no controls at all.
 count if nothing was done yet. If it is less than count then only the controls
 up to error_idx-1 were successfully applied.
 
-3) When attempting to read a button control the framework will return -EACCES
-instead of -EINVAL as stated in the spec. It seems to make more sense since
-button controls are write-only controls.
-
-4) Attempting to write to a read-only control will return -EACCES instead of
--EINVAL as the spec says.
-
-5) The spec does not mention what should happen when you try to set/get a
-control class controls. The framework will return -EACCES.
-
 
 Proposals for Extensions
 ========================
@@ -703,9 +698,3 @@ decimal. Useful for e.g. video_mute_yuv.
 2) It is possible to mark in the controls array which controls have been
 successfully written and which failed by for example adding a bit to the
 control ID. Not sure if it is worth the effort, though.
-
-3) Trying to set volatile inactive controls should result in -EACCESS.
-
-4) Add a new flag to mark volatile controls. Any application that wants
-to store the state of the controls can then skip volatile inactive controls.
-Currently it is not possible to detect such controls.
index b0e4b9c..7945b0b 100644 (file)
@@ -175,10 +175,30 @@ Parameters: vcpu id (apic id on x86)
 Returns: vcpu fd on success, -1 on error
 
 This API adds a vcpu to a virtual machine.  The vcpu id is a small integer
-in the range [0, max_vcpus).  You can use KVM_CAP_NR_VCPUS of the
-KVM_CHECK_EXTENSION ioctl() to determine the value for max_vcpus at run-time.
+in the range [0, max_vcpus).
+
+The recommended max_vcpus value can be retrieved using the KVM_CAP_NR_VCPUS of
+the KVM_CHECK_EXTENSION ioctl() at run-time.
+The maximum possible value for max_vcpus can be retrieved using the
+KVM_CAP_MAX_VCPUS of the KVM_CHECK_EXTENSION ioctl() at run-time.
+
 If the KVM_CAP_NR_VCPUS does not exist, you should assume that max_vcpus is 4
 cpus max.
+If the KVM_CAP_MAX_VCPUS does not exist, you should assume that max_vcpus is
+same as the value returned from KVM_CAP_NR_VCPUS.
+
+On powerpc using book3s_hv mode, the vcpus are mapped onto virtual
+threads in one or more virtual CPU cores.  (This is because the
+hardware requires all the hardware threads in a CPU core to be in the
+same partition.)  The KVM_CAP_PPC_SMT capability indicates the number
+of vcpus per virtual core (vcore).  The vcore id is obtained by
+dividing the vcpu id by the number of vcpus per vcore.  The vcpus in a
+given vcore will always be in the same physical core as each other
+(though that might be a different physical core from time to time).
+Userspace can control the threading (SMT) mode of the guest by its
+allocation of vcpu ids.  For example, if userspace wants
+single-threaded guest vcpus, it should make all vcpu ids be a multiple
+of the number of vcpus per vcore.
 
 On powerpc using book3s_hv mode, the vcpus are mapped onto virtual
 threads in one or more virtual CPU cores.  (This is because the
@@ -1633,3 +1653,50 @@ developer registration required to access it).
                char padding[256];
        };
 };
+
+6. Capabilities that can be enabled
+
+There are certain capabilities that change the behavior of the virtual CPU when
+enabled. To enable them, please see section 4.37. Below you can find a list of
+capabilities and what their effect on the vCPU is when enabling them.
+
+The following information is provided along with the description:
+
+  Architectures: which instruction set architectures provide this ioctl.
+      x86 includes both i386 and x86_64.
+
+  Parameters: what parameters are accepted by the capability.
+
+  Returns: the return value.  General error numbers (EBADF, ENOMEM, EINVAL)
+      are not detailed, but errors with specific meanings are.
+
+6.1 KVM_CAP_PPC_OSI
+
+Architectures: ppc
+Parameters: none
+Returns: 0 on success; -1 on error
+
+This capability enables interception of OSI hypercalls that otherwise would
+be treated as normal system calls to be injected into the guest. OSI hypercalls
+were invented by Mac-on-Linux to have a standardized communication mechanism
+between the guest and the host.
+
+When this capability is enabled, KVM_EXIT_OSI can occur.
+
+6.2 KVM_CAP_PPC_PAPR
+
+Architectures: ppc
+Parameters: none
+Returns: 0 on success; -1 on error
+
+This capability enables interception of PAPR hypercalls. PAPR hypercalls are
+done using the hypercall instruction "sc 1".
+
+It also sets the guest privilege level to "supervisor" mode. Usually the guest
+runs in "hypervisor" privilege mode with a few missing features.
+
+In addition to the above, it changes the semantics of SDR1. In this mode, the
+HTAB address part of SDR1 contains an HVA instead of a GPA, as PAPR keeps the
+HTAB invisible to the guest.
+
+When this capability is enabled, KVM_EXIT_PAPR_HCALL can occur.
index 07e5dbd..d498c70 100644 (file)
@@ -1085,6 +1085,24 @@ F:       arch/arm/plat-s5p/dev-fimc*
 F:     arch/arm/plat-samsung/include/plat/*fimc*
 F:     drivers/media/video/s5p-fimc/
 
+ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT
+M:     Kyungmin Park <kyungmin.park@samsung.com>
+M:     Kamil Debski <k.debski@samsung.com>
+L:     linux-arm-kernel@lists.infradead.org
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     arch/arm/plat-s5p/dev-mfc.c
+F:     drivers/media/video/s5p-mfc/
+
+ARM/SAMSUNG S5P SERIES TV SUBSYSTEM SUPPORT
+M:     Kyungmin Park <kyungmin.park@samsung.com>
+M:     Tomasz Stanislawski <t.stanislaws@samsung.com>
+L:     linux-arm-kernel@lists.infradead.org
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     arch/arm/plat-s5p/dev-tv.c
+F:     drivers/media/video/s5p-tv/
+
 ARM/SHMOBILE ARM ARCHITECTURE
 M:     Paul Mundt <lethal@linux-sh.org>
 M:     Magnus Damm <magnus.damm@gmail.com>
@@ -3209,6 +3227,13 @@ F:       Documentation/ide/
 F:     drivers/ide/
 F:     include/linux/ide.h
 
+IDEAPAD LAPTOP EXTRAS DRIVER
+M:     Ike Panhc <ike.pan@canonical.com>
+L:     platform-driver-x86@vger.kernel.org
+W:     http://launchpad.net/ideapad-laptop
+S:     Maintained
+F:     drivers/platform/x86/ideapad-laptop.c
+
 IDE/ATAPI DRIVERS
 M:     Borislav Petkov <petkovbb@gmail.com>
 L:     linux-ide@vger.kernel.org
@@ -5970,6 +5995,12 @@ L:       netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/smsc/smsc9420.*
 
+SMSC UFX6000 and UFX7000 USB to VGA DRIVER
+M:     Steve Glendinning <steve.glendinning@smsc.com>
+L:     linux-fbdev@vger.kernel.org
+S:     Supported
+F:     drivers/video/smscufx.c
+
 SN-IA64 (Itanium) SUB-PLATFORM
 M:     Jes Sorensen <jes@sgi.com>
 L:     linux-altix@sgi.com
index 87f43ad..f8ce84b 100644 (file)
@@ -39,6 +39,9 @@
 #include <plat/usb.h>
 #include <plat/gpmc-smc91x.h>
 
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
+
 #include "mux.h"
 #include "hsmmc.h"
 #include "common-board-devices.h"
@@ -99,20 +102,72 @@ static struct platform_device sdp2430_flash_device = {
        .resource       = &sdp2430_flash_resource,
 };
 
-static struct platform_device sdp2430_lcd_device = {
-       .name           = "sdp2430_lcd",
-       .id             = -1,
-};
-
 static struct platform_device *sdp2430_devices[] __initdata = {
        &sdp2430_flash_device,
+};
+
+/* LCD */
+#define SDP2430_LCD_PANEL_BACKLIGHT_GPIO       91
+#define SDP2430_LCD_PANEL_ENABLE_GPIO          154
+
+static int sdp2430_panel_enable_lcd(struct omap_dss_device *dssdev)
+{
+       gpio_direction_output(SDP2430_LCD_PANEL_ENABLE_GPIO, 1);
+       gpio_direction_output(SDP2430_LCD_PANEL_BACKLIGHT_GPIO, 1);
+
+       return 0;
+}
+
+static void sdp2430_panel_disable_lcd(struct omap_dss_device *dssdev)
+{
+       gpio_direction_output(SDP2430_LCD_PANEL_ENABLE_GPIO, 0);
+       gpio_direction_output(SDP2430_LCD_PANEL_BACKLIGHT_GPIO, 0);
+}
+
+static struct panel_generic_dpi_data sdp2430_panel_data = {
+       .name                   = "nec_nl2432dr22-11b",
+       .platform_enable        = sdp2430_panel_enable_lcd,
+       .platform_disable       = sdp2430_panel_disable_lcd,
+};
+
+static struct omap_dss_device sdp2430_lcd_device = {
+       .name                   = "lcd",
+       .driver_name            = "generic_dpi_panel",
+       .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .phy.dpi.data_lines     = 16,
+       .data                   = &sdp2430_panel_data,
+};
+
+static struct omap_dss_device *sdp2430_dss_devices[] = {
        &sdp2430_lcd_device,
 };
 
-static struct omap_lcd_config sdp2430_lcd_config __initdata = {
-       .ctrl_name      = "internal",
+static struct omap_dss_board_info sdp2430_dss_data = {
+       .num_devices    = ARRAY_SIZE(sdp2430_dss_devices),
+       .devices        = sdp2430_dss_devices,
+       .default_device = &sdp2430_lcd_device,
 };
 
+static void __init sdp2430_display_init(void)
+{
+       int r;
+
+       static struct gpio gpios[] __initdata = {
+               { SDP2430_LCD_PANEL_ENABLE_GPIO, GPIOF_OUT_INIT_LOW,
+                       "LCD reset" },
+               { SDP2430_LCD_PANEL_BACKLIGHT_GPIO, GPIOF_OUT_INIT_LOW,
+                       "LCD Backlight" },
+       };
+
+       r = gpio_request_array(gpios, ARRAY_SIZE(gpios));
+       if (r) {
+               pr_err("Cannot request LCD GPIOs, error %d\n", r);
+               return;
+       }
+
+       omap_display_init(&sdp2430_dss_data);
+}
+
 #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91x_MODULE)
 
 static struct omap_smc91x_platform_data board_smc91x_data = {
@@ -137,10 +192,6 @@ static inline void board_smc91x_init(void)
 
 #endif
 
-static struct omap_board_config_kernel sdp2430_config[] __initdata = {
-       {OMAP_TAG_LCD, &sdp2430_lcd_config},
-};
-
 static void __init omap_2430sdp_init_early(void)
 {
        omap2_init_common_infrastructure();
@@ -229,9 +280,6 @@ static void __init omap_2430sdp_init(void)
 {
        omap2430_mux_init(board_mux, OMAP_PACKAGE_ZAC);
 
-       omap_board_config = sdp2430_config;
-       omap_board_config_size = ARRAY_SIZE(sdp2430_config);
-
        omap2430_i2c_init();
 
        platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices));
@@ -247,6 +295,8 @@ static void __init omap_2430sdp_init(void)
        /* Turn off secondary LCD backlight */
        gpio_request_one(SECONDARY_LCD_GPIO, GPIOF_OUT_INIT_LOW,
                         "Secondary LCD backlight");
+
+       sdp2430_display_init();
 }
 
 static void __init omap_2430sdp_map_io(void)
index 2430531..204bedd 100644 (file)
@@ -37,7 +37,7 @@
 #include <plat/dma.h>
 #include <plat/gpmc.h>
 #include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-dvi.h>
 
 #include <plat/gpmc-smc91x.h>
 
@@ -186,8 +186,7 @@ static struct omap_dss_device sdp3430_lcd_device = {
        .platform_disable       = sdp3430_panel_disable_lcd,
 };
 
-static struct panel_generic_dpi_data dvi_panel = {
-       .name                   = "generic",
+static struct panel_dvi_platform_data dvi_panel = {
        .platform_enable        = sdp3430_panel_enable_dvi,
        .platform_disable       = sdp3430_panel_disable_dvi,
 };
@@ -195,7 +194,7 @@ static struct panel_generic_dpi_data dvi_panel = {
 static struct omap_dss_device sdp3430_dvi_device = {
        .name                   = "dvi",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
-       .driver_name            = "generic_dpi_panel",
+       .driver_name            = "dvi",
        .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
 };
index be93110..484cec5 100644 (file)
@@ -38,6 +38,8 @@
 #include <plat/mmc.h>
 #include <plat/omap4-keypad.h>
 #include <video/omapdss.h>
+#include <video/omap-panel-nokia-dsi.h>
+#include <video/omap-panel-picodlp.h>
 #include <linux/wl12xx.h>
 
 #include "mux.h"
@@ -52,6 +54,8 @@
 #define OMAP4_SFH7741_ENABLE_GPIO              188
 #define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */
 #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
+#define DISPLAY_SEL_GPIO       59      /* LCD2/PicoDLP switch */
+#define DLP_POWER_ON_GPIO      40
 
 #define GPIO_WIFI_PMENA                54
 #define GPIO_WIFI_IRQ          53
@@ -340,11 +344,6 @@ static int __init omap_ethernet_init(void)
        return status;
 }
 
-static struct platform_device sdp4430_lcd_device = {
-       .name           = "sdp4430_lcd",
-       .id             = -1,
-};
-
 static struct regulator_consumer_supply sdp4430_vbat_supply[] = {
        REGULATOR_SUPPLY("vddvibl", "twl6040-vibra"),
        REGULATOR_SUPPLY("vddvibr", "twl6040-vibra"),
@@ -374,21 +373,12 @@ static struct platform_device sdp4430_vbat = {
 };
 
 static struct platform_device *sdp4430_devices[] __initdata = {
-       &sdp4430_lcd_device,
        &sdp4430_gpio_keys_device,
        &sdp4430_leds_gpio,
        &sdp4430_leds_pwm,
        &sdp4430_vbat,
 };
 
-static struct omap_lcd_config sdp4430_lcd_config __initdata = {
-       .ctrl_name      = "internal",
-};
-
-static struct omap_board_config_kernel sdp4430_config[] __initdata = {
-       { OMAP_TAG_LCD,         &sdp4430_lcd_config },
-};
-
 static void __init omap_4430sdp_init_early(void)
 {
        omap2_init_common_infrastructure();
@@ -648,37 +638,202 @@ static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev)
        gpio_free(HDMI_GPIO_HPD);
 }
 
-static struct omap_dss_device sdp4430_hdmi_device = {
-       .name = "hdmi",
-       .driver_name = "hdmi_panel",
-       .type = OMAP_DISPLAY_TYPE_HDMI,
-       .clocks = {
-               .dispc  = {
+static struct nokia_dsi_panel_data dsi1_panel = {
+               .name           = "taal",
+               .reset_gpio     = 102,
+               .use_ext_te     = false,
+               .ext_te_gpio    = 101,
+               .esd_interval   = 0,
+};
+
+static struct omap_dss_device sdp4430_lcd_device = {
+       .name                   = "lcd",
+       .driver_name            = "taal",
+       .type                   = OMAP_DISPLAY_TYPE_DSI,
+       .data                   = &dsi1_panel,
+       .phy.dsi                = {
+               .clk_lane       = 1,
+               .clk_pol        = 0,
+               .data1_lane     = 2,
+               .data1_pol      = 0,
+               .data2_lane     = 3,
+               .data2_pol      = 0,
+
+               .module         = 0,
+       },
+
+       .clocks = {
+               .dispc = {
+                       .channel = {
+                               /* Logic Clock = 172.8 MHz */
+                               .lck_div        = 1,
+                               /* Pixel Clock = 34.56 MHz */
+                               .pck_div        = 5,
+                               .lcd_clk_src    = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC,
+                       },
                        .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK,
                },
-               .hdmi   = {
-                       .regn   = 15,
-                       .regm2  = 1,
+
+               .dsi = {
+                       .regn           = 16,   /* Fint = 2.4 MHz */
+                       .regm           = 180,  /* DDR Clock = 216 MHz */
+                       .regm_dispc     = 5,    /* PLL1_CLK1 = 172.8 MHz */
+                       .regm_dsi       = 5,    /* PLL1_CLK2 = 172.8 MHz */
+
+                       .lp_clk_div     = 10,   /* LP Clock = 8.64 MHz */
+                       .dsi_fclk_src   = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI,
+               },
+       },
+       .channel                = OMAP_DSS_CHANNEL_LCD,
+};
+
+static struct nokia_dsi_panel_data dsi2_panel = {
+               .name           = "taal",
+               .reset_gpio     = 104,
+               .use_ext_te     = false,
+               .ext_te_gpio    = 103,
+               .esd_interval   = 0,
+};
+
+static struct omap_dss_device sdp4430_lcd2_device = {
+       .name                   = "lcd2",
+       .driver_name            = "taal",
+       .type                   = OMAP_DISPLAY_TYPE_DSI,
+       .data                   = &dsi2_panel,
+       .phy.dsi                = {
+               .clk_lane       = 1,
+               .clk_pol        = 0,
+               .data1_lane     = 2,
+               .data1_pol      = 0,
+               .data2_lane     = 3,
+               .data2_pol      = 0,
+
+               .module         = 1,
+       },
+
+       .clocks = {
+               .dispc = {
+                       .channel = {
+                               /* Logic Clock = 172.8 MHz */
+                               .lck_div        = 1,
+                               /* Pixel Clock = 34.56 MHz */
+                               .pck_div        = 5,
+                               .lcd_clk_src    = OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC,
+                       },
+                       .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK,
+               },
+
+               .dsi = {
+                       .regn           = 16,   /* Fint = 2.4 MHz */
+                       .regm           = 180,  /* DDR Clock = 216 MHz */
+                       .regm_dispc     = 5,    /* PLL1_CLK1 = 172.8 MHz */
+                       .regm_dsi       = 5,    /* PLL1_CLK2 = 172.8 MHz */
+
+                       .lp_clk_div     = 10,   /* LP Clock = 8.64 MHz */
+                       .dsi_fclk_src   = OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI,
                },
        },
+       .channel                = OMAP_DSS_CHANNEL_LCD2,
+};
+
+static void sdp4430_lcd_init(void)
+{
+       int r;
+
+       r = gpio_request_one(dsi1_panel.reset_gpio, GPIOF_DIR_OUT,
+               "lcd1_reset_gpio");
+       if (r)
+               pr_err("%s: Could not get lcd1_reset_gpio\n", __func__);
+
+       r = gpio_request_one(dsi2_panel.reset_gpio, GPIOF_DIR_OUT,
+               "lcd2_reset_gpio");
+       if (r)
+               pr_err("%s: Could not get lcd2_reset_gpio\n", __func__);
+}
+
+static struct omap_dss_device sdp4430_hdmi_device = {
+       .name = "hdmi",
+       .driver_name = "hdmi_panel",
+       .type = OMAP_DISPLAY_TYPE_HDMI,
        .platform_enable = sdp4430_panel_enable_hdmi,
        .platform_disable = sdp4430_panel_disable_hdmi,
        .channel = OMAP_DSS_CHANNEL_DIGIT,
 };
 
+static struct picodlp_panel_data sdp4430_picodlp_pdata = {
+       .picodlp_adapter_id     = 2,
+       .emu_done_gpio          = 44,
+       .pwrgood_gpio           = 45,
+};
+
+static void sdp4430_picodlp_init(void)
+{
+       int r;
+       const struct gpio picodlp_gpios[] = {
+               {DLP_POWER_ON_GPIO, GPIOF_OUT_INIT_LOW,
+                       "DLP POWER ON"},
+               {sdp4430_picodlp_pdata.emu_done_gpio, GPIOF_IN,
+                       "DLP EMU DONE"},
+               {sdp4430_picodlp_pdata.pwrgood_gpio, GPIOF_OUT_INIT_LOW,
+                       "DLP PWRGOOD"},
+       };
+
+       r = gpio_request_array(picodlp_gpios, ARRAY_SIZE(picodlp_gpios));
+       if (r)
+               pr_err("Cannot request PicoDLP GPIOs, error %d\n", r);
+}
+
+static int sdp4430_panel_enable_picodlp(struct omap_dss_device *dssdev)
+{
+       gpio_set_value(DISPLAY_SEL_GPIO, 0);
+       gpio_set_value(DLP_POWER_ON_GPIO, 1);
+
+       return 0;
+}
+
+static void sdp4430_panel_disable_picodlp(struct omap_dss_device *dssdev)
+{
+       gpio_set_value(DLP_POWER_ON_GPIO, 0);
+       gpio_set_value(DISPLAY_SEL_GPIO, 1);
+}
+
+static struct omap_dss_device sdp4430_picodlp_device = {
+       .name                   = "picodlp",
+       .driver_name            = "picodlp_panel",
+       .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .phy.dpi.data_lines     = 24,
+       .channel                = OMAP_DSS_CHANNEL_LCD2,
+       .platform_enable        = sdp4430_panel_enable_picodlp,
+       .platform_disable       = sdp4430_panel_disable_picodlp,
+       .data                   = &sdp4430_picodlp_pdata,
+};
+
 static struct omap_dss_device *sdp4430_dss_devices[] = {
+       &sdp4430_lcd_device,
+       &sdp4430_lcd2_device,
        &sdp4430_hdmi_device,
+       &sdp4430_picodlp_device,
 };
 
 static struct omap_dss_board_info sdp4430_dss_data = {
        .num_devices    = ARRAY_SIZE(sdp4430_dss_devices),
        .devices        = sdp4430_dss_devices,
-       .default_device = &sdp4430_hdmi_device,
+       .default_device = &sdp4430_lcd_device,
 };
 
-void omap_4430sdp_display_init(void)
+static void omap_4430sdp_display_init(void)
 {
+       int r;
+
+       /* Enable LCD2 by default (instead of Pico DLP) */
+       r = gpio_request_one(DISPLAY_SEL_GPIO, GPIOF_OUT_INIT_HIGH,
+                       "display_sel");
+       if (r)
+               pr_err("%s: Could not get display_sel GPIO\n", __func__);
+
+       sdp4430_lcd_init();
        sdp4430_hdmi_mux_init();
+       sdp4430_picodlp_init();
        omap_display_init(&sdp4430_dss_data);
 }
 
@@ -802,9 +957,6 @@ static void __init omap_4430sdp_init(void)
                package = OMAP_PACKAGE_CBL;
        omap4_mux_init(board_mux, NULL, package);
 
-       omap_board_config = sdp4430_config;
-       omap_board_config_size = ARRAY_SIZE(sdp4430_config);
-
        omap4_i2c_init();
        omap_sfh7741prox_init();
        platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices));
index 1325085..ab10f75 100644 (file)
@@ -36,6 +36,7 @@
 #include <plat/usb.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-dvi.h>
 
 #include "mux.h"
 #include "control.h"
@@ -333,8 +334,7 @@ static void am3517_evm_panel_disable_dvi(struct omap_dss_device *dssdev)
        dvi_enabled = 0;
 }
 
-static struct panel_generic_dpi_data dvi_panel = {
-       .name                   = "generic",
+static struct panel_dvi_platform_data dvi_panel = {
        .platform_enable        = am3517_evm_panel_enable_dvi,
        .platform_disable       = am3517_evm_panel_disable_dvi,
 };
@@ -342,7 +342,7 @@ static struct panel_generic_dpi_data dvi_panel = {
 static struct omap_dss_device am3517_evm_dvi_device = {
        .type                   = OMAP_DISPLAY_TYPE_DPI,
        .name                   = "dvi",
-       .driver_name            = "generic_dpi_panel",
+       .driver_name            = "dvi",
        .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
 };
index 67800e6..ad55351 100644 (file)
@@ -40,6 +40,9 @@
 #include <plat/common.h>
 #include <plat/gpmc.h>
 
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
+
 #include "mux.h"
 #include "control.h"
 
@@ -149,11 +152,6 @@ static struct platform_device apollon_smc91x_device = {
        .resource       = apollon_smc91x_resources,
 };
 
-static struct platform_device apollon_lcd_device = {
-       .name           = "apollon_lcd",
-       .id             = -1,
-};
-
 static struct omap_led_config apollon_led_config[] = {
        {
                .cdev   = {
@@ -191,7 +189,6 @@ static struct platform_device apollon_led_device = {
 static struct platform_device *apollon_devices[] __initdata = {
        &apollon_onenand_device,
        &apollon_smc91x_device,
-       &apollon_lcd_device,
        &apollon_led_device,
 };
 
@@ -265,12 +262,26 @@ static struct omap_usb_config apollon_usb_config __initdata = {
        .pins[0]        = 6,
 };
 
-static struct omap_lcd_config apollon_lcd_config __initdata = {
-       .ctrl_name      = "internal",
+static struct panel_generic_dpi_data apollon_panel_data = {
+       .name                   = "apollon",
 };
 
-static struct omap_board_config_kernel apollon_config[] __initdata = {
-       { OMAP_TAG_LCD,         &apollon_lcd_config },
+static struct omap_dss_device apollon_lcd_device = {
+       .name                   = "lcd",
+       .driver_name            = "generic_dpi_panel",
+       .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .phy.dpi.data_lines     = 18,
+       .data                   = &apollon_panel_data,
+};
+
+static struct omap_dss_device *apollon_dss_devices[] = {
+       &apollon_lcd_device,
+};
+
+static struct omap_dss_board_info apollon_dss_data = {
+       .num_devices    = ARRAY_SIZE(apollon_dss_devices),
+       .devices        = apollon_dss_devices,
+       .default_device = &apollon_lcd_device,
 };
 
 static void __init omap_apollon_init_early(void)
@@ -314,8 +325,6 @@ static void __init omap_apollon_init(void)
        u32 v;
 
        omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAC);
-       omap_board_config = apollon_config;
-       omap_board_config_size = ARRAY_SIZE(apollon_config);
 
        apollon_init_smc91x();
        apollon_led_init();
@@ -340,6 +349,8 @@ static void __init omap_apollon_init(void)
         */
        platform_add_devices(apollon_devices, ARRAY_SIZE(apollon_devices));
        omap_serial_init();
+
+       omap_display_init(&apollon_dss_data);
 }
 
 static void __init omap_apollon_map_io(void)
index 38179c1..6e0f0d2 100644 (file)
@@ -43,6 +43,7 @@
 #include <plat/usb.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-dvi.h>
 #include <plat/mcspi.h>
 
 #include <mach/hardware.h>
@@ -242,8 +243,7 @@ static struct omap_dss_device cm_t35_lcd_device = {
        .phy.dpi.data_lines     = 18,
 };
 
-static struct panel_generic_dpi_data dvi_panel = {
-       .name                   = "generic",
+static struct panel_dvi_platform_data dvi_panel = {
        .platform_enable        = cm_t35_panel_enable_dvi,
        .platform_disable       = cm_t35_panel_disable_dvi,
 };
@@ -251,7 +251,7 @@ static struct panel_generic_dpi_data dvi_panel = {
 static struct omap_dss_device cm_t35_dvi_device = {
        .name                   = "dvi",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
-       .driver_name            = "generic_dpi_panel",
+       .driver_name            = "dvi",
        .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
 };
index 99a4243..d9bfe54 100644 (file)
@@ -47,6 +47,7 @@
 #include <plat/usb.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-dvi.h>
 
 #include <plat/mcspi.h>
 #include <linux/input/matrix_keypad.h>
@@ -139,7 +140,7 @@ static struct regulator_consumer_supply devkit8000_vio_supply[] = {
 };
 
 static struct panel_generic_dpi_data lcd_panel = {
-       .name                   = "generic",
+       .name                   = "innolux_at070tn83",
        .platform_enable        = devkit8000_panel_enable_lcd,
        .platform_disable       = devkit8000_panel_disable_lcd,
 };
@@ -152,8 +153,7 @@ static struct omap_dss_device devkit8000_lcd_device = {
        .phy.dpi.data_lines     = 24,
 };
 
-static struct panel_generic_dpi_data dvi_panel = {
-       .name                   = "generic",
+static struct panel_dvi_platform_data dvi_panel = {
        .platform_enable        = devkit8000_panel_enable_dvi,
        .platform_disable       = devkit8000_panel_disable_dvi,
 };
@@ -161,7 +161,7 @@ static struct panel_generic_dpi_data dvi_panel = {
 static struct omap_dss_device devkit8000_dvi_device = {
        .name                   = "dvi",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
-       .driver_name            = "generic_dpi_panel",
+       .driver_name            = "dvi",
        .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
 };
@@ -267,7 +267,7 @@ static struct twl4030_gpio_platform_data devkit8000_gpio_data = {
 
 static struct regulator_consumer_supply devkit8000_vpll1_supplies[] = {
        REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
-       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi.0"),
 };
 
 /* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
index 82421a4..8fcf796 100644 (file)
@@ -39,6 +39,9 @@
 #include <plat/dma.h>
 #include <plat/gpmc.h>
 
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
+
 #include "mux.h"
 #include "control.h"
 
@@ -156,17 +159,33 @@ static struct platform_device h4_kp_device = {
        },
 };
 
-static struct platform_device h4_lcd_device = {
-       .name           = "lcd_h4",
-       .id             = -1,
-};
-
 static struct platform_device *h4_devices[] __initdata = {
        &h4_flash_device,
        &h4_kp_device,
+};
+
+static struct panel_generic_dpi_data h4_panel_data = {
+       .name                   = "h4",
+};
+
+static struct omap_dss_device h4_lcd_device = {
+       .name                   = "lcd",
+       .driver_name            = "generic_dpi_panel",
+       .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .phy.dpi.data_lines     = 16,
+       .data                   = &h4_panel_data,
+};
+
+static struct omap_dss_device *h4_dss_devices[] = {
        &h4_lcd_device,
 };
 
+static struct omap_dss_board_info h4_dss_data = {
+       .num_devices    = ARRAY_SIZE(h4_dss_devices),
+       .devices        = h4_dss_devices,
+       .default_device = &h4_lcd_device,
+};
+
 /* 2420 Sysboot setup (2430 is different) */
 static u32 get_sysboot_value(void)
 {
@@ -270,10 +289,6 @@ static void __init h4_init_flash(void)
        h4_flash_resource.end   = base + SZ_64M - 1;
 }
 
-static struct omap_lcd_config h4_lcd_config __initdata = {
-       .ctrl_name      = "internal",
-};
-
 static struct omap_usb_config h4_usb_config __initdata = {
        /* S1.10 OFF -- usb "download port"
         * usb0 switched to Mini-B port and isp1105 transceiver;
@@ -285,10 +300,6 @@ static struct omap_usb_config h4_usb_config __initdata = {
        .hmc_mode       = 0x00,         /* 0:dev|otg 1:disable 2:disable */
 };
 
-static struct omap_board_config_kernel h4_config[] __initdata = {
-       { OMAP_TAG_LCD,         &h4_lcd_config },
-};
-
 static void __init omap_h4_init_early(void)
 {
        omap2_init_common_infrastructure();
@@ -330,9 +341,6 @@ static void __init omap_h4_init(void)
 {
        omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAF);
 
-       omap_board_config = h4_config;
-       omap_board_config_size = ARRAY_SIZE(h4_config);
-
        /*
         * Make sure the serial ports are muxed on at this point.
         * You have to mux them off in device drivers later on
@@ -371,6 +379,8 @@ static void __init omap_h4_init(void)
        omap2_usbfs_init(&h4_usb_config);
        omap_serial_init();
        h4_init_flash();
+
+       omap_display_init(&h4_dss_data);
 }
 
 static void __init omap_h4_map_io(void)
index 7040352..96f9ef3 100644 (file)
@@ -32,7 +32,7 @@
 #include <plat/gpmc.h>
 #include <plat/usb.h>
 #include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-dvi.h>
 #include <plat/onenand.h>
 
 #include "mux.h"
@@ -455,16 +455,16 @@ static void igep2_disable_dvi(struct omap_dss_device *dssdev)
        gpio_direction_output(IGEP2_GPIO_DVI_PUP, 0);
 }
 
-static struct panel_generic_dpi_data dvi_panel = {
-       .name                   = "generic",
+static struct panel_dvi_platform_data dvi_panel = {
        .platform_enable        = igep2_enable_dvi,
        .platform_disable       = igep2_disable_dvi,
+       .i2c_bus_num = 3,
 };
 
 static struct omap_dss_device igep2_dvi_device = {
        .type                   = OMAP_DISPLAY_TYPE_DPI,
        .name                   = "dvi",
-       .driver_name            = "generic_dpi_panel",
+       .driver_name            = "dvi",
        .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
 };
index abe8c7e..f8f8a68 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/io.h>
 #include <linux/smsc911x.h>
 #include <linux/mmc/host.h>
+#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -43,6 +44,9 @@
 #include <plat/usb.h>
 #include <plat/gpmc-smsc911x.h>
 
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
+
 #include "board-flash.h"
 #include "mux.h"
 #include "hsmmc.h"
@@ -179,29 +183,108 @@ static inline void __init ldp_init_smsc911x(void)
        gpmc_smsc911x_init(&smsc911x_cfg);
 }
 
-static struct platform_device ldp_lcd_device = {
-       .name           = "ldp_lcd",
-       .id             = -1,
+/* LCD */
+
+static int ldp_backlight_gpio;
+static int ldp_lcd_enable_gpio;
+
+#define LCD_PANEL_RESET_GPIO           55
+#define LCD_PANEL_QVGA_GPIO            56
+
+static int ldp_panel_enable_lcd(struct omap_dss_device *dssdev)
+{
+       if (gpio_is_valid(ldp_lcd_enable_gpio))
+               gpio_direction_output(ldp_lcd_enable_gpio, 1);
+       if (gpio_is_valid(ldp_backlight_gpio))
+               gpio_direction_output(ldp_backlight_gpio, 1);
+
+       return 0;
+}
+
+static void ldp_panel_disable_lcd(struct omap_dss_device *dssdev)
+{
+       if (gpio_is_valid(ldp_lcd_enable_gpio))
+               gpio_direction_output(ldp_lcd_enable_gpio, 0);
+       if (gpio_is_valid(ldp_backlight_gpio))
+               gpio_direction_output(ldp_backlight_gpio, 0);
+}
+
+static struct panel_generic_dpi_data ldp_panel_data = {
+       .name                   = "nec_nl2432dr22-11b",
+       .platform_enable        = ldp_panel_enable_lcd,
+       .platform_disable       = ldp_panel_disable_lcd,
 };
 
-static struct omap_lcd_config ldp_lcd_config __initdata = {
-       .ctrl_name      = "internal",
+static struct omap_dss_device ldp_lcd_device = {
+       .name                   = "lcd",
+       .driver_name            = "generic_dpi_panel",
+       .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .phy.dpi.data_lines     = 18,
+       .data                   = &ldp_panel_data,
+};
+
+static struct omap_dss_device *ldp_dss_devices[] = {
+       &ldp_lcd_device,
 };
 
-static struct omap_board_config_kernel ldp_config[] __initdata = {
-       { OMAP_TAG_LCD,         &ldp_lcd_config },
+static struct omap_dss_board_info ldp_dss_data = {
+       .num_devices    = ARRAY_SIZE(ldp_dss_devices),
+       .devices        = ldp_dss_devices,
+       .default_device = &ldp_lcd_device,
 };
 
+static void __init ldp_display_init(void)
+{
+       int r;
+
+       static struct gpio gpios[] __initdata = {
+               {LCD_PANEL_RESET_GPIO, GPIOF_OUT_INIT_HIGH, "LCD RESET"},
+               {LCD_PANEL_QVGA_GPIO, GPIOF_OUT_INIT_HIGH, "LCD QVGA"},
+       };
+
+       r = gpio_request_array(gpios, ARRAY_SIZE(gpios));
+       if (r) {
+               pr_err("Cannot request LCD GPIOs, error %d\n", r);
+               return;
+       }
+
+       omap_display_init(&ldp_dss_data);
+}
+
 static void __init omap_ldp_init_early(void)
 {
        omap2_init_common_infrastructure();
        omap2_init_common_devices(NULL, NULL);
 }
 
+static int ldp_twl_gpio_setup(struct device *dev, unsigned gpio, unsigned ngpio)
+{
+       int r;
+
+       struct gpio gpios[] = {
+               {gpio + 7 , GPIOF_OUT_INIT_LOW, "LCD ENABLE"},
+               {gpio + 15, GPIOF_OUT_INIT_LOW, "LCD BACKLIGHT"},
+       };
+
+       r = gpio_request_array(gpios, ARRAY_SIZE(gpios));
+       if (r) {
+               pr_err("Cannot request LCD GPIOs, error %d\n", r);
+               ldp_backlight_gpio = -EINVAL;
+               ldp_lcd_enable_gpio = -EINVAL;
+               return r;
+       }
+
+       ldp_backlight_gpio = gpio + 15;
+       ldp_lcd_enable_gpio = gpio + 7;
+
+       return 0;
+}
+
 static struct twl4030_gpio_platform_data ldp_gpio_data = {
        .gpio_base      = OMAP_MAX_GPIO_LINES,
        .irq_base       = TWL4030_GPIO_IRQ_BASE,
        .irq_end        = TWL4030_GPIO_IRQ_END,
+       .setup          = ldp_twl_gpio_setup,
 };
 
 static struct regulator_consumer_supply ldp_vmmc1_supply[] = {
@@ -243,10 +326,31 @@ static struct regulator_init_data ldp_vaux1 = {
        .consumer_supplies              = ldp_vaux1_supplies,
 };
 
+static struct regulator_consumer_supply ldp_vpll2_supplies[] = {
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
+
+static struct regulator_init_data ldp_vpll2 = {
+       .constraints = {
+               .name                   = "VDVI",
+               .min_uV                 = 1800000,
+               .max_uV                 = 1800000,
+               .apply_uV               = true,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = ARRAY_SIZE(ldp_vpll2_supplies),
+       .consumer_supplies      = ldp_vpll2_supplies,
+};
+
 static struct twl4030_platform_data ldp_twldata = {
        /* platform_data for children goes here */
        .vmmc1          = &ldp_vmmc1,
        .vaux1          = &ldp_vaux1,
+       .vpll2          = &ldp_vpll2,
        .gpio           = &ldp_gpio_data,
        .keypad         = &ldp_kp_twl4030_data,
 };
@@ -272,7 +376,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
 };
 
 static struct platform_device *ldp_devices[] __initdata = {
-       &ldp_lcd_device,
        &ldp_gpio_keys_device,
 };
 
@@ -317,8 +420,6 @@ static struct mtd_partition ldp_nand_partitions[] = {
 static void __init omap_ldp_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
-       omap_board_config = ldp_config;
-       omap_board_config_size = ARRAY_SIZE(ldp_config);
        ldp_init_smsc911x();
        omap_i2c_init();
        platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices));
@@ -329,6 +430,7 @@ static void __init omap_ldp_init(void)
                ARRAY_SIZE(ldp_nand_partitions), ZOOM_NAND_CS, 0);
 
        omap2_hsmmc_init(mmc);
+       ldp_display_init();
 }
 
 MACHINE_START(OMAP_LDP, "OMAP LDP board")
index 1fde8a0..928933b 100644 (file)
@@ -42,7 +42,7 @@
 #include <plat/board.h>
 #include <plat/common.h>
 #include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-dvi.h>
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
@@ -203,16 +203,16 @@ static void beagle_disable_dvi(struct omap_dss_device *dssdev)
                gpio_set_value(dssdev->reset_gpio, 0);
 }
 
-static struct panel_generic_dpi_data dvi_panel = {
-       .name = "generic",
+static struct panel_dvi_platform_data dvi_panel = {
        .platform_enable = beagle_enable_dvi,
        .platform_disable = beagle_disable_dvi,
+       .i2c_bus_num = 3,
 };
 
 static struct omap_dss_device beagle_dvi_device = {
        .type = OMAP_DISPLAY_TYPE_DPI,
        .name = "dvi",
-       .driver_name = "generic_dpi_panel",
+       .driver_name = "dvi",
        .data = &dvi_panel,
        .phy.dpi.data_lines = 24,
        .reset_gpio = -EINVAL,
index 15c69a0..0d5a9e4 100644 (file)
@@ -45,7 +45,7 @@
 #include <plat/common.h>
 #include <plat/mcspi.h>
 #include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-dvi.h>
 
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
@@ -247,8 +247,7 @@ static void omap3_evm_disable_dvi(struct omap_dss_device *dssdev)
        dvi_enabled = 0;
 }
 
-static struct panel_generic_dpi_data dvi_panel = {
-       .name                   = "generic",
+static struct panel_dvi_platform_data dvi_panel = {
        .platform_enable        = omap3_evm_enable_dvi,
        .platform_disable       = omap3_evm_disable_dvi,
 };
@@ -256,7 +255,7 @@ static struct panel_generic_dpi_data dvi_panel = {
 static struct omap_dss_device omap3_evm_dvi_device = {
        .name                   = "dvi",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
-       .driver_name            = "generic_dpi_panel",
+       .driver_name            = "dvi",
        .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
 };
index ace5693..cca523e 100644 (file)
@@ -335,7 +335,7 @@ static struct regulator_consumer_supply pandora_vmmc3_supply[] = {
 static struct regulator_consumer_supply pandora_vdds_supplies[] = {
        REGULATOR_SUPPLY("vdds_sdi", "omapdss"),
        REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
-       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi.0"),
 };
 
 static struct regulator_consumer_supply pandora_vcc_lcd_supply[] = {
index ba13e1d..4732589 100644 (file)
@@ -41,6 +41,7 @@
 #include <plat/usb.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-dvi.h>
 
 #include <plat/mcspi.h>
 #include <linux/input/matrix_keypad.h>
@@ -107,39 +108,6 @@ static void __init omap3_stalker_display_init(void)
        return;
 }
 
-static int omap3_stalker_enable_lcd(struct omap_dss_device *dssdev)
-{
-       if (dvi_enabled) {
-               printk(KERN_ERR "cannot enable LCD, DVI is enabled\n");
-               return -EINVAL;
-       }
-       gpio_set_value(DSS_ENABLE_GPIO, 1);
-       gpio_set_value(LCD_PANEL_BKLIGHT_GPIO, 1);
-       lcd_enabled = 1;
-       return 0;
-}
-
-static void omap3_stalker_disable_lcd(struct omap_dss_device *dssdev)
-{
-       gpio_set_value(DSS_ENABLE_GPIO, 0);
-       gpio_set_value(LCD_PANEL_BKLIGHT_GPIO, 0);
-       lcd_enabled = 0;
-}
-
-static struct panel_generic_dpi_data lcd_panel = {
-       .name                   = "generic",
-       .platform_enable        = omap3_stalker_enable_lcd,
-       .platform_disable       = omap3_stalker_disable_lcd,
-};
-
-static struct omap_dss_device omap3_stalker_lcd_device = {
-       .name                   = "lcd",
-       .driver_name            = "generic_dpi_panel",
-       .data                   = &lcd_panel,
-       .phy.dpi.data_lines     = 24,
-       .type                   = OMAP_DISPLAY_TYPE_DPI,
-};
-
 static int omap3_stalker_enable_tv(struct omap_dss_device *dssdev)
 {
        return 0;
@@ -179,8 +147,7 @@ static void omap3_stalker_disable_dvi(struct omap_dss_device *dssdev)
        dvi_enabled = 0;
 }
 
-static struct panel_generic_dpi_data dvi_panel = {
-       .name                   = "generic",
+static struct panel_dvi_platform_data dvi_panel = {
        .platform_enable        = omap3_stalker_enable_dvi,
        .platform_disable       = omap3_stalker_disable_dvi,
 };
@@ -188,13 +155,12 @@ static struct panel_generic_dpi_data dvi_panel = {
 static struct omap_dss_device omap3_stalker_dvi_device = {
        .name                   = "dvi",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
-       .driver_name            = "generic_dpi_panel",
+       .driver_name            = "dvi",
        .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
 };
 
 static struct omap_dss_device *omap3_stalker_dss_devices[] = {
-       &omap3_stalker_lcd_device,
        &omap3_stalker_tv_device,
        &omap3_stalker_dvi_device,
 };
index 49e4bd2..abb6891 100644 (file)
@@ -104,15 +104,6 @@ static struct omap2_hsmmc_info mmc[] = {
        {}      /* Terminator */
 };
 
-static struct platform_device omap3_touchbook_lcd_device = {
-       .name           = "omap3touchbook_lcd",
-       .id             = -1,
-};
-
-static struct omap_lcd_config omap3_touchbook_lcd_config __initdata = {
-       .ctrl_name      = "internal",
-};
-
 static struct regulator_consumer_supply touchbook_vmmc1_supply[] = {
        REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
 };
@@ -165,14 +156,12 @@ static struct twl4030_gpio_platform_data touchbook_gpio_data = {
 static struct regulator_consumer_supply touchbook_vdac_supply[] = {
 {
        .supply         = "vdac",
-       .dev            = &omap3_touchbook_lcd_device.dev,
 },
 };
 
 static struct regulator_consumer_supply touchbook_vdvi_supply[] = {
 {
        .supply         = "vdvi",
-       .dev            = &omap3_touchbook_lcd_device.dev,
 },
 };
 
@@ -316,10 +305,6 @@ static struct platform_device keys_gpio = {
        },
 };
 
-static struct omap_board_config_kernel omap3_touchbook_config[] __initdata = {
-       { OMAP_TAG_LCD,         &omap3_touchbook_lcd_config },
-};
-
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
        { .reg_offset = OMAP_MUX_TERMINATOR },
@@ -339,7 +324,6 @@ static void __init omap3_touchbook_init_irq(void)
 }
 
 static struct platform_device *omap3_touchbook_devices[] __initdata = {
-       &omap3_touchbook_lcd_device,
        &leds_gpio,
        &keys_gpio,
 };
@@ -376,8 +360,6 @@ early_param("tbr", early_touchbook_revision);
 static void __init omap3_touchbook_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
-       omap_board_config = omap3_touchbook_config;
-       omap_board_config_size = ARRAY_SIZE(omap3_touchbook_config);
 
        pm_power_off = omap3_touchbook_poweroff;
 
index 683bede..ed38d8f 100644 (file)
@@ -40,7 +40,7 @@
 #include <plat/common.h>
 #include <plat/usb.h>
 #include <plat/mmc.h>
-#include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-dvi.h>
 
 #include "hsmmc.h"
 #include "control.h"
@@ -455,16 +455,16 @@ static void omap4_panda_disable_dvi(struct omap_dss_device *dssdev)
 }
 
 /* Using generic display panel */
-static struct panel_generic_dpi_data omap4_dvi_panel = {
-       .name                   = "generic",
+static struct panel_dvi_platform_data omap4_dvi_panel = {
        .platform_enable        = omap4_panda_enable_dvi,
        .platform_disable       = omap4_panda_disable_dvi,
+       .i2c_bus_num = 3,
 };
 
 struct omap_dss_device omap4_panda_dvi_device = {
        .type                   = OMAP_DISPLAY_TYPE_DPI,
        .name                   = "dvi",
-       .driver_name            = "generic_dpi_panel",
+       .driver_name            = "dvi",
        .data                   = &omap4_dvi_panel,
        .phy.dpi.data_lines     = 24,
        .reset_gpio             = PANDA_DVI_TFP410_POWER_DOWN_GPIO,
index e592fb1..ec0f60c 100644 (file)
@@ -46,6 +46,7 @@
 #include <plat/common.h>
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-dvi.h>
 #include <plat/gpmc.h>
 #include <mach/hardware.h>
 #include <plat/nand.h>
@@ -182,16 +183,16 @@ static void overo_panel_disable_dvi(struct omap_dss_device *dssdev)
        dvi_enabled = 0;
 }
 
-static struct panel_generic_dpi_data dvi_panel = {
-       .name                   = "generic",
+static struct panel_dvi_platform_data dvi_panel = {
        .platform_enable        = overo_panel_enable_dvi,
        .platform_disable       = overo_panel_disable_dvi,
+       .i2c_bus_num            = 3,
 };
 
 static struct omap_dss_device overo_dvi_device = {
        .name                   = "dvi",
        .type                   = OMAP_DISPLAY_TYPE_DPI,
-       .driver_name            = "generic_dpi_panel",
+       .driver_name            = "dvi",
        .data                   = &dvi_panel,
        .phy.dpi.data_lines     = 24,
 };
index a6c473b..faa2a8e 100644 (file)
@@ -79,29 +79,6 @@ static struct cpuidle_params rx51_cpuidle_params[] = {
        {7505 + 15274, 484329, 1},
 };
 
-static struct omap_lcd_config rx51_lcd_config = {
-       .ctrl_name      = "internal",
-};
-
-static struct omap_fbmem_config rx51_fbmem0_config = {
-       .size = 752 * 1024,
-};
-
-static struct omap_fbmem_config rx51_fbmem1_config = {
-       .size = 752 * 1024,
-};
-
-static struct omap_fbmem_config rx51_fbmem2_config = {
-       .size = 752 * 1024,
-};
-
-static struct omap_board_config_kernel rx51_config[] = {
-       { OMAP_TAG_FBMEM,       &rx51_fbmem0_config },
-       { OMAP_TAG_FBMEM,       &rx51_fbmem1_config },
-       { OMAP_TAG_FBMEM,       &rx51_fbmem2_config },
-       { OMAP_TAG_LCD,         &rx51_lcd_config },
-};
-
 static void __init rx51_init_early(void)
 {
        struct omap_sdrc_params *sdrc_params;
@@ -128,8 +105,6 @@ static struct omap_musb_board_data musb_board_data = {
 static void __init rx51_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
-       omap_board_config = rx51_config;
-       omap_board_config_size = ARRAY_SIZE(rx51_config);
        omap3_pm_init_cpuidle(rx51_cpuidle_params);
        omap_serial_init();
        usb_musb_init(&musb_board_data);
index a5b7a23..62510ec 100644 (file)
@@ -27,6 +27,8 @@
 #include <plat/omap_device.h>
 #include <plat/omap-pm.h>
 
+#include "control.h"
+
 static struct platform_device omap_display_device = {
        .name          = "omapdss",
        .id            = -1,
@@ -61,7 +63,7 @@ static const struct omap_dss_hwmod_data omap3_dss_hwmod_data[] __initdata = {
        { "dss_dispc", "omapdss_dispc", -1 },
        { "dss_rfbi", "omapdss_rfbi", -1 },
        { "dss_venc", "omapdss_venc", -1 },
-       { "dss_dsi1", "omapdss_dsi1", -1 },
+       { "dss_dsi1", "omapdss_dsi", 0 },
 };
 
 static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = {
@@ -69,11 +71,58 @@ static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = {
        { "dss_dispc", "omapdss_dispc", -1 },
        { "dss_rfbi", "omapdss_rfbi", -1 },
        { "dss_venc", "omapdss_venc", -1 },
-       { "dss_dsi1", "omapdss_dsi1", -1 },
-       { "dss_dsi2", "omapdss_dsi2", -1 },
+       { "dss_dsi1", "omapdss_dsi", 0 },
+       { "dss_dsi2", "omapdss_dsi", 1 },
        { "dss_hdmi", "omapdss_hdmi", -1 },
 };
 
+static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes)
+{
+       u32 enable_mask, enable_shift;
+       u32 pipd_mask, pipd_shift;
+       u32 reg;
+
+       if (dsi_id == 0) {
+               enable_mask = OMAP4_DSI1_LANEENABLE_MASK;
+               enable_shift = OMAP4_DSI1_LANEENABLE_SHIFT;
+               pipd_mask = OMAP4_DSI1_PIPD_MASK;
+               pipd_shift = OMAP4_DSI1_PIPD_SHIFT;
+       } else if (dsi_id == 1) {
+               enable_mask = OMAP4_DSI2_LANEENABLE_MASK;
+               enable_shift = OMAP4_DSI2_LANEENABLE_SHIFT;
+               pipd_mask = OMAP4_DSI2_PIPD_MASK;
+               pipd_shift = OMAP4_DSI2_PIPD_SHIFT;
+       } else {
+               return -ENODEV;
+       }
+
+       reg = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY);
+
+       reg &= ~enable_mask;
+       reg &= ~pipd_mask;
+
+       reg |= (lanes << enable_shift) & enable_mask;
+       reg |= (lanes << pipd_shift) & pipd_mask;
+
+       omap4_ctrl_pad_writel(reg, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY);
+
+       return 0;
+}
+
+static int omap_dsi_enable_pads(int dsi_id, unsigned lane_mask)
+{
+       if (cpu_is_omap44xx())
+               return omap4_dsi_mux_pads(dsi_id, lane_mask);
+
+       return 0;
+}
+
+static void omap_dsi_disable_pads(int dsi_id, unsigned lane_mask)
+{
+       if (cpu_is_omap44xx())
+               omap4_dsi_mux_pads(dsi_id, 0);
+}
+
 int __init omap_display_init(struct omap_dss_board_info *board_data)
 {
        int r = 0;
@@ -96,6 +145,11 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
                oh_count = ARRAY_SIZE(omap4_dss_hwmod_data);
        }
 
+       if (board_data->dsi_enable_pads == NULL)
+               board_data->dsi_enable_pads = omap_dsi_enable_pads;
+       if (board_data->dsi_disable_pads == NULL)
+               board_data->dsi_disable_pads = omap_dsi_disable_pads;
+
        pdata.board_data = board_data;
        pdata.board_data->get_context_loss_count =
                omap_pm_get_dev_context_loss_count;
index f286012..eefc379 100644 (file)
@@ -66,7 +66,7 @@
         ((pgsz) == MMU_CAM_PGSZ_4K)  ? 0xfffff000 : 0)
 
 
-static void __iommu_set_twl(struct iommu *obj, bool on)
+static void __iommu_set_twl(struct omap_iommu *obj, bool on)
 {
        u32 l = iommu_read_reg(obj, MMU_CNTL);
 
@@ -85,7 +85,7 @@ static void __iommu_set_twl(struct iommu *obj, bool on)
 }
 
 
-static int omap2_iommu_enable(struct iommu *obj)
+static int omap2_iommu_enable(struct omap_iommu *obj)
 {
        u32 l, pa;
        unsigned long timeout;
@@ -127,7 +127,7 @@ static int omap2_iommu_enable(struct iommu *obj)
        return 0;
 }
 
-static void omap2_iommu_disable(struct iommu *obj)
+static void omap2_iommu_disable(struct omap_iommu *obj)
 {
        u32 l = iommu_read_reg(obj, MMU_CNTL);
 
@@ -138,12 +138,12 @@ static void omap2_iommu_disable(struct iommu *obj)
        dev_dbg(obj->dev, "%s is shutting down\n", obj->name);
 }
 
-static void omap2_iommu_set_twl(struct iommu *obj, bool on)
+static void omap2_iommu_set_twl(struct omap_iommu *obj, bool on)
 {
        __iommu_set_twl(obj, false);
 }
 
-static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra)
+static u32 omap2_iommu_fault_isr(struct omap_iommu *obj, u32 *ra)
 {
        u32 stat, da;
        u32 errs = 0;
@@ -173,13 +173,13 @@ static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra)
        return errs;
 }
 
-static void omap2_tlb_read_cr(struct iommu *obj, struct cr_regs *cr)
+static void omap2_tlb_read_cr(struct omap_iommu *obj, struct cr_regs *cr)
 {
        cr->cam = iommu_read_reg(obj, MMU_READ_CAM);
        cr->ram = iommu_read_reg(obj, MMU_READ_RAM);
 }
 
-static void omap2_tlb_load_cr(struct iommu *obj, struct cr_regs *cr)
+static void omap2_tlb_load_cr(struct omap_iommu *obj, struct cr_regs *cr)
 {
        iommu_write_reg(obj, cr->cam | MMU_CAM_V, MMU_CAM);
        iommu_write_reg(obj, cr->ram, MMU_RAM);
@@ -193,7 +193,8 @@ static u32 omap2_cr_to_virt(struct cr_regs *cr)
        return cr->cam & mask;
 }
 
-static struct cr_regs *omap2_alloc_cr(struct iommu *obj, struct iotlb_entry *e)
+static struct cr_regs *omap2_alloc_cr(struct omap_iommu *obj,
+                                               struct iotlb_entry *e)
 {
        struct cr_regs *cr;
 
@@ -230,7 +231,8 @@ static u32 omap2_get_pte_attr(struct iotlb_entry *e)
        return attr;
 }
 
-static ssize_t omap2_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf)
+static ssize_t
+omap2_dump_cr(struct omap_iommu *obj, struct cr_regs *cr, char *buf)
 {
        char *p = buf;
 
@@ -254,7 +256,8 @@ static ssize_t omap2_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf)
                        goto out;                                       \
        } while (0)
 
-static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t len)
+static ssize_t
+omap2_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len)
 {
        char *p = buf;
 
@@ -280,7 +283,7 @@ out:
        return p - buf;
 }
 
-static void omap2_iommu_save_ctx(struct iommu *obj)
+static void omap2_iommu_save_ctx(struct omap_iommu *obj)
 {
        int i;
        u32 *p = obj->ctx;
@@ -293,7 +296,7 @@ static void omap2_iommu_save_ctx(struct iommu *obj)
        BUG_ON(p[0] != IOMMU_ARCH_VERSION);
 }
 
-static void omap2_iommu_restore_ctx(struct iommu *obj)
+static void omap2_iommu_restore_ctx(struct omap_iommu *obj)
 {
        int i;
        u32 *p = obj->ctx;
@@ -343,13 +346,13 @@ static const struct iommu_functions omap2_iommu_ops = {
 
 static int __init omap2_iommu_init(void)
 {
-       return install_iommu_arch(&omap2_iommu_ops);
+       return omap_install_iommu_arch(&omap2_iommu_ops);
 }
 module_init(omap2_iommu_init);
 
 static void __exit omap2_iommu_exit(void)
 {
-       uninstall_iommu_arch(&omap2_iommu_ops);
+       omap_uninstall_iommu_arch(&omap2_iommu_ops);
 }
 module_exit(omap2_iommu_exit);
 
index daa056e..5224357 100644 (file)
@@ -99,7 +99,7 @@ static struct regulator_init_data omap3_vdac_idata = {
 
 static struct regulator_consumer_supply omap3_vpll2_supplies[] = {
        REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
-       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi.0"),
 };
 
 static struct regulator_init_data omap3_vpll2_idata = {
@@ -235,6 +235,12 @@ static struct regulator_init_data omap4_vana_idata = {
        },
 };
 
+static struct regulator_consumer_supply omap4_vcxio_supply[] = {
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dss"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi.0"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi.1"),
+};
+
 static struct regulator_init_data omap4_vcxio_idata = {
        .constraints = {
                .min_uV                 = 1800000,
@@ -243,7 +249,10 @@ static struct regulator_init_data omap4_vcxio_idata = {
                                        | REGULATOR_MODE_STANDBY,
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
                                        | REGULATOR_CHANGE_STATUS,
+               .always_on              = true,
        },
+       .num_consumer_supplies  = ARRAY_SIZE(omap4_vcxio_supply),
+       .consumer_supplies      = omap4_vcxio_supply,
 };
 
 static struct regulator_init_data omap4_vusb_idata = {
index 4de92dc..3689ad2 100644 (file)
@@ -1597,6 +1597,7 @@ static void __init mackerel_init(void)
 
        sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device);
        sh7372_add_device_to_domain(&sh7372_a4lc, &hdmi_lcdc_device);
+       sh7372_add_device_to_domain(&sh7372_a4lc, &meram_device);
        sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device);
        sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs0_device);
        sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs1_device);
index 6f4edd3..aa59f42 100644 (file)
@@ -134,18 +134,6 @@ config OMAP_MBOX_KFIFO_SIZE
          This can also be changed at runtime (via the mbox_kfifo_size
          module parameter).
 
-config OMAP_IOMMU
-       tristate
-
-config OMAP_IOMMU_DEBUG
-       tristate "Export OMAP IOMMU internals in DebugFS"
-       depends on OMAP_IOMMU && DEBUG_FS
-       help
-         Select this to see extensive information about
-         the internal state of OMAP IOMMU in debugfs.
-
-         Say N unless you know you need this.
-
 config OMAP_IOMMU_IVA2
        bool
 
index f0233e6..9852622 100644 (file)
@@ -18,8 +18,6 @@ obj-$(CONFIG_ARCH_OMAP3) += omap_device.o
 obj-$(CONFIG_ARCH_OMAP4) += omap_device.o
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
-obj-$(CONFIG_OMAP_IOMMU) += iommu.o iovmm.o
-obj-$(CONFIG_OMAP_IOMMU_DEBUG) += iommu-debug.o
 
 obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
 obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
index 174f1b9..a1d79ee 100644 (file)
@@ -25,16 +25,17 @@ struct iotlb_entry {
        };
 };
 
-struct iommu {
+struct omap_iommu {
        const char      *name;
        struct module   *owner;
        struct clk      *clk;
        void __iomem    *regbase;
        struct device   *dev;
        void            *isr_priv;
+       struct iommu_domain *domain;
 
        unsigned int    refcount;
-       struct mutex    iommu_lock;     /* global for this whole object */
+       spinlock_t      iommu_lock;     /* global for this whole object */
 
        /*
         * We don't change iopgd for a situation like pgd for a task,
@@ -48,8 +49,6 @@ struct iommu {
        struct list_head        mmap;
        struct mutex            mmap_lock; /* protect mmap */
 
-       int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs, void *priv);
-
        void *ctx; /* iommu context: registres saved area */
        u32 da_start;
        u32 da_end;
@@ -81,25 +80,27 @@ struct iotlb_lock {
 struct iommu_functions {
        unsigned long   version;
 
-       int (*enable)(struct iommu *obj);
-       void (*disable)(struct iommu *obj);
-       void (*set_twl)(struct iommu *obj, bool on);
-       u32 (*fault_isr)(struct iommu *obj, u32 *ra);
+       int (*enable)(struct omap_iommu *obj);
+       void (*disable)(struct omap_iommu *obj);
+       void (*set_twl)(struct omap_iommu *obj, bool on);
+       u32 (*fault_isr)(struct omap_iommu *obj, u32 *ra);
 
-       void (*tlb_read_cr)(struct iommu *obj, struct cr_regs *cr);
-       void (*tlb_load_cr)(struct iommu *obj, struct cr_regs *cr);
+       void (*tlb_read_cr)(struct omap_iommu *obj, struct cr_regs *cr);
+       void (*tlb_load_cr)(struct omap_iommu *obj, struct cr_regs *cr);
 
-       struct cr_regs *(*alloc_cr)(struct iommu *obj, struct iotlb_entry *e);
+       struct cr_regs *(*alloc_cr)(struct omap_iommu *obj,
+                                                       struct iotlb_entry *e);
        int (*cr_valid)(struct cr_regs *cr);
        u32 (*cr_to_virt)(struct cr_regs *cr);
        void (*cr_to_e)(struct cr_regs *cr, struct iotlb_entry *e);
-       ssize_t (*dump_cr)(struct iommu *obj, struct cr_regs *cr, char *buf);
+       ssize_t (*dump_cr)(struct omap_iommu *obj, struct cr_regs *cr,
+                                                       char *buf);
 
        u32 (*get_pte_attr)(struct iotlb_entry *e);
 
-       void (*save_ctx)(struct iommu *obj);
-       void (*restore_ctx)(struct iommu *obj);
-       ssize_t (*dump_ctx)(struct iommu *obj, char *buf, ssize_t len);
+       void (*save_ctx)(struct omap_iommu *obj);
+       void (*restore_ctx)(struct omap_iommu *obj);
+       ssize_t (*dump_ctx)(struct omap_iommu *obj, char *buf, ssize_t len);
 };
 
 struct iommu_platform_data {
@@ -150,40 +151,31 @@ struct iommu_platform_data {
 /*
  * global functions
  */
-extern u32 iommu_arch_version(void);
-
-extern void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e);
-extern u32 iotlb_cr_to_virt(struct cr_regs *cr);
-
-extern int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e);
-extern void iommu_set_twl(struct iommu *obj, bool on);
-extern void flush_iotlb_page(struct iommu *obj, u32 da);
-extern void flush_iotlb_range(struct iommu *obj, u32 start, u32 end);
-extern void flush_iotlb_all(struct iommu *obj);
-
-extern int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e);
-extern void iopgtable_lookup_entry(struct iommu *obj, u32 da, u32 **ppgd,
-                                  u32 **ppte);
-extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova);
-
-extern int iommu_set_da_range(struct iommu *obj, u32 start, u32 end);
-extern struct iommu *iommu_get(const char *name);
-extern void iommu_put(struct iommu *obj);
-extern int iommu_set_isr(const char *name,
-                        int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs,
+extern u32 omap_iommu_arch_version(void);
+
+extern void omap_iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e);
+
+extern int
+omap_iopgtable_store_entry(struct omap_iommu *obj, struct iotlb_entry *e);
+
+extern int omap_iommu_set_isr(const char *name,
+                int (*isr)(struct omap_iommu *obj, u32 da, u32 iommu_errs,
                                    void *priv),
                         void *isr_priv);
 
-extern void iommu_save_ctx(struct iommu *obj);
-extern void iommu_restore_ctx(struct iommu *obj);
+extern void omap_iommu_save_ctx(struct omap_iommu *obj);
+extern void omap_iommu_restore_ctx(struct omap_iommu *obj);
 
-extern int install_iommu_arch(const struct iommu_functions *ops);
-extern void uninstall_iommu_arch(const struct iommu_functions *ops);
+extern int omap_install_iommu_arch(const struct iommu_functions *ops);
+extern void omap_uninstall_iommu_arch(const struct iommu_functions *ops);
 
-extern int foreach_iommu_device(void *data,
+extern int omap_foreach_iommu_device(void *data,
                                int (*fn)(struct device *, void *));
 
-extern ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t len);
-extern size_t dump_tlb_entries(struct iommu *obj, char *buf, ssize_t len);
+extern ssize_t
+omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len);
+extern size_t
+omap_dump_tlb_entries(struct omap_iommu *obj, char *buf, ssize_t len);
+struct device *omap_find_iommu_device(const char *name);
 
 #endif /* __MACH_IOMMU_H */
index 10ad05f..d4116b5 100644 (file)
 /*
  * register accessors
  */
-static inline u32 iommu_read_reg(struct iommu *obj, size_t offs)
+static inline u32 iommu_read_reg(struct omap_iommu *obj, size_t offs)
 {
        return __raw_readl(obj->regbase + offs);
 }
 
-static inline void iommu_write_reg(struct iommu *obj, u32 val, size_t offs)
+static inline void iommu_write_reg(struct omap_iommu *obj, u32 val, size_t offs)
 {
        __raw_writel(val, obj->regbase + offs);
 }
diff --git a/arch/arm/plat-omap/include/plat/iopgtable.h b/arch/arm/plat-omap/include/plat/iopgtable.h
new file mode 100644 (file)
index 0000000..66a8139
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * omap iommu: pagetable definitions
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __PLAT_OMAP_IOMMU_H
+#define __PLAT_OMAP_IOMMU_H
+
+/*
+ * "L2 table" address mask and size definitions.
+ */
+#define IOPGD_SHIFT            20
+#define IOPGD_SIZE             (1UL << IOPGD_SHIFT)
+#define IOPGD_MASK             (~(IOPGD_SIZE - 1))
+
+/*
+ * "section" address mask and size definitions.
+ */
+#define IOSECTION_SHIFT                20
+#define IOSECTION_SIZE         (1UL << IOSECTION_SHIFT)
+#define IOSECTION_MASK         (~(IOSECTION_SIZE - 1))
+
+/*
+ * "supersection" address mask and size definitions.
+ */
+#define IOSUPER_SHIFT          24
+#define IOSUPER_SIZE           (1UL << IOSUPER_SHIFT)
+#define IOSUPER_MASK           (~(IOSUPER_SIZE - 1))
+
+#define PTRS_PER_IOPGD         (1UL << (32 - IOPGD_SHIFT))
+#define IOPGD_TABLE_SIZE       (PTRS_PER_IOPGD * sizeof(u32))
+
+/*
+ * "small page" address mask and size definitions.
+ */
+#define IOPTE_SHIFT            12
+#define IOPTE_SIZE             (1UL << IOPTE_SHIFT)
+#define IOPTE_MASK             (~(IOPTE_SIZE - 1))
+
+/*
+ * "large page" address mask and size definitions.
+ */
+#define IOLARGE_SHIFT          16
+#define IOLARGE_SIZE           (1UL << IOLARGE_SHIFT)
+#define IOLARGE_MASK           (~(IOLARGE_SIZE - 1))
+
+#define PTRS_PER_IOPTE         (1UL << (IOPGD_SHIFT - IOPTE_SHIFT))
+#define IOPTE_TABLE_SIZE       (PTRS_PER_IOPTE * sizeof(u32))
+
+#define IOPAGE_MASK            IOPTE_MASK
+
+/**
+ * omap_iommu_translate() - va to pa translation
+ * @d:         omap iommu descriptor
+ * @va:                virtual address
+ * @mask:      omap iommu descriptor mask
+ *
+ * va to pa translation
+ */
+static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask)
+{
+       return (d & mask) | (va & (~mask));
+}
+
+/*
+ * some descriptor attributes.
+ */
+#define IOPGD_TABLE            (1 << 0)
+#define IOPGD_SECTION          (2 << 0)
+#define IOPGD_SUPER            (1 << 18 | 2 << 0)
+
+#define iopgd_is_table(x)      (((x) & 3) == IOPGD_TABLE)
+#define iopgd_is_section(x)    (((x) & (1 << 18 | 3)) == IOPGD_SECTION)
+#define iopgd_is_super(x)      (((x) & (1 << 18 | 3)) == IOPGD_SUPER)
+
+#define IOPTE_SMALL            (2 << 0)
+#define IOPTE_LARGE            (1 << 0)
+
+#define iopte_is_small(x)      (((x) & 2) == IOPTE_SMALL)
+#define iopte_is_large(x)      (((x) & 3) == IOPTE_LARGE)
+
+/* to find an entry in a page-table-directory */
+#define iopgd_index(da)                (((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1))
+#define iopgd_offset(obj, da)  ((obj)->iopgd + iopgd_index(da))
+
+#define iopgd_page_paddr(iopgd)        (*iopgd & ~((1 << 10) - 1))
+#define iopgd_page_vaddr(iopgd)        ((u32 *)phys_to_virt(iopgd_page_paddr(iopgd)))
+
+/* to find an entry in the second-level page table. */
+#define iopte_index(da)                (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1))
+#define iopte_offset(iopgd, da)        (iopgd_page_vaddr(iopgd) + iopte_index(da))
+
+static inline u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa,
+                                  u32 flags)
+{
+       memset(e, 0, sizeof(*e));
+
+       e->da           = da;
+       e->pa           = pa;
+       e->valid        = 1;
+       /* FIXME: add OMAP1 support */
+       e->pgsz         = flags & MMU_CAM_PGSZ_MASK;
+       e->endian       = flags & MMU_RAM_ENDIAN_MASK;
+       e->elsz         = flags & MMU_RAM_ELSZ_MASK;
+       e->mixed        = flags & MMU_RAM_MIXED_MASK;
+
+       return iopgsz_to_bytes(e->pgsz);
+}
+
+#define to_iommu(dev)                                                  \
+       (struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))
+
+#endif /* __PLAT_OMAP_IOMMU_H */
index e992b96..6af1a91 100644 (file)
 #ifndef __IOMMU_MMAP_H
 #define __IOMMU_MMAP_H
 
+#include <linux/iommu.h>
+
 struct iovm_struct {
-       struct iommu            *iommu; /* iommu object which this belongs to */
+       struct omap_iommu       *iommu; /* iommu object which this belongs to */
        u32                     da_start; /* area definition */
        u32                     da_end;
        u32                     flags; /* IOVMF_: see below */
@@ -70,20 +72,18 @@ struct iovm_struct {
 #define IOVMF_DA_FIXED         (1 << (4 + IOVMF_SW_SHIFT))
 
 
-extern struct iovm_struct *find_iovm_area(struct iommu *obj, u32 da);
-extern u32 iommu_vmap(struct iommu *obj, u32 da,
+extern struct iovm_struct *omap_find_iovm_area(struct omap_iommu *obj, u32 da);
+extern u32
+omap_iommu_vmap(struct iommu_domain *domain, struct omap_iommu *obj, u32 da,
                        const struct sg_table *sgt, u32 flags);
-extern struct sg_table *iommu_vunmap(struct iommu *obj, u32 da);
-extern u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes,
-                          u32 flags);
-extern void iommu_vfree(struct iommu *obj, const u32 da);
-extern u32 iommu_kmap(struct iommu *obj, u32 da, u32 pa, size_t bytes,
-                       u32 flags);
-extern void iommu_kunmap(struct iommu *obj, u32 da);
-extern u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes,
-                          u32 flags);
-extern void iommu_kfree(struct iommu *obj, u32 da);
-
-extern void *da_to_va(struct iommu *obj, u32 da);
+extern struct sg_table *omap_iommu_vunmap(struct iommu_domain *domain,
+                               struct omap_iommu *obj, u32 da);
+extern u32
+omap_iommu_vmalloc(struct iommu_domain *domain, struct omap_iommu *obj,
+                               u32 da, size_t bytes, u32 flags);
+extern void
+omap_iommu_vfree(struct iommu_domain *domain, struct omap_iommu *obj,
+                               const u32 da);
+extern void *omap_da_to_va(struct omap_iommu *obj, u32 da);
 
 #endif /* __IOMMU_MMAP_H */
diff --git a/arch/arm/plat-omap/iommu-debug.c b/arch/arm/plat-omap/iommu-debug.c
deleted file mode 100644 (file)
index f07cf2f..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * omap iommu: debugfs interface
- *
- * Copyright (C) 2008-2009 Nokia Corporation
- *
- * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/platform_device.h>
-#include <linux/debugfs.h>
-
-#include <plat/iommu.h>
-#include <plat/iovmm.h>
-
-#include "iopgtable.h"
-
-#define MAXCOLUMN 100 /* for short messages */
-
-static DEFINE_MUTEX(iommu_debug_lock);
-
-static struct dentry *iommu_debug_root;
-
-static ssize_t debug_read_ver(struct file *file, char __user *userbuf,
-                             size_t count, loff_t *ppos)
-{
-       u32 ver = iommu_arch_version();
-       char buf[MAXCOLUMN], *p = buf;
-
-       p += sprintf(p, "H/W version: %d.%d\n", (ver >> 4) & 0xf , ver & 0xf);
-
-       return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
-}
-
-static ssize_t debug_read_regs(struct file *file, char __user *userbuf,
-                              size_t count, loff_t *ppos)
-{
-       struct iommu *obj = file->private_data;
-       char *p, *buf;
-       ssize_t bytes;
-
-       buf = kmalloc(count, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-       p = buf;
-
-       mutex_lock(&iommu_debug_lock);
-
-       bytes = iommu_dump_ctx(obj, p, count);
-       bytes = simple_read_from_buffer(userbuf, count, ppos, buf, bytes);
-
-       mutex_unlock(&iommu_debug_lock);
-       kfree(buf);
-
-       return bytes;
-}
-
-static ssize_t debug_read_tlb(struct file *file, char __user *userbuf,
-                             size_t count, loff_t *ppos)
-{
-       struct iommu *obj = file->private_data;
-       char *p, *buf;
-       ssize_t bytes, rest;
-
-       buf = kmalloc(count, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-       p = buf;
-
-       mutex_lock(&iommu_debug_lock);
-
-       p += sprintf(p, "%8s %8s\n", "cam:", "ram:");
-       p += sprintf(p, "-----------------------------------------\n");
-       rest = count - (p - buf);
-       p += dump_tlb_entries(obj, p, rest);
-
-       bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
-
-       mutex_unlock(&iommu_debug_lock);
-       kfree(buf);
-
-       return bytes;
-}
-
-static ssize_t debug_write_pagetable(struct file *file,
-                    const char __user *userbuf, size_t count, loff_t *ppos)
-{
-       struct iotlb_entry e;
-       struct cr_regs cr;
-       int err;
-       struct iommu *obj = file->private_data;
-       char buf[MAXCOLUMN], *p = buf;
-
-       count = min(count, sizeof(buf));
-
-       mutex_lock(&iommu_debug_lock);
-       if (copy_from_user(p, userbuf, count)) {
-               mutex_unlock(&iommu_debug_lock);
-               return -EFAULT;
-       }
-
-       sscanf(p, "%x %x", &cr.cam, &cr.ram);
-       if (!cr.cam || !cr.ram) {
-               mutex_unlock(&iommu_debug_lock);
-               return -EINVAL;
-       }
-
-       iotlb_cr_to_e(&cr, &e);
-       err = iopgtable_store_entry(obj, &e);
-       if (err)
-               dev_err(obj->dev, "%s: fail to store cr\n", __func__);
-
-       mutex_unlock(&iommu_debug_lock);
-       return count;
-}
-
-#define dump_ioptable_entry_one(lv, da, val)                   \
-       ({                                                      \
-               int __err = 0;                                  \
-               ssize_t bytes;                                  \
-               const int maxcol = 22;                          \
-               const char *str = "%d: %08x %08x\n";            \
-               bytes = snprintf(p, maxcol, str, lv, da, val);  \
-               p += bytes;                                     \
-               len -= bytes;                                   \
-               if (len < maxcol)                               \
-                       __err = -ENOMEM;                        \
-               __err;                                          \
-       })
-
-static ssize_t dump_ioptable(struct iommu *obj, char *buf, ssize_t len)
-{
-       int i;
-       u32 *iopgd;
-       char *p = buf;
-
-       spin_lock(&obj->page_table_lock);
-
-       iopgd = iopgd_offset(obj, 0);
-       for (i = 0; i < PTRS_PER_IOPGD; i++, iopgd++) {
-               int j, err;
-               u32 *iopte;
-               u32 da;
-
-               if (!*iopgd)
-                       continue;
-
-               if (!(*iopgd & IOPGD_TABLE)) {
-                       da = i << IOPGD_SHIFT;
-
-                       err = dump_ioptable_entry_one(1, da, *iopgd);
-                       if (err)
-                               goto out;
-                       continue;
-               }
-
-               iopte = iopte_offset(iopgd, 0);
-
-               for (j = 0; j < PTRS_PER_IOPTE; j++, iopte++) {
-                       if (!*iopte)
-                               continue;
-
-                       da = (i << IOPGD_SHIFT) + (j << IOPTE_SHIFT);
-                       err = dump_ioptable_entry_one(2, da, *iopgd);
-                       if (err)
-                               goto out;
-               }
-       }
-out:
-       spin_unlock(&obj->page_table_lock);
-
-       return p - buf;
-}
-
-static ssize_t debug_read_pagetable(struct file *file, char __user *userbuf,
-                                   size_t count, loff_t *ppos)
-{
-       struct iommu *obj = file->private_data;
-       char *p, *buf;
-       size_t bytes;
-
-       buf = (char *)__get_free_page(GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-       p = buf;
-
-       p += sprintf(p, "L: %8s %8s\n", "da:", "pa:");
-       p += sprintf(p, "-----------------------------------------\n");
-
-       mutex_lock(&iommu_debug_lock);
-
-       bytes = PAGE_SIZE - (p - buf);
-       p += dump_ioptable(obj, p, bytes);
-
-       bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
-
-       mutex_unlock(&iommu_debug_lock);
-       free_page((unsigned long)buf);
-
-       return bytes;
-}
-
-static ssize_t debug_read_mmap(struct file *file, char __user *userbuf,
-                              size_t count, loff_t *ppos)
-{
-       struct iommu *obj = file->private_data;
-       char *p, *buf;
-       struct iovm_struct *tmp;
-       int uninitialized_var(i);
-       ssize_t bytes;
-
-       buf = (char *)__get_free_page(GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-       p = buf;
-
-       p += sprintf(p, "%-3s %-8s %-8s %6s %8s\n",
-                    "No", "start", "end", "size", "flags");
-       p += sprintf(p, "-------------------------------------------------\n");
-
-       mutex_lock(&iommu_debug_lock);
-
-       list_for_each_entry(tmp, &obj->mmap, list) {
-               size_t len;
-               const char *str = "%3d %08x-%08x %6x %8x\n";
-               const int maxcol = 39;
-
-               len = tmp->da_end - tmp->da_start;
-               p += snprintf(p, maxcol, str,
-                             i, tmp->da_start, tmp->da_end, len, tmp->flags);
-
-               if (PAGE_SIZE - (p - buf) < maxcol)
-                       break;
-               i++;
-       }
-
-       bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
-
-       mutex_unlock(&iommu_debug_lock);
-       free_page((unsigned long)buf);
-
-       return bytes;
-}
-
-static ssize_t debug_read_mem(struct file *file, char __user *userbuf,
-                             size_t count, loff_t *ppos)
-{
-       struct iommu *obj = file->private_data;
-       char *p, *buf;
-       struct iovm_struct *area;
-       ssize_t bytes;
-
-       count = min_t(ssize_t, count, PAGE_SIZE);
-
-       buf = (char *)__get_free_page(GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-       p = buf;
-
-       mutex_lock(&iommu_debug_lock);
-
-       area = find_iovm_area(obj, (u32)ppos);
-       if (IS_ERR(area)) {
-               bytes = -EINVAL;
-               goto err_out;
-       }
-       memcpy(p, area->va, count);
-       p += count;
-
-       bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
-err_out:
-       mutex_unlock(&iommu_debug_lock);
-       free_page((unsigned long)buf);
-
-       return bytes;
-}
-
-static ssize_t debug_write_mem(struct file *file, const char __user *userbuf,
-                              size_t count, loff_t *ppos)
-{
-       struct iommu *obj = file->private_data;
-       struct iovm_struct *area;
-       char *p, *buf;
-
-       count = min_t(size_t, count, PAGE_SIZE);
-
-       buf = (char *)__get_free_page(GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-       p = buf;
-
-       mutex_lock(&iommu_debug_lock);
-
-       if (copy_from_user(p, userbuf, count)) {
-               count =  -EFAULT;
-               goto err_out;
-       }
-
-       area = find_iovm_area(obj, (u32)ppos);
-       if (IS_ERR(area)) {
-               count = -EINVAL;
-               goto err_out;
-       }
-       memcpy(area->va, p, count);
-err_out:
-       mutex_unlock(&iommu_debug_lock);
-       free_page((unsigned long)buf);
-
-       return count;
-}
-
-static int debug_open_generic(struct inode *inode, struct file *file)
-{
-       file->private_data = inode->i_private;
-       return 0;
-}
-
-#define DEBUG_FOPS(name)                                               \
-       static const struct file_operations debug_##name##_fops = {     \
-               .open = debug_open_generic,                             \
-               .read = debug_read_##name,                              \
-               .write = debug_write_##name,                            \
-               .llseek = generic_file_llseek,                          \
-       };
-
-#define DEBUG_FOPS_RO(name)                                            \
-       static const struct file_operations debug_##name##_fops = {     \
-               .open = debug_open_generic,                             \
-               .read = debug_read_##name,                              \
-               .llseek = generic_file_llseek,                          \
-       };
-
-DEBUG_FOPS_RO(ver);
-DEBUG_FOPS_RO(regs);
-DEBUG_FOPS_RO(tlb);
-DEBUG_FOPS(pagetable);
-DEBUG_FOPS_RO(mmap);
-DEBUG_FOPS(mem);
-
-#define __DEBUG_ADD_FILE(attr, mode)                                   \
-       {                                                               \
-               struct dentry *dent;                                    \
-               dent = debugfs_create_file(#attr, mode, parent,         \
-                                          obj, &debug_##attr##_fops);  \
-               if (!dent)                                              \
-                       return -ENOMEM;                                 \
-       }
-
-#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 600)
-#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 400)
-
-static int iommu_debug_register(struct device *dev, void *data)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct iommu *obj = platform_get_drvdata(pdev);
-       struct dentry *d, *parent;
-
-       if (!obj || !obj->dev)
-               return -EINVAL;
-
-       d = debugfs_create_dir(obj->name, iommu_debug_root);
-       if (!d)
-               return -ENOMEM;
-       parent = d;
-
-       d = debugfs_create_u8("nr_tlb_entries", 400, parent,
-                             (u8 *)&obj->nr_tlb_entries);
-       if (!d)
-               return -ENOMEM;
-
-       DEBUG_ADD_FILE_RO(ver);
-       DEBUG_ADD_FILE_RO(regs);
-       DEBUG_ADD_FILE_RO(tlb);
-       DEBUG_ADD_FILE(pagetable);
-       DEBUG_ADD_FILE_RO(mmap);
-       DEBUG_ADD_FILE(mem);
-
-       return 0;
-}
-
-static int __init iommu_debug_init(void)
-{
-       struct dentry *d;
-       int err;
-
-       d = debugfs_create_dir("iommu", NULL);
-       if (!d)
-               return -ENOMEM;
-       iommu_debug_root = d;
-
-       err = foreach_iommu_device(d, iommu_debug_register);
-       if (err)
-               goto err_out;
-       return 0;
-
-err_out:
-       debugfs_remove_recursive(iommu_debug_root);
-       return err;
-}
-module_init(iommu_debug_init)
-
-static void __exit iommu_debugfs_exit(void)
-{
-       debugfs_remove_recursive(iommu_debug_root);
-}
-module_exit(iommu_debugfs_exit)
-
-MODULE_DESCRIPTION("omap iommu: debugfs interface");
-MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
deleted file mode 100644 (file)
index 34fc31e..0000000
+++ /dev/null
@@ -1,1102 +0,0 @@
-/*
- * omap iommu: tlb and pagetable primitives
- *
- * Copyright (C) 2008-2010 Nokia Corporation
- *
- * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>,
- *             Paul Mundt and Toshihiro Kobayashi
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-#include <asm/cacheflush.h>
-
-#include <plat/iommu.h>
-
-#include "iopgtable.h"
-
-#define for_each_iotlb_cr(obj, n, __i, cr)                             \
-       for (__i = 0;                                                   \
-            (__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true);   \
-            __i++)
-
-/* accommodate the difference between omap1 and omap2/3 */
-static const struct iommu_functions *arch_iommu;
-
-static struct platform_driver omap_iommu_driver;
-static struct kmem_cache *iopte_cachep;
-
-/**
- * install_iommu_arch - Install archtecure specific iommu functions
- * @ops:       a pointer to architecture specific iommu functions
- *
- * There are several kind of iommu algorithm(tlb, pagetable) among
- * omap series. This interface installs such an iommu algorighm.
- **/
-int install_iommu_arch(const struct iommu_functions *ops)
-{
-       if (arch_iommu)
-               return -EBUSY;
-
-       arch_iommu = ops;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(install_iommu_arch);
-
-/**
- * uninstall_iommu_arch - Uninstall archtecure specific iommu functions
- * @ops:       a pointer to architecture specific iommu functions
- *
- * This interface uninstalls the iommu algorighm installed previously.
- **/
-void uninstall_iommu_arch(const struct iommu_functions *ops)
-{
-       if (arch_iommu != ops)
-               pr_err("%s: not your arch\n", __func__);
-
-       arch_iommu = NULL;
-}
-EXPORT_SYMBOL_GPL(uninstall_iommu_arch);
-
-/**
- * iommu_save_ctx - Save registers for pm off-mode support
- * @obj:       target iommu
- **/
-void iommu_save_ctx(struct iommu *obj)
-{
-       arch_iommu->save_ctx(obj);
-}
-EXPORT_SYMBOL_GPL(iommu_save_ctx);
-
-/**
- * iommu_restore_ctx - Restore registers for pm off-mode support
- * @obj:       target iommu
- **/
-void iommu_restore_ctx(struct iommu *obj)
-{
-       arch_iommu->restore_ctx(obj);
-}
-EXPORT_SYMBOL_GPL(iommu_restore_ctx);
-
-/**
- * iommu_arch_version - Return running iommu arch version
- **/
-u32 iommu_arch_version(void)
-{
-       return arch_iommu->version;
-}
-EXPORT_SYMBOL_GPL(iommu_arch_version);
-
-static int iommu_enable(struct iommu *obj)
-{
-       int err;
-
-       if (!obj)
-               return -EINVAL;
-
-       if (!arch_iommu)
-               return -ENODEV;
-
-       clk_enable(obj->clk);
-
-       err = arch_iommu->enable(obj);
-
-       clk_disable(obj->clk);
-       return err;
-}
-
-static void iommu_disable(struct iommu *obj)
-{
-       if (!obj)
-               return;
-
-       clk_enable(obj->clk);
-
-       arch_iommu->disable(obj);
-
-       clk_disable(obj->clk);
-}
-
-/*
- *     TLB operations
- */
-void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
-{
-       BUG_ON(!cr || !e);
-
-       arch_iommu->cr_to_e(cr, e);
-}
-EXPORT_SYMBOL_GPL(iotlb_cr_to_e);
-
-static inline int iotlb_cr_valid(struct cr_regs *cr)
-{
-       if (!cr)
-               return -EINVAL;
-
-       return arch_iommu->cr_valid(cr);
-}
-
-static inline struct cr_regs *iotlb_alloc_cr(struct iommu *obj,
-                                            struct iotlb_entry *e)
-{
-       if (!e)
-               return NULL;
-
-       return arch_iommu->alloc_cr(obj, e);
-}
-
-u32 iotlb_cr_to_virt(struct cr_regs *cr)
-{
-       return arch_iommu->cr_to_virt(cr);
-}
-EXPORT_SYMBOL_GPL(iotlb_cr_to_virt);
-
-static u32 get_iopte_attr(struct iotlb_entry *e)
-{
-       return arch_iommu->get_pte_attr(e);
-}
-
-static u32 iommu_report_fault(struct iommu *obj, u32 *da)
-{
-       return arch_iommu->fault_isr(obj, da);
-}
-
-static void iotlb_lock_get(struct iommu *obj, struct iotlb_lock *l)
-{
-       u32 val;
-
-       val = iommu_read_reg(obj, MMU_LOCK);
-
-       l->base = MMU_LOCK_BASE(val);
-       l->vict = MMU_LOCK_VICT(val);
-
-}
-
-static void iotlb_lock_set(struct iommu *obj, struct iotlb_lock *l)
-{
-       u32 val;
-
-       val = (l->base << MMU_LOCK_BASE_SHIFT);
-       val |= (l->vict << MMU_LOCK_VICT_SHIFT);
-
-       iommu_write_reg(obj, val, MMU_LOCK);
-}
-
-static void iotlb_read_cr(struct iommu *obj, struct cr_regs *cr)
-{
-       arch_iommu->tlb_read_cr(obj, cr);
-}
-
-static void iotlb_load_cr(struct iommu *obj, struct cr_regs *cr)
-{
-       arch_iommu->tlb_load_cr(obj, cr);
-
-       iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
-       iommu_write_reg(obj, 1, MMU_LD_TLB);
-}
-
-/**
- * iotlb_dump_cr - Dump an iommu tlb entry into buf
- * @obj:       target iommu
- * @cr:                contents of cam and ram register
- * @buf:       output buffer
- **/
-static inline ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr,
-                                   char *buf)
-{
-       BUG_ON(!cr || !buf);
-
-       return arch_iommu->dump_cr(obj, cr, buf);
-}
-
-/* only used in iotlb iteration for-loop */
-static struct cr_regs __iotlb_read_cr(struct iommu *obj, int n)
-{
-       struct cr_regs cr;
-       struct iotlb_lock l;
-
-       iotlb_lock_get(obj, &l);
-       l.vict = n;
-       iotlb_lock_set(obj, &l);
-       iotlb_read_cr(obj, &cr);
-
-       return cr;
-}
-
-/**
- * load_iotlb_entry - Set an iommu tlb entry
- * @obj:       target iommu
- * @e:         an iommu tlb entry info
- **/
-int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
-{
-       int err = 0;
-       struct iotlb_lock l;
-       struct cr_regs *cr;
-
-       if (!obj || !obj->nr_tlb_entries || !e)
-               return -EINVAL;
-
-       clk_enable(obj->clk);
-
-       iotlb_lock_get(obj, &l);
-       if (l.base == obj->nr_tlb_entries) {
-               dev_warn(obj->dev, "%s: preserve entries full\n", __func__);
-               err = -EBUSY;
-               goto out;
-       }
-       if (!e->prsvd) {
-               int i;
-               struct cr_regs tmp;
-
-               for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, tmp)
-                       if (!iotlb_cr_valid(&tmp))
-                               break;
-
-               if (i == obj->nr_tlb_entries) {
-                       dev_dbg(obj->dev, "%s: full: no entry\n", __func__);
-                       err = -EBUSY;
-                       goto out;
-               }
-
-               iotlb_lock_get(obj, &l);
-       } else {
-               l.vict = l.base;
-               iotlb_lock_set(obj, &l);
-       }
-
-       cr = iotlb_alloc_cr(obj, e);
-       if (IS_ERR(cr)) {
-               clk_disable(obj->clk);
-               return PTR_ERR(cr);
-       }
-
-       iotlb_load_cr(obj, cr);
-       kfree(cr);
-
-       if (e->prsvd)
-               l.base++;
-       /* increment victim for next tlb load */
-       if (++l.vict == obj->nr_tlb_entries)
-               l.vict = l.base;
-       iotlb_lock_set(obj, &l);
-out:
-       clk_disable(obj->clk);
-       return err;
-}
-EXPORT_SYMBOL_GPL(load_iotlb_entry);
-
-/**
- * flush_iotlb_page - Clear an iommu tlb entry
- * @obj:       target iommu
- * @da:                iommu device virtual address
- *
- * Clear an iommu tlb entry which includes 'da' address.
- **/
-void flush_iotlb_page(struct iommu *obj, u32 da)
-{
-       int i;
-       struct cr_regs cr;
-
-       clk_enable(obj->clk);
-
-       for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr) {
-               u32 start;
-               size_t bytes;
-
-               if (!iotlb_cr_valid(&cr))
-                       continue;
-
-               start = iotlb_cr_to_virt(&cr);
-               bytes = iopgsz_to_bytes(cr.cam & 3);
-
-               if ((start <= da) && (da < start + bytes)) {
-                       dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
-                               __func__, start, da, bytes);
-                       iotlb_load_cr(obj, &cr);
-                       iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
-               }
-       }
-       clk_disable(obj->clk);
-
-       if (i == obj->nr_tlb_entries)
-               dev_dbg(obj->dev, "%s: no page for %08x\n", __func__, da);
-}
-EXPORT_SYMBOL_GPL(flush_iotlb_page);
-
-/**
- * flush_iotlb_range - Clear an iommu tlb entries
- * @obj:       target iommu
- * @start:     iommu device virtual address(start)
- * @end:       iommu device virtual address(end)
- *
- * Clear an iommu tlb entry which includes 'da' address.
- **/
-void flush_iotlb_range(struct iommu *obj, u32 start, u32 end)
-{
-       u32 da = start;
-
-       while (da < end) {
-               flush_iotlb_page(obj, da);
-               /* FIXME: Optimize for multiple page size */
-               da += IOPTE_SIZE;
-       }
-}
-EXPORT_SYMBOL_GPL(flush_iotlb_range);
-
-/**
- * flush_iotlb_all - Clear all iommu tlb entries
- * @obj:       target iommu
- **/
-void flush_iotlb_all(struct iommu *obj)
-{
-       struct iotlb_lock l;
-
-       clk_enable(obj->clk);
-
-       l.base = 0;
-       l.vict = 0;
-       iotlb_lock_set(obj, &l);
-
-       iommu_write_reg(obj, 1, MMU_GFLUSH);
-
-       clk_disable(obj->clk);
-}
-EXPORT_SYMBOL_GPL(flush_iotlb_all);
-
-/**
- * iommu_set_twl - enable/disable table walking logic
- * @obj:       target iommu
- * @on:                enable/disable
- *
- * Function used to enable/disable TWL. If one wants to work
- * exclusively with locked TLB entries and receive notifications
- * for TLB miss then call this function to disable TWL.
- */
-void iommu_set_twl(struct iommu *obj, bool on)
-{
-       clk_enable(obj->clk);
-       arch_iommu->set_twl(obj, on);
-       clk_disable(obj->clk);
-}
-EXPORT_SYMBOL_GPL(iommu_set_twl);
-
-#if defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
-
-ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t bytes)
-{
-       if (!obj || !buf)
-               return -EINVAL;
-
-       clk_enable(obj->clk);
-
-       bytes = arch_iommu->dump_ctx(obj, buf, bytes);
-
-       clk_disable(obj->clk);
-
-       return bytes;
-}
-EXPORT_SYMBOL_GPL(iommu_dump_ctx);
-
-static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs, int num)
-{
-       int i;
-       struct iotlb_lock saved;
-       struct cr_regs tmp;
-       struct cr_regs *p = crs;
-
-       clk_enable(obj->clk);
-       iotlb_lock_get(obj, &saved);
-
-       for_each_iotlb_cr(obj, num, i, tmp) {
-               if (!iotlb_cr_valid(&tmp))
-                       continue;
-               *p++ = tmp;
-       }
-
-       iotlb_lock_set(obj, &saved);
-       clk_disable(obj->clk);
-
-       return  p - crs;
-}
-
-/**
- * dump_tlb_entries - dump cr arrays to given buffer
- * @obj:       target iommu
- * @buf:       output buffer
- **/
-size_t dump_tlb_entries(struct iommu *obj, char *buf, ssize_t bytes)
-{
-       int i, num;
-       struct cr_regs *cr;
-       char *p = buf;
-
-       num = bytes / sizeof(*cr);
-       num = min(obj->nr_tlb_entries, num);
-
-       cr = kcalloc(num, sizeof(*cr), GFP_KERNEL);
-       if (!cr)
-               return 0;
-
-       num = __dump_tlb_entries(obj, cr, num);
-       for (i = 0; i < num; i++)
-               p += iotlb_dump_cr(obj, cr + i, p);
-       kfree(cr);
-
-       return p - buf;
-}
-EXPORT_SYMBOL_GPL(dump_tlb_entries);
-
-int foreach_iommu_device(void *data, int (*fn)(struct device *, void *))
-{
-       return driver_for_each_device(&omap_iommu_driver.driver,
-                                     NULL, data, fn);
-}
-EXPORT_SYMBOL_GPL(foreach_iommu_device);
-
-#endif /* CONFIG_OMAP_IOMMU_DEBUG_MODULE */
-
-/*
- *     H/W pagetable operations
- */
-static void flush_iopgd_range(u32 *first, u32 *last)
-{
-       /* FIXME: L2 cache should be taken care of if it exists */
-       do {
-               asm("mcr        p15, 0, %0, c7, c10, 1 @ flush_pgd"
-                   : : "r" (first));
-               first += L1_CACHE_BYTES / sizeof(*first);
-       } while (first <= last);
-}
-
-static void flush_iopte_range(u32 *first, u32 *last)
-{
-       /* FIXME: L2 cache should be taken care of if it exists */
-       do {
-               asm("mcr        p15, 0, %0, c7, c10, 1 @ flush_pte"
-                   : : "r" (first));
-               first += L1_CACHE_BYTES / sizeof(*first);
-       } while (first <= last);
-}
-
-static void iopte_free(u32 *iopte)
-{
-       /* Note: freed iopte's must be clean ready for re-use */
-       kmem_cache_free(iopte_cachep, iopte);
-}
-
-static u32 *iopte_alloc(struct iommu *obj, u32 *iopgd, u32 da)
-{
-       u32 *iopte;
-
-       /* a table has already existed */
-       if (*iopgd)
-               goto pte_ready;
-
-       /*
-        * do the allocation outside the page table lock
-        */
-       spin_unlock(&obj->page_table_lock);
-       iopte = kmem_cache_zalloc(iopte_cachep, GFP_KERNEL);
-       spin_lock(&obj->page_table_lock);
-
-       if (!*iopgd) {
-               if (!iopte)
-                       return ERR_PTR(-ENOMEM);
-
-               *iopgd = virt_to_phys(iopte) | IOPGD_TABLE;
-               flush_iopgd_range(iopgd, iopgd);
-
-               dev_vdbg(obj->dev, "%s: a new pte:%p\n", __func__, iopte);
-       } else {
-               /* We raced, free the reduniovant table */
-               iopte_free(iopte);
-       }
-
-pte_ready:
-       iopte = iopte_offset(iopgd, da);
-
-       dev_vdbg(obj->dev,
-                "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n",
-                __func__, da, iopgd, *iopgd, iopte, *iopte);
-
-       return iopte;
-}
-
-static int iopgd_alloc_section(struct iommu *obj, u32 da, u32 pa, u32 prot)
-{
-       u32 *iopgd = iopgd_offset(obj, da);
-
-       if ((da | pa) & ~IOSECTION_MASK) {
-               dev_err(obj->dev, "%s: %08x:%08x should aligned on %08lx\n",
-                       __func__, da, pa, IOSECTION_SIZE);
-               return -EINVAL;
-       }
-
-       *iopgd = (pa & IOSECTION_MASK) | prot | IOPGD_SECTION;
-       flush_iopgd_range(iopgd, iopgd);
-       return 0;
-}
-
-static int iopgd_alloc_super(struct iommu *obj, u32 da, u32 pa, u32 prot)
-{
-       u32 *iopgd = iopgd_offset(obj, da);
-       int i;
-
-       if ((da | pa) & ~IOSUPER_MASK) {
-               dev_err(obj->dev, "%s: %08x:%08x should aligned on %08lx\n",
-                       __func__, da, pa, IOSUPER_SIZE);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < 16; i++)
-               *(iopgd + i) = (pa & IOSUPER_MASK) | prot | IOPGD_SUPER;
-       flush_iopgd_range(iopgd, iopgd + 15);
-       return 0;
-}
-
-static int iopte_alloc_page(struct iommu *obj, u32 da, u32 pa, u32 prot)
-{
-       u32 *iopgd = iopgd_offset(obj, da);
-       u32 *iopte = iopte_alloc(obj, iopgd, da);
-
-       if (IS_ERR(iopte))
-               return PTR_ERR(iopte);
-
-       *iopte = (pa & IOPAGE_MASK) | prot | IOPTE_SMALL;
-       flush_iopte_range(iopte, iopte);
-
-       dev_vdbg(obj->dev, "%s: da:%08x pa:%08x pte:%p *pte:%08x\n",
-                __func__, da, pa, iopte, *iopte);
-
-       return 0;
-}
-
-static int iopte_alloc_large(struct iommu *obj, u32 da, u32 pa, u32 prot)
-{
-       u32 *iopgd = iopgd_offset(obj, da);
-       u32 *iopte = iopte_alloc(obj, iopgd, da);
-       int i;
-
-       if ((da | pa) & ~IOLARGE_MASK) {
-               dev_err(obj->dev, "%s: %08x:%08x should aligned on %08lx\n",
-                       __func__, da, pa, IOLARGE_SIZE);
-               return -EINVAL;
-       }
-
-       if (IS_ERR(iopte))
-               return PTR_ERR(iopte);
-
-       for (i = 0; i < 16; i++)
-               *(iopte + i) = (pa & IOLARGE_MASK) | prot | IOPTE_LARGE;
-       flush_iopte_range(iopte, iopte + 15);
-       return 0;
-}
-
-static int iopgtable_store_entry_core(struct iommu *obj, struct iotlb_entry *e)
-{
-       int (*fn)(struct iommu *, u32, u32, u32);
-       u32 prot;
-       int err;
-
-       if (!obj || !e)
-               return -EINVAL;
-
-       switch (e->pgsz) {
-       case MMU_CAM_PGSZ_16M:
-               fn = iopgd_alloc_super;
-               break;
-       case MMU_CAM_PGSZ_1M:
-               fn = iopgd_alloc_section;
-               break;
-       case MMU_CAM_PGSZ_64K:
-               fn = iopte_alloc_large;
-               break;
-       case MMU_CAM_PGSZ_4K:
-               fn = iopte_alloc_page;
-               break;
-       default:
-               fn = NULL;
-               BUG();
-               break;
-       }
-
-       prot = get_iopte_attr(e);
-
-       spin_lock(&obj->page_table_lock);
-       err = fn(obj, e->da, e->pa, prot);
-       spin_unlock(&obj->page_table_lock);
-
-       return err;
-}
-
-/**
- * iopgtable_store_entry - Make an iommu pte entry
- * @obj:       target iommu
- * @e:         an iommu tlb entry info
- **/
-int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e)
-{
-       int err;
-
-       flush_iotlb_page(obj, e->da);
-       err = iopgtable_store_entry_core(obj, e);
-#ifdef PREFETCH_IOTLB
-       if (!err)
-               load_iotlb_entry(obj, e);
-#endif
-       return err;
-}
-EXPORT_SYMBOL_GPL(iopgtable_store_entry);
-
-/**
- * iopgtable_lookup_entry - Lookup an iommu pte entry
- * @obj:       target iommu
- * @da:                iommu device virtual address
- * @ppgd:      iommu pgd entry pointer to be returned
- * @ppte:      iommu pte entry pointer to be returned
- **/
-void iopgtable_lookup_entry(struct iommu *obj, u32 da, u32 **ppgd, u32 **ppte)
-{
-       u32 *iopgd, *iopte = NULL;
-
-       iopgd = iopgd_offset(obj, da);
-       if (!*iopgd)
-               goto out;
-
-       if (iopgd_is_table(*iopgd))
-               iopte = iopte_offset(iopgd, da);
-out:
-       *ppgd = iopgd;
-       *ppte = iopte;
-}
-EXPORT_SYMBOL_GPL(iopgtable_lookup_entry);
-
-static size_t iopgtable_clear_entry_core(struct iommu *obj, u32 da)
-{
-       size_t bytes;
-       u32 *iopgd = iopgd_offset(obj, da);
-       int nent = 1;
-
-       if (!*iopgd)
-               return 0;
-
-       if (iopgd_is_table(*iopgd)) {
-               int i;
-               u32 *iopte = iopte_offset(iopgd, da);
-
-               bytes = IOPTE_SIZE;
-               if (*iopte & IOPTE_LARGE) {
-                       nent *= 16;
-                       /* rewind to the 1st entry */
-                       iopte = iopte_offset(iopgd, (da & IOLARGE_MASK));
-               }
-               bytes *= nent;
-               memset(iopte, 0, nent * sizeof(*iopte));
-               flush_iopte_range(iopte, iopte + (nent - 1) * sizeof(*iopte));
-
-               /*
-                * do table walk to check if this table is necessary or not
-                */
-               iopte = iopte_offset(iopgd, 0);
-               for (i = 0; i < PTRS_PER_IOPTE; i++)
-                       if (iopte[i])
-                               goto out;
-
-               iopte_free(iopte);
-               nent = 1; /* for the next L1 entry */
-       } else {
-               bytes = IOPGD_SIZE;
-               if ((*iopgd & IOPGD_SUPER) == IOPGD_SUPER) {
-                       nent *= 16;
-                       /* rewind to the 1st entry */
-                       iopgd = iopgd_offset(obj, (da & IOSUPER_MASK));
-               }
-               bytes *= nent;
-       }
-       memset(iopgd, 0, nent * sizeof(*iopgd));
-       flush_iopgd_range(iopgd, iopgd + (nent - 1) * sizeof(*iopgd));
-out:
-       return bytes;
-}
-
-/**
- * iopgtable_clear_entry - Remove an iommu pte entry
- * @obj:       target iommu
- * @da:                iommu device virtual address
- **/
-size_t iopgtable_clear_entry(struct iommu *obj, u32 da)
-{
-       size_t bytes;
-
-       spin_lock(&obj->page_table_lock);
-
-       bytes = iopgtable_clear_entry_core(obj, da);
-       flush_iotlb_page(obj, da);
-
-       spin_unlock(&obj->page_table_lock);
-
-       return bytes;
-}
-EXPORT_SYMBOL_GPL(iopgtable_clear_entry);
-
-static void iopgtable_clear_entry_all(struct iommu *obj)
-{
-       int i;
-
-       spin_lock(&obj->page_table_lock);
-
-       for (i = 0; i < PTRS_PER_IOPGD; i++) {
-               u32 da;
-               u32 *iopgd;
-
-               da = i << IOPGD_SHIFT;
-               iopgd = iopgd_offset(obj, da);
-
-               if (!*iopgd)
-                       continue;
-
-               if (iopgd_is_table(*iopgd))
-                       iopte_free(iopte_offset(iopgd, 0));
-
-               *iopgd = 0;
-               flush_iopgd_range(iopgd, iopgd);
-       }
-
-       flush_iotlb_all(obj);
-
-       spin_unlock(&obj->page_table_lock);
-}
-
-/*
- *     Device IOMMU generic operations
- */
-static irqreturn_t iommu_fault_handler(int irq, void *data)
-{
-       u32 da, errs;
-       u32 *iopgd, *iopte;
-       struct iommu *obj = data;
-
-       if (!obj->refcount)
-               return IRQ_NONE;
-
-       clk_enable(obj->clk);
-       errs = iommu_report_fault(obj, &da);
-       clk_disable(obj->clk);
-       if (errs == 0)
-               return IRQ_HANDLED;
-
-       /* Fault callback or TLB/PTE Dynamic loading */
-       if (obj->isr && !obj->isr(obj, da, errs, obj->isr_priv))
-               return IRQ_HANDLED;
-
-       iommu_disable(obj);
-
-       iopgd = iopgd_offset(obj, da);
-
-       if (!iopgd_is_table(*iopgd)) {
-               dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p "
-                       "*pgd:px%08x\n", obj->name, errs, da, iopgd, *iopgd);
-               return IRQ_NONE;
-       }
-
-       iopte = iopte_offset(iopgd, da);
-
-       dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x "
-               "pte:0x%p *pte:0x%08x\n", obj->name, errs, da, iopgd, *iopgd,
-               iopte, *iopte);
-
-       return IRQ_NONE;
-}
-
-static int device_match_by_alias(struct device *dev, void *data)
-{
-       struct iommu *obj = to_iommu(dev);
-       const char *name = data;
-
-       pr_debug("%s: %s %s\n", __func__, obj->name, name);
-
-       return strcmp(obj->name, name) == 0;
-}
-
-/**
- * iommu_set_da_range - Set a valid device address range
- * @obj:               target iommu
- * @start              Start of valid range
- * @end                        End of valid range
- **/
-int iommu_set_da_range(struct iommu *obj, u32 start, u32 end)
-{
-
-       if (!obj)
-               return -EFAULT;
-
-       if (end < start || !PAGE_ALIGN(start | end))
-               return -EINVAL;
-
-       obj->da_start = start;
-       obj->da_end = end;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(iommu_set_da_range);
-
-/**
- * iommu_get - Get iommu handler
- * @name:      target iommu name
- **/
-struct iommu *iommu_get(const char *name)
-{
-       int err = -ENOMEM;
-       struct device *dev;
-       struct iommu *obj;
-
-       dev = driver_find_device(&omap_iommu_driver.driver, NULL, (void *)name,
-                                device_match_by_alias);
-       if (!dev)
-               return ERR_PTR(-ENODEV);
-
-       obj = to_iommu(dev);
-
-       mutex_lock(&obj->iommu_lock);
-
-       if (obj->refcount++ == 0) {
-               err = iommu_enable(obj);
-               if (err)
-                       goto err_enable;
-               flush_iotlb_all(obj);
-       }
-
-       if (!try_module_get(obj->owner))
-               goto err_module;
-
-       mutex_unlock(&obj->iommu_lock);
-
-       dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name);
-       return obj;
-
-err_module:
-       if (obj->refcount == 1)
-               iommu_disable(obj);
-err_enable:
-       obj->refcount--;
-       mutex_unlock(&obj->iommu_lock);
-       return ERR_PTR(err);
-}
-EXPORT_SYMBOL_GPL(iommu_get);
-
-/**
- * iommu_put - Put back iommu handler
- * @obj:       target iommu
- **/
-void iommu_put(struct iommu *obj)
-{
-       if (!obj || IS_ERR(obj))
-               return;
-
-       mutex_lock(&obj->iommu_lock);
-
-       if (--obj->refcount == 0)
-               iommu_disable(obj);
-
-       module_put(obj->owner);
-
-       mutex_unlock(&obj->iommu_lock);
-
-       dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name);
-}
-EXPORT_SYMBOL_GPL(iommu_put);
-
-int iommu_set_isr(const char *name,
-                 int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs,
-                            void *priv),
-                 void *isr_priv)
-{
-       struct device *dev;
-       struct iommu *obj;
-
-       dev = driver_find_device(&omap_iommu_driver.driver, NULL, (void *)name,
-                                device_match_by_alias);
-       if (!dev)
-               return -ENODEV;
-
-       obj = to_iommu(dev);
-       mutex_lock(&obj->iommu_lock);
-       if (obj->refcount != 0) {
-               mutex_unlock(&obj->iommu_lock);
-               return -EBUSY;
-       }
-       obj->isr = isr;
-       obj->isr_priv = isr_priv;
-       mutex_unlock(&obj->iommu_lock);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(iommu_set_isr);
-
-/*
- *     OMAP Device MMU(IOMMU) detection
- */
-static int __devinit omap_iommu_probe(struct platform_device *pdev)
-{
-       int err = -ENODEV;
-       void *p;
-       int irq;
-       struct iommu *obj;
-       struct resource *res;
-       struct iommu_platform_data *pdata = pdev->dev.platform_data;
-
-       if (pdev->num_resources != 2)
-               return -EINVAL;
-
-       obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
-       if (!obj)
-               return -ENOMEM;
-
-       obj->clk = clk_get(&pdev->dev, pdata->clk_name);
-       if (IS_ERR(obj->clk))
-               goto err_clk;
-
-       obj->nr_tlb_entries = pdata->nr_tlb_entries;
-       obj->name = pdata->name;
-       obj->dev = &pdev->dev;
-       obj->ctx = (void *)obj + sizeof(*obj);
-       obj->da_start = pdata->da_start;
-       obj->da_end = pdata->da_end;
-
-       mutex_init(&obj->iommu_lock);
-       mutex_init(&obj->mmap_lock);
-       spin_lock_init(&obj->page_table_lock);
-       INIT_LIST_HEAD(&obj->mmap);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               err = -ENODEV;
-               goto err_mem;
-       }
-
-       res = request_mem_region(res->start, resource_size(res),
-                                dev_name(&pdev->dev));
-       if (!res) {
-               err = -EIO;
-               goto err_mem;
-       }
-
-       obj->regbase = ioremap(res->start, resource_size(res));
-       if (!obj->regbase) {
-               err = -ENOMEM;
-               goto err_ioremap;
-       }
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               err = -ENODEV;
-               goto err_irq;
-       }
-       err = request_irq(irq, iommu_fault_handler, IRQF_SHARED,
-                         dev_name(&pdev->dev), obj);
-       if (err < 0)
-               goto err_irq;
-       platform_set_drvdata(pdev, obj);
-
-       p = (void *)__get_free_pages(GFP_KERNEL, get_order(IOPGD_TABLE_SIZE));
-       if (!p) {
-               err = -ENOMEM;
-               goto err_pgd;
-       }
-       memset(p, 0, IOPGD_TABLE_SIZE);
-       clean_dcache_area(p, IOPGD_TABLE_SIZE);
-       obj->iopgd = p;
-
-       BUG_ON(!IS_ALIGNED((unsigned long)obj->iopgd, IOPGD_TABLE_SIZE));
-
-       dev_info(&pdev->dev, "%s registered\n", obj->name);
-       return 0;
-
-err_pgd:
-       free_irq(irq, obj);
-err_irq:
-       iounmap(obj->regbase);
-err_ioremap:
-       release_mem_region(res->start, resource_size(res));
-err_mem:
-       clk_put(obj->clk);
-err_clk:
-       kfree(obj);
-       return err;
-}
-
-static int __devexit omap_iommu_remove(struct platform_device *pdev)
-{
-       int irq;
-       struct resource *res;
-       struct iommu *obj = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-
-       iopgtable_clear_entry_all(obj);
-       free_pages((unsigned long)obj->iopgd, get_order(IOPGD_TABLE_SIZE));
-
-       irq = platform_get_irq(pdev, 0);
-       free_irq(irq, obj);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-       iounmap(obj->regbase);
-
-       clk_put(obj->clk);
-       dev_info(&pdev->dev, "%s removed\n", obj->name);
-       kfree(obj);
-       return 0;
-}
-
-static struct platform_driver omap_iommu_driver = {
-       .probe  = omap_iommu_probe,
-       .remove = __devexit_p(omap_iommu_remove),
-       .driver = {
-               .name   = "omap-iommu",
-       },
-};
-
-static void iopte_cachep_ctor(void *iopte)
-{
-       clean_dcache_area(iopte, IOPTE_TABLE_SIZE);
-}
-
-static int __init omap_iommu_init(void)
-{
-       struct kmem_cache *p;
-       const unsigned long flags = SLAB_HWCACHE_ALIGN;
-       size_t align = 1 << 10; /* L2 pagetable alignement */
-
-       p = kmem_cache_create("iopte_cache", IOPTE_TABLE_SIZE, align, flags,
-                             iopte_cachep_ctor);
-       if (!p)
-               return -ENOMEM;
-       iopte_cachep = p;
-
-       return platform_driver_register(&omap_iommu_driver);
-}
-module_init(omap_iommu_init);
-
-static void __exit omap_iommu_exit(void)
-{
-       kmem_cache_destroy(iopte_cachep);
-
-       platform_driver_unregister(&omap_iommu_driver);
-}
-module_exit(omap_iommu_exit);
-
-MODULE_DESCRIPTION("omap iommu: tlb and pagetable primitives");
-MODULE_ALIAS("platform:omap-iommu");
-MODULE_AUTHOR("Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/plat-omap/iopgtable.h b/arch/arm/plat-omap/iopgtable.h
deleted file mode 100644 (file)
index c3e93bb..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * omap iommu: pagetable definitions
- *
- * Copyright (C) 2008-2010 Nokia Corporation
- *
- * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __PLAT_OMAP_IOMMU_H
-#define __PLAT_OMAP_IOMMU_H
-
-/*
- * "L2 table" address mask and size definitions.
- */
-#define IOPGD_SHIFT            20
-#define IOPGD_SIZE             (1UL << IOPGD_SHIFT)
-#define IOPGD_MASK             (~(IOPGD_SIZE - 1))
-
-/*
- * "section" address mask and size definitions.
- */
-#define IOSECTION_SHIFT                20
-#define IOSECTION_SIZE         (1UL << IOSECTION_SHIFT)
-#define IOSECTION_MASK         (~(IOSECTION_SIZE - 1))
-
-/*
- * "supersection" address mask and size definitions.
- */
-#define IOSUPER_SHIFT          24
-#define IOSUPER_SIZE           (1UL << IOSUPER_SHIFT)
-#define IOSUPER_MASK           (~(IOSUPER_SIZE - 1))
-
-#define PTRS_PER_IOPGD         (1UL << (32 - IOPGD_SHIFT))
-#define IOPGD_TABLE_SIZE       (PTRS_PER_IOPGD * sizeof(u32))
-
-/*
- * "small page" address mask and size definitions.
- */
-#define IOPTE_SHIFT            12
-#define IOPTE_SIZE             (1UL << IOPTE_SHIFT)
-#define IOPTE_MASK             (~(IOPTE_SIZE - 1))
-
-/*
- * "large page" address mask and size definitions.
- */
-#define IOLARGE_SHIFT          16
-#define IOLARGE_SIZE           (1UL << IOLARGE_SHIFT)
-#define IOLARGE_MASK           (~(IOLARGE_SIZE - 1))
-
-#define PTRS_PER_IOPTE         (1UL << (IOPGD_SHIFT - IOPTE_SHIFT))
-#define IOPTE_TABLE_SIZE       (PTRS_PER_IOPTE * sizeof(u32))
-
-#define IOPAGE_MASK            IOPTE_MASK
-
-/*
- * some descriptor attributes.
- */
-#define IOPGD_TABLE            (1 << 0)
-#define IOPGD_SECTION          (2 << 0)
-#define IOPGD_SUPER            (1 << 18 | 2 << 0)
-
-#define iopgd_is_table(x)      (((x) & 3) == IOPGD_TABLE)
-
-#define IOPTE_SMALL            (2 << 0)
-#define IOPTE_LARGE            (1 << 0)
-
-/* to find an entry in a page-table-directory */
-#define iopgd_index(da)                (((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1))
-#define iopgd_offset(obj, da)  ((obj)->iopgd + iopgd_index(da))
-
-#define iopgd_page_paddr(iopgd)        (*iopgd & ~((1 << 10) - 1))
-#define iopgd_page_vaddr(iopgd)        ((u32 *)phys_to_virt(iopgd_page_paddr(iopgd)))
-
-/* to find an entry in the second-level page table. */
-#define iopte_index(da)                (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1))
-#define iopte_offset(iopgd, da)        (iopgd_page_vaddr(iopgd) + iopte_index(da))
-
-static inline u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa,
-                                  u32 flags)
-{
-       memset(e, 0, sizeof(*e));
-
-       e->da           = da;
-       e->pa           = pa;
-       e->valid        = 1;
-       /* FIXME: add OMAP1 support */
-       e->pgsz         = flags & MMU_CAM_PGSZ_MASK;
-       e->endian       = flags & MMU_RAM_ENDIAN_MASK;
-       e->elsz         = flags & MMU_RAM_ELSZ_MASK;
-       e->mixed        = flags & MMU_RAM_MIXED_MASK;
-
-       return iopgsz_to_bytes(e->pgsz);
-}
-
-#define to_iommu(dev)                                                  \
-       (struct iommu *)platform_get_drvdata(to_platform_device(dev))
-
-#endif /* __PLAT_OMAP_IOMMU_H */
diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c
deleted file mode 100644 (file)
index 79e7fed..0000000
+++ /dev/null
@@ -1,904 +0,0 @@
-/*
- * omap iommu: simple virtual address space management
- *
- * Copyright (C) 2008-2009 Nokia Corporation
- *
- * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/device.h>
-#include <linux/scatterlist.h>
-
-#include <asm/cacheflush.h>
-#include <asm/mach/map.h>
-
-#include <plat/iommu.h>
-#include <plat/iovmm.h>
-
-#include "iopgtable.h"
-
-/*
- * A device driver needs to create address mappings between:
- *
- * - iommu/device address
- * - physical address
- * - mpu virtual address
- *
- * There are 4 possible patterns for them:
- *
- *    |iova/                     mapping               iommu_          page
- *    | da     pa      va      (d)-(p)-(v)             function        type
- *  ---------------------------------------------------------------------------
- *  1 | c      c       c        1 - 1 - 1        _kmap() / _kunmap()   s
- *  2 | c      c,a     c        1 - 1 - 1      _kmalloc()/ _kfree()    s
- *  3 | c      d       c        1 - n - 1        _vmap() / _vunmap()   s
- *  4 | c      d,a     c        1 - n - 1      _vmalloc()/ _vfree()    n*
- *
- *
- *     'iova': device iommu virtual address
- *     'da':   alias of 'iova'
- *     'pa':   physical address
- *     'va':   mpu virtual address
- *
- *     'c':    contiguous memory area
- *     'd':    discontiguous memory area
- *     'a':    anonymous memory allocation
- *     '()':   optional feature
- *
- *     'n':    a normal page(4KB) size is used.
- *     's':    multiple iommu superpage(16MB, 1MB, 64KB, 4KB) size is used.
- *
- *     '*':    not yet, but feasible.
- */
-
-static struct kmem_cache *iovm_area_cachep;
-
-/* return total bytes of sg buffers */
-static size_t sgtable_len(const struct sg_table *sgt)
-{
-       unsigned int i, total = 0;
-       struct scatterlist *sg;
-
-       if (!sgt)
-               return 0;
-
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               size_t bytes;
-
-               bytes = sg->length;
-
-               if (!iopgsz_ok(bytes)) {
-                       pr_err("%s: sg[%d] not iommu pagesize(%x)\n",
-                              __func__, i, bytes);
-                       return 0;
-               }
-
-               total += bytes;
-       }
-
-       return total;
-}
-#define sgtable_ok(x)  (!!sgtable_len(x))
-
-static unsigned max_alignment(u32 addr)
-{
-       int i;
-       unsigned pagesize[] = { SZ_16M, SZ_1M, SZ_64K, SZ_4K, };
-       for (i = 0; i < ARRAY_SIZE(pagesize) && addr & (pagesize[i] - 1); i++)
-               ;
-       return (i < ARRAY_SIZE(pagesize)) ? pagesize[i] : 0;
-}
-
-/*
- * calculate the optimal number sg elements from total bytes based on
- * iommu superpages
- */
-static unsigned sgtable_nents(size_t bytes, u32 da, u32 pa)
-{
-       unsigned nr_entries = 0, ent_sz;
-
-       if (!IS_ALIGNED(bytes, PAGE_SIZE)) {
-               pr_err("%s: wrong size %08x\n", __func__, bytes);
-               return 0;
-       }
-
-       while (bytes) {
-               ent_sz = max_alignment(da | pa);
-               ent_sz = min_t(unsigned, ent_sz, iopgsz_max(bytes));
-               nr_entries++;
-               da += ent_sz;
-               pa += ent_sz;
-               bytes -= ent_sz;
-       }
-
-       return nr_entries;
-}
-
-/* allocate and initialize sg_table header(a kind of 'superblock') */
-static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags,
-                                                       u32 da, u32 pa)
-{
-       unsigned int nr_entries;
-       int err;
-       struct sg_table *sgt;
-
-       if (!bytes)
-               return ERR_PTR(-EINVAL);
-
-       if (!IS_ALIGNED(bytes, PAGE_SIZE))
-               return ERR_PTR(-EINVAL);
-
-       if (flags & IOVMF_LINEAR) {
-               nr_entries = sgtable_nents(bytes, da, pa);
-               if (!nr_entries)
-                       return ERR_PTR(-EINVAL);
-       } else
-               nr_entries =  bytes / PAGE_SIZE;
-
-       sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
-       if (!sgt)
-               return ERR_PTR(-ENOMEM);
-
-       err = sg_alloc_table(sgt, nr_entries, GFP_KERNEL);
-       if (err) {
-               kfree(sgt);
-               return ERR_PTR(err);
-       }
-
-       pr_debug("%s: sgt:%p(%d entries)\n", __func__, sgt, nr_entries);
-
-       return sgt;
-}
-
-/* free sg_table header(a kind of superblock) */
-static void sgtable_free(struct sg_table *sgt)
-{
-       if (!sgt)
-               return;
-
-       sg_free_table(sgt);
-       kfree(sgt);
-
-       pr_debug("%s: sgt:%p\n", __func__, sgt);
-}
-
-/* map 'sglist' to a contiguous mpu virtual area and return 'va' */
-static void *vmap_sg(const struct sg_table *sgt)
-{
-       u32 va;
-       size_t total;
-       unsigned int i;
-       struct scatterlist *sg;
-       struct vm_struct *new;
-       const struct mem_type *mtype;
-
-       mtype = get_mem_type(MT_DEVICE);
-       if (!mtype)
-               return ERR_PTR(-EINVAL);
-
-       total = sgtable_len(sgt);
-       if (!total)
-               return ERR_PTR(-EINVAL);
-
-       new = __get_vm_area(total, VM_IOREMAP, VMALLOC_START, VMALLOC_END);
-       if (!new)
-               return ERR_PTR(-ENOMEM);
-       va = (u32)new->addr;
-
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               size_t bytes;
-               u32 pa;
-               int err;
-
-               pa = sg_phys(sg);
-               bytes = sg->length;
-
-               BUG_ON(bytes != PAGE_SIZE);
-
-               err = ioremap_page(va,  pa, mtype);
-               if (err)
-                       goto err_out;
-
-               va += bytes;
-       }
-
-       flush_cache_vmap((unsigned long)new->addr,
-                               (unsigned long)(new->addr + total));
-       return new->addr;
-
-err_out:
-       WARN_ON(1); /* FIXME: cleanup some mpu mappings */
-       vunmap(new->addr);
-       return ERR_PTR(-EAGAIN);
-}
-
-static inline void vunmap_sg(const void *va)
-{
-       vunmap(va);
-}
-
-static struct iovm_struct *__find_iovm_area(struct iommu *obj, const u32 da)
-{
-       struct iovm_struct *tmp;
-
-       list_for_each_entry(tmp, &obj->mmap, list) {
-               if ((da >= tmp->da_start) && (da < tmp->da_end)) {
-                       size_t len;
-
-                       len = tmp->da_end - tmp->da_start;
-
-                       dev_dbg(obj->dev, "%s: %08x-%08x-%08x(%x) %08x\n",
-                               __func__, tmp->da_start, da, tmp->da_end, len,
-                               tmp->flags);
-
-                       return tmp;
-               }
-       }
-
-       return NULL;
-}
-
-/**
- * find_iovm_area  -  find iovma which includes @da
- * @da:                iommu device virtual address
- *
- * Find the existing iovma starting at @da
- */
-struct iovm_struct *find_iovm_area(struct iommu *obj, u32 da)
-{
-       struct iovm_struct *area;
-
-       mutex_lock(&obj->mmap_lock);
-       area = __find_iovm_area(obj, da);
-       mutex_unlock(&obj->mmap_lock);
-
-       return area;
-}
-EXPORT_SYMBOL_GPL(find_iovm_area);
-
-/*
- * This finds the hole(area) which fits the requested address and len
- * in iovmas mmap, and returns the new allocated iovma.
- */
-static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da,
-                                          size_t bytes, u32 flags)
-{
-       struct iovm_struct *new, *tmp;
-       u32 start, prev_end, alignment;
-
-       if (!obj || !bytes)
-               return ERR_PTR(-EINVAL);
-
-       start = da;
-       alignment = PAGE_SIZE;
-
-       if (~flags & IOVMF_DA_FIXED) {
-               /* Don't map address 0 */
-               start = obj->da_start ? obj->da_start : alignment;
-
-               if (flags & IOVMF_LINEAR)
-                       alignment = iopgsz_max(bytes);
-               start = roundup(start, alignment);
-       } else if (start < obj->da_start || start > obj->da_end ||
-                                       obj->da_end - start < bytes) {
-               return ERR_PTR(-EINVAL);
-       }
-
-       tmp = NULL;
-       if (list_empty(&obj->mmap))
-               goto found;
-
-       prev_end = 0;
-       list_for_each_entry(tmp, &obj->mmap, list) {
-
-               if (prev_end > start)
-                       break;
-
-               if (tmp->da_start > start && (tmp->da_start - start) >= bytes)
-                       goto found;
-
-               if (tmp->da_end >= start && ~flags & IOVMF_DA_FIXED)
-                       start = roundup(tmp->da_end + 1, alignment);
-
-               prev_end = tmp->da_end;
-       }
-
-       if ((start >= prev_end) && (obj->da_end - start >= bytes))
-               goto found;
-
-       dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n",
-               __func__, da, bytes, flags);
-
-       return ERR_PTR(-EINVAL);
-
-found:
-       new = kmem_cache_zalloc(iovm_area_cachep, GFP_KERNEL);
-       if (!new)
-               return ERR_PTR(-ENOMEM);
-
-       new->iommu = obj;
-       new->da_start = start;
-       new->da_end = start + bytes;
-       new->flags = flags;
-
-       /*
-        * keep ascending order of iovmas
-        */
-       if (tmp)
-               list_add_tail(&new->list, &tmp->list);
-       else
-               list_add(&new->list, &obj->mmap);
-
-       dev_dbg(obj->dev, "%s: found %08x-%08x-%08x(%x) %08x\n",
-               __func__, new->da_start, start, new->da_end, bytes, flags);
-
-       return new;
-}
-
-static void free_iovm_area(struct iommu *obj, struct iovm_struct *area)
-{
-       size_t bytes;
-
-       BUG_ON(!obj || !area);
-
-       bytes = area->da_end - area->da_start;
-
-       dev_dbg(obj->dev, "%s: %08x-%08x(%x) %08x\n",
-               __func__, area->da_start, area->da_end, bytes, area->flags);
-
-       list_del(&area->list);
-       kmem_cache_free(iovm_area_cachep, area);
-}
-
-/**
- * da_to_va - convert (d) to (v)
- * @obj:       objective iommu
- * @da:                iommu device virtual address
- * @va:                mpu virtual address
- *
- * Returns mpu virtual addr which corresponds to a given device virtual addr
- */
-void *da_to_va(struct iommu *obj, u32 da)
-{
-       void *va = NULL;
-       struct iovm_struct *area;
-
-       mutex_lock(&obj->mmap_lock);
-
-       area = __find_iovm_area(obj, da);
-       if (!area) {
-               dev_dbg(obj->dev, "%s: no da area(%08x)\n", __func__, da);
-               goto out;
-       }
-       va = area->va;
-out:
-       mutex_unlock(&obj->mmap_lock);
-
-       return va;
-}
-EXPORT_SYMBOL_GPL(da_to_va);
-
-static void sgtable_fill_vmalloc(struct sg_table *sgt, void *_va)
-{
-       unsigned int i;
-       struct scatterlist *sg;
-       void *va = _va;
-       void *va_end;
-
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               struct page *pg;
-               const size_t bytes = PAGE_SIZE;
-
-               /*
-                * iommu 'superpage' isn't supported with 'iommu_vmalloc()'
-                */
-               pg = vmalloc_to_page(va);
-               BUG_ON(!pg);
-               sg_set_page(sg, pg, bytes, 0);
-
-               va += bytes;
-       }
-
-       va_end = _va + PAGE_SIZE * i;
-}
-
-static inline void sgtable_drain_vmalloc(struct sg_table *sgt)
-{
-       /*
-        * Actually this is not necessary at all, just exists for
-        * consistency of the code readability.
-        */
-       BUG_ON(!sgt);
-}
-
-static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, u32 da,
-                                                               size_t len)
-{
-       unsigned int i;
-       struct scatterlist *sg;
-
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               unsigned bytes;
-
-               bytes = max_alignment(da | pa);
-               bytes = min_t(unsigned, bytes, iopgsz_max(len));
-
-               BUG_ON(!iopgsz_ok(bytes));
-
-               sg_set_buf(sg, phys_to_virt(pa), bytes);
-               /*
-                * 'pa' is cotinuous(linear).
-                */
-               pa += bytes;
-               da += bytes;
-               len -= bytes;
-       }
-       BUG_ON(len);
-}
-
-static inline void sgtable_drain_kmalloc(struct sg_table *sgt)
-{
-       /*
-        * Actually this is not necessary at all, just exists for
-        * consistency of the code readability
-        */
-       BUG_ON(!sgt);
-}
-
-/* create 'da' <-> 'pa' mapping from 'sgt' */
-static int map_iovm_area(struct iommu *obj, struct iovm_struct *new,
-                        const struct sg_table *sgt, u32 flags)
-{
-       int err;
-       unsigned int i, j;
-       struct scatterlist *sg;
-       u32 da = new->da_start;
-
-       if (!obj || !sgt)
-               return -EINVAL;
-
-       BUG_ON(!sgtable_ok(sgt));
-
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               u32 pa;
-               int pgsz;
-               size_t bytes;
-               struct iotlb_entry e;
-
-               pa = sg_phys(sg);
-               bytes = sg->length;
-
-               flags &= ~IOVMF_PGSZ_MASK;
-               pgsz = bytes_to_iopgsz(bytes);
-               if (pgsz < 0)
-                       goto err_out;
-               flags |= pgsz;
-
-               pr_debug("%s: [%d] %08x %08x(%x)\n", __func__,
-                        i, da, pa, bytes);
-
-               iotlb_init_entry(&e, da, pa, flags);
-               err = iopgtable_store_entry(obj, &e);
-               if (err)
-                       goto err_out;
-
-               da += bytes;
-       }
-       return 0;
-
-err_out:
-       da = new->da_start;
-
-       for_each_sg(sgt->sgl, sg, i, j) {
-               size_t bytes;
-
-               bytes = iopgtable_clear_entry(obj, da);
-
-               BUG_ON(!iopgsz_ok(bytes));
-
-               da += bytes;
-       }
-       return err;
-}
-
-/* release 'da' <-> 'pa' mapping */
-static void unmap_iovm_area(struct iommu *obj, struct iovm_struct *area)
-{
-       u32 start;
-       size_t total = area->da_end - area->da_start;
-
-       BUG_ON((!total) || !IS_ALIGNED(total, PAGE_SIZE));
-
-       start = area->da_start;
-       while (total > 0) {
-               size_t bytes;
-
-               bytes = iopgtable_clear_entry(obj, start);
-               if (bytes == 0)
-                       bytes = PAGE_SIZE;
-               else
-                       dev_dbg(obj->dev, "%s: unmap %08x(%x) %08x\n",
-                               __func__, start, bytes, area->flags);
-
-               BUG_ON(!IS_ALIGNED(bytes, PAGE_SIZE));
-
-               total -= bytes;
-               start += bytes;
-       }
-       BUG_ON(total);
-}
-
-/* template function for all unmapping */
-static struct sg_table *unmap_vm_area(struct iommu *obj, const u32 da,
-                                     void (*fn)(const void *), u32 flags)
-{
-       struct sg_table *sgt = NULL;
-       struct iovm_struct *area;
-
-       if (!IS_ALIGNED(da, PAGE_SIZE)) {
-               dev_err(obj->dev, "%s: alignment err(%08x)\n", __func__, da);
-               return NULL;
-       }
-
-       mutex_lock(&obj->mmap_lock);
-
-       area = __find_iovm_area(obj, da);
-       if (!area) {
-               dev_dbg(obj->dev, "%s: no da area(%08x)\n", __func__, da);
-               goto out;
-       }
-
-       if ((area->flags & flags) != flags) {
-               dev_err(obj->dev, "%s: wrong flags(%08x)\n", __func__,
-                       area->flags);
-               goto out;
-       }
-       sgt = (struct sg_table *)area->sgt;
-
-       unmap_iovm_area(obj, area);
-
-       fn(area->va);
-
-       dev_dbg(obj->dev, "%s: %08x-%08x-%08x(%x) %08x\n", __func__,
-               area->da_start, da, area->da_end,
-               area->da_end - area->da_start, area->flags);
-
-       free_iovm_area(obj, area);
-out:
-       mutex_unlock(&obj->mmap_lock);
-
-       return sgt;
-}
-
-static u32 map_iommu_region(struct iommu *obj, u32 da,
-             const struct sg_table *sgt, void *va, size_t bytes, u32 flags)
-{
-       int err = -ENOMEM;
-       struct iovm_struct *new;
-
-       mutex_lock(&obj->mmap_lock);
-
-       new = alloc_iovm_area(obj, da, bytes, flags);
-       if (IS_ERR(new)) {
-               err = PTR_ERR(new);
-               goto err_alloc_iovma;
-       }
-       new->va = va;
-       new->sgt = sgt;
-
-       if (map_iovm_area(obj, new, sgt, new->flags))
-               goto err_map;
-
-       mutex_unlock(&obj->mmap_lock);
-
-       dev_dbg(obj->dev, "%s: da:%08x(%x) flags:%08x va:%p\n",
-               __func__, new->da_start, bytes, new->flags, va);
-
-       return new->da_start;
-
-err_map:
-       free_iovm_area(obj, new);
-err_alloc_iovma:
-       mutex_unlock(&obj->mmap_lock);
-       return err;
-}
-
-static inline u32 __iommu_vmap(struct iommu *obj, u32 da,
-                const struct sg_table *sgt, void *va, size_t bytes, u32 flags)
-{
-       return map_iommu_region(obj, da, sgt, va, bytes, flags);
-}
-
-/**
- * iommu_vmap  -  (d)-(p)-(v) address mapper
- * @obj:       objective iommu
- * @sgt:       address of scatter gather table
- * @flags:     iovma and page property
- *
- * Creates 1-n-1 mapping with given @sgt and returns @da.
- * All @sgt element must be io page size aligned.
- */
-u32 iommu_vmap(struct iommu *obj, u32 da, const struct sg_table *sgt,
-                u32 flags)
-{
-       size_t bytes;
-       void *va = NULL;
-
-       if (!obj || !obj->dev || !sgt)
-               return -EINVAL;
-
-       bytes = sgtable_len(sgt);
-       if (!bytes)
-               return -EINVAL;
-       bytes = PAGE_ALIGN(bytes);
-
-       if (flags & IOVMF_MMIO) {
-               va = vmap_sg(sgt);
-               if (IS_ERR(va))
-                       return PTR_ERR(va);
-       }
-
-       flags |= IOVMF_DISCONT;
-       flags |= IOVMF_MMIO;
-
-       da = __iommu_vmap(obj, da, sgt, va, bytes, flags);
-       if (IS_ERR_VALUE(da))
-               vunmap_sg(va);
-
-       return da;
-}
-EXPORT_SYMBOL_GPL(iommu_vmap);
-
-/**
- * iommu_vunmap  -  release virtual mapping obtained by 'iommu_vmap()'
- * @obj:       objective iommu
- * @da:                iommu device virtual address
- *
- * Free the iommu virtually contiguous memory area starting at
- * @da, which was returned by 'iommu_vmap()'.
- */
-struct sg_table *iommu_vunmap(struct iommu *obj, u32 da)
-{
-       struct sg_table *sgt;
-       /*
-        * 'sgt' is allocated before 'iommu_vmalloc()' is called.
-        * Just returns 'sgt' to the caller to free
-        */
-       sgt = unmap_vm_area(obj, da, vunmap_sg, IOVMF_DISCONT | IOVMF_MMIO);
-       if (!sgt)
-               dev_dbg(obj->dev, "%s: No sgt\n", __func__);
-       return sgt;
-}
-EXPORT_SYMBOL_GPL(iommu_vunmap);
-
-/**
- * iommu_vmalloc  -  (d)-(p)-(v) address allocator and mapper
- * @obj:       objective iommu
- * @da:                contiguous iommu virtual memory
- * @bytes:     allocation size
- * @flags:     iovma and page property
- *
- * Allocate @bytes linearly and creates 1-n-1 mapping and returns
- * @da again, which might be adjusted if 'IOVMF_DA_FIXED' is not set.
- */
-u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
-{
-       void *va;
-       struct sg_table *sgt;
-
-       if (!obj || !obj->dev || !bytes)
-               return -EINVAL;
-
-       bytes = PAGE_ALIGN(bytes);
-
-       va = vmalloc(bytes);
-       if (!va)
-               return -ENOMEM;
-
-       flags |= IOVMF_DISCONT;
-       flags |= IOVMF_ALLOC;
-
-       sgt = sgtable_alloc(bytes, flags, da, 0);
-       if (IS_ERR(sgt)) {
-               da = PTR_ERR(sgt);
-               goto err_sgt_alloc;
-       }
-       sgtable_fill_vmalloc(sgt, va);
-
-       da = __iommu_vmap(obj, da, sgt, va, bytes, flags);
-       if (IS_ERR_VALUE(da))
-               goto err_iommu_vmap;
-
-       return da;
-
-err_iommu_vmap:
-       sgtable_drain_vmalloc(sgt);
-       sgtable_free(sgt);
-err_sgt_alloc:
-       vfree(va);
-       return da;
-}
-EXPORT_SYMBOL_GPL(iommu_vmalloc);
-
-/**
- * iommu_vfree  -  release memory allocated by 'iommu_vmalloc()'
- * @obj:       objective iommu
- * @da:                iommu device virtual address
- *
- * Frees the iommu virtually continuous memory area starting at
- * @da, as obtained from 'iommu_vmalloc()'.
- */
-void iommu_vfree(struct iommu *obj, const u32 da)
-{
-       struct sg_table *sgt;
-
-       sgt = unmap_vm_area(obj, da, vfree, IOVMF_DISCONT | IOVMF_ALLOC);
-       if (!sgt)
-               dev_dbg(obj->dev, "%s: No sgt\n", __func__);
-       sgtable_free(sgt);
-}
-EXPORT_SYMBOL_GPL(iommu_vfree);
-
-static u32 __iommu_kmap(struct iommu *obj, u32 da, u32 pa, void *va,
-                         size_t bytes, u32 flags)
-{
-       struct sg_table *sgt;
-
-       sgt = sgtable_alloc(bytes, flags, da, pa);
-       if (IS_ERR(sgt))
-               return PTR_ERR(sgt);
-
-       sgtable_fill_kmalloc(sgt, pa, da, bytes);
-
-       da = map_iommu_region(obj, da, sgt, va, bytes, flags);
-       if (IS_ERR_VALUE(da)) {
-               sgtable_drain_kmalloc(sgt);
-               sgtable_free(sgt);
-       }
-
-       return da;
-}
-
-/**
- * iommu_kmap  -  (d)-(p)-(v) address mapper
- * @obj:       objective iommu
- * @da:                contiguous iommu virtual memory
- * @pa:                contiguous physical memory
- * @flags:     iovma and page property
- *
- * Creates 1-1-1 mapping and returns @da again, which can be
- * adjusted if 'IOVMF_DA_FIXED' is not set.
- */
-u32 iommu_kmap(struct iommu *obj, u32 da, u32 pa, size_t bytes,
-                u32 flags)
-{
-       void *va;
-
-       if (!obj || !obj->dev || !bytes)
-               return -EINVAL;
-
-       bytes = PAGE_ALIGN(bytes);
-
-       va = ioremap(pa, bytes);
-       if (!va)
-               return -ENOMEM;
-
-       flags |= IOVMF_LINEAR;
-       flags |= IOVMF_MMIO;
-
-       da = __iommu_kmap(obj, da, pa, va, bytes, flags);
-       if (IS_ERR_VALUE(da))
-               iounmap(va);
-
-       return da;
-}
-EXPORT_SYMBOL_GPL(iommu_kmap);
-
-/**
- * iommu_kunmap  -  release virtual mapping obtained by 'iommu_kmap()'
- * @obj:       objective iommu
- * @da:                iommu device virtual address
- *
- * Frees the iommu virtually contiguous memory area starting at
- * @da, which was passed to and was returned by'iommu_kmap()'.
- */
-void iommu_kunmap(struct iommu *obj, u32 da)
-{
-       struct sg_table *sgt;
-       typedef void (*func_t)(const void *);
-
-       sgt = unmap_vm_area(obj, da, (func_t)iounmap,
-                           IOVMF_LINEAR | IOVMF_MMIO);
-       if (!sgt)
-               dev_dbg(obj->dev, "%s: No sgt\n", __func__);
-       sgtable_free(sgt);
-}
-EXPORT_SYMBOL_GPL(iommu_kunmap);
-
-/**
- * iommu_kmalloc  -  (d)-(p)-(v) address allocator and mapper
- * @obj:       objective iommu
- * @da:                contiguous iommu virtual memory
- * @bytes:     bytes for allocation
- * @flags:     iovma and page property
- *
- * Allocate @bytes linearly and creates 1-1-1 mapping and returns
- * @da again, which might be adjusted if 'IOVMF_DA_FIXED' is not set.
- */
-u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
-{
-       void *va;
-       u32 pa;
-
-       if (!obj || !obj->dev || !bytes)
-               return -EINVAL;
-
-       bytes = PAGE_ALIGN(bytes);
-
-       va = kmalloc(bytes, GFP_KERNEL | GFP_DMA);
-       if (!va)
-               return -ENOMEM;
-       pa = virt_to_phys(va);
-
-       flags |= IOVMF_LINEAR;
-       flags |= IOVMF_ALLOC;
-
-       da = __iommu_kmap(obj, da, pa, va, bytes, flags);
-       if (IS_ERR_VALUE(da))
-               kfree(va);
-
-       return da;
-}
-EXPORT_SYMBOL_GPL(iommu_kmalloc);
-
-/**
- * iommu_kfree  -  release virtual mapping obtained by 'iommu_kmalloc()'
- * @obj:       objective iommu
- * @da:                iommu device virtual address
- *
- * Frees the iommu virtually contiguous memory area starting at
- * @da, which was passed to and was returned by'iommu_kmalloc()'.
- */
-void iommu_kfree(struct iommu *obj, u32 da)
-{
-       struct sg_table *sgt;
-
-       sgt = unmap_vm_area(obj, da, kfree, IOVMF_LINEAR | IOVMF_ALLOC);
-       if (!sgt)
-               dev_dbg(obj->dev, "%s: No sgt\n", __func__);
-       sgtable_free(sgt);
-}
-EXPORT_SYMBOL_GPL(iommu_kfree);
-
-
-static int __init iovmm_init(void)
-{
-       const unsigned long flags = SLAB_HWCACHE_ALIGN;
-       struct kmem_cache *p;
-
-       p = kmem_cache_create("iovm_area_cache", sizeof(struct iovm_struct), 0,
-                             flags, NULL);
-       if (!p)
-               return -ENOMEM;
-       iovm_area_cachep = p;
-
-       return 0;
-}
-module_init(iovmm_init);
-
-static void __exit iovmm_exit(void)
-{
-       kmem_cache_destroy(iovm_area_cachep);
-}
-module_exit(iovmm_exit);
-
-MODULE_DESCRIPTION("omap iommu: simple virtual address space management");
-MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
-MODULE_LICENSE("GPL v2");
index 8213efe..43f4c92 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/uaccess.h>
 #include <linux/iommu.h>
 #include <linux/intel-iommu.h>
+#include <linux/pci.h>
 
 #include <asm/pgtable.h>
 #include <asm/gcc_intrin.h>
@@ -204,7 +205,7 @@ int kvm_dev_ioctl_check_extension(long ext)
                r = KVM_COALESCED_MMIO_PAGE_OFFSET;
                break;
        case KVM_CAP_IOMMU:
-               r = iommu_found();
+               r = iommu_present(&pci_bus_type);
                break;
        default:
                r = 0;
index a569514..3a3e5b8 100644 (file)
 #include <linux/dma-attrs.h>
 #include <asm/io.h>
 #include <asm-generic/dma-coherent.h>
+#include <asm/cacheflush.h>
 
 #define DMA_ERROR_CODE         (~(dma_addr_t)0x0)
 
 #define __dma_alloc_coherent(dev, gfp, size, handle)   NULL
 #define __dma_free_coherent(size, addr)                ((void)0)
-#define __dma_sync(addr, size, rw)             ((void)0)
 
 static inline unsigned long device_to_mask(struct device *dev)
 {
@@ -95,6 +95,22 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask)
 
 #include <asm-generic/dma-mapping-common.h>
 
+static inline void __dma_sync(unsigned long paddr,
+                             size_t size, enum dma_data_direction direction)
+{
+       switch (direction) {
+       case DMA_TO_DEVICE:
+       case DMA_BIDIRECTIONAL:
+               flush_dcache_range(paddr, paddr + size);
+               break;
+       case DMA_FROM_DEVICE:
+               invalidate_dcache_range(paddr, paddr + size);
+               break;
+       default:
+               BUG();
+       }
+}
+
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
@@ -135,7 +151,7 @@ static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
                enum dma_data_direction direction)
 {
        BUG_ON(direction == DMA_NONE);
-       __dma_sync(vaddr, size, (int)direction);
+       __dma_sync(virt_to_phys(vaddr), size, (int)direction);
 }
 
 #endif /* _ASM_MICROBLAZE_DMA_MAPPING_H */
index 098dfdd..834849f 100644 (file)
  * I've snaffled the value from the microblaze binutils source code
  * /binutils/microblaze/include/elf/microblaze.h
  */
-#define EM_XILINX_MICROBLAZE   0xbaab
-#define ELF_ARCH               EM_XILINX_MICROBLAZE
+#define EM_MICROBLAZE          189
+#define EM_MICROBLAZE_OLD      0xbaab
+#define ELF_ARCH               EM_MICROBLAZE
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
-#define elf_check_arch(x)      ((x)->e_machine == EM_XILINX_MICROBLAZE)
+#define elf_check_arch(x)      ((x)->e_machine == EM_MICROBLAZE \
+                                || (x)->e_machine == EM_MICROBLAZE_OLD)
 
 /*
  * These are used to set parameters in the core dumps.
index e6a2284..5a433cb 100644 (file)
@@ -17,8 +17,6 @@
 #include <asm-generic/cmpxchg.h>
 #include <asm-generic/cmpxchg-local.h>
 
-#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
-
 struct task_struct;
 struct thread_info;
 
@@ -96,11 +94,4 @@ extern struct dentry *of_debugfs_root;
 
 #define arch_align_stack(x) (x)
 
-/*
- * MicroBlaze doesn't handle unaligned accesses in hardware.
- *
- * Based on this we force the IP header alignment in network drivers.
- */
-#define NET_IP_ALIGN   2
-
 #endif /* _ASM_MICROBLAZE_SYSTEM_H */
index 5bb95a1..072b007 100644 (file)
@@ -95,7 +95,7 @@ static inline int ___range_ok(unsigned long addr, unsigned long size)
  *  - "addr", "addr + size" and "size" are all below the limit
  */
 #define access_ok(type, addr, size) \
-       (get_fs().seg > (((unsigned long)(addr)) | \
+       (get_fs().seg >= (((unsigned long)(addr)) | \
                (size) | ((unsigned long)(addr) + (size))))
 
 /* || printk("access_ok failed for %s at 0x%08lx (size %d), seg 0x%08x\n",
index 44394d8..54194b2 100644 (file)
@@ -34,6 +34,7 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
        {"8.00.a", 0x12},
        {"8.00.b", 0x13},
        {"8.10.a", 0x14},
+       {"8.20.a", 0x15},
        {NULL, 0},
 };
 
index 393e6b2..dc6416d 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/gfp.h>
 #include <linux/dma-debug.h>
 #include <asm/bug.h>
-#include <asm/cacheflush.h>
 
 /*
  * Generic direct DMA implementation
  * can set archdata.dma_data to an unsigned long holding the offset. By
  * default the offset is PCI_DRAM_OFFSET.
  */
-static inline void __dma_sync_page(unsigned long paddr, unsigned long offset,
-                               size_t size, enum dma_data_direction direction)
-{
-       switch (direction) {
-       case DMA_TO_DEVICE:
-       case DMA_BIDIRECTIONAL:
-               flush_dcache_range(paddr + offset, paddr + offset + size);
-               break;
-       case DMA_FROM_DEVICE:
-               invalidate_dcache_range(paddr + offset, paddr + offset + size);
-               break;
-       default:
-               BUG();
-       }
-}
 
 static unsigned long get_dma_direct_offset(struct device *dev)
 {
@@ -91,7 +75,7 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
        /* FIXME this part of code is untested */
        for_each_sg(sgl, sg, nents, i) {
                sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev);
-               __dma_sync_page(page_to_phys(sg_page(sg)), sg->offset,
+               __dma_sync(page_to_phys(sg_page(sg)) + sg->offset,
                                                        sg->length, direction);
        }
 
@@ -116,7 +100,7 @@ static inline dma_addr_t dma_direct_map_page(struct device *dev,
                                             enum dma_data_direction direction,
                                             struct dma_attrs *attrs)
 {
-       __dma_sync_page(page_to_phys(page), offset, size, direction);
+       __dma_sync(page_to_phys(page) + offset, size, direction);
        return page_to_phys(page) + offset + get_dma_direct_offset(dev);
 }
 
@@ -131,7 +115,63 @@ static inline void dma_direct_unmap_page(struct device *dev,
  * phys_to_virt is here because in __dma_sync_page is __virt_to_phys and
  * dma_address is physical address
  */
-       __dma_sync_page(dma_address, 0 , size, direction);
+       __dma_sync(dma_address, size, direction);
+}
+
+static inline void
+dma_direct_sync_single_for_cpu(struct device *dev,
+                              dma_addr_t dma_handle, size_t size,
+                              enum dma_data_direction direction)
+{
+       /*
+        * It's pointless to flush the cache as the memory segment
+        * is given to the CPU
+        */
+
+       if (direction == DMA_FROM_DEVICE)
+               __dma_sync(dma_handle, size, direction);
+}
+
+static inline void
+dma_direct_sync_single_for_device(struct device *dev,
+                                 dma_addr_t dma_handle, size_t size,
+                                 enum dma_data_direction direction)
+{
+       /*
+        * It's pointless to invalidate the cache if the device isn't
+        * supposed to write to the relevant region
+        */
+
+       if (direction == DMA_TO_DEVICE)
+               __dma_sync(dma_handle, size, direction);
+}
+
+static inline void
+dma_direct_sync_sg_for_cpu(struct device *dev,
+                          struct scatterlist *sgl, int nents,
+                          enum dma_data_direction direction)
+{
+       struct scatterlist *sg;
+       int i;
+
+       /* FIXME this part of code is untested */
+       if (direction == DMA_FROM_DEVICE)
+               for_each_sg(sgl, sg, nents, i)
+                       __dma_sync(sg->dma_address, sg->length, direction);
+}
+
+static inline void
+dma_direct_sync_sg_for_device(struct device *dev,
+                             struct scatterlist *sgl, int nents,
+                             enum dma_data_direction direction)
+{
+       struct scatterlist *sg;
+       int i;
+
+       /* FIXME this part of code is untested */
+       if (direction == DMA_TO_DEVICE)
+               for_each_sg(sgl, sg, nents, i)
+                       __dma_sync(sg->dma_address, sg->length, direction);
 }
 
 struct dma_map_ops dma_direct_ops = {
@@ -142,6 +182,10 @@ struct dma_map_ops dma_direct_ops = {
        .dma_supported  = dma_direct_dma_supported,
        .map_page       = dma_direct_map_page,
        .unmap_page     = dma_direct_unmap_page,
+       .sync_single_for_cpu            = dma_direct_sync_single_for_cpu,
+       .sync_single_for_device         = dma_direct_sync_single_for_device,
+       .sync_sg_for_cpu                = dma_direct_sync_sg_for_cpu,
+       .sync_sg_for_device             = dma_direct_sync_sg_for_device,
 };
 EXPORT_SYMBOL(dma_direct_ops);
 
index 66fad23..6348dc8 100644 (file)
@@ -119,7 +119,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
        case MICROBLAZE_DIV_ZERO_EXCEPTION:
                if (user_mode(regs)) {
                        pr_debug("Divide by zero exception in user mode\n");
-                       _exception(SIGILL, regs, FPE_INTDIV, addr);
+                       _exception(SIGFPE, regs, FPE_INTDIV, addr);
                        return;
                }
                printk(KERN_WARNING "Divide by zero exception " \
index dbb8124..95cc295 100644 (file)
@@ -179,6 +179,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
 
        ti->cpu_context.msr = (childregs->msr|MSR_VM);
        ti->cpu_context.msr &= ~MSR_UMS; /* switch_to to kernel mode */
+       ti->cpu_context.msr &= ~MSR_IE;
 #endif
        ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8;
 
index 6a8e0cc..043cb58 100644 (file)
@@ -148,7 +148,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
                ret = -1L;
 
        if (unlikely(current->audit_context))
-               audit_syscall_entry(EM_XILINX_MICROBLAZE, regs->r12,
+               audit_syscall_entry(EM_MICROBLAZE, regs->r12,
                                    regs->r5, regs->r6,
                                    regs->r7, regs->r8);
 
index e5550ce..af74b11 100644 (file)
@@ -308,7 +308,8 @@ unsigned long long notrace sched_clock(void)
 {
        if (timer_initialized) {
                struct clocksource *cs = &clocksource_microblaze;
-               cycle_t cyc = cnt32_to_63(cs->read(NULL));
+
+               cycle_t cyc = cnt32_to_63(cs->read(NULL)) & LLONG_MAX;
                return clocksource_cyc2ns(cyc, cs->mult, cs->shift);
        }
        return 0;
index 10c320a..c13067b 100644 (file)
@@ -25,5 +25,6 @@ lib-y += lshrdi3.o
 lib-y += modsi3.o
 lib-y += muldi3.o
 lib-y += mulsi3.o
+lib-y += ucmpdi2.o
 lib-y += udivsi3.o
 lib-y += umodsi3.o
index 5810cec..f037266 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/errno.h>
 #include <linux/linkage.h>
+#include <asm/page.h>
 
 /*
  * int __strncpy_user(char *to, char *from, int len);
@@ -33,8 +34,8 @@ __strncpy_user:
         * r3 - temp count
         * r4 - temp val
         */
+       beqid   r7,3f
        addik   r3,r7,0         /* temp_count = len */
-       beqi    r3,3f
 1:
        lbu     r4,r6,r0
        sb      r4,r5,r0
@@ -76,8 +77,8 @@ __strncpy_user:
 .type  __strnlen_user, @function
 .align 4;
 __strnlen_user:
+       beqid   r6,3f
        addik   r3,r6,0
-       beqi    r3,3f
 1:
        lbu     r4,r5,r0
        beqid   r4,2f           /* break on NUL */
@@ -102,6 +103,49 @@ __strnlen_user:
        .section        __ex_table,"a"
        .word   1b,4b
 
+/* Loop unrolling for __copy_tofrom_user */
+#define COPY(offset)   \
+1:     lwi     r4 , r6, 0x0000 + offset;       \
+2:     lwi     r19, r6, 0x0004 + offset;       \
+3:     lwi     r20, r6, 0x0008 + offset;       \
+4:     lwi     r21, r6, 0x000C + offset;       \
+5:     lwi     r22, r6, 0x0010 + offset;       \
+6:     lwi     r23, r6, 0x0014 + offset;       \
+7:     lwi     r24, r6, 0x0018 + offset;       \
+8:     lwi     r25, r6, 0x001C + offset;       \
+9:     swi     r4 , r5, 0x0000 + offset;       \
+10:    swi     r19, r5, 0x0004 + offset;       \
+11:    swi     r20, r5, 0x0008 + offset;       \
+12:    swi     r21, r5, 0x000C + offset;       \
+13:    swi     r22, r5, 0x0010 + offset;       \
+14:    swi     r23, r5, 0x0014 + offset;       \
+15:    swi     r24, r5, 0x0018 + offset;       \
+16:    swi     r25, r5, 0x001C + offset;       \
+       .section __ex_table,"a";                \
+       .word   1b, 0f;                         \
+       .word   2b, 0f;                         \
+       .word   3b, 0f;                         \
+       .word   4b, 0f;                         \
+       .word   5b, 0f;                         \
+       .word   6b, 0f;                         \
+       .word   7b, 0f;                         \
+       .word   8b, 0f;                         \
+       .word   9b, 0f;                         \
+       .word   10b, 0f;                        \
+       .word   11b, 0f;                        \
+       .word   12b, 0f;                        \
+       .word   13b, 0f;                        \
+       .word   14b, 0f;                        \
+       .word   15b, 0f;                        \
+       .word   16b, 0f;                        \
+       .text
+
+#define COPY_80(offset)        \
+       COPY(0x00 + offset);\
+       COPY(0x20 + offset);\
+       COPY(0x40 + offset);\
+       COPY(0x60 + offset);
+
 /*
  * int __copy_tofrom_user(char *to, char *from, int len)
  * Return:
@@ -119,34 +163,79 @@ __copy_tofrom_user:
         * r7, r3 - count
         * r4 - tempval
         */
-       beqid   r7, 3f /* zero size is not likely */
-       andi    r3, r7, 0x3 /* filter add count */
-       bneid   r3, 4f /* if is odd value then byte copying */
+       beqid   r7, 0f /* zero size is not likely */
        or      r3, r5, r6 /* find if is any to/from unaligned */
-       andi    r3, r3, 0x3 /* mask unaligned */
-       bneid   r3, 1f /* it is unaligned -> then jump */
+       or      r3, r3, r7 /* find if count is unaligned */
+       andi    r3, r3, 0x3 /* mask last 3 bits */
+       bneid   r3, bu1 /* if r3 is not zero then byte copying */
+       or      r3, r0, r0
+
+       rsubi   r3, r7, PAGE_SIZE /* detect PAGE_SIZE */
+       beqid   r3, page;
        or      r3, r0, r0
 
-/* at least one 4 byte copy */
-5:     lw      r4, r6, r3
-6:     sw      r4, r5, r3
+w1:    lw      r4, r6, r3 /* at least one 4 byte copy */
+w2:    sw      r4, r5, r3
        addik   r7, r7, -4
-       bneid   r7, 5b
+       bneid   r7, w1
        addik   r3, r3, 4
        addik   r3, r7, 0
        rtsd    r15, 8
        nop
-4:     or      r3, r0, r0
-1:     lbu     r4,r6,r3
-2:     sb      r4,r5,r3
+
+       .section        __ex_table,"a"
+       .word   w1, 0f;
+       .word   w2, 0f;
+       .text
+
+.align 4 /* Alignment is important to keep icache happy */
+page:  /* Create room on stack and save registers for storign values */
+       addik   r1, r1, -32
+       swi     r19, r1, 4
+       swi     r20, r1, 8
+       swi     r21, r1, 12
+       swi     r22, r1, 16
+       swi     r23, r1, 20
+       swi     r24, r1, 24
+       swi     r25, r1, 28
+loop:  /* r4, r19, r20, r21, r22, r23, r24, r25 are used for storing values */
+       /* Loop unrolling to get performance boost */
+       COPY_80(0x000);
+       COPY_80(0x080);
+       COPY_80(0x100);
+       COPY_80(0x180);
+       /* copy loop */
+       addik   r6, r6, 0x200
+       addik   r7, r7, -0x200
+       bneid   r7, loop
+       addik   r5, r5, 0x200
+       /* Restore register content */
+       lwi     r19, r1, 4
+       lwi     r20, r1, 8
+       lwi     r21, r1, 12
+       lwi     r22, r1, 16
+       lwi     r23, r1, 20
+       lwi     r24, r1, 24
+       lwi     r25, r1, 28
+       addik   r1, r1, 32
+       /* return back */
+       addik   r3, r7, 0
+       rtsd    r15, 8
+       nop
+
+.align 4 /* Alignment is important to keep icache happy */
+bu1:   lbu     r4,r6,r3
+bu2:   sb      r4,r5,r3
        addik   r7,r7,-1
-       bneid   r7,1b
+       bneid   r7,bu1
        addik   r3,r3,1         /* delay slot */
-3:
+0:
        addik   r3,r7,0
        rtsd    r15,8
        nop
        .size   __copy_tofrom_user, . - __copy_tofrom_user
 
        .section        __ex_table,"a"
-       .word   1b,3b,2b,3b,5b,3b,6b,3b
+       .word   bu1, 0b;
+       .word   bu2, 0b;
+       .text
diff --git a/arch/microblaze/lib/ucmpdi2.c b/arch/microblaze/lib/ucmpdi2.c
new file mode 100644 (file)
index 0000000..63ca105
--- /dev/null
@@ -0,0 +1,20 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+word_type __ucmpdi2(unsigned long long a, unsigned long long b)
+{
+       const DWunion au = {.ll = a};
+       const DWunion bu = {.ll = b};
+
+       if ((unsigned int) au.s.high < (unsigned int) bu.s.high)
+               return 0;
+       else if ((unsigned int) au.s.high > (unsigned int) bu.s.high)
+               return 2;
+       if ((unsigned int) au.s.low < (unsigned int) bu.s.low)
+               return 0;
+       else if ((unsigned int) au.s.low > (unsigned int) bu.s.low)
+               return 2;
+       return 1;
+}
+EXPORT_SYMBOL(__ucmpdi2);
index a4f6c85..08fe69e 100644 (file)
@@ -148,6 +148,12 @@ struct kvm_regs {
 #define KVM_SREGS_E_UPDATE_DEC         (1 << 2)
 #define KVM_SREGS_E_UPDATE_DBSR                (1 << 3)
 
+/*
+ * Book3S special bits to indicate contents in the struct by maintaining
+ * backwards compatibility with older structs. If adding a new field,
+ * please make sure to add a flag for that new field */
+#define KVM_SREGS_S_HIOR               (1 << 0)
+
 /*
  * In KVM_SET_SREGS, reserved/pad fields must be left untouched from a
  * previous KVM_GET_REGS.
@@ -173,6 +179,8 @@ struct kvm_sregs {
                                __u64 ibat[8]; 
                                __u64 dbat[8]; 
                        } ppc32;
+                       __u64 flags; /* KVM_SREGS_S_ */
+                       __u64 hior;
                } s;
                struct {
                        union {
@@ -276,6 +284,11 @@ struct kvm_guest_debug_arch {
 #define KVM_INTERRUPT_UNSET    -2U
 #define KVM_INTERRUPT_SET_LEVEL        -3U
 
+#define KVM_CPU_440            1
+#define KVM_CPU_E500V2         2
+#define KVM_CPU_3S_32          3
+#define KVM_CPU_3S_64          4
+
 /* for KVM_CAP_SPAPR_TCE */
 struct kvm_create_spapr_tce {
        __u64 liobn;
index 98da010..a384ffd 100644 (file)
@@ -90,6 +90,8 @@ struct kvmppc_vcpu_book3s {
 #endif
        int context_id[SID_CONTEXTS];
 
+       bool hior_sregs;                /* HIOR is set by SREGS, not PVR */
+
        struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE];
        struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG];
        struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
@@ -139,15 +141,14 @@ extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
 extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu);
 extern pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
 
-extern void kvmppc_handler_lowmem_trampoline(void);
-extern void kvmppc_handler_trampoline_enter(void);
-extern void kvmppc_rmcall(ulong srr0, ulong srr1);
+extern void kvmppc_entry_trampoline(void);
 extern void kvmppc_hv_entry_trampoline(void);
 extern void kvmppc_load_up_fpu(void);
 extern void kvmppc_load_up_altivec(void);
 extern void kvmppc_load_up_vsx(void);
 extern u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst);
 extern ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst);
+extern int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd);
 
 static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu)
 {
@@ -382,6 +383,39 @@ static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu)
 }
 #endif
 
+static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r,
+                                            unsigned long pte_index)
+{
+       unsigned long rb, va_low;
+
+       rb = (v & ~0x7fUL) << 16;               /* AVA field */
+       va_low = pte_index >> 3;
+       if (v & HPTE_V_SECONDARY)
+               va_low = ~va_low;
+       /* xor vsid from AVA */
+       if (!(v & HPTE_V_1TB_SEG))
+               va_low ^= v >> 12;
+       else
+               va_low ^= v >> 24;
+       va_low &= 0x7ff;
+       if (v & HPTE_V_LARGE) {
+               rb |= 1;                        /* L field */
+               if (cpu_has_feature(CPU_FTR_ARCH_206) &&
+                   (r & 0xff000)) {
+                       /* non-16MB large page, must be 64k */
+                       /* (masks depend on page size) */
+                       rb |= 0x1000;           /* page encoding in LP field */
+                       rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
+                       rb |= (va_low & 0xfe);  /* AVAL field (P7 doesn't seem to care) */
+               }
+       } else {
+               /* 4kB page */
+               rb |= (va_low & 0x7ff) << 12;   /* remaining 11b of VA */
+       }
+       rb |= (v >> 54) & 0x300;                /* B field */
+       return rb;
+}
+
 /* Magic register values loaded into r3 and r4 before the 'sc' assembly
  * instruction for the OSI hypercalls */
 #define OSI_SC_MAGIC_R3                        0x113724FA
index ef7b368..1f2f5b6 100644 (file)
@@ -75,6 +75,8 @@ struct kvmppc_host_state {
        ulong scratch0;
        ulong scratch1;
        u8 in_guest;
+       u8 restore_hid5;
+       u8 napping;
 
 #ifdef CONFIG_KVM_BOOK3S_64_HV
        struct kvm_vcpu *kvm_vcpu;
index cc22b28..bf8af5d 100644 (file)
@@ -198,21 +198,29 @@ struct kvm_arch {
  */
 struct kvmppc_vcore {
        int n_runnable;
-       int n_blocked;
+       int n_busy;
        int num_threads;
        int entry_exit_count;
        int n_woken;
        int nap_count;
+       int napping_threads;
        u16 pcpu;
-       u8 vcore_running;
+       u8 vcore_state;
        u8 in_guest;
        struct list_head runnable_threads;
        spinlock_t lock;
+       wait_queue_head_t wq;
 };
 
 #define VCORE_ENTRY_COUNT(vc)  ((vc)->entry_exit_count & 0xff)
 #define VCORE_EXIT_COUNT(vc)   ((vc)->entry_exit_count >> 8)
 
+/* Values for vcore_state */
+#define VCORE_INACTIVE 0
+#define VCORE_RUNNING  1
+#define VCORE_EXITING  2
+#define VCORE_SLEEPING 3
+
 struct kvmppc_pte {
        ulong eaddr;
        u64 vpage;
@@ -258,14 +266,6 @@ struct kvm_vcpu_arch {
        ulong host_stack;
        u32 host_pid;
 #ifdef CONFIG_PPC_BOOK3S
-       ulong host_msr;
-       ulong host_r2;
-       void *host_retip;
-       ulong trampoline_lowmem;
-       ulong trampoline_enter;
-       ulong highmem_handler;
-       ulong rmcall;
-       ulong host_paca_phys;
        struct kvmppc_slb slb[64];
        int slb_max;            /* 1 + index of last valid entry in slb[] */
        int slb_nr;             /* total number of entries in SLB */
@@ -389,6 +389,9 @@ struct kvm_vcpu_arch {
        u8 dcr_is_write;
        u8 osi_needed;
        u8 osi_enabled;
+       u8 papr_enabled;
+       u8 sane;
+       u8 cpu_type;
        u8 hcall_needed;
 
        u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
@@ -408,11 +411,13 @@ struct kvm_vcpu_arch {
        struct dtl *dtl;
        struct dtl *dtl_end;
 
+       wait_queue_head_t *wqp;
        struct kvmppc_vcore *vcore;
        int ret;
        int trap;
        int state;
        int ptid;
+       bool timer_running;
        wait_queue_head_t cpu_run;
 
        struct kvm_vcpu_arch_shared *shared;
@@ -428,8 +433,9 @@ struct kvm_vcpu_arch {
 #endif
 };
 
-#define KVMPPC_VCPU_BUSY_IN_HOST       0
-#define KVMPPC_VCPU_BLOCKED            1
+/* Values for vcpu->arch.state */
+#define KVMPPC_VCPU_STOPPED            0
+#define KVMPPC_VCPU_BUSY_IN_HOST       1
 #define KVMPPC_VCPU_RUNNABLE           2
 
 #endif /* __POWERPC_KVM_HOST_H__ */
index d121f49..46efd1a 100644 (file)
@@ -66,6 +66,7 @@ extern int kvmppc_emulate_instruction(struct kvm_run *run,
 extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
 extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu);
 extern u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb);
+extern int kvmppc_sanity_check(struct kvm_vcpu *vcpu);
 
 /* Core-specific hooks */
 
index 5f078bc..69f7ffe 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/compat.h>
 #include <asm/mmu.h>
 #include <asm/hvcall.h>
+#include <asm/xics.h>
 #endif
 #ifdef CONFIG_PPC_ISERIES
 #include <asm/iseries/alpaca.h>
@@ -449,8 +450,6 @@ int main(void)
 #ifdef CONFIG_PPC_BOOK3S
        DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm));
        DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id));
-       DEFINE(VCPU_HOST_RETIP, offsetof(struct kvm_vcpu, arch.host_retip));
-       DEFINE(VCPU_HOST_MSR, offsetof(struct kvm_vcpu, arch.host_msr));
        DEFINE(VCPU_PURR, offsetof(struct kvm_vcpu, arch.purr));
        DEFINE(VCPU_SPURR, offsetof(struct kvm_vcpu, arch.spurr));
        DEFINE(VCPU_DSCR, offsetof(struct kvm_vcpu, arch.dscr));
@@ -458,14 +457,12 @@ int main(void)
        DEFINE(VCPU_UAMOR, offsetof(struct kvm_vcpu, arch.uamor));
        DEFINE(VCPU_CTRL, offsetof(struct kvm_vcpu, arch.ctrl));
        DEFINE(VCPU_DABR, offsetof(struct kvm_vcpu, arch.dabr));
-       DEFINE(VCPU_TRAMPOLINE_LOWMEM, offsetof(struct kvm_vcpu, arch.trampoline_lowmem));
-       DEFINE(VCPU_TRAMPOLINE_ENTER, offsetof(struct kvm_vcpu, arch.trampoline_enter));
-       DEFINE(VCPU_HIGHMEM_HANDLER, offsetof(struct kvm_vcpu, arch.highmem_handler));
-       DEFINE(VCPU_RMCALL, offsetof(struct kvm_vcpu, arch.rmcall));
        DEFINE(VCPU_HFLAGS, offsetof(struct kvm_vcpu, arch.hflags));
        DEFINE(VCPU_DEC, offsetof(struct kvm_vcpu, arch.dec));
        DEFINE(VCPU_DEC_EXPIRES, offsetof(struct kvm_vcpu, arch.dec_expires));
        DEFINE(VCPU_PENDING_EXC, offsetof(struct kvm_vcpu, arch.pending_exceptions));
+       DEFINE(VCPU_CEDED, offsetof(struct kvm_vcpu, arch.ceded));
+       DEFINE(VCPU_PRODDED, offsetof(struct kvm_vcpu, arch.prodded));
        DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa));
        DEFINE(VCPU_MMCR, offsetof(struct kvm_vcpu, arch.mmcr));
        DEFINE(VCPU_PMC, offsetof(struct kvm_vcpu, arch.pmc));
@@ -481,6 +478,7 @@ int main(void)
        DEFINE(VCORE_ENTRY_EXIT, offsetof(struct kvmppc_vcore, entry_exit_count));
        DEFINE(VCORE_NAP_COUNT, offsetof(struct kvmppc_vcore, nap_count));
        DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest));
+       DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads));
        DEFINE(VCPU_SVCPU, offsetof(struct kvmppc_vcpu_book3s, shadow_vcpu) -
                           offsetof(struct kvmppc_vcpu_book3s, vcpu));
        DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige));
@@ -537,6 +535,8 @@ int main(void)
        HSTATE_FIELD(HSTATE_SCRATCH0, scratch0);
        HSTATE_FIELD(HSTATE_SCRATCH1, scratch1);
        HSTATE_FIELD(HSTATE_IN_GUEST, in_guest);
+       HSTATE_FIELD(HSTATE_RESTORE_HID5, restore_hid5);
+       HSTATE_FIELD(HSTATE_NAPPING, napping);
 
 #ifdef CONFIG_KVM_BOOK3S_64_HV
        HSTATE_FIELD(HSTATE_KVM_VCPU, kvm_vcpu);
@@ -549,6 +549,7 @@ int main(void)
        HSTATE_FIELD(HSTATE_DSCR, host_dscr);
        HSTATE_FIELD(HSTATE_DABR, dabr);
        HSTATE_FIELD(HSTATE_DECEXP, dec_expires);
+       DEFINE(IPI_PRIORITY, IPI_PRIORITY);
 #endif /* CONFIG_KVM_BOOK3S_64_HV */
 
 #else /* CONFIG_PPC_BOOK3S */
index 41b02c7..29ddd8b 100644 (file)
@@ -427,16 +427,6 @@ slb_miss_user_pseries:
        b       .                               /* prevent spec. execution */
 #endif /* __DISABLED__ */
 
-/* KVM's trampoline code needs to be close to the interrupt handlers */
-
-#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-#ifdef CONFIG_KVM_BOOK3S_PR
-#include "../kvm/book3s_rmhandlers.S"
-#else
-#include "../kvm/book3s_hv_rmhandlers.S"
-#endif
-#endif
-
        .align  7
        .globl  __end_interrupts
 __end_interrupts:
index da3a122..ca1f88b 100644 (file)
@@ -78,6 +78,8 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
        for (i = 0; i < ARRAY_SIZE(vcpu_44x->shadow_refs); i++)
                vcpu_44x->shadow_refs[i].gtlb_index = -1;
 
+       vcpu->arch.cpu_type = KVM_CPU_440;
+
        return 0;
 }
 
index 08428e2..3688aee 100644 (file)
@@ -43,18 +43,22 @@ kvm-book3s_64-objs-$(CONFIG_KVM_BOOK3S_64_PR) := \
        fpu.o \
        book3s_paired_singles.o \
        book3s_pr.o \
+       book3s_pr_papr.o \
        book3s_emulate.o \
        book3s_interrupts.o \
        book3s_mmu_hpte.o \
        book3s_64_mmu_host.o \
        book3s_64_mmu.o \
        book3s_32_mmu.o
+kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_PR) := \
+       book3s_rmhandlers.o
 
 kvm-book3s_64-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \
        book3s_hv.o \
        book3s_hv_interrupts.o \
        book3s_64_mmu_hv.o
 kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \
+       book3s_hv_rmhandlers.o \
        book3s_hv_rm_mmu.o \
        book3s_64_vio_hv.o \
        book3s_hv_builtin.o
index 3608471..7e06a6f 100644 (file)
@@ -31,7 +31,7 @@
         * R1 = host R1
         * R2 = host R2
         * R3 = shadow vcpu
-        * all other volatile GPRS = free
+        * all other volatile GPRS = free except R4, R6
         * SVCPU[CR]  = guest CR
         * SVCPU[XER] = guest XER
         * SVCPU[CTR] = guest CTR
index c6d3e19..b871721 100644 (file)
@@ -128,7 +128,13 @@ static hva_t kvmppc_mmu_book3s_64_get_pteg(
        dprintk("MMU: page=0x%x sdr1=0x%llx pteg=0x%llx vsid=0x%llx\n",
                page, vcpu_book3s->sdr1, pteg, slbe->vsid);
 
-       r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT);
+       /* When running a PAPR guest, SDR1 contains a HVA address instead
+           of a GPA */
+       if (vcpu_book3s->vcpu.arch.papr_enabled)
+               r = pteg;
+       else
+               r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT);
+
        if (kvm_is_error_hva(r))
                return r;
        return r | (pteg & ~PAGE_MASK);
index 04e7d3b..f2e6e48 100644 (file)
@@ -53,7 +53,7 @@ slb_exit_skip_ ## num:
         * R1 = host R1
         * R2 = host R2
         * R3 = shadow vcpu
-        * all other volatile GPRS = free
+        * all other volatile GPRS = free except R4, R6
         * SVCPU[CR]  = guest CR
         * SVCPU[XER] = guest XER
         * SVCPU[CTR] = guest CTR
index 4668465..0c9dc62 100644 (file)
  * function pointers, so let's just disable the define. */
 #undef mfsrin
 
+enum priv_level {
+       PRIV_PROBLEM = 0,
+       PRIV_SUPER = 1,
+       PRIV_HYPER = 2,
+};
+
+static bool spr_allowed(struct kvm_vcpu *vcpu, enum priv_level level)
+{
+       /* PAPR VMs only access supervisor SPRs */
+       if (vcpu->arch.papr_enabled && (level > PRIV_SUPER))
+               return false;
+
+       /* Limit user space to its own small SPR set */
+       if ((vcpu->arch.shared->msr & MSR_PR) && level > PRIV_PROBLEM)
+               return false;
+
+       return true;
+}
+
 int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                            unsigned int inst, int *advance)
 {
@@ -296,6 +315,8 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
 
        switch (sprn) {
        case SPRN_SDR1:
+               if (!spr_allowed(vcpu, PRIV_HYPER))
+                       goto unprivileged;
                to_book3s(vcpu)->sdr1 = spr_val;
                break;
        case SPRN_DSISR:
@@ -390,6 +411,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
        case SPRN_PMC4_GEKKO:
        case SPRN_WPAR_GEKKO:
                break;
+unprivileged:
        default:
                printk(KERN_INFO "KVM: invalid SPR write: %d\n", sprn);
 #ifndef DEBUG_SPR
@@ -421,6 +443,8 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
                break;
        }
        case SPRN_SDR1:
+               if (!spr_allowed(vcpu, PRIV_HYPER))
+                       goto unprivileged;
                kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1);
                break;
        case SPRN_DSISR:
@@ -449,6 +473,10 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
        case SPRN_HID5:
                kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[5]);
                break;
+       case SPRN_CFAR:
+       case SPRN_PURR:
+               kvmppc_set_gpr(vcpu, rt, 0);
+               break;
        case SPRN_GQR0:
        case SPRN_GQR1:
        case SPRN_GQR2:
@@ -476,6 +504,7 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
                kvmppc_set_gpr(vcpu, rt, 0);
                break;
        default:
+unprivileged:
                printk(KERN_INFO "KVM: invalid SPR read: %d\n", sprn);
 #ifndef DEBUG_SPR
                emulated = EMULATE_FAIL;
index 88c8f26..f7f63a0 100644 (file)
@@ -23,9 +23,7 @@
 #ifdef CONFIG_KVM_BOOK3S_64_HV
 EXPORT_SYMBOL_GPL(kvmppc_hv_entry_trampoline);
 #else
-EXPORT_SYMBOL_GPL(kvmppc_handler_trampoline_enter);
-EXPORT_SYMBOL_GPL(kvmppc_handler_lowmem_trampoline);
-EXPORT_SYMBOL_GPL(kvmppc_rmcall);
+EXPORT_SYMBOL_GPL(kvmppc_entry_trampoline);
 EXPORT_SYMBOL_GPL(kvmppc_load_up_fpu);
 #ifdef CONFIG_ALTIVEC
 EXPORT_SYMBOL_GPL(kvmppc_load_up_altivec);
index cc0d7f1..4644c79 100644 (file)
@@ -62,6 +62,8 @@
 /* #define EXIT_DEBUG_SIMPLE */
 /* #define EXIT_DEBUG_INT */
 
+static void kvmppc_end_cede(struct kvm_vcpu *vcpu);
+
 void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
        local_paca->kvm_hstate.kvm_vcpu = vcpu;
@@ -72,40 +74,10 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
 {
 }
 
-static void kvmppc_vcpu_blocked(struct kvm_vcpu *vcpu);
-static void kvmppc_vcpu_unblocked(struct kvm_vcpu *vcpu);
-
-void kvmppc_vcpu_block(struct kvm_vcpu *vcpu)
-{
-       u64 now;
-       unsigned long dec_nsec;
-
-       now = get_tb();
-       if (now >= vcpu->arch.dec_expires && !kvmppc_core_pending_dec(vcpu))
-               kvmppc_core_queue_dec(vcpu);
-       if (vcpu->arch.pending_exceptions)
-               return;
-       if (vcpu->arch.dec_expires != ~(u64)0) {
-               dec_nsec = (vcpu->arch.dec_expires - now) * NSEC_PER_SEC /
-                       tb_ticks_per_sec;
-               hrtimer_start(&vcpu->arch.dec_timer, ktime_set(0, dec_nsec),
-                             HRTIMER_MODE_REL);
-       }
-
-       kvmppc_vcpu_blocked(vcpu);
-
-       kvm_vcpu_block(vcpu);
-       vcpu->stat.halt_wakeup++;
-
-       if (vcpu->arch.dec_expires != ~(u64)0)
-               hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
-
-       kvmppc_vcpu_unblocked(vcpu);
-}
-
 void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
 {
        vcpu->arch.shregs.msr = msr;
+       kvmppc_end_cede(vcpu);
 }
 
 void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
@@ -257,15 +229,6 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
 
        switch (req) {
        case H_CEDE:
-               vcpu->arch.shregs.msr |= MSR_EE;
-               vcpu->arch.ceded = 1;
-               smp_mb();
-               if (!vcpu->arch.prodded)
-                       kvmppc_vcpu_block(vcpu);
-               else
-                       vcpu->arch.prodded = 0;
-               smp_mb();
-               vcpu->arch.ceded = 0;
                break;
        case H_PROD:
                target = kvmppc_get_gpr(vcpu, 4);
@@ -388,20 +351,6 @@ static int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                break;
        }
 
-
-       if (!(r & RESUME_HOST)) {
-               /* To avoid clobbering exit_reason, only check for signals if
-                * we aren't already exiting to userspace for some other
-                * reason. */
-               if (signal_pending(tsk)) {
-                       vcpu->stat.signal_exits++;
-                       run->exit_reason = KVM_EXIT_INTR;
-                       r = -EINTR;
-               } else {
-                       kvmppc_core_deliver_interrupts(vcpu);
-               }
-       }
-
        return r;
 }
 
@@ -479,13 +428,9 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
        kvmppc_mmu_book3s_hv_init(vcpu);
 
        /*
-        * Some vcpus may start out in stopped state.  If we initialize
-        * them to busy-in-host state they will stop other vcpus in the
-        * vcore from running.  Instead we initialize them to blocked
-        * state, effectively considering them to be stopped until we
-        * see the first run ioctl for them.
+        * We consider the vcpu stopped until we see the first run ioctl for it.
         */
-       vcpu->arch.state = KVMPPC_VCPU_BLOCKED;
+       vcpu->arch.state = KVMPPC_VCPU_STOPPED;
 
        init_waitqueue_head(&vcpu->arch.cpu_run);
 
@@ -496,6 +441,7 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
                if (vcore) {
                        INIT_LIST_HEAD(&vcore->runnable_threads);
                        spin_lock_init(&vcore->lock);
+                       init_waitqueue_head(&vcore->wq);
                }
                kvm->arch.vcores[core] = vcore;
        }
@@ -506,10 +452,12 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
 
        spin_lock(&vcore->lock);
        ++vcore->num_threads;
-       ++vcore->n_blocked;
        spin_unlock(&vcore->lock);
        vcpu->arch.vcore = vcore;
 
+       vcpu->arch.cpu_type = KVM_CPU_3S_64;
+       kvmppc_sanity_check(vcpu);
+
        return vcpu;
 
 free_vcpu:
@@ -524,30 +472,31 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
        kfree(vcpu);
 }
 
-static void kvmppc_vcpu_blocked(struct kvm_vcpu *vcpu)
+static void kvmppc_set_timer(struct kvm_vcpu *vcpu)
 {
-       struct kvmppc_vcore *vc = vcpu->arch.vcore;
+       unsigned long dec_nsec, now;
 
-       spin_lock(&vc->lock);
-       vcpu->arch.state = KVMPPC_VCPU_BLOCKED;
-       ++vc->n_blocked;
-       if (vc->n_runnable > 0 &&
-           vc->n_runnable + vc->n_blocked == vc->num_threads) {
-               vcpu = list_first_entry(&vc->runnable_threads, struct kvm_vcpu,
-                                       arch.run_list);
-               wake_up(&vcpu->arch.cpu_run);
+       now = get_tb();
+       if (now > vcpu->arch.dec_expires) {
+               /* decrementer has already gone negative */
+               kvmppc_core_queue_dec(vcpu);
+               kvmppc_core_deliver_interrupts(vcpu);
+               return;
        }
-       spin_unlock(&vc->lock);
+       dec_nsec = (vcpu->arch.dec_expires - now) * NSEC_PER_SEC
+                  / tb_ticks_per_sec;
+       hrtimer_start(&vcpu->arch.dec_timer, ktime_set(0, dec_nsec),
+                     HRTIMER_MODE_REL);
+       vcpu->arch.timer_running = 1;
 }
 
-static void kvmppc_vcpu_unblocked(struct kvm_vcpu *vcpu)
+static void kvmppc_end_cede(struct kvm_vcpu *vcpu)
 {
-       struct kvmppc_vcore *vc = vcpu->arch.vcore;
-
-       spin_lock(&vc->lock);
-       vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST;
-       --vc->n_blocked;
-       spin_unlock(&vc->lock);
+       vcpu->arch.ceded = 0;
+       if (vcpu->arch.timer_running) {
+               hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
+               vcpu->arch.timer_running = 0;
+       }
 }
 
 extern int __kvmppc_vcore_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
@@ -562,6 +511,7 @@ static void kvmppc_remove_runnable(struct kvmppc_vcore *vc,
                return;
        vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST;
        --vc->n_runnable;
+       ++vc->n_busy;
        /* decrement the physical thread id of each following vcpu */
        v = vcpu;
        list_for_each_entry_continue(v, &vc->runnable_threads, arch.run_list)
@@ -575,15 +525,20 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu)
        struct paca_struct *tpaca;
        struct kvmppc_vcore *vc = vcpu->arch.vcore;
 
+       if (vcpu->arch.timer_running) {
+               hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
+               vcpu->arch.timer_running = 0;
+       }
        cpu = vc->pcpu + vcpu->arch.ptid;
        tpaca = &paca[cpu];
        tpaca->kvm_hstate.kvm_vcpu = vcpu;
        tpaca->kvm_hstate.kvm_vcore = vc;
+       tpaca->kvm_hstate.napping = 0;
+       vcpu->cpu = vc->pcpu;
        smp_wmb();
 #ifdef CONFIG_PPC_ICP_NATIVE
        if (vcpu->arch.ptid) {
                tpaca->cpu_start = 0x80;
-               tpaca->kvm_hstate.in_guest = KVM_GUEST_MODE_GUEST;
                wmb();
                xics_wake_cpu(cpu);
                ++vc->n_woken;
@@ -631,9 +586,10 @@ static int on_primary_thread(void)
  */
 static int kvmppc_run_core(struct kvmppc_vcore *vc)
 {
-       struct kvm_vcpu *vcpu, *vnext;
+       struct kvm_vcpu *vcpu, *vcpu0, *vnext;
        long ret;
        u64 now;
+       int ptid;
 
        /* don't start if any threads have a signal pending */
        list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list)
@@ -652,29 +608,50 @@ static int kvmppc_run_core(struct kvmppc_vcore *vc)
                goto out;
        }
 
+       /*
+        * Assign physical thread IDs, first to non-ceded vcpus
+        * and then to ceded ones.
+        */
+       ptid = 0;
+       vcpu0 = NULL;
+       list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) {
+               if (!vcpu->arch.ceded) {
+                       if (!ptid)
+                               vcpu0 = vcpu;
+                       vcpu->arch.ptid = ptid++;
+               }
+       }
+       if (!vcpu0)
+               return 0;               /* nothing to run */
+       list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list)
+               if (vcpu->arch.ceded)
+                       vcpu->arch.ptid = ptid++;
+
        vc->n_woken = 0;
        vc->nap_count = 0;
        vc->entry_exit_count = 0;
-       vc->vcore_running = 1;
+       vc->vcore_state = VCORE_RUNNING;
        vc->in_guest = 0;
        vc->pcpu = smp_processor_id();
+       vc->napping_threads = 0;
        list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list)
                kvmppc_start_thread(vcpu);
-       vcpu = list_first_entry(&vc->runnable_threads, struct kvm_vcpu,
-                               arch.run_list);
 
+       preempt_disable();
        spin_unlock(&vc->lock);
 
-       preempt_disable();
        kvm_guest_enter();
-       __kvmppc_vcore_entry(NULL, vcpu);
+       __kvmppc_vcore_entry(NULL, vcpu0);
 
-       /* wait for secondary threads to finish writing their state to memory */
        spin_lock(&vc->lock);
+       /* disable sending of IPIs on virtual external irqs */
+       list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list)
+               vcpu->cpu = -1;
+       /* wait for secondary threads to finish writing their state to memory */
        if (vc->nap_count < vc->n_woken)
                kvmppc_wait_for_nap(vc);
        /* prevent other vcpu threads from doing kvmppc_start_thread() now */
-       vc->vcore_running = 2;
+       vc->vcore_state = VCORE_EXITING;
        spin_unlock(&vc->lock);
 
        /* make sure updates to secondary vcpu structs are visible now */
@@ -690,22 +667,26 @@ static int kvmppc_run_core(struct kvmppc_vcore *vc)
                if (now < vcpu->arch.dec_expires &&
                    kvmppc_core_pending_dec(vcpu))
                        kvmppc_core_dequeue_dec(vcpu);
-               if (!vcpu->arch.trap) {
-                       if (signal_pending(vcpu->arch.run_task)) {
-                               vcpu->arch.kvm_run->exit_reason = KVM_EXIT_INTR;
-                               vcpu->arch.ret = -EINTR;
-                       }
-                       continue;               /* didn't get to run */
-               }
-               ret = kvmppc_handle_exit(vcpu->arch.kvm_run, vcpu,
-                                        vcpu->arch.run_task);
+
+               ret = RESUME_GUEST;
+               if (vcpu->arch.trap)
+                       ret = kvmppc_handle_exit(vcpu->arch.kvm_run, vcpu,
+                                                vcpu->arch.run_task);
+
                vcpu->arch.ret = ret;
                vcpu->arch.trap = 0;
+
+               if (vcpu->arch.ceded) {
+                       if (ret != RESUME_GUEST)
+                               kvmppc_end_cede(vcpu);
+                       else
+                               kvmppc_set_timer(vcpu);
+               }
        }
 
        spin_lock(&vc->lock);
  out:
-       vc->vcore_running = 0;
+       vc->vcore_state = VCORE_INACTIVE;
        list_for_each_entry_safe(vcpu, vnext, &vc->runnable_threads,
                                 arch.run_list) {
                if (vcpu->arch.ret != RESUME_GUEST) {
@@ -717,82 +698,130 @@ static int kvmppc_run_core(struct kvmppc_vcore *vc)
        return 1;
 }
 
-static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
+/*
+ * Wait for some other vcpu thread to execute us, and
+ * wake us up when we need to handle something in the host.
+ */
+static void kvmppc_wait_for_exec(struct kvm_vcpu *vcpu, int wait_state)
 {
-       int ptid;
-       int wait_state;
-       struct kvmppc_vcore *vc;
        DEFINE_WAIT(wait);
 
-       /* No need to go into the guest when all we do is going out */
-       if (signal_pending(current)) {
-               kvm_run->exit_reason = KVM_EXIT_INTR;
-               return -EINTR;
+       prepare_to_wait(&vcpu->arch.cpu_run, &wait, wait_state);
+       if (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE)
+               schedule();
+       finish_wait(&vcpu->arch.cpu_run, &wait);
+}
+
+/*
+ * All the vcpus in this vcore are idle, so wait for a decrementer
+ * or external interrupt to one of the vcpus.  vc->lock is held.
+ */
+static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc)
+{
+       DEFINE_WAIT(wait);
+       struct kvm_vcpu *v;
+       int all_idle = 1;
+
+       prepare_to_wait(&vc->wq, &wait, TASK_INTERRUPTIBLE);
+       vc->vcore_state = VCORE_SLEEPING;
+       spin_unlock(&vc->lock);
+       list_for_each_entry(v, &vc->runnable_threads, arch.run_list) {
+               if (!v->arch.ceded || v->arch.pending_exceptions) {
+                       all_idle = 0;
+                       break;
+               }
        }
+       if (all_idle)
+               schedule();
+       finish_wait(&vc->wq, &wait);
+       spin_lock(&vc->lock);
+       vc->vcore_state = VCORE_INACTIVE;
+}
 
-       /* On PPC970, check that we have an RMA region */
-       if (!vcpu->kvm->arch.rma && cpu_has_feature(CPU_FTR_ARCH_201))
-               return -EPERM;
+static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
+{
+       int n_ceded;
+       int prev_state;
+       struct kvmppc_vcore *vc;
+       struct kvm_vcpu *v, *vn;
 
        kvm_run->exit_reason = 0;
        vcpu->arch.ret = RESUME_GUEST;
        vcpu->arch.trap = 0;
 
-       flush_fp_to_thread(current);
-       flush_altivec_to_thread(current);
-       flush_vsx_to_thread(current);
-
        /*
         * Synchronize with other threads in this virtual core
         */
        vc = vcpu->arch.vcore;
        spin_lock(&vc->lock);
-       /* This happens the first time this is called for a vcpu */
-       if (vcpu->arch.state == KVMPPC_VCPU_BLOCKED)
-               --vc->n_blocked;
-       vcpu->arch.state = KVMPPC_VCPU_RUNNABLE;
-       ptid = vc->n_runnable;
+       vcpu->arch.ceded = 0;
        vcpu->arch.run_task = current;
        vcpu->arch.kvm_run = kvm_run;
-       vcpu->arch.ptid = ptid;
+       prev_state = vcpu->arch.state;
+       vcpu->arch.state = KVMPPC_VCPU_RUNNABLE;
        list_add_tail(&vcpu->arch.run_list, &vc->runnable_threads);
        ++vc->n_runnable;
 
-       wait_state = TASK_INTERRUPTIBLE;
-       while (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE) {
-               if (signal_pending(current)) {
-                       if (!vc->vcore_running) {
-                               kvm_run->exit_reason = KVM_EXIT_INTR;
-                               vcpu->arch.ret = -EINTR;
-                               break;
-                       }
-                       /* have to wait for vcore to stop executing guest */
-                       wait_state = TASK_UNINTERRUPTIBLE;
-                       smp_send_reschedule(vc->pcpu);
+       /*
+        * This happens the first time this is called for a vcpu.
+        * If the vcore is already running, we may be able to start
+        * this thread straight away and have it join in.
+        */
+       if (prev_state == KVMPPC_VCPU_STOPPED) {
+               if (vc->vcore_state == VCORE_RUNNING &&
+                   VCORE_EXIT_COUNT(vc) == 0) {
+                       vcpu->arch.ptid = vc->n_runnable - 1;
+                       kvmppc_start_thread(vcpu);
                }
 
-               if (!vc->vcore_running &&
-                   vc->n_runnable + vc->n_blocked == vc->num_threads) {
-                       /* we can run now */
-                       if (kvmppc_run_core(vc))
-                               continue;
-               }
+       } else if (prev_state == KVMPPC_VCPU_BUSY_IN_HOST)
+               --vc->n_busy;
 
-               if (vc->vcore_running == 1 && VCORE_EXIT_COUNT(vc) == 0)
-                       kvmppc_start_thread(vcpu);
+       while (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE &&
+              !signal_pending(current)) {
+               if (vc->n_busy || vc->vcore_state != VCORE_INACTIVE) {
+                       spin_unlock(&vc->lock);
+                       kvmppc_wait_for_exec(vcpu, TASK_INTERRUPTIBLE);
+                       spin_lock(&vc->lock);
+                       continue;
+               }
+               n_ceded = 0;
+               list_for_each_entry(v, &vc->runnable_threads, arch.run_list)
+                       n_ceded += v->arch.ceded;
+               if (n_ceded == vc->n_runnable)
+                       kvmppc_vcore_blocked(vc);
+               else
+                       kvmppc_run_core(vc);
+
+               list_for_each_entry_safe(v, vn, &vc->runnable_threads,
+                                        arch.run_list) {
+                       kvmppc_core_deliver_interrupts(v);
+                       if (signal_pending(v->arch.run_task)) {
+                               kvmppc_remove_runnable(vc, v);
+                               v->stat.signal_exits++;
+                               v->arch.kvm_run->exit_reason = KVM_EXIT_INTR;
+                               v->arch.ret = -EINTR;
+                               wake_up(&v->arch.cpu_run);
+                       }
+               }
+       }
 
-               /* wait for other threads to come in, or wait for vcore */
-               prepare_to_wait(&vcpu->arch.cpu_run, &wait, wait_state);
-               spin_unlock(&vc->lock);
-               schedule();
-               finish_wait(&vcpu->arch.cpu_run, &wait);
-               spin_lock(&vc->lock);
+       if (signal_pending(current)) {
+               if (vc->vcore_state == VCORE_RUNNING ||
+                   vc->vcore_state == VCORE_EXITING) {
+                       spin_unlock(&vc->lock);
+                       kvmppc_wait_for_exec(vcpu, TASK_UNINTERRUPTIBLE);
+                       spin_lock(&vc->lock);
+               }
+               if (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE) {
+                       kvmppc_remove_runnable(vc, vcpu);
+                       vcpu->stat.signal_exits++;
+                       kvm_run->exit_reason = KVM_EXIT_INTR;
+                       vcpu->arch.ret = -EINTR;
+               }
        }
 
-       if (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE)
-               kvmppc_remove_runnable(vc, vcpu);
        spin_unlock(&vc->lock);
-
        return vcpu->arch.ret;
 }
 
@@ -800,6 +829,26 @@ int kvmppc_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)
 {
        int r;
 
+       if (!vcpu->arch.sane) {
+               run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+               return -EINVAL;
+       }
+
+       /* No need to go into the guest when all we'll do is come back out */
+       if (signal_pending(current)) {
+               run->exit_reason = KVM_EXIT_INTR;
+               return -EINTR;
+       }
+
+       /* On PPC970, check that we have an RMA region */
+       if (!vcpu->kvm->arch.rma && cpu_has_feature(CPU_FTR_ARCH_201))
+               return -EPERM;
+
+       flush_fp_to_thread(current);
+       flush_altivec_to_thread(current);
+       flush_vsx_to_thread(current);
+       vcpu->arch.wqp = &vcpu->arch.vcore->wq;
+
        do {
                r = kvmppc_run_vcpu(run, vcpu);
 
index fcfe6b0..bacb0cf 100644 (file)
@@ -110,39 +110,6 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
        return H_SUCCESS;
 }
 
-static unsigned long compute_tlbie_rb(unsigned long v, unsigned long r,
-                                     unsigned long pte_index)
-{
-       unsigned long rb, va_low;
-
-       rb = (v & ~0x7fUL) << 16;               /* AVA field */
-       va_low = pte_index >> 3;
-       if (v & HPTE_V_SECONDARY)
-               va_low = ~va_low;
-       /* xor vsid from AVA */
-       if (!(v & HPTE_V_1TB_SEG))
-               va_low ^= v >> 12;
-       else
-               va_low ^= v >> 24;
-       va_low &= 0x7ff;
-       if (v & HPTE_V_LARGE) {
-               rb |= 1;                        /* L field */
-               if (cpu_has_feature(CPU_FTR_ARCH_206) &&
-                   (r & 0xff000)) {
-                       /* non-16MB large page, must be 64k */
-                       /* (masks depend on page size) */
-                       rb |= 0x1000;           /* page encoding in LP field */
-                       rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
-                       rb |= (va_low & 0xfe);  /* AVAL field (P7 doesn't seem to care) */
-               }
-       } else {
-               /* 4kB page */
-               rb |= (va_low & 0x7ff) << 12;   /* remaining 11b of VA */
-       }
-       rb |= (v >> 54) & 0x300;                /* B field */
-       return rb;
-}
-
 #define LOCK_TOKEN     (*(u32 *)(&get_paca()->lock_token))
 
 static inline int try_lock_tlbie(unsigned int *lock)
index de29501..f422231 100644 (file)
 #include <asm/ppc_asm.h>
 #include <asm/kvm_asm.h>
 #include <asm/reg.h>
+#include <asm/mmu.h>
 #include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/hvcall.h>
 #include <asm/asm-offsets.h>
 #include <asm/exception-64s.h>
 
@@ -49,7 +52,7 @@ kvmppc_skip_Hinterrupt:
        b       .
 
 /*
- * Call kvmppc_handler_trampoline_enter in real mode.
+ * Call kvmppc_hv_entry in real mode.
  * Must be called with interrupts hard-disabled.
  *
  * Input Registers:
@@ -89,6 +92,12 @@ _GLOBAL(kvmppc_hv_entry_trampoline)
 kvm_start_guest:
        ld      r1,PACAEMERGSP(r13)
        subi    r1,r1,STACK_FRAME_OVERHEAD
+       ld      r2,PACATOC(r13)
+
+       /* were we napping due to cede? */
+       lbz     r0,HSTATE_NAPPING(r13)
+       cmpwi   r0,0
+       bne     kvm_end_cede
 
        /* get vcpu pointer */
        ld      r4, HSTATE_KVM_VCPU(r13)
@@ -276,15 +285,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        cmpwi   r0,0
        beq     20b
 
-       /* Set LPCR.  Set the MER bit if there is a pending external irq. */
+       /* Set LPCR and RMOR. */
 10:    ld      r8,KVM_LPCR(r9)
-       ld      r0,VCPU_PENDING_EXC(r4)
-       li      r7,(1 << BOOK3S_IRQPRIO_EXTERNAL)
-       oris    r7,r7,(1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h
-       and.    r0,r0,r7
-       beq     11f
-       ori     r8,r8,LPCR_MER
-11:    mtspr   SPRN_LPCR,r8
+       mtspr   SPRN_LPCR,r8
        ld      r8,KVM_RMOR(r9)
        mtspr   SPRN_RMOR,r8
        isync
@@ -448,19 +451,50 @@ toc_tlbie_lock:
        mtctr   r6
        mtxer   r7
 
-       /* Move SRR0 and SRR1 into the respective regs */
+kvmppc_cede_reentry:           /* r4 = vcpu, r13 = paca */
        ld      r6, VCPU_SRR0(r4)
        ld      r7, VCPU_SRR1(r4)
-       mtspr   SPRN_SRR0, r6
-       mtspr   SPRN_SRR1, r7
-
        ld      r10, VCPU_PC(r4)
+       ld      r11, VCPU_MSR(r4)       /* r11 = vcpu->arch.msr & ~MSR_HV */
 
-       ld      r11, VCPU_MSR(r4)       /* r10 = vcpu->arch.msr & ~MSR_HV */
        rldicl  r11, r11, 63 - MSR_HV_LG, 1
        rotldi  r11, r11, 1 + MSR_HV_LG
        ori     r11, r11, MSR_ME
 
+       /* Check if we can deliver an external or decrementer interrupt now */
+       ld      r0,VCPU_PENDING_EXC(r4)
+       li      r8,(1 << BOOK3S_IRQPRIO_EXTERNAL)
+       oris    r8,r8,(1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h
+       and     r0,r0,r8
+       cmpdi   cr1,r0,0
+       andi.   r0,r11,MSR_EE
+       beq     cr1,11f
+BEGIN_FTR_SECTION
+       mfspr   r8,SPRN_LPCR
+       ori     r8,r8,LPCR_MER
+       mtspr   SPRN_LPCR,r8
+       isync
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
+       beq     5f
+       li      r0,BOOK3S_INTERRUPT_EXTERNAL
+12:    mr      r6,r10
+       mr      r10,r0
+       mr      r7,r11
+       li      r11,(MSR_ME << 1) | 1   /* synthesize MSR_SF | MSR_ME */
+       rotldi  r11,r11,63
+       b       5f
+11:    beq     5f
+       mfspr   r0,SPRN_DEC
+       cmpwi   r0,0
+       li      r0,BOOK3S_INTERRUPT_DECREMENTER
+       blt     12b
+
+       /* Move SRR0 and SRR1 into the respective regs */
+5:     mtspr   SPRN_SRR0, r6
+       mtspr   SPRN_SRR1, r7
+       li      r0,0
+       stb     r0,VCPU_CEDED(r4)       /* cancel cede */
+
 fast_guest_return:
        mtspr   SPRN_HSRR0,r10
        mtspr   SPRN_HSRR1,r11
@@ -574,21 +608,20 @@ kvmppc_interrupt:
        /* See if this is something we can handle in real mode */
        cmpwi   r12,BOOK3S_INTERRUPT_SYSCALL
        beq     hcall_try_real_mode
-hcall_real_cont:
 
        /* Check for mediated interrupts (could be done earlier really ...) */
 BEGIN_FTR_SECTION
        cmpwi   r12,BOOK3S_INTERRUPT_EXTERNAL
        bne+    1f
-       ld      r5,VCPU_KVM(r9)
-       ld      r5,KVM_LPCR(r5)
        andi.   r0,r11,MSR_EE
        beq     1f
+       mfspr   r5,SPRN_LPCR
        andi.   r0,r5,LPCR_MER
        bne     bounce_ext_interrupt
 1:
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 
+hcall_real_cont:               /* r9 = vcpu, r12 = trap, r13 = paca */
        /* Save DEC */
        mfspr   r5,SPRN_DEC
        mftb    r6
@@ -682,7 +715,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_201)
        slbia
        ptesync
 
-hdec_soon:
+hdec_soon:                     /* r9 = vcpu, r12 = trap, r13 = paca */
 BEGIN_FTR_SECTION
        b       32f
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
@@ -700,6 +733,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        addi    r0,r3,0x100
        stwcx.  r0,0,r6
        bne     41b
+       lwsync
 
        /*
         * At this point we have an interrupt that we have to pass
@@ -713,18 +747,39 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
         * interrupt, since the other threads will already be on their
         * way here in that case.
         */
+       cmpwi   r3,0x100        /* Are we the first here? */
+       bge     43f
+       cmpwi   r3,1            /* Are any other threads in the guest? */
+       ble     43f
        cmpwi   r12,BOOK3S_INTERRUPT_HV_DECREMENTER
        beq     40f
-       cmpwi   r3,0x100        /* Are we the first here? */
-       bge     40f
-       cmpwi   r3,1
-       ble     40f
        li      r0,0
        mtspr   SPRN_HDEC,r0
 40:
+       /*
+        * Send an IPI to any napping threads, since an HDEC interrupt
+        * doesn't wake CPUs up from nap.
+        */
+       lwz     r3,VCORE_NAPPING_THREADS(r5)
+       lwz     r4,VCPU_PTID(r9)
+       li      r0,1
+       sldi    r0,r0,r4
+       andc.   r3,r3,r0                /* no sense IPI'ing ourselves */
+       beq     43f
+       mulli   r4,r4,PACA_SIZE         /* get paca for thread 0 */
+       subf    r6,r4,r13
+42:    andi.   r0,r3,1
+       beq     44f
+       ld      r8,HSTATE_XICS_PHYS(r6) /* get thread's XICS reg addr */
+       li      r0,IPI_PRIORITY
+       li      r7,XICS_QIRR
+       stbcix  r0,r7,r8                /* trigger the IPI */
+44:    srdi.   r3,r3,1
+       addi    r6,r6,PACA_SIZE
+       bne     42b
 
        /* Secondary threads wait for primary to do partition switch */
-       ld      r4,VCPU_KVM(r9)         /* pointer to struct kvm */
+43:    ld      r4,VCPU_KVM(r9)         /* pointer to struct kvm */
        ld      r5,HSTATE_KVM_VCORE(r13)
        lwz     r3,VCPU_PTID(r9)
        cmpwi   r3,0
@@ -1077,7 +1132,6 @@ hcall_try_real_mode:
 hcall_real_fallback:
        li      r12,BOOK3S_INTERRUPT_SYSCALL
        ld      r9, HSTATE_KVM_VCPU(r13)
-       ld      r11, VCPU_MSR(r9)
 
        b       hcall_real_cont
 
@@ -1139,7 +1193,7 @@ hcall_real_table:
        .long   0               /* 0xd4 */
        .long   0               /* 0xd8 */
        .long   0               /* 0xdc */
-       .long   0               /* 0xe0 */
+       .long   .kvmppc_h_cede - hcall_real_table
        .long   0               /* 0xe4 */
        .long   0               /* 0xe8 */
        .long   0               /* 0xec */
@@ -1168,7 +1222,8 @@ bounce_ext_interrupt:
        mtspr   SPRN_SRR0,r10
        mtspr   SPRN_SRR1,r11
        li      r10,BOOK3S_INTERRUPT_EXTERNAL
-       LOAD_REG_IMMEDIATE(r11,MSR_SF | MSR_ME);
+       li      r11,(MSR_ME << 1) | 1   /* synthesize MSR_SF | MSR_ME */
+       rotldi  r11,r11,63
        b       fast_guest_return
 
 _GLOBAL(kvmppc_h_set_dabr)
@@ -1177,6 +1232,178 @@ _GLOBAL(kvmppc_h_set_dabr)
        li      r3,0
        blr
 
+_GLOBAL(kvmppc_h_cede)
+       ori     r11,r11,MSR_EE
+       std     r11,VCPU_MSR(r3)
+       li      r0,1
+       stb     r0,VCPU_CEDED(r3)
+       sync                    /* order setting ceded vs. testing prodded */
+       lbz     r5,VCPU_PRODDED(r3)
+       cmpwi   r5,0
+       bne     1f
+       li      r0,0            /* set trap to 0 to say hcall is handled */
+       stw     r0,VCPU_TRAP(r3)
+       li      r0,H_SUCCESS
+       std     r0,VCPU_GPR(r3)(r3)
+BEGIN_FTR_SECTION
+       b       2f              /* just send it up to host on 970 */
+END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
+
+       /*
+        * Set our bit in the bitmask of napping threads unless all the
+        * other threads are already napping, in which case we send this
+        * up to the host.
+        */
+       ld      r5,HSTATE_KVM_VCORE(r13)
+       lwz     r6,VCPU_PTID(r3)
+       lwz     r8,VCORE_ENTRY_EXIT(r5)
+       clrldi  r8,r8,56
+       li      r0,1
+       sld     r0,r0,r6
+       addi    r6,r5,VCORE_NAPPING_THREADS
+31:    lwarx   r4,0,r6
+       or      r4,r4,r0
+       popcntw r7,r4
+       cmpw    r7,r8
+       bge     2f
+       stwcx.  r4,0,r6
+       bne     31b
+       li      r0,1
+       stb     r0,HSTATE_NAPPING(r13)
+       /* order napping_threads update vs testing entry_exit_count */
+       lwsync
+       mr      r4,r3
+       lwz     r7,VCORE_ENTRY_EXIT(r5)
+       cmpwi   r7,0x100
+       bge     33f             /* another thread already exiting */
+
+/*
+ * Although not specifically required by the architecture, POWER7
+ * preserves the following registers in nap mode, even if an SMT mode
+ * switch occurs: SLB entries, PURR, SPURR, AMOR, UAMOR, AMR, SPRG0-3,
+ * DAR, DSISR, DABR, DABRX, DSCR, PMCx, MMCRx, SIAR, SDAR.
+ */
+       /* Save non-volatile GPRs */
+       std     r14, VCPU_GPR(r14)(r3)
+       std     r15, VCPU_GPR(r15)(r3)
+       std     r16, VCPU_GPR(r16)(r3)
+       std     r17, VCPU_GPR(r17)(r3)
+       std     r18, VCPU_GPR(r18)(r3)
+       std     r19, VCPU_GPR(r19)(r3)
+       std     r20, VCPU_GPR(r20)(r3)
+       std     r21, VCPU_GPR(r21)(r3)
+       std     r22, VCPU_GPR(r22)(r3)
+       std     r23, VCPU_GPR(r23)(r3)
+       std     r24, VCPU_GPR(r24)(r3)
+       std     r25, VCPU_GPR(r25)(r3)
+       std     r26, VCPU_GPR(r26)(r3)
+       std     r27, VCPU_GPR(r27)(r3)
+       std     r28, VCPU_GPR(r28)(r3)
+       std     r29, VCPU_GPR(r29)(r3)
+       std     r30, VCPU_GPR(r30)(r3)
+       std     r31, VCPU_GPR(r31)(r3)
+
+       /* save FP state */
+       bl      .kvmppc_save_fp
+
+       /*
+        * Take a nap until a decrementer or external interrupt occurs,
+        * with PECE1 (wake on decr) and PECE0 (wake on external) set in LPCR
+        */
+       li      r0,0x80
+       stb     r0,PACAPROCSTART(r13)
+       mfspr   r5,SPRN_LPCR
+       ori     r5,r5,LPCR_PECE0 | LPCR_PECE1
+       mtspr   SPRN_LPCR,r5
+       isync
+       li      r0, 0
+       std     r0, HSTATE_SCRATCH0(r13)
+       ptesync
+       ld      r0, HSTATE_SCRATCH0(r13)
+1:     cmpd    r0, r0
+       bne     1b
+       nap
+       b       .
+
+kvm_end_cede:
+       /* Woken by external or decrementer interrupt */
+       ld      r1, HSTATE_HOST_R1(r13)
+       ld      r2, PACATOC(r13)
+
+       /* If we're a secondary thread and we got here by an IPI, ack it */
+       ld      r4,HSTATE_KVM_VCPU(r13)
+       lwz     r3,VCPU_PTID(r4)
+       cmpwi   r3,0
+       beq     27f
+       mfspr   r3,SPRN_SRR1
+       rlwinm  r3,r3,44-31,0x7         /* extract wake reason field */
+       cmpwi   r3,4                    /* was it an external interrupt? */
+       bne     27f
+       ld      r5, HSTATE_XICS_PHYS(r13)
+       li      r0,0xff
+       li      r6,XICS_QIRR
+       li      r7,XICS_XIRR
+       lwzcix  r8,r5,r7                /* ack the interrupt */
+       sync
+       stbcix  r0,r5,r6                /* clear it */
+       stwcix  r8,r5,r7                /* EOI it */
+27:
+       /* load up FP state */
+       bl      kvmppc_load_fp
+
+       /* Load NV GPRS */
+       ld      r14, VCPU_GPR(r14)(r4)
+       ld      r15, VCPU_GPR(r15)(r4)
+       ld      r16, VCPU_GPR(r16)(r4)
+       ld      r17, VCPU_GPR(r17)(r4)
+       ld      r18, VCPU_GPR(r18)(r4)
+       ld      r19, VCPU_GPR(r19)(r4)
+       ld      r20, VCPU_GPR(r20)(r4)
+       ld      r21, VCPU_GPR(r21)(r4)
+       ld      r22, VCPU_GPR(r22)(r4)
+       ld      r23, VCPU_GPR(r23)(r4)
+       ld      r24, VCPU_GPR(r24)(r4)
+       ld      r25, VCPU_GPR(r25)(r4)
+       ld      r26, VCPU_GPR(r26)(r4)
+       ld      r27, VCPU_GPR(r27)(r4)
+       ld      r28, VCPU_GPR(r28)(r4)
+       ld      r29, VCPU_GPR(r29)(r4)
+       ld      r30, VCPU_GPR(r30)(r4)
+       ld      r31, VCPU_GPR(r31)(r4)
+
+       /* clear our bit in vcore->napping_threads */
+33:    ld      r5,HSTATE_KVM_VCORE(r13)
+       lwz     r3,VCPU_PTID(r4)
+       li      r0,1
+       sld     r0,r0,r3
+       addi    r6,r5,VCORE_NAPPING_THREADS
+32:    lwarx   r7,0,r6
+       andc    r7,r7,r0
+       stwcx.  r7,0,r6
+       bne     32b
+       li      r0,0
+       stb     r0,HSTATE_NAPPING(r13)
+
+       /* see if any other thread is already exiting */
+       lwz     r0,VCORE_ENTRY_EXIT(r5)
+       cmpwi   r0,0x100
+       blt     kvmppc_cede_reentry     /* if not go back to guest */
+
+       /* some threads are exiting, so go to the guest exit path */
+       b       hcall_real_fallback
+
+       /* cede when already previously prodded case */
+1:     li      r0,0
+       stb     r0,VCPU_PRODDED(r3)
+       sync                    /* order testing prodded vs. clearing ceded */
+       stb     r0,VCPU_CEDED(r3)
+       li      r3,H_SUCCESS
+       blr
+
+       /* we've ceded but we want to give control to the host */
+2:     li      r3,H_TOO_HARD
+       blr
+
 secondary_too_late:
        ld      r5,HSTATE_KVM_VCORE(r13)
        HMT_LOW
@@ -1194,14 +1421,20 @@ secondary_too_late:
        slbmte  r6,r5
 1:     addi    r11,r11,16
        .endr
-       b       50f
 
 secondary_nap:
-       /* Clear any pending IPI */
-50:    ld      r5, HSTATE_XICS_PHYS(r13)
+       /* Clear any pending IPI - assume we're a secondary thread */
+       ld      r5, HSTATE_XICS_PHYS(r13)
+       li      r7, XICS_XIRR
+       lwzcix  r3, r5, r7              /* ack any pending interrupt */
+       rlwinm. r0, r3, 0, 0xffffff     /* any pending? */
+       beq     37f
+       sync
        li      r0, 0xff
        li      r6, XICS_QIRR
-       stbcix  r0, r5, r6
+       stbcix  r0, r5, r6              /* clear the IPI */
+       stwcix  r3, r5, r7              /* EOI it */
+37:    sync
 
        /* increment the nap count and then go to nap mode */
        ld      r4, HSTATE_KVM_VCORE(r13)
@@ -1211,13 +1444,12 @@ secondary_nap:
        addi    r3, r3, 1
        stwcx.  r3, 0, r4
        bne     51b
-       isync
 
+       li      r3, LPCR_PECE0
        mfspr   r4, SPRN_LPCR
-       li      r0, LPCR_PECE
-       andc    r4, r4, r0
-       ori     r4, r4, LPCR_PECE0      /* exit nap on interrupt */
+       rlwimi  r4, r3, 0, LPCR_PECE0 | LPCR_PECE1
        mtspr   SPRN_LPCR, r4
+       isync
        li      r0, 0
        std     r0, HSTATE_SCRATCH0(r13)
        ptesync
index c54b0e3..0a8515a 100644 (file)
 #define ULONG_SIZE             8
 #define FUNC(name)             GLUE(.,name)
 
-#define GET_SHADOW_VCPU_R13
-
-#define DISABLE_INTERRUPTS     \
-       mfmsr   r0;             \
-       rldicl  r0,r0,48,1;     \
-       rotldi  r0,r0,16;       \
-       mtmsrd  r0,1;           \
-
 #elif defined(CONFIG_PPC_BOOK3S_32)
 
 #define ULONG_SIZE              4
 #define FUNC(name)             name
 
-#define GET_SHADOW_VCPU_R13    \
-       lwz     r13, (THREAD + THREAD_KVM_SVCPU)(r2)
-
-#define DISABLE_INTERRUPTS     \
-       mfmsr   r0;             \
-       rlwinm  r0,r0,0,17,15;  \
-       mtmsr   r0;             \
-
 #endif /* CONFIG_PPC_BOOK3S_XX */
 
 
@@ -108,44 +92,17 @@ kvm_start_entry:
 
 kvm_start_lightweight:
 
-       GET_SHADOW_VCPU_R13
-       PPC_LL  r3, VCPU_HIGHMEM_HANDLER(r4)
-       PPC_STL r3, HSTATE_VMHANDLER(r13)
-
-       PPC_LL  r10, VCPU_SHADOW_MSR(r4)        /* r10 = vcpu->arch.shadow_msr */
-
-       DISABLE_INTERRUPTS
-
 #ifdef CONFIG_PPC_BOOK3S_64
-       /* Some guests may need to have dcbz set to 32 byte length.
-        *
-        * Usually we ensure that by patching the guest's instructions
-        * to trap on dcbz and emulate it in the hypervisor.
-        *
-        * If we can, we should tell the CPU to use 32 byte dcbz though,
-        * because that's a lot faster.
-        */
-
        PPC_LL  r3, VCPU_HFLAGS(r4)
-       rldicl. r3, r3, 0, 63           /* CR = ((r3 & 1) == 0) */
-       beq     no_dcbz32_on
-
-       mfspr   r3,SPRN_HID5
-       ori     r3, r3, 0x80            /* XXX HID5_dcbz32 = 0x80 */
-       mtspr   SPRN_HID5,r3
-
-no_dcbz32_on:
-
+       rldicl  r3, r3, 0, 63           /* r3 &= 1 */
+       stb     r3, HSTATE_RESTORE_HID5(r13)
 #endif /* CONFIG_PPC_BOOK3S_64 */
 
-       PPC_LL  r6, VCPU_RMCALL(r4)
-       mtctr   r6
-
-       PPC_LL  r3, VCPU_TRAMPOLINE_ENTER(r4)
-       LOAD_REG_IMMEDIATE(r4, MSR_KERNEL & ~(MSR_IR | MSR_DR))
+       PPC_LL  r4, VCPU_SHADOW_MSR(r4) /* get shadow_msr */
 
        /* Jump to segment patching handler and into our guest */
-       bctr
+       bl      FUNC(kvmppc_entry_trampoline)
+       nop
 
 /*
  * This is the handler in module memory. It gets jumped at from the
@@ -170,21 +127,6 @@ kvmppc_handler_highmem:
        /* R7 = vcpu */
        PPC_LL  r7, GPR4(r1)
 
-#ifdef CONFIG_PPC_BOOK3S_64
-
-       PPC_LL  r5, VCPU_HFLAGS(r7)
-       rldicl. r5, r5, 0, 63           /* CR = ((r5 & 1) == 0) */
-       beq     no_dcbz32_off
-
-       li      r4, 0
-       mfspr   r5,SPRN_HID5
-       rldimi  r5,r4,6,56
-       mtspr   SPRN_HID5,r5
-
-no_dcbz32_off:
-
-#endif /* CONFIG_PPC_BOOK3S_64 */
-
        PPC_STL r14, VCPU_GPR(r14)(r7)
        PPC_STL r15, VCPU_GPR(r15)(r7)
        PPC_STL r16, VCPU_GPR(r16)(r7)
@@ -204,67 +146,6 @@ no_dcbz32_off:
        PPC_STL r30, VCPU_GPR(r30)(r7)
        PPC_STL r31, VCPU_GPR(r31)(r7)
 
-       /* Restore host msr -> SRR1 */
-       PPC_LL  r6, VCPU_HOST_MSR(r7)
-
-       /*
-        * For some interrupts, we need to call the real Linux
-        * handler, so it can do work for us. This has to happen
-        * as if the interrupt arrived from the kernel though,
-        * so let's fake it here where most state is restored.
-        *
-        * Call Linux for hardware interrupts/decrementer
-        * r3 = address of interrupt handler (exit reason)
-        */
-
-       cmpwi   r12, BOOK3S_INTERRUPT_EXTERNAL
-       beq     call_linux_handler
-       cmpwi   r12, BOOK3S_INTERRUPT_DECREMENTER
-       beq     call_linux_handler
-       cmpwi   r12, BOOK3S_INTERRUPT_PERFMON
-       beq     call_linux_handler
-
-       /* Back to EE=1 */
-       mtmsr   r6
-       sync
-       b       kvm_return_point
-
-call_linux_handler:
-
-       /*
-        * If we land here we need to jump back to the handler we
-        * came from.
-        *
-        * We have a page that we can access from real mode, so let's
-        * jump back to that and use it as a trampoline to get back into the
-        * interrupt handler!
-        *
-        * R3 still contains the exit code,
-        * R5 VCPU_HOST_RETIP and
-        * R6 VCPU_HOST_MSR
-        */
-
-       /* Restore host IP -> SRR0 */
-       PPC_LL  r5, VCPU_HOST_RETIP(r7)
-
-       /* XXX Better move to a safe function?
-        *     What if we get an HTAB flush in between mtsrr0 and mtsrr1? */
-
-       mtlr    r12
-
-       PPC_LL  r4, VCPU_TRAMPOLINE_LOWMEM(r7)
-       mtsrr0  r4
-       LOAD_REG_IMMEDIATE(r3, MSR_KERNEL & ~(MSR_IR | MSR_DR))
-       mtsrr1  r3
-
-       RFI
-
-.global kvm_return_point
-kvm_return_point:
-
-       /* Jump back to lightweight entry if we're supposed to */
-       /* go back into the guest */
-
        /* Pass the exit number as 3rd argument to kvmppc_handle_exit */
        mr      r5, r12
 
index 0c0d3f2..d417511 100644 (file)
@@ -150,16 +150,22 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
 #ifdef CONFIG_PPC_BOOK3S_64
        if ((pvr >= 0x330000) && (pvr < 0x70330000)) {
                kvmppc_mmu_book3s_64_init(vcpu);
-               to_book3s(vcpu)->hior = 0xfff00000;
+               if (!to_book3s(vcpu)->hior_sregs)
+                       to_book3s(vcpu)->hior = 0xfff00000;
                to_book3s(vcpu)->msr_mask = 0xffffffffffffffffULL;
+               vcpu->arch.cpu_type = KVM_CPU_3S_64;
        } else
 #endif
        {
                kvmppc_mmu_book3s_32_init(vcpu);
-               to_book3s(vcpu)->hior = 0;
+               if (!to_book3s(vcpu)->hior_sregs)
+                       to_book3s(vcpu)->hior = 0;
                to_book3s(vcpu)->msr_mask = 0xffffffffULL;
+               vcpu->arch.cpu_type = KVM_CPU_3S_32;
        }
 
+       kvmppc_sanity_check(vcpu);
+
        /* If we are in hypervisor level on 970, we can tell the CPU to
         * treat DCBZ as 32 bytes store */
        vcpu->arch.hflags &= ~BOOK3S_HFLAG_DCBZ32;
@@ -646,7 +652,27 @@ program_interrupt:
                break;
        }
        case BOOK3S_INTERRUPT_SYSCALL:
-               if (vcpu->arch.osi_enabled &&
+               if (vcpu->arch.papr_enabled &&
+                   (kvmppc_get_last_inst(vcpu) == 0x44000022) &&
+                   !(vcpu->arch.shared->msr & MSR_PR)) {
+                       /* SC 1 papr hypercalls */
+                       ulong cmd = kvmppc_get_gpr(vcpu, 3);
+                       int i;
+
+                       if (kvmppc_h_pr(vcpu, cmd) == EMULATE_DONE) {
+                               r = RESUME_GUEST;
+                               break;
+                       }
+
+                       run->papr_hcall.nr = cmd;
+                       for (i = 0; i < 9; ++i) {
+                               ulong gpr = kvmppc_get_gpr(vcpu, 4 + i);
+                               run->papr_hcall.args[i] = gpr;
+                       }
+                       run->exit_reason = KVM_EXIT_PAPR_HCALL;
+                       vcpu->arch.hcall_needed = 1;
+                       r = RESUME_HOST;
+               } else if (vcpu->arch.osi_enabled &&
                    (((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) &&
                    (((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) {
                        /* MOL hypercalls */
@@ -770,6 +796,9 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
                }
        }
 
+       if (sregs->u.s.flags & KVM_SREGS_S_HIOR)
+               sregs->u.s.hior = to_book3s(vcpu)->hior;
+
        return 0;
 }
 
@@ -806,6 +835,11 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
        /* Flush the MMU after messing with the segments */
        kvmppc_mmu_pte_flush(vcpu, 0, 0);
 
+       if (sregs->u.s.flags & KVM_SREGS_S_HIOR) {
+               to_book3s(vcpu)->hior_sregs = true;
+               to_book3s(vcpu)->hior = sregs->u.s.hior;
+       }
+
        return 0;
 }
 
@@ -841,8 +875,6 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
        if (!p)
                goto uninit_vcpu;
 
-       vcpu->arch.host_retip = kvm_return_point;
-       vcpu->arch.host_msr = mfmsr();
 #ifdef CONFIG_PPC_BOOK3S_64
        /* default to book3s_64 (970fx) */
        vcpu->arch.pvr = 0x3C0301;
@@ -853,16 +885,6 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
        kvmppc_set_pvr(vcpu, vcpu->arch.pvr);
        vcpu->arch.slb_nr = 64;
 
-       /* remember where some real-mode handlers are */
-       vcpu->arch.trampoline_lowmem = __pa(kvmppc_handler_lowmem_trampoline);
-       vcpu->arch.trampoline_enter = __pa(kvmppc_handler_trampoline_enter);
-       vcpu->arch.highmem_handler = (ulong)kvmppc_handler_highmem;
-#ifdef CONFIG_PPC_BOOK3S_64
-       vcpu->arch.rmcall = *(ulong*)kvmppc_rmcall;
-#else
-       vcpu->arch.rmcall = (ulong)kvmppc_rmcall;
-#endif
-
        vcpu->arch.shadow_msr = MSR_USER64;
 
        err = kvmppc_mmu_init(vcpu);
@@ -908,6 +930,12 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 #endif
        ulong ext_msr;
 
+       /* Check if we can run the vcpu at all */
+       if (!vcpu->arch.sane) {
+               kvm_run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+               return -EINVAL;
+       }
+
        /* No need to go into the guest when all we do is going out */
        if (signal_pending(current)) {
                kvm_run->exit_reason = KVM_EXIT_INTR;
diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c
new file mode 100644 (file)
index 0000000..b958932
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2011. Freescale Inc. All rights reserved.
+ *
+ * Authors:
+ *    Alexander Graf <agraf@suse.de>
+ *    Paul Mackerras <paulus@samba.org>
+ *
+ * Description:
+ *
+ * Hypercall handling for running PAPR guests in PR KVM on Book 3S
+ * processors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/uaccess.h>
+#include <asm/kvm_ppc.h>
+#include <asm/kvm_book3s.h>
+
+static unsigned long get_pteg_addr(struct kvm_vcpu *vcpu, long pte_index)
+{
+       struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
+       unsigned long pteg_addr;
+
+       pte_index <<= 4;
+       pte_index &= ((1 << ((vcpu_book3s->sdr1 & 0x1f) + 11)) - 1) << 7 | 0x70;
+       pteg_addr = vcpu_book3s->sdr1 & 0xfffffffffffc0000ULL;
+       pteg_addr |= pte_index;
+
+       return pteg_addr;
+}
+
+static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu)
+{
+       long flags = kvmppc_get_gpr(vcpu, 4);
+       long pte_index = kvmppc_get_gpr(vcpu, 5);
+       unsigned long pteg[2 * 8];
+       unsigned long pteg_addr, i, *hpte;
+
+       pte_index &= ~7UL;
+       pteg_addr = get_pteg_addr(vcpu, pte_index);
+
+       copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg));
+       hpte = pteg;
+
+       if (likely((flags & H_EXACT) == 0)) {
+               pte_index &= ~7UL;
+               for (i = 0; ; ++i) {
+                       if (i == 8)
+                               return H_PTEG_FULL;
+                       if ((*hpte & HPTE_V_VALID) == 0)
+                               break;
+                       hpte += 2;
+               }
+       } else {
+               i = kvmppc_get_gpr(vcpu, 5) & 7UL;
+               hpte += i * 2;
+       }
+
+       hpte[0] = kvmppc_get_gpr(vcpu, 6);
+       hpte[1] = kvmppc_get_gpr(vcpu, 7);
+       copy_to_user((void __user *)pteg_addr, pteg, sizeof(pteg));
+       kvmppc_set_gpr(vcpu, 3, H_SUCCESS);
+       kvmppc_set_gpr(vcpu, 4, pte_index | i);
+
+       return EMULATE_DONE;
+}
+
+static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu)
+{
+       unsigned long flags= kvmppc_get_gpr(vcpu, 4);
+       unsigned long pte_index = kvmppc_get_gpr(vcpu, 5);
+       unsigned long avpn = kvmppc_get_gpr(vcpu, 6);
+       unsigned long v = 0, pteg, rb;
+       unsigned long pte[2];
+
+       pteg = get_pteg_addr(vcpu, pte_index);
+       copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+
+       if ((pte[0] & HPTE_V_VALID) == 0 ||
+           ((flags & H_AVPN) && (pte[0] & ~0x7fUL) != avpn) ||
+           ((flags & H_ANDCOND) && (pte[0] & avpn) != 0)) {
+               kvmppc_set_gpr(vcpu, 3, H_NOT_FOUND);
+               return EMULATE_DONE;
+       }
+
+       copy_to_user((void __user *)pteg, &v, sizeof(v));
+
+       rb = compute_tlbie_rb(pte[0], pte[1], pte_index);
+       vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
+
+       kvmppc_set_gpr(vcpu, 3, H_SUCCESS);
+       kvmppc_set_gpr(vcpu, 4, pte[0]);
+       kvmppc_set_gpr(vcpu, 5, pte[1]);
+
+       return EMULATE_DONE;
+}
+
+static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu)
+{
+       unsigned long flags = kvmppc_get_gpr(vcpu, 4);
+       unsigned long pte_index = kvmppc_get_gpr(vcpu, 5);
+       unsigned long avpn = kvmppc_get_gpr(vcpu, 6);
+       unsigned long rb, pteg, r, v;
+       unsigned long pte[2];
+
+       pteg = get_pteg_addr(vcpu, pte_index);
+       copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+
+       if ((pte[0] & HPTE_V_VALID) == 0 ||
+           ((flags & H_AVPN) && (pte[0] & ~0x7fUL) != avpn)) {
+               kvmppc_set_gpr(vcpu, 3, H_NOT_FOUND);
+               return EMULATE_DONE;
+       }
+
+       v = pte[0];
+       r = pte[1];
+       r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_HI |
+              HPTE_R_KEY_LO);
+       r |= (flags << 55) & HPTE_R_PP0;
+       r |= (flags << 48) & HPTE_R_KEY_HI;
+       r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
+
+       pte[1] = r;
+
+       rb = compute_tlbie_rb(v, r, pte_index);
+       vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
+       copy_to_user((void __user *)pteg, pte, sizeof(pte));
+
+       kvmppc_set_gpr(vcpu, 3, H_SUCCESS);
+
+       return EMULATE_DONE;
+}
+
+int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
+{
+       switch (cmd) {
+       case H_ENTER:
+               return kvmppc_h_pr_enter(vcpu);
+       case H_REMOVE:
+               return kvmppc_h_pr_remove(vcpu);
+       case H_PROTECT:
+               return kvmppc_h_pr_protect(vcpu);
+       case H_BULK_REMOVE:
+               /* We just flush all PTEs, so user space can
+                  handle the HPT modifications */
+               kvmppc_mmu_pte_flush(vcpu, 0, 0);
+               break;
+       case H_CEDE:
+               kvm_vcpu_block(vcpu);
+               vcpu->stat.halt_wakeup++;
+               return EMULATE_DONE;
+       }
+
+       return EMULATE_FAIL;
+}
index c1f877c..3418758 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/ppc_asm.h>
 #include <asm/kvm_asm.h>
 #include <asm/reg.h>
+#include <asm/mmu.h>
 #include <asm/page.h>
 #include <asm/asm-offsets.h>
 
 
 #if defined(CONFIG_PPC_BOOK3S_64)
 
-#define LOAD_SHADOW_VCPU(reg)  GET_PACA(reg)                                   
-#define MSR_NOIRQ              MSR_KERNEL & ~(MSR_IR | MSR_DR)
 #define FUNC(name)             GLUE(.,name)
+#define MTMSR_EERI(reg)                mtmsrd  (reg),1
 
+       .globl  kvmppc_skip_interrupt
 kvmppc_skip_interrupt:
        /*
         * Here all GPRs are unchanged from when the interrupt happened
@@ -51,6 +52,7 @@ kvmppc_skip_interrupt:
        rfid
        b       .
 
+       .globl  kvmppc_skip_Hinterrupt
 kvmppc_skip_Hinterrupt:
        /*
         * Here all GPRs are unchanged from when the interrupt happened
@@ -65,8 +67,8 @@ kvmppc_skip_Hinterrupt:
 
 #elif defined(CONFIG_PPC_BOOK3S_32)
 
-#define MSR_NOIRQ              MSR_KERNEL
 #define FUNC(name)             name
+#define MTMSR_EERI(reg)                mtmsr   (reg)
 
 .macro INTERRUPT_TRAMPOLINE intno
 
@@ -167,40 +169,24 @@ kvmppc_handler_skip_ins:
 #endif
 
 /*
- * This trampoline brings us back to a real mode handler
- *
- * Input Registers:
- *
- * R5 = SRR0
- * R6 = SRR1
- * LR = real-mode IP
+ * Call kvmppc_handler_trampoline_enter in real mode
  *
+ * On entry, r4 contains the guest shadow MSR
  */
-.global kvmppc_handler_lowmem_trampoline
-kvmppc_handler_lowmem_trampoline:
-
-       mtsrr0  r5
+_GLOBAL(kvmppc_entry_trampoline)
+       mfmsr   r5
+       LOAD_REG_ADDR(r7, kvmppc_handler_trampoline_enter)
+       toreal(r7)
+
+       li      r9, MSR_RI
+       ori     r9, r9, MSR_EE
+       andc    r9, r5, r9      /* Clear EE and RI in MSR value */
+       li      r6, MSR_IR | MSR_DR
+       ori     r6, r6, MSR_EE
+       andc    r6, r5, r6      /* Clear EE, DR and IR in MSR value */
+       MTMSR_EERI(r9)          /* Clear EE and RI in MSR */
+       mtsrr0  r7              /* before we set srr0/1 */
        mtsrr1  r6
-       blr
-kvmppc_handler_lowmem_trampoline_end:
-
-/*
- * Call a function in real mode
- *
- * Input Registers:
- *
- * R3 = function
- * R4 = MSR
- * R5 = scratch register
- *
- */
-_GLOBAL(kvmppc_rmcall)
-       LOAD_REG_IMMEDIATE(r5, MSR_NOIRQ)
-       mtmsr   r5              /* Disable relocation and interrupts, so mtsrr
-                                  doesn't get interrupted */
-       sync
-       mtsrr0  r3
-       mtsrr1  r4
        RFI
 
 #if defined(CONFIG_PPC_BOOK3S_32)
index aed32e5..0676ae2 100644 (file)
@@ -23,6 +23,7 @@
 
 #define GET_SHADOW_VCPU(reg)    \
        mr      reg, r13
+#define MTMSR_EERI(reg)                mtmsrd  (reg),1
 
 #elif defined(CONFIG_PPC_BOOK3S_32)
 
@@ -30,6 +31,7 @@
        tophys(reg, r2);                        \
        lwz     reg, (THREAD + THREAD_KVM_SVCPU)(reg);  \
        tophys(reg, reg)
+#define MTMSR_EERI(reg)                mtmsr   (reg)
 
 #endif
 
@@ -57,10 +59,12 @@ kvmppc_handler_trampoline_enter:
        /* Required state:
         *
         * MSR = ~IR|DR
-        * R13 = PACA
         * R1 = host R1
         * R2 = host R2
-        * R10 = guest MSR
+        * R4 = guest shadow MSR
+        * R5 = normal host MSR
+        * R6 = current host MSR (EE, IR, DR off)
+        * LR = highmem guest exit code
         * all other volatile GPRS = free
         * SVCPU[CR] = guest CR
         * SVCPU[XER] = guest XER
@@ -71,15 +75,15 @@ kvmppc_handler_trampoline_enter:
        /* r3 = shadow vcpu */
        GET_SHADOW_VCPU(r3)
 
+       /* Save guest exit handler address and MSR */
+       mflr    r0
+       PPC_STL r0, HSTATE_VMHANDLER(r3)
+       PPC_STL r5, HSTATE_HOST_MSR(r3)
+
        /* Save R1/R2 in the PACA (64-bit) or shadow_vcpu (32-bit) */
        PPC_STL r1, HSTATE_HOST_R1(r3)
        PPC_STL r2, HSTATE_HOST_R2(r3)
 
-       /* Move SRR0 and SRR1 into the respective regs */
-       PPC_LL  r9, SVCPU_PC(r3)
-       mtsrr0  r9
-       mtsrr1  r10
-
        /* Activate guest mode, so faults get handled by KVM */
        li      r11, KVM_GUEST_MODE_GUEST
        stb     r11, HSTATE_IN_GUEST(r3)
@@ -87,17 +91,46 @@ kvmppc_handler_trampoline_enter:
        /* Switch to guest segment. This is subarch specific. */
        LOAD_GUEST_SEGMENTS
 
+#ifdef CONFIG_PPC_BOOK3S_64
+       /* Some guests may need to have dcbz set to 32 byte length.
+        *
+        * Usually we ensure that by patching the guest's instructions
+        * to trap on dcbz and emulate it in the hypervisor.
+        *
+        * If we can, we should tell the CPU to use 32 byte dcbz though,
+        * because that's a lot faster.
+        */
+       lbz     r0, HSTATE_RESTORE_HID5(r3)
+       cmpwi   r0, 0
+       beq     no_dcbz32_on
+
+       mfspr   r0,SPRN_HID5
+       ori     r0, r0, 0x80            /* XXX HID5_dcbz32 = 0x80 */
+       mtspr   SPRN_HID5,r0
+no_dcbz32_on:
+
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
        /* Enter guest */
 
-       PPC_LL  r4, SVCPU_CTR(r3)
-       PPC_LL  r5, SVCPU_LR(r3)
-       lwz     r6, SVCPU_CR(r3)
-       lwz     r7, SVCPU_XER(r3)
+       PPC_LL  r8, SVCPU_CTR(r3)
+       PPC_LL  r9, SVCPU_LR(r3)
+       lwz     r10, SVCPU_CR(r3)
+       lwz     r11, SVCPU_XER(r3)
+
+       mtctr   r8
+       mtlr    r9
+       mtcr    r10
+       mtxer   r11
 
-       mtctr   r4
-       mtlr    r5
-       mtcr    r6
-       mtxer   r7
+       /* Move SRR0 and SRR1 into the respective regs */
+       PPC_LL  r9, SVCPU_PC(r3)
+       /* First clear RI in our current MSR value */
+       li      r0, MSR_RI
+       andc    r6, r6, r0
+       MTMSR_EERI(r6)
+       mtsrr0  r9
+       mtsrr1  r4
 
        PPC_LL  r0, SVCPU_R0(r3)
        PPC_LL  r1, SVCPU_R1(r3)
@@ -213,11 +246,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
        beq     ld_last_inst
        cmpwi   r12, BOOK3S_INTERRUPT_PROGRAM
        beq     ld_last_inst
+       cmpwi   r12, BOOK3S_INTERRUPT_SYSCALL
+       beq     ld_last_prev_inst
        cmpwi   r12, BOOK3S_INTERRUPT_ALIGNMENT
        beq-    ld_last_inst
 
        b       no_ld_last_inst
 
+ld_last_prev_inst:
+       addi    r3, r3, -4
+
 ld_last_inst:
        /* Save off the guest instruction we're at */
 
@@ -254,6 +292,43 @@ no_ld_last_inst:
        /* Switch back to host MMU */
        LOAD_HOST_SEGMENTS
 
+#ifdef CONFIG_PPC_BOOK3S_64
+
+       lbz     r5, HSTATE_RESTORE_HID5(r13)
+       cmpwi   r5, 0
+       beq     no_dcbz32_off
+
+       li      r4, 0
+       mfspr   r5,SPRN_HID5
+       rldimi  r5,r4,6,56
+       mtspr   SPRN_HID5,r5
+
+no_dcbz32_off:
+
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
+       /*
+        * For some interrupts, we need to call the real Linux
+        * handler, so it can do work for us. This has to happen
+        * as if the interrupt arrived from the kernel though,
+        * so let's fake it here where most state is restored.
+        *
+        * Having set up SRR0/1 with the address where we want
+        * to continue with relocation on (potentially in module
+        * space), we either just go straight there with rfi[d],
+        * or we jump to an interrupt handler with bctr if there
+        * is an interrupt to be handled first.  In the latter
+        * case, the rfi[d] at the end of the interrupt handler
+        * will get us back to where we want to continue.
+        */
+
+       cmpwi   r12, BOOK3S_INTERRUPT_EXTERNAL
+       beq     1f
+       cmpwi   r12, BOOK3S_INTERRUPT_DECREMENTER
+       beq     1f
+       cmpwi   r12, BOOK3S_INTERRUPT_PERFMON
+1:     mtctr   r12
+
        /* Register usage at this point:
         *
         * R1       = host R1
@@ -264,13 +339,15 @@ no_ld_last_inst:
         *
         */
 
-       /* RFI into the highmem handler */
-       mfmsr   r7
-       ori     r7, r7, MSR_IR|MSR_DR|MSR_RI|MSR_ME     /* Enable paging */
-       mtsrr1  r7
-       /* Load highmem handler address */
+       PPC_LL  r6, HSTATE_HOST_MSR(r13)
        PPC_LL  r8, HSTATE_VMHANDLER(r13)
+
+       /* Restore host msr -> SRR1 */
+       mtsrr1  r6
+       /* Load highmem handler address */
        mtsrr0  r8
 
+       /* RFI into the highmem handler, or jump to interrupt handler */
+       beqctr
        RFI
 kvmppc_handler_trampoline_exit_end:
index ee45fa0..bb6c988 100644 (file)
@@ -316,6 +316,11 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
        int ret;
 
+       if (!vcpu->arch.sane) {
+               kvm_run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+               return -EINVAL;
+       }
+
        local_irq_disable();
        kvm_guest_enter();
        ret = __kvmppc_vcpu_run(kvm_run, vcpu);
@@ -618,6 +623,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 {
        int i;
+       int r;
 
        vcpu->arch.pc = 0;
        vcpu->arch.shared->msr = 0;
@@ -634,7 +640,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 
        kvmppc_init_timing_stats(vcpu);
 
-       return kvmppc_core_vcpu_setup(vcpu);
+       r = kvmppc_core_vcpu_setup(vcpu);
+       kvmppc_sanity_check(vcpu);
+       return r;
 }
 
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
index 797a744..26d2090 100644 (file)
@@ -73,6 +73,8 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
        /* Since booke kvm only support one core, update all vcpus' PIR to 0 */
        vcpu->vcpu_id = 0;
 
+       vcpu->arch.cpu_type = KVM_CPU_E500V2;
+
        return 0;
 }
 
index a107c9b..0d843c6 100644 (file)
 
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
-#ifndef CONFIG_KVM_BOOK3S_64_HV
        return !(v->arch.shared->msr & MSR_WE) ||
               !!(v->arch.pending_exceptions);
-#else
-       return !(v->arch.ceded) || !!(v->arch.pending_exceptions);
-#endif
 }
 
 int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
@@ -95,6 +91,31 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
        return r;
 }
 
+int kvmppc_sanity_check(struct kvm_vcpu *vcpu)
+{
+       int r = false;
+
+       /* We have to know what CPU to virtualize */
+       if (!vcpu->arch.pvr)
+               goto out;
+
+       /* PAPR only works with book3s_64 */
+       if ((vcpu->arch.cpu_type != KVM_CPU_3S_64) && vcpu->arch.papr_enabled)
+               goto out;
+
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+       /* HV KVM can only do PAPR mode for now */
+       if (!vcpu->arch.papr_enabled)
+               goto out;
+#endif
+
+       r = true;
+
+out:
+       vcpu->arch.sane = r;
+       return r ? 0 : -EINVAL;
+}
+
 int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
 {
        enum emulation_result er;
@@ -188,6 +209,8 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_PPC_BOOKE_SREGS:
 #else
        case KVM_CAP_PPC_SEGSTATE:
+       case KVM_CAP_PPC_HIOR:
+       case KVM_CAP_PPC_PAPR:
 #endif
        case KVM_CAP_PPC_UNSET_IRQ:
        case KVM_CAP_PPC_IRQ_LEVEL:
@@ -258,6 +281,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
 {
        struct kvm_vcpu *vcpu;
        vcpu = kvmppc_core_vcpu_create(kvm, id);
+       vcpu->arch.wqp = &vcpu->wq;
        if (!IS_ERR(vcpu))
                kvmppc_create_vcpu_debugfs(vcpu, id);
        return vcpu;
@@ -289,8 +313,8 @@ static void kvmppc_decrementer_func(unsigned long data)
 
        kvmppc_core_queue_dec(vcpu);
 
-       if (waitqueue_active(&vcpu->wq)) {
-               wake_up_interruptible(&vcpu->wq);
+       if (waitqueue_active(vcpu->arch.wqp)) {
+               wake_up_interruptible(vcpu->arch.wqp);
                vcpu->stat.halt_wakeup++;
        }
 }
@@ -543,13 +567,15 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
 {
-       if (irq->irq == KVM_INTERRUPT_UNSET)
+       if (irq->irq == KVM_INTERRUPT_UNSET) {
                kvmppc_core_dequeue_external(vcpu, irq);
-       else
-               kvmppc_core_queue_external(vcpu, irq);
+               return 0;
+       }
+
+       kvmppc_core_queue_external(vcpu, irq);
 
-       if (waitqueue_active(&vcpu->wq)) {
-               wake_up_interruptible(&vcpu->wq);
+       if (waitqueue_active(vcpu->arch.wqp)) {
+               wake_up_interruptible(vcpu->arch.wqp);
                vcpu->stat.halt_wakeup++;
        } else if (vcpu->cpu != -1) {
                smp_send_reschedule(vcpu->cpu);
@@ -571,11 +597,18 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
                r = 0;
                vcpu->arch.osi_enabled = true;
                break;
+       case KVM_CAP_PPC_PAPR:
+               r = 0;
+               vcpu->arch.papr_enabled = true;
+               break;
        default:
                r = -EINVAL;
                break;
        }
 
+       if (!r)
+               r = kvmppc_sanity_check(vcpu);
+
        return r;
 }
 
index e41ebbd..cfe958e 100644 (file)
@@ -66,8 +66,8 @@ struct fsl_diu_shared_fb {
        bool            in_use;
 };
 
-unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel,
-                                     int monitor_port)
+u32 mpc512x_get_pixel_format(enum fsl_diu_monitor_port port,
+                            unsigned int bits_per_pixel)
 {
        switch (bits_per_pixel) {
        case 32:
@@ -80,11 +80,12 @@ unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel,
        return 0x00000400;
 }
 
-void mpc512x_set_gamma_table(int monitor_port, char *gamma_table_base)
+void mpc512x_set_gamma_table(enum fsl_diu_monitor_port port,
+                            char *gamma_table_base)
 {
 }
 
-void mpc512x_set_monitor_port(int monitor_port)
+void mpc512x_set_monitor_port(enum fsl_diu_monitor_port port)
 {
 }
 
@@ -182,14 +183,10 @@ void mpc512x_set_pixel_clock(unsigned int pixclock)
        iounmap(ccm);
 }
 
-ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf)
+enum fsl_diu_monitor_port
+mpc512x_valid_monitor_port(enum fsl_diu_monitor_port port)
 {
-       return sprintf(buf, "0 - 5121 LCD\n");
-}
-
-int mpc512x_set_sysfs_monitor_port(int val)
-{
-       return 0;
+       return FSL_DIU_PORT_DVI;
 }
 
 static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
@@ -256,7 +253,7 @@ void __init mpc512x_init_diu(void)
        }
 
        mode = in_be32(&diu_reg->diu_mode);
-       if (mode != MFB_MODE1) {
+       if (mode == MFB_MODE0) {
                pr_info("%s: DIU OFF\n", __func__);
                goto out;
        }
@@ -332,8 +329,7 @@ void __init mpc512x_setup_diu(void)
        diu_ops.set_gamma_table         = mpc512x_set_gamma_table;
        diu_ops.set_monitor_port        = mpc512x_set_monitor_port;
        diu_ops.set_pixel_clock         = mpc512x_set_pixel_clock;
-       diu_ops.show_monitor_port       = mpc512x_show_monitor_port;
-       diu_ops.set_sysfs_monitor_port  = mpc512x_set_sysfs_monitor_port;
+       diu_ops.valid_monitor_port      = mpc512x_valid_monitor_port;
        diu_ops.release_bootmem         = mpc512x_release_bootmem;
 #endif
 }
index 266b3aa..c01c727 100644 (file)
@@ -93,8 +93,8 @@
  * The Area Descriptor is a 32-bit value that determine which bits in each
  * pixel are to be used for each color.
  */
-static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel,
-       int monitor_port)
+static u32 p1022ds_get_pixel_format(enum fsl_diu_monitor_port port,
+                                   unsigned int bits_per_pixel)
 {
        switch (bits_per_pixel) {
        case 32:
@@ -118,7 +118,8 @@ static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel,
  * On some boards, the gamma table for some ports may need to be modified.
  * This is not the case on the P1022DS, so we do nothing.
 */
-static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base)
+static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port,
+                                   char *gamma_table_base)
 {
 }
 
@@ -126,7 +127,7 @@ static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base)
  * p1022ds_set_monitor_port: switch the output to a different monitor port
  *
  */
-static void p1022ds_set_monitor_port(int monitor_port)
+static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
 {
        struct device_node *pixis_node;
        void __iomem *pixis;
@@ -145,19 +146,21 @@ static void p1022ds_set_monitor_port(int monitor_port)
        }
        brdcfg1 = pixis + 9;    /* BRDCFG1 is at offset 9 in the ngPIXIS */
 
-       switch (monitor_port) {
-       case 0: /* DVI */
+       switch (port) {
+       case FSL_DIU_PORT_DVI:
+               printk(KERN_INFO "%s:%u\n", __func__, __LINE__);
                /* Enable the DVI port, disable the DFP and the backlight */
                clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
                             PX_BRDCFG1_DVIEN);
                break;
-       case 1: /* Single link LVDS */
+       case FSL_DIU_PORT_LVDS:
+               printk(KERN_INFO "%s:%u\n", __func__, __LINE__);
                /* Enable the DFP port, disable the DVI and the backlight */
                clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
                             PX_BRDCFG1_DFPEN);
                break;
        default:
-               pr_err("p1022ds: unsupported monitor port %i\n", monitor_port);
+               pr_err("p1022ds: unsupported monitor port %i\n", port);
        }
 
        iounmap(pixis);
@@ -214,23 +217,18 @@ void p1022ds_set_pixel_clock(unsigned int pixclock)
 }
 
 /**
- * p1022ds_show_monitor_port: show the current monitor
- *
- * This function returns a string indicating whether the current monitor is
- * set to DVI or LVDS.
- */
-ssize_t p1022ds_show_monitor_port(int monitor_port, char *buf)
-{
-       return sprintf(buf, "%c0 - DVI\n%c1 - Single link LVDS\n",
-               monitor_port == 0 ? '*' : ' ', monitor_port == 1 ? '*' : ' ');
-}
-
-/**
- * p1022ds_set_sysfs_monitor_port: set the monitor port for sysfs
+ * p1022ds_valid_monitor_port: set the monitor port for sysfs
  */
-int p1022ds_set_sysfs_monitor_port(int val)
+enum fsl_diu_monitor_port
+p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port)
 {
-       return val < 2 ? val : 0;
+       switch (port) {
+       case FSL_DIU_PORT_DVI:
+       case FSL_DIU_PORT_LVDS:
+               return port;
+       default:
+               return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */
+       }
 }
 
 #endif
@@ -305,8 +303,7 @@ static void __init p1022_ds_setup_arch(void)
        diu_ops.set_gamma_table         = p1022ds_set_gamma_table;
        diu_ops.set_monitor_port        = p1022ds_set_monitor_port;
        diu_ops.set_pixel_clock         = p1022ds_set_pixel_clock;
-       diu_ops.show_monitor_port       = p1022ds_show_monitor_port;
-       diu_ops.set_sysfs_monitor_port  = p1022ds_set_sysfs_monitor_port;
+       diu_ops.valid_monitor_port      = p1022ds_valid_monitor_port;
 #endif
 
 #ifdef CONFIG_SMP
index 74e018e..13fa9a6 100644 (file)
@@ -152,10 +152,10 @@ machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices);
        (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
        (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
 
-unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel,
-                                               int monitor_port)
+u32 mpc8610hpcd_get_pixel_format(enum fsl_diu_monitor_port port,
+                                unsigned int bits_per_pixel)
 {
-       static const unsigned long pixelformat[][3] = {
+       static const u32 pixelformat[][3] = {
                {
                        MAKE_AD(3, 0, 2, 1, 3, 8, 8, 8, 8),
                        MAKE_AD(4, 2, 0, 1, 2, 8, 8, 8, 0),
@@ -170,7 +170,8 @@ unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel,
        unsigned int arch_monitor;
 
        /* The DVI port is mis-wired on revision 1 of this board. */
-       arch_monitor = ((*pixis_arch == 0x01) && (monitor_port == 0))? 0 : 1;
+       arch_monitor =
+               ((*pixis_arch == 0x01) && (port == FSL_DIU_PORT_DVI)) ? 0 : 1;
 
        switch (bits_per_pixel) {
        case 32:
@@ -185,10 +186,11 @@ unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel,
        }
 }
 
-void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base)
+void mpc8610hpcd_set_gamma_table(enum fsl_diu_monitor_port port,
+                                char *gamma_table_base)
 {
        int i;
-       if (monitor_port == 2) {                /* dual link LVDS */
+       if (port == FSL_DIU_PORT_DLVDS) {
                for (i = 0; i < 256*3; i++)
                        gamma_table_base[i] = (gamma_table_base[i] << 2) |
                                         ((gamma_table_base[i] >> 6) & 0x03);
@@ -199,17 +201,21 @@ void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base)
 #define PX_BRDCFG0_DLINK       (1 << 4)
 #define PX_BRDCFG0_DIU_MASK    (PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK)
 
-void mpc8610hpcd_set_monitor_port(int monitor_port)
+void mpc8610hpcd_set_monitor_port(enum fsl_diu_monitor_port port)
 {
-       static const u8 bdcfg[] = {
-               PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK,
-               PX_BRDCFG0_DLINK,
-               0,
-       };
-
-       if (monitor_port < 3)
+       switch (port) {
+       case FSL_DIU_PORT_DVI:
                clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK,
-                            bdcfg[monitor_port]);
+                            PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK);
+               break;
+       case FSL_DIU_PORT_LVDS:
+               clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK,
+                            PX_BRDCFG0_DLINK);
+               break;
+       case FSL_DIU_PORT_DLVDS:
+               clrbits8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK);
+               break;
+       }
 }
 
 /**
@@ -262,20 +268,10 @@ void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
        iounmap(guts);
 }
 
-ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE,
-                       "%c0 - DVI\n"
-                       "%c1 - Single link LVDS\n"
-                       "%c2 - Dual link LVDS\n",
-                       monitor_port == 0 ? '*' : ' ',
-                       monitor_port == 1 ? '*' : ' ',
-                       monitor_port == 2 ? '*' : ' ');
-}
-
-int mpc8610hpcd_set_sysfs_monitor_port(int val)
+enum fsl_diu_monitor_port
+mpc8610hpcd_valid_monitor_port(enum fsl_diu_monitor_port port)
 {
-       return val < 3 ? val : 0;
+       return port;
 }
 
 #endif
@@ -307,8 +303,7 @@ static void __init mpc86xx_hpcd_setup_arch(void)
        diu_ops.set_gamma_table         = mpc8610hpcd_set_gamma_table;
        diu_ops.set_monitor_port        = mpc8610hpcd_set_monitor_port;
        diu_ops.set_pixel_clock         = mpc8610hpcd_set_pixel_clock;
-       diu_ops.show_monitor_port       = mpc8610hpcd_show_monitor_port;
-       diu_ops.set_sysfs_monitor_port  = mpc8610hpcd_set_sysfs_monitor_port;
+       diu_ops.valid_monitor_port      = mpc8610hpcd_valid_monitor_port;
 #endif
 
        pixis_node = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis");
index 2ece02b..c6d0073 100644 (file)
@@ -22,15 +22,24 @@ struct device_node;
 extern void fsl_rstcr_restart(char *cmd);
 
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+/* The different ports that the DIU can be connected to */
+enum fsl_diu_monitor_port {
+       FSL_DIU_PORT_DVI,       /* DVI */
+       FSL_DIU_PORT_LVDS,      /* Single-link LVDS */
+       FSL_DIU_PORT_DLVDS      /* Dual-link LVDS */
+};
+
 struct platform_diu_data_ops {
-       unsigned int (*get_pixel_format) (unsigned int bits_per_pixel,
-               int monitor_port);
-       void (*set_gamma_table) (int monitor_port, char *gamma_table_base);
-       void (*set_monitor_port) (int monitor_port);
-       void (*set_pixel_clock) (unsigned int pixclock);
-       ssize_t (*show_monitor_port) (int monitor_port, char *buf);
-       int (*set_sysfs_monitor_port) (int val);
-       void (*release_bootmem) (void);
+       u32 (*get_pixel_format)(enum fsl_diu_monitor_port port,
+               unsigned int bpp);
+       void (*set_gamma_table)(enum fsl_diu_monitor_port port,
+               char *gamma_table_base);
+       void (*set_monitor_port)(enum fsl_diu_monitor_port port);
+       void (*set_pixel_clock)(unsigned int pixclock);
+       enum fsl_diu_monitor_port (*valid_monitor_port)
+               (enum fsl_diu_monitor_port port);
+       void (*release_bootmem)(void);
 };
 
 extern struct platform_diu_data_ops diu_ops;
index 46c0bda..24e1847 100644 (file)
@@ -119,6 +119,7 @@ struct kvm_vcpu_stat {
        u32 instruction_lctlg;
        u32 exit_program_interruption;
        u32 exit_instr_and_program;
+       u32 deliver_external_call;
        u32 deliver_emergency_signal;
        u32 deliver_service_signal;
        u32 deliver_virtio_interrupt;
@@ -138,6 +139,7 @@ struct kvm_vcpu_stat {
        u32 instruction_stfl;
        u32 instruction_tprot;
        u32 instruction_sigp_sense;
+       u32 instruction_sigp_external_call;
        u32 instruction_sigp_emergency;
        u32 instruction_sigp_stop;
        u32 instruction_sigp_arch;
@@ -175,6 +177,10 @@ struct kvm_s390_prefix_info {
        __u32 address;
 };
 
+struct kvm_s390_extcall_info {
+       __u16 code;
+};
+
 struct kvm_s390_emerg_info {
        __u16 code;
 };
@@ -187,6 +193,7 @@ struct kvm_s390_interrupt_info {
                struct kvm_s390_ext_info ext;
                struct kvm_s390_pgm_info pgm;
                struct kvm_s390_emerg_info emerg;
+               struct kvm_s390_extcall_info extcall;
                struct kvm_s390_prefix_info prefix;
        };
 };
index c9aeb4b..87c1670 100644 (file)
@@ -38,6 +38,11 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
                                      struct kvm_s390_interrupt_info *inti)
 {
        switch (inti->type) {
+       case KVM_S390_INT_EXTERNAL_CALL:
+               if (psw_extint_disabled(vcpu))
+                       return 0;
+               if (vcpu->arch.sie_block->gcr[0] & 0x2000ul)
+                       return 1;
        case KVM_S390_INT_EMERGENCY:
                if (psw_extint_disabled(vcpu))
                        return 0;
@@ -98,6 +103,7 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
                                      struct kvm_s390_interrupt_info *inti)
 {
        switch (inti->type) {
+       case KVM_S390_INT_EXTERNAL_CALL:
        case KVM_S390_INT_EMERGENCY:
        case KVM_S390_INT_SERVICE:
        case KVM_S390_INT_VIRTIO:
@@ -143,6 +149,28 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
                        exception = 1;
                break;
 
+       case KVM_S390_INT_EXTERNAL_CALL:
+               VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call");
+               vcpu->stat.deliver_external_call++;
+               rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1202);
+               if (rc == -EFAULT)
+                       exception = 1;
+
+               rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, inti->extcall.code);
+               if (rc == -EFAULT)
+                       exception = 1;
+
+               rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
+                        &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+               if (rc == -EFAULT)
+                       exception = 1;
+
+               rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+                       __LC_EXT_NEW_PSW, sizeof(psw_t));
+               if (rc == -EFAULT)
+                       exception = 1;
+               break;
+
        case KVM_S390_INT_SERVICE:
                VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x",
                           inti->ext.ext_params);
@@ -522,6 +550,7 @@ int kvm_s390_inject_vm(struct kvm *kvm,
                break;
        case KVM_S390_PROGRAM_INT:
        case KVM_S390_SIGP_STOP:
+       case KVM_S390_INT_EXTERNAL_CALL:
        case KVM_S390_INT_EMERGENCY:
        default:
                kfree(inti);
@@ -581,6 +610,7 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
                break;
        case KVM_S390_SIGP_STOP:
        case KVM_S390_RESTART:
+       case KVM_S390_INT_EXTERNAL_CALL:
        case KVM_S390_INT_EMERGENCY:
                VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
                inti->type = s390int->type;
index 189d6bd..0bd3bea 100644 (file)
@@ -46,6 +46,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "instruction_lctlg", VCPU_STAT(instruction_lctlg) },
        { "instruction_lctl", VCPU_STAT(instruction_lctl) },
        { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) },
+       { "deliver_external_call", VCPU_STAT(deliver_external_call) },
        { "deliver_service_signal", VCPU_STAT(deliver_service_signal) },
        { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) },
        { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) },
@@ -64,6 +65,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "instruction_stfl", VCPU_STAT(instruction_stfl) },
        { "instruction_tprot", VCPU_STAT(instruction_tprot) },
        { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) },
+       { "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) },
        { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) },
        { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) },
        { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) },
@@ -176,6 +178,8 @@ int kvm_arch_init_vm(struct kvm *kvm)
        if (rc)
                goto out_err;
 
+       rc = -ENOMEM;
+
        kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL);
        if (!kvm->arch.sca)
                goto out_err;
@@ -313,11 +317,17 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
                                      unsigned int id)
 {
-       struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
-       int rc = -ENOMEM;
+       struct kvm_vcpu *vcpu;
+       int rc = -EINVAL;
+
+       if (id >= KVM_MAX_VCPUS)
+               goto out;
 
+       rc = -ENOMEM;
+
+       vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
        if (!vcpu)
-               goto out_nomem;
+               goto out;
 
        vcpu->arch.sie_block = (struct kvm_s390_sie_block *)
                                        get_zeroed_page(GFP_KERNEL);
@@ -353,7 +363,7 @@ out_free_sie_block:
        free_page((unsigned long)(vcpu->arch.sie_block));
 out_free_cpu:
        kfree(vcpu);
-out_nomem:
+out:
        return ERR_PTR(rc);
 }
 
@@ -387,6 +397,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 {
        memcpy(&vcpu->arch.guest_acrs, &sregs->acrs, sizeof(sregs->acrs));
        memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs));
+       restore_access_regs(vcpu->arch.guest_acrs);
        return 0;
 }
 
@@ -402,6 +413,7 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
        memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
        vcpu->arch.guest_fpregs.fpc = fpu->fpc;
+       restore_fp_regs(&vcpu->arch.guest_fpregs);
        return 0;
 }
 
index d6a50c1..f815118 100644 (file)
@@ -87,6 +87,7 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
                return -ENOMEM;
 
        inti->type = KVM_S390_INT_EMERGENCY;
+       inti->emerg.code = vcpu->vcpu_id;
 
        spin_lock(&fi->lock);
        li = fi->local_int[cpu_addr];
@@ -103,9 +104,47 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
                wake_up_interruptible(&li->wq);
        spin_unlock_bh(&li->lock);
        rc = 0; /* order accepted */
+       VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
+unlock:
+       spin_unlock(&fi->lock);
+       return rc;
+}
+
+static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
+{
+       struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+       struct kvm_s390_local_interrupt *li;
+       struct kvm_s390_interrupt_info *inti;
+       int rc;
+
+       if (cpu_addr >= KVM_MAX_VCPUS)
+               return 3; /* not operational */
+
+       inti = kzalloc(sizeof(*inti), GFP_KERNEL);
+       if (!inti)
+               return -ENOMEM;
+
+       inti->type = KVM_S390_INT_EXTERNAL_CALL;
+       inti->extcall.code = vcpu->vcpu_id;
+
+       spin_lock(&fi->lock);
+       li = fi->local_int[cpu_addr];
+       if (li == NULL) {
+               rc = 3; /* not operational */
+               kfree(inti);
+               goto unlock;
+       }
+       spin_lock_bh(&li->lock);
+       list_add_tail(&inti->list, &li->list);
+       atomic_set(&li->active, 1);
+       atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+       if (waitqueue_active(&li->wq))
+               wake_up_interruptible(&li->wq);
+       spin_unlock_bh(&li->lock);
+       rc = 0; /* order accepted */
+       VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", cpu_addr);
 unlock:
        spin_unlock(&fi->lock);
-       VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
        return rc;
 }
 
@@ -267,6 +306,10 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
                rc = __sigp_sense(vcpu, cpu_addr,
                                  &vcpu->arch.guest_gprs[r1]);
                break;
+       case SIGP_EXTERNAL_CALL:
+               vcpu->stat.instruction_sigp_external_call++;
+               rc = __sigp_external_call(vcpu, cpu_addr);
+               break;
        case SIGP_EMERGENCY:
                vcpu->stat.instruction_sigp_emergency++;
                rc = __sigp_emergency(vcpu, cpu_addr);
index 32b626c..7337067 100644 (file)
@@ -713,17 +713,17 @@ static void pcmp(struct pt_regs *regs, unsigned int insn, unsigned int opf)
                        s16 b = (rs2 >> (i * 16)) & 0xffff;
 
                        if (a > b)
-                               rd_val |= 1 << i;
+                               rd_val |= 8 >> i;
                }
                break;
 
        case FCMPGT32_OPF:
                for (i = 0; i < 2; i++) {
-                       s32 a = (rs1 >> (i * 32)) & 0xffff;
-                       s32 b = (rs2 >> (i * 32)) & 0xffff;
+                       s32 a = (rs1 >> (i * 32)) & 0xffffffff;
+                       s32 b = (rs2 >> (i * 32)) & 0xffffffff;
 
                        if (a > b)
-                               rd_val |= 1 << i;
+                               rd_val |= 2 >> i;
                }
                break;
 
@@ -733,17 +733,17 @@ static void pcmp(struct pt_regs *regs, unsigned int insn, unsigned int opf)
                        s16 b = (rs2 >> (i * 16)) & 0xffff;
 
                        if (a <= b)
-                               rd_val |= 1 << i;
+                               rd_val |= 8 >> i;
                }
                break;
 
        case FCMPLE32_OPF:
                for (i = 0; i < 2; i++) {
-                       s32 a = (rs1 >> (i * 32)) & 0xffff;
-                       s32 b = (rs2 >> (i * 32)) & 0xffff;
+                       s32 a = (rs1 >> (i * 32)) & 0xffffffff;
+                       s32 b = (rs2 >> (i * 32)) & 0xffffffff;
 
                        if (a <= b)
-                               rd_val |= 1 << i;
+                               rd_val |= 2 >> i;
                }
                break;
 
@@ -753,17 +753,17 @@ static void pcmp(struct pt_regs *regs, unsigned int insn, unsigned int opf)
                        s16 b = (rs2 >> (i * 16)) & 0xffff;
 
                        if (a != b)
-                               rd_val |= 1 << i;
+                               rd_val |= 8 >> i;
                }
                break;
 
        case FCMPNE32_OPF:
                for (i = 0; i < 2; i++) {
-                       s32 a = (rs1 >> (i * 32)) & 0xffff;
-                       s32 b = (rs2 >> (i * 32)) & 0xffff;
+                       s32 a = (rs1 >> (i * 32)) & 0xffffffff;
+                       s32 b = (rs2 >> (i * 32)) & 0xffffffff;
 
                        if (a != b)
-                               rd_val |= 1 << i;
+                               rd_val |= 2 >> i;
                }
                break;
 
@@ -773,17 +773,17 @@ static void pcmp(struct pt_regs *regs, unsigned int insn, unsigned int opf)
                        s16 b = (rs2 >> (i * 16)) & 0xffff;
 
                        if (a == b)
-                               rd_val |= 1 << i;
+                               rd_val |= 8 >> i;
                }
                break;
 
        case FCMPEQ32_OPF:
                for (i = 0; i < 2; i++) {
-                       s32 a = (rs1 >> (i * 32)) & 0xffff;
-                       s32 b = (rs2 >> (i * 32)) & 0xffff;
+                       s32 a = (rs1 >> (i * 32)) & 0xffffffff;
+                       s32 b = (rs2 >> (i * 32)) & 0xffffffff;
 
                        if (a == b)
-                               rd_val |= 1 << i;
+                               rd_val |= 2 >> i;
                }
                break;
        }
index 34fe657..4d8c497 100644 (file)
@@ -7,40 +7,12 @@
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
-#ifdef __KERNEL__
-
-#define FUNC(x)                                                                                        \
+#define FUNC(x)                \
        .globl  x;              \
        .type   x,@function;    \
-       .align  4;                                                                                      \
+       .align  4;              \
 x:
 
-#undef FASTER_REVERSE
-#undef FASTER_NONALIGNED
-#define FASTER_ALIGNED
-
-/* In kernel these functions don't return a value.
- * One should use macros in asm/string.h for that purpose.
- * We return 0, so that bugs are more apparent.
- */
-#define SETUP_RETL
-#define RETL_INSN      clr     %o0
-
-#else
-
-/* libc */
-
-#include "DEFS.h"
-
-#define FASTER_REVERSE
-#define FASTER_NONALIGNED
-#define FASTER_ALIGNED
-
-#define SETUP_RETL     mov     %o0, %g6
-#define RETL_INSN      mov     %g6, %o0
-
-#endif
-
 /* Both these macros have to start with exactly the same insn */
 #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
        ldd     [%src + (offset) + 0x00], %t0; \
@@ -164,30 +136,6 @@ x:
        .text
        .align  4
 
-#ifdef FASTER_REVERSE
-
-70:    /* rdword_align */
-
-       andcc           %o1, 1, %g0
-       be              4f
-        andcc          %o1, 2, %g0
-
-       ldub            [%o1 - 1], %g2
-       sub             %o1, 1, %o1
-       stb             %g2, [%o0 - 1]
-       sub             %o2, 1, %o2
-       be              3f
-        sub            %o0, 1, %o0
-4:
-       lduh            [%o1 - 2], %g2
-       sub             %o1, 2, %o1
-       sth             %g2, [%o0 - 2]
-       sub             %o2, 2, %o2
-       b               3f
-        sub            %o0, 2, %o0
-
-#endif /* FASTER_REVERSE */
-
 0:
        retl
         nop            ! Only bcopy returns here and it retuns void...
@@ -198,7 +146,7 @@ FUNC(__memmove)
 #endif
 FUNC(memmove)
        cmp             %o0, %o1
-       SETUP_RETL
+       mov             %o0, %g7
        bleu            9f
         sub            %o0, %o1, %o4
 
@@ -207,8 +155,6 @@ FUNC(memmove)
        bleu            0f
         andcc          %o4, 3, %o5
 
-#ifndef FASTER_REVERSE
-
        add             %o1, %o2, %o1
        add             %o0, %o2, %o0
        sub             %o1, 1, %o1
@@ -224,295 +170,7 @@ FUNC(memmove)
         sub            %o0, 1, %o0
 
        retl
-        RETL_INSN
-
-#else /* FASTER_REVERSE */
-
-       add             %o1, %o2, %o1
-       add             %o0, %o2, %o0
-       bne             77f
-        cmp            %o2, 15
-       bleu            91f
-        andcc          %o1, 3, %g0
-       bne             70b
-3:
-        andcc          %o1, 4, %g0
-
-       be              2f
-        mov            %o2, %g1
-
-       ld              [%o1 - 4], %o4
-       sub             %g1, 4, %g1
-       st              %o4, [%o0 - 4]
-       sub             %o1, 4, %o1
-       sub             %o0, 4, %o0
-2:
-       andcc           %g1, 0xffffff80, %g7
-       be              3f
-        andcc          %o0, 4, %g0
-
-       be              74f + 4
-5:
-       RMOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
-       RMOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
-       RMOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
-       RMOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-       subcc           %g7, 128, %g7
-       sub             %o1, 128, %o1
-       bne             5b
-        sub            %o0, 128, %o0
-3:
-       andcc           %g1, 0x70, %g7
-       be              72f
-        andcc          %g1, 8, %g0
-
-       sethi           %hi(72f), %o5
-       srl             %g7, 1, %o4
-       add             %g7, %o4, %o4
-       sub             %o1, %g7, %o1
-       sub             %o5, %o4, %o5
-       jmpl            %o5 + %lo(72f), %g0
-        sub            %o0, %g7, %o0
-
-71:    /* rmemcpy_table */
-       RMOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
-       RMOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
-       RMOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
-       RMOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
-       RMOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
-       RMOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
-       RMOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
-
-72:    /* rmemcpy_table_end */
-
-       be              73f
-        andcc          %g1, 4, %g0
-
-       ldd             [%o1 - 0x08], %g2
-       sub             %o0, 8, %o0
-       sub             %o1, 8, %o1
-       st              %g2, [%o0]
-       st              %g3, [%o0 + 0x04]
-
-73:    /* rmemcpy_last7 */
-
-       be              1f
-        andcc          %g1, 2, %g0
-
-       ld              [%o1 - 4], %g2
-       sub             %o1, 4, %o1
-       st              %g2, [%o0 - 4]
-       sub             %o0, 4, %o0
-1:
-       be              1f
-        andcc          %g1, 1, %g0
-
-       lduh            [%o1 - 2], %g2
-       sub             %o1, 2, %o1
-       sth             %g2, [%o0 - 2]
-       sub             %o0, 2, %o0
-1:
-       be              1f
-        nop
-
-       ldub            [%o1 - 1], %g2
-       stb             %g2, [%o0 - 1]
-1:
-       retl
-        RETL_INSN
-
-74:    /* rldd_std */
-       RMOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
-       RMOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
-       RMOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
-       RMOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-       subcc           %g7, 128, %g7
-       sub             %o1, 128, %o1
-       bne             74b
-        sub            %o0, 128, %o0
-
-       andcc           %g1, 0x70, %g7
-       be              72b
-        andcc          %g1, 8, %g0
-
-       sethi           %hi(72b), %o5
-       srl             %g7, 1, %o4
-       add             %g7, %o4, %o4
-       sub             %o1, %g7, %o1
-       sub             %o5, %o4, %o5
-       jmpl            %o5 + %lo(72b), %g0
-        sub            %o0, %g7, %o0
-
-75:    /* rshort_end */
-
-       and             %o2, 0xe, %o3
-2:
-       sethi           %hi(76f), %o5
-       sll             %o3, 3, %o4
-       sub             %o0, %o3, %o0
-       sub             %o5, %o4, %o5
-       sub             %o1, %o3, %o1
-       jmpl            %o5 + %lo(76f), %g0
-        andcc          %o2, 1, %g0
-
-       RMOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
-       RMOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
-       RMOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
-       RMOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
-       RMOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
-       RMOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
-       RMOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
-
-76:    /* rshort_table_end */
-
-       be              1f
-        nop
-       ldub            [%o1 - 1], %g2
-       stb             %g2, [%o0 - 1]
-1:
-       retl
-        RETL_INSN
-
-91:    /* rshort_aligned_end */
-
-       bne             75b
-        andcc          %o2, 8, %g0
-
-       be              1f
-        andcc          %o2, 4, %g0
-
-       ld              [%o1 - 0x08], %g2
-       ld              [%o1 - 0x04], %g3
-       sub             %o1, 8, %o1
-       st              %g2, [%o0 - 0x08]
-       st              %g3, [%o0 - 0x04]
-       sub             %o0, 8, %o0
-1:
-       b               73b
-        mov            %o2, %g1
-
-77:    /* rnon_aligned */
-       cmp             %o2, 15
-       bleu            75b
-        andcc          %o0, 3, %g0
-       be              64f
-        andcc          %o0, 1, %g0
-       be              63f
-        andcc          %o0, 2, %g0
-       ldub            [%o1 - 1], %g5
-       sub             %o1, 1, %o1
-       stb             %g5, [%o0 - 1]
-       sub             %o0, 1, %o0
-       be              64f
-        sub            %o2, 1, %o2
-63:
-       ldub            [%o1 - 1], %g5
-       sub             %o1, 2, %o1
-       stb             %g5, [%o0 - 1]
-       sub             %o0, 2, %o0
-       ldub            [%o1], %g5
-       sub             %o2, 2, %o2
-       stb             %g5, [%o0]
-64:    
-       and             %o1, 3, %g2
-       and             %o1, -4, %o1
-       and             %o2, 0xc, %g3
-       add             %o1, 4, %o1
-       cmp             %g3, 4
-       sll             %g2, 3, %g4
-       mov             32, %g2
-       be              4f
-        sub            %g2, %g4, %g7
-
-       blu             3f
-        cmp            %g3, 8
-
-       be              2f
-        srl            %o2, 2, %g3
-
-       ld              [%o1 - 4], %o3
-       add             %o0, -8, %o0
-       ld              [%o1 - 8], %o4
-       add             %o1, -16, %o1
-       b               7f
-        add            %g3, 1, %g3
-2:
-       ld              [%o1 - 4], %o4
-       add             %o0, -4, %o0
-       ld              [%o1 - 8], %g1
-       add             %o1, -12, %o1
-       b               8f
-        add            %g3, 2, %g3
-3:
-       ld              [%o1 - 4], %o5
-       add             %o0, -12, %o0
-       ld              [%o1 - 8], %o3
-       add             %o1, -20, %o1
-       b               6f
-        srl            %o2, 2, %g3
-4:
-       ld              [%o1 - 4], %g1
-       srl             %o2, 2, %g3
-       ld              [%o1 - 8], %o5
-       add             %o1, -24, %o1
-       add             %o0, -16, %o0
-       add             %g3, -1, %g3
-
-       ld              [%o1 + 12], %o3
-5:
-       sll             %o5, %g4, %g2
-       srl             %g1, %g7, %g5
-       or              %g2, %g5, %g2
-       st              %g2, [%o0 + 12]
-6:
-       ld              [%o1 + 8], %o4
-       sll             %o3, %g4, %g2
-       srl             %o5, %g7, %g5
-       or              %g2, %g5, %g2
-       st              %g2, [%o0 + 8]
-7:
-       ld              [%o1 + 4], %g1
-       sll             %o4, %g4, %g2
-       srl             %o3, %g7, %g5
-       or              %g2, %g5, %g2
-       st              %g2, [%o0 + 4]
-8:
-       ld              [%o1], %o5
-       sll             %g1, %g4, %g2
-       srl             %o4, %g7, %g5
-       addcc           %g3, -4, %g3
-       or              %g2, %g5, %g2
-       add             %o1, -16, %o1
-       st              %g2, [%o0]
-       add             %o0, -16, %o0
-       bne,a           5b      
-        ld             [%o1 + 12], %o3
-       sll             %o5, %g4, %g2
-       srl             %g1, %g7, %g5
-       srl             %g4, 3, %g3
-       or              %g2, %g5, %g2
-       add             %o1, %g3, %o1
-       andcc           %o2, 2, %g0
-       st              %g2, [%o0 + 12]
-       be              1f
-        andcc          %o2, 1, %g0
-       
-       ldub            [%o1 + 15], %g5
-       add             %o1, -2, %o1
-       stb             %g5, [%o0 + 11]
-       add             %o0, -2, %o0
-       ldub            [%o1 + 16], %g5
-       stb             %g5, [%o0 + 12]
-1:
-       be              1f
-        nop
-       ldub            [%o1 + 15], %g5
-       stb             %g5, [%o0 + 11]
-1:
-       retl
-        RETL_INSN
-
-#endif /* FASTER_REVERSE */
+        mov            %g7, %o0
 
 /* NOTE: This code is executed just for the cases,
          where %src (=%o1) & 3 is != 0.
@@ -546,7 +204,7 @@ FUNC(memmove)
 FUNC(memcpy)   /* %o0=dst %o1=src %o2=len */
 
        sub             %o0, %o1, %o4
-       SETUP_RETL
+       mov             %o0, %g7
 9:
        andcc           %o4, 3, %o5
 0:
@@ -569,7 +227,7 @@ FUNC(memcpy)        /* %o0=dst %o1=src %o2=len */
        add             %o1, 4, %o1
        add             %o0, 4, %o0
 2:
-       andcc           %g1, 0xffffff80, %g7
+       andcc           %g1, 0xffffff80, %g0
        be              3f
         andcc          %o0, 4, %g0
 
@@ -579,22 +237,23 @@ FUNC(memcpy)      /* %o0=dst %o1=src %o2=len */
        MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
        MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
        MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-       subcc           %g7, 128, %g7
+       sub             %g1, 128, %g1
        add             %o1, 128, %o1
-       bne             5b
+       cmp             %g1, 128
+       bge             5b
         add            %o0, 128, %o0
 3:
-       andcc           %g1, 0x70, %g7
+       andcc           %g1, 0x70, %g4
        be              80f
         andcc          %g1, 8, %g0
 
        sethi           %hi(80f), %o5
-       srl             %g7, 1, %o4
-       add             %g7, %o4, %o4
-       add             %o1, %g7, %o1
+       srl             %g4, 1, %o4
+       add             %g4, %o4, %o4
+       add             %o1, %g4, %o1
        sub             %o5, %o4, %o5
        jmpl            %o5 + %lo(80f), %g0
-        add            %o0, %g7, %o0
+        add            %o0, %g4, %o0
 
 79:    /* memcpy_table */
 
@@ -641,43 +300,28 @@ FUNC(memcpy)      /* %o0=dst %o1=src %o2=len */
        stb             %g2, [%o0]
 1:
        retl
-        RETL_INSN
+        mov            %g7, %o0
 
 82:    /* ldd_std */
        MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
        MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
        MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
        MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-       subcc           %g7, 128, %g7
+       subcc           %g1, 128, %g1
        add             %o1, 128, %o1
-       bne             82b
+       cmp             %g1, 128
+       bge             82b
         add            %o0, 128, %o0
 
-#ifndef FASTER_ALIGNED
-
-       andcc           %g1, 0x70, %g7
-       be              80b
-        andcc          %g1, 8, %g0
-
-       sethi           %hi(80b), %o5
-       srl             %g7, 1, %o4
-       add             %g7, %o4, %o4
-       add             %o1, %g7, %o1
-       sub             %o5, %o4, %o5
-       jmpl            %o5 + %lo(80b), %g0
-        add            %o0, %g7, %o0
-
-#else /* FASTER_ALIGNED */
-
-       andcc           %g1, 0x70, %g7
+       andcc           %g1, 0x70, %g4
        be              84f
         andcc          %g1, 8, %g0
 
        sethi           %hi(84f), %o5
-       add             %o1, %g7, %o1
-       sub             %o5, %g7, %o5
+       add             %o1, %g4, %o1
+       sub             %o5, %g4, %o5
        jmpl            %o5 + %lo(84f), %g0
-        add            %o0, %g7, %o0
+        add            %o0, %g4, %o0
 
 83:    /* amemcpy_table */
 
@@ -721,382 +365,132 @@ FUNC(memcpy)    /* %o0=dst %o1=src %o2=len */
        stb             %g2, [%o0]
 1:
        retl
-        RETL_INSN
-
-#endif /* FASTER_ALIGNED */
+        mov            %g7, %o0
 
 86:    /* non_aligned */
        cmp             %o2, 6
        bleu            88f
+        nop
 
-#ifdef FASTER_NONALIGNED
-
-        cmp            %o2, 256
-       bcc             87f
-
-#endif /* FASTER_NONALIGNED */
-
-        andcc          %o0, 3, %g0
+       save            %sp, -96, %sp
+       andcc           %i0, 3, %g0
        be              61f
-        andcc          %o0, 1, %g0
+        andcc          %i0, 1, %g0
        be              60f
-        andcc          %o0, 2, %g0
+        andcc          %i0, 2, %g0
 
-       ldub            [%o1], %g5
-       add             %o1, 1, %o1
-       stb             %g5, [%o0]
-       sub             %o2, 1, %o2
+       ldub            [%i1], %g5
+       add             %i1, 1, %i1
+       stb             %g5, [%i0]
+       sub             %i2, 1, %i2
        bne             61f
-        add            %o0, 1, %o0
+        add            %i0, 1, %i0
 60:
-       ldub            [%o1], %g3
-       add             %o1, 2, %o1
-       stb             %g3, [%o0]
-       sub             %o2, 2, %o2
-       ldub            [%o1 - 1], %g3
-       add             %o0, 2, %o0
-       stb             %g3, [%o0 - 1]
+       ldub            [%i1], %g3
+       add             %i1, 2, %i1
+       stb             %g3, [%i0]
+       sub             %i2, 2, %i2
+       ldub            [%i1 - 1], %g3
+       add             %i0, 2, %i0
+       stb             %g3, [%i0 - 1]
 61:
-       and             %o1, 3, %g2
-       and             %o2, 0xc, %g3
-       and             %o1, -4, %o1
+       and             %i1, 3, %g2
+       and             %i2, 0xc, %g3
+       and             %i1, -4, %i1
        cmp             %g3, 4
        sll             %g2, 3, %g4
        mov             32, %g2
        be              4f
-        sub            %g2, %g4, %g7
+        sub            %g2, %g4, %l0
        
        blu             3f
         cmp            %g3, 0x8
 
        be              2f
-        srl            %o2, 2, %g3
+        srl            %i2, 2, %g3
 
-       ld              [%o1], %o3
-       add             %o0, -8, %o0
-       ld              [%o1 + 4], %o4
+       ld              [%i1], %i3
+       add             %i0, -8, %i0
+       ld              [%i1 + 4], %i4
        b               8f
         add            %g3, 1, %g3
 2:
-       ld              [%o1], %o4
-       add             %o0, -12, %o0
-       ld              [%o1 + 4], %o5
+       ld              [%i1], %i4
+       add             %i0, -12, %i0
+       ld              [%i1 + 4], %i5
        add             %g3, 2, %g3
        b               9f
-        add            %o1, -4, %o1
+        add            %i1, -4, %i1
 3:
-       ld              [%o1], %g1
-       add             %o0, -4, %o0
-       ld              [%o1 + 4], %o3
-       srl             %o2, 2, %g3
+       ld              [%i1], %g1
+       add             %i0, -4, %i0
+       ld              [%i1 + 4], %i3
+       srl             %i2, 2, %g3
        b               7f
-        add            %o1, 4, %o1
+        add            %i1, 4, %i1
 4:
-       ld              [%o1], %o5
-       cmp             %o2, 7
-       ld              [%o1 + 4], %g1
-       srl             %o2, 2, %g3
+       ld              [%i1], %i5
+       cmp             %i2, 7
+       ld              [%i1 + 4], %g1
+       srl             %i2, 2, %g3
        bleu            10f
-        add            %o1, 8, %o1
+        add            %i1, 8, %i1
 
-       ld              [%o1], %o3
+       ld              [%i1], %i3
        add             %g3, -1, %g3
 5:
-       sll             %o5, %g4, %g2
-       srl             %g1, %g7, %g5
+       sll             %i5, %g4, %g2
+       srl             %g1, %l0, %g5
        or              %g2, %g5, %g2
-       st              %g2, [%o0]
+       st              %g2, [%i0]
 7:
-       ld              [%o1 + 4], %o4
+       ld              [%i1 + 4], %i4
        sll             %g1, %g4, %g2
-       srl             %o3, %g7, %g5
+       srl             %i3, %l0, %g5
        or              %g2, %g5, %g2
-       st              %g2, [%o0 + 4]
+       st              %g2, [%i0 + 4]
 8:
-       ld              [%o1 + 8], %o5
-       sll             %o3, %g4, %g2
-       srl             %o4, %g7, %g5
+       ld              [%i1 + 8], %i5
+       sll             %i3, %g4, %g2
+       srl             %i4, %l0, %g5
        or              %g2, %g5, %g2
-       st              %g2, [%o0 + 8]
+       st              %g2, [%i0 + 8]
 9:
-       ld              [%o1 + 12], %g1
-       sll             %o4, %g4, %g2
-       srl             %o5, %g7, %g5
+       ld              [%i1 + 12], %g1
+       sll             %i4, %g4, %g2
+       srl             %i5, %l0, %g5
        addcc           %g3, -4, %g3
        or              %g2, %g5, %g2
-       add             %o1, 16, %o1
-       st              %g2, [%o0 + 12]
-       add             %o0, 16, %o0
+       add             %i1, 16, %i1
+       st              %g2, [%i0 + 12]
+       add             %i0, 16, %i0
        bne,a           5b
-        ld             [%o1], %o3
+        ld             [%i1], %i3
 10:
-       sll             %o5, %g4, %g2
-       srl             %g1, %g7, %g5
-       srl             %g7, 3, %g3
+       sll             %i5, %g4, %g2
+       srl             %g1, %l0, %g5
+       srl             %l0, 3, %g3
        or              %g2, %g5, %g2
-       sub             %o1, %g3, %o1
-       andcc           %o2, 2, %g0
-       st              %g2, [%o0]
+       sub             %i1, %g3, %i1
+       andcc           %i2, 2, %g0
+       st              %g2, [%i0]
        be              1f
-        andcc          %o2, 1, %g0
-
-       ldub            [%o1], %g2
-       add             %o1, 2, %o1
-       stb             %g2, [%o0 + 4]
-       add             %o0, 2, %o0
-       ldub            [%o1 - 1], %g2
-       stb             %g2, [%o0 + 3]
+        andcc          %i2, 1, %g0
+
+       ldub            [%i1], %g2
+       add             %i1, 2, %i1
+       stb             %g2, [%i0 + 4]
+       add             %i0, 2, %i0
+       ldub            [%i1 - 1], %g2
+       stb             %g2, [%i0 + 3]
 1:
        be              1f
         nop
-       ldub            [%o1], %g2
-       stb             %g2, [%o0 + 4]
-1:
-       retl
-        RETL_INSN
-
-#ifdef FASTER_NONALIGNED
-
-87:    /* faster_nonaligned */
-
-       andcc           %o1, 3, %g0
-       be              3f
-        andcc          %o1, 1, %g0
-
-       be              4f
-        andcc          %o1, 2, %g0
-
-       ldub            [%o1], %g2
-       add             %o1, 1, %o1
-       stb             %g2, [%o0]
-       sub             %o2, 1, %o2
-       bne             3f
-        add            %o0, 1, %o0
-4:
-       lduh            [%o1], %g2
-       add             %o1, 2, %o1
-       srl             %g2, 8, %g3
-       sub             %o2, 2, %o2
-       stb             %g3, [%o0]
-       add             %o0, 2, %o0
-       stb             %g2, [%o0 - 1]
-3:
-        andcc          %o1, 4, %g0
-
-       bne             2f
-        cmp            %o5, 1
-
-       ld              [%o1], %o4
-       srl             %o4, 24, %g2
-       stb             %g2, [%o0]
-       srl             %o4, 16, %g3
-       stb             %g3, [%o0 + 1]
-       srl             %o4, 8, %g2
-       stb             %g2, [%o0 + 2]
-       sub             %o2, 4, %o2
-       stb             %o4, [%o0 + 3]
-       add             %o1, 4, %o1
-       add             %o0, 4, %o0
-2:
-       be              33f
-        cmp            %o5, 2
-       be              32f
-        sub            %o2, 4, %o2
-31:
-       ld              [%o1], %g2
-       add             %o1, 4, %o1
-       srl             %g2, 24, %g3
-       and             %o0, 7, %g5
-       stb             %g3, [%o0]
-       cmp             %g5, 7
-       sll             %g2, 8, %g1
-       add             %o0, 4, %o0
-       be              41f
-        and            %o2, 0xffffffc0, %o3
-       ld              [%o0 - 7], %o4
-4:
-       SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-       SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-       SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-       SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-       subcc           %o3, 64, %o3
-       add             %o1, 64, %o1
-       bne             4b
-        add            %o0, 64, %o0
-
-       andcc           %o2, 0x30, %o3
-       be,a            1f
-        srl            %g1, 16, %g2
-4:
-       SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-       subcc           %o3, 16, %o3
-       add             %o1, 16, %o1
-       bne             4b
-        add            %o0, 16, %o0
-
-       srl             %g1, 16, %g2
-1:
-       st              %o4, [%o0 - 7]
-       sth             %g2, [%o0 - 3]
-       srl             %g1, 8, %g4
-       b               88f
-        stb            %g4, [%o0 - 1]
-32:
-       ld              [%o1], %g2
-       add             %o1, 4, %o1
-       srl             %g2, 16, %g3
-       and             %o0, 7, %g5
-       sth             %g3, [%o0]
-       cmp             %g5, 6
-       sll             %g2, 16, %g1
-       add             %o0, 4, %o0
-       be              42f
-        and            %o2, 0xffffffc0, %o3
-       ld              [%o0 - 6], %o4
-4:
-       SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-       SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-       SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-       SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-       subcc           %o3, 64, %o3
-       add             %o1, 64, %o1
-       bne             4b
-        add            %o0, 64, %o0
-
-       andcc           %o2, 0x30, %o3
-       be,a            1f
-        srl            %g1, 16, %g2
-4:
-       SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-       subcc           %o3, 16, %o3
-       add             %o1, 16, %o1
-       bne             4b
-        add            %o0, 16, %o0
-
-       srl             %g1, 16, %g2
-1:
-       st              %o4, [%o0 - 6]
-       b               88f
-        sth            %g2, [%o0 - 2]
-33:
-       ld              [%o1], %g2
-       sub             %o2, 4, %o2
-       srl             %g2, 24, %g3
-       and             %o0, 7, %g5
-       stb             %g3, [%o0]
-       cmp             %g5, 5
-       srl             %g2, 8, %g4
-       sll             %g2, 24, %g1
-       sth             %g4, [%o0 + 1]
-       add             %o1, 4, %o1
-       be              43f
-        and            %o2, 0xffffffc0, %o3
-
-       ld              [%o0 - 1], %o4
-       add             %o0, 4, %o0
-4:
-       SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
-       SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
-       SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
-       SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
-       subcc           %o3, 64, %o3
-       add             %o1, 64, %o1
-       bne             4b
-        add            %o0, 64, %o0
-
-       andcc           %o2, 0x30, %o3
-       be,a            1f
-        srl            %g1, 24, %g2
-4:
-       SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
-       subcc           %o3, 16, %o3
-       add             %o1, 16, %o1
-       bne             4b
-        add            %o0, 16, %o0
-
-       srl             %g1, 24, %g2
-1:
-       st              %o4, [%o0 - 5]
-       b               88f
-        stb            %g2, [%o0 - 1]
-41:
-       SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-       SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-       SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-       SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-       subcc           %o3, 64, %o3
-       add             %o1, 64, %o1
-       bne             41b
-        add            %o0, 64, %o0
-        
-       andcc           %o2, 0x30, %o3
-       be,a            1f
-        srl            %g1, 16, %g2
-4:
-       SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-       subcc           %o3, 16, %o3
-       add             %o1, 16, %o1
-       bne             4b
-        add            %o0, 16, %o0
-
-       srl             %g1, 16, %g2
+       ldub            [%i1], %g2
+       stb             %g2, [%i0 + 4]
 1:
-       sth             %g2, [%o0 - 3]
-       srl             %g1, 8, %g4
-       b               88f
-        stb            %g4, [%o0 - 1]
-43:
-       SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
-       SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
-       SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
-       SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
-       subcc           %o3, 64, %o3
-       add             %o1, 64, %o1
-       bne             43b
-        add            %o0, 64, %o0
-
-       andcc           %o2, 0x30, %o3
-       be,a            1f
-        srl            %g1, 24, %g2
-4:
-       SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
-       subcc           %o3, 16, %o3
-       add             %o1, 16, %o1
-       bne             4b
-        add            %o0, 16, %o0
-
-       srl             %g1, 24, %g2
-1:
-       stb             %g2, [%o0 + 3]
-       b               88f
-        add            %o0, 4, %o0
-42:
-       SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-       SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-       SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-       SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-       subcc           %o3, 64, %o3
-       add             %o1, 64, %o1
-       bne             42b
-        add            %o0, 64, %o0
-        
-       andcc           %o2, 0x30, %o3
-       be,a            1f
-        srl            %g1, 16, %g2
-4:
-       SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-       subcc           %o3, 16, %o3
-       add             %o1, 16, %o1
-       bne             4b
-        add            %o0, 16, %o0
-
-       srl             %g1, 16, %g2
-1:
-       sth             %g2, [%o0 - 2]
-
-       /* Fall through */
-        
-#endif /* FASTER_NONALIGNED */
+       ret
+        restore        %g7, %g0, %o0
 
 88:    /* short_end */
 
@@ -1127,7 +521,7 @@ FUNC(memcpy)       /* %o0=dst %o1=src %o2=len */
        stb             %g2, [%o0]
 1:
        retl
-        RETL_INSN
+        mov            %g7, %o0
 
 90:    /* short_aligned_end */
        bne             88b
index 34595d5..3925d80 100644 (file)
 #define                APIC_TIMER_BASE_CLKIN           0x0
 #define                APIC_TIMER_BASE_TMBASE          0x1
 #define                APIC_TIMER_BASE_DIV             0x2
+#define                APIC_LVT_TIMER_ONESHOT          (0 << 17)
 #define                APIC_LVT_TIMER_PERIODIC         (1 << 17)
+#define                APIC_LVT_TIMER_TSCDEADLINE      (2 << 17)
 #define                APIC_LVT_MASKED                 (1 << 16)
 #define                APIC_LVT_LEVEL_TRIGGER          (1 << 15)
 #define                APIC_LVT_REMOTE_IRR             (1 << 14)
index aa6a488..2f84a43 100644 (file)
 #define X86_FEATURE_X2APIC     (4*32+21) /* x2APIC */
 #define X86_FEATURE_MOVBE      (4*32+22) /* MOVBE instruction */
 #define X86_FEATURE_POPCNT      (4*32+23) /* POPCNT instruction */
+#define X86_FEATURE_TSC_DEADLINE_TIMER (4*32+24) /* Tsc deadline timer */
 #define X86_FEATURE_AES                (4*32+25) /* AES instructions */
 #define X86_FEATURE_XSAVE      (4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
 #define X86_FEATURE_OSXSAVE    (4*32+27) /* "" XSAVE enabled in the OS */
index 6040d11..a026507 100644 (file)
@@ -262,7 +262,7 @@ struct x86_emulate_ctxt {
        struct operand dst;
        bool has_seg_override;
        u8 seg_override;
-       unsigned int d;
+       u64 d;
        int (*execute)(struct x86_emulate_ctxt *ctxt);
        int (*check_perm)(struct x86_emulate_ctxt *ctxt);
        /* modrm */
@@ -275,6 +275,8 @@ struct x86_emulate_ctxt {
        unsigned long _eip;
        /* Fields above regs are cleared together. */
        unsigned long regs[NR_VCPU_REGS];
+       struct operand memop;
+       struct operand *memopp;
        struct fetch_cache fetch;
        struct read_cache io_read;
        struct read_cache mem_read;
index dd51c83..b4973f4 100644 (file)
@@ -26,7 +26,8 @@
 #include <asm/mtrr.h>
 #include <asm/msr-index.h>
 
-#define KVM_MAX_VCPUS 64
+#define KVM_MAX_VCPUS 254
+#define KVM_SOFT_MAX_VCPUS 64
 #define KVM_MEMORY_SLOTS 32
 /* memory slots that does not exposed to userspace */
 #define KVM_PRIVATE_MEM_SLOTS 4
@@ -264,6 +265,7 @@ struct kvm_mmu {
        void (*new_cr3)(struct kvm_vcpu *vcpu);
        void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long root);
        unsigned long (*get_cr3)(struct kvm_vcpu *vcpu);
+       u64 (*get_pdptr)(struct kvm_vcpu *vcpu, int index);
        int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err,
                          bool prefault);
        void (*inject_page_fault)(struct kvm_vcpu *vcpu,
@@ -411,8 +413,9 @@ struct kvm_vcpu_arch {
        u32  tsc_catchup_mult;
        s8   tsc_catchup_shift;
 
-       bool nmi_pending;
-       bool nmi_injected;
+       atomic_t nmi_queued;  /* unprocessed asynchronous NMIs */
+       unsigned nmi_pending; /* NMI queued after currently running handler */
+       bool nmi_injected;    /* Trying to inject an NMI this entry */
 
        struct mtrr_state_type mtrr_state;
        u32 pat;
@@ -628,14 +631,13 @@ struct kvm_x86_ops {
        void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
 
        u64 (*compute_tsc_offset)(struct kvm_vcpu *vcpu, u64 target_tsc);
+       u64 (*read_l1_tsc)(struct kvm_vcpu *vcpu);
 
        void (*get_exit_info)(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2);
 
        int (*check_intercept)(struct kvm_vcpu *vcpu,
                               struct x86_instruction_info *info,
                               enum x86_intercept_stage stage);
-
-       const struct trace_print_flags *exit_reasons_str;
 };
 
 struct kvm_arch_async_pf {
@@ -672,6 +674,8 @@ u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn);
 
 extern bool tdp_enabled;
 
+u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu);
+
 /* control of guest tsc rate supported? */
 extern bool kvm_has_tsc_control;
 /* minimum supported tsc_khz for guests */
index d52609a..a6962d9 100644 (file)
 #define MSR_IA32_APICBASE_ENABLE       (1<<11)
 #define MSR_IA32_APICBASE_BASE         (0xfffff<<12)
 
+#define MSR_IA32_TSCDEADLINE           0x000006e0
+
 #define MSR_IA32_UCODE_WRITE           0x00000079
 #define MSR_IA32_UCODE_REV             0x0000008b
 
index 2caf290..31f180c 100644 (file)
@@ -350,6 +350,18 @@ enum vmcs_field {
 #define DEBUG_REG_ACCESS_REG(eq)        (((eq) >> 8) & 0xf) /* 11:8, general purpose reg. */
 
 
+/*
+ * Exit Qualifications for APIC-Access
+ */
+#define APIC_ACCESS_OFFSET              0xfff   /* 11:0, offset within the APIC page */
+#define APIC_ACCESS_TYPE                0xf000  /* 15:12, access type */
+#define TYPE_LINEAR_APIC_INST_READ      (0 << 12)
+#define TYPE_LINEAR_APIC_INST_WRITE     (1 << 12)
+#define TYPE_LINEAR_APIC_INST_FETCH     (2 << 12)
+#define TYPE_LINEAR_APIC_EVENT          (3 << 12)
+#define TYPE_PHYSICAL_APIC_EVENT        (10 << 12)
+#define TYPE_PHYSICAL_APIC_INST         (15 << 12)
+
 /* segment AR */
 #define SEGMENT_AR_L_MASK (1 << 13)
 
index 8b4cc5f..f1e3be1 100644 (file)
 #include "x86.h"
 #include "tss.h"
 
+/*
+ * Operand types
+ */
+#define OpNone             0ull
+#define OpImplicit         1ull  /* No generic decode */
+#define OpReg              2ull  /* Register */
+#define OpMem              3ull  /* Memory */
+#define OpAcc              4ull  /* Accumulator: AL/AX/EAX/RAX */
+#define OpDI               5ull  /* ES:DI/EDI/RDI */
+#define OpMem64            6ull  /* Memory, 64-bit */
+#define OpImmUByte         7ull  /* Zero-extended 8-bit immediate */
+#define OpDX               8ull  /* DX register */
+#define OpCL               9ull  /* CL register (for shifts) */
+#define OpImmByte         10ull  /* 8-bit sign extended immediate */
+#define OpOne             11ull  /* Implied 1 */
+#define OpImm             12ull  /* Sign extended immediate */
+#define OpMem16           13ull  /* Memory operand (16-bit). */
+#define OpMem32           14ull  /* Memory operand (32-bit). */
+#define OpImmU            15ull  /* Immediate operand, zero extended */
+#define OpSI              16ull  /* SI/ESI/RSI */
+#define OpImmFAddr        17ull  /* Immediate far address */
+#define OpMemFAddr        18ull  /* Far address in memory */
+#define OpImmU16          19ull  /* Immediate operand, 16 bits, zero extended */
+#define OpES              20ull  /* ES */
+#define OpCS              21ull  /* CS */
+#define OpSS              22ull  /* SS */
+#define OpDS              23ull  /* DS */
+#define OpFS              24ull  /* FS */
+#define OpGS              25ull  /* GS */
+
+#define OpBits             5  /* Width of operand field */
+#define OpMask             ((1ull << OpBits) - 1)
+
 /*
  * Opcode effective-address decode tables.
  * Note that we only emulate instructions that have at least one memory
 /* Operand sizes: 8-bit operands or specified/overridden size. */
 #define ByteOp      (1<<0)     /* 8-bit operands. */
 /* Destination operand type. */
-#define ImplicitOps (1<<1)     /* Implicit in opcode. No generic decode. */
-#define DstReg      (2<<1)     /* Register operand. */
-#define DstMem      (3<<1)     /* Memory operand. */
-#define DstAcc      (4<<1)     /* Destination Accumulator */
-#define DstDI       (5<<1)     /* Destination is in ES:(E)DI */
-#define DstMem64    (6<<1)     /* 64bit memory operand */
-#define DstImmUByte (7<<1)     /* 8-bit unsigned immediate operand */
-#define DstDX       (8<<1)     /* Destination is in DX register */
-#define DstMask     (0xf<<1)
+#define DstShift    1
+#define ImplicitOps (OpImplicit << DstShift)
+#define DstReg      (OpReg << DstShift)
+#define DstMem      (OpMem << DstShift)
+#define DstAcc      (OpAcc << DstShift)
+#define DstDI       (OpDI << DstShift)
+#define DstMem64    (OpMem64 << DstShift)
+#define DstImmUByte (OpImmUByte << DstShift)
+#define DstDX       (OpDX << DstShift)
+#define DstMask     (OpMask << DstShift)
 /* Source operand type. */
-#define SrcNone     (0<<5)     /* No source operand. */
-#define SrcReg      (1<<5)     /* Register operand. */
-#define SrcMem      (2<<5)     /* Memory operand. */
-#define SrcMem16    (3<<5)     /* Memory operand (16-bit). */
-#define SrcMem32    (4<<5)     /* Memory operand (32-bit). */
-#define SrcImm      (5<<5)     /* Immediate operand. */
-#define SrcImmByte  (6<<5)     /* 8-bit sign-extended immediate operand. */
-#define SrcOne      (7<<5)     /* Implied '1' */
-#define SrcImmUByte (8<<5)      /* 8-bit unsigned immediate operand. */
-#define SrcImmU     (9<<5)      /* Immediate operand, unsigned */
-#define SrcSI       (0xa<<5)   /* Source is in the DS:RSI */
-#define SrcImmFAddr (0xb<<5)   /* Source is immediate far address */
-#define SrcMemFAddr (0xc<<5)   /* Source is far address in memory */
-#define SrcAcc      (0xd<<5)   /* Source Accumulator */
-#define SrcImmU16   (0xe<<5)    /* Immediate operand, unsigned, 16 bits */
-#define SrcDX       (0xf<<5)   /* Source is in DX register */
-#define SrcMask     (0xf<<5)
-/* Generic ModRM decode. */
-#define ModRM       (1<<9)
-/* Destination is only written; never read. */
-#define Mov         (1<<10)
+#define SrcShift    6
+#define SrcNone     (OpNone << SrcShift)
+#define SrcReg      (OpReg << SrcShift)
+#define SrcMem      (OpMem << SrcShift)
+#define SrcMem16    (OpMem16 << SrcShift)
+#define SrcMem32    (OpMem32 << SrcShift)
+#define SrcImm      (OpImm << SrcShift)
+#define SrcImmByte  (OpImmByte << SrcShift)
+#define SrcOne      (OpOne << SrcShift)
+#define SrcImmUByte (OpImmUByte << SrcShift)
+#define SrcImmU     (OpImmU << SrcShift)
+#define SrcSI       (OpSI << SrcShift)
+#define SrcImmFAddr (OpImmFAddr << SrcShift)
+#define SrcMemFAddr (OpMemFAddr << SrcShift)
+#define SrcAcc      (OpAcc << SrcShift)
+#define SrcImmU16   (OpImmU16 << SrcShift)
+#define SrcDX       (OpDX << SrcShift)
+#define SrcMask     (OpMask << SrcShift)
 #define BitOp       (1<<11)
 #define MemAbs      (1<<12)      /* Memory operand is absolute displacement */
 #define String      (1<<13)     /* String instruction (rep capable) */
 #define Prefix      (3<<15)     /* Instruction varies with 66/f2/f3 prefix */
 #define RMExt       (4<<15)     /* Opcode extension in ModRM r/m if mod == 3 */
 #define Sse         (1<<18)     /* SSE Vector instruction */
+/* Generic ModRM decode. */
+#define ModRM       (1<<19)
+/* Destination is only written; never read. */
+#define Mov         (1<<20)
 /* Misc flags */
 #define Prot        (1<<21) /* instruction generates #UD if not in prot-mode */
 #define VendorSpecific (1<<22) /* Vendor specific instruction */
 #define Priv        (1<<27) /* instruction generates #GP if current CPL != 0 */
 #define No64       (1<<28)
 /* Source 2 operand type */
-#define Src2None    (0<<29)
-#define Src2CL      (1<<29)
-#define Src2ImmByte (2<<29)
-#define Src2One     (3<<29)
-#define Src2Imm     (4<<29)
-#define Src2Mask    (7<<29)
+#define Src2Shift   (29)
+#define Src2None    (OpNone << Src2Shift)
+#define Src2CL      (OpCL << Src2Shift)
+#define Src2ImmByte (OpImmByte << Src2Shift)
+#define Src2One     (OpOne << Src2Shift)
+#define Src2Imm     (OpImm << Src2Shift)
+#define Src2ES      (OpES << Src2Shift)
+#define Src2CS      (OpCS << Src2Shift)
+#define Src2SS      (OpSS << Src2Shift)
+#define Src2DS      (OpDS << Src2Shift)
+#define Src2FS      (OpFS << Src2Shift)
+#define Src2GS      (OpGS << Src2Shift)
+#define Src2Mask    (OpMask << Src2Shift)
 
 #define X2(x...) x, x
 #define X3(x...) X2(x), x
 #define X16(x...) X8(x), X8(x)
 
 struct opcode {
-       u32 flags;
-       u8 intercept;
+       u64 flags : 56;
+       u64 intercept : 8;
        union {
                int (*execute)(struct x86_emulate_ctxt *ctxt);
                struct opcode *group;
@@ -205,105 +247,100 @@ struct gprefix {
 #define ON64(x)
 #endif
 
-#define ____emulate_2op(_op, _src, _dst, _eflags, _x, _y, _suffix, _dsttype) \
+#define ____emulate_2op(ctxt, _op, _x, _y, _suffix, _dsttype)  \
        do {                                                            \
                __asm__ __volatile__ (                                  \
                        _PRE_EFLAGS("0", "4", "2")                      \
                        _op _suffix " %"_x"3,%1; "                      \
                        _POST_EFLAGS("0", "4", "2")                     \
-                       : "=m" (_eflags), "+q" (*(_dsttype*)&(_dst).val),\
+                       : "=m" ((ctxt)->eflags),                        \
+                         "+q" (*(_dsttype*)&(ctxt)->dst.val),          \
                          "=&r" (_tmp)                                  \
-                       : _y ((_src).val), "i" (EFLAGS_MASK));          \
+                       : _y ((ctxt)->src.val), "i" (EFLAGS_MASK));     \
        } while (0)
 
 
 /* Raw emulation: instruction has two explicit operands. */
-#define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy) \
+#define __emulate_2op_nobyte(ctxt,_op,_wx,_wy,_lx,_ly,_qx,_qy)         \
        do {                                                            \
                unsigned long _tmp;                                     \
                                                                        \
-               switch ((_dst).bytes) {                                 \
+               switch ((ctxt)->dst.bytes) {                            \
                case 2:                                                 \
-                       ____emulate_2op(_op,_src,_dst,_eflags,_wx,_wy,"w",u16);\
+                       ____emulate_2op(ctxt,_op,_wx,_wy,"w",u16);      \
                        break;                                          \
                case 4:                                                 \
-                       ____emulate_2op(_op,_src,_dst,_eflags,_lx,_ly,"l",u32);\
+                       ____emulate_2op(ctxt,_op,_lx,_ly,"l",u32);      \
                        break;                                          \
                case 8:                                                 \
-                       ON64(____emulate_2op(_op,_src,_dst,_eflags,_qx,_qy,"q",u64)); \
+                       ON64(____emulate_2op(ctxt,_op,_qx,_qy,"q",u64)); \
                        break;                                          \
                }                                                       \
        } while (0)
 
-#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy) \
+#define __emulate_2op(ctxt,_op,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy)                     \
        do {                                                                 \
                unsigned long _tmp;                                          \
-               switch ((_dst).bytes) {                                      \
+               switch ((ctxt)->dst.bytes) {                                 \
                case 1:                                                      \
-                       ____emulate_2op(_op,_src,_dst,_eflags,_bx,_by,"b",u8); \
+                       ____emulate_2op(ctxt,_op,_bx,_by,"b",u8);            \
                        break;                                               \
                default:                                                     \
-                       __emulate_2op_nobyte(_op, _src, _dst, _eflags,       \
+                       __emulate_2op_nobyte(ctxt, _op,                      \
                                             _wx, _wy, _lx, _ly, _qx, _qy);  \
                        break;                                               \
                }                                                            \
        } while (0)
 
 /* Source operand is byte-sized and may be restricted to just %cl. */
-#define emulate_2op_SrcB(_op, _src, _dst, _eflags)                      \
-       __emulate_2op(_op, _src, _dst, _eflags,                         \
-                     "b", "c", "b", "c", "b", "c", "b", "c")
+#define emulate_2op_SrcB(ctxt, _op)                                    \
+       __emulate_2op(ctxt, _op, "b", "c", "b", "c", "b", "c", "b", "c")
 
 /* Source operand is byte, word, long or quad sized. */
-#define emulate_2op_SrcV(_op, _src, _dst, _eflags)                      \
-       __emulate_2op(_op, _src, _dst, _eflags,                         \
-                     "b", "q", "w", "r", _LO32, "r", "", "r")
+#define emulate_2op_SrcV(ctxt, _op)                                    \
+       __emulate_2op(ctxt, _op, "b", "q", "w", "r", _LO32, "r", "", "r")
 
 /* Source operand is word, long or quad sized. */
-#define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags)               \
-       __emulate_2op_nobyte(_op, _src, _dst, _eflags,                  \
-                            "w", "r", _LO32, "r", "", "r")
+#define emulate_2op_SrcV_nobyte(ctxt, _op)                             \
+       __emulate_2op_nobyte(ctxt, _op, "w", "r", _LO32, "r", "", "r")
 
 /* Instruction has three operands and one operand is stored in ECX register */
-#define __emulate_2op_cl(_op, _cl, _src, _dst, _eflags, _suffix, _type)        \
+#define __emulate_2op_cl(ctxt, _op, _suffix, _type)            \
        do {                                                            \
                unsigned long _tmp;                                     \
-               _type _clv  = (_cl).val;                                \
-               _type _srcv = (_src).val;                               \
-               _type _dstv = (_dst).val;                               \
+               _type _clv  = (ctxt)->src2.val;                         \
+               _type _srcv = (ctxt)->src.val;                          \
+               _type _dstv = (ctxt)->dst.val;                          \
                                                                        \
                __asm__ __volatile__ (                                  \
                        _PRE_EFLAGS("0", "5", "2")                      \
                        _op _suffix " %4,%1 \n"                         \
                        _POST_EFLAGS("0", "5", "2")                     \
-                       : "=m" (_eflags), "+r" (_dstv), "=&r" (_tmp)    \
+                       : "=m" ((ctxt)->eflags), "+r" (_dstv), "=&r" (_tmp) \
                        : "c" (_clv) , "r" (_srcv), "i" (EFLAGS_MASK)   \
                        );                                              \
                                                                        \
-               (_cl).val  = (unsigned long) _clv;                      \
-               (_src).val = (unsigned long) _srcv;                     \
-               (_dst).val = (unsigned long) _dstv;                     \
+               (ctxt)->src2.val  = (unsigned long) _clv;               \
+               (ctxt)->src2.val = (unsigned long) _srcv;               \
+               (ctxt)->dst.val = (unsigned long) _dstv;                \
        } while (0)
 
-#define emulate_2op_cl(_op, _cl, _src, _dst, _eflags)                  \
+#define emulate_2op_cl(ctxt, _op)                                      \
        do {                                                            \
-               switch ((_dst).bytes) {                                 \
+               switch ((ctxt)->dst.bytes) {                            \
                case 2:                                                 \
-                       __emulate_2op_cl(_op, _cl, _src, _dst, _eflags, \
-                                        "w", unsigned short);          \
+                       __emulate_2op_cl(ctxt, _op, "w", u16);          \
                        break;                                          \
                case 4:                                                 \
-                       __emulate_2op_cl(_op, _cl, _src, _dst, _eflags, \
-                                        "l", unsigned int);            \
+                       __emulate_2op_cl(ctxt, _op, "l", u32);          \
                        break;                                          \
                case 8:                                                 \
-                       ON64(__emulate_2op_cl(_op, _cl, _src, _dst, _eflags, \
-                                             "q", unsigned long));     \
+                       ON64(__emulate_2op_cl(ctxt, _op, "q", ulong));  \
                        break;                                          \
                }                                                       \
        } while (0)
 
-#define __emulate_1op(_op, _dst, _eflags, _suffix)                     \
+#define __emulate_1op(ctxt, _op, _suffix)                              \
        do {                                                            \
                unsigned long _tmp;                                     \
                                                                        \
@@ -311,39 +348,27 @@ struct gprefix {
                        _PRE_EFLAGS("0", "3", "2")                      \
                        _op _suffix " %1; "                             \
                        _POST_EFLAGS("0", "3", "2")                     \
-                       : "=m" (_eflags), "+m" ((_dst).val),            \
+                       : "=m" ((ctxt)->eflags), "+m" ((ctxt)->dst.val), \
                          "=&r" (_tmp)                                  \
                        : "i" (EFLAGS_MASK));                           \
        } while (0)
 
 /* Instruction has only one explicit operand (no source operand). */
-#define emulate_1op(_op, _dst, _eflags)                                    \
+#define emulate_1op(ctxt, _op)                                         \
        do {                                                            \
-               switch ((_dst).bytes) {                                 \
-               case 1: __emulate_1op(_op, _dst, _eflags, "b"); break;  \
-               case 2: __emulate_1op(_op, _dst, _eflags, "w"); break;  \
-               case 4: __emulate_1op(_op, _dst, _eflags, "l"); break;  \
-               case 8: ON64(__emulate_1op(_op, _dst, _eflags, "q")); break; \
+               switch ((ctxt)->dst.bytes) {                            \
+               case 1: __emulate_1op(ctxt, _op, "b"); break;           \
+               case 2: __emulate_1op(ctxt, _op, "w"); break;           \
+               case 4: __emulate_1op(ctxt, _op, "l"); break;           \
+               case 8: ON64(__emulate_1op(ctxt, _op, "q")); break;     \
                }                                                       \
        } while (0)
 
-#define __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, _suffix)         \
-       do {                                                            \
-               unsigned long _tmp;                                     \
-                                                                       \
-               __asm__ __volatile__ (                                  \
-                       _PRE_EFLAGS("0", "4", "1")                      \
-                       _op _suffix " %5; "                             \
-                       _POST_EFLAGS("0", "4", "1")                     \
-                       : "=m" (_eflags), "=&r" (_tmp),                 \
-                         "+a" (_rax), "+d" (_rdx)                      \
-                       : "i" (EFLAGS_MASK), "m" ((_src).val),          \
-                         "a" (_rax), "d" (_rdx));                      \
-       } while (0)
-
-#define __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, _eflags, _suffix, _ex) \
+#define __emulate_1op_rax_rdx(ctxt, _op, _suffix, _ex)                 \
        do {                                                            \
                unsigned long _tmp;                                     \
+               ulong *rax = &(ctxt)->regs[VCPU_REGS_RAX];              \
+               ulong *rdx = &(ctxt)->regs[VCPU_REGS_RDX];              \
                                                                        \
                __asm__ __volatile__ (                                  \
                        _PRE_EFLAGS("0", "5", "1")                      \
@@ -356,53 +381,27 @@ struct gprefix {
                        "jmp 2b \n\t"                                   \
                        ".popsection \n\t"                              \
                        _ASM_EXTABLE(1b, 3b)                            \
-                       : "=m" (_eflags), "=&r" (_tmp),                 \
-                         "+a" (_rax), "+d" (_rdx), "+qm"(_ex)          \
-                       : "i" (EFLAGS_MASK), "m" ((_src).val),          \
-                         "a" (_rax), "d" (_rdx));                      \
+                       : "=m" ((ctxt)->eflags), "=&r" (_tmp),          \
+                         "+a" (*rax), "+d" (*rdx), "+qm"(_ex)          \
+                       : "i" (EFLAGS_MASK), "m" ((ctxt)->src.val),     \
+                         "a" (*rax), "d" (*rdx));                      \
        } while (0)
 
 /* instruction has only one source operand, destination is implicit (e.g. mul, div, imul, idiv) */
-#define emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags)            \
+#define emulate_1op_rax_rdx(ctxt, _op, _ex)    \
        do {                                                            \
-               switch((_src).bytes) {                                  \
+               switch((ctxt)->src.bytes) {                             \
                case 1:                                                 \
-                       __emulate_1op_rax_rdx(_op, _src, _rax, _rdx,    \
-                                             _eflags, "b");            \
+                       __emulate_1op_rax_rdx(ctxt, _op, "b", _ex);     \
                        break;                                          \
                case 2:                                                 \
-                       __emulate_1op_rax_rdx(_op, _src, _rax, _rdx,    \
-                                             _eflags, "w");            \
+                       __emulate_1op_rax_rdx(ctxt, _op, "w", _ex);     \
                        break;                                          \
                case 4:                                                 \
-                       __emulate_1op_rax_rdx(_op, _src, _rax, _rdx,    \
-                                             _eflags, "l");            \
-                       break;                                          \
-               case 8:                                                 \
-                       ON64(__emulate_1op_rax_rdx(_op, _src, _rax, _rdx, \
-                                                  _eflags, "q"));      \
-                       break;                                          \
-               }                                                       \
-       } while (0)
-
-#define emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, _eflags, _ex)    \
-       do {                                                            \
-               switch((_src).bytes) {                                  \
-               case 1:                                                 \
-                       __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \
-                                                _eflags, "b", _ex);    \
-                       break;                                          \
-               case 2:                                                 \
-                       __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \
-                                                _eflags, "w", _ex);    \
-                       break;                                          \
-               case 4:                                                 \
-                       __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \
-                                                _eflags, "l", _ex);    \
+                       __emulate_1op_rax_rdx(ctxt, _op, "l", _ex);     \
                        break;                                          \
                case 8: ON64(                                           \
-                       __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \
-                                                _eflags, "q", _ex));   \
+                       __emulate_1op_rax_rdx(ctxt, _op, "q", _ex));    \
                        break;                                          \
                }                                                       \
        } while (0)
@@ -651,41 +650,50 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt,
        return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception);
 }
 
-static int do_insn_fetch_byte(struct x86_emulate_ctxt *ctxt,
-                             unsigned long eip, u8 *dest)
+/*
+ * Fetch the next byte of the instruction being emulated which is pointed to
+ * by ctxt->_eip, then increment ctxt->_eip.
+ *
+ * Also prefetch the remaining bytes of the instruction without crossing page
+ * boundary if they are not in fetch_cache yet.
+ */
+static int do_insn_fetch_byte(struct x86_emulate_ctxt *ctxt, u8 *dest)
 {
        struct fetch_cache *fc = &ctxt->fetch;
        int rc;
        int size, cur_size;
 
-       if (eip == fc->end) {
+       if (ctxt->_eip == fc->end) {
                unsigned long linear;
-               struct segmented_address addr = { .seg=VCPU_SREG_CS, .ea=eip};
+               struct segmented_address addr = { .seg = VCPU_SREG_CS,
+                                                 .ea  = ctxt->_eip };
                cur_size = fc->end - fc->start;
-               size = min(15UL - cur_size, PAGE_SIZE - offset_in_page(eip));
+               size = min(15UL - cur_size,
+                          PAGE_SIZE - offset_in_page(ctxt->_eip));
                rc = __linearize(ctxt, addr, size, false, true, &linear);
-               if (rc != X86EMUL_CONTINUE)
+               if (unlikely(rc != X86EMUL_CONTINUE))
                        return rc;
                rc = ctxt->ops->fetch(ctxt, linear, fc->data + cur_size,
                                      size, &ctxt->exception);
-               if (rc != X86EMUL_CONTINUE)
+               if (unlikely(rc != X86EMUL_CONTINUE))
                        return rc;
                fc->end += size;
        }
-       *dest = fc->data[eip - fc->start];
+       *dest = fc->data[ctxt->_eip - fc->start];
+       ctxt->_eip++;
        return X86EMUL_CONTINUE;
 }
 
 static int do_insn_fetch(struct x86_emulate_ctxt *ctxt,
-                        unsigned long eip, void *dest, unsigned size)
+                        void *dest, unsigned size)
 {
        int rc;
 
        /* x86 instructions are limited to 15 bytes. */
-       if (eip + size - ctxt->eip > 15)
+       if (unlikely(ctxt->_eip + size - ctxt->eip > 15))
                return X86EMUL_UNHANDLEABLE;
        while (size--) {
-               rc = do_insn_fetch_byte(ctxt, eip++, dest++);
+               rc = do_insn_fetch_byte(ctxt, dest++);
                if (rc != X86EMUL_CONTINUE)
                        return rc;
        }
@@ -693,20 +701,18 @@ static int do_insn_fetch(struct x86_emulate_ctxt *ctxt,
 }
 
 /* Fetch next part of the instruction being emulated. */
-#define insn_fetch(_type, _size, _eip)                                 \
+#define insn_fetch(_type, _ctxt)                                       \
 ({     unsigned long _x;                                               \
-       rc = do_insn_fetch(ctxt, (_eip), &_x, (_size));                 \
+       rc = do_insn_fetch(_ctxt, &_x, sizeof(_type));                  \
        if (rc != X86EMUL_CONTINUE)                                     \
                goto done;                                              \
-       (_eip) += (_size);                                              \
        (_type)_x;                                                      \
 })
 
-#define insn_fetch_arr(_arr, _size, _eip)                              \
-({     rc = do_insn_fetch(ctxt, (_eip), _arr, (_size));                \
+#define insn_fetch_arr(_arr, _size, _ctxt)                             \
+({     rc = do_insn_fetch(_ctxt, _arr, (_size));                       \
        if (rc != X86EMUL_CONTINUE)                                     \
                goto done;                                              \
-       (_eip) += (_size);                                              \
 })
 
 /*
@@ -894,7 +900,7 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
                ctxt->modrm_rm = base_reg = (ctxt->rex_prefix & 1) << 3; /* REG.B */
        }
 
-       ctxt->modrm = insn_fetch(u8, 1, ctxt->_eip);
+       ctxt->modrm = insn_fetch(u8, ctxt);
        ctxt->modrm_mod |= (ctxt->modrm & 0xc0) >> 6;
        ctxt->modrm_reg |= (ctxt->modrm & 0x38) >> 3;
        ctxt->modrm_rm |= (ctxt->modrm & 0x07);
@@ -928,13 +934,13 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
                switch (ctxt->modrm_mod) {
                case 0:
                        if (ctxt->modrm_rm == 6)
-                               modrm_ea += insn_fetch(u16, 2, ctxt->_eip);
+                               modrm_ea += insn_fetch(u16, ctxt);
                        break;
                case 1:
-                       modrm_ea += insn_fetch(s8, 1, ctxt->_eip);
+                       modrm_ea += insn_fetch(s8, ctxt);
                        break;
                case 2:
-                       modrm_ea += insn_fetch(u16, 2, ctxt->_eip);
+                       modrm_ea += insn_fetch(u16, ctxt);
                        break;
                }
                switch (ctxt->modrm_rm) {
@@ -971,13 +977,13 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
        } else {
                /* 32/64-bit ModR/M decode. */
                if ((ctxt->modrm_rm & 7) == 4) {
-                       sib = insn_fetch(u8, 1, ctxt->_eip);
+                       sib = insn_fetch(u8, ctxt);
                        index_reg |= (sib >> 3) & 7;
                        base_reg |= sib & 7;
                        scale = sib >> 6;
 
                        if ((base_reg & 7) == 5 && ctxt->modrm_mod == 0)
-                               modrm_ea += insn_fetch(s32, 4, ctxt->_eip);
+                               modrm_ea += insn_fetch(s32, ctxt);
                        else
                                modrm_ea += ctxt->regs[base_reg];
                        if (index_reg != 4)
@@ -990,13 +996,13 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
                switch (ctxt->modrm_mod) {
                case 0:
                        if (ctxt->modrm_rm == 5)
-                               modrm_ea += insn_fetch(s32, 4, ctxt->_eip);
+                               modrm_ea += insn_fetch(s32, ctxt);
                        break;
                case 1:
-                       modrm_ea += insn_fetch(s8, 1, ctxt->_eip);
+                       modrm_ea += insn_fetch(s8, ctxt);
                        break;
                case 2:
-                       modrm_ea += insn_fetch(s32, 4, ctxt->_eip);
+                       modrm_ea += insn_fetch(s32, ctxt);
                        break;
                }
        }
@@ -1013,13 +1019,13 @@ static int decode_abs(struct x86_emulate_ctxt *ctxt,
        op->type = OP_MEM;
        switch (ctxt->ad_bytes) {
        case 2:
-               op->addr.mem.ea = insn_fetch(u16, 2, ctxt->_eip);
+               op->addr.mem.ea = insn_fetch(u16, ctxt);
                break;
        case 4:
-               op->addr.mem.ea = insn_fetch(u32, 4, ctxt->_eip);
+               op->addr.mem.ea = insn_fetch(u32, ctxt);
                break;
        case 8:
-               op->addr.mem.ea = insn_fetch(u64, 8, ctxt->_eip);
+               op->addr.mem.ea = insn_fetch(u64, ctxt);
                break;
        }
 done:
@@ -1452,15 +1458,18 @@ static int em_popf(struct x86_emulate_ctxt *ctxt)
        return emulate_popf(ctxt, &ctxt->dst.val, ctxt->op_bytes);
 }
 
-static int emulate_push_sreg(struct x86_emulate_ctxt *ctxt, int seg)
+static int em_push_sreg(struct x86_emulate_ctxt *ctxt)
 {
+       int seg = ctxt->src2.val;
+
        ctxt->src.val = get_segment_selector(ctxt, seg);
 
        return em_push(ctxt);
 }
 
-static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt, int seg)
+static int em_pop_sreg(struct x86_emulate_ctxt *ctxt)
 {
+       int seg = ctxt->src2.val;
        unsigned long selector;
        int rc;
 
@@ -1674,64 +1683,74 @@ static int em_grp2(struct x86_emulate_ctxt *ctxt)
 {
        switch (ctxt->modrm_reg) {
        case 0: /* rol */
-               emulate_2op_SrcB("rol", ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_SrcB(ctxt, "rol");
                break;
        case 1: /* ror */
-               emulate_2op_SrcB("ror", ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_SrcB(ctxt, "ror");
                break;
        case 2: /* rcl */
-               emulate_2op_SrcB("rcl", ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_SrcB(ctxt, "rcl");
                break;
        case 3: /* rcr */
-               emulate_2op_SrcB("rcr", ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_SrcB(ctxt, "rcr");
                break;
        case 4: /* sal/shl */
        case 6: /* sal/shl */
-               emulate_2op_SrcB("sal", ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_SrcB(ctxt, "sal");
                break;
        case 5: /* shr */
-               emulate_2op_SrcB("shr", ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_SrcB(ctxt, "shr");
                break;
        case 7: /* sar */
-               emulate_2op_SrcB("sar", ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_SrcB(ctxt, "sar");
                break;
        }
        return X86EMUL_CONTINUE;
 }
 
-static int em_grp3(struct x86_emulate_ctxt *ctxt)
+static int em_not(struct x86_emulate_ctxt *ctxt)
+{
+       ctxt->dst.val = ~ctxt->dst.val;
+       return X86EMUL_CONTINUE;
+}
+
+static int em_neg(struct x86_emulate_ctxt *ctxt)
+{
+       emulate_1op(ctxt, "neg");
+       return X86EMUL_CONTINUE;
+}
+
+static int em_mul_ex(struct x86_emulate_ctxt *ctxt)
+{
+       u8 ex = 0;
+
+       emulate_1op_rax_rdx(ctxt, "mul", ex);
+       return X86EMUL_CONTINUE;
+}
+
+static int em_imul_ex(struct x86_emulate_ctxt *ctxt)
+{
+       u8 ex = 0;
+
+       emulate_1op_rax_rdx(ctxt, "imul", ex);
+       return X86EMUL_CONTINUE;
+}
+
+static int em_div_ex(struct x86_emulate_ctxt *ctxt)
 {
-       unsigned long *rax = &ctxt->regs[VCPU_REGS_RAX];
-       unsigned long *rdx = &ctxt->regs[VCPU_REGS_RDX];
        u8 de = 0;
 
-       switch (ctxt->modrm_reg) {
-       case 0 ... 1:   /* test */
-               emulate_2op_SrcV("test", ctxt->src, ctxt->dst, ctxt->eflags);
-               break;
-       case 2: /* not */
-               ctxt->dst.val = ~ctxt->dst.val;
-               break;
-       case 3: /* neg */
-               emulate_1op("neg", ctxt->dst, ctxt->eflags);
-               break;
-       case 4: /* mul */
-               emulate_1op_rax_rdx("mul", ctxt->src, *rax, *rdx, ctxt->eflags);
-               break;
-       case 5: /* imul */
-               emulate_1op_rax_rdx("imul", ctxt->src, *rax, *rdx, ctxt->eflags);
-               break;
-       case 6: /* div */
-               emulate_1op_rax_rdx_ex("div", ctxt->src, *rax, *rdx,
-                                      ctxt->eflags, de);
-               break;
-       case 7: /* idiv */
-               emulate_1op_rax_rdx_ex("idiv", ctxt->src, *rax, *rdx,
-                                      ctxt->eflags, de);
-               break;
-       default:
-               return X86EMUL_UNHANDLEABLE;
-       }
+       emulate_1op_rax_rdx(ctxt, "div", de);
+       if (de)
+               return emulate_de(ctxt);
+       return X86EMUL_CONTINUE;
+}
+
+static int em_idiv_ex(struct x86_emulate_ctxt *ctxt)
+{
+       u8 de = 0;
+
+       emulate_1op_rax_rdx(ctxt, "idiv", de);
        if (de)
                return emulate_de(ctxt);
        return X86EMUL_CONTINUE;
@@ -1743,10 +1762,10 @@ static int em_grp45(struct x86_emulate_ctxt *ctxt)
 
        switch (ctxt->modrm_reg) {
        case 0: /* inc */
-               emulate_1op("inc", ctxt->dst, ctxt->eflags);
+               emulate_1op(ctxt, "inc");
                break;
        case 1: /* dec */
-               emulate_1op("dec", ctxt->dst, ctxt->eflags);
+               emulate_1op(ctxt, "dec");
                break;
        case 2: /* call near abs */ {
                long int old_eip;
@@ -1812,8 +1831,9 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt)
        return rc;
 }
 
-static int emulate_load_segment(struct x86_emulate_ctxt *ctxt, int seg)
+static int em_lseg(struct x86_emulate_ctxt *ctxt)
 {
+       int seg = ctxt->src2.val;
        unsigned short sel;
        int rc;
 
@@ -2452,7 +2472,7 @@ static int em_das(struct x86_emulate_ctxt *ctxt)
        ctxt->src.type = OP_IMM;
        ctxt->src.val = 0;
        ctxt->src.bytes = 1;
-       emulate_2op_SrcV("or", ctxt->src, ctxt->dst, ctxt->eflags);
+       emulate_2op_SrcV(ctxt, "or");
        ctxt->eflags &= ~(X86_EFLAGS_AF | X86_EFLAGS_CF);
        if (cf)
                ctxt->eflags |= X86_EFLAGS_CF;
@@ -2502,49 +2522,49 @@ static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt)
 
 static int em_add(struct x86_emulate_ctxt *ctxt)
 {
-       emulate_2op_SrcV("add", ctxt->src, ctxt->dst, ctxt->eflags);
+       emulate_2op_SrcV(ctxt, "add");
        return X86EMUL_CONTINUE;
 }
 
 static int em_or(struct x86_emulate_ctxt *ctxt)
 {
-       emulate_2op_SrcV("or", ctxt->src, ctxt->dst, ctxt->eflags);
+       emulate_2op_SrcV(ctxt, "or");
        return X86EMUL_CONTINUE;
 }
 
 static int em_adc(struct x86_emulate_ctxt *ctxt)
 {
-       emulate_2op_SrcV("adc", ctxt->src, ctxt->dst, ctxt->eflags);
+       emulate_2op_SrcV(ctxt, "adc");
        return X86EMUL_CONTINUE;
 }
 
 static int em_sbb(struct x86_emulate_ctxt *ctxt)
 {
-       emulate_2op_SrcV("sbb", ctxt->src, ctxt->dst, ctxt->eflags);
+       emulate_2op_SrcV(ctxt, "sbb");
        return X86EMUL_CONTINUE;
 }
 
 static int em_and(struct x86_emulate_ctxt *ctxt)
 {
-       emulate_2op_SrcV("and", ctxt->src, ctxt->dst, ctxt->eflags);
+       emulate_2op_SrcV(ctxt, "and");
        return X86EMUL_CONTINUE;
 }
 
 static int em_sub(struct x86_emulate_ctxt *ctxt)
 {
-       emulate_2op_SrcV("sub", ctxt->src, ctxt->dst, ctxt->eflags);
+       emulate_2op_SrcV(ctxt, "sub");
        return X86EMUL_CONTINUE;
 }
 
 static int em_xor(struct x86_emulate_ctxt *ctxt)
 {
-       emulate_2op_SrcV("xor", ctxt->src, ctxt->dst, ctxt->eflags);
+       emulate_2op_SrcV(ctxt, "xor");
        return X86EMUL_CONTINUE;
 }
 
 static int em_cmp(struct x86_emulate_ctxt *ctxt)
 {
-       emulate_2op_SrcV("cmp", ctxt->src, ctxt->dst, ctxt->eflags);
+       emulate_2op_SrcV(ctxt, "cmp");
        /* Disable writeback. */
        ctxt->dst.type = OP_NONE;
        return X86EMUL_CONTINUE;
@@ -2552,7 +2572,9 @@ static int em_cmp(struct x86_emulate_ctxt *ctxt)
 
 static int em_test(struct x86_emulate_ctxt *ctxt)
 {
-       emulate_2op_SrcV("test", ctxt->src, ctxt->dst, ctxt->eflags);
+       emulate_2op_SrcV(ctxt, "test");
+       /* Disable writeback. */
+       ctxt->dst.type = OP_NONE;
        return X86EMUL_CONTINUE;
 }
 
@@ -2570,7 +2592,7 @@ static int em_xchg(struct x86_emulate_ctxt *ctxt)
 
 static int em_imul(struct x86_emulate_ctxt *ctxt)
 {
-       emulate_2op_SrcV_nobyte("imul", ctxt->src, ctxt->dst, ctxt->eflags);
+       emulate_2op_SrcV_nobyte(ctxt, "imul");
        return X86EMUL_CONTINUE;
 }
 
@@ -3025,9 +3047,14 @@ static struct opcode group1A[] = {
 };
 
 static struct opcode group3[] = {
-       D(DstMem | SrcImm | ModRM), D(DstMem | SrcImm | ModRM),
-       D(DstMem | SrcNone | ModRM | Lock), D(DstMem | SrcNone | ModRM | Lock),
-       X4(D(SrcMem | ModRM)),
+       I(DstMem | SrcImm | ModRM, em_test),
+       I(DstMem | SrcImm | ModRM, em_test),
+       I(DstMem | SrcNone | ModRM | Lock, em_not),
+       I(DstMem | SrcNone | ModRM | Lock, em_neg),
+       I(SrcMem | ModRM, em_mul_ex),
+       I(SrcMem | ModRM, em_imul_ex),
+       I(SrcMem | ModRM, em_div_ex),
+       I(SrcMem | ModRM, em_idiv_ex),
 };
 
 static struct opcode group4[] = {
@@ -3090,16 +3117,20 @@ static struct gprefix pfx_0f_6f_0f_7f = {
 static struct opcode opcode_table[256] = {
        /* 0x00 - 0x07 */
        I6ALU(Lock, em_add),
-       D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
+       I(ImplicitOps | Stack | No64 | Src2ES, em_push_sreg),
+       I(ImplicitOps | Stack | No64 | Src2ES, em_pop_sreg),
        /* 0x08 - 0x0F */
        I6ALU(Lock, em_or),
-       D(ImplicitOps | Stack | No64), N,
+       I(ImplicitOps | Stack | No64 | Src2CS, em_push_sreg),
+       N,
        /* 0x10 - 0x17 */
        I6ALU(Lock, em_adc),
-       D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
+       I(ImplicitOps | Stack | No64 | Src2SS, em_push_sreg),
+       I(ImplicitOps | Stack | No64 | Src2SS, em_pop_sreg),
        /* 0x18 - 0x1F */
        I6ALU(Lock, em_sbb),
-       D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
+       I(ImplicitOps | Stack | No64 | Src2DS, em_push_sreg),
+       I(ImplicitOps | Stack | No64 | Src2DS, em_pop_sreg),
        /* 0x20 - 0x27 */
        I6ALU(Lock, em_and), N, N,
        /* 0x28 - 0x2F */
@@ -3167,7 +3198,8 @@ static struct opcode opcode_table[256] = {
        D2bv(DstMem | SrcImmByte | ModRM),
        I(ImplicitOps | Stack | SrcImmU16, em_ret_near_imm),
        I(ImplicitOps | Stack, em_ret),
-       D(DstReg | SrcMemFAddr | ModRM | No64), D(DstReg | SrcMemFAddr | ModRM | No64),
+       I(DstReg | SrcMemFAddr | ModRM | No64 | Src2ES, em_lseg),
+       I(DstReg | SrcMemFAddr | ModRM | No64 | Src2DS, em_lseg),
        G(ByteOp, group11), G(0, group11),
        /* 0xC8 - 0xCF */
        N, N, N, I(ImplicitOps | Stack, em_ret_far),
@@ -3242,20 +3274,22 @@ static struct opcode twobyte_table[256] = {
        /* 0x90 - 0x9F */
        X16(D(ByteOp | DstMem | SrcNone | ModRM| Mov)),
        /* 0xA0 - 0xA7 */
-       D(ImplicitOps | Stack), D(ImplicitOps | Stack),
+       I(Stack | Src2FS, em_push_sreg), I(Stack | Src2FS, em_pop_sreg),
        DI(ImplicitOps, cpuid), D(DstMem | SrcReg | ModRM | BitOp),
        D(DstMem | SrcReg | Src2ImmByte | ModRM),
        D(DstMem | SrcReg | Src2CL | ModRM), N, N,
        /* 0xA8 - 0xAF */
-       D(ImplicitOps | Stack), D(ImplicitOps | Stack),
+       I(Stack | Src2GS, em_push_sreg), I(Stack | Src2GS, em_pop_sreg),
        DI(ImplicitOps, rsm), D(DstMem | SrcReg | ModRM | BitOp | Lock),
        D(DstMem | SrcReg | Src2ImmByte | ModRM),
        D(DstMem | SrcReg | Src2CL | ModRM),
        D(ModRM), I(DstReg | SrcMem | ModRM, em_imul),
        /* 0xB0 - 0xB7 */
        D2bv(DstMem | SrcReg | ModRM | Lock),
-       D(DstReg | SrcMemFAddr | ModRM), D(DstMem | SrcReg | ModRM | BitOp | Lock),
-       D(DstReg | SrcMemFAddr | ModRM), D(DstReg | SrcMemFAddr | ModRM),
+       I(DstReg | SrcMemFAddr | ModRM | Src2SS, em_lseg),
+       D(DstMem | SrcReg | ModRM | BitOp | Lock),
+       I(DstReg | SrcMemFAddr | ModRM | Src2FS, em_lseg),
+       I(DstReg | SrcMemFAddr | ModRM | Src2GS, em_lseg),
        D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
        /* 0xB8 - 0xBF */
        N, N,
@@ -3309,13 +3343,13 @@ static int decode_imm(struct x86_emulate_ctxt *ctxt, struct operand *op,
        /* NB. Immediates are sign-extended as necessary. */
        switch (op->bytes) {
        case 1:
-               op->val = insn_fetch(s8, 1, ctxt->_eip);
+               op->val = insn_fetch(s8, ctxt);
                break;
        case 2:
-               op->val = insn_fetch(s16, 2, ctxt->_eip);
+               op->val = insn_fetch(s16, ctxt);
                break;
        case 4:
-               op->val = insn_fetch(s32, 4, ctxt->_eip);
+               op->val = insn_fetch(s32, ctxt);
                break;
        }
        if (!sign_extension) {
@@ -3335,6 +3369,125 @@ done:
        return rc;
 }
 
+static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op,
+                         unsigned d)
+{
+       int rc = X86EMUL_CONTINUE;
+
+       switch (d) {
+       case OpReg:
+               decode_register_operand(ctxt, op,
+                        op == &ctxt->dst &&
+                        ctxt->twobyte && (ctxt->b == 0xb6 || ctxt->b == 0xb7));
+               break;
+       case OpImmUByte:
+               rc = decode_imm(ctxt, op, 1, false);
+               break;
+       case OpMem:
+               ctxt->memop.bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes;
+       mem_common:
+               *op = ctxt->memop;
+               ctxt->memopp = op;
+               if ((ctxt->d & BitOp) && op == &ctxt->dst)
+                       fetch_bit_operand(ctxt);
+               op->orig_val = op->val;
+               break;
+       case OpMem64:
+               ctxt->memop.bytes = 8;
+               goto mem_common;
+       case OpAcc:
+               op->type = OP_REG;
+               op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes;
+               op->addr.reg = &ctxt->regs[VCPU_REGS_RAX];
+               fetch_register_operand(op);
+               op->orig_val = op->val;
+               break;
+       case OpDI:
+               op->type = OP_MEM;
+               op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes;
+               op->addr.mem.ea =
+                       register_address(ctxt, ctxt->regs[VCPU_REGS_RDI]);
+               op->addr.mem.seg = VCPU_SREG_ES;
+               op->val = 0;
+               break;
+       case OpDX:
+               op->type = OP_REG;
+               op->bytes = 2;
+               op->addr.reg = &ctxt->regs[VCPU_REGS_RDX];
+               fetch_register_operand(op);
+               break;
+       case OpCL:
+               op->bytes = 1;
+               op->val = ctxt->regs[VCPU_REGS_RCX] & 0xff;
+               break;
+       case OpImmByte:
+               rc = decode_imm(ctxt, op, 1, true);
+               break;
+       case OpOne:
+               op->bytes = 1;
+               op->val = 1;
+               break;
+       case OpImm:
+               rc = decode_imm(ctxt, op, imm_size(ctxt), true);
+               break;
+       case OpMem16:
+               ctxt->memop.bytes = 2;
+               goto mem_common;
+       case OpMem32:
+               ctxt->memop.bytes = 4;
+               goto mem_common;
+       case OpImmU16:
+               rc = decode_imm(ctxt, op, 2, false);
+               break;
+       case OpImmU:
+               rc = decode_imm(ctxt, op, imm_size(ctxt), false);
+               break;
+       case OpSI:
+               op->type = OP_MEM;
+               op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes;
+               op->addr.mem.ea =
+                       register_address(ctxt, ctxt->regs[VCPU_REGS_RSI]);
+               op->addr.mem.seg = seg_override(ctxt);
+               op->val = 0;
+               break;
+       case OpImmFAddr:
+               op->type = OP_IMM;
+               op->addr.mem.ea = ctxt->_eip;
+               op->bytes = ctxt->op_bytes + 2;
+               insn_fetch_arr(op->valptr, op->bytes, ctxt);
+               break;
+       case OpMemFAddr:
+               ctxt->memop.bytes = ctxt->op_bytes + 2;
+               goto mem_common;
+       case OpES:
+               op->val = VCPU_SREG_ES;
+               break;
+       case OpCS:
+               op->val = VCPU_SREG_CS;
+               break;
+       case OpSS:
+               op->val = VCPU_SREG_SS;
+               break;
+       case OpDS:
+               op->val = VCPU_SREG_DS;
+               break;
+       case OpFS:
+               op->val = VCPU_SREG_FS;
+               break;
+       case OpGS:
+               op->val = VCPU_SREG_GS;
+               break;
+       case OpImplicit:
+               /* Special instructions do their own operand decoding. */
+       default:
+               op->type = OP_NONE; /* Disable writeback. */
+               break;
+       }
+
+done:
+       return rc;
+}
+
 int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
 {
        int rc = X86EMUL_CONTINUE;
@@ -3342,8 +3495,9 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
        int def_op_bytes, def_ad_bytes, goffset, simd_prefix;
        bool op_prefix = false;
        struct opcode opcode;
-       struct operand memop = { .type = OP_NONE }, *memopp = NULL;
 
+       ctxt->memop.type = OP_NONE;
+       ctxt->memopp = NULL;
        ctxt->_eip = ctxt->eip;
        ctxt->fetch.start = ctxt->_eip;
        ctxt->fetch.end = ctxt->fetch.start + insn_len;
@@ -3366,7 +3520,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
                break;
 #endif
        default:
-               return -1;
+               return EMULATION_FAILED;
        }
 
        ctxt->op_bytes = def_op_bytes;
@@ -3374,7 +3528,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
 
        /* Legacy prefixes. */
        for (;;) {
-               switch (ctxt->b = insn_fetch(u8, 1, ctxt->_eip)) {
+               switch (ctxt->b = insn_fetch(u8, ctxt)) {
                case 0x66:      /* operand-size override */
                        op_prefix = true;
                        /* switch between 2/4 bytes */
@@ -3430,7 +3584,7 @@ done_prefixes:
        /* Two-byte opcode? */
        if (ctxt->b == 0x0f) {
                ctxt->twobyte = 1;
-               ctxt->b = insn_fetch(u8, 1, ctxt->_eip);
+               ctxt->b = insn_fetch(u8, ctxt);
                opcode = twobyte_table[ctxt->b];
        }
        ctxt->d = opcode.flags;
@@ -3438,13 +3592,13 @@ done_prefixes:
        while (ctxt->d & GroupMask) {
                switch (ctxt->d & GroupMask) {
                case Group:
-                       ctxt->modrm = insn_fetch(u8, 1, ctxt->_eip);
+                       ctxt->modrm = insn_fetch(u8, ctxt);
                        --ctxt->_eip;
                        goffset = (ctxt->modrm >> 3) & 7;
                        opcode = opcode.u.group[goffset];
                        break;
                case GroupDual:
-                       ctxt->modrm = insn_fetch(u8, 1, ctxt->_eip);
+                       ctxt->modrm = insn_fetch(u8, ctxt);
                        --ctxt->_eip;
                        goffset = (ctxt->modrm >> 3) & 7;
                        if ((ctxt->modrm >> 6) == 3)
@@ -3458,7 +3612,7 @@ done_prefixes:
                        break;
                case Prefix:
                        if (ctxt->rep_prefix && op_prefix)
-                               return X86EMUL_UNHANDLEABLE;
+                               return EMULATION_FAILED;
                        simd_prefix = op_prefix ? 0x66 : ctxt->rep_prefix;
                        switch (simd_prefix) {
                        case 0x00: opcode = opcode.u.gprefix->pfx_no; break;
@@ -3468,10 +3622,10 @@ done_prefixes:
                        }
                        break;
                default:
-                       return X86EMUL_UNHANDLEABLE;
+                       return EMULATION_FAILED;
                }
 
-               ctxt->d &= ~GroupMask;
+               ctxt->d &= ~(u64)GroupMask;
                ctxt->d |= opcode.flags;
        }
 
@@ -3481,10 +3635,10 @@ done_prefixes:
 
        /* Unrecognised? */
        if (ctxt->d == 0 || (ctxt->d & Undefined))
-               return -1;
+               return EMULATION_FAILED;
 
        if (!(ctxt->d & VendorSpecific) && ctxt->only_vendor_specific_insn)
-               return -1;
+               return EMULATION_FAILED;
 
        if (mode == X86EMUL_MODE_PROT64 && (ctxt->d & Stack))
                ctxt->op_bytes = 8;
@@ -3501,96 +3655,27 @@ done_prefixes:
 
        /* ModRM and SIB bytes. */
        if (ctxt->d & ModRM) {
-               rc = decode_modrm(ctxt, &memop);
+               rc = decode_modrm(ctxt, &ctxt->memop);
                if (!ctxt->has_seg_override)
                        set_seg_override(ctxt, ctxt->modrm_seg);
        } else if (ctxt->d & MemAbs)
-               rc = decode_abs(ctxt, &memop);
+               rc = decode_abs(ctxt, &ctxt->memop);
        if (rc != X86EMUL_CONTINUE)
                goto done;
 
        if (!ctxt->has_seg_override)
                set_seg_override(ctxt, VCPU_SREG_DS);
 
-       memop.addr.mem.seg = seg_override(ctxt);
+       ctxt->memop.addr.mem.seg = seg_override(ctxt);
 
-       if (memop.type == OP_MEM && ctxt->ad_bytes != 8)
-               memop.addr.mem.ea = (u32)memop.addr.mem.ea;
+       if (ctxt->memop.type == OP_MEM && ctxt->ad_bytes != 8)
+               ctxt->memop.addr.mem.ea = (u32)ctxt->memop.addr.mem.ea;
 
        /*
         * Decode and fetch the source operand: register, memory
         * or immediate.
         */
-       switch (ctxt->d & SrcMask) {
-       case SrcNone:
-               break;
-       case SrcReg:
-               decode_register_operand(ctxt, &ctxt->src, 0);
-               break;
-       case SrcMem16:
-               memop.bytes = 2;
-               goto srcmem_common;
-       case SrcMem32:
-               memop.bytes = 4;
-               goto srcmem_common;
-       case SrcMem:
-               memop.bytes = (ctxt->d & ByteOp) ? 1 :
-                                                          ctxt->op_bytes;
-       srcmem_common:
-               ctxt->src = memop;
-               memopp = &ctxt->src;
-               break;
-       case SrcImmU16:
-               rc = decode_imm(ctxt, &ctxt->src, 2, false);
-               break;
-       case SrcImm:
-               rc = decode_imm(ctxt, &ctxt->src, imm_size(ctxt), true);
-               break;
-       case SrcImmU:
-               rc = decode_imm(ctxt, &ctxt->src, imm_size(ctxt), false);
-               break;
-       case SrcImmByte:
-               rc = decode_imm(ctxt, &ctxt->src, 1, true);
-               break;
-       case SrcImmUByte:
-               rc = decode_imm(ctxt, &ctxt->src, 1, false);
-               break;
-       case SrcAcc:
-               ctxt->src.type = OP_REG;
-               ctxt->src.bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes;
-               ctxt->src.addr.reg = &ctxt->regs[VCPU_REGS_RAX];
-               fetch_register_operand(&ctxt->src);
-               break;
-       case SrcOne:
-               ctxt->src.bytes = 1;
-               ctxt->src.val = 1;
-               break;
-       case SrcSI:
-               ctxt->src.type = OP_MEM;
-               ctxt->src.bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes;
-               ctxt->src.addr.mem.ea =
-                       register_address(ctxt, ctxt->regs[VCPU_REGS_RSI]);
-               ctxt->src.addr.mem.seg = seg_override(ctxt);
-               ctxt->src.val = 0;
-               break;
-       case SrcImmFAddr:
-               ctxt->src.type = OP_IMM;
-               ctxt->src.addr.mem.ea = ctxt->_eip;
-               ctxt->src.bytes = ctxt->op_bytes + 2;
-               insn_fetch_arr(ctxt->src.valptr, ctxt->src.bytes, ctxt->_eip);
-               break;
-       case SrcMemFAddr:
-               memop.bytes = ctxt->op_bytes + 2;
-               goto srcmem_common;
-               break;
-       case SrcDX:
-               ctxt->src.type = OP_REG;
-               ctxt->src.bytes = 2;
-               ctxt->src.addr.reg = &ctxt->regs[VCPU_REGS_RDX];
-               fetch_register_operand(&ctxt->src);
-               break;
-       }
-
+       rc = decode_operand(ctxt, &ctxt->src, (ctxt->d >> SrcShift) & OpMask);
        if (rc != X86EMUL_CONTINUE)
                goto done;
 
@@ -3598,85 +3683,18 @@ done_prefixes:
         * Decode and fetch the second source operand: register, memory
         * or immediate.
         */
-       switch (ctxt->d & Src2Mask) {
-       case Src2None:
-               break;
-       case Src2CL:
-               ctxt->src2.bytes = 1;
-               ctxt->src2.val = ctxt->regs[VCPU_REGS_RCX] & 0xff;
-               break;
-       case Src2ImmByte:
-               rc = decode_imm(ctxt, &ctxt->src2, 1, true);
-               break;
-       case Src2One:
-               ctxt->src2.bytes = 1;
-               ctxt->src2.val = 1;
-               break;
-       case Src2Imm:
-               rc = decode_imm(ctxt, &ctxt->src2, imm_size(ctxt), true);
-               break;
-       }
-
+       rc = decode_operand(ctxt, &ctxt->src2, (ctxt->d >> Src2Shift) & OpMask);
        if (rc != X86EMUL_CONTINUE)
                goto done;
 
        /* Decode and fetch the destination operand: register or memory. */
-       switch (ctxt->d & DstMask) {
-       case DstReg:
-               decode_register_operand(ctxt, &ctxt->dst,
-                        ctxt->twobyte && (ctxt->b == 0xb6 || ctxt->b == 0xb7));
-               break;
-       case DstImmUByte:
-               ctxt->dst.type = OP_IMM;
-               ctxt->dst.addr.mem.ea = ctxt->_eip;
-               ctxt->dst.bytes = 1;
-               ctxt->dst.val = insn_fetch(u8, 1, ctxt->_eip);
-               break;
-       case DstMem:
-       case DstMem64:
-               ctxt->dst = memop;
-               memopp = &ctxt->dst;
-               if ((ctxt->d & DstMask) == DstMem64)
-                       ctxt->dst.bytes = 8;
-               else
-                       ctxt->dst.bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes;
-               if (ctxt->d & BitOp)
-                       fetch_bit_operand(ctxt);
-               ctxt->dst.orig_val = ctxt->dst.val;
-               break;
-       case DstAcc:
-               ctxt->dst.type = OP_REG;
-               ctxt->dst.bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes;
-               ctxt->dst.addr.reg = &ctxt->regs[VCPU_REGS_RAX];
-               fetch_register_operand(&ctxt->dst);
-               ctxt->dst.orig_val = ctxt->dst.val;
-               break;
-       case DstDI:
-               ctxt->dst.type = OP_MEM;
-               ctxt->dst.bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes;
-               ctxt->dst.addr.mem.ea =
-                       register_address(ctxt, ctxt->regs[VCPU_REGS_RDI]);
-               ctxt->dst.addr.mem.seg = VCPU_SREG_ES;
-               ctxt->dst.val = 0;
-               break;
-       case DstDX:
-               ctxt->dst.type = OP_REG;
-               ctxt->dst.bytes = 2;
-               ctxt->dst.addr.reg = &ctxt->regs[VCPU_REGS_RDX];
-               fetch_register_operand(&ctxt->dst);
-               break;
-       case ImplicitOps:
-               /* Special instructions do their own operand decoding. */
-       default:
-               ctxt->dst.type = OP_NONE; /* Disable writeback. */
-               break;
-       }
+       rc = decode_operand(ctxt, &ctxt->dst, (ctxt->d >> DstShift) & OpMask);
 
 done:
-       if (memopp && memopp->type == OP_MEM && ctxt->rip_relative)
-               memopp->addr.mem.ea += ctxt->_eip;
+       if (ctxt->memopp && ctxt->memopp->type == OP_MEM && ctxt->rip_relative)
+               ctxt->memopp->addr.mem.ea += ctxt->_eip;
 
-       return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK;
+       return (rc != X86EMUL_CONTINUE) ? EMULATION_FAILED : EMULATION_OK;
 }
 
 static bool string_insn_completed(struct x86_emulate_ctxt *ctxt)
@@ -3825,32 +3843,11 @@ special_insn:
                goto twobyte_insn;
 
        switch (ctxt->b) {
-       case 0x06:              /* push es */
-               rc = emulate_push_sreg(ctxt, VCPU_SREG_ES);
-               break;
-       case 0x07:              /* pop es */
-               rc = emulate_pop_sreg(ctxt, VCPU_SREG_ES);
-               break;
-       case 0x0e:              /* push cs */
-               rc = emulate_push_sreg(ctxt, VCPU_SREG_CS);
-               break;
-       case 0x16:              /* push ss */
-               rc = emulate_push_sreg(ctxt, VCPU_SREG_SS);
-               break;
-       case 0x17:              /* pop ss */
-               rc = emulate_pop_sreg(ctxt, VCPU_SREG_SS);
-               break;
-       case 0x1e:              /* push ds */
-               rc = emulate_push_sreg(ctxt, VCPU_SREG_DS);
-               break;
-       case 0x1f:              /* pop ds */
-               rc = emulate_pop_sreg(ctxt, VCPU_SREG_DS);
-               break;
        case 0x40 ... 0x47: /* inc r16/r32 */
-               emulate_1op("inc", ctxt->dst, ctxt->eflags);
+               emulate_1op(ctxt, "inc");
                break;
        case 0x48 ... 0x4f: /* dec r16/r32 */
-               emulate_1op("dec", ctxt->dst, ctxt->eflags);
+               emulate_1op(ctxt, "dec");
                break;
        case 0x63:              /* movsxd */
                if (ctxt->mode != X86EMUL_MODE_PROT64)
@@ -3891,12 +3888,6 @@ special_insn:
        case 0xc0 ... 0xc1:
                rc = em_grp2(ctxt);
                break;
-       case 0xc4:              /* les */
-               rc = emulate_load_segment(ctxt, VCPU_SREG_ES);
-               break;
-       case 0xc5:              /* lds */
-               rc = emulate_load_segment(ctxt, VCPU_SREG_DS);
-               break;
        case 0xcc:              /* int3 */
                rc = emulate_int(ctxt, 3);
                break;
@@ -3953,9 +3944,6 @@ special_insn:
                /* complement carry flag from eflags reg */
                ctxt->eflags ^= EFLG_CF;
                break;
-       case 0xf6 ... 0xf7:     /* Grp3 */
-               rc = em_grp3(ctxt);
-               break;
        case 0xf8: /* clc */
                ctxt->eflags &= ~EFLG_CF;
                break;
@@ -4103,36 +4091,24 @@ twobyte_insn:
        case 0x90 ... 0x9f:     /* setcc r/m8 */
                ctxt->dst.val = test_cc(ctxt->b, ctxt->eflags);
                break;
-       case 0xa0:        /* push fs */
-               rc = emulate_push_sreg(ctxt, VCPU_SREG_FS);
-               break;
-       case 0xa1:       /* pop fs */
-               rc = emulate_pop_sreg(ctxt, VCPU_SREG_FS);
-               break;
        case 0xa3:
              bt:               /* bt */
                ctxt->dst.type = OP_NONE;
                /* only subword offset */
                ctxt->src.val &= (ctxt->dst.bytes << 3) - 1;
-               emulate_2op_SrcV_nobyte("bt", ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_SrcV_nobyte(ctxt, "bt");
                break;
        case 0xa4: /* shld imm8, r, r/m */
        case 0xa5: /* shld cl, r, r/m */
-               emulate_2op_cl("shld", ctxt->src2, ctxt->src, ctxt->dst, ctxt->eflags);
-               break;
-       case 0xa8:      /* push gs */
-               rc = emulate_push_sreg(ctxt, VCPU_SREG_GS);
-               break;
-       case 0xa9:      /* pop gs */
-               rc = emulate_pop_sreg(ctxt, VCPU_SREG_GS);
+               emulate_2op_cl(ctxt, "shld");
                break;
        case 0xab:
              bts:              /* bts */
-               emulate_2op_SrcV_nobyte("bts", ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_SrcV_nobyte(ctxt, "bts");
                break;
        case 0xac: /* shrd imm8, r, r/m */
        case 0xad: /* shrd cl, r, r/m */
-               emulate_2op_cl("shrd", ctxt->src2, ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_cl(ctxt, "shrd");
                break;
        case 0xae:              /* clflush */
                break;
@@ -4143,7 +4119,7 @@ twobyte_insn:
                 */
                ctxt->src.orig_val = ctxt->src.val;
                ctxt->src.val = ctxt->regs[VCPU_REGS_RAX];
-               emulate_2op_SrcV("cmp", ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_SrcV(ctxt, "cmp");
                if (ctxt->eflags & EFLG_ZF) {
                        /* Success: write back to memory. */
                        ctxt->dst.val = ctxt->src.orig_val;
@@ -4153,18 +4129,9 @@ twobyte_insn:
                        ctxt->dst.addr.reg = (unsigned long *)&ctxt->regs[VCPU_REGS_RAX];
                }
                break;
-       case 0xb2:              /* lss */
-               rc = emulate_load_segment(ctxt, VCPU_SREG_SS);
-               break;
        case 0xb3:
              btr:              /* btr */
-               emulate_2op_SrcV_nobyte("btr", ctxt->src, ctxt->dst, ctxt->eflags);
-               break;
-       case 0xb4:              /* lfs */
-               rc = emulate_load_segment(ctxt, VCPU_SREG_FS);
-               break;
-       case 0xb5:              /* lgs */
-               rc = emulate_load_segment(ctxt, VCPU_SREG_GS);
+               emulate_2op_SrcV_nobyte(ctxt, "btr");
                break;
        case 0xb6 ... 0xb7:     /* movzx */
                ctxt->dst.bytes = ctxt->op_bytes;
@@ -4185,7 +4152,7 @@ twobyte_insn:
                break;
        case 0xbb:
              btc:              /* btc */
-               emulate_2op_SrcV_nobyte("btc", ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_SrcV_nobyte(ctxt, "btc");
                break;
        case 0xbc: {            /* bsf */
                u8 zf;
@@ -4217,7 +4184,7 @@ twobyte_insn:
                                                        (s16) ctxt->src.val;
                break;
        case 0xc0 ... 0xc1:     /* xadd */
-               emulate_2op_SrcV("add", ctxt->src, ctxt->dst, ctxt->eflags);
+               emulate_2op_SrcV(ctxt, "add");
                /* Write back the register source. */
                ctxt->src.val = ctxt->dst.orig_val;
                write_register_operand(&ctxt->src);
index efad723..76e3f1c 100644 (file)
@@ -713,14 +713,16 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
        kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
 
        kvm_iodevice_init(&pit->dev, &pit_dev_ops);
-       ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, &pit->dev);
+       ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, KVM_PIT_BASE_ADDRESS,
+                                     KVM_PIT_MEM_LENGTH, &pit->dev);
        if (ret < 0)
                goto fail;
 
        if (flags & KVM_PIT_SPEAKER_DUMMY) {
                kvm_iodevice_init(&pit->speaker_dev, &speaker_dev_ops);
                ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS,
-                                               &pit->speaker_dev);
+                                             KVM_SPEAKER_BASE_ADDRESS, 4,
+                                             &pit->speaker_dev);
                if (ret < 0)
                        goto fail_unregister;
        }
index 19fe855..cac4746 100644 (file)
@@ -34,6 +34,9 @@
 #include <linux/kvm_host.h>
 #include "trace.h"
 
+#define pr_pic_unimpl(fmt, ...)        \
+       pr_err_ratelimited("kvm: pic: " fmt, ## __VA_ARGS__)
+
 static void pic_irq_request(struct kvm *kvm, int level);
 
 static void pic_lock(struct kvm_pic *s)
@@ -306,10 +309,10 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val)
                        }
                        s->init_state = 1;
                        if (val & 0x02)
-                               printk(KERN_ERR "single mode not supported");
+                               pr_pic_unimpl("single mode not supported");
                        if (val & 0x08)
-                               printk(KERN_ERR
-                                      "level sensitive irq not supported");
+                               pr_pic_unimpl(
+                                       "level sensitive irq not supported");
                } else if (val & 0x08) {
                        if (val & 0x04)
                                s->poll = 1;
@@ -459,22 +462,15 @@ static int picdev_in_range(gpa_t addr)
        }
 }
 
-static inline struct kvm_pic *to_pic(struct kvm_io_device *dev)
-{
-       return container_of(dev, struct kvm_pic, dev);
-}
-
-static int picdev_write(struct kvm_io_device *this,
+static int picdev_write(struct kvm_pic *s,
                         gpa_t addr, int len, const void *val)
 {
-       struct kvm_pic *s = to_pic(this);
        unsigned char data = *(unsigned char *)val;
        if (!picdev_in_range(addr))
                return -EOPNOTSUPP;
 
        if (len != 1) {
-               if (printk_ratelimit())
-                       printk(KERN_ERR "PIC: non byte write\n");
+               pr_pic_unimpl("non byte write\n");
                return 0;
        }
        pic_lock(s);
@@ -494,17 +490,15 @@ static int picdev_write(struct kvm_io_device *this,
        return 0;
 }
 
-static int picdev_read(struct kvm_io_device *this,
+static int picdev_read(struct kvm_pic *s,
                       gpa_t addr, int len, void *val)
 {
-       struct kvm_pic *s = to_pic(this);
        unsigned char data = 0;
        if (!picdev_in_range(addr))
                return -EOPNOTSUPP;
 
        if (len != 1) {
-               if (printk_ratelimit())
-                       printk(KERN_ERR "PIC: non byte read\n");
+               pr_pic_unimpl("non byte read\n");
                return 0;
        }
        pic_lock(s);
@@ -525,6 +519,48 @@ static int picdev_read(struct kvm_io_device *this,
        return 0;
 }
 
+static int picdev_master_write(struct kvm_io_device *dev,
+                              gpa_t addr, int len, const void *val)
+{
+       return picdev_write(container_of(dev, struct kvm_pic, dev_master),
+                           addr, len, val);
+}
+
+static int picdev_master_read(struct kvm_io_device *dev,
+                             gpa_t addr, int len, void *val)
+{
+       return picdev_read(container_of(dev, struct kvm_pic, dev_master),
+                           addr, len, val);
+}
+
+static int picdev_slave_write(struct kvm_io_device *dev,
+                             gpa_t addr, int len, const void *val)
+{
+       return picdev_write(container_of(dev, struct kvm_pic, dev_slave),
+                           addr, len, val);
+}
+
+static int picdev_slave_read(struct kvm_io_device *dev,
+                            gpa_t addr, int len, void *val)
+{
+       return picdev_read(container_of(dev, struct kvm_pic, dev_slave),
+                           addr, len, val);
+}
+
+static int picdev_eclr_write(struct kvm_io_device *dev,
+                            gpa_t addr, int len, const void *val)
+{
+       return picdev_write(container_of(dev, struct kvm_pic, dev_eclr),
+                           addr, len, val);
+}
+
+static int picdev_eclr_read(struct kvm_io_device *dev,
+                           gpa_t addr, int len, void *val)
+{
+       return picdev_read(container_of(dev, struct kvm_pic, dev_eclr),
+                           addr, len, val);
+}
+
 /*
  * callback when PIC0 irq status changed
  */
@@ -537,9 +573,19 @@ static void pic_irq_request(struct kvm *kvm, int level)
        s->output = level;
 }
 
-static const struct kvm_io_device_ops picdev_ops = {
-       .read     = picdev_read,
-       .write    = picdev_write,
+static const struct kvm_io_device_ops picdev_master_ops = {
+       .read     = picdev_master_read,
+       .write    = picdev_master_write,
+};
+
+static const struct kvm_io_device_ops picdev_slave_ops = {
+       .read     = picdev_slave_read,
+       .write    = picdev_slave_write,
+};
+
+static const struct kvm_io_device_ops picdev_eclr_ops = {
+       .read     = picdev_eclr_read,
+       .write    = picdev_eclr_write,
 };
 
 struct kvm_pic *kvm_create_pic(struct kvm *kvm)
@@ -560,16 +606,39 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
        /*
         * Initialize PIO device
         */
-       kvm_iodevice_init(&s->dev, &picdev_ops);
+       kvm_iodevice_init(&s->dev_master, &picdev_master_ops);
+       kvm_iodevice_init(&s->dev_slave, &picdev_slave_ops);
+       kvm_iodevice_init(&s->dev_eclr, &picdev_eclr_ops);
        mutex_lock(&kvm->slots_lock);
-       ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, &s->dev);
+       ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x20, 2,
+                                     &s->dev_master);
+       if (ret < 0)
+               goto fail_unlock;
+
+       ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0xa0, 2, &s->dev_slave);
+       if (ret < 0)
+               goto fail_unreg_2;
+
+       ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x4d0, 2, &s->dev_eclr);
+       if (ret < 0)
+               goto fail_unreg_1;
+
        mutex_unlock(&kvm->slots_lock);
-       if (ret < 0) {
-               kfree(s);
-               return NULL;
-       }
 
        return s;
+
+fail_unreg_1:
+       kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &s->dev_slave);
+
+fail_unreg_2:
+       kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &s->dev_master);
+
+fail_unlock:
+       mutex_unlock(&kvm->slots_lock);
+
+       kfree(s);
+
+       return NULL;
 }
 
 void kvm_destroy_pic(struct kvm *kvm)
@@ -577,7 +646,9 @@ void kvm_destroy_pic(struct kvm *kvm)
        struct kvm_pic *vpic = kvm->arch.vpic;
 
        if (vpic) {
-               kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev);
+               kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev_master);
+               kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev_slave);
+               kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev_eclr);
                kvm->arch.vpic = NULL;
                kfree(vpic);
        }
index 53e2d08..2086f2b 100644 (file)
@@ -66,7 +66,9 @@ struct kvm_pic {
        struct kvm *kvm;
        struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */
        int output;             /* intr from master PIC */
-       struct kvm_io_device dev;
+       struct kvm_io_device dev_master;
+       struct kvm_io_device dev_slave;
+       struct kvm_io_device dev_eclr;
        void (*ack_notifier)(void *opaque, int irq);
        unsigned long irq_states[16];
 };
index 3377d53..544076c 100644 (file)
@@ -45,13 +45,6 @@ static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index)
        return vcpu->arch.walk_mmu->pdptrs[index];
 }
 
-static inline u64 kvm_pdptr_read_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, int index)
-{
-       load_pdptrs(vcpu, mmu, mmu->get_cr3(vcpu));
-
-       return mmu->pdptrs[index];
-}
-
 static inline ulong kvm_read_cr0_bits(struct kvm_vcpu *vcpu, ulong mask)
 {
        ulong tmask = mask & KVM_POSSIBLE_CR0_GUEST_BITS;
index 64bc6ea..497dbaa 100644 (file)
@@ -2,6 +2,8 @@
 struct kvm_timer {
        struct hrtimer timer;
        s64 period;                             /* unit: ns */
+       u32 timer_mode_mask;
+       u64 tscdeadline;
        atomic_t pending;                       /* accumulated triggered timers */
        bool reinject;
        struct kvm_timer_ops *t_ops;
index 57dcbd4..54abb40 100644 (file)
@@ -68,6 +68,9 @@
 #define VEC_POS(v) ((v) & (32 - 1))
 #define REG_POS(v) (((v) >> 5) << 4)
 
+static unsigned int min_timer_period_us = 500;
+module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR);
+
 static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off)
 {
        return *((u32 *) (apic->regs + reg_off));
@@ -135,9 +138,23 @@ static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type)
        return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
 }
 
+static inline int apic_lvtt_oneshot(struct kvm_lapic *apic)
+{
+       return ((apic_get_reg(apic, APIC_LVTT) &
+               apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_ONESHOT);
+}
+
 static inline int apic_lvtt_period(struct kvm_lapic *apic)
 {
-       return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC;
+       return ((apic_get_reg(apic, APIC_LVTT) &
+               apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_PERIODIC);
+}
+
+static inline int apic_lvtt_tscdeadline(struct kvm_lapic *apic)
+{
+       return ((apic_get_reg(apic, APIC_LVTT) &
+               apic->lapic_timer.timer_mode_mask) ==
+                       APIC_LVT_TIMER_TSCDEADLINE);
 }
 
 static inline int apic_lvt_nmi_mode(u32 lvt_val)
@@ -166,7 +183,7 @@ static inline int apic_x2apic_mode(struct kvm_lapic *apic)
 }
 
 static unsigned int apic_lvt_mask[APIC_LVT_NUM] = {
-       LVT_MASK | APIC_LVT_TIMER_PERIODIC,     /* LVTT */
+       LVT_MASK ,      /* part LVTT mask, timer mode mask added at runtime */
        LVT_MASK | APIC_MODE_MASK,      /* LVTTHMR */
        LVT_MASK | APIC_MODE_MASK,      /* LVTPC */
        LINT_MASK, LINT_MASK,   /* LVT0-1 */
@@ -316,8 +333,8 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
                        result = 1;
                break;
        default:
-               printk(KERN_WARNING "Bad DFR vcpu %d: %08x\n",
-                      apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR));
+               apic_debug("Bad DFR vcpu %d: %08x\n",
+                          apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR));
                break;
        }
 
@@ -354,8 +371,8 @@ int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
                result = (target != source);
                break;
        default:
-               printk(KERN_WARNING "Bad dest shorthand value %x\n",
-                      short_hand);
+               apic_debug("kvm: apic: Bad dest shorthand value %x\n",
+                          short_hand);
                break;
        }
 
@@ -401,11 +418,11 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                break;
 
        case APIC_DM_REMRD:
-               printk(KERN_DEBUG "Ignoring delivery mode 3\n");
+               apic_debug("Ignoring delivery mode 3\n");
                break;
 
        case APIC_DM_SMI:
-               printk(KERN_DEBUG "Ignoring guest SMI\n");
+               apic_debug("Ignoring guest SMI\n");
                break;
 
        case APIC_DM_NMI:
@@ -565,11 +582,13 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
                        val = kvm_apic_id(apic) << 24;
                break;
        case APIC_ARBPRI:
-               printk(KERN_WARNING "Access APIC ARBPRI register "
-                      "which is for P6\n");
+               apic_debug("Access APIC ARBPRI register which is for P6\n");
                break;
 
        case APIC_TMCCT:        /* Timer CCR */
+               if (apic_lvtt_tscdeadline(apic))
+                       return 0;
+
                val = apic_get_tmcct(apic);
                break;
 
@@ -664,29 +683,40 @@ static void update_divide_count(struct kvm_lapic *apic)
 
 static void start_apic_timer(struct kvm_lapic *apic)
 {
-       ktime_t now = apic->lapic_timer.timer.base->get_time();
-
-       apic->lapic_timer.period = (u64)apic_get_reg(apic, APIC_TMICT) *
-                   APIC_BUS_CYCLE_NS * apic->divide_count;
+       ktime_t now;
        atomic_set(&apic->lapic_timer.pending, 0);
 
-       if (!apic->lapic_timer.period)
-               return;
-       /*
-        * Do not allow the guest to program periodic timers with small
-        * interval, since the hrtimers are not throttled by the host
-        * scheduler.
-        */
-       if (apic_lvtt_period(apic)) {
-               if (apic->lapic_timer.period < NSEC_PER_MSEC/2)
-                       apic->lapic_timer.period = NSEC_PER_MSEC/2;
-       }
+       if (apic_lvtt_period(apic) || apic_lvtt_oneshot(apic)) {
+               /* lapic timer in oneshot or peroidic mode */
+               now = apic->lapic_timer.timer.base->get_time();
+               apic->lapic_timer.period = (u64)apic_get_reg(apic, APIC_TMICT)
+                           * APIC_BUS_CYCLE_NS * apic->divide_count;
+
+               if (!apic->lapic_timer.period)
+                       return;
+               /*
+                * Do not allow the guest to program periodic timers with small
+                * interval, since the hrtimers are not throttled by the host
+                * scheduler.
+                */
+               if (apic_lvtt_period(apic)) {
+                       s64 min_period = min_timer_period_us * 1000LL;
+
+                       if (apic->lapic_timer.period < min_period) {
+                               pr_info_ratelimited(
+                                   "kvm: vcpu %i: requested %lld ns "
+                                   "lapic timer period limited to %lld ns\n",
+                                   apic->vcpu->vcpu_id,
+                                   apic->lapic_timer.period, min_period);
+                               apic->lapic_timer.period = min_period;
+                       }
+               }
 
-       hrtimer_start(&apic->lapic_timer.timer,
-                     ktime_add_ns(now, apic->lapic_timer.period),
-                     HRTIMER_MODE_ABS);
+               hrtimer_start(&apic->lapic_timer.timer,
+                             ktime_add_ns(now, apic->lapic_timer.period),
+                             HRTIMER_MODE_ABS);
 
-       apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
+               apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
                           PRIx64 ", "
                           "timer initial count 0x%x, period %lldns, "
                           "expire @ 0x%016" PRIx64 ".\n", __func__,
@@ -695,6 +725,30 @@ static void start_apic_timer(struct kvm_lapic *apic)
                           apic->lapic_timer.period,
                           ktime_to_ns(ktime_add_ns(now,
                                        apic->lapic_timer.period)));
+       } else if (apic_lvtt_tscdeadline(apic)) {
+               /* lapic timer in tsc deadline mode */
+               u64 guest_tsc, tscdeadline = apic->lapic_timer.tscdeadline;
+               u64 ns = 0;
+               struct kvm_vcpu *vcpu = apic->vcpu;
+               unsigned long this_tsc_khz = vcpu_tsc_khz(vcpu);
+               unsigned long flags;
+
+               if (unlikely(!tscdeadline || !this_tsc_khz))
+                       return;
+
+               local_irq_save(flags);
+
+               now = apic->lapic_timer.timer.base->get_time();
+               guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu);
+               if (likely(tscdeadline > guest_tsc)) {
+                       ns = (tscdeadline - guest_tsc) * 1000000ULL;
+                       do_div(ns, this_tsc_khz);
+               }
+               hrtimer_start(&apic->lapic_timer.timer,
+                       ktime_add_ns(now, ns), HRTIMER_MODE_ABS);
+
+               local_irq_restore(flags);
+       }
 }
 
 static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val)
@@ -782,7 +836,6 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 
        case APIC_LVT0:
                apic_manage_nmi_watchdog(apic, val);
-       case APIC_LVTT:
        case APIC_LVTTHMR:
        case APIC_LVTPC:
        case APIC_LVT1:
@@ -796,7 +849,22 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 
                break;
 
+       case APIC_LVTT:
+               if ((apic_get_reg(apic, APIC_LVTT) &
+                   apic->lapic_timer.timer_mode_mask) !=
+                  (val & apic->lapic_timer.timer_mode_mask))
+                       hrtimer_cancel(&apic->lapic_timer.timer);
+
+               if (!apic_sw_enabled(apic))
+                       val |= APIC_LVT_MASKED;
+               val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask);
+               apic_set_reg(apic, APIC_LVTT, val);
+               break;
+
        case APIC_TMICT:
+               if (apic_lvtt_tscdeadline(apic))
+                       break;
+
                hrtimer_cancel(&apic->lapic_timer.timer);
                apic_set_reg(apic, APIC_TMICT, val);
                start_apic_timer(apic);
@@ -804,14 +872,14 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 
        case APIC_TDCR:
                if (val & 4)
-                       printk(KERN_ERR "KVM_WRITE:TDCR %x\n", val);
+                       apic_debug("KVM_WRITE:TDCR %x\n", val);
                apic_set_reg(apic, APIC_TDCR, val);
                update_divide_count(apic);
                break;
 
        case APIC_ESR:
                if (apic_x2apic_mode(apic) && val != 0) {
-                       printk(KERN_ERR "KVM_WRITE:ESR not zero %x\n", val);
+                       apic_debug("KVM_WRITE:ESR not zero %x\n", val);
                        ret = 1;
                }
                break;
@@ -864,6 +932,15 @@ static int apic_mmio_write(struct kvm_io_device *this,
        return 0;
 }
 
+void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+
+       if (apic)
+               apic_reg_write(vcpu->arch.apic, APIC_EOI, 0);
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi);
+
 void kvm_free_lapic(struct kvm_vcpu *vcpu)
 {
        if (!vcpu->arch.apic)
@@ -883,6 +960,32 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu)
  *----------------------------------------------------------------------
  */
 
+u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+       if (!apic)
+               return 0;
+
+       if (apic_lvtt_oneshot(apic) || apic_lvtt_period(apic))
+               return 0;
+
+       return apic->lapic_timer.tscdeadline;
+}
+
+void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+       if (!apic)
+               return;
+
+       if (apic_lvtt_oneshot(apic) || apic_lvtt_period(apic))
+               return;
+
+       hrtimer_cancel(&apic->lapic_timer.timer);
+       apic->lapic_timer.tscdeadline = data;
+       start_apic_timer(apic);
+}
+
 void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
index 52c9e6b..138e8cc 100644 (file)
@@ -26,6 +26,7 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
 void kvm_lapic_reset(struct kvm_vcpu *vcpu);
 u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
 void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
+void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu);
 void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
 u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
 void kvm_apic_set_version(struct kvm_vcpu *vcpu);
@@ -41,6 +42,9 @@ int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
 bool kvm_apic_present(struct kvm_vcpu *vcpu);
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
 
+u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);
+void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data);
+
 void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
 void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu);
 void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu);
index 8e8da79..f1b36cf 100644 (file)
@@ -2770,7 +2770,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
 
                ASSERT(!VALID_PAGE(root));
                if (vcpu->arch.mmu.root_level == PT32E_ROOT_LEVEL) {
-                       pdptr = kvm_pdptr_read_mmu(vcpu, &vcpu->arch.mmu, i);
+                       pdptr = vcpu->arch.mmu.get_pdptr(vcpu, i);
                        if (!is_present_gpte(pdptr)) {
                                vcpu->arch.mmu.pae_root[i] = 0;
                                continue;
@@ -3318,6 +3318,7 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
        context->direct_map = true;
        context->set_cr3 = kvm_x86_ops->set_tdp_cr3;
        context->get_cr3 = get_cr3;
+       context->get_pdptr = kvm_pdptr_read;
        context->inject_page_fault = kvm_inject_page_fault;
        context->nx = is_nx(vcpu);
 
@@ -3376,6 +3377,7 @@ static int init_kvm_softmmu(struct kvm_vcpu *vcpu)
 
        vcpu->arch.walk_mmu->set_cr3           = kvm_x86_ops->set_cr3;
        vcpu->arch.walk_mmu->get_cr3           = get_cr3;
+       vcpu->arch.walk_mmu->get_pdptr         = kvm_pdptr_read;
        vcpu->arch.walk_mmu->inject_page_fault = kvm_inject_page_fault;
 
        return r;
@@ -3386,6 +3388,7 @@ static int init_kvm_nested_mmu(struct kvm_vcpu *vcpu)
        struct kvm_mmu *g_context = &vcpu->arch.nested_mmu;
 
        g_context->get_cr3           = get_cr3;
+       g_context->get_pdptr         = kvm_pdptr_read;
        g_context->inject_page_fault = kvm_inject_page_fault;
 
        /*
index 2460a26..746ec25 100644 (file)
@@ -121,16 +121,16 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
 
 static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
 {
+       static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10);
        unsigned long *rmapp;
        struct kvm_mmu_page *rev_sp;
        gfn_t gfn;
 
-
        rev_sp = page_header(__pa(sptep));
        gfn = kvm_mmu_page_get_gfn(rev_sp, sptep - rev_sp->spt);
 
        if (!gfn_to_memslot(kvm, gfn)) {
-               if (!printk_ratelimit())
+               if (!__ratelimit(&ratelimit_state))
                        return;
                audit_printk(kvm, "no memslot for gfn %llx\n", gfn);
                audit_printk(kvm, "index %ld of sp (gfn=%llx)\n",
@@ -141,7 +141,7 @@ static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
 
        rmapp = gfn_to_rmap(kvm, gfn, rev_sp->role.level);
        if (!*rmapp) {
-               if (!printk_ratelimit())
+               if (!__ratelimit(&ratelimit_state))
                        return;
                audit_printk(kvm, "no rmap for writable spte %llx\n",
                             *sptep);
index 507e2b8..9299410 100644 (file)
@@ -147,7 +147,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
        gfn_t table_gfn;
        unsigned index, pt_access, uninitialized_var(pte_access);
        gpa_t pte_gpa;
-       bool eperm;
+       bool eperm, last_gpte;
        int offset;
        const int write_fault = access & PFERR_WRITE_MASK;
        const int user_fault  = access & PFERR_USER_MASK;
@@ -163,7 +163,7 @@ retry_walk:
 
 #if PTTYPE == 64
        if (walker->level == PT32E_ROOT_LEVEL) {
-               pte = kvm_pdptr_read_mmu(vcpu, mmu, (addr >> 30) & 3);
+               pte = mmu->get_pdptr(vcpu, (addr >> 30) & 3);
                trace_kvm_mmu_paging_element(pte, walker->level);
                if (!is_present_gpte(pte))
                        goto error;
@@ -221,6 +221,17 @@ retry_walk:
                        eperm = true;
 #endif
 
+               last_gpte = FNAME(is_last_gpte)(walker, vcpu, mmu, pte);
+               if (last_gpte) {
+                       pte_access = pt_access &
+                                    FNAME(gpte_access)(vcpu, pte, true);
+                       /* check if the kernel is fetching from user page */
+                       if (unlikely(pte_access & PT_USER_MASK) &&
+                           kvm_read_cr4_bits(vcpu, X86_CR4_SMEP))
+                               if (fetch_fault && !user_fault)
+                                       eperm = true;
+               }
+
                if (!eperm && unlikely(!(pte & PT_ACCESSED_MASK))) {
                        int ret;
                        trace_kvm_mmu_set_accessed_bit(table_gfn, index,
@@ -238,18 +249,12 @@ retry_walk:
 
                walker->ptes[walker->level - 1] = pte;
 
-               if (FNAME(is_last_gpte)(walker, vcpu, mmu, pte)) {
+               if (last_gpte) {
                        int lvl = walker->level;
                        gpa_t real_gpa;
                        gfn_t gfn;
                        u32 ac;
 
-                       /* check if the kernel is fetching from user page */
-                       if (unlikely(pte_access & PT_USER_MASK) &&
-                           kvm_read_cr4_bits(vcpu, X86_CR4_SMEP))
-                               if (fetch_fault && !user_fault)
-                                       eperm = true;
-
                        gfn = gpte_to_gfn_lvl(pte, lvl);
                        gfn += (addr & PT_LVL_OFFSET_MASK(lvl)) >> PAGE_SHIFT;
 
@@ -295,7 +300,6 @@ retry_walk:
                walker->ptes[walker->level - 1] = pte;
        }
 
-       pte_access = pt_access & FNAME(gpte_access)(vcpu, pte, true);
        walker->pt_access = pt_access;
        walker->pte_access = pte_access;
        pgprintk("%s: pte %llx pte_access %x pt_access %x\n",
index 475d1c9..e32243e 100644 (file)
@@ -1084,7 +1084,6 @@ static void init_vmcb(struct vcpu_svm *svm)
        if (npt_enabled) {
                /* Setup VMCB for Nested Paging */
                control->nested_ctl = 1;
-               clr_intercept(svm, INTERCEPT_TASK_SWITCH);
                clr_intercept(svm, INTERCEPT_INVLPG);
                clr_exception_intercept(svm, PF_VECTOR);
                clr_cr_intercept(svm, INTERCEPT_CR3_READ);
@@ -1844,6 +1843,20 @@ static unsigned long nested_svm_get_tdp_cr3(struct kvm_vcpu *vcpu)
        return svm->nested.nested_cr3;
 }
 
+static u64 nested_svm_get_tdp_pdptr(struct kvm_vcpu *vcpu, int index)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u64 cr3 = svm->nested.nested_cr3;
+       u64 pdpte;
+       int ret;
+
+       ret = kvm_read_guest_page(vcpu->kvm, gpa_to_gfn(cr3), &pdpte,
+                                 offset_in_page(cr3) + index * 8, 8);
+       if (ret)
+               return 0;
+       return pdpte;
+}
+
 static void nested_svm_set_tdp_cr3(struct kvm_vcpu *vcpu,
                                   unsigned long root)
 {
@@ -1875,6 +1888,7 @@ static int nested_svm_init_mmu_context(struct kvm_vcpu *vcpu)
 
        vcpu->arch.mmu.set_cr3           = nested_svm_set_tdp_cr3;
        vcpu->arch.mmu.get_cr3           = nested_svm_get_tdp_cr3;
+       vcpu->arch.mmu.get_pdptr         = nested_svm_get_tdp_pdptr;
        vcpu->arch.mmu.inject_page_fault = nested_svm_inject_npf_exit;
        vcpu->arch.mmu.shadow_root_level = get_npt_level();
        vcpu->arch.walk_mmu              = &vcpu->arch.nested_mmu;
@@ -2182,7 +2196,8 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
                                       vmcb->control.exit_info_1,
                                       vmcb->control.exit_info_2,
                                       vmcb->control.exit_int_info,
-                                      vmcb->control.exit_int_info_err);
+                                      vmcb->control.exit_int_info_err,
+                                      KVM_ISA_SVM);
 
        nested_vmcb = nested_svm_map(svm, svm->nested.vmcb, &page);
        if (!nested_vmcb)
@@ -2894,15 +2909,20 @@ static int cr8_write_interception(struct vcpu_svm *svm)
        return 0;
 }
 
+u64 svm_read_l1_tsc(struct kvm_vcpu *vcpu)
+{
+       struct vmcb *vmcb = get_host_vmcb(to_svm(vcpu));
+       return vmcb->control.tsc_offset +
+               svm_scale_tsc(vcpu, native_read_tsc());
+}
+
 static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
        switch (ecx) {
        case MSR_IA32_TSC: {
-               struct vmcb *vmcb = get_host_vmcb(svm);
-
-               *data = vmcb->control.tsc_offset +
+               *data = svm->vmcb->control.tsc_offset +
                        svm_scale_tsc(vcpu, native_read_tsc());
 
                break;
@@ -3314,8 +3334,6 @@ static int handle_exit(struct kvm_vcpu *vcpu)
        struct kvm_run *kvm_run = vcpu->run;
        u32 exit_code = svm->vmcb->control.exit_code;
 
-       trace_kvm_exit(exit_code, vcpu, KVM_ISA_SVM);
-
        if (!is_cr_intercept(svm, INTERCEPT_CR0_WRITE))
                vcpu->arch.cr0 = svm->vmcb->save.cr0;
        if (npt_enabled)
@@ -3335,7 +3353,8 @@ static int handle_exit(struct kvm_vcpu *vcpu)
                                        svm->vmcb->control.exit_info_1,
                                        svm->vmcb->control.exit_info_2,
                                        svm->vmcb->control.exit_int_info,
-                                       svm->vmcb->control.exit_int_info_err);
+                                       svm->vmcb->control.exit_int_info_err,
+                                       KVM_ISA_SVM);
 
                vmexit = nested_svm_exit_special(svm);
 
@@ -3768,6 +3787,8 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
        vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
        vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
 
+       trace_kvm_exit(svm->vmcb->control.exit_code, vcpu, KVM_ISA_SVM);
+
        if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
                kvm_before_handle_nmi(&svm->vcpu);
 
@@ -3897,60 +3918,6 @@ static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
        }
 }
 
-static const struct trace_print_flags svm_exit_reasons_str[] = {
-       { SVM_EXIT_READ_CR0,                    "read_cr0" },
-       { SVM_EXIT_READ_CR3,                    "read_cr3" },
-       { SVM_EXIT_READ_CR4,                    "read_cr4" },
-       { SVM_EXIT_READ_CR8,                    "read_cr8" },
-       { SVM_EXIT_WRITE_CR0,                   "write_cr0" },
-       { SVM_EXIT_WRITE_CR3,                   "write_cr3" },
-       { SVM_EXIT_WRITE_CR4,                   "write_cr4" },
-       { SVM_EXIT_WRITE_CR8,                   "write_cr8" },
-       { SVM_EXIT_READ_DR0,                    "read_dr0" },
-       { SVM_EXIT_READ_DR1,                    "read_dr1" },
-       { SVM_EXIT_READ_DR2,                    "read_dr2" },
-       { SVM_EXIT_READ_DR3,                    "read_dr3" },
-       { SVM_EXIT_WRITE_DR0,                   "write_dr0" },
-       { SVM_EXIT_WRITE_DR1,                   "write_dr1" },
-       { SVM_EXIT_WRITE_DR2,                   "write_dr2" },
-       { SVM_EXIT_WRITE_DR3,                   "write_dr3" },
-       { SVM_EXIT_WRITE_DR5,                   "write_dr5" },
-       { SVM_EXIT_WRITE_DR7,                   "write_dr7" },
-       { SVM_EXIT_EXCP_BASE + DB_VECTOR,       "DB excp" },
-       { SVM_EXIT_EXCP_BASE + BP_VECTOR,       "BP excp" },
-       { SVM_EXIT_EXCP_BASE + UD_VECTOR,       "UD excp" },
-       { SVM_EXIT_EXCP_BASE + PF_VECTOR,       "PF excp" },
-       { SVM_EXIT_EXCP_BASE + NM_VECTOR,       "NM excp" },
-       { SVM_EXIT_EXCP_BASE + MC_VECTOR,       "MC excp" },
-       { SVM_EXIT_INTR,                        "interrupt" },
-       { SVM_EXIT_NMI,                         "nmi" },
-       { SVM_EXIT_SMI,                         "smi" },
-       { SVM_EXIT_INIT,                        "init" },
-       { SVM_EXIT_VINTR,                       "vintr" },
-       { SVM_EXIT_CPUID,                       "cpuid" },
-       { SVM_EXIT_INVD,                        "invd" },
-       { SVM_EXIT_HLT,                         "hlt" },
-       { SVM_EXIT_INVLPG,                      "invlpg" },
-       { SVM_EXIT_INVLPGA,                     "invlpga" },
-       { SVM_EXIT_IOIO,                        "io" },
-       { SVM_EXIT_MSR,                         "msr" },
-       { SVM_EXIT_TASK_SWITCH,                 "task_switch" },
-       { SVM_EXIT_SHUTDOWN,                    "shutdown" },
-       { SVM_EXIT_VMRUN,                       "vmrun" },
-       { SVM_EXIT_VMMCALL,                     "hypercall" },
-       { SVM_EXIT_VMLOAD,                      "vmload" },
-       { SVM_EXIT_VMSAVE,                      "vmsave" },
-       { SVM_EXIT_STGI,                        "stgi" },
-       { SVM_EXIT_CLGI,                        "clgi" },
-       { SVM_EXIT_SKINIT,                      "skinit" },
-       { SVM_EXIT_WBINVD,                      "wbinvd" },
-       { SVM_EXIT_MONITOR,                     "monitor" },
-       { SVM_EXIT_MWAIT,                       "mwait" },
-       { SVM_EXIT_XSETBV,                      "xsetbv" },
-       { SVM_EXIT_NPF,                         "npf" },
-       { -1, NULL }
-};
-
 static int svm_get_lpage_level(void)
 {
        return PT_PDPE_LEVEL;
@@ -4223,7 +4190,6 @@ static struct kvm_x86_ops svm_x86_ops = {
        .get_mt_mask = svm_get_mt_mask,
 
        .get_exit_info = svm_get_exit_info,
-       .exit_reasons_str = svm_exit_reasons_str,
 
        .get_lpage_level = svm_get_lpage_level,
 
@@ -4239,6 +4205,7 @@ static struct kvm_x86_ops svm_x86_ops = {
        .write_tsc_offset = svm_write_tsc_offset,
        .adjust_tsc_offset = svm_adjust_tsc_offset,
        .compute_tsc_offset = svm_compute_tsc_offset,
+       .read_l1_tsc = svm_read_l1_tsc,
 
        .set_tdp_cr3 = set_tdp_cr3,
 
index 3ff898c..911d264 100644 (file)
@@ -2,6 +2,8 @@
 #define _TRACE_KVM_H
 
 #include <linux/tracepoint.h>
+#include <asm/vmx.h>
+#include <asm/svm.h>
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM kvm
@@ -181,6 +183,95 @@ TRACE_EVENT(kvm_apic,
 #define KVM_ISA_VMX   1
 #define KVM_ISA_SVM   2
 
+#define VMX_EXIT_REASONS \
+       { EXIT_REASON_EXCEPTION_NMI,            "EXCEPTION_NMI" }, \
+       { EXIT_REASON_EXTERNAL_INTERRUPT,       "EXTERNAL_INTERRUPT" }, \
+       { EXIT_REASON_TRIPLE_FAULT,             "TRIPLE_FAULT" }, \
+       { EXIT_REASON_PENDING_INTERRUPT,        "PENDING_INTERRUPT" }, \
+       { EXIT_REASON_NMI_WINDOW,               "NMI_WINDOW" }, \
+       { EXIT_REASON_TASK_SWITCH,              "TASK_SWITCH" }, \
+       { EXIT_REASON_CPUID,                    "CPUID" }, \
+       { EXIT_REASON_HLT,                      "HLT" }, \
+       { EXIT_REASON_INVLPG,                   "INVLPG" }, \
+       { EXIT_REASON_RDPMC,                    "RDPMC" }, \
+       { EXIT_REASON_RDTSC,                    "RDTSC" }, \
+       { EXIT_REASON_VMCALL,                   "VMCALL" }, \
+       { EXIT_REASON_VMCLEAR,                  "VMCLEAR" }, \
+       { EXIT_REASON_VMLAUNCH,                 "VMLAUNCH" }, \
+       { EXIT_REASON_VMPTRLD,                  "VMPTRLD" }, \
+       { EXIT_REASON_VMPTRST,                  "VMPTRST" }, \
+       { EXIT_REASON_VMREAD,                   "VMREAD" }, \
+       { EXIT_REASON_VMRESUME,                 "VMRESUME" }, \
+       { EXIT_REASON_VMWRITE,                  "VMWRITE" }, \
+       { EXIT_REASON_VMOFF,                    "VMOFF" }, \
+       { EXIT_REASON_VMON,                     "VMON" }, \
+       { EXIT_REASON_CR_ACCESS,                "CR_ACCESS" }, \
+       { EXIT_REASON_DR_ACCESS,                "DR_ACCESS" }, \
+       { EXIT_REASON_IO_INSTRUCTION,           "IO_INSTRUCTION" }, \
+       { EXIT_REASON_MSR_READ,                 "MSR_READ" }, \
+       { EXIT_REASON_MSR_WRITE,                "MSR_WRITE" }, \
+       { EXIT_REASON_MWAIT_INSTRUCTION,        "MWAIT_INSTRUCTION" }, \
+       { EXIT_REASON_MONITOR_INSTRUCTION,      "MONITOR_INSTRUCTION" }, \
+       { EXIT_REASON_PAUSE_INSTRUCTION,        "PAUSE_INSTRUCTION" }, \
+       { EXIT_REASON_MCE_DURING_VMENTRY,       "MCE_DURING_VMENTRY" }, \
+       { EXIT_REASON_TPR_BELOW_THRESHOLD,      "TPR_BELOW_THRESHOLD" },        \
+       { EXIT_REASON_APIC_ACCESS,              "APIC_ACCESS" }, \
+       { EXIT_REASON_EPT_VIOLATION,            "EPT_VIOLATION" }, \
+       { EXIT_REASON_EPT_MISCONFIG,            "EPT_MISCONFIG" }, \
+       { EXIT_REASON_WBINVD,                   "WBINVD" }
+
+#define SVM_EXIT_REASONS \
+       { SVM_EXIT_READ_CR0,                    "read_cr0" }, \
+       { SVM_EXIT_READ_CR3,                    "read_cr3" }, \
+       { SVM_EXIT_READ_CR4,                    "read_cr4" }, \
+       { SVM_EXIT_READ_CR8,                    "read_cr8" }, \
+       { SVM_EXIT_WRITE_CR0,                   "write_cr0" }, \
+       { SVM_EXIT_WRITE_CR3,                   "write_cr3" }, \
+       { SVM_EXIT_WRITE_CR4,                   "write_cr4" }, \
+       { SVM_EXIT_WRITE_CR8,                   "write_cr8" }, \
+       { SVM_EXIT_READ_DR0,                    "read_dr0" }, \
+       { SVM_EXIT_READ_DR1,                    "read_dr1" }, \
+       { SVM_EXIT_READ_DR2,                    "read_dr2" }, \
+       { SVM_EXIT_READ_DR3,                    "read_dr3" }, \
+       { SVM_EXIT_WRITE_DR0,                   "write_dr0" }, \
+       { SVM_EXIT_WRITE_DR1,                   "write_dr1" }, \
+       { SVM_EXIT_WRITE_DR2,                   "write_dr2" }, \
+       { SVM_EXIT_WRITE_DR3,                   "write_dr3" }, \
+       { SVM_EXIT_WRITE_DR5,                   "write_dr5" }, \
+       { SVM_EXIT_WRITE_DR7,                   "write_dr7" }, \
+       { SVM_EXIT_EXCP_BASE + DB_VECTOR,       "DB excp" }, \
+       { SVM_EXIT_EXCP_BASE + BP_VECTOR,       "BP excp" }, \
+       { SVM_EXIT_EXCP_BASE + UD_VECTOR,       "UD excp" }, \
+       { SVM_EXIT_EXCP_BASE + PF_VECTOR,       "PF excp" }, \
+       { SVM_EXIT_EXCP_BASE + NM_VECTOR,       "NM excp" }, \
+       { SVM_EXIT_EXCP_BASE + MC_VECTOR,       "MC excp" }, \
+       { SVM_EXIT_INTR,                        "interrupt" }, \
+       { SVM_EXIT_NMI,                         "nmi" }, \
+       { SVM_EXIT_SMI,                         "smi" }, \
+       { SVM_EXIT_INIT,                        "init" }, \
+       { SVM_EXIT_VINTR,                       "vintr" }, \
+       { SVM_EXIT_CPUID,                       "cpuid" }, \
+       { SVM_EXIT_INVD,                        "invd" }, \
+       { SVM_EXIT_HLT,                         "hlt" }, \
+       { SVM_EXIT_INVLPG,                      "invlpg" }, \
+       { SVM_EXIT_INVLPGA,                     "invlpga" }, \
+       { SVM_EXIT_IOIO,                        "io" }, \
+       { SVM_EXIT_MSR,                         "msr" }, \
+       { SVM_EXIT_TASK_SWITCH,                 "task_switch" }, \
+       { SVM_EXIT_SHUTDOWN,                    "shutdown" }, \
+       { SVM_EXIT_VMRUN,                       "vmrun" }, \
+       { SVM_EXIT_VMMCALL,                     "hypercall" }, \
+       { SVM_EXIT_VMLOAD,                      "vmload" }, \
+       { SVM_EXIT_VMSAVE,                      "vmsave" }, \
+       { SVM_EXIT_STGI,                        "stgi" }, \
+       { SVM_EXIT_CLGI,                        "clgi" }, \
+       { SVM_EXIT_SKINIT,                      "skinit" }, \
+       { SVM_EXIT_WBINVD,                      "wbinvd" }, \
+       { SVM_EXIT_MONITOR,                     "monitor" }, \
+       { SVM_EXIT_MWAIT,                       "mwait" }, \
+       { SVM_EXIT_XSETBV,                      "xsetbv" }, \
+       { SVM_EXIT_NPF,                         "npf" }
+
 /*
  * Tracepoint for kvm guest exit:
  */
@@ -205,8 +296,9 @@ TRACE_EVENT(kvm_exit,
        ),
 
        TP_printk("reason %s rip 0x%lx info %llx %llx",
-                ftrace_print_symbols_seq(p, __entry->exit_reason,
-                                         kvm_x86_ops->exit_reasons_str),
+                (__entry->isa == KVM_ISA_VMX) ?
+                __print_symbolic(__entry->exit_reason, VMX_EXIT_REASONS) :
+                __print_symbolic(__entry->exit_reason, SVM_EXIT_REASONS),
                 __entry->guest_rip, __entry->info1, __entry->info2)
 );
 
@@ -486,9 +578,9 @@ TRACE_EVENT(kvm_nested_intercepts,
 TRACE_EVENT(kvm_nested_vmexit,
            TP_PROTO(__u64 rip, __u32 exit_code,
                     __u64 exit_info1, __u64 exit_info2,
-                    __u32 exit_int_info, __u32 exit_int_info_err),
+                    __u32 exit_int_info, __u32 exit_int_info_err, __u32 isa),
            TP_ARGS(rip, exit_code, exit_info1, exit_info2,
-                   exit_int_info, exit_int_info_err),
+                   exit_int_info, exit_int_info_err, isa),
 
        TP_STRUCT__entry(
                __field(        __u64,          rip                     )
@@ -497,6 +589,7 @@ TRACE_EVENT(kvm_nested_vmexit,
                __field(        __u64,          exit_info2              )
                __field(        __u32,          exit_int_info           )
                __field(        __u32,          exit_int_info_err       )
+               __field(        __u32,          isa                     )
        ),
 
        TP_fast_assign(
@@ -506,12 +599,14 @@ TRACE_EVENT(kvm_nested_vmexit,
                __entry->exit_info2             = exit_info2;
                __entry->exit_int_info          = exit_int_info;
                __entry->exit_int_info_err      = exit_int_info_err;
+               __entry->isa                    = isa;
        ),
        TP_printk("rip: 0x%016llx reason: %s ext_inf1: 0x%016llx "
                  "ext_inf2: 0x%016llx ext_int: 0x%08x ext_int_err: 0x%08x",
                  __entry->rip,
-                 ftrace_print_symbols_seq(p, __entry->exit_code,
-                                          kvm_x86_ops->exit_reasons_str),
+                (__entry->isa == KVM_ISA_VMX) ?
+                __print_symbolic(__entry->exit_code, VMX_EXIT_REASONS) :
+                __print_symbolic(__entry->exit_code, SVM_EXIT_REASONS),
                  __entry->exit_info1, __entry->exit_info2,
                  __entry->exit_int_info, __entry->exit_int_info_err)
 );
@@ -522,9 +617,9 @@ TRACE_EVENT(kvm_nested_vmexit,
 TRACE_EVENT(kvm_nested_vmexit_inject,
            TP_PROTO(__u32 exit_code,
                     __u64 exit_info1, __u64 exit_info2,
-                    __u32 exit_int_info, __u32 exit_int_info_err),
+                    __u32 exit_int_info, __u32 exit_int_info_err, __u32 isa),
            TP_ARGS(exit_code, exit_info1, exit_info2,
-                   exit_int_info, exit_int_info_err),
+                   exit_int_info, exit_int_info_err, isa),
 
        TP_STRUCT__entry(
                __field(        __u32,          exit_code               )
@@ -532,6 +627,7 @@ TRACE_EVENT(kvm_nested_vmexit_inject,
                __field(        __u64,          exit_info2              )
                __field(        __u32,          exit_int_info           )
                __field(        __u32,          exit_int_info_err       )
+               __field(        __u32,          isa                     )
        ),
 
        TP_fast_assign(
@@ -540,12 +636,14 @@ TRACE_EVENT(kvm_nested_vmexit_inject,
                __entry->exit_info2             = exit_info2;
                __entry->exit_int_info          = exit_int_info;
                __entry->exit_int_info_err      = exit_int_info_err;
+               __entry->isa                    = isa;
        ),
 
        TP_printk("reason: %s ext_inf1: 0x%016llx "
                  "ext_inf2: 0x%016llx ext_int: 0x%08x ext_int_err: 0x%08x",
-                 ftrace_print_symbols_seq(p, __entry->exit_code,
-                                          kvm_x86_ops->exit_reasons_str),
+                (__entry->isa == KVM_ISA_VMX) ?
+                __print_symbolic(__entry->exit_code, VMX_EXIT_REASONS) :
+                __print_symbolic(__entry->exit_code, SVM_EXIT_REASONS),
                __entry->exit_info1, __entry->exit_info2,
                __entry->exit_int_info, __entry->exit_int_info_err)
 );
index e65a158..a0d6bd9 100644 (file)
@@ -71,6 +71,9 @@ module_param(vmm_exclusive, bool, S_IRUGO);
 static int __read_mostly yield_on_hlt = 1;
 module_param(yield_on_hlt, bool, S_IRUGO);
 
+static int __read_mostly fasteoi = 1;
+module_param(fasteoi, bool, S_IRUGO);
+
 /*
  * If nested=1, nested virtualization is supported, i.e., guests may use
  * VMX and be a hypervisor for its own guests. If nested=0, guests may not
@@ -1747,6 +1750,21 @@ static u64 guest_read_tsc(void)
        return host_tsc + tsc_offset;
 }
 
+/*
+ * Like guest_read_tsc, but always returns L1's notion of the timestamp
+ * counter, even if a nested guest (L2) is currently running.
+ */
+u64 vmx_read_l1_tsc(struct kvm_vcpu *vcpu)
+{
+       u64 host_tsc, tsc_offset;
+
+       rdtscll(host_tsc);
+       tsc_offset = is_guest_mode(vcpu) ?
+               to_vmx(vcpu)->nested.vmcs01_tsc_offset :
+               vmcs_read64(TSC_OFFSET);
+       return host_tsc + tsc_offset;
+}
+
 /*
  * Empty call-back. Needs to be implemented when VMX enables the SET_TSC_KHZ
  * ioctl. In this case the call-back should update internal vmx state to make
@@ -1762,15 +1780,23 @@ static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
  */
 static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
 {
-       vmcs_write64(TSC_OFFSET, offset);
-       if (is_guest_mode(vcpu))
+       if (is_guest_mode(vcpu)) {
                /*
-                * We're here if L1 chose not to trap the TSC MSR. Since
-                * prepare_vmcs12() does not copy tsc_offset, we need to also
-                * set the vmcs12 field here.
+                * We're here if L1 chose not to trap WRMSR to TSC. According
+                * to the spec, this should set L1's TSC; The offset that L1
+                * set for L2 remains unchanged, and still needs to be added
+                * to the newly set TSC to get L2's TSC.
                 */
-               get_vmcs12(vcpu)->tsc_offset = offset -
-                       to_vmx(vcpu)->nested.vmcs01_tsc_offset;
+               struct vmcs12 *vmcs12;
+               to_vmx(vcpu)->nested.vmcs01_tsc_offset = offset;
+               /* recalculate vmcs02.TSC_OFFSET: */
+               vmcs12 = get_vmcs12(vcpu);
+               vmcs_write64(TSC_OFFSET, offset +
+                       (nested_cpu_has(vmcs12, CPU_BASED_USE_TSC_OFFSETING) ?
+                        vmcs12->tsc_offset : 0));
+       } else {
+               vmcs_write64(TSC_OFFSET, offset);
+       }
 }
 
 static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
@@ -2736,8 +2762,8 @@ static void enter_lmode(struct kvm_vcpu *vcpu)
 
        guest_tr_ar = vmcs_read32(GUEST_TR_AR_BYTES);
        if ((guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) {
-               printk(KERN_DEBUG "%s: tss fixup for long mode. \n",
-                      __func__);
+               pr_debug_ratelimited("%s: tss fixup for long mode. \n",
+                                    __func__);
                vmcs_write32(GUEST_TR_AR_BYTES,
                             (guest_tr_ar & ~AR_TYPE_MASK)
                             | AR_TYPE_BUSY_64_TSS);
@@ -4115,8 +4141,7 @@ static int handle_exception(struct kvm_vcpu *vcpu)
                error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
        if (is_page_fault(intr_info)) {
                /* EPT won't cause page fault directly */
-               if (enable_ept)
-                       BUG();
+               BUG_ON(enable_ept);
                cr2 = vmcs_readl(EXIT_QUALIFICATION);
                trace_kvm_page_fault(cr2, error_code);
 
@@ -4518,6 +4543,24 @@ static int handle_xsetbv(struct kvm_vcpu *vcpu)
 
 static int handle_apic_access(struct kvm_vcpu *vcpu)
 {
+       if (likely(fasteoi)) {
+               unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
+               int access_type, offset;
+
+               access_type = exit_qualification & APIC_ACCESS_TYPE;
+               offset = exit_qualification & APIC_ACCESS_OFFSET;
+               /*
+                * Sane guest uses MOV to write EOI, with written value
+                * not cared. So make a short-circuit here by avoiding
+                * heavy instruction emulation.
+                */
+               if ((access_type == TYPE_LINEAR_APIC_INST_WRITE) &&
+                   (offset == APIC_EOI)) {
+                       kvm_lapic_set_eoi(vcpu);
+                       skip_emulated_instruction(vcpu);
+                       return 1;
+               }
+       }
        return emulate_instruction(vcpu, 0) == EMULATE_DONE;
 }
 
@@ -5591,8 +5634,8 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
                return 0;
 
        if (unlikely(vmx->fail)) {
-               printk(KERN_INFO "%s failed vm entry %x\n",
-                      __func__, vmcs_read32(VM_INSTRUCTION_ERROR));
+               pr_info_ratelimited("%s failed vm entry %x\n", __func__,
+                                   vmcs_read32(VM_INSTRUCTION_ERROR));
                return 1;
        }
 
@@ -5696,8 +5739,6 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
        u32 exit_reason = vmx->exit_reason;
        u32 vectoring_info = vmx->idt_vectoring_info;
 
-       trace_kvm_exit(exit_reason, vcpu, KVM_ISA_VMX);
-
        /* If guest state is invalid, start emulating */
        if (vmx->emulation_required && emulate_invalid_guest_state)
                return handle_invalid_guest_state(vcpu);
@@ -6101,6 +6142,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
        vmx->loaded_vmcs->launched = 1;
 
        vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
+       trace_kvm_exit(vmx->exit_reason, vcpu, KVM_ISA_VMX);
 
        vmx_complete_atomic_exit(vmx);
        vmx_recover_nmi_blocking(vmx);
@@ -6241,49 +6283,6 @@ static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
        return ret;
 }
 
-#define _ER(x) { EXIT_REASON_##x, #x }
-
-static const struct trace_print_flags vmx_exit_reasons_str[] = {
-       _ER(EXCEPTION_NMI),
-       _ER(EXTERNAL_INTERRUPT),
-       _ER(TRIPLE_FAULT),
-       _ER(PENDING_INTERRUPT),
-       _ER(NMI_WINDOW),
-       _ER(TASK_SWITCH),
-       _ER(CPUID),
-       _ER(HLT),
-       _ER(INVLPG),
-       _ER(RDPMC),
-       _ER(RDTSC),
-       _ER(VMCALL),
-       _ER(VMCLEAR),
-       _ER(VMLAUNCH),
-       _ER(VMPTRLD),
-       _ER(VMPTRST),
-       _ER(VMREAD),
-       _ER(VMRESUME),
-       _ER(VMWRITE),
-       _ER(VMOFF),
-       _ER(VMON),
-       _ER(CR_ACCESS),
-       _ER(DR_ACCESS),
-       _ER(IO_INSTRUCTION),
-       _ER(MSR_READ),
-       _ER(MSR_WRITE),
-       _ER(MWAIT_INSTRUCTION),
-       _ER(MONITOR_INSTRUCTION),
-       _ER(PAUSE_INSTRUCTION),
-       _ER(MCE_DURING_VMENTRY),
-       _ER(TPR_BELOW_THRESHOLD),
-       _ER(APIC_ACCESS),
-       _ER(EPT_VIOLATION),
-       _ER(EPT_MISCONFIG),
-       _ER(WBINVD),
-       { -1, NULL }
-};
-
-#undef _ER
-
 static int vmx_get_lpage_level(void)
 {
        if (enable_ept && !cpu_has_vmx_ept_1g_page())
@@ -6514,8 +6513,11 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
 
        set_cr4_guest_host_mask(vmx);
 
-       vmcs_write64(TSC_OFFSET,
-               vmx->nested.vmcs01_tsc_offset + vmcs12->tsc_offset);
+       if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
+               vmcs_write64(TSC_OFFSET,
+                       vmx->nested.vmcs01_tsc_offset + vmcs12->tsc_offset);
+       else
+               vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset);
 
        if (enable_vpid) {
                /*
@@ -6610,9 +6612,8 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
        if (vmcs12->vm_entry_msr_load_count > 0 ||
            vmcs12->vm_exit_msr_load_count > 0 ||
            vmcs12->vm_exit_msr_store_count > 0) {
-               if (printk_ratelimit())
-                       printk(KERN_WARNING
-                         "%s: VMCS MSR_{LOAD,STORE} unsupported\n", __func__);
+               pr_warn_ratelimited("%s: VMCS MSR_{LOAD,STORE} unsupported\n",
+                                   __func__);
                nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
                return 1;
        }
@@ -6922,7 +6923,7 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu)
 
        load_vmcs12_host_state(vcpu, vmcs12);
 
-       /* Update TSC_OFFSET if vmx_adjust_tsc_offset() was used while L2 ran */
+       /* Update TSC_OFFSET if TSC was changed while L2 ran */
        vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset);
 
        /* This is needed for same reason as it was needed in prepare_vmcs02 */
@@ -7039,7 +7040,6 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .get_mt_mask = vmx_get_mt_mask,
 
        .get_exit_info = vmx_get_exit_info,
-       .exit_reasons_str = vmx_exit_reasons_str,
 
        .get_lpage_level = vmx_get_lpage_level,
 
@@ -7055,6 +7055,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .write_tsc_offset = vmx_write_tsc_offset,
        .adjust_tsc_offset = vmx_adjust_tsc_offset,
        .compute_tsc_offset = vmx_compute_tsc_offset,
+       .read_l1_tsc = vmx_read_l1_tsc,
 
        .set_tdp_cr3 = vmx_set_cr3,
 
index 84a28ea..c38efd7 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/perf_event.h>
 #include <linux/uaccess.h>
 #include <linux/hash.h>
+#include <linux/pci.h>
 #include <trace/events/kvm.h>
 
 #define CREATE_TRACE_POINTS
@@ -83,6 +84,7 @@ static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE);
 static void update_cr8_intercept(struct kvm_vcpu *vcpu);
 static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
                                    struct kvm_cpuid_entry2 __user *entries);
+static void process_nmi(struct kvm_vcpu *vcpu);
 
 struct kvm_x86_ops *kvm_x86_ops;
 EXPORT_SYMBOL_GPL(kvm_x86_ops);
@@ -359,8 +361,8 @@ void kvm_propagate_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault)
 
 void kvm_inject_nmi(struct kvm_vcpu *vcpu)
 {
-       kvm_make_request(KVM_REQ_EVENT, vcpu);
-       vcpu->arch.nmi_pending = 1;
+       atomic_inc(&vcpu->arch.nmi_queued);
+       kvm_make_request(KVM_REQ_NMI, vcpu);
 }
 EXPORT_SYMBOL_GPL(kvm_inject_nmi);
 
@@ -599,6 +601,8 @@ static bool guest_cpuid_has_fsgsbase(struct kvm_vcpu *vcpu)
 static void update_cpuid(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpuid_entry2 *best;
+       struct kvm_lapic *apic = vcpu->arch.apic;
+       u32 timer_mode_mask;
 
        best = kvm_find_cpuid_entry(vcpu, 1, 0);
        if (!best)
@@ -610,6 +614,16 @@ static void update_cpuid(struct kvm_vcpu *vcpu)
                if (kvm_read_cr4_bits(vcpu, X86_CR4_OSXSAVE))
                        best->ecx |= bit(X86_FEATURE_OSXSAVE);
        }
+
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+               best->function == 0x1) {
+               best->ecx |= bit(X86_FEATURE_TSC_DEADLINE_TIMER);
+               timer_mode_mask = 3 << 17;
+       } else
+               timer_mode_mask = 1 << 17;
+
+       if (apic)
+               apic->lapic_timer.timer_mode_mask = timer_mode_mask;
 }
 
 int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -825,6 +839,7 @@ static u32 msrs_to_save[] = {
 static unsigned num_msrs_to_save;
 
 static u32 emulated_msrs[] = {
+       MSR_IA32_TSCDEADLINE,
        MSR_IA32_MISC_ENABLE,
        MSR_IA32_MCG_STATUS,
        MSR_IA32_MCG_CTL,
@@ -1000,7 +1015,7 @@ static inline int kvm_tsc_changes_freq(void)
        return ret;
 }
 
-static u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu)
+u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu)
 {
        if (vcpu->arch.virtual_tsc_khz)
                return vcpu->arch.virtual_tsc_khz;
@@ -1098,7 +1113,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
 
        /* Keep irq disabled to prevent changes to the clock */
        local_irq_save(flags);
-       kvm_get_msr(v, MSR_IA32_TSC, &tsc_timestamp);
+       tsc_timestamp = kvm_x86_ops->read_l1_tsc(v);
        kernel_ns = get_kernel_ns();
        this_tsc_khz = vcpu_tsc_khz(v);
        if (unlikely(this_tsc_khz == 0)) {
@@ -1564,6 +1579,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
                break;
        case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
                return kvm_x2apic_msr_write(vcpu, msr, data);
+       case MSR_IA32_TSCDEADLINE:
+               kvm_set_lapic_tscdeadline_msr(vcpu, data);
+               break;
        case MSR_IA32_MISC_ENABLE:
                vcpu->arch.ia32_misc_enable_msr = data;
                break;
@@ -1825,6 +1843,9 @@ static int get_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
                return kvm_hv_vapic_msr_read(vcpu, APIC_ICR, pdata);
        case HV_X64_MSR_TPR:
                return kvm_hv_vapic_msr_read(vcpu, APIC_TASKPRI, pdata);
+       case HV_X64_MSR_APIC_ASSIST_PAGE:
+               data = vcpu->arch.hv_vapic;
+               break;
        default:
                pr_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
                return 1;
@@ -1839,7 +1860,6 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
 
        switch (msr) {
        case MSR_IA32_PLATFORM_ID:
-       case MSR_IA32_UCODE_REV:
        case MSR_IA32_EBL_CR_POWERON:
        case MSR_IA32_DEBUGCTLMSR:
        case MSR_IA32_LASTBRANCHFROMIP:
@@ -1860,6 +1880,9 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
        case MSR_FAM10H_MMIO_CONF_BASE:
                data = 0;
                break;
+       case MSR_IA32_UCODE_REV:
+               data = 0x100000000ULL;
+               break;
        case MSR_MTRRcap:
                data = 0x500 | KVM_NR_VAR_MTRR;
                break;
@@ -1888,6 +1911,9 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
        case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
                return kvm_x2apic_msr_read(vcpu, msr, pdata);
                break;
+       case MSR_IA32_TSCDEADLINE:
+               data = kvm_get_lapic_tscdeadline_msr(vcpu);
+               break;
        case MSR_IA32_MISC_ENABLE:
                data = vcpu->arch.ia32_misc_enable_msr;
                break;
@@ -2086,6 +2112,9 @@ int kvm_dev_ioctl_check_extension(long ext)
                r = !kvm_x86_ops->cpu_has_accelerated_tpr();
                break;
        case KVM_CAP_NR_VCPUS:
+               r = KVM_SOFT_MAX_VCPUS;
+               break;
+       case KVM_CAP_MAX_VCPUS:
                r = KVM_MAX_VCPUS;
                break;
        case KVM_CAP_NR_MEMSLOTS:
@@ -2095,7 +2124,7 @@ int kvm_dev_ioctl_check_extension(long ext)
                r = 0;
                break;
        case KVM_CAP_IOMMU:
-               r = iommu_found();
+               r = iommu_present(&pci_bus_type);
                break;
        case KVM_CAP_MCE:
                r = KVM_MAX_MCE_BANKS;
@@ -2210,7 +2239,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
                s64 tsc_delta;
                u64 tsc;
 
-               kvm_get_msr(vcpu, MSR_IA32_TSC, &tsc);
+               tsc = kvm_x86_ops->read_l1_tsc(vcpu);
                tsc_delta = !vcpu->arch.last_guest_tsc ? 0 :
                             tsc - vcpu->arch.last_guest_tsc;
 
@@ -2234,7 +2263,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
        kvm_x86_ops->vcpu_put(vcpu);
        kvm_put_guest_fpu(vcpu);
-       kvm_get_msr(vcpu, MSR_IA32_TSC, &vcpu->arch.last_guest_tsc);
+       vcpu->arch.last_guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu);
 }
 
 static int is_efer_nx(void)
@@ -2819,6 +2848,7 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu,
 static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
                                               struct kvm_vcpu_events *events)
 {
+       process_nmi(vcpu);
        events->exception.injected =
                vcpu->arch.exception.pending &&
                !kvm_exception_is_soft(vcpu->arch.exception.nr);
@@ -2836,7 +2866,7 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
                        KVM_X86_SHADOW_INT_MOV_SS | KVM_X86_SHADOW_INT_STI);
 
        events->nmi.injected = vcpu->arch.nmi_injected;
-       events->nmi.pending = vcpu->arch.nmi_pending;
+       events->nmi.pending = vcpu->arch.nmi_pending != 0;
        events->nmi.masked = kvm_x86_ops->get_nmi_mask(vcpu);
        events->nmi.pad = 0;
 
@@ -2856,6 +2886,7 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
                              | KVM_VCPUEVENT_VALID_SHADOW))
                return -EINVAL;
 
+       process_nmi(vcpu);
        vcpu->arch.exception.pending = events->exception.injected;
        vcpu->arch.exception.nr = events->exception.nr;
        vcpu->arch.exception.has_error_code = events->exception.has_error_code;
@@ -3556,7 +3587,11 @@ long kvm_arch_vm_ioctl(struct file *filp,
                        if (r) {
                                mutex_lock(&kvm->slots_lock);
                                kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
-                                                         &vpic->dev);
+                                                         &vpic->dev_master);
+                               kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
+                                                         &vpic->dev_slave);
+                               kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
+                                                         &vpic->dev_eclr);
                                mutex_unlock(&kvm->slots_lock);
                                kfree(vpic);
                                goto create_irqchip_unlock;
@@ -4045,84 +4080,105 @@ static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva,
        return 0;
 }
 
-static int emulator_read_emulated(struct x86_emulate_ctxt *ctxt,
-                                 unsigned long addr,
-                                 void *val,
-                                 unsigned int bytes,
-                                 struct x86_exception *exception)
+int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
+                       const void *val, int bytes)
 {
-       struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
-       gpa_t gpa;
-       int handled, ret;
+       int ret;
 
+       ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes);
+       if (ret < 0)
+               return 0;
+       kvm_mmu_pte_write(vcpu, gpa, val, bytes, 1);
+       return 1;
+}
+
+struct read_write_emulator_ops {
+       int (*read_write_prepare)(struct kvm_vcpu *vcpu, void *val,
+                                 int bytes);
+       int (*read_write_emulate)(struct kvm_vcpu *vcpu, gpa_t gpa,
+                                 void *val, int bytes);
+       int (*read_write_mmio)(struct kvm_vcpu *vcpu, gpa_t gpa,
+                              int bytes, void *val);
+       int (*read_write_exit_mmio)(struct kvm_vcpu *vcpu, gpa_t gpa,
+                                   void *val, int bytes);
+       bool write;
+};
+
+static int read_prepare(struct kvm_vcpu *vcpu, void *val, int bytes)
+{
        if (vcpu->mmio_read_completed) {
                memcpy(val, vcpu->mmio_data, bytes);
                trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes,
                               vcpu->mmio_phys_addr, *(u64 *)val);
                vcpu->mmio_read_completed = 0;
-               return X86EMUL_CONTINUE;
+               return 1;
        }
 
-       ret = vcpu_mmio_gva_to_gpa(vcpu, addr, &gpa, exception, false);
-
-       if (ret < 0)
-               return X86EMUL_PROPAGATE_FAULT;
-
-       if (ret)
-               goto mmio;
-
-       if (kvm_read_guest_virt(ctxt, addr, val, bytes, exception)
-           == X86EMUL_CONTINUE)
-               return X86EMUL_CONTINUE;
+       return 0;
+}
 
-mmio:
-       /*
-        * Is this MMIO handled locally?
-        */
-       handled = vcpu_mmio_read(vcpu, gpa, bytes, val);
+static int read_emulate(struct kvm_vcpu *vcpu, gpa_t gpa,
+                       void *val, int bytes)
+{
+       return !kvm_read_guest(vcpu->kvm, gpa, val, bytes);
+}
 
-       if (handled == bytes)
-               return X86EMUL_CONTINUE;
+static int write_emulate(struct kvm_vcpu *vcpu, gpa_t gpa,
+                        void *val, int bytes)
+{
+       return emulator_write_phys(vcpu, gpa, val, bytes);
+}
 
-       gpa += handled;
-       bytes -= handled;
-       val += handled;
+static int write_mmio(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes, void *val)
+{
+       trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, *(u64 *)val);
+       return vcpu_mmio_write(vcpu, gpa, bytes, val);
+}
 
+static int read_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa,
+                         void *val, int bytes)
+{
        trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0);
-
-       vcpu->mmio_needed = 1;
-       vcpu->run->exit_reason = KVM_EXIT_MMIO;
-       vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa;
-       vcpu->mmio_size = bytes;
-       vcpu->run->mmio.len = min(vcpu->mmio_size, 8);
-       vcpu->run->mmio.is_write = vcpu->mmio_is_write = 0;
-       vcpu->mmio_index = 0;
-
        return X86EMUL_IO_NEEDED;
 }
 
-int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
-                       const void *val, int bytes)
+static int write_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa,
+                          void *val, int bytes)
 {
-       int ret;
-
-       ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes);
-       if (ret < 0)
-               return 0;
-       kvm_mmu_pte_write(vcpu, gpa, val, bytes, 1);
-       return 1;
+       memcpy(vcpu->mmio_data, val, bytes);
+       memcpy(vcpu->run->mmio.data, vcpu->mmio_data, 8);
+       return X86EMUL_CONTINUE;
 }
 
-static int emulator_write_emulated_onepage(unsigned long addr,
-                                          const void *val,
-                                          unsigned int bytes,
-                                          struct x86_exception *exception,
-                                          struct kvm_vcpu *vcpu)
+static struct read_write_emulator_ops read_emultor = {
+       .read_write_prepare = read_prepare,
+       .read_write_emulate = read_emulate,
+       .read_write_mmio = vcpu_mmio_read,
+       .read_write_exit_mmio = read_exit_mmio,
+};
+
+static struct read_write_emulator_ops write_emultor = {
+       .read_write_emulate = write_emulate,
+       .read_write_mmio = write_mmio,
+       .read_write_exit_mmio = write_exit_mmio,
+       .write = true,
+};
+
+static int emulator_read_write_onepage(unsigned long addr, void *val,
+                                      unsigned int bytes,
+                                      struct x86_exception *exception,
+                                      struct kvm_vcpu *vcpu,
+                                      struct read_write_emulator_ops *ops)
 {
        gpa_t gpa;
        int handled, ret;
+       bool write = ops->write;
 
-       ret = vcpu_mmio_gva_to_gpa(vcpu, addr, &gpa, exception, true);
+       if (ops->read_write_prepare &&
+                 ops->read_write_prepare(vcpu, val, bytes))
+               return X86EMUL_CONTINUE;
+
+       ret = vcpu_mmio_gva_to_gpa(vcpu, addr, &gpa, exception, write);
 
        if (ret < 0)
                return X86EMUL_PROPAGATE_FAULT;
@@ -4131,15 +4187,14 @@ static int emulator_write_emulated_onepage(unsigned long addr,
        if (ret)
                goto mmio;
 
-       if (emulator_write_phys(vcpu, gpa, val, bytes))
+       if (ops->read_write_emulate(vcpu, gpa, val, bytes))
                return X86EMUL_CONTINUE;
 
 mmio:
-       trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, *(u64 *)val);
        /*
         * Is this MMIO handled locally?
         */
-       handled = vcpu_mmio_write(vcpu, gpa, bytes, val);
+       handled = ops->read_write_mmio(vcpu, gpa, bytes, val);
        if (handled == bytes)
                return X86EMUL_CONTINUE;
 
@@ -4148,23 +4203,20 @@ mmio:
        val += handled;
 
        vcpu->mmio_needed = 1;
-       memcpy(vcpu->mmio_data, val, bytes);
        vcpu->run->exit_reason = KVM_EXIT_MMIO;
        vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa;
        vcpu->mmio_size = bytes;
        vcpu->run->mmio.len = min(vcpu->mmio_size, 8);
-       vcpu->run->mmio.is_write = vcpu->mmio_is_write = 1;
-       memcpy(vcpu->run->mmio.data, vcpu->mmio_data, 8);
+       vcpu->run->mmio.is_write = vcpu->mmio_is_write = write;
        vcpu->mmio_index = 0;
 
-       return X86EMUL_CONTINUE;
+       return ops->read_write_exit_mmio(vcpu, gpa, val, bytes);
 }
 
-int emulator_write_emulated(struct x86_emulate_ctxt *ctxt,
-                           unsigned long addr,
-                           const void *val,
-                           unsigned int bytes,
-                           struct x86_exception *exception)
+int emulator_read_write(struct x86_emulate_ctxt *ctxt, unsigned long addr,
+                       void *val, unsigned int bytes,
+                       struct x86_exception *exception,
+                       struct read_write_emulator_ops *ops)
 {
        struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
 
@@ -4173,16 +4225,38 @@ int emulator_write_emulated(struct x86_emulate_ctxt *ctxt,
                int rc, now;
 
                now = -addr & ~PAGE_MASK;
-               rc = emulator_write_emulated_onepage(addr, val, now, exception,
-                                                    vcpu);
+               rc = emulator_read_write_onepage(addr, val, now, exception,
+                                                vcpu, ops);
+
                if (rc != X86EMUL_CONTINUE)
                        return rc;
                addr += now;
                val += now;
                bytes -= now;
        }
-       return emulator_write_emulated_onepage(addr, val, bytes, exception,
-                                              vcpu);
+
+       return emulator_read_write_onepage(addr, val, bytes, exception,
+                                          vcpu, ops);
+}
+
+static int emulator_read_emulated(struct x86_emulate_ctxt *ctxt,
+                                 unsigned long addr,
+                                 void *val,
+                                 unsigned int bytes,
+                                 struct x86_exception *exception)
+{
+       return emulator_read_write(ctxt, addr, val, bytes,
+                                  exception, &read_emultor);
+}
+
+int emulator_write_emulated(struct x86_emulate_ctxt *ctxt,
+                           unsigned long addr,
+                           const void *val,
+                           unsigned int bytes,
+                           struct x86_exception *exception)
+{
+       return emulator_read_write(ctxt, addr, (void *)val, bytes,
+                                  exception, &write_emultor);
 }
 
 #define CMPXCHG_TYPE(t, ptr, old, new) \
@@ -4712,7 +4786,7 @@ int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip)
        kvm_set_rflags(vcpu, ctxt->eflags);
 
        if (irq == NMI_VECTOR)
-               vcpu->arch.nmi_pending = false;
+               vcpu->arch.nmi_pending = 0;
        else
                vcpu->arch.interrupt.pending = false;
 
@@ -4788,7 +4862,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
 
                trace_kvm_emulate_insn_start(vcpu);
                ++vcpu->stat.insn_emulation;
-               if (r)  {
+               if (r != EMULATION_OK)  {
                        if (emulation_type & EMULTYPE_TRAP_UD)
                                return EMULATE_FAIL;
                        if (reexecute_instruction(vcpu, cr2))
@@ -5521,7 +5595,7 @@ static void inject_pending_event(struct kvm_vcpu *vcpu)
        /* try to inject new event if pending */
        if (vcpu->arch.nmi_pending) {
                if (kvm_x86_ops->nmi_allowed(vcpu)) {
-                       vcpu->arch.nmi_pending = false;
+                       --vcpu->arch.nmi_pending;
                        vcpu->arch.nmi_injected = true;
                        kvm_x86_ops->set_nmi(vcpu);
                }
@@ -5553,10 +5627,26 @@ static void kvm_put_guest_xcr0(struct kvm_vcpu *vcpu)
        }
 }
 
+static void process_nmi(struct kvm_vcpu *vcpu)
+{
+       unsigned limit = 2;
+
+       /*
+        * x86 is limited to one NMI running, and one NMI pending after it.
+        * If an NMI is already in progress, limit further NMIs to just one.
+        * Otherwise, allow two (and we'll inject the first one immediately).
+        */
+       if (kvm_x86_ops->get_nmi_mask(vcpu) || vcpu->arch.nmi_injected)
+               limit = 1;
+
+       vcpu->arch.nmi_pending += atomic_xchg(&vcpu->arch.nmi_queued, 0);
+       vcpu->arch.nmi_pending = min(vcpu->arch.nmi_pending, limit);
+       kvm_make_request(KVM_REQ_EVENT, vcpu);
+}
+
 static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 {
        int r;
-       bool nmi_pending;
        bool req_int_win = !irqchip_in_kernel(vcpu->kvm) &&
                vcpu->run->request_interrupt_window;
 
@@ -5596,6 +5686,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                }
                if (kvm_check_request(KVM_REQ_STEAL_UPDATE, vcpu))
                        record_steal_time(vcpu);
+               if (kvm_check_request(KVM_REQ_NMI, vcpu))
+                       process_nmi(vcpu);
 
        }
 
@@ -5603,19 +5695,11 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
        if (unlikely(r))
                goto out;
 
-       /*
-        * An NMI can be injected between local nmi_pending read and
-        * vcpu->arch.nmi_pending read inside inject_pending_event().
-        * But in that case, KVM_REQ_EVENT will be set, which makes
-        * the race described above benign.
-        */
-       nmi_pending = ACCESS_ONCE(vcpu->arch.nmi_pending);
-
        if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
                inject_pending_event(vcpu);
 
                /* enable NMI/IRQ window open exits if needed */
-               if (nmi_pending)
+               if (vcpu->arch.nmi_pending)
                        kvm_x86_ops->enable_nmi_window(vcpu);
                else if (kvm_cpu_has_interrupt(vcpu) || req_int_win)
                        kvm_x86_ops->enable_irq_window(vcpu);
@@ -5678,7 +5762,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
        if (hw_breakpoint_active())
                hw_breakpoint_restore();
 
-       kvm_get_msr(vcpu, MSR_IA32_TSC, &vcpu->arch.last_guest_tsc);
+       vcpu->arch.last_guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu);
 
        vcpu->mode = OUTSIDE_GUEST_MODE;
        smp_wmb();
@@ -6323,7 +6407,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 
 int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu)
 {
-       vcpu->arch.nmi_pending = false;
+       atomic_set(&vcpu->arch.nmi_queued, 0);
+       vcpu->arch.nmi_pending = 0;
        vcpu->arch.nmi_injected = false;
 
        vcpu->arch.switch_db_regs = 0;
@@ -6598,7 +6683,7 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
                !vcpu->arch.apf.halted)
                || !list_empty_careful(&vcpu->async_pf.done)
                || vcpu->arch.mp_state == KVM_MP_STATE_SIPI_RECEIVED
-               || vcpu->arch.nmi_pending ||
+               || atomic_read(&vcpu->arch.nmi_queued) ||
                (kvm_arch_interrupt_allowed(vcpu) &&
                 kvm_cpu_has_interrupt(vcpu));
 }
index 9a8bebc..c9eee6d 100644 (file)
@@ -114,10 +114,22 @@ static int f10_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
        return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
 }
 
+/*
+ * Select DCT to which PCI cfg accesses are routed
+ */
+static void f15h_select_dct(struct amd64_pvt *pvt, u8 dct)
+{
+       u32 reg = 0;
+
+       amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, &reg);
+       reg &= 0xfffffffe;
+       reg |= dct;
+       amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg);
+}
+
 static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
                                 const char *func)
 {
-       u32 reg = 0;
        u8 dct  = 0;
 
        if (addr >= 0x140 && addr <= 0x1a0) {
@@ -125,10 +137,7 @@ static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
                addr -= 0x100;
        }
 
-       amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, &reg);
-       reg &= 0xfffffffe;
-       reg |= dct;
-       amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg);
+       f15h_select_dct(pvt, dct);
 
        return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
 }
@@ -198,6 +207,10 @@ static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
        if (boot_cpu_data.x86 == 0xf)
                min_scrubrate = 0x0;
 
+       /* F15h Erratum #505 */
+       if (boot_cpu_data.x86 == 0x15)
+               f15h_select_dct(pvt, 0);
+
        return __amd64_set_scrub_rate(pvt->F3, bw, min_scrubrate);
 }
 
@@ -207,6 +220,10 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
        u32 scrubval = 0;
        int i, retval = -EINVAL;
 
+       /* F15h Erratum #505 */
+       if (boot_cpu_data.x86 == 0x15)
+               f15h_select_dct(pvt, 0);
+
        amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
 
        scrubval = scrubval & 0x001F;
@@ -751,10 +768,10 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
  * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
  * are ECC capable.
  */
-static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt)
+static unsigned long amd64_determine_edac_cap(struct amd64_pvt *pvt)
 {
        u8 bit;
-       enum dev_type edac_cap = EDAC_FLAG_NONE;
+       unsigned long edac_cap = EDAC_FLAG_NONE;
 
        bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= K8_REV_F)
                ? 19
@@ -1953,11 +1970,9 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
                amd64_handle_ue(mci, m);
 }
 
-void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
+void amd64_decode_bus_error(int node_id, struct mce *m)
 {
-       struct mem_ctl_info *mci = mcis[node_id];
-
-       __amd64_decode_bus_error(mci, m);
+       __amd64_decode_bus_error(mcis[node_id], m);
 }
 
 /*
index 795cfbc..d0864d9 100644 (file)
@@ -9,7 +9,7 @@ static u8 xec_mask       = 0xf;
 static u8 nb_err_cpumask = 0xf;
 
 static bool report_gart_errors;
-static void (*nb_bus_decoder)(int node_id, struct mce *m, u32 nbcfg);
+static void (*nb_bus_decoder)(int node_id, struct mce *m);
 
 void amd_report_gart_errors(bool v)
 {
@@ -17,13 +17,13 @@ void amd_report_gart_errors(bool v)
 }
 EXPORT_SYMBOL_GPL(amd_report_gart_errors);
 
-void amd_register_ecc_decoder(void (*f)(int, struct mce *, u32))
+void amd_register_ecc_decoder(void (*f)(int, struct mce *))
 {
        nb_bus_decoder = f;
 }
 EXPORT_SYMBOL_GPL(amd_register_ecc_decoder);
 
-void amd_unregister_ecc_decoder(void (*f)(int, struct mce *, u32))
+void amd_unregister_ecc_decoder(void (*f)(int, struct mce *))
 {
        if (nb_bus_decoder) {
                WARN_ON(nb_bus_decoder != f);
@@ -592,31 +592,14 @@ static bool nb_noop_mce(u16 ec, u8 xec)
        return false;
 }
 
-void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)
+void amd_decode_nb_mce(struct mce *m)
 {
        struct cpuinfo_x86 *c = &boot_cpu_data;
-       u16 ec   = EC(m->status);
-       u8 xec   = XEC(m->status, 0x1f);
-       u32 nbsh = (u32)(m->status >> 32);
-       int core = -1;
-
-       pr_emerg(HW_ERR "Northbridge Error (node %d", node_id);
-
-       /* F10h, revD can disable ErrCpu[3:0] through ErrCpuVal */
-       if (c->x86 == 0x10 && c->x86_model > 7) {
-               if (nbsh & NBSH_ERR_CPU_VAL)
-                       core = nbsh & nb_err_cpumask;
-       } else {
-               u8 assoc_cpus = nbsh & nb_err_cpumask;
-
-               if (assoc_cpus > 0)
-                       core = fls(assoc_cpus) - 1;
-       }
+       int node_id = amd_get_nb_id(m->extcpu);
+       u16 ec = EC(m->status);
+       u8 xec = XEC(m->status, 0x1f);
 
-       if (core >= 0)
-               pr_cont(", core %d): ", core);
-       else
-               pr_cont("): ");
+       pr_emerg(HW_ERR "Northbridge Error (node %d): ", node_id);
 
        switch (xec) {
        case 0x2:
@@ -648,7 +631,7 @@ void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)
 
        if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x15)
                if ((xec == 0x8 || xec == 0x0) && nb_bus_decoder)
-                       nb_bus_decoder(node_id, m, nbcfg);
+                       nb_bus_decoder(node_id, m);
 
        return;
 
@@ -764,13 +747,13 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
 {
        struct mce *m = (struct mce *)data;
        struct cpuinfo_x86 *c = &boot_cpu_data;
-       int node, ecc;
+       int ecc;
 
        if (amd_filter_mce(m))
                return NOTIFY_STOP;
 
-       pr_emerg(HW_ERR "MC%d_STATUS[%s|%s|%s|%s|%s",
-               m->bank,
+       pr_emerg(HW_ERR "CPU:%d\tMC%d_STATUS[%s|%s|%s|%s|%s",
+               m->extcpu, m->bank,
                ((m->status & MCI_STATUS_OVER)  ? "Over"  : "-"),
                ((m->status & MCI_STATUS_UC)    ? "UE"    : "CE"),
                ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
@@ -789,6 +772,8 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
 
        pr_cont("]: 0x%016llx\n", m->status);
 
+       if (m->status & MCI_STATUS_ADDRV)
+               pr_emerg(HW_ERR "\tMC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
 
        switch (m->bank) {
        case 0:
@@ -811,8 +796,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
                break;
 
        case 4:
-               node = amd_get_nb_id(m->extcpu);
-               amd_decode_nb_mce(node, m, 0);
+               amd_decode_nb_mce(m);
                break;
 
        case 5:
index 795a320..0106747 100644 (file)
@@ -86,9 +86,9 @@ struct amd_decoder_ops {
 };
 
 void amd_report_gart_errors(bool);
-void amd_register_ecc_decoder(void (*f)(int, struct mce *, u32));
-void amd_unregister_ecc_decoder(void (*f)(int, struct mce *, u32));
-void amd_decode_nb_mce(int, struct mce *, u32);
+void amd_register_ecc_decoder(void (*f)(int, struct mce *));
+void amd_unregister_ecc_decoder(void (*f)(int, struct mce *));
+void amd_decode_nb_mce(struct mce *);
 int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data);
 
 #endif /* _EDAC_MCE_AMD_H */
index d6d5868..85584a5 100644 (file)
@@ -47,8 +47,8 @@
 /* ----- global variables ---------------------------------------------        */
 
 static int bit_test;   /* see if the line-setting functions work       */
-module_param(bit_test, bool, 0);
-MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
+module_param(bit_test, int, S_IRUGO);
+MODULE_PARM_DESC(bit_test, "lines testing - 0 off; 1 report; 2 fail if stuck");
 
 #ifdef DEBUG
 static int i2c_debug = 1;
@@ -250,7 +250,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
        sda = getsda(adap);
        scl = (adap->getscl == NULL) ? 1 : getscl(adap);
        if (!scl || !sda) {
-               printk(KERN_WARNING "%s: bus seems to be busy\n", name);
+               printk(KERN_WARNING
+                      "%s: bus seems to be busy (scl=%d, sda=%d)\n",
+                      name, scl, sda);
                goto bailout;
        }
 
@@ -441,7 +443,7 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
                                        acknak(i2c_adap, 0);
                                dev_err(&i2c_adap->dev, "readbytes: invalid "
                                        "block length (%d)\n", inval);
-                               return -EREMOTEIO;
+                               return -EPROTO;
                        }
                        /* The original count value accounts for the extra
                           bytes, that is, either 1 for a regular transaction,
@@ -470,7 +472,7 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
  * reads, writes as well as 10bit-addresses.
  * returns:
  *  0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
- * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
+ * -x an error occurred (like: -ENXIO if the device did not answer, or
  *     -ETIMEDOUT, for example if the lines are stuck...)
  */
 static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
@@ -493,14 +495,14 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
                if ((ret != 1) && !nak_ok)  {
                        dev_err(&i2c_adap->dev,
                                "died at extended address code\n");
-                       return -EREMOTEIO;
+                       return -ENXIO;
                }
                /* the remaining 8 bit address */
                ret = i2c_outb(i2c_adap, msg->addr & 0x7f);
                if ((ret != 1) && !nak_ok) {
                        /* the chip did not ack / xmission error occurred */
                        dev_err(&i2c_adap->dev, "died at 2nd address code\n");
-                       return -EREMOTEIO;
+                       return -ENXIO;
                }
                if (flags & I2C_M_RD) {
                        bit_dbg(3, &i2c_adap->dev, "emitting repeated "
@@ -512,7 +514,7 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
                        if ((ret != 1) && !nak_ok) {
                                dev_err(&i2c_adap->dev,
                                        "died at repeated address code\n");
-                               return -EREMOTEIO;
+                               return -EIO;
                        }
                }
        } else {                /* normal 7bit address  */
@@ -570,7 +572,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
                                        ret, ret == 1 ? "" : "s");
                        if (ret < pmsg->len) {
                                if (ret >= 0)
-                                       ret = -EREMOTEIO;
+                                       ret = -EIO;
                                goto bailout;
                        }
                } else {
@@ -581,7 +583,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
                                        ret, ret == 1 ? "" : "s");
                        if (ret < pmsg->len) {
                                if (ret >= 0)
-                                       ret = -EREMOTEIO;
+                                       ret = -EIO;
                                goto bailout;
                        }
                }
@@ -624,7 +626,7 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
 
        if (bit_test) {
                ret = test_bus(adap);
-               if (ret < 0)
+               if (bit_test >= 2 && ret < 0)
                        return -ENODEV;
        }
 
index 4ca9cf9..beb9ffe 100644 (file)
@@ -196,7 +196,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
                } else {
                        dev_dbg(&i2c_adap->dev, "bus is not idle. status is "
                                "%#04x\n", state);
-                       return -EAGAIN;
+                       return -EBUSY;
                }
        }
 
@@ -224,7 +224,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
        }
 
        curmsg = 0;
-       ret = -EREMOTEIO;
+       ret = -EIO;
        while (curmsg < num) {
                state = pca_status(adap);
 
@@ -259,6 +259,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
                case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */
                        DEB2("NOT ACK received after SLA+W\n");
                        pca_stop(adap);
+                       ret = -ENXIO;
                        goto out;
 
                case 0x40: /* SLA+R has been transmitted; ACK has been received */
@@ -283,6 +284,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
                case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */
                        DEB2("NOT ACK received after SLA+R\n");
                        pca_stop(adap);
+                       ret = -ENXIO;
                        goto out;
 
                case 0x30: /* Data byte in I2CDAT has been transmitted; NOT ACK has been received */
index 646068e..d1fc5cf 100644 (file)
@@ -789,7 +789,7 @@ config I2C_ACORN
 
 config I2C_ELEKTOR
        tristate "Elektor ISA card"
-       depends on ISA && BROKEN_ON_SMP
+       depends on ISA && HAS_IOPORT && BROKEN_ON_SMP
        select I2C_ALGOPCF
        help
          This supports the PCF8584 ISA bus I2C adapter.  Say Y if you own
index 986e5f6..91e349c 100644 (file)
@@ -550,7 +550,7 @@ static int __devexit scx200_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct platform_driver scx200_pci_drv = {
+static struct platform_driver scx200_pci_driver = {
        .driver = {
                .name = "cs5535-smb",
                .owner = THIS_MODULE,
@@ -593,14 +593,14 @@ static int __init scx200_acb_init(void)
                return 0;
 
        /* No ISA devices; register the platform driver for PCI-based devices */
-       return platform_driver_register(&scx200_pci_drv);
+       return platform_driver_register(&scx200_pci_driver);
 }
 
 static void __exit scx200_acb_cleanup(void)
 {
        struct scx200_acb_iface *iface;
 
-       platform_driver_unregister(&scx200_pci_drv);
+       platform_driver_unregister(&scx200_pci_driver);
 
        mutex_lock(&scx200_acb_list_mutex);
        while ((iface = scx200_acb_list) != NULL) {
index a1aa35a..56aa465 100644 (file)
@@ -217,22 +217,6 @@ config INPUT_ATLAS_BTNS
          To compile this driver as a module, choose M here: the module will
          be called atlas_btns.
 
-config INPUT_ATI_REMOTE
-       tristate "ATI / X10 USB RF remote control"
-       depends on USB_ARCH_HAS_HCD
-       select USB
-       help
-         Say Y here if you want to use an ATI or X10 "Lola" USB remote control.
-         These are RF remotes with USB receivers.
-         The ATI remote comes with many of ATI's All-In-Wonder video cards.
-         The X10 "Lola" remote is available at:
-            <http://www.x10.com/products/lola_sg1.htm>
-         This driver provides mouse pointer, left and right mouse buttons,
-         and maps all the other remote buttons to keypress events.
-
-         To compile this driver as a module, choose M here: the module will be
-         called ati_remote.
-
 config INPUT_ATI_REMOTE2
        tristate "ATI / Philips USB RF remote control"
        depends on USB_ARCH_HAS_HCD
index 53a8d0f..62dcd79 100644 (file)
@@ -13,7 +13,6 @@ obj-$(CONFIG_INPUT_ADXL34X)           += adxl34x.o
 obj-$(CONFIG_INPUT_ADXL34X_I2C)                += adxl34x-i2c.o
 obj-$(CONFIG_INPUT_ADXL34X_SPI)                += adxl34x-spi.o
 obj-$(CONFIG_INPUT_APANEL)             += apanel.o
-obj-$(CONFIG_INPUT_ATI_REMOTE)         += ati_remote.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)                += ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)         += atlas_btns.o
 obj-$(CONFIG_INPUT_BFIN_ROTARY)                += bfin_rotary.o
diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c
deleted file mode 100644 (file)
index bce5712..0000000
+++ /dev/null
@@ -1,867 +0,0 @@
-/*
- *  USB ATI Remote support
- *
- *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
- *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
- *
- *  This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
- *  porting to the 2.6 kernel interfaces, along with other modification
- *  to better match the style of the existing usb/input drivers.  However, the
- *  protocol and hardware handling is essentially unchanged from 2.1.1.
- *
- *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
- *  Vojtech Pavlik.
- *
- *  Changes:
- *
- *  Feb 2004: Torrey Hoffman <thoffman@arnor.net>
- *            Version 2.2.0
- *  Jun 2004: Torrey Hoffman <thoffman@arnor.net>
- *            Version 2.2.1
- *            Added key repeat support contributed by:
- *                Vincent Vanackere <vanackere@lif.univ-mrs.fr>
- *            Added support for the "Lola" remote contributed by:
- *                Seth Cohn <sethcohn@yahoo.com>
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * Hardware & software notes
- *
- * These remote controls are distributed by ATI as part of their
- * "All-In-Wonder" video card packages.  The receiver self-identifies as a
- * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
- *
- * The "Lola" remote is available from X10.  See:
- *    http://www.x10.com/products/lola_sg1.htm
- * The Lola is similar to the ATI remote but has no mouse support, and slightly
- * different keys.
- *
- * It is possible to use multiple receivers and remotes on multiple computers
- * simultaneously by configuring them to use specific channels.
- *
- * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
- * Actually, it may even support more, at least in some revisions of the
- * hardware.
- *
- * Each remote can be configured to transmit on one channel as follows:
- *   - Press and hold the "hand icon" button.
- *   - When the red LED starts to blink, let go of the "hand icon" button.
- *   - When it stops blinking, input the channel code as two digits, from 01
- *     to 16, and press the hand icon again.
- *
- * The timing can be a little tricky.  Try loading the module with debug=1
- * to have the kernel print out messages about the remote control number
- * and mask.  Note: debugging prints remote numbers as zero-based hexadecimal.
- *
- * The driver has a "channel_mask" parameter. This bitmask specifies which
- * channels will be ignored by the module.  To mask out channels, just add
- * all the 2^channel_number values together.
- *
- * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
- * ignore signals coming from remote controls transmitting on channel 4, but
- * accept all other channels.
- *
- * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
- * ignored.
- *
- * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
- * parameter are unused.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/usb/input.h>
-#include <linux/wait.h>
-#include <linux/jiffies.h>
-
-/*
- * Module and Version Information, Module Parameters
- */
-
-#define ATI_REMOTE_VENDOR_ID           0x0bc7
-#define LOLA_REMOTE_PRODUCT_ID         0x0002
-#define LOLA2_REMOTE_PRODUCT_ID                0x0003
-#define ATI_REMOTE_PRODUCT_ID          0x0004
-#define NVIDIA_REMOTE_PRODUCT_ID       0x0005
-#define MEDION_REMOTE_PRODUCT_ID       0x0006
-
-#define DRIVER_VERSION         "2.2.1"
-#define DRIVER_AUTHOR           "Torrey Hoffman <thoffman@arnor.net>"
-#define DRIVER_DESC             "ATI/X10 RF USB Remote Control"
-
-#define NAME_BUFSIZE      80    /* size of product name, path buffers */
-#define DATA_BUFSIZE      63    /* size of URB data buffers */
-
-/*
- * Duplicate event filtering time.
- * Sequential, identical KIND_FILTERED inputs with less than
- * FILTER_TIME milliseconds between them are considered as repeat
- * events. The hardware generates 5 events for the first keypress
- * and we have to take this into account for an accurate repeat
- * behaviour.
- */
-#define FILTER_TIME    60 /* msec */
-#define REPEAT_DELAY   500 /* msec */
-
-static unsigned long channel_mask;
-module_param(channel_mask, ulong, 0644);
-MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
-
-static int repeat_filter = FILTER_TIME;
-module_param(repeat_filter, int, 0644);
-MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec");
-
-static int repeat_delay = REPEAT_DELAY;
-module_param(repeat_delay, int, 0644);
-MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec");
-
-#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
-#undef err
-#define err(format, arg...) printk(KERN_ERR format , ## arg)
-
-static struct usb_device_id ati_remote_table[] = {
-       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
-       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) },
-       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
-       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) },
-       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) },
-       {}      /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, ati_remote_table);
-
-/* Get hi and low bytes of a 16-bits int */
-#define HI(a)  ((unsigned char)((a) >> 8))
-#define LO(a)  ((unsigned char)((a) & 0xff))
-
-#define SEND_FLAG_IN_PROGRESS  1
-#define SEND_FLAG_COMPLETE     2
-
-/* Device initialization strings */
-static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
-static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
-
-struct ati_remote {
-       struct input_dev *idev;
-       struct usb_device *udev;
-       struct usb_interface *interface;
-
-       struct urb *irq_urb;
-       struct urb *out_urb;
-       struct usb_endpoint_descriptor *endpoint_in;
-       struct usb_endpoint_descriptor *endpoint_out;
-       unsigned char *inbuf;
-       unsigned char *outbuf;
-       dma_addr_t inbuf_dma;
-       dma_addr_t outbuf_dma;
-
-       unsigned char old_data[2];  /* Detect duplicate events */
-       unsigned long old_jiffies;
-       unsigned long acc_jiffies;  /* handle acceleration */
-       unsigned long first_jiffies;
-
-       unsigned int repeat_count;
-
-       char name[NAME_BUFSIZE];
-       char phys[NAME_BUFSIZE];
-
-       wait_queue_head_t wait;
-       int send_flags;
-};
-
-/* "Kinds" of messages sent from the hardware to the driver. */
-#define KIND_END        0
-#define KIND_LITERAL    1   /* Simply pass to input system */
-#define KIND_FILTERED   2   /* Add artificial key-up events, drop keyrepeats */
-#define KIND_LU         3   /* Directional keypad diagonals - left up, */
-#define KIND_RU         4   /*   right up,  */
-#define KIND_LD         5   /*   left down, */
-#define KIND_RD         6   /*   right down */
-#define KIND_ACCEL      7   /* Directional keypad - left, right, up, down.*/
-
-/* Translation table from hardware messages to input events. */
-static const struct {
-       short kind;
-       unsigned char data1, data2;
-       int type;
-       unsigned int code;
-       int value;
-}  ati_remote_tbl[] = {
-       /* Directional control pad axes */
-       {KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},   /* left */
-       {KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
-       {KIND_ACCEL,   0x37, 0x72, EV_REL, REL_Y, -1},   /* up */
-       {KIND_ACCEL,   0x38, 0x73, EV_REL, REL_Y, 1},    /* down */
-       /* Directional control pad diagonals */
-       {KIND_LU,      0x39, 0x74, EV_REL, 0, 0},        /* left up */
-       {KIND_RU,      0x3a, 0x75, EV_REL, 0, 0},        /* right up */
-       {KIND_LD,      0x3c, 0x77, EV_REL, 0, 0},        /* left down */
-       {KIND_RD,      0x3b, 0x76, EV_REL, 0, 0},        /* right down */
-
-       /* "Mouse button" buttons */
-       {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */
-       {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */
-       {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
-       {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
-
-       /* Artificial "doubleclick" events are generated by the hardware.
-        * They are mapped to the "side" and "extra" mouse buttons here. */
-       {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
-       {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
-
-       /* keyboard. */
-       {KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
-       {KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
-       {KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
-       {KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
-       {KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
-       {KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
-       {KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
-       {KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
-       {KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
-       {KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
-       {KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1},
-       {KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1},
-       {KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1},
-       {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1},
-       {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1},
-       {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1},
-
-       /* "special" keys */
-       {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1},    /* "check" */
-       {KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1},       /* "menu" */
-       {KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1},      /* Power */
-       {KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1},         /* TV */
-       {KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1},        /* DVD */
-       {KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1},        /* WEB */
-       {KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1},  /* "book" */
-       {KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1},       /* "hand" */
-       {KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1},     /* "timer" */
-       {KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1},      /* "max" */
-       {KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1},       /* left */
-       {KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1},      /* right */
-       {KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},       /* down */
-       {KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},         /* up */
-       {KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1},         /* "OK" */
-       {KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */
-       {KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1},   /* VOL - */
-       {KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1},       /* MUTE  */
-       {KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
-       {KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
-       {KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},     /* ( o) red */
-       {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},       /* ( >) */
-       {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
-       {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
-       {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */
-       {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1},      /* ('') */
-       {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1},   /* (<-) */
-       {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1},       /* (>+) */
-       {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1},       /* PLAYING */
-       {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1},       /* TOP */
-       {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1},        /* END */
-       {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */
-
-       {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
-};
-
-/* Local function prototypes */
-static int ati_remote_open             (struct input_dev *inputdev);
-static void ati_remote_close           (struct input_dev *inputdev);
-static int ati_remote_sendpacket       (struct ati_remote *ati_remote, u16 cmd, unsigned char *data);
-static void ati_remote_irq_out         (struct urb *urb);
-static void ati_remote_irq_in          (struct urb *urb);
-static void ati_remote_input_report    (struct urb *urb);
-static int ati_remote_initialize       (struct ati_remote *ati_remote);
-static int ati_remote_probe            (struct usb_interface *interface, const struct usb_device_id *id);
-static void ati_remote_disconnect      (struct usb_interface *interface);
-
-/* usb specific object to register with the usb subsystem */
-static struct usb_driver ati_remote_driver = {
-       .name         = "ati_remote",
-       .probe        = ati_remote_probe,
-       .disconnect   = ati_remote_disconnect,
-       .id_table     = ati_remote_table,
-};
-
-/*
- *     ati_remote_dump_input
- */
-static void ati_remote_dump(struct device *dev, unsigned char *data,
-                           unsigned int len)
-{
-       if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
-               dev_warn(dev, "Weird byte 0x%02x\n", data[0]);
-       else if (len == 4)
-               dev_warn(dev, "Weird key %02x %02x %02x %02x\n",
-                    data[0], data[1], data[2], data[3]);
-       else
-               dev_warn(dev, "Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n",
-                    len, data[0], data[1], data[2], data[3], data[4], data[5]);
-}
-
-/*
- *     ati_remote_open
- */
-static int ati_remote_open(struct input_dev *inputdev)
-{
-       struct ati_remote *ati_remote = input_get_drvdata(inputdev);
-
-       /* On first open, submit the read urb which was set up previously. */
-       ati_remote->irq_urb->dev = ati_remote->udev;
-       if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
-               dev_err(&ati_remote->interface->dev,
-                       "%s: usb_submit_urb failed!\n", __func__);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*
- *     ati_remote_close
- */
-static void ati_remote_close(struct input_dev *inputdev)
-{
-       struct ati_remote *ati_remote = input_get_drvdata(inputdev);
-
-       usb_kill_urb(ati_remote->irq_urb);
-}
-
-/*
- *             ati_remote_irq_out
- */
-static void ati_remote_irq_out(struct urb *urb)
-{
-       struct ati_remote *ati_remote = urb->context;
-
-       if (urb->status) {
-               dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
-                       __func__, urb->status);
-               return;
-       }
-
-       ati_remote->send_flags |= SEND_FLAG_COMPLETE;
-       wmb();
-       wake_up(&ati_remote->wait);
-}
-
-/*
- *     ati_remote_sendpacket
- *
- *     Used to send device initialization strings
- */
-static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
-{
-       int retval = 0;
-
-       /* Set up out_urb */
-       memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
-       ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
-
-       ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
-       ati_remote->out_urb->dev = ati_remote->udev;
-       ati_remote->send_flags = SEND_FLAG_IN_PROGRESS;
-
-       retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
-       if (retval) {
-               dev_dbg(&ati_remote->interface->dev,
-                        "sendpacket: usb_submit_urb failed: %d\n", retval);
-               return retval;
-       }
-
-       wait_event_timeout(ati_remote->wait,
-               ((ati_remote->out_urb->status != -EINPROGRESS) ||
-                       (ati_remote->send_flags & SEND_FLAG_COMPLETE)),
-               HZ);
-       usb_kill_urb(ati_remote->out_urb);
-
-       return retval;
-}
-
-/*
- *     ati_remote_event_lookup
- */
-static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
-{
-       int i;
-
-       for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
-               /*
-                * Decide if the table entry matches the remote input.
-                */
-               if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
-                   ((((ati_remote_tbl[i].data1 >> 4) -
-                      (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
-                   (ati_remote_tbl[i].data2 == d2))
-                       return i;
-
-       }
-       return -1;
-}
-
-/*
- *     ati_remote_compute_accel
- *
- * Implements acceleration curve for directional control pad
- * If elapsed time since last event is > 1/4 second, user "stopped",
- * so reset acceleration. Otherwise, user is probably holding the control
- * pad down, so we increase acceleration, ramping up over two seconds to
- * a maximum speed.
- */
-static int ati_remote_compute_accel(struct ati_remote *ati_remote)
-{
-       static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
-       unsigned long now = jiffies;
-       int acc;
-
-       if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) {
-               acc = 1;
-               ati_remote->acc_jiffies = now;
-       }
-       else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125)))
-               acc = accel[0];
-       else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250)))
-               acc = accel[1];
-       else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500)))
-               acc = accel[2];
-       else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000)))
-               acc = accel[3];
-       else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500)))
-               acc = accel[4];
-       else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000)))
-               acc = accel[5];
-       else
-               acc = accel[6];
-
-       return acc;
-}
-
-/*
- *     ati_remote_report_input
- */
-static void ati_remote_input_report(struct urb *urb)
-{
-       struct ati_remote *ati_remote = urb->context;
-       unsigned char *data= ati_remote->inbuf;
-       struct input_dev *dev = ati_remote->idev;
-       int index, acc;
-       int remote_num;
-
-       /* Deal with strange looking inputs */
-       if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
-               ((data[3] & 0x0f) != 0x00) ) {
-               ati_remote_dump(&urb->dev->dev, data, urb->actual_length);
-               return;
-       }
-
-       /* Mask unwanted remote channels.  */
-       /* note: remote_num is 0-based, channel 1 on remote == 0 here */
-       remote_num = (data[3] >> 4) & 0x0f;
-        if (channel_mask & (1 << (remote_num + 1))) {
-               dbginfo(&ati_remote->interface->dev,
-                       "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
-                       remote_num, data[1], data[2], channel_mask);
-               return;
-       }
-
-       /* Look up event code index in translation table */
-       index = ati_remote_event_lookup(remote_num, data[1], data[2]);
-       if (index < 0) {
-               dev_warn(&ati_remote->interface->dev,
-                        "Unknown input from channel 0x%02x: data %02x,%02x\n",
-                        remote_num, data[1], data[2]);
-               return;
-       }
-       dbginfo(&ati_remote->interface->dev,
-               "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
-               remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
-
-       if (ati_remote_tbl[index].kind == KIND_LITERAL) {
-               input_event(dev, ati_remote_tbl[index].type,
-                       ati_remote_tbl[index].code,
-                       ati_remote_tbl[index].value);
-               input_sync(dev);
-
-               ati_remote->old_jiffies = jiffies;
-               return;
-       }
-
-       if (ati_remote_tbl[index].kind == KIND_FILTERED) {
-               unsigned long now = jiffies;
-
-               /* Filter duplicate events which happen "too close" together. */
-               if (ati_remote->old_data[0] == data[1] &&
-                   ati_remote->old_data[1] == data[2] &&
-                   time_before(now, ati_remote->old_jiffies +
-                                    msecs_to_jiffies(repeat_filter))) {
-                       ati_remote->repeat_count++;
-               } else {
-                       ati_remote->repeat_count = 0;
-                       ati_remote->first_jiffies = now;
-               }
-
-               ati_remote->old_data[0] = data[1];
-               ati_remote->old_data[1] = data[2];
-               ati_remote->old_jiffies = now;
-
-               /* Ensure we skip at least the 4 first duplicate events (generated
-                * by a single keypress), and continue skipping until repeat_delay
-                * msecs have passed
-                */
-               if (ati_remote->repeat_count > 0 &&
-                   (ati_remote->repeat_count < 5 ||
-                    time_before(now, ati_remote->first_jiffies +
-                                     msecs_to_jiffies(repeat_delay))))
-                       return;
-
-
-               input_event(dev, ati_remote_tbl[index].type,
-                       ati_remote_tbl[index].code, 1);
-               input_sync(dev);
-               input_event(dev, ati_remote_tbl[index].type,
-                       ati_remote_tbl[index].code, 0);
-               input_sync(dev);
-
-       } else {
-
-               /*
-                * Other event kinds are from the directional control pad, and have an
-                * acceleration factor applied to them.  Without this acceleration, the
-                * control pad is mostly unusable.
-                */
-               acc = ati_remote_compute_accel(ati_remote);
-
-               switch (ati_remote_tbl[index].kind) {
-               case KIND_ACCEL:
-                       input_event(dev, ati_remote_tbl[index].type,
-                               ati_remote_tbl[index].code,
-                               ati_remote_tbl[index].value * acc);
-                       break;
-               case KIND_LU:
-                       input_report_rel(dev, REL_X, -acc);
-                       input_report_rel(dev, REL_Y, -acc);
-                       break;
-               case KIND_RU:
-                       input_report_rel(dev, REL_X, acc);
-                       input_report_rel(dev, REL_Y, -acc);
-                       break;
-               case KIND_LD:
-                       input_report_rel(dev, REL_X, -acc);
-                       input_report_rel(dev, REL_Y, acc);
-                       break;
-               case KIND_RD:
-                       input_report_rel(dev, REL_X, acc);
-                       input_report_rel(dev, REL_Y, acc);
-                       break;
-               default:
-                       dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
-                               ati_remote_tbl[index].kind);
-               }
-               input_sync(dev);
-
-               ati_remote->old_jiffies = jiffies;
-               ati_remote->old_data[0] = data[1];
-               ati_remote->old_data[1] = data[2];
-       }
-}
-
-/*
- *     ati_remote_irq_in
- */
-static void ati_remote_irq_in(struct urb *urb)
-{
-       struct ati_remote *ati_remote = urb->context;
-       int retval;
-
-       switch (urb->status) {
-       case 0:                 /* success */
-               ati_remote_input_report(urb);
-               break;
-       case -ECONNRESET:       /* unlink */
-       case -ENOENT:
-       case -ESHUTDOWN:
-               dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
-                       __func__);
-               return;
-       default:                /* error */
-               dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
-                       __func__, urb->status);
-       }
-
-       retval = usb_submit_urb(urb, GFP_ATOMIC);
-       if (retval)
-               dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
-                       __func__, retval);
-}
-
-/*
- *     ati_remote_alloc_buffers
- */
-static int ati_remote_alloc_buffers(struct usb_device *udev,
-                                   struct ati_remote *ati_remote)
-{
-       ati_remote->inbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
-                                              &ati_remote->inbuf_dma);
-       if (!ati_remote->inbuf)
-               return -1;
-
-       ati_remote->outbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
-                                               &ati_remote->outbuf_dma);
-       if (!ati_remote->outbuf)
-               return -1;
-
-       ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!ati_remote->irq_urb)
-               return -1;
-
-       ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!ati_remote->out_urb)
-               return -1;
-
-       return 0;
-}
-
-/*
- *     ati_remote_free_buffers
- */
-static void ati_remote_free_buffers(struct ati_remote *ati_remote)
-{
-       usb_free_urb(ati_remote->irq_urb);
-       usb_free_urb(ati_remote->out_urb);
-
-       usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
-               ati_remote->inbuf, ati_remote->inbuf_dma);
-
-       usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
-               ati_remote->outbuf, ati_remote->outbuf_dma);
-}
-
-static void ati_remote_input_init(struct ati_remote *ati_remote)
-{
-       struct input_dev *idev = ati_remote->idev;
-       int i;
-
-       idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
-       idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
-               BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
-       idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
-       for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
-               if (ati_remote_tbl[i].type == EV_KEY)
-                       set_bit(ati_remote_tbl[i].code, idev->keybit);
-
-       input_set_drvdata(idev, ati_remote);
-
-       idev->open = ati_remote_open;
-       idev->close = ati_remote_close;
-
-       idev->name = ati_remote->name;
-       idev->phys = ati_remote->phys;
-
-       usb_to_input_id(ati_remote->udev, &idev->id);
-       idev->dev.parent = &ati_remote->udev->dev;
-}
-
-static int ati_remote_initialize(struct ati_remote *ati_remote)
-{
-       struct usb_device *udev = ati_remote->udev;
-       int pipe, maxp;
-
-       init_waitqueue_head(&ati_remote->wait);
-
-       /* Set up irq_urb */
-       pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
-       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-       maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
-
-       usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
-                        maxp, ati_remote_irq_in, ati_remote,
-                        ati_remote->endpoint_in->bInterval);
-       ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
-       ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       /* Set up out_urb */
-       pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
-       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-       maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
-
-       usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
-                        maxp, ati_remote_irq_out, ati_remote,
-                        ati_remote->endpoint_out->bInterval);
-       ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
-       ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       /* send initialization strings */
-       if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
-           (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
-               dev_err(&ati_remote->interface->dev,
-                        "Initializing ati_remote hardware failed.\n");
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*
- *     ati_remote_probe
- */
-static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(interface);
-       struct usb_host_interface *iface_host = interface->cur_altsetting;
-       struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
-       struct ati_remote *ati_remote;
-       struct input_dev *input_dev;
-       int err = -ENOMEM;
-
-       if (iface_host->desc.bNumEndpoints != 2) {
-               err("%s: Unexpected desc.bNumEndpoints\n", __func__);
-               return -ENODEV;
-       }
-
-       endpoint_in = &iface_host->endpoint[0].desc;
-       endpoint_out = &iface_host->endpoint[1].desc;
-
-       if (!usb_endpoint_is_int_in(endpoint_in)) {
-               err("%s: Unexpected endpoint_in\n", __func__);
-               return -ENODEV;
-       }
-       if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {
-               err("%s: endpoint_in message size==0? \n", __func__);
-               return -ENODEV;
-       }
-
-       ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!ati_remote || !input_dev)
-               goto fail1;
-
-       /* Allocate URB buffers, URBs */
-       if (ati_remote_alloc_buffers(udev, ati_remote))
-               goto fail2;
-
-       ati_remote->endpoint_in = endpoint_in;
-       ati_remote->endpoint_out = endpoint_out;
-       ati_remote->udev = udev;
-       ati_remote->idev = input_dev;
-       ati_remote->interface = interface;
-
-       usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys));
-       strlcat(ati_remote->phys, "/input0", sizeof(ati_remote->phys));
-
-       if (udev->manufacturer)
-               strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name));
-
-       if (udev->product)
-               snprintf(ati_remote->name, sizeof(ati_remote->name),
-                        "%s %s", ati_remote->name, udev->product);
-
-       if (!strlen(ati_remote->name))
-               snprintf(ati_remote->name, sizeof(ati_remote->name),
-                       DRIVER_DESC "(%04x,%04x)",
-                       le16_to_cpu(ati_remote->udev->descriptor.idVendor),
-                       le16_to_cpu(ati_remote->udev->descriptor.idProduct));
-
-       ati_remote_input_init(ati_remote);
-
-       /* Device Hardware Initialization - fills in ati_remote->idev from udev. */
-       err = ati_remote_initialize(ati_remote);
-       if (err)
-               goto fail3;
-
-       /* Set up and register input device */
-       err = input_register_device(ati_remote->idev);
-       if (err)
-               goto fail3;
-
-       usb_set_intfdata(interface, ati_remote);
-       return 0;
-
- fail3:        usb_kill_urb(ati_remote->irq_urb);
-       usb_kill_urb(ati_remote->out_urb);
- fail2:        ati_remote_free_buffers(ati_remote);
- fail1:        input_free_device(input_dev);
-       kfree(ati_remote);
-       return err;
-}
-
-/*
- *     ati_remote_disconnect
- */
-static void ati_remote_disconnect(struct usb_interface *interface)
-{
-       struct ati_remote *ati_remote;
-
-       ati_remote = usb_get_intfdata(interface);
-       usb_set_intfdata(interface, NULL);
-       if (!ati_remote) {
-               dev_warn(&interface->dev, "%s - null device?\n", __func__);
-               return;
-       }
-
-       usb_kill_urb(ati_remote->irq_urb);
-       usb_kill_urb(ati_remote->out_urb);
-       input_unregister_device(ati_remote->idev);
-       ati_remote_free_buffers(ati_remote);
-       kfree(ati_remote);
-}
-
-/*
- *     ati_remote_init
- */
-static int __init ati_remote_init(void)
-{
-       int result;
-
-       result = usb_register(&ati_remote_driver);
-       if (result)
-               printk(KERN_ERR KBUILD_MODNAME
-                      ": usb_register error #%d\n", result);
-       else
-               printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-                      DRIVER_DESC "\n");
-
-       return result;
-}
-
-/*
- *     ati_remote_exit
- */
-static void __exit ati_remote_exit(void)
-{
-       usb_deregister(&ati_remote_driver);
-}
-
-/*
- *     module specification
- */
-
-module_init(ati_remote_init);
-module_exit(ati_remote_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
index 7d7eaa1..5414253 100644 (file)
@@ -112,4 +112,23 @@ config IRQ_REMAP
          To use x2apic mode in the CPU's which support x2APIC enhancements or
          to support platforms with CPU's having > 8 bit APIC ID, say Y.
 
+# OMAP IOMMU support
+config OMAP_IOMMU
+       bool "OMAP IOMMU Support"
+       depends on ARCH_OMAP
+       select IOMMU_API
+
+config OMAP_IOVMM
+       tristate "OMAP IO Virtual Memory Manager Support"
+       depends on OMAP_IOMMU
+
+config OMAP_IOMMU_DEBUG
+       tristate "Export OMAP IOMMU/IOVMM internals in DebugFS"
+       depends on OMAP_IOVMM && DEBUG_FS
+       help
+         Select this to see extensive information about
+         the internal state of OMAP IOMMU/IOVMM in debugfs.
+
+         Say N unless you know you need this.
+
 endif # IOMMU_SUPPORT
index 6394994..2f44487 100644 (file)
@@ -4,3 +4,6 @@ obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
 obj-$(CONFIG_DMAR_TABLE) += dmar.o
 obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o
 obj-$(CONFIG_IRQ_REMAP) += intr_remapping.o
+obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
+obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o
+obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
index 0e4227f..4ee277a 100644 (file)
@@ -1283,7 +1283,7 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom,
                if (!pte || !IOMMU_PTE_PRESENT(*pte))
                        continue;
 
-               dma_ops_reserve_addresses(dma_dom, i << PAGE_SHIFT, 1);
+               dma_ops_reserve_addresses(dma_dom, i >> PAGE_SHIFT, 1);
        }
 
        update_domain(&dma_dom->domain);
@@ -2495,7 +2495,7 @@ static unsigned device_dma_ops_init(void)
 
 void __init amd_iommu_init_api(void)
 {
-       register_iommu(&amd_iommu_ops);
+       bus_set_iommu(&pci_bus_type, &amd_iommu_ops);
 }
 
 int __init amd_iommu_init_dma_ops(void)
index be1953c..bb161d2 100644 (file)
@@ -3642,7 +3642,7 @@ int __init intel_iommu_init(void)
 
        init_iommu_pm_ops();
 
-       register_iommu(&intel_iommu_ops);
+       bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
 
        bus_register_notifier(&pci_bus_type, &device_nb);
 
index 6e6b6a1..2fb2963 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <linux/device.h>
+#include <linux/kernel.h>
 #include <linux/bug.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/iommu.h>
 
-static struct iommu_ops *iommu_ops;
+static void iommu_bus_init(struct bus_type *bus, struct iommu_ops *ops)
+{
+}
 
-void register_iommu(struct iommu_ops *ops)
+/**
+ * bus_set_iommu - set iommu-callbacks for the bus
+ * @bus: bus.
+ * @ops: the callbacks provided by the iommu-driver
+ *
+ * This function is called by an iommu driver to set the iommu methods
+ * used for a particular bus. Drivers for devices on that bus can use
+ * the iommu-api after these ops are registered.
+ * This special function is needed because IOMMUs are usually devices on
+ * the bus itself, so the iommu drivers are not initialized when the bus
+ * is set up. With this function the iommu-driver can set the iommu-ops
+ * afterwards.
+ */
+int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops)
 {
-       if (iommu_ops)
-               BUG();
+       if (bus->iommu_ops != NULL)
+               return -EBUSY;
+
+       bus->iommu_ops = ops;
+
+       /* Do IOMMU specific setup for this bus-type */
+       iommu_bus_init(bus, ops);
 
-       iommu_ops = ops;
+       return 0;
 }
+EXPORT_SYMBOL_GPL(bus_set_iommu);
 
-bool iommu_found(void)
+bool iommu_present(struct bus_type *bus)
 {
-       return iommu_ops != NULL;
+       return bus->iommu_ops != NULL;
 }
-EXPORT_SYMBOL_GPL(iommu_found);
+EXPORT_SYMBOL_GPL(iommu_present);
 
-struct iommu_domain *iommu_domain_alloc(void)
+/**
+ * iommu_set_fault_handler() - set a fault handler for an iommu domain
+ * @domain: iommu domain
+ * @handler: fault handler
+ *
+ * This function should be used by IOMMU users which want to be notified
+ * whenever an IOMMU fault happens.
+ *
+ * The fault handler itself should return 0 on success, and an appropriate
+ * error code otherwise.
+ */
+void iommu_set_fault_handler(struct iommu_domain *domain,
+                                       iommu_fault_handler_t handler)
+{
+       BUG_ON(!domain);
+
+       domain->handler = handler;
+}
+EXPORT_SYMBOL_GPL(iommu_set_fault_handler);
+
+struct iommu_domain *iommu_domain_alloc(struct bus_type *bus)
 {
        struct iommu_domain *domain;
        int ret;
 
+       if (bus == NULL || bus->iommu_ops == NULL)
+               return NULL;
+
        domain = kmalloc(sizeof(*domain), GFP_KERNEL);
        if (!domain)
                return NULL;
 
-       ret = iommu_ops->domain_init(domain);
+       domain->ops = bus->iommu_ops;
+
+       ret = domain->ops->domain_init(domain);
        if (ret)
                goto out_free;
 
@@ -63,62 +111,78 @@ EXPORT_SYMBOL_GPL(iommu_domain_alloc);
 
 void iommu_domain_free(struct iommu_domain *domain)
 {
-       iommu_ops->domain_destroy(domain);
+       if (likely(domain->ops->domain_destroy != NULL))
+               domain->ops->domain_destroy(domain);
+
        kfree(domain);
 }
 EXPORT_SYMBOL_GPL(iommu_domain_free);
 
 int iommu_attach_device(struct iommu_domain *domain, struct device *dev)
 {
-       return iommu_ops->attach_dev(domain, dev);
+       if (unlikely(domain->ops->attach_dev == NULL))
+               return -ENODEV;
+
+       return domain->ops->attach_dev(domain, dev);
 }
 EXPORT_SYMBOL_GPL(iommu_attach_device);
 
 void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
 {
-       iommu_ops->detach_dev(domain, dev);
+       if (unlikely(domain->ops->detach_dev == NULL))
+               return;
+
+       domain->ops->detach_dev(domain, dev);
 }
 EXPORT_SYMBOL_GPL(iommu_detach_device);
 
 phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
                               unsigned long iova)
 {
-       return iommu_ops->iova_to_phys(domain, iova);
+       if (unlikely(domain->ops->iova_to_phys == NULL))
+               return 0;
+
+       return domain->ops->iova_to_phys(domain, iova);
 }
 EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
 
 int iommu_domain_has_cap(struct iommu_domain *domain,
                         unsigned long cap)
 {
-       return iommu_ops->domain_has_cap(domain, cap);
+       if (unlikely(domain->ops->domain_has_cap == NULL))
+               return 0;
+
+       return domain->ops->domain_has_cap(domain, cap);
 }
 EXPORT_SYMBOL_GPL(iommu_domain_has_cap);
 
 int iommu_map(struct iommu_domain *domain, unsigned long iova,
              phys_addr_t paddr, int gfp_order, int prot)
 {
-       unsigned long invalid_mask;
        size_t size;
 
-       size         = 0x1000UL << gfp_order;
-       invalid_mask = size - 1;
+       if (unlikely(domain->ops->map == NULL))
+               return -ENODEV;
 
-       BUG_ON((iova | paddr) & invalid_mask);
+       size         = PAGE_SIZE << gfp_order;
 
-       return iommu_ops->map(domain, iova, paddr, gfp_order, prot);
+       BUG_ON(!IS_ALIGNED(iova | paddr, size));
+
+       return domain->ops->map(domain, iova, paddr, gfp_order, prot);
 }
 EXPORT_SYMBOL_GPL(iommu_map);
 
 int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order)
 {
-       unsigned long invalid_mask;
        size_t size;
 
-       size         = 0x1000UL << gfp_order;
-       invalid_mask = size - 1;
+       if (unlikely(domain->ops->unmap == NULL))
+               return -ENODEV;
+
+       size         = PAGE_SIZE << gfp_order;
 
-       BUG_ON(iova & invalid_mask);
+       BUG_ON(!IS_ALIGNED(iova, size));
 
-       return iommu_ops->unmap(domain, iova, gfp_order);
+       return domain->ops->unmap(domain, iova, gfp_order);
 }
 EXPORT_SYMBOL_GPL(iommu_unmap);
index 1a584e0..5865dd2 100644 (file)
@@ -543,6 +543,13 @@ static int msm_iommu_unmap(struct iommu_domain *domain, unsigned long va,
        }
 
        ret = __flush_iotlb(domain);
+
+       /*
+        * the IOMMU API requires us to return the order of the unmapped
+        * page (on success).
+        */
+       if (!ret)
+               ret = order;
 fail:
        spin_unlock_irqrestore(&msm_iommu_lock, flags);
        return ret;
@@ -721,7 +728,7 @@ static void __init setup_iommu_tex_classes(void)
 static int __init msm_iommu_init(void)
 {
        setup_iommu_tex_classes();
-       register_iommu(&msm_iommu_ops);
+       bus_set_iommu(&platform_bus_type, &msm_iommu_ops);
        return 0;
 }
 
diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c
new file mode 100644 (file)
index 0000000..9c192e7
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ * omap iommu: debugfs interface
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
+
+#include <plat/iopgtable.h>
+
+#define MAXCOLUMN 100 /* for short messages */
+
+static DEFINE_MUTEX(iommu_debug_lock);
+
+static struct dentry *iommu_debug_root;
+
+static ssize_t debug_read_ver(struct file *file, char __user *userbuf,
+                             size_t count, loff_t *ppos)
+{
+       u32 ver = omap_iommu_arch_version();
+       char buf[MAXCOLUMN], *p = buf;
+
+       p += sprintf(p, "H/W version: %d.%d\n", (ver >> 4) & 0xf , ver & 0xf);
+
+       return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+
+static ssize_t debug_read_regs(struct file *file, char __user *userbuf,
+                              size_t count, loff_t *ppos)
+{
+       struct omap_iommu *obj = file->private_data;
+       char *p, *buf;
+       ssize_t bytes;
+
+       buf = kmalloc(count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       p = buf;
+
+       mutex_lock(&iommu_debug_lock);
+
+       bytes = omap_iommu_dump_ctx(obj, p, count);
+       bytes = simple_read_from_buffer(userbuf, count, ppos, buf, bytes);
+
+       mutex_unlock(&iommu_debug_lock);
+       kfree(buf);
+
+       return bytes;
+}
+
+static ssize_t debug_read_tlb(struct file *file, char __user *userbuf,
+                             size_t count, loff_t *ppos)
+{
+       struct omap_iommu *obj = file->private_data;
+       char *p, *buf;
+       ssize_t bytes, rest;
+
+       buf = kmalloc(count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       p = buf;
+
+       mutex_lock(&iommu_debug_lock);
+
+       p += sprintf(p, "%8s %8s\n", "cam:", "ram:");
+       p += sprintf(p, "-----------------------------------------\n");
+       rest = count - (p - buf);
+       p += omap_dump_tlb_entries(obj, p, rest);
+
+       bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+
+       mutex_unlock(&iommu_debug_lock);
+       kfree(buf);
+
+       return bytes;
+}
+
+static ssize_t debug_write_pagetable(struct file *file,
+                    const char __user *userbuf, size_t count, loff_t *ppos)
+{
+       struct iotlb_entry e;
+       struct cr_regs cr;
+       int err;
+       struct omap_iommu *obj = file->private_data;
+       char buf[MAXCOLUMN], *p = buf;
+
+       count = min(count, sizeof(buf));
+
+       mutex_lock(&iommu_debug_lock);
+       if (copy_from_user(p, userbuf, count)) {
+               mutex_unlock(&iommu_debug_lock);
+               return -EFAULT;
+       }
+
+       sscanf(p, "%x %x", &cr.cam, &cr.ram);
+       if (!cr.cam || !cr.ram) {
+               mutex_unlock(&iommu_debug_lock);
+               return -EINVAL;
+       }
+
+       omap_iotlb_cr_to_e(&cr, &e);
+       err = omap_iopgtable_store_entry(obj, &e);
+       if (err)
+               dev_err(obj->dev, "%s: fail to store cr\n", __func__);
+
+       mutex_unlock(&iommu_debug_lock);
+       return count;
+}
+
+#define dump_ioptable_entry_one(lv, da, val)                   \
+       ({                                                      \
+               int __err = 0;                                  \
+               ssize_t bytes;                                  \
+               const int maxcol = 22;                          \
+               const char *str = "%d: %08x %08x\n";            \
+               bytes = snprintf(p, maxcol, str, lv, da, val);  \
+               p += bytes;                                     \
+               len -= bytes;                                   \
+               if (len < maxcol)                               \
+                       __err = -ENOMEM;                        \
+               __err;                                          \
+       })
+
+static ssize_t dump_ioptable(struct omap_iommu *obj, char *buf, ssize_t len)
+{
+       int i;
+       u32 *iopgd;
+       char *p = buf;
+
+       spin_lock(&obj->page_table_lock);
+
+       iopgd = iopgd_offset(obj, 0);
+       for (i = 0; i < PTRS_PER_IOPGD; i++, iopgd++) {
+               int j, err;
+               u32 *iopte;
+               u32 da;
+
+               if (!*iopgd)
+                       continue;
+
+               if (!(*iopgd & IOPGD_TABLE)) {
+                       da = i << IOPGD_SHIFT;
+
+                       err = dump_ioptable_entry_one(1, da, *iopgd);
+                       if (err)
+                               goto out;
+                       continue;
+               }
+
+               iopte = iopte_offset(iopgd, 0);
+
+               for (j = 0; j < PTRS_PER_IOPTE; j++, iopte++) {
+                       if (!*iopte)
+                               continue;
+
+                       da = (i << IOPGD_SHIFT) + (j << IOPTE_SHIFT);
+                       err = dump_ioptable_entry_one(2, da, *iopgd);
+                       if (err)
+                               goto out;
+               }
+       }
+out:
+       spin_unlock(&obj->page_table_lock);
+
+       return p - buf;
+}
+
+static ssize_t debug_read_pagetable(struct file *file, char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       struct omap_iommu *obj = file->private_data;
+       char *p, *buf;
+       size_t bytes;
+
+       buf = (char *)__get_free_page(GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       p = buf;
+
+       p += sprintf(p, "L: %8s %8s\n", "da:", "pa:");
+       p += sprintf(p, "-----------------------------------------\n");
+
+       mutex_lock(&iommu_debug_lock);
+
+       bytes = PAGE_SIZE - (p - buf);
+       p += dump_ioptable(obj, p, bytes);
+
+       bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+
+       mutex_unlock(&iommu_debug_lock);
+       free_page((unsigned long)buf);
+
+       return bytes;
+}
+
+static ssize_t debug_read_mmap(struct file *file, char __user *userbuf,
+                              size_t count, loff_t *ppos)
+{
+       struct omap_iommu *obj = file->private_data;
+       char *p, *buf;
+       struct iovm_struct *tmp;
+       int uninitialized_var(i);
+       ssize_t bytes;
+
+       buf = (char *)__get_free_page(GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       p = buf;
+
+       p += sprintf(p, "%-3s %-8s %-8s %6s %8s\n",
+                    "No", "start", "end", "size", "flags");
+       p += sprintf(p, "-------------------------------------------------\n");
+
+       mutex_lock(&iommu_debug_lock);
+
+       list_for_each_entry(tmp, &obj->mmap, list) {
+               size_t len;
+               const char *str = "%3d %08x-%08x %6x %8x\n";
+               const int maxcol = 39;
+
+               len = tmp->da_end - tmp->da_start;
+               p += snprintf(p, maxcol, str,
+                             i, tmp->da_start, tmp->da_end, len, tmp->flags);
+
+               if (PAGE_SIZE - (p - buf) < maxcol)
+                       break;
+               i++;
+       }
+
+       bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+
+       mutex_unlock(&iommu_debug_lock);
+       free_page((unsigned long)buf);
+
+       return bytes;
+}
+
+static ssize_t debug_read_mem(struct file *file, char __user *userbuf,
+                             size_t count, loff_t *ppos)
+{
+       struct omap_iommu *obj = file->private_data;
+       char *p, *buf;
+       struct iovm_struct *area;
+       ssize_t bytes;
+
+       count = min_t(ssize_t, count, PAGE_SIZE);
+
+       buf = (char *)__get_free_page(GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       p = buf;
+
+       mutex_lock(&iommu_debug_lock);
+
+       area = omap_find_iovm_area(obj, (u32)ppos);
+       if (IS_ERR(area)) {
+               bytes = -EINVAL;
+               goto err_out;
+       }
+       memcpy(p, area->va, count);
+       p += count;
+
+       bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+err_out:
+       mutex_unlock(&iommu_debug_lock);
+       free_page((unsigned long)buf);
+
+       return bytes;
+}
+
+static ssize_t debug_write_mem(struct file *file, const char __user *userbuf,
+                              size_t count, loff_t *ppos)
+{
+       struct omap_iommu *obj = file->private_data;
+       struct iovm_struct *area;
+       char *p, *buf;
+
+       count = min_t(size_t, count, PAGE_SIZE);
+
+       buf = (char *)__get_free_page(GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       p = buf;
+
+       mutex_lock(&iommu_debug_lock);
+
+       if (copy_from_user(p, userbuf, count)) {
+               count =  -EFAULT;
+               goto err_out;
+       }
+
+       area = omap_find_iovm_area(obj, (u32)ppos);
+       if (IS_ERR(area)) {
+               count = -EINVAL;
+               goto err_out;
+       }
+       memcpy(area->va, p, count);
+err_out:
+       mutex_unlock(&iommu_debug_lock);
+       free_page((unsigned long)buf);
+
+       return count;
+}
+
+static int debug_open_generic(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+#define DEBUG_FOPS(name)                                               \
+       static const struct file_operations debug_##name##_fops = {     \
+               .open = debug_open_generic,                             \
+               .read = debug_read_##name,                              \
+               .write = debug_write_##name,                            \
+               .llseek = generic_file_llseek,                          \
+       };
+
+#define DEBUG_FOPS_RO(name)                                            \
+       static const struct file_operations debug_##name##_fops = {     \
+               .open = debug_open_generic,                             \
+               .read = debug_read_##name,                              \
+               .llseek = generic_file_llseek,                          \
+       };
+
+DEBUG_FOPS_RO(ver);
+DEBUG_FOPS_RO(regs);
+DEBUG_FOPS_RO(tlb);
+DEBUG_FOPS(pagetable);
+DEBUG_FOPS_RO(mmap);
+DEBUG_FOPS(mem);
+
+#define __DEBUG_ADD_FILE(attr, mode)                                   \
+       {                                                               \
+               struct dentry *dent;                                    \
+               dent = debugfs_create_file(#attr, mode, parent,         \
+                                          obj, &debug_##attr##_fops);  \
+               if (!dent)                                              \
+                       return -ENOMEM;                                 \
+       }
+
+#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 600)
+#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 400)
+
+static int iommu_debug_register(struct device *dev, void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct omap_iommu *obj = platform_get_drvdata(pdev);
+       struct dentry *d, *parent;
+
+       if (!obj || !obj->dev)
+               return -EINVAL;
+
+       d = debugfs_create_dir(obj->name, iommu_debug_root);
+       if (!d)
+               return -ENOMEM;
+       parent = d;
+
+       d = debugfs_create_u8("nr_tlb_entries", 400, parent,
+                             (u8 *)&obj->nr_tlb_entries);
+       if (!d)
+               return -ENOMEM;
+
+       DEBUG_ADD_FILE_RO(ver);
+       DEBUG_ADD_FILE_RO(regs);
+       DEBUG_ADD_FILE_RO(tlb);
+       DEBUG_ADD_FILE(pagetable);
+       DEBUG_ADD_FILE_RO(mmap);
+       DEBUG_ADD_FILE(mem);
+
+       return 0;
+}
+
+static int __init iommu_debug_init(void)
+{
+       struct dentry *d;
+       int err;
+
+       d = debugfs_create_dir("iommu", NULL);
+       if (!d)
+               return -ENOMEM;
+       iommu_debug_root = d;
+
+       err = omap_foreach_iommu_device(d, iommu_debug_register);
+       if (err)
+               goto err_out;
+       return 0;
+
+err_out:
+       debugfs_remove_recursive(iommu_debug_root);
+       return err;
+}
+module_init(iommu_debug_init)
+
+static void __exit iommu_debugfs_exit(void)
+{
+       debugfs_remove_recursive(iommu_debug_root);
+}
+module_exit(iommu_debugfs_exit)
+
+MODULE_DESCRIPTION("omap iommu: debugfs interface");
+MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
new file mode 100644 (file)
index 0000000..8f32b2b
--- /dev/null
@@ -0,0 +1,1245 @@
+/*
+ * omap iommu: tlb and pagetable primitives
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>,
+ *             Paul Mundt and Toshihiro Kobayashi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/iommu.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
+#include <asm/cacheflush.h>
+
+#include <plat/iommu.h>
+
+#include <plat/iopgtable.h>
+
+#define for_each_iotlb_cr(obj, n, __i, cr)                             \
+       for (__i = 0;                                                   \
+            (__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true);   \
+            __i++)
+
+/**
+ * struct omap_iommu_domain - omap iommu domain
+ * @pgtable:   the page table
+ * @iommu_dev: an omap iommu device attached to this domain. only a single
+ *             iommu device can be attached for now.
+ * @lock:      domain lock, should be taken when attaching/detaching
+ */
+struct omap_iommu_domain {
+       u32 *pgtable;
+       struct omap_iommu *iommu_dev;
+       spinlock_t lock;
+};
+
+/* accommodate the difference between omap1 and omap2/3 */
+static const struct iommu_functions *arch_iommu;
+
+static struct platform_driver omap_iommu_driver;
+static struct kmem_cache *iopte_cachep;
+
+/**
+ * omap_install_iommu_arch - Install archtecure specific iommu functions
+ * @ops:       a pointer to architecture specific iommu functions
+ *
+ * There are several kind of iommu algorithm(tlb, pagetable) among
+ * omap series. This interface installs such an iommu algorighm.
+ **/
+int omap_install_iommu_arch(const struct iommu_functions *ops)
+{
+       if (arch_iommu)
+               return -EBUSY;
+
+       arch_iommu = ops;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(omap_install_iommu_arch);
+
+/**
+ * omap_uninstall_iommu_arch - Uninstall archtecure specific iommu functions
+ * @ops:       a pointer to architecture specific iommu functions
+ *
+ * This interface uninstalls the iommu algorighm installed previously.
+ **/
+void omap_uninstall_iommu_arch(const struct iommu_functions *ops)
+{
+       if (arch_iommu != ops)
+               pr_err("%s: not your arch\n", __func__);
+
+       arch_iommu = NULL;
+}
+EXPORT_SYMBOL_GPL(omap_uninstall_iommu_arch);
+
+/**
+ * omap_iommu_save_ctx - Save registers for pm off-mode support
+ * @obj:       target iommu
+ **/
+void omap_iommu_save_ctx(struct omap_iommu *obj)
+{
+       arch_iommu->save_ctx(obj);
+}
+EXPORT_SYMBOL_GPL(omap_iommu_save_ctx);
+
+/**
+ * omap_iommu_restore_ctx - Restore registers for pm off-mode support
+ * @obj:       target iommu
+ **/
+void omap_iommu_restore_ctx(struct omap_iommu *obj)
+{
+       arch_iommu->restore_ctx(obj);
+}
+EXPORT_SYMBOL_GPL(omap_iommu_restore_ctx);
+
+/**
+ * omap_iommu_arch_version - Return running iommu arch version
+ **/
+u32 omap_iommu_arch_version(void)
+{
+       return arch_iommu->version;
+}
+EXPORT_SYMBOL_GPL(omap_iommu_arch_version);
+
+static int iommu_enable(struct omap_iommu *obj)
+{
+       int err;
+
+       if (!obj)
+               return -EINVAL;
+
+       if (!arch_iommu)
+               return -ENODEV;
+
+       clk_enable(obj->clk);
+
+       err = arch_iommu->enable(obj);
+
+       clk_disable(obj->clk);
+       return err;
+}
+
+static void iommu_disable(struct omap_iommu *obj)
+{
+       if (!obj)
+               return;
+
+       clk_enable(obj->clk);
+
+       arch_iommu->disable(obj);
+
+       clk_disable(obj->clk);
+}
+
+/*
+ *     TLB operations
+ */
+void omap_iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
+{
+       BUG_ON(!cr || !e);
+
+       arch_iommu->cr_to_e(cr, e);
+}
+EXPORT_SYMBOL_GPL(omap_iotlb_cr_to_e);
+
+static inline int iotlb_cr_valid(struct cr_regs *cr)
+{
+       if (!cr)
+               return -EINVAL;
+
+       return arch_iommu->cr_valid(cr);
+}
+
+static inline struct cr_regs *iotlb_alloc_cr(struct omap_iommu *obj,
+                                            struct iotlb_entry *e)
+{
+       if (!e)
+               return NULL;
+
+       return arch_iommu->alloc_cr(obj, e);
+}
+
+static u32 iotlb_cr_to_virt(struct cr_regs *cr)
+{
+       return arch_iommu->cr_to_virt(cr);
+}
+
+static u32 get_iopte_attr(struct iotlb_entry *e)
+{
+       return arch_iommu->get_pte_attr(e);
+}
+
+static u32 iommu_report_fault(struct omap_iommu *obj, u32 *da)
+{
+       return arch_iommu->fault_isr(obj, da);
+}
+
+static void iotlb_lock_get(struct omap_iommu *obj, struct iotlb_lock *l)
+{
+       u32 val;
+
+       val = iommu_read_reg(obj, MMU_LOCK);
+
+       l->base = MMU_LOCK_BASE(val);
+       l->vict = MMU_LOCK_VICT(val);
+
+}
+
+static void iotlb_lock_set(struct omap_iommu *obj, struct iotlb_lock *l)
+{
+       u32 val;
+
+       val = (l->base << MMU_LOCK_BASE_SHIFT);
+       val |= (l->vict << MMU_LOCK_VICT_SHIFT);
+
+       iommu_write_reg(obj, val, MMU_LOCK);
+}
+
+static void iotlb_read_cr(struct omap_iommu *obj, struct cr_regs *cr)
+{
+       arch_iommu->tlb_read_cr(obj, cr);
+}
+
+static void iotlb_load_cr(struct omap_iommu *obj, struct cr_regs *cr)
+{
+       arch_iommu->tlb_load_cr(obj, cr);
+
+       iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
+       iommu_write_reg(obj, 1, MMU_LD_TLB);
+}
+
+/**
+ * iotlb_dump_cr - Dump an iommu tlb entry into buf
+ * @obj:       target iommu
+ * @cr:                contents of cam and ram register
+ * @buf:       output buffer
+ **/
+static inline ssize_t iotlb_dump_cr(struct omap_iommu *obj, struct cr_regs *cr,
+                                   char *buf)
+{
+       BUG_ON(!cr || !buf);
+
+       return arch_iommu->dump_cr(obj, cr, buf);
+}
+
+/* only used in iotlb iteration for-loop */
+static struct cr_regs __iotlb_read_cr(struct omap_iommu *obj, int n)
+{
+       struct cr_regs cr;
+       struct iotlb_lock l;
+
+       iotlb_lock_get(obj, &l);
+       l.vict = n;
+       iotlb_lock_set(obj, &l);
+       iotlb_read_cr(obj, &cr);
+
+       return cr;
+}
+
+/**
+ * load_iotlb_entry - Set an iommu tlb entry
+ * @obj:       target iommu
+ * @e:         an iommu tlb entry info
+ **/
+#ifdef PREFETCH_IOTLB
+static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
+{
+       int err = 0;
+       struct iotlb_lock l;
+       struct cr_regs *cr;
+
+       if (!obj || !obj->nr_tlb_entries || !e)
+               return -EINVAL;
+
+       clk_enable(obj->clk);
+
+       iotlb_lock_get(obj, &l);
+       if (l.base == obj->nr_tlb_entries) {
+               dev_warn(obj->dev, "%s: preserve entries full\n", __func__);
+               err = -EBUSY;
+               goto out;
+       }
+       if (!e->prsvd) {
+               int i;
+               struct cr_regs tmp;
+
+               for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, tmp)
+                       if (!iotlb_cr_valid(&tmp))
+                               break;
+
+               if (i == obj->nr_tlb_entries) {
+                       dev_dbg(obj->dev, "%s: full: no entry\n", __func__);
+                       err = -EBUSY;
+                       goto out;
+               }
+
+               iotlb_lock_get(obj, &l);
+       } else {
+               l.vict = l.base;
+               iotlb_lock_set(obj, &l);
+       }
+
+       cr = iotlb_alloc_cr(obj, e);
+       if (IS_ERR(cr)) {
+               clk_disable(obj->clk);
+               return PTR_ERR(cr);
+       }
+
+       iotlb_load_cr(obj, cr);
+       kfree(cr);
+
+       if (e->prsvd)
+               l.base++;
+       /* increment victim for next tlb load */
+       if (++l.vict == obj->nr_tlb_entries)
+               l.vict = l.base;
+       iotlb_lock_set(obj, &l);
+out:
+       clk_disable(obj->clk);
+       return err;
+}
+
+#else /* !PREFETCH_IOTLB */
+
+static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
+{
+       return 0;
+}
+
+#endif /* !PREFETCH_IOTLB */
+
+static int prefetch_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
+{
+       return load_iotlb_entry(obj, e);
+}
+
+/**
+ * flush_iotlb_page - Clear an iommu tlb entry
+ * @obj:       target iommu
+ * @da:                iommu device virtual address
+ *
+ * Clear an iommu tlb entry which includes 'da' address.
+ **/
+static void flush_iotlb_page(struct omap_iommu *obj, u32 da)
+{
+       int i;
+       struct cr_regs cr;
+
+       clk_enable(obj->clk);
+
+       for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr) {
+               u32 start;
+               size_t bytes;
+
+               if (!iotlb_cr_valid(&cr))
+                       continue;
+
+               start = iotlb_cr_to_virt(&cr);
+               bytes = iopgsz_to_bytes(cr.cam & 3);
+
+               if ((start <= da) && (da < start + bytes)) {
+                       dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
+                               __func__, start, da, bytes);
+                       iotlb_load_cr(obj, &cr);
+                       iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
+               }
+       }
+       clk_disable(obj->clk);
+
+       if (i == obj->nr_tlb_entries)
+               dev_dbg(obj->dev, "%s: no page for %08x\n", __func__, da);
+}
+
+/**
+ * flush_iotlb_all - Clear all iommu tlb entries
+ * @obj:       target iommu
+ **/
+static void flush_iotlb_all(struct omap_iommu *obj)
+{
+       struct iotlb_lock l;
+
+       clk_enable(obj->clk);
+
+       l.base = 0;
+       l.vict = 0;
+       iotlb_lock_set(obj, &l);
+
+       iommu_write_reg(obj, 1, MMU_GFLUSH);
+
+       clk_disable(obj->clk);
+}
+
+#if defined(CONFIG_OMAP_IOMMU_DEBUG) || defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
+
+ssize_t omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t bytes)
+{
+       if (!obj || !buf)
+               return -EINVAL;
+
+       clk_enable(obj->clk);
+
+       bytes = arch_iommu->dump_ctx(obj, buf, bytes);
+
+       clk_disable(obj->clk);
+
+       return bytes;
+}
+EXPORT_SYMBOL_GPL(omap_iommu_dump_ctx);
+
+static int
+__dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num)
+{
+       int i;
+       struct iotlb_lock saved;
+       struct cr_regs tmp;
+       struct cr_regs *p = crs;
+
+       clk_enable(obj->clk);
+       iotlb_lock_get(obj, &saved);
+
+       for_each_iotlb_cr(obj, num, i, tmp) {
+               if (!iotlb_cr_valid(&tmp))
+                       continue;
+               *p++ = tmp;
+       }
+
+       iotlb_lock_set(obj, &saved);
+       clk_disable(obj->clk);
+
+       return  p - crs;
+}
+
+/**
+ * omap_dump_tlb_entries - dump cr arrays to given buffer
+ * @obj:       target iommu
+ * @buf:       output buffer
+ **/
+size_t omap_dump_tlb_entries(struct omap_iommu *obj, char *buf, ssize_t bytes)
+{
+       int i, num;
+       struct cr_regs *cr;
+       char *p = buf;
+
+       num = bytes / sizeof(*cr);
+       num = min(obj->nr_tlb_entries, num);
+
+       cr = kcalloc(num, sizeof(*cr), GFP_KERNEL);
+       if (!cr)
+               return 0;
+
+       num = __dump_tlb_entries(obj, cr, num);
+       for (i = 0; i < num; i++)
+               p += iotlb_dump_cr(obj, cr + i, p);
+       kfree(cr);
+
+       return p - buf;
+}
+EXPORT_SYMBOL_GPL(omap_dump_tlb_entries);
+
+int omap_foreach_iommu_device(void *data, int (*fn)(struct device *, void *))
+{
+       return driver_for_each_device(&omap_iommu_driver.driver,
+                                     NULL, data, fn);
+}
+EXPORT_SYMBOL_GPL(omap_foreach_iommu_device);
+
+#endif /* CONFIG_OMAP_IOMMU_DEBUG_MODULE */
+
+/*
+ *     H/W pagetable operations
+ */
+static void flush_iopgd_range(u32 *first, u32 *last)
+{
+       /* FIXME: L2 cache should be taken care of if it exists */
+       do {
+               asm("mcr        p15, 0, %0, c7, c10, 1 @ flush_pgd"
+                   : : "r" (first));
+               first += L1_CACHE_BYTES / sizeof(*first);
+       } while (first <= last);
+}
+
+static void flush_iopte_range(u32 *first, u32 *last)
+{
+       /* FIXME: L2 cache should be taken care of if it exists */
+       do {
+               asm("mcr        p15, 0, %0, c7, c10, 1 @ flush_pte"
+                   : : "r" (first));
+               first += L1_CACHE_BYTES / sizeof(*first);
+       } while (first <= last);
+}
+
+static void iopte_free(u32 *iopte)
+{
+       /* Note: freed iopte's must be clean ready for re-use */
+       kmem_cache_free(iopte_cachep, iopte);
+}
+
+static u32 *iopte_alloc(struct omap_iommu *obj, u32 *iopgd, u32 da)
+{
+       u32 *iopte;
+
+       /* a table has already existed */
+       if (*iopgd)
+               goto pte_ready;
+
+       /*
+        * do the allocation outside the page table lock
+        */
+       spin_unlock(&obj->page_table_lock);
+       iopte = kmem_cache_zalloc(iopte_cachep, GFP_KERNEL);
+       spin_lock(&obj->page_table_lock);
+
+       if (!*iopgd) {
+               if (!iopte)
+                       return ERR_PTR(-ENOMEM);
+
+               *iopgd = virt_to_phys(iopte) | IOPGD_TABLE;
+               flush_iopgd_range(iopgd, iopgd);
+
+               dev_vdbg(obj->dev, "%s: a new pte:%p\n", __func__, iopte);
+       } else {
+               /* We raced, free the reduniovant table */
+               iopte_free(iopte);
+       }
+
+pte_ready:
+       iopte = iopte_offset(iopgd, da);
+
+       dev_vdbg(obj->dev,
+                "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n",
+                __func__, da, iopgd, *iopgd, iopte, *iopte);
+
+       return iopte;
+}
+
+static int iopgd_alloc_section(struct omap_iommu *obj, u32 da, u32 pa, u32 prot)
+{
+       u32 *iopgd = iopgd_offset(obj, da);
+
+       if ((da | pa) & ~IOSECTION_MASK) {
+               dev_err(obj->dev, "%s: %08x:%08x should aligned on %08lx\n",
+                       __func__, da, pa, IOSECTION_SIZE);
+               return -EINVAL;
+       }
+
+       *iopgd = (pa & IOSECTION_MASK) | prot | IOPGD_SECTION;
+       flush_iopgd_range(iopgd, iopgd);
+       return 0;
+}
+
+static int iopgd_alloc_super(struct omap_iommu *obj, u32 da, u32 pa, u32 prot)
+{
+       u32 *iopgd = iopgd_offset(obj, da);
+       int i;
+
+       if ((da | pa) & ~IOSUPER_MASK) {
+               dev_err(obj->dev, "%s: %08x:%08x should aligned on %08lx\n",
+                       __func__, da, pa, IOSUPER_SIZE);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < 16; i++)
+               *(iopgd + i) = (pa & IOSUPER_MASK) | prot | IOPGD_SUPER;
+       flush_iopgd_range(iopgd, iopgd + 15);
+       return 0;
+}
+
+static int iopte_alloc_page(struct omap_iommu *obj, u32 da, u32 pa, u32 prot)
+{
+       u32 *iopgd = iopgd_offset(obj, da);
+       u32 *iopte = iopte_alloc(obj, iopgd, da);
+
+       if (IS_ERR(iopte))
+               return PTR_ERR(iopte);
+
+       *iopte = (pa & IOPAGE_MASK) | prot | IOPTE_SMALL;
+       flush_iopte_range(iopte, iopte);
+
+       dev_vdbg(obj->dev, "%s: da:%08x pa:%08x pte:%p *pte:%08x\n",
+                __func__, da, pa, iopte, *iopte);
+
+       return 0;
+}
+
+static int iopte_alloc_large(struct omap_iommu *obj, u32 da, u32 pa, u32 prot)
+{
+       u32 *iopgd = iopgd_offset(obj, da);
+       u32 *iopte = iopte_alloc(obj, iopgd, da);
+       int i;
+
+       if ((da | pa) & ~IOLARGE_MASK) {
+               dev_err(obj->dev, "%s: %08x:%08x should aligned on %08lx\n",
+                       __func__, da, pa, IOLARGE_SIZE);
+               return -EINVAL;
+       }
+
+       if (IS_ERR(iopte))
+               return PTR_ERR(iopte);
+
+       for (i = 0; i < 16; i++)
+               *(iopte + i) = (pa & IOLARGE_MASK) | prot | IOPTE_LARGE;
+       flush_iopte_range(iopte, iopte + 15);
+       return 0;
+}
+
+static int
+iopgtable_store_entry_core(struct omap_iommu *obj, struct iotlb_entry *e)
+{
+       int (*fn)(struct omap_iommu *, u32, u32, u32);
+       u32 prot;
+       int err;
+
+       if (!obj || !e)
+               return -EINVAL;
+
+       switch (e->pgsz) {
+       case MMU_CAM_PGSZ_16M:
+               fn = iopgd_alloc_super;
+               break;
+       case MMU_CAM_PGSZ_1M:
+               fn = iopgd_alloc_section;
+               break;
+       case MMU_CAM_PGSZ_64K:
+               fn = iopte_alloc_large;
+               break;
+       case MMU_CAM_PGSZ_4K:
+               fn = iopte_alloc_page;
+               break;
+       default:
+               fn = NULL;
+               BUG();
+               break;
+       }
+
+       prot = get_iopte_attr(e);
+
+       spin_lock(&obj->page_table_lock);
+       err = fn(obj, e->da, e->pa, prot);
+       spin_unlock(&obj->page_table_lock);
+
+       return err;
+}
+
+/**
+ * omap_iopgtable_store_entry - Make an iommu pte entry
+ * @obj:       target iommu
+ * @e:         an iommu tlb entry info
+ **/
+int omap_iopgtable_store_entry(struct omap_iommu *obj, struct iotlb_entry *e)
+{
+       int err;
+
+       flush_iotlb_page(obj, e->da);
+       err = iopgtable_store_entry_core(obj, e);
+       if (!err)
+               prefetch_iotlb_entry(obj, e);
+       return err;
+}
+EXPORT_SYMBOL_GPL(omap_iopgtable_store_entry);
+
+/**
+ * iopgtable_lookup_entry - Lookup an iommu pte entry
+ * @obj:       target iommu
+ * @da:                iommu device virtual address
+ * @ppgd:      iommu pgd entry pointer to be returned
+ * @ppte:      iommu pte entry pointer to be returned
+ **/
+static void
+iopgtable_lookup_entry(struct omap_iommu *obj, u32 da, u32 **ppgd, u32 **ppte)
+{
+       u32 *iopgd, *iopte = NULL;
+
+       iopgd = iopgd_offset(obj, da);
+       if (!*iopgd)
+               goto out;
+
+       if (iopgd_is_table(*iopgd))
+               iopte = iopte_offset(iopgd, da);
+out:
+       *ppgd = iopgd;
+       *ppte = iopte;
+}
+
+static size_t iopgtable_clear_entry_core(struct omap_iommu *obj, u32 da)
+{
+       size_t bytes;
+       u32 *iopgd = iopgd_offset(obj, da);
+       int nent = 1;
+
+       if (!*iopgd)
+               return 0;
+
+       if (iopgd_is_table(*iopgd)) {
+               int i;
+               u32 *iopte = iopte_offset(iopgd, da);
+
+               bytes = IOPTE_SIZE;
+               if (*iopte & IOPTE_LARGE) {
+                       nent *= 16;
+                       /* rewind to the 1st entry */
+                       iopte = iopte_offset(iopgd, (da & IOLARGE_MASK));
+               }
+               bytes *= nent;
+               memset(iopte, 0, nent * sizeof(*iopte));
+               flush_iopte_range(iopte, iopte + (nent - 1) * sizeof(*iopte));
+
+               /*
+                * do table walk to check if this table is necessary or not
+                */
+               iopte = iopte_offset(iopgd, 0);
+               for (i = 0; i < PTRS_PER_IOPTE; i++)
+                       if (iopte[i])
+                               goto out;
+
+               iopte_free(iopte);
+               nent = 1; /* for the next L1 entry */
+       } else {
+               bytes = IOPGD_SIZE;
+               if ((*iopgd & IOPGD_SUPER) == IOPGD_SUPER) {
+                       nent *= 16;
+                       /* rewind to the 1st entry */
+                       iopgd = iopgd_offset(obj, (da & IOSUPER_MASK));
+               }
+               bytes *= nent;
+       }
+       memset(iopgd, 0, nent * sizeof(*iopgd));
+       flush_iopgd_range(iopgd, iopgd + (nent - 1) * sizeof(*iopgd));
+out:
+       return bytes;
+}
+
+/**
+ * iopgtable_clear_entry - Remove an iommu pte entry
+ * @obj:       target iommu
+ * @da:                iommu device virtual address
+ **/
+static size_t iopgtable_clear_entry(struct omap_iommu *obj, u32 da)
+{
+       size_t bytes;
+
+       spin_lock(&obj->page_table_lock);
+
+       bytes = iopgtable_clear_entry_core(obj, da);
+       flush_iotlb_page(obj, da);
+
+       spin_unlock(&obj->page_table_lock);
+
+       return bytes;
+}
+
+static void iopgtable_clear_entry_all(struct omap_iommu *obj)
+{
+       int i;
+
+       spin_lock(&obj->page_table_lock);
+
+       for (i = 0; i < PTRS_PER_IOPGD; i++) {
+               u32 da;
+               u32 *iopgd;
+
+               da = i << IOPGD_SHIFT;
+               iopgd = iopgd_offset(obj, da);
+
+               if (!*iopgd)
+                       continue;
+
+               if (iopgd_is_table(*iopgd))
+                       iopte_free(iopte_offset(iopgd, 0));
+
+               *iopgd = 0;
+               flush_iopgd_range(iopgd, iopgd);
+       }
+
+       flush_iotlb_all(obj);
+
+       spin_unlock(&obj->page_table_lock);
+}
+
+/*
+ *     Device IOMMU generic operations
+ */
+static irqreturn_t iommu_fault_handler(int irq, void *data)
+{
+       u32 da, errs;
+       u32 *iopgd, *iopte;
+       struct omap_iommu *obj = data;
+       struct iommu_domain *domain = obj->domain;
+
+       if (!obj->refcount)
+               return IRQ_NONE;
+
+       clk_enable(obj->clk);
+       errs = iommu_report_fault(obj, &da);
+       clk_disable(obj->clk);
+       if (errs == 0)
+               return IRQ_HANDLED;
+
+       /* Fault callback or TLB/PTE Dynamic loading */
+       if (!report_iommu_fault(domain, obj->dev, da, 0))
+               return IRQ_HANDLED;
+
+       iommu_disable(obj);
+
+       iopgd = iopgd_offset(obj, da);
+
+       if (!iopgd_is_table(*iopgd)) {
+               dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p "
+                       "*pgd:px%08x\n", obj->name, errs, da, iopgd, *iopgd);
+               return IRQ_NONE;
+       }
+
+       iopte = iopte_offset(iopgd, da);
+
+       dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x "
+               "pte:0x%p *pte:0x%08x\n", obj->name, errs, da, iopgd, *iopgd,
+               iopte, *iopte);
+
+       return IRQ_NONE;
+}
+
+static int device_match_by_alias(struct device *dev, void *data)
+{
+       struct omap_iommu *obj = to_iommu(dev);
+       const char *name = data;
+
+       pr_debug("%s: %s %s\n", __func__, obj->name, name);
+
+       return strcmp(obj->name, name) == 0;
+}
+
+/**
+ * omap_find_iommu_device() - find an omap iommu device by name
+ * @name:      name of the iommu device
+ *
+ * The generic iommu API requires the caller to provide the device
+ * he wishes to attach to a certain iommu domain.
+ *
+ * Drivers generally should not bother with this as it should just
+ * be taken care of by the DMA-API using dev_archdata.
+ *
+ * This function is provided as an interim solution until the latter
+ * materializes, and omap3isp is fully migrated to the DMA-API.
+ */
+struct device *omap_find_iommu_device(const char *name)
+{
+       return driver_find_device(&omap_iommu_driver.driver, NULL,
+                               (void *)name,
+                               device_match_by_alias);
+}
+EXPORT_SYMBOL_GPL(omap_find_iommu_device);
+
+/**
+ * omap_iommu_attach() - attach iommu device to an iommu domain
+ * @dev:       target omap iommu device
+ * @iopgd:     page table
+ **/
+static struct omap_iommu *omap_iommu_attach(struct device *dev, u32 *iopgd)
+{
+       int err = -ENOMEM;
+       struct omap_iommu *obj = to_iommu(dev);
+
+       spin_lock(&obj->iommu_lock);
+
+       /* an iommu device can only be attached once */
+       if (++obj->refcount > 1) {
+               dev_err(dev, "%s: already attached!\n", obj->name);
+               err = -EBUSY;
+               goto err_enable;
+       }
+
+       obj->iopgd = iopgd;
+       err = iommu_enable(obj);
+       if (err)
+               goto err_enable;
+       flush_iotlb_all(obj);
+
+       if (!try_module_get(obj->owner))
+               goto err_module;
+
+       spin_unlock(&obj->iommu_lock);
+
+       dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name);
+       return obj;
+
+err_module:
+       if (obj->refcount == 1)
+               iommu_disable(obj);
+err_enable:
+       obj->refcount--;
+       spin_unlock(&obj->iommu_lock);
+       return ERR_PTR(err);
+}
+
+/**
+ * omap_iommu_detach - release iommu device
+ * @obj:       target iommu
+ **/
+static void omap_iommu_detach(struct omap_iommu *obj)
+{
+       if (!obj || IS_ERR(obj))
+               return;
+
+       spin_lock(&obj->iommu_lock);
+
+       if (--obj->refcount == 0)
+               iommu_disable(obj);
+
+       module_put(obj->owner);
+
+       obj->iopgd = NULL;
+
+       spin_unlock(&obj->iommu_lock);
+
+       dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name);
+}
+
+/*
+ *     OMAP Device MMU(IOMMU) detection
+ */
+static int __devinit omap_iommu_probe(struct platform_device *pdev)
+{
+       int err = -ENODEV;
+       int irq;
+       struct omap_iommu *obj;
+       struct resource *res;
+       struct iommu_platform_data *pdata = pdev->dev.platform_data;
+
+       if (pdev->num_resources != 2)
+               return -EINVAL;
+
+       obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
+       if (!obj)
+               return -ENOMEM;
+
+       obj->clk = clk_get(&pdev->dev, pdata->clk_name);
+       if (IS_ERR(obj->clk))
+               goto err_clk;
+
+       obj->nr_tlb_entries = pdata->nr_tlb_entries;
+       obj->name = pdata->name;
+       obj->dev = &pdev->dev;
+       obj->ctx = (void *)obj + sizeof(*obj);
+       obj->da_start = pdata->da_start;
+       obj->da_end = pdata->da_end;
+
+       spin_lock_init(&obj->iommu_lock);
+       mutex_init(&obj->mmap_lock);
+       spin_lock_init(&obj->page_table_lock);
+       INIT_LIST_HEAD(&obj->mmap);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               err = -ENODEV;
+               goto err_mem;
+       }
+
+       res = request_mem_region(res->start, resource_size(res),
+                                dev_name(&pdev->dev));
+       if (!res) {
+               err = -EIO;
+               goto err_mem;
+       }
+
+       obj->regbase = ioremap(res->start, resource_size(res));
+       if (!obj->regbase) {
+               err = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               err = -ENODEV;
+               goto err_irq;
+       }
+       err = request_irq(irq, iommu_fault_handler, IRQF_SHARED,
+                         dev_name(&pdev->dev), obj);
+       if (err < 0)
+               goto err_irq;
+       platform_set_drvdata(pdev, obj);
+
+       dev_info(&pdev->dev, "%s registered\n", obj->name);
+       return 0;
+
+err_irq:
+       iounmap(obj->regbase);
+err_ioremap:
+       release_mem_region(res->start, resource_size(res));
+err_mem:
+       clk_put(obj->clk);
+err_clk:
+       kfree(obj);
+       return err;
+}
+
+static int __devexit omap_iommu_remove(struct platform_device *pdev)
+{
+       int irq;
+       struct resource *res;
+       struct omap_iommu *obj = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       iopgtable_clear_entry_all(obj);
+
+       irq = platform_get_irq(pdev, 0);
+       free_irq(irq, obj);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+       iounmap(obj->regbase);
+
+       clk_put(obj->clk);
+       dev_info(&pdev->dev, "%s removed\n", obj->name);
+       kfree(obj);
+       return 0;
+}
+
+static struct platform_driver omap_iommu_driver = {
+       .probe  = omap_iommu_probe,
+       .remove = __devexit_p(omap_iommu_remove),
+       .driver = {
+               .name   = "omap-iommu",
+       },
+};
+
+static void iopte_cachep_ctor(void *iopte)
+{
+       clean_dcache_area(iopte, IOPTE_TABLE_SIZE);
+}
+
+static int omap_iommu_map(struct iommu_domain *domain, unsigned long da,
+                        phys_addr_t pa, int order, int prot)
+{
+       struct omap_iommu_domain *omap_domain = domain->priv;
+       struct omap_iommu *oiommu = omap_domain->iommu_dev;
+       struct device *dev = oiommu->dev;
+       size_t bytes = PAGE_SIZE << order;
+       struct iotlb_entry e;
+       int omap_pgsz;
+       u32 ret, flags;
+
+       /* we only support mapping a single iommu page for now */
+       omap_pgsz = bytes_to_iopgsz(bytes);
+       if (omap_pgsz < 0) {
+               dev_err(dev, "invalid size to map: %d\n", bytes);
+               return -EINVAL;
+       }
+
+       dev_dbg(dev, "mapping da 0x%lx to pa 0x%x size 0x%x\n", da, pa, bytes);
+
+       flags = omap_pgsz | prot;
+
+       iotlb_init_entry(&e, da, pa, flags);
+
+       ret = omap_iopgtable_store_entry(oiommu, &e);
+       if (ret)
+               dev_err(dev, "omap_iopgtable_store_entry failed: %d\n", ret);
+
+       return ret;
+}
+
+static int omap_iommu_unmap(struct iommu_domain *domain, unsigned long da,
+                           int order)
+{
+       struct omap_iommu_domain *omap_domain = domain->priv;
+       struct omap_iommu *oiommu = omap_domain->iommu_dev;
+       struct device *dev = oiommu->dev;
+       size_t unmap_size;
+
+       dev_dbg(dev, "unmapping da 0x%lx order %d\n", da, order);
+
+       unmap_size = iopgtable_clear_entry(oiommu, da);
+
+       return unmap_size ? get_order(unmap_size) : -EINVAL;
+}
+
+static int
+omap_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
+{
+       struct omap_iommu_domain *omap_domain = domain->priv;
+       struct omap_iommu *oiommu;
+       int ret = 0;
+
+       spin_lock(&omap_domain->lock);
+
+       /* only a single device is supported per domain for now */
+       if (omap_domain->iommu_dev) {
+               dev_err(dev, "iommu domain is already attached\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       /* get a handle to and enable the omap iommu */
+       oiommu = omap_iommu_attach(dev, omap_domain->pgtable);
+       if (IS_ERR(oiommu)) {
+               ret = PTR_ERR(oiommu);
+               dev_err(dev, "can't get omap iommu: %d\n", ret);
+               goto out;
+       }
+
+       omap_domain->iommu_dev = oiommu;
+       oiommu->domain = domain;
+
+out:
+       spin_unlock(&omap_domain->lock);
+       return ret;
+}
+
+static void omap_iommu_detach_dev(struct iommu_domain *domain,
+                                struct device *dev)
+{
+       struct omap_iommu_domain *omap_domain = domain->priv;
+       struct omap_iommu *oiommu = to_iommu(dev);
+
+       spin_lock(&omap_domain->lock);
+
+       /* only a single device is supported per domain for now */
+       if (omap_domain->iommu_dev != oiommu) {
+               dev_err(dev, "invalid iommu device\n");
+               goto out;
+       }
+
+       iopgtable_clear_entry_all(oiommu);
+
+       omap_iommu_detach(oiommu);
+
+       omap_domain->iommu_dev = NULL;
+
+out:
+       spin_unlock(&omap_domain->lock);
+}
+
+static int omap_iommu_domain_init(struct iommu_domain *domain)
+{
+       struct omap_iommu_domain *omap_domain;
+
+       omap_domain = kzalloc(sizeof(*omap_domain), GFP_KERNEL);
+       if (!omap_domain) {
+               pr_err("kzalloc failed\n");
+               goto out;
+       }
+
+       omap_domain->pgtable = kzalloc(IOPGD_TABLE_SIZE, GFP_KERNEL);
+       if (!omap_domain->pgtable) {
+               pr_err("kzalloc failed\n");
+               goto fail_nomem;
+       }
+
+       /*
+        * should never fail, but please keep this around to ensure
+        * we keep the hardware happy
+        */
+       BUG_ON(!IS_ALIGNED((long)omap_domain->pgtable, IOPGD_TABLE_SIZE));
+
+       clean_dcache_area(omap_domain->pgtable, IOPGD_TABLE_SIZE);
+       spin_lock_init(&omap_domain->lock);
+
+       domain->priv = omap_domain;
+
+       return 0;
+
+fail_nomem:
+       kfree(omap_domain);
+out:
+       return -ENOMEM;
+}
+
+/* assume device was already detached */
+static void omap_iommu_domain_destroy(struct iommu_domain *domain)
+{
+       struct omap_iommu_domain *omap_domain = domain->priv;
+
+       domain->priv = NULL;
+
+       kfree(omap_domain->pgtable);
+       kfree(omap_domain);
+}
+
+static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain,
+                                         unsigned long da)
+{
+       struct omap_iommu_domain *omap_domain = domain->priv;
+       struct omap_iommu *oiommu = omap_domain->iommu_dev;
+       struct device *dev = oiommu->dev;
+       u32 *pgd, *pte;
+       phys_addr_t ret = 0;
+
+       iopgtable_lookup_entry(oiommu, da, &pgd, &pte);
+
+       if (pte) {
+               if (iopte_is_small(*pte))
+                       ret = omap_iommu_translate(*pte, da, IOPTE_MASK);
+               else if (iopte_is_large(*pte))
+                       ret = omap_iommu_translate(*pte, da, IOLARGE_MASK);
+               else
+                       dev_err(dev, "bogus pte 0x%x", *pte);
+       } else {
+               if (iopgd_is_section(*pgd))
+                       ret = omap_iommu_translate(*pgd, da, IOSECTION_MASK);
+               else if (iopgd_is_super(*pgd))
+                       ret = omap_iommu_translate(*pgd, da, IOSUPER_MASK);
+               else
+                       dev_err(dev, "bogus pgd 0x%x", *pgd);
+       }
+
+       return ret;
+}
+
+static int omap_iommu_domain_has_cap(struct iommu_domain *domain,
+                                   unsigned long cap)
+{
+       return 0;
+}
+
+static struct iommu_ops omap_iommu_ops = {
+       .domain_init    = omap_iommu_domain_init,
+       .domain_destroy = omap_iommu_domain_destroy,
+       .attach_dev     = omap_iommu_attach_dev,
+       .detach_dev     = omap_iommu_detach_dev,
+       .map            = omap_iommu_map,
+       .unmap          = omap_iommu_unmap,
+       .iova_to_phys   = omap_iommu_iova_to_phys,
+       .domain_has_cap = omap_iommu_domain_has_cap,
+};
+
+static int __init omap_iommu_init(void)
+{
+       struct kmem_cache *p;
+       const unsigned long flags = SLAB_HWCACHE_ALIGN;
+       size_t align = 1 << 10; /* L2 pagetable alignement */
+
+       p = kmem_cache_create("iopte_cache", IOPTE_TABLE_SIZE, align, flags,
+                             iopte_cachep_ctor);
+       if (!p)
+               return -ENOMEM;
+       iopte_cachep = p;
+
+       bus_set_iommu(&platform_bus_type, &omap_iommu_ops);
+
+       return platform_driver_register(&omap_iommu_driver);
+}
+module_init(omap_iommu_init);
+
+static void __exit omap_iommu_exit(void)
+{
+       kmem_cache_destroy(iopte_cachep);
+
+       platform_driver_unregister(&omap_iommu_driver);
+}
+module_exit(omap_iommu_exit);
+
+MODULE_DESCRIPTION("omap iommu: tlb and pagetable primitives");
+MODULE_ALIAS("platform:omap-iommu");
+MODULE_AUTHOR("Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/omap-iovmm.c b/drivers/iommu/omap-iovmm.c
new file mode 100644 (file)
index 0000000..e8fdb88
--- /dev/null
@@ -0,0 +1,742 @@
+/*
+ * omap iommu: simple virtual address space management
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/device.h>
+#include <linux/scatterlist.h>
+#include <linux/iommu.h>
+
+#include <asm/cacheflush.h>
+#include <asm/mach/map.h>
+
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
+
+#include <plat/iopgtable.h>
+
+static struct kmem_cache *iovm_area_cachep;
+
+/* return the offset of the first scatterlist entry in a sg table */
+static unsigned int sgtable_offset(const struct sg_table *sgt)
+{
+       if (!sgt || !sgt->nents)
+               return 0;
+
+       return sgt->sgl->offset;
+}
+
+/* return total bytes of sg buffers */
+static size_t sgtable_len(const struct sg_table *sgt)
+{
+       unsigned int i, total = 0;
+       struct scatterlist *sg;
+
+       if (!sgt)
+               return 0;
+
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               size_t bytes;
+
+               bytes = sg->length + sg->offset;
+
+               if (!iopgsz_ok(bytes)) {
+                       pr_err("%s: sg[%d] not iommu pagesize(%u %u)\n",
+                              __func__, i, bytes, sg->offset);
+                       return 0;
+               }
+
+               if (i && sg->offset) {
+                       pr_err("%s: sg[%d] offset not allowed in internal "
+                                       "entries\n", __func__, i);
+                       return 0;
+               }
+
+               total += bytes;
+       }
+
+       return total;
+}
+#define sgtable_ok(x)  (!!sgtable_len(x))
+
+static unsigned max_alignment(u32 addr)
+{
+       int i;
+       unsigned pagesize[] = { SZ_16M, SZ_1M, SZ_64K, SZ_4K, };
+       for (i = 0; i < ARRAY_SIZE(pagesize) && addr & (pagesize[i] - 1); i++)
+               ;
+       return (i < ARRAY_SIZE(pagesize)) ? pagesize[i] : 0;
+}
+
+/*
+ * calculate the optimal number sg elements from total bytes based on
+ * iommu superpages
+ */
+static unsigned sgtable_nents(size_t bytes, u32 da, u32 pa)
+{
+       unsigned nr_entries = 0, ent_sz;
+
+       if (!IS_ALIGNED(bytes, PAGE_SIZE)) {
+               pr_err("%s: wrong size %08x\n", __func__, bytes);
+               return 0;
+       }
+
+       while (bytes) {
+               ent_sz = max_alignment(da | pa);
+               ent_sz = min_t(unsigned, ent_sz, iopgsz_max(bytes));
+               nr_entries++;
+               da += ent_sz;
+               pa += ent_sz;
+               bytes -= ent_sz;
+       }
+
+       return nr_entries;
+}
+
+/* allocate and initialize sg_table header(a kind of 'superblock') */
+static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags,
+                                                       u32 da, u32 pa)
+{
+       unsigned int nr_entries;
+       int err;
+       struct sg_table *sgt;
+
+       if (!bytes)
+               return ERR_PTR(-EINVAL);
+
+       if (!IS_ALIGNED(bytes, PAGE_SIZE))
+               return ERR_PTR(-EINVAL);
+
+       if (flags & IOVMF_LINEAR) {
+               nr_entries = sgtable_nents(bytes, da, pa);
+               if (!nr_entries)
+                       return ERR_PTR(-EINVAL);
+       } else
+               nr_entries =  bytes / PAGE_SIZE;
+
+       sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
+       if (!sgt)
+               return ERR_PTR(-ENOMEM);
+
+       err = sg_alloc_table(sgt, nr_entries, GFP_KERNEL);
+       if (err) {
+               kfree(sgt);
+               return ERR_PTR(err);
+       }
+
+       pr_debug("%s: sgt:%p(%d entries)\n", __func__, sgt, nr_entries);
+
+       return sgt;
+}
+
+/* free sg_table header(a kind of superblock) */
+static void sgtable_free(struct sg_table *sgt)
+{
+       if (!sgt)
+               return;
+
+       sg_free_table(sgt);
+       kfree(sgt);
+
+       pr_debug("%s: sgt:%p\n", __func__, sgt);
+}
+
+/* map 'sglist' to a contiguous mpu virtual area and return 'va' */
+static void *vmap_sg(const struct sg_table *sgt)
+{
+       u32 va;
+       size_t total;
+       unsigned int i;
+       struct scatterlist *sg;
+       struct vm_struct *new;
+       const struct mem_type *mtype;
+
+       mtype = get_mem_type(MT_DEVICE);
+       if (!mtype)
+               return ERR_PTR(-EINVAL);
+
+       total = sgtable_len(sgt);
+       if (!total)
+               return ERR_PTR(-EINVAL);
+
+       new = __get_vm_area(total, VM_IOREMAP, VMALLOC_START, VMALLOC_END);
+       if (!new)
+               return ERR_PTR(-ENOMEM);
+       va = (u32)new->addr;
+
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               size_t bytes;
+               u32 pa;
+               int err;
+
+               pa = sg_phys(sg) - sg->offset;
+               bytes = sg->length + sg->offset;
+
+               BUG_ON(bytes != PAGE_SIZE);
+
+               err = ioremap_page(va,  pa, mtype);
+               if (err)
+                       goto err_out;
+
+               va += bytes;
+       }
+
+       flush_cache_vmap((unsigned long)new->addr,
+                               (unsigned long)(new->addr + total));
+       return new->addr;
+
+err_out:
+       WARN_ON(1); /* FIXME: cleanup some mpu mappings */
+       vunmap(new->addr);
+       return ERR_PTR(-EAGAIN);
+}
+
+static inline void vunmap_sg(const void *va)
+{
+       vunmap(va);
+}
+
+static struct iovm_struct *__find_iovm_area(struct omap_iommu *obj,
+                                                       const u32 da)
+{
+       struct iovm_struct *tmp;
+
+       list_for_each_entry(tmp, &obj->mmap, list) {
+               if ((da >= tmp->da_start) && (da < tmp->da_end)) {
+                       size_t len;
+
+                       len = tmp->da_end - tmp->da_start;
+
+                       dev_dbg(obj->dev, "%s: %08x-%08x-%08x(%x) %08x\n",
+                               __func__, tmp->da_start, da, tmp->da_end, len,
+                               tmp->flags);
+
+                       return tmp;
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * omap_find_iovm_area  -  find iovma which includes @da
+ * @da:                iommu device virtual address
+ *
+ * Find the existing iovma starting at @da
+ */
+struct iovm_struct *omap_find_iovm_area(struct omap_iommu *obj, u32 da)
+{
+       struct iovm_struct *area;
+
+       mutex_lock(&obj->mmap_lock);
+       area = __find_iovm_area(obj, da);
+       mutex_unlock(&obj->mmap_lock);
+
+       return area;
+}
+EXPORT_SYMBOL_GPL(omap_find_iovm_area);
+
+/*
+ * This finds the hole(area) which fits the requested address and len
+ * in iovmas mmap, and returns the new allocated iovma.
+ */
+static struct iovm_struct *alloc_iovm_area(struct omap_iommu *obj, u32 da,
+                                          size_t bytes, u32 flags)
+{
+       struct iovm_struct *new, *tmp;
+       u32 start, prev_end, alignment;
+
+       if (!obj || !bytes)
+               return ERR_PTR(-EINVAL);
+
+       start = da;
+       alignment = PAGE_SIZE;
+
+       if (~flags & IOVMF_DA_FIXED) {
+               /* Don't map address 0 */
+               start = obj->da_start ? obj->da_start : alignment;
+
+               if (flags & IOVMF_LINEAR)
+                       alignment = iopgsz_max(bytes);
+               start = roundup(start, alignment);
+       } else if (start < obj->da_start || start > obj->da_end ||
+                                       obj->da_end - start < bytes) {
+               return ERR_PTR(-EINVAL);
+       }
+
+       tmp = NULL;
+       if (list_empty(&obj->mmap))
+               goto found;
+
+       prev_end = 0;
+       list_for_each_entry(tmp, &obj->mmap, list) {
+
+               if (prev_end > start)
+                       break;
+
+               if (tmp->da_start > start && (tmp->da_start - start) >= bytes)
+                       goto found;
+
+               if (tmp->da_end >= start && ~flags & IOVMF_DA_FIXED)
+                       start = roundup(tmp->da_end + 1, alignment);
+
+               prev_end = tmp->da_end;
+       }
+
+       if ((start >= prev_end) && (obj->da_end - start >= bytes))
+               goto found;
+
+       dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n",
+               __func__, da, bytes, flags);
+
+       return ERR_PTR(-EINVAL);
+
+found:
+       new = kmem_cache_zalloc(iovm_area_cachep, GFP_KERNEL);
+       if (!new)
+               return ERR_PTR(-ENOMEM);
+
+       new->iommu = obj;
+       new->da_start = start;
+       new->da_end = start + bytes;
+       new->flags = flags;
+
+       /*
+        * keep ascending order of iovmas
+        */
+       if (tmp)
+               list_add_tail(&new->list, &tmp->list);
+       else
+               list_add(&new->list, &obj->mmap);
+
+       dev_dbg(obj->dev, "%s: found %08x-%08x-%08x(%x) %08x\n",
+               __func__, new->da_start, start, new->da_end, bytes, flags);
+
+       return new;
+}
+
+static void free_iovm_area(struct omap_iommu *obj, struct iovm_struct *area)
+{
+       size_t bytes;
+
+       BUG_ON(!obj || !area);
+
+       bytes = area->da_end - area->da_start;
+
+       dev_dbg(obj->dev, "%s: %08x-%08x(%x) %08x\n",
+               __func__, area->da_start, area->da_end, bytes, area->flags);
+
+       list_del(&area->list);
+       kmem_cache_free(iovm_area_cachep, area);
+}
+
+/**
+ * omap_da_to_va - convert (d) to (v)
+ * @obj:       objective iommu
+ * @da:                iommu device virtual address
+ * @va:                mpu virtual address
+ *
+ * Returns mpu virtual addr which corresponds to a given device virtual addr
+ */
+void *omap_da_to_va(struct omap_iommu *obj, u32 da)
+{
+       void *va = NULL;
+       struct iovm_struct *area;
+
+       mutex_lock(&obj->mmap_lock);
+
+       area = __find_iovm_area(obj, da);
+       if (!area) {
+               dev_dbg(obj->dev, "%s: no da area(%08x)\n", __func__, da);
+               goto out;
+       }
+       va = area->va;
+out:
+       mutex_unlock(&obj->mmap_lock);
+
+       return va;
+}
+EXPORT_SYMBOL_GPL(omap_da_to_va);
+
+static void sgtable_fill_vmalloc(struct sg_table *sgt, void *_va)
+{
+       unsigned int i;
+       struct scatterlist *sg;
+       void *va = _va;
+       void *va_end;
+
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               struct page *pg;
+               const size_t bytes = PAGE_SIZE;
+
+               /*
+                * iommu 'superpage' isn't supported with 'omap_iommu_vmalloc()'
+                */
+               pg = vmalloc_to_page(va);
+               BUG_ON(!pg);
+               sg_set_page(sg, pg, bytes, 0);
+
+               va += bytes;
+       }
+
+       va_end = _va + PAGE_SIZE * i;
+}
+
+static inline void sgtable_drain_vmalloc(struct sg_table *sgt)
+{
+       /*
+        * Actually this is not necessary at all, just exists for
+        * consistency of the code readability.
+        */
+       BUG_ON(!sgt);
+}
+
+/* create 'da' <-> 'pa' mapping from 'sgt' */
+static int map_iovm_area(struct iommu_domain *domain, struct iovm_struct *new,
+                       const struct sg_table *sgt, u32 flags)
+{
+       int err;
+       unsigned int i, j;
+       struct scatterlist *sg;
+       u32 da = new->da_start;
+       int order;
+
+       if (!domain || !sgt)
+               return -EINVAL;
+
+       BUG_ON(!sgtable_ok(sgt));
+
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               u32 pa;
+               size_t bytes;
+
+               pa = sg_phys(sg) - sg->offset;
+               bytes = sg->length + sg->offset;
+
+               flags &= ~IOVMF_PGSZ_MASK;
+
+               if (bytes_to_iopgsz(bytes) < 0)
+                       goto err_out;
+
+               order = get_order(bytes);
+
+               pr_debug("%s: [%d] %08x %08x(%x)\n", __func__,
+                        i, da, pa, bytes);
+
+               err = iommu_map(domain, da, pa, order, flags);
+               if (err)
+                       goto err_out;
+
+               da += bytes;
+       }
+       return 0;
+
+err_out:
+       da = new->da_start;
+
+       for_each_sg(sgt->sgl, sg, i, j) {
+               size_t bytes;
+
+               bytes = sg->length + sg->offset;
+               order = get_order(bytes);
+
+               /* ignore failures.. we're already handling one */
+               iommu_unmap(domain, da, order);
+
+               da += bytes;
+       }
+       return err;
+}
+
+/* release 'da' <-> 'pa' mapping */
+static void unmap_iovm_area(struct iommu_domain *domain, struct omap_iommu *obj,
+                                               struct iovm_struct *area)
+{
+       u32 start;
+       size_t total = area->da_end - area->da_start;
+       const struct sg_table *sgt = area->sgt;
+       struct scatterlist *sg;
+       int i, err;
+
+       BUG_ON(!sgtable_ok(sgt));
+       BUG_ON((!total) || !IS_ALIGNED(total, PAGE_SIZE));
+
+       start = area->da_start;
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               size_t bytes;
+               int order;
+
+               bytes = sg->length + sg->offset;
+               order = get_order(bytes);
+
+               err = iommu_unmap(domain, start, order);
+               if (err < 0)
+                       break;
+
+               dev_dbg(obj->dev, "%s: unmap %08x(%x) %08x\n",
+                               __func__, start, bytes, area->flags);
+
+               BUG_ON(!IS_ALIGNED(bytes, PAGE_SIZE));
+
+               total -= bytes;
+               start += bytes;
+       }
+       BUG_ON(total);
+}
+
+/* template function for all unmapping */
+static struct sg_table *unmap_vm_area(struct iommu_domain *domain,
+                                     struct omap_iommu *obj, const u32 da,
+                                     void (*fn)(const void *), u32 flags)
+{
+       struct sg_table *sgt = NULL;
+       struct iovm_struct *area;
+
+       if (!IS_ALIGNED(da, PAGE_SIZE)) {
+               dev_err(obj->dev, "%s: alignment err(%08x)\n", __func__, da);
+               return NULL;
+       }
+
+       mutex_lock(&obj->mmap_lock);
+
+       area = __find_iovm_area(obj, da);
+       if (!area) {
+               dev_dbg(obj->dev, "%s: no da area(%08x)\n", __func__, da);
+               goto out;
+       }
+
+       if ((area->flags & flags) != flags) {
+               dev_err(obj->dev, "%s: wrong flags(%08x)\n", __func__,
+                       area->flags);
+               goto out;
+       }
+       sgt = (struct sg_table *)area->sgt;
+
+       unmap_iovm_area(domain, obj, area);
+
+       fn(area->va);
+
+       dev_dbg(obj->dev, "%s: %08x-%08x-%08x(%x) %08x\n", __func__,
+               area->da_start, da, area->da_end,
+               area->da_end - area->da_start, area->flags);
+
+       free_iovm_area(obj, area);
+out:
+       mutex_unlock(&obj->mmap_lock);
+
+       return sgt;
+}
+
+static u32 map_iommu_region(struct iommu_domain *domain, struct omap_iommu *obj,
+                               u32 da, const struct sg_table *sgt, void *va,
+                               size_t bytes, u32 flags)
+{
+       int err = -ENOMEM;
+       struct iovm_struct *new;
+
+       mutex_lock(&obj->mmap_lock);
+
+       new = alloc_iovm_area(obj, da, bytes, flags);
+       if (IS_ERR(new)) {
+               err = PTR_ERR(new);
+               goto err_alloc_iovma;
+       }
+       new->va = va;
+       new->sgt = sgt;
+
+       if (map_iovm_area(domain, new, sgt, new->flags))
+               goto err_map;
+
+       mutex_unlock(&obj->mmap_lock);
+
+       dev_dbg(obj->dev, "%s: da:%08x(%x) flags:%08x va:%p\n",
+               __func__, new->da_start, bytes, new->flags, va);
+
+       return new->da_start;
+
+err_map:
+       free_iovm_area(obj, new);
+err_alloc_iovma:
+       mutex_unlock(&obj->mmap_lock);
+       return err;
+}
+
+static inline u32
+__iommu_vmap(struct iommu_domain *domain, struct omap_iommu *obj,
+                               u32 da, const struct sg_table *sgt,
+                               void *va, size_t bytes, u32 flags)
+{
+       return map_iommu_region(domain, obj, da, sgt, va, bytes, flags);
+}
+
+/**
+ * omap_iommu_vmap  -  (d)-(p)-(v) address mapper
+ * @obj:       objective iommu
+ * @sgt:       address of scatter gather table
+ * @flags:     iovma and page property
+ *
+ * Creates 1-n-1 mapping with given @sgt and returns @da.
+ * All @sgt element must be io page size aligned.
+ */
+u32 omap_iommu_vmap(struct iommu_domain *domain, struct omap_iommu *obj, u32 da,
+               const struct sg_table *sgt, u32 flags)
+{
+       size_t bytes;
+       void *va = NULL;
+
+       if (!obj || !obj->dev || !sgt)
+               return -EINVAL;
+
+       bytes = sgtable_len(sgt);
+       if (!bytes)
+               return -EINVAL;
+       bytes = PAGE_ALIGN(bytes);
+
+       if (flags & IOVMF_MMIO) {
+               va = vmap_sg(sgt);
+               if (IS_ERR(va))
+                       return PTR_ERR(va);
+       }
+
+       flags |= IOVMF_DISCONT;
+       flags |= IOVMF_MMIO;
+
+       da = __iommu_vmap(domain, obj, da, sgt, va, bytes, flags);
+       if (IS_ERR_VALUE(da))
+               vunmap_sg(va);
+
+       return da + sgtable_offset(sgt);
+}
+EXPORT_SYMBOL_GPL(omap_iommu_vmap);
+
+/**
+ * omap_iommu_vunmap  -  release virtual mapping obtained by 'omap_iommu_vmap()'
+ * @obj:       objective iommu
+ * @da:                iommu device virtual address
+ *
+ * Free the iommu virtually contiguous memory area starting at
+ * @da, which was returned by 'omap_iommu_vmap()'.
+ */
+struct sg_table *
+omap_iommu_vunmap(struct iommu_domain *domain, struct omap_iommu *obj, u32 da)
+{
+       struct sg_table *sgt;
+       /*
+        * 'sgt' is allocated before 'omap_iommu_vmalloc()' is called.
+        * Just returns 'sgt' to the caller to free
+        */
+       da &= PAGE_MASK;
+       sgt = unmap_vm_area(domain, obj, da, vunmap_sg,
+                                       IOVMF_DISCONT | IOVMF_MMIO);
+       if (!sgt)
+               dev_dbg(obj->dev, "%s: No sgt\n", __func__);
+       return sgt;
+}
+EXPORT_SYMBOL_GPL(omap_iommu_vunmap);
+
+/**
+ * omap_iommu_vmalloc  -  (d)-(p)-(v) address allocator and mapper
+ * @obj:       objective iommu
+ * @da:                contiguous iommu virtual memory
+ * @bytes:     allocation size
+ * @flags:     iovma and page property
+ *
+ * Allocate @bytes linearly and creates 1-n-1 mapping and returns
+ * @da again, which might be adjusted if 'IOVMF_DA_FIXED' is not set.
+ */
+u32
+omap_iommu_vmalloc(struct iommu_domain *domain, struct omap_iommu *obj, u32 da,
+                                               size_t bytes, u32 flags)
+{
+       void *va;
+       struct sg_table *sgt;
+
+       if (!obj || !obj->dev || !bytes)
+               return -EINVAL;
+
+       bytes = PAGE_ALIGN(bytes);
+
+       va = vmalloc(bytes);
+       if (!va)
+               return -ENOMEM;
+
+       flags |= IOVMF_DISCONT;
+       flags |= IOVMF_ALLOC;
+
+       sgt = sgtable_alloc(bytes, flags, da, 0);
+       if (IS_ERR(sgt)) {
+               da = PTR_ERR(sgt);
+               goto err_sgt_alloc;
+       }
+       sgtable_fill_vmalloc(sgt, va);
+
+       da = __iommu_vmap(domain, obj, da, sgt, va, bytes, flags);
+       if (IS_ERR_VALUE(da))
+               goto err_iommu_vmap;
+
+       return da;
+
+err_iommu_vmap:
+       sgtable_drain_vmalloc(sgt);
+       sgtable_free(sgt);
+err_sgt_alloc:
+       vfree(va);
+       return da;
+}
+EXPORT_SYMBOL_GPL(omap_iommu_vmalloc);
+
+/**
+ * omap_iommu_vfree  -  release memory allocated by 'omap_iommu_vmalloc()'
+ * @obj:       objective iommu
+ * @da:                iommu device virtual address
+ *
+ * Frees the iommu virtually continuous memory area starting at
+ * @da, as obtained from 'omap_iommu_vmalloc()'.
+ */
+void omap_iommu_vfree(struct iommu_domain *domain, struct omap_iommu *obj,
+                                                               const u32 da)
+{
+       struct sg_table *sgt;
+
+       sgt = unmap_vm_area(domain, obj, da, vfree,
+                                               IOVMF_DISCONT | IOVMF_ALLOC);
+       if (!sgt)
+               dev_dbg(obj->dev, "%s: No sgt\n", __func__);
+       sgtable_free(sgt);
+}
+EXPORT_SYMBOL_GPL(omap_iommu_vfree);
+
+static int __init iovmm_init(void)
+{
+       const unsigned long flags = SLAB_HWCACHE_ALIGN;
+       struct kmem_cache *p;
+
+       p = kmem_cache_create("iovm_area_cache", sizeof(struct iovm_struct), 0,
+                             flags, NULL);
+       if (!p)
+               return -ENOMEM;
+       iovm_area_cachep = p;
+
+       return 0;
+}
+module_init(iovmm_init);
+
+static void __exit iovmm_exit(void)
+{
+       kmem_cache_destroy(iovm_area_cachep);
+}
+module_exit(iovmm_exit);
+
+MODULE_DESCRIPTION("omap iommu: simple virtual address space management");
+MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
+MODULE_LICENSE("GPL v2");
index 132c18e..c025a82 100644 (file)
@@ -1355,7 +1355,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
                struct mirror_info *p = &conf->mirrors[mirror];
                if (p->recovery_disabled == mddev->recovery_disabled)
                        continue;
-               if (!p->rdev)
+               if (p->rdev)
                        continue;
 
                disk_stack_limits(mddev->gendisk, rdev->bdev,
index 9af2140..f5d53a2 100644 (file)
@@ -18,6 +18,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <media/saa7146.h>
 
 LIST_HEAD(saa7146_devices);
@@ -35,10 +37,9 @@ static void dump_registers(struct saa7146_dev* dev)
 {
        int i = 0;
 
-       INFO((" @ %li jiffies:\n",jiffies));
-       for(i = 0; i <= 0x148; i+=4) {
-               printk("0x%03x: 0x%08x\n",i,saa7146_read(dev,i));
-       }
+       pr_info(" @ %li jiffies:\n", jiffies);
+       for (i = 0; i <= 0x148; i += 4)
+               pr_info("0x%03x: 0x%08x\n", i, saa7146_read(dev, i));
 }
 #endif
 
@@ -72,9 +73,8 @@ static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
                if (saa7146_read(dev, MC2) & 2)
                        break;
                if (err) {
-                       printk(KERN_ERR "%s: %s timed out while waiting for "
-                                       "registers getting programmed\n",
-                                       dev->name, __func__);
+                       pr_err("%s: %s timed out while waiting for registers getting programmed\n",
+                              dev->name, __func__);
                        return -ETIMEDOUT;
                }
                msleep(1);
@@ -88,8 +88,8 @@ static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
                        break;
                saa7146_read(dev, MC2);
                if (err) {
-                       DEB_S(("%s: %s timed out while waiting for transfer "
-                               "completion\n", dev->name, __func__));
+                       DEB_S("%s: %s timed out while waiting for transfer completion\n",
+                             dev->name, __func__);
                        return -ETIMEDOUT;
                }
                msleep(1);
@@ -109,9 +109,8 @@ static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
                if (saa7146_read(dev, MC2) & 2)
                        break;
                if (!loops--) {
-                       printk(KERN_ERR "%s: %s timed out while waiting for "
-                                       "registers getting programmed\n",
-                                       dev->name, __func__);
+                       pr_err("%s: %s timed out while waiting for registers getting programmed\n",
+                              dev->name, __func__);
                        return -ETIMEDOUT;
                }
                udelay(1);
@@ -124,8 +123,8 @@ static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
                        break;
                saa7146_read(dev, MC2);
                if (!loops--) {
-                       DEB_S(("%s: %s timed out while waiting for transfer "
-                               "completion\n", dev->name, __func__));
+                       DEB_S("%s: %s timed out while waiting for transfer completion\n",
+                             dev->name, __func__);
                        return -ETIMEDOUT;
                }
                udelay(5);
@@ -264,7 +263,9 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
        ptr = pt->cpu;
        for (i = 0; i < sglen; i++, list++) {
 /*
-               printk("i:%d, adr:0x%08x, len:%d, offset:%d\n", i,sg_dma_address(list), sg_dma_len(list), list->offset);
+               pr_debug("i:%d, adr:0x%08x, len:%d, offset:%d\n",
+                        i, sg_dma_address(list), sg_dma_len(list),
+                        list->offset);
 */
                for (p = 0; p * 4096 < list->length; p++, ptr++) {
                        *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);
@@ -281,9 +282,9 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
 
 /*
        ptr = pt->cpu;
-       printk("offset: %d\n",pt->offset);
+       pr_debug("offset: %d\n", pt->offset);
        for(i=0;i<5;i++) {
-               printk("ptr1 %d: 0x%08x\n",i,ptr[i]);
+               pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]);
        }
 */
        return 0;
@@ -314,7 +315,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
                }
        }
        if (0 != (isr & (MASK_27))) {
-               DEB_INT(("irq: RPS0 (0x%08x).\n",isr));
+               DEB_INT("irq: RPS0 (0x%08x)\n", isr);
                if (dev->vv_data && dev->vv_callback)
                        dev->vv_callback(dev,isr);
                isr &= ~MASK_27;
@@ -333,14 +334,15 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
                } else {
                        u32 psr = saa7146_read(dev, PSR);
                        u32 ssr = saa7146_read(dev, SSR);
-                       printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
-                              dev->name, isr, psr, ssr);
+                       pr_warn("%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
+                               dev->name, isr, psr, ssr);
                }
                isr &= ~(MASK_16|MASK_17);
        }
        if( 0 != isr ) {
-               ERR(("warning: interrupt enabled, but not handled properly.(0x%08x)\n",isr));
-               ERR(("disabling interrupt source(s)!\n"));
+               ERR("warning: interrupt enabled, but not handled properly.(0x%08x)\n",
+                   isr);
+               ERR("disabling interrupt source(s)!\n");
                SAA7146_IER_DISABLE(dev,isr);
        }
        saa7146_write(dev, ISR, ack_isr);
@@ -360,15 +362,15 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        /* clear out mem for sure */
        dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
        if (!dev) {
-               ERR(("out of memory.\n"));
+               ERR("out of memory\n");
                goto out;
        }
 
-       DEB_EE(("pci:%p\n",pci));
+       DEB_EE("pci:%p\n", pci);
 
        err = pci_enable_device(pci);
        if (err < 0) {
-               ERR(("pci_enable_device() failed.\n"));
+               ERR("pci_enable_device() failed\n");
                goto err_free;
        }
 
@@ -389,7 +391,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        dev->mem = ioremap(pci_resource_start(pci, 0),
                           pci_resource_len(pci, 0));
        if (!dev->mem) {
-               ERR(("ioremap() failed.\n"));
+               ERR("ioremap() failed\n");
                err = -ENODEV;
                goto err_release;
        }
@@ -414,7 +416,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED,
                          dev->name, dev);
        if (err < 0) {
-               ERR(("request_irq() failed.\n"));
+               ERR("request_irq() failed\n");
                goto err_unmap;
        }
 
@@ -444,7 +446,9 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        /* create a nice device name */
        sprintf(dev->name, "saa7146 (%d)", saa7146_num);
 
-       INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device));
+       pr_info("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x)\n",
+               dev->mem, dev->revision, pci->irq,
+               pci->subsystem_vendor, pci->subsystem_device);
        dev->ext = ext;
 
        mutex_init(&dev->v4l2_lock);
@@ -464,12 +468,12 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        err = -ENODEV;
 
        if (ext->probe && ext->probe(dev)) {
-               DEB_D(("ext->probe() failed for %p. skipping device.\n",dev));
+               DEB_D("ext->probe() failed for %p. skipping device.\n", dev);
                goto err_free_i2c;
        }
 
        if (ext->attach(dev, pci_ext)) {
-               DEB_D(("ext->attach() failed for %p. skipping device.\n",dev));
+               DEB_D("ext->attach() failed for %p. skipping device.\n", dev);
                goto err_free_i2c;
        }
        /* V4L extensions will set the pci drvdata to the v4l2_device in the
@@ -521,7 +525,7 @@ static void saa7146_remove_one(struct pci_dev *pdev)
                { NULL, 0 }
        }, *p;
 
-       DEB_EE(("dev:%p\n",dev));
+       DEB_EE("dev:%p\n", dev);
 
        dev->ext->detach(dev);
        /* Zero the PCI drvdata after use. */
@@ -552,21 +556,21 @@ static void saa7146_remove_one(struct pci_dev *pdev)
 
 int saa7146_register_extension(struct saa7146_extension* ext)
 {
-       DEB_EE(("ext:%p\n",ext));
+       DEB_EE("ext:%p\n", ext);
 
        ext->driver.name = ext->name;
        ext->driver.id_table = ext->pci_tbl;
        ext->driver.probe = saa7146_init_one;
        ext->driver.remove = saa7146_remove_one;
 
-       printk("saa7146: register extension '%s'.\n",ext->name);
+       pr_info("register extension '%s'\n", ext->name);
        return pci_register_driver(&ext->driver);
 }
 
 int saa7146_unregister_extension(struct saa7146_extension* ext)
 {
-       DEB_EE(("ext:%p\n",ext));
-       printk("saa7146: unregister extension '%s'.\n",ext->name);
+       DEB_EE("ext:%p\n", ext);
+       pr_info("unregister extension '%s'\n", ext->name);
        pci_unregister_driver(&ext->driver);
        return 0;
 }
index 1bd3dd7..a925461 100644 (file)
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <media/saa7146_vv.h>
 
 /****************************************************************************/
@@ -9,21 +11,23 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
        struct saa7146_vv *vv = dev->vv_data;
 
        if (fh->resources & bit) {
-               DEB_D(("already allocated! want: 0x%02x, cur:0x%02x\n",bit,vv->resources));
+               DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n",
+                     bit, vv->resources);
                /* have it already allocated */
                return 1;
        }
 
        /* is it free? */
        if (vv->resources & bit) {
-               DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit));
+               DEB_D("locked! vv->resources:0x%02x, we want:0x%02x\n",
+                     vv->resources, bit);
                /* no, someone else uses it */
                return 0;
        }
        /* it's free, grab it */
-       fh->resources  |= bit;
+       fh->resources |= bit;
        vv->resources |= bit;
-       DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources));
+       DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources);
        return 1;
 }
 
@@ -34,9 +38,9 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
 
        BUG_ON((fh->resources & bits) != bits);
 
-       fh->resources  &= ~bits;
+       fh->resources &= ~bits;
        vv->resources &= ~bits;
-       DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources));
+       DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources);
 }
 
 
@@ -47,7 +51,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
                                                struct saa7146_buf *buf)
 {
        struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
-       DEB_EE(("dev:%p, buf:%p\n",dev,buf));
+       DEB_EE("dev:%p, buf:%p\n", dev, buf);
 
        BUG_ON(in_interrupt());
 
@@ -66,18 +70,19 @@ int saa7146_buffer_queue(struct saa7146_dev *dev,
                         struct saa7146_buf *buf)
 {
        assert_spin_locked(&dev->slock);
-       DEB_EE(("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf));
+       DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf);
 
        BUG_ON(!q);
 
        if (NULL == q->curr) {
                q->curr = buf;
-               DEB_D(("immediately activating buffer %p\n", buf));
+               DEB_D("immediately activating buffer %p\n", buf);
                buf->activate(dev,buf,NULL);
        } else {
                list_add_tail(&buf->vb.queue,&q->queue);
                buf->vb.state = VIDEOBUF_QUEUED;
-               DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf));
+               DEB_D("adding buffer %p to queue. (active buffer present)\n",
+                     buf);
        }
        return 0;
 }
@@ -87,14 +92,14 @@ void saa7146_buffer_finish(struct saa7146_dev *dev,
                           int state)
 {
        assert_spin_locked(&dev->slock);
-       DEB_EE(("dev:%p, dmaq:%p, state:%d\n", dev, q, state));
-       DEB_EE(("q->curr:%p\n",q->curr));
+       DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state);
+       DEB_EE("q->curr:%p\n", q->curr);
 
        BUG_ON(!q->curr);
 
        /* finish current buffer */
        if (NULL == q->curr) {
-               DEB_D(("aiii. no current buffer\n"));
+               DEB_D("aiii. no current buffer\n");
                return;
        }
 
@@ -112,7 +117,7 @@ void saa7146_buffer_next(struct saa7146_dev *dev,
 
        BUG_ON(!q);
 
-       DEB_INT(("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi));
+       DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi);
 
        assert_spin_locked(&dev->slock);
        if (!list_empty(&q->queue)) {
@@ -122,10 +127,11 @@ void saa7146_buffer_next(struct saa7146_dev *dev,
                if (!list_empty(&q->queue))
                        next = list_entry(q->queue.next,struct saa7146_buf, vb.queue);
                q->curr = buf;
-               DEB_INT(("next buffer: buf:%p, prev:%p, next:%p\n", buf, q->queue.prev,q->queue.next));
+               DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n",
+                       buf, q->queue.prev, q->queue.next);
                buf->activate(dev,buf,next);
        } else {
-               DEB_INT(("no next buffer. stopping.\n"));
+               DEB_INT("no next buffer. stopping.\n");
                if( 0 != vbi ) {
                        /* turn off video-dma3 */
                        saa7146_write(dev,MC1, MASK_20);
@@ -162,11 +168,11 @@ void saa7146_buffer_timeout(unsigned long data)
        struct saa7146_dev *dev = q->dev;
        unsigned long flags;
 
-       DEB_EE(("dev:%p, dmaq:%p\n", dev, q));
+       DEB_EE("dev:%p, dmaq:%p\n", dev, q);
 
        spin_lock_irqsave(&dev->slock,flags);
        if (q->curr) {
-               DEB_D(("timeout on %p\n", q->curr));
+               DEB_D("timeout on %p\n", q->curr);
                saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
        }
 
@@ -194,12 +200,12 @@ static int fops_open(struct file *file)
 
        enum v4l2_buf_type type;
 
-       DEB_EE(("file:%p, dev:%s\n", file, video_device_node_name(vdev)));
+       DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
 
        if (mutex_lock_interruptible(&saa7146_devices_lock))
                return -ERESTARTSYS;
 
-       DEB_D(("using: %p\n",dev));
+       DEB_D("using: %p\n", dev);
 
        type = vdev->vfl_type == VFL_TYPE_GRABBER
             ? V4L2_BUF_TYPE_VIDEO_CAPTURE
@@ -207,7 +213,7 @@ static int fops_open(struct file *file)
 
        /* check if an extension is registered */
        if( NULL == dev->ext ) {
-               DEB_S(("no extension registered for this device.\n"));
+               DEB_S("no extension registered for this device\n");
                result = -ENODEV;
                goto out;
        }
@@ -215,7 +221,7 @@ static int fops_open(struct file *file)
        /* allocate per open data */
        fh = kzalloc(sizeof(*fh),GFP_KERNEL);
        if (NULL == fh) {
-               DEB_S(("cannot allocate memory for per open data.\n"));
+               DEB_S("cannot allocate memory for per open data\n");
                result = -ENOMEM;
                goto out;
        }
@@ -225,13 +231,13 @@ static int fops_open(struct file *file)
        fh->type = type;
 
        if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-               DEB_S(("initializing vbi...\n"));
+               DEB_S("initializing vbi...\n");
                if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
                        result = saa7146_vbi_uops.open(dev,file);
                if (dev->ext_vv_data->vbi_fops.open)
                        dev->ext_vv_data->vbi_fops.open(file);
        } else {
-               DEB_S(("initializing video...\n"));
+               DEB_S("initializing video...\n");
                result = saa7146_video_uops.open(dev,file);
        }
 
@@ -259,7 +265,7 @@ static int fops_release(struct file *file)
        struct saa7146_fh  *fh  = file->private_data;
        struct saa7146_dev *dev = fh->dev;
 
-       DEB_EE(("file:%p\n", file));
+       DEB_EE("file:%p\n", file);
 
        if (mutex_lock_interruptible(&saa7146_devices_lock))
                return -ERESTARTSYS;
@@ -289,12 +295,14 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
 
        switch (fh->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-               DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",file, vma));
+               DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
+                      file, vma);
                q = &fh->video_q;
                break;
                }
        case V4L2_BUF_TYPE_VBI_CAPTURE: {
-               DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",file, vma));
+               DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",
+                      file, vma);
                q = &fh->vbi_q;
                break;
                }
@@ -312,14 +320,14 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
        struct videobuf_buffer *buf = NULL;
        struct videobuf_queue *q;
 
-       DEB_EE(("file:%p, poll:%p\n",file, wait));
+       DEB_EE("file:%p, poll:%p\n", file, wait);
 
        if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
                if( 0 == fh->vbi_q.streaming )
                        return videobuf_poll_stream(file, &fh->vbi_q, wait);
                q = &fh->vbi_q;
        } else {
-               DEB_D(("using video queue.\n"));
+               DEB_D("using video queue\n");
                q = &fh->video_q;
        }
 
@@ -327,17 +335,17 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
                buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
 
        if (!buf) {
-               DEB_D(("buf == NULL!\n"));
+               DEB_D("buf == NULL!\n");
                return POLLERR;
        }
 
        poll_wait(file, &buf->done, wait);
        if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
-               DEB_D(("poll succeeded!\n"));
+               DEB_D("poll succeeded!\n");
                return POLLIN|POLLRDNORM;
        }
 
-       DEB_D(("nothing to poll for, buf->state:%d\n",buf->state));
+       DEB_D("nothing to poll for, buf->state:%d\n", buf->state);
        return 0;
 }
 
@@ -346,18 +354,20 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
        struct saa7146_fh *fh = file->private_data;
 
        switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-//             DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", file, data, (unsigned long)count));
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+/*
+               DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
+                      file, data, (unsigned long)count);
+*/
                return saa7146_video_uops.read(file,data,count,ppos);
-               }
-       case V4L2_BUF_TYPE_VBI_CAPTURE: {
-//             DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count));
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+/*
+               DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
+                      file, data, (unsigned long)count);
+*/
                if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
                        return saa7146_vbi_uops.read(file,data,count,ppos);
-               else
-                       return -EINVAL;
-               }
-               break;
+               return -EINVAL;
        default:
                BUG();
                return 0;
@@ -398,22 +408,22 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status)
 {
        u32 isr = status;
 
-       DEB_INT(("dev:%p, isr:0x%08x\n",dev,(u32)status));
+       DEB_INT("dev:%p, isr:0x%08x\n", dev, (u32)status);
 
        if (0 != (isr & (MASK_27))) {
-               DEB_INT(("irq: RPS0 (0x%08x).\n",isr));
+               DEB_INT("irq: RPS0 (0x%08x)\n", isr);
                saa7146_video_uops.irq_done(dev,isr);
        }
 
        if (0 != (isr & (MASK_28))) {
                u32 mc2 = saa7146_read(dev, MC2);
                if( 0 != (mc2 & MASK_15)) {
-                       DEB_INT(("irq: RPS1 vbi workaround (0x%08x).\n",isr));
+                       DEB_INT("irq: RPS1 vbi workaround (0x%08x)\n", isr);
                        wake_up(&dev->vv_data->vbi_wq);
                        saa7146_write(dev,MC2, MASK_31);
                        return;
                }
-               DEB_INT(("irq: RPS1 (0x%08x).\n",isr));
+               DEB_INT("irq: RPS1 (0x%08x)\n", isr);
                saa7146_vbi_uops.irq_done(dev,isr);
        }
 }
@@ -429,13 +439,13 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
 
        vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
        if (vv == NULL) {
-               ERR(("out of memory. aborting.\n"));
+               ERR("out of memory. aborting.\n");
                return -ENOMEM;
        }
        ext_vv->ops = saa7146_video_ioctl_ops;
        ext_vv->core_ops = &saa7146_video_ioctl_ops;
 
-       DEB_EE(("dev:%p\n",dev));
+       DEB_EE("dev:%p\n", dev);
 
        /* set default values for video parts of the saa7146 */
        saa7146_write(dev, BCS_CTRL, 0x80400040);
@@ -450,7 +460,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
 
        vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle);
        if( NULL == vv->d_clipping.cpu_addr ) {
-               ERR(("out of memory. aborting.\n"));
+               ERR("out of memory. aborting.\n");
                kfree(vv);
                return -1;
        }
@@ -471,7 +481,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
 {
        struct saa7146_vv *vv = dev->vv_data;
 
-       DEB_EE(("dev:%p\n",dev));
+       DEB_EE("dev:%p\n", dev);
 
        v4l2_device_unregister(&dev->v4l2_dev);
        pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
@@ -490,7 +500,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
        int err;
        int i;
 
-       DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type));
+       DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type);
 
        // released by vfd->release
        vfd = video_device_alloc();
@@ -509,13 +519,13 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
 
        err = video_register_device(vfd, type, -1);
        if (err < 0) {
-               ERR(("cannot register v4l2 device. skipping.\n"));
+               ERR("cannot register v4l2 device. skipping.\n");
                video_device_release(vfd);
                return err;
        }
 
-       INFO(("%s: registered device %s [v4l2]\n",
-               dev->name, video_device_node_name(vfd)));
+       pr_info("%s: registered device %s [v4l2]\n",
+               dev->name, video_device_node_name(vfd));
 
        *vid = vfd;
        return 0;
@@ -524,7 +534,7 @@ EXPORT_SYMBOL_GPL(saa7146_register_device);
 
 int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
 {
-       DEB_EE(("dev:%p\n",dev));
+       DEB_EE("dev:%p\n", dev);
 
        video_unregister_device(*vid);
        *vid = NULL;
index 1d1d8d2..79ad73a 100644 (file)
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <media/saa7146_vv.h>
 
@@ -711,8 +713,8 @@ static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa71
 
        int depth = sfmt->depth;
 
-       DEB_CAP(("[size=%dx%d,fields=%s]\n",
-               width,height,v4l2_field_names[field]));
+       DEB_CAP("[size=%dx%d,fields=%s]\n",
+               width, height, v4l2_field_names[field]);
 
        if( bytesperline != 0) {
                vdma1.pitch = bytesperline*2;
@@ -837,8 +839,8 @@ static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa71
        BUG_ON(0 == buf->pt[1].dma);
        BUG_ON(0 == buf->pt[2].dma);
 
-       DEB_CAP(("[size=%dx%d,fields=%s]\n",
-               width,height,v4l2_field_names[field]));
+       DEB_CAP("[size=%dx%d,fields=%s]\n",
+               width, height, v4l2_field_names[field]);
 
        /* fixme: look at bytesperline! */
 
@@ -998,12 +1000,12 @@ void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struc
        struct saa7146_vv *vv = dev->vv_data;
        u32 vdma1_prot_addr;
 
-       DEB_CAP(("buf:%p, next:%p\n",buf,next));
+       DEB_CAP("buf:%p, next:%p\n", buf, next);
 
        vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1);
        if( 0 == vdma1_prot_addr ) {
                /* clear out beginning of streaming bit (rps register 0)*/
-               DEB_CAP(("forcing sync to new frame\n"));
+               DEB_CAP("forcing sync to new frame\n");
                saa7146_write(dev, MC2, MASK_27 );
        }
 
index b2ba9dc..2202719 100644 (file)
@@ -1,8 +1,10 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <media/saa7146_vv.h>
 
 static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
 {
-//fm   DEB_I2C(("'%s'.\n", adapter->name));
+       /* DEB_I2C("'%s'\n", adapter->name); */
 
        return    I2C_FUNC_I2C
                | I2C_FUNC_SMBUS_QUICK
@@ -14,9 +16,7 @@ static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
 static inline u32 saa7146_i2c_status(struct saa7146_dev *dev)
 {
        u32 iicsta = saa7146_read(dev, I2C_STATUS);
-/*
-       DEB_I2C(("status: 0x%08x\n",iicsta));
-*/
+       /* DEB_I2C("status: 0x%08x\n", iicsta); */
        return iicsta;
 }
 
@@ -39,10 +39,11 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op)
           plus one extra byte to address the device */
        mem = 1 + ((mem-1) / 3);
 
-       /* we assume that op points to a memory of at least SAA7146_I2C_MEM bytes
-          size. if we exceed this limit... */
-       if ( (4*mem) > SAA7146_I2C_MEM ) {
-//fm           DEB_I2C(("cannot prepare i2c-message.\n"));
+       /* we assume that op points to a memory of at least
+        * SAA7146_I2C_MEM bytes size. if we exceed this limit...
+        */
+       if ((4 * mem) > SAA7146_I2C_MEM) {
+               /* DEB_I2C("cannot prepare i2c-message\n"); */
                return -ENOMEM;
        }
 
@@ -123,7 +124,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev)
        if ( 0 != ( status & SAA7146_I2C_BUSY) ) {
 
                /* yes, kill ongoing operation */
-               DEB_I2C(("busy_state detected.\n"));
+               DEB_I2C("busy_state detected\n");
 
                /* set "ABORT-OPERATION"-bit (bit 7)*/
                saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
@@ -141,7 +142,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev)
 
        if ( dev->i2c_bitrate != status ) {
 
-               DEB_I2C(("error_state detected. status:0x%08x\n",status));
+               DEB_I2C("error_state detected. status:0x%08x\n", status);
 
                /* Repeat the abort operation. This seems to be necessary
                   after serious protocol errors caused by e.g. the SAA7740 */
@@ -164,7 +165,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev)
        /* if any error is still present, a fatal error has occurred ... */
        status = saa7146_i2c_status(dev);
        if ( dev->i2c_bitrate != status ) {
-               DEB_I2C(("fatal error. status:0x%08x\n",status));
+               DEB_I2C("fatal error. status:0x%08x\n", status);
                return -1;
        }
 
@@ -181,7 +182,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor
        unsigned long timeout;
 
        /* write out i2c-command */
-       DEB_I2C(("before: 0x%08x (status: 0x%08x), %d\n",*dword,saa7146_read(dev, I2C_STATUS), dev->i2c_op));
+       DEB_I2C("before: 0x%08x (status: 0x%08x), %d\n",
+               *dword, saa7146_read(dev, I2C_STATUS), dev->i2c_op);
 
        if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
 
@@ -202,7 +204,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor
                                /* a signal arrived */
                                return -ERESTARTSYS;
 
-                       printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n",
+                       pr_warn("%s %s [irq]: timed out waiting for end of xfer\n",
                                dev->name, __func__);
                        return -EIO;
                }
@@ -220,7 +222,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor
                                break;
                        }
                        if (time_after(jiffies,timeout)) {
-                               printk(KERN_WARNING "%s %s: timed out waiting for MC2\n",
+                               pr_warn("%s %s: timed out waiting for MC2\n",
                                        dev->name, __func__);
                                return -EIO;
                        }
@@ -237,7 +239,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor
                                /* this is normal when probing the bus
                                 * (no answer from nonexisistant device...)
                                 */
-                               printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n",
+                               pr_warn("%s %s [poll]: timed out waiting for end of xfer\n",
                                        dev->name, __func__);
                                return -EIO;
                        }
@@ -257,24 +259,24 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor
                if ( 0 == (status & SAA7146_I2C_ERR) ||
                     0 == (status & SAA7146_I2C_BUSY) ) {
                        /* it may take some time until ERR goes high - ignore */
-                       DEB_I2C(("unexpected i2c status %04x\n", status));
+                       DEB_I2C("unexpected i2c status %04x\n", status);
                }
                if( 0 != (status & SAA7146_I2C_SPERR) ) {
-                       DEB_I2C(("error due to invalid start/stop condition.\n"));
+                       DEB_I2C("error due to invalid start/stop condition\n");
                }
                if( 0 != (status & SAA7146_I2C_DTERR) ) {
-                       DEB_I2C(("error in data transmission.\n"));
+                       DEB_I2C("error in data transmission\n");
                }
                if( 0 != (status & SAA7146_I2C_DRERR) ) {
-                       DEB_I2C(("error when receiving data.\n"));
+                       DEB_I2C("error when receiving data\n");
                }
                if( 0 != (status & SAA7146_I2C_AL) ) {
-                       DEB_I2C(("error because arbitration lost.\n"));
+                       DEB_I2C("error because arbitration lost\n");
                }
 
                /* we handle address-errors here */
                if( 0 != (status & SAA7146_I2C_APERR) ) {
-                       DEB_I2C(("error in address phase.\n"));
+                       DEB_I2C("error in address phase\n");
                        return -EREMOTEIO;
                }
 
@@ -284,7 +286,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor
        /* read back data, just in case we were reading ... */
        *dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER));
 
-       DEB_I2C(("after: 0x%08x\n",*dword));
+       DEB_I2C("after: 0x%08x\n", *dword);
        return 0;
 }
 
@@ -299,7 +301,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
                return -ERESTARTSYS;
 
        for(i=0;i<num;i++) {
-               DEB_I2C(("msg:%d/%d\n",i+1,num));
+               DEB_I2C("msg:%d/%d\n", i+1, num);
        }
 
        /* prepare the message(s), get number of u32s to transfer */
@@ -316,7 +318,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
                /* reset the i2c-device if necessary */
                err = saa7146_i2c_reset(dev);
                if ( 0 > err ) {
-                       DEB_I2C(("could not reset i2c-device.\n"));
+                       DEB_I2C("could not reset i2c-device\n");
                        goto out;
                }
 
@@ -336,7 +338,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
                                   address error and trust the saa7146 address error detection. */
                                if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags))
                                        goto out;
-                               DEB_I2C(("error while sending message(s). starting again.\n"));
+                               DEB_I2C("error while sending message(s). starting again\n");
                                break;
                        }
                }
@@ -356,13 +358,13 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
 
        /* if any things had to be read, get the results */
        if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) {
-               DEB_I2C(("could not cleanup i2c-message.\n"));
+               DEB_I2C("could not cleanup i2c-message\n");
                err = -1;
                goto out;
        }
 
        /* return the number of delivered messages */
-       DEB_I2C(("transmission successful. (msg:%d).\n",err));
+       DEB_I2C("transmission successful. (msg:%d)\n", err);
 out:
        /* another bug in revision 0: the i2c-registers get uploaded randomly by other
           uploads, so we better clear them out before continuing */
@@ -370,7 +372,7 @@ out:
                __le32 zero = 0;
                saa7146_i2c_reset(dev);
                if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
-                       INFO(("revision 0 error. this should never happen.\n"));
+                       pr_info("revision 0 error. this should never happen\n");
                }
        }
 
@@ -400,7 +402,7 @@ static struct i2c_algorithm saa7146_algo = {
 
 int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
 {
-       DEB_EE(("bitrate: 0x%08x\n",bitrate));
+       DEB_EE("bitrate: 0x%08x\n", bitrate);
 
        /* enable i2c-port pins */
        saa7146_write(dev, MC1, (MASK_08 | MASK_24));
index afe8580..b2e7183 100644 (file)
@@ -14,7 +14,7 @@ static int vbi_workaround(struct saa7146_dev *dev)
 
        DECLARE_WAITQUEUE(wait, current);
 
-       DEB_VBI(("dev:%p\n",dev));
+       DEB_VBI("dev:%p\n", dev);
 
        /* once again, a bug in the saa7146: the brs acquisition
           is buggy and especially the BXO-counter does not work
@@ -40,14 +40,14 @@ static int vbi_workaround(struct saa7146_dev *dev)
        WRITE_RPS1(0xc000008c);
        /* wait for vbi_a or vbi_b*/
        if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
-               DEB_D(("...using port b\n"));
+               DEB_D("...using port b\n");
                WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B);
                WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B);
 /*
                WRITE_RPS1(CMD_PAUSE | MASK_09);
 */
        } else {
-               DEB_D(("...using port a\n"));
+               DEB_D("...using port a\n");
                WRITE_RPS1(CMD_PAUSE | MASK_10);
        }
        /* upload brs */
@@ -103,7 +103,7 @@ static int vbi_workaround(struct saa7146_dev *dev)
 
                schedule();
 
-               DEB_VBI(("brs bug workaround %d/1.\n",i));
+               DEB_VBI("brs bug workaround %d/1\n", i);
 
                remove_wait_queue(&vv->vbi_wq, &wait);
                current->state = TASK_RUNNING;
@@ -116,7 +116,8 @@ static int vbi_workaround(struct saa7146_dev *dev)
 
                if(signal_pending(current)) {
 
-                       DEB_VBI(("aborted (rps:0x%08x).\n",saa7146_read(dev,RPS_ADDR1)));
+                       DEB_VBI("aborted (rps:0x%08x)\n",
+                               saa7146_read(dev, RPS_ADDR1));
 
                        /* stop rps1 for sure */
                        saa7146_write(dev, MC1, MASK_29);
@@ -207,7 +208,7 @@ static int buffer_activate(struct saa7146_dev *dev,
        struct saa7146_vv *vv = dev->vv_data;
        buf->vb.state = VIDEOBUF_ACTIVE;
 
-       DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next));
+       DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next);
        saa7146_set_vbi_capture(dev,buf,next);
 
        mod_timer(&vv->vbi_q.timeout, jiffies+BUFFER_TIMEOUT);
@@ -228,10 +229,10 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
        llength = vbi_pixel_to_capture;
        size = lines * llength;
 
-       DEB_VBI(("vb:%p\n",vb));
+       DEB_VBI("vb:%p\n", vb);
 
        if (0 != buf->vb.baddr  &&  buf->vb.bsize < size) {
-               DEB_VBI(("size mismatch.\n"));
+               DEB_VBI("size mismatch\n");
                return -EINVAL;
        }
 
@@ -263,7 +264,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
        return 0;
 
  oops:
-       DEB_VBI(("error out.\n"));
+       DEB_VBI("error out\n");
        saa7146_dma_free(dev,q,buf);
 
        return err;
@@ -279,7 +280,7 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned
        *size = lines * llength;
        *count = 2;
 
-       DEB_VBI(("count:%d, size:%d\n",*count,*size));
+       DEB_VBI("count:%d, size:%d\n", *count, *size);
 
        return 0;
 }
@@ -292,7 +293,7 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
        struct saa7146_vv *vv = dev->vv_data;
        struct saa7146_buf *buf = (struct saa7146_buf *)vb;
 
-       DEB_VBI(("vb:%p\n",vb));
+       DEB_VBI("vb:%p\n", vb);
        saa7146_buffer_queue(dev,&vv->vbi_q,buf);
 }
 
@@ -303,7 +304,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
        struct saa7146_dev *dev = fh->dev;
        struct saa7146_buf *buf = (struct saa7146_buf *)vb;
 
-       DEB_VBI(("vb:%p\n",vb));
+       DEB_VBI("vb:%p\n", vb);
        saa7146_dma_free(dev,q,buf);
 }
 
@@ -321,7 +322,7 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file)
        struct saa7146_dev *dev = fh->dev;
        struct saa7146_vv *vv = dev->vv_data;
        unsigned long flags;
-       DEB_VBI(("dev:%p, fh:%p\n",dev, fh));
+       DEB_VBI("dev:%p, fh:%p\n", dev, fh);
 
        spin_lock_irqsave(&dev->slock,flags);
 
@@ -354,14 +355,14 @@ static void vbi_read_timeout(unsigned long data)
        struct saa7146_fh *fh = file->private_data;
        struct saa7146_dev *dev = fh->dev;
 
-       DEB_VBI(("dev:%p, fh:%p\n",dev, fh));
+       DEB_VBI("dev:%p, fh:%p\n", dev, fh);
 
        vbi_stop(fh, file);
 }
 
 static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
 {
-       DEB_VBI(("dev:%p\n",dev));
+       DEB_VBI("dev:%p\n", dev);
 
        INIT_LIST_HEAD(&vv->vbi_q.queue);
 
@@ -380,11 +381,11 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
        u32 arbtr_ctrl  = saa7146_read(dev, PCI_BT_V1);
        int ret = 0;
 
-       DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
+       DEB_VBI("dev:%p, fh:%p\n", dev, fh);
 
        ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS);
        if (0 == ret) {
-               DEB_S(("cannot get vbi RESOURCE_DMA3_BRS resource\n"));
+               DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n");
                return -EBUSY;
        }
 
@@ -425,7 +426,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
                saa7146_write(dev, BRS_CTRL, 0x00000001);
 
                if (0 != (ret = vbi_workaround(dev))) {
-                       DEB_VBI(("vbi workaround failed!\n"));
+                       DEB_VBI("vbi workaround failed!\n");
                        /* return ret;*/
                }
        }
@@ -439,7 +440,7 @@ static void vbi_close(struct saa7146_dev *dev, struct file *file)
 {
        struct saa7146_fh *fh = file->private_data;
        struct saa7146_vv *vv = dev->vv_data;
-       DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
+       DEB_VBI("dev:%p, fh:%p\n", dev, fh);
 
        if( fh == vv->vbi_streaming ) {
                vbi_stop(fh, file);
@@ -453,13 +454,13 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
        spin_lock(&dev->slock);
 
        if (vv->vbi_q.curr) {
-               DEB_VBI(("dev:%p, curr:%p\n",dev,vv->vbi_q.curr));
+               DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_q.curr);
                /* this must be += 2, one count for each field */
                vv->vbi_fieldcount+=2;
                vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount;
                saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
        } else {
-               DEB_VBI(("dev:%p\n",dev));
+               DEB_VBI("dev:%p\n", dev);
        }
        saa7146_buffer_next(dev,&vv->vbi_q,1);
 
@@ -473,7 +474,7 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff
        struct saa7146_vv *vv = dev->vv_data;
        ssize_t ret = 0;
 
-       DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
+       DEB_VBI("dev:%p, fh:%p\n", dev, fh);
 
        if( NULL == vv->vbi_streaming ) {
                // fixme: check if dma3 is available
@@ -482,7 +483,8 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff
        }
 
        if( fh != vv->vbi_streaming ) {
-               DEB_VBI(("open %p is already using vbi capture.",vv->vbi_streaming));
+               DEB_VBI("open %p is already using vbi capture\n",
+                       vv->vbi_streaming);
                return -EBUSY;
        }
 
index 9aafa4e..384b358 100644 (file)
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <media/saa7146_vv.h>
 #include <media/v4l2-chip-ident.h>
 
@@ -94,7 +96,7 @@ struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fou
                }
        }
 
-       DEB_D(("unknown pixelformat:'%4.4s'\n",(char *)&fourcc));
+       DEB_D("unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
        return NULL;
 }
 
@@ -107,32 +109,32 @@ int saa7146_start_preview(struct saa7146_fh *fh)
        struct v4l2_format fmt;
        int ret = 0, err = 0;
 
-       DEB_EE(("dev:%p, fh:%p\n",dev,fh));
+       DEB_EE("dev:%p, fh:%p\n", dev, fh);
 
        /* check if we have overlay informations */
        if( NULL == fh->ov.fh ) {
-               DEB_D(("no overlay data available. try S_FMT first.\n"));
+               DEB_D("no overlay data available. try S_FMT first.\n");
                return -EAGAIN;
        }
 
        /* check if streaming capture is running */
        if (IS_CAPTURE_ACTIVE(fh) != 0) {
-               DEB_D(("streaming capture is active.\n"));
+               DEB_D("streaming capture is active\n");
                return -EBUSY;
        }
 
        /* check if overlay is running */
        if (IS_OVERLAY_ACTIVE(fh) != 0) {
                if (vv->video_fh == fh) {
-                       DEB_D(("overlay is already active.\n"));
+                       DEB_D("overlay is already active\n");
                        return 0;
                }
-               DEB_D(("overlay is already active in another open.\n"));
+               DEB_D("overlay is already active in another open\n");
                return -EBUSY;
        }
 
        if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
-               DEB_D(("cannot get necessary overlay resources\n"));
+               DEB_D("cannot get necessary overlay resources\n");
                return -EBUSY;
        }
 
@@ -145,13 +147,13 @@ int saa7146_start_preview(struct saa7146_fh *fh)
        fh->ov.win = fmt.fmt.win;
        vv->ov_data = &fh->ov;
 
-       DEB_D(("%dx%d+%d+%d %s field=%s\n",
-               fh->ov.win.w.width,fh->ov.win.w.height,
-               fh->ov.win.w.left,fh->ov.win.w.top,
-               vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field]));
+       DEB_D("%dx%d+%d+%d %s field=%s\n",
+             fh->ov.win.w.width, fh->ov.win.w.height,
+             fh->ov.win.w.left, fh->ov.win.w.top,
+             vv->ov_fmt->name, v4l2_field_names[fh->ov.win.field]);
 
        if (0 != (ret = saa7146_enable_overlay(fh))) {
-               DEB_D(("enabling overlay failed: %d\n",ret));
+               DEB_D("enabling overlay failed: %d\n", ret);
                saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
                return ret;
        }
@@ -168,22 +170,22 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
        struct saa7146_dev *dev = fh->dev;
        struct saa7146_vv *vv = dev->vv_data;
 
-       DEB_EE(("dev:%p, fh:%p\n",dev,fh));
+       DEB_EE("dev:%p, fh:%p\n", dev, fh);
 
        /* check if streaming capture is running */
        if (IS_CAPTURE_ACTIVE(fh) != 0) {
-               DEB_D(("streaming capture is active.\n"));
+               DEB_D("streaming capture is active\n");
                return -EBUSY;
        }
 
        /* check if overlay is running at all */
        if ((vv->video_status & STATUS_OVERLAY) == 0) {
-               DEB_D(("no active overlay.\n"));
+               DEB_D("no active overlay\n");
                return 0;
        }
 
        if (vv->video_fh != fh) {
-               DEB_D(("overlay is active, but in another open.\n"));
+               DEB_D("overlay is active, but in another open\n");
                return -EBUSY;
        }
 
@@ -268,7 +270,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
        int length = dma->sglen;
        struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
 
-       DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));
+       DEB_EE("dev:%p, buf:%p, sg_len:%d\n", dev, buf, length);
 
        if( 0 != IS_PLANAR(sfmt->trans)) {
                struct saa7146_pgtable *pt1 = &buf->pt[0];
@@ -288,7 +290,8 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
                                m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
                                o1 = size%PAGE_SIZE;
                                o2 = (size+(size/4))%PAGE_SIZE;
-                               DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));
+                               DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
+                                       size, m1, m2, m3, o1, o2);
                                break;
                        }
                        case 16: {
@@ -298,7 +301,8 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
                                m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;
                                o1 = size%PAGE_SIZE;
                                o2 = (size+(size/2))%PAGE_SIZE;
-                               DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));
+                               DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
+                                       size, m1, m2, m3, o1, o2);
                                break;
                        }
                        default: {
@@ -387,23 +391,23 @@ static int video_begin(struct saa7146_fh *fh)
        unsigned int resource;
        int ret = 0, err = 0;
 
-       DEB_EE(("dev:%p, fh:%p\n",dev,fh));
+       DEB_EE("dev:%p, fh:%p\n", dev, fh);
 
        if ((vv->video_status & STATUS_CAPTURE) != 0) {
                if (vv->video_fh == fh) {
-                       DEB_S(("already capturing.\n"));
+                       DEB_S("already capturing\n");
                        return 0;
                }
-               DEB_S(("already capturing in another open.\n"));
+               DEB_S("already capturing in another open\n");
                return -EBUSY;
        }
 
        if ((vv->video_status & STATUS_OVERLAY) != 0) {
-               DEB_S(("warning: suspending overlay video for streaming capture.\n"));
+               DEB_S("warning: suspending overlay video for streaming capture\n");
                vv->ov_suspend = vv->video_fh;
                err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
                if (0 != err) {
-                       DEB_D(("suspending video failed. aborting\n"));
+                       DEB_D("suspending video failed. aborting\n");
                        return err;
                }
        }
@@ -420,7 +424,7 @@ static int video_begin(struct saa7146_fh *fh)
 
        ret = saa7146_res_get(fh, resource);
        if (0 == ret) {
-               DEB_S(("cannot get capture resource %d\n",resource));
+               DEB_S("cannot get capture resource %d\n", resource);
                if (vv->ov_suspend != NULL) {
                        saa7146_start_preview(vv->ov_suspend);
                        vv->ov_suspend = NULL;
@@ -448,15 +452,15 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
        unsigned long flags;
        unsigned int resource;
        u32 dmas = 0;
-       DEB_EE(("dev:%p, fh:%p\n",dev,fh));
+       DEB_EE("dev:%p, fh:%p\n", dev, fh);
 
        if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
-               DEB_S(("not capturing.\n"));
+               DEB_S("not capturing\n");
                return 0;
        }
 
        if (vv->video_fh != fh) {
-               DEB_S(("capturing, but in another open.\n"));
+               DEB_S("capturing, but in another open\n");
                return -EBUSY;
        }
 
@@ -530,7 +534,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
        struct saa7146_vv *vv = dev->vv_data;
        struct saa7146_format *fmt;
 
-       DEB_EE(("VIDIOC_S_FBUF\n"));
+       DEB_EE("VIDIOC_S_FBUF\n");
 
        if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
                return -EPERM;
@@ -542,13 +546,13 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
 
        /* planar formats are not allowed for overlay video, clipping and video dma would clash */
        if (fmt->flags & FORMAT_IS_PLANAR)
-               DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",
-                                       (char *)&fmt->pixelformat));
+               DEB_S("planar pixelformat '%4.4s' not allowed for overlay\n",
+                     (char *)&fmt->pixelformat);
 
        /* check if overlay is running */
        if (IS_OVERLAY_ACTIVE(fh) != 0) {
                if (vv->video_fh != fh) {
-                       DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n"));
+                       DEB_D("refusing to change framebuffer informations while overlay is active in another open\n");
                        return -EBUSY;
                }
        }
@@ -559,7 +563,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
 
        if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) {
                vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8;
-               DEB_D(("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline));
+               DEB_D("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline);
        }
        return 0;
 }
@@ -588,7 +592,7 @@ static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *
        if (ctrl == NULL)
                return -EINVAL;
 
-       DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n", c->id));
+       DEB_EE("VIDIOC_QUERYCTRL: id:%d\n", c->id);
        *c = *ctrl;
        return 0;
 }
@@ -607,25 +611,25 @@ static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
        case V4L2_CID_BRIGHTNESS:
                value = saa7146_read(dev, BCS_CTRL);
                c->value = 0xff & (value >> 24);
-               DEB_D(("V4L2_CID_BRIGHTNESS: %d\n", c->value));
+               DEB_D("V4L2_CID_BRIGHTNESS: %d\n", c->value);
                break;
        case V4L2_CID_CONTRAST:
                value = saa7146_read(dev, BCS_CTRL);
                c->value = 0x7f & (value >> 16);
-               DEB_D(("V4L2_CID_CONTRAST: %d\n", c->value));
+               DEB_D("V4L2_CID_CONTRAST: %d\n", c->value);
                break;
        case V4L2_CID_SATURATION:
                value = saa7146_read(dev, BCS_CTRL);
                c->value = 0x7f & (value >> 0);
-               DEB_D(("V4L2_CID_SATURATION: %d\n", c->value));
+               DEB_D("V4L2_CID_SATURATION: %d\n", c->value);
                break;
        case V4L2_CID_VFLIP:
                c->value = vv->vflip;
-               DEB_D(("V4L2_CID_VFLIP: %d\n", c->value));
+               DEB_D("V4L2_CID_VFLIP: %d\n", c->value);
                break;
        case V4L2_CID_HFLIP:
                c->value = vv->hflip;
-               DEB_D(("V4L2_CID_HFLIP: %d\n", c->value));
+               DEB_D("V4L2_CID_HFLIP: %d\n", c->value);
                break;
        default:
                return -EINVAL;
@@ -641,7 +645,7 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
 
        ctrl = ctrl_by_id(c->id);
        if (NULL == ctrl) {
-               DEB_D(("unknown control %d\n", c->id));
+               DEB_D("unknown control %d\n", c->id);
                return -EINVAL;
        }
 
@@ -686,14 +690,14 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
        case V4L2_CID_HFLIP:
                /* fixme: we can support changing VFLIP and HFLIP here... */
                if (IS_CAPTURE_ACTIVE(fh) != 0) {
-                       DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
+                       DEB_D("V4L2_CID_HFLIP while active capture\n");
                        return -EBUSY;
                }
                vv->hflip = c->value;
                break;
        case V4L2_CID_VFLIP:
                if (IS_CAPTURE_ACTIVE(fh) != 0) {
-                       DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
+                       DEB_D("V4L2_CID_VFLIP while active capture\n");
                        return -EBUSY;
                }
                vv->vflip = c->value;
@@ -748,7 +752,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma
        int maxw, maxh;
        int calc_bpl;
 
-       DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
+       DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
 
        fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat);
        if (NULL == fmt)
@@ -777,7 +781,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma
                vv->last_field = V4L2_FIELD_INTERLACED;
                break;
        default:
-               DEB_D(("no known field mode '%d'.\n", field));
+               DEB_D("no known field mode '%d'\n", field);
                return -EINVAL;
        }
 
@@ -796,8 +800,9 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma
                f->fmt.pix.bytesperline = calc_bpl;
 
        f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
-       DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n", f->fmt.pix.width,
-                       f->fmt.pix.height, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage));
+       DEB_D("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",
+             f->fmt.pix.width, f->fmt.pix.height,
+             f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
 
        return 0;
 }
@@ -811,22 +816,23 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_f
        enum v4l2_field field;
        int maxw, maxh;
 
-       DEB_EE(("dev:%p\n", dev));
+       DEB_EE("dev:%p\n", dev);
 
        if (NULL == vv->ov_fb.base) {
-               DEB_D(("no fb base set.\n"));
+               DEB_D("no fb base set\n");
                return -EINVAL;
        }
        if (NULL == vv->ov_fmt) {
-               DEB_D(("no fb fmt set.\n"));
+               DEB_D("no fb fmt set\n");
                return -EINVAL;
        }
        if (win->w.width < 48 || win->w.height < 32) {
-               DEB_D(("min width/height. (%d,%d)\n", win->w.width, win->w.height));
+               DEB_D("min width/height. (%d,%d)\n",
+                     win->w.width, win->w.height);
                return -EINVAL;
        }
        if (win->clipcount > 16) {
-               DEB_D(("clipcount too big.\n"));
+               DEB_D("clipcount too big\n");
                return -EINVAL;
        }
 
@@ -848,7 +854,7 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_f
        case V4L2_FIELD_INTERLACED:
                break;
        default:
-               DEB_D(("no known field mode '%d'.\n", field));
+               DEB_D("no known field mode '%d'\n", field);
                return -EINVAL;
        }
 
@@ -868,16 +874,17 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_forma
        struct saa7146_vv *vv = dev->vv_data;
        int err;
 
-       DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
+       DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
        if (IS_CAPTURE_ACTIVE(fh) != 0) {
-               DEB_EE(("streaming capture is active\n"));
+               DEB_EE("streaming capture is active\n");
                return -EBUSY;
        }
        err = vidioc_try_fmt_vid_cap(file, fh, f);
        if (0 != err)
                return err;
        fh->video_fmt = f->fmt.pix;
-       DEB_EE(("set to pixelformat '%4.4s'\n", (char *)&fh->video_fmt.pixelformat));
+       DEB_EE("set to pixelformat '%4.4s'\n",
+              (char *)&fh->video_fmt.pixelformat);
        return 0;
 }
 
@@ -888,7 +895,7 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_f
        struct saa7146_vv *vv = dev->vv_data;
        int err;
 
-       DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh));
+       DEB_EE("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh);
        err = vidioc_try_fmt_vid_overlay(file, fh, f);
        if (0 != err)
                return err;
@@ -931,7 +938,7 @@ static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
                if (e->index < 0 )
                        return -EINVAL;
                if( e->index < dev->ext_vv_data->num_stds ) {
-                       DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index));
+                       DEB_EE("VIDIOC_ENUMSTD: index:%d\n", e->index);
                        v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name);
                        return 0;
                }
@@ -946,10 +953,10 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
        int found = 0;
        int err, i;
 
-       DEB_EE(("VIDIOC_S_STD\n"));
+       DEB_EE("VIDIOC_S_STD\n");
 
        if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
-               DEB_D(("cannot change video standard while streaming capture is active\n"));
+               DEB_D("cannot change video standard while streaming capture is active\n");
                return -EBUSY;
        }
 
@@ -957,7 +964,7 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
                vv->ov_suspend = vv->video_fh;
                err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
                if (0 != err) {
-                       DEB_D(("suspending video failed. aborting\n"));
+                       DEB_D("suspending video failed. aborting\n");
                        return err;
                }
        }
@@ -978,11 +985,11 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
        }
 
        if (!found) {
-               DEB_EE(("VIDIOC_S_STD: standard not found.\n"));
+               DEB_EE("VIDIOC_S_STD: standard not found\n");
                return -EINVAL;
        }
 
-       DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name));
+       DEB_EE("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name);
        return 0;
 }
 
@@ -990,7 +997,7 @@ static int vidioc_overlay(struct file *file, void *fh, unsigned int on)
 {
        int err;
 
-       DEB_D(("VIDIOC_OVERLAY on:%d\n", on));
+       DEB_D("VIDIOC_OVERLAY on:%d\n", on);
        if (on)
                err = saa7146_start_preview(fh);
        else
@@ -1047,7 +1054,7 @@ static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type typ
        struct saa7146_fh *fh = __fh;
        int err;
 
-       DEB_D(("VIDIOC_STREAMON, type:%d\n", type));
+       DEB_D("VIDIOC_STREAMON, type:%d\n", type);
 
        err = video_begin(fh);
        if (err)
@@ -1066,18 +1073,18 @@ static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type ty
        struct saa7146_vv *vv = dev->vv_data;
        int err;
 
-       DEB_D(("VIDIOC_STREAMOFF, type:%d\n", type));
+       DEB_D("VIDIOC_STREAMOFF, type:%d\n", type);
 
        /* ugly: we need to copy some checks from video_end(),
           because videobuf_streamoff() relies on the capture running.
           check and fix this */
        if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
-               DEB_S(("not capturing.\n"));
+               DEB_S("not capturing\n");
                return 0;
        }
 
        if (vv->video_fh != fh) {
-               DEB_S(("capturing, but in another open.\n"));
+               DEB_S("capturing, but in another open\n");
                return -EBUSY;
        }
 
@@ -1087,7 +1094,7 @@ static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type ty
        else if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
                err = videobuf_streamoff(&fh->vbi_q);
        if (0 != err) {
-               DEB_D(("warning: videobuf_streamoff() failed.\n"));
+               DEB_D("warning: videobuf_streamoff() failed\n");
                video_end(fh, file);
        } else {
                err = video_end(fh, file);
@@ -1174,25 +1181,27 @@ static int buffer_prepare(struct videobuf_queue *q,
        struct saa7146_buf *buf = (struct saa7146_buf *)vb;
        int size,err = 0;
 
-       DEB_CAP(("vbuf:%p\n",vb));
+       DEB_CAP("vbuf:%p\n", vb);
 
        /* sanity checks */
        if (fh->video_fmt.width  < 48 ||
            fh->video_fmt.height < 32 ||
            fh->video_fmt.width  > vv->standard->h_max_out ||
            fh->video_fmt.height > vv->standard->v_max_out) {
-               DEB_D(("w (%d) / h (%d) out of bounds.\n",fh->video_fmt.width,fh->video_fmt.height));
+               DEB_D("w (%d) / h (%d) out of bounds\n",
+                     fh->video_fmt.width, fh->video_fmt.height);
                return -EINVAL;
        }
 
        size = fh->video_fmt.sizeimage;
        if (0 != buf->vb.baddr && buf->vb.bsize < size) {
-               DEB_D(("size mismatch.\n"));
+               DEB_D("size mismatch\n");
                return -EINVAL;
        }
 
-       DEB_CAP(("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
-               fh->video_fmt.width,fh->video_fmt.height,size,v4l2_field_names[fh->video_fmt.field]));
+       DEB_CAP("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
+               fh->video_fmt.width, fh->video_fmt.height,
+               size, v4l2_field_names[fh->video_fmt.field]);
        if (buf->vb.width  != fh->video_fmt.width  ||
            buf->vb.bytesperline != fh->video_fmt.bytesperline ||
            buf->vb.height != fh->video_fmt.height ||
@@ -1238,7 +1247,7 @@ static int buffer_prepare(struct videobuf_queue *q,
        return 0;
 
  oops:
-       DEB_D(("error out.\n"));
+       DEB_D("error out\n");
        saa7146_dma_free(dev,q,buf);
 
        return err;
@@ -1259,7 +1268,7 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned
                *count = (max_memory*1048576) / *size;
        }
 
-       DEB_CAP(("%d buffers, %d bytes each.\n",*count,*size));
+       DEB_CAP("%d buffers, %d bytes each\n", *count, *size);
 
        return 0;
 }
@@ -1272,7 +1281,7 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
        struct saa7146_vv *vv = dev->vv_data;
        struct saa7146_buf *buf = (struct saa7146_buf *)vb;
 
-       DEB_CAP(("vbuf:%p\n",vb));
+       DEB_CAP("vbuf:%p\n", vb);
        saa7146_buffer_queue(fh->dev,&vv->video_q,buf);
 }
 
@@ -1283,7 +1292,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
        struct saa7146_dev *dev = fh->dev;
        struct saa7146_buf *buf = (struct saa7146_buf *)vb;
 
-       DEB_CAP(("vbuf:%p\n",vb));
+       DEB_CAP("vbuf:%p\n", vb);
 
        saa7146_dma_free(dev,q,buf);
 
@@ -1347,18 +1356,14 @@ static void video_close(struct saa7146_dev *dev, struct file *file)
        struct saa7146_fh *fh = file->private_data;
        struct saa7146_vv *vv = dev->vv_data;
        struct videobuf_queue *q = &fh->video_q;
-       int err;
 
-       if (IS_CAPTURE_ACTIVE(fh) != 0) {
-               err = video_end(fh, file);
-       } else if (IS_OVERLAY_ACTIVE(fh) != 0) {
-               err = saa7146_stop_preview(fh);
-       }
+       if (IS_CAPTURE_ACTIVE(fh) != 0)
+               video_end(fh, file);
+       else if (IS_OVERLAY_ACTIVE(fh) != 0)
+               saa7146_stop_preview(fh);
 
        videobuf_stop(q);
-
        /* hmm, why is this function declared void? */
-       /* return err */
 }
 
 
@@ -1368,7 +1373,7 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
        struct saa7146_dmaqueue *q = &vv->video_q;
 
        spin_lock(&dev->slock);
-       DEB_CAP(("called.\n"));
+       DEB_CAP("called\n");
 
        /* only finish the buffer if we have one... */
        if( NULL != q->curr ) {
@@ -1386,15 +1391,15 @@ static ssize_t video_read(struct file *file, char __user *data, size_t count, lo
        struct saa7146_vv *vv = dev->vv_data;
        ssize_t ret = 0;
 
-       DEB_EE(("called.\n"));
+       DEB_EE("called\n");
 
        if ((vv->video_status & STATUS_CAPTURE) != 0) {
                /* fixme: should we allow read() captures while streaming capture? */
                if (vv->video_fh == fh) {
-                       DEB_S(("already capturing.\n"));
+                       DEB_S("already capturing\n");
                        return -EBUSY;
                }
-               DEB_S(("already capturing in another open.\n"));
+               DEB_S("already capturing in another open\n");
                return -EBUSY;
        }
 
index 20d24fc..196c12a 100644 (file)
@@ -28,5 +28,5 @@ obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
 obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
 obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
index d0e70e1..0e74e97 100644 (file)
@@ -430,11 +430,10 @@ static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna)
 {
        struct microtune_priv *priv = fe->tuner_priv;
        unsigned char buf[2];
-       int ret;
 
        buf[0] = 6;
        buf[1] = antenna ? 0x11 : 0x10;
-       ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
+       tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
        tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
 }
 
@@ -574,21 +573,20 @@ static int mt2050_init(struct dvb_frontend *fe)
 {
        struct microtune_priv *priv = fe->tuner_priv;
        unsigned char buf[2];
-       int ret;
 
-       buf[0]=6;
-       buf[1]=0x10;
-       ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); //  power
+       buf[0] = 6;
+       buf[1] = 0x10;
+       tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* power */
 
-       buf[0]=0x0f;
-       buf[1]=0x0f;
-       ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo
+       buf[0] = 0x0f;
+       buf[1] = 0x0f;
+       tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* m1lo */
 
-       buf[0]=0x0d;
-       ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
-       tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
+       buf[0] = 0x0d;
+       tuner_i2c_xfer_send(&priv->i2c_props, buf, 1);
+       tuner_i2c_xfer_recv(&priv->i2c_props, buf, 1);
 
-       tuner_dbg("mt2050: sro is %x\n",buf[0]);
+       tuner_dbg("mt2050: sro is %x\n", buf[0]);
 
        memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops));
 
index 56fe75c..54be9e6 100644 (file)
@@ -309,7 +309,6 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
 static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val);
 static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
        u8 *RegVal, int *count);
-static u32 MXL_GetXtalInt(u32 Xtal_Freq);
 static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq);
 static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe);
 static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe);
@@ -2307,14 +2306,6 @@ static u16 MXL_IFSynthInit(struct dvb_frontend *fe)
        return status ;
 }
 
-static u32 MXL_GetXtalInt(u32 Xtal_Freq)
-{
-       if ((Xtal_Freq % 1000000) == 0)
-               return (Xtal_Freq / 10000);
-       else
-               return (((Xtal_Freq / 1000000) + 1)*100);
-}
-
 static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
 {
        struct mxl5005s_state *state = fe->tuner_priv;
@@ -2324,13 +2315,10 @@ static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
        u32 Kdbl_RF = 2;
        u32 tg_divval;
        u32 tg_lo;
-       u32 Xtal_Int;
 
        u32 Fref_TG;
        u32 Fvco;
 
-       Xtal_Int = MXL_GetXtalInt(state->Fxtal);
-
        state->RF_IN = RF_Freq;
 
        MXL_SynthRFTGLO_Calc(fe);
@@ -2779,6 +2767,16 @@ static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
        tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8;
 
        /* below equation is same as above but much harder to debug.
+        *
+        * static u32 MXL_GetXtalInt(u32 Xtal_Freq)
+        * {
+        *      if ((Xtal_Freq % 1000000) == 0)
+        *              return (Xtal_Freq / 10000);
+        *      else
+        *              return (((Xtal_Freq / 1000000) + 1)*100);
+        * }
+        *
+        * u32 Xtal_Int = MXL_GetXtalInt(state->Fxtal);
         * tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) -
         * ((state->TG_LO/10000)*divider_val *
         * (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 *
index 1f1db20..e29cc2b 100644 (file)
  *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include "tda18212_priv.h"
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "tda18212.h"
+
+struct tda18212_priv {
+       struct tda18212_config *cfg;
+       struct i2c_adapter *i2c;
+};
+
+#define dbg(fmt, arg...)                                       \
+do {                                                           \
+       if (debug)                                              \
+               pr_info("%s: " fmt, __func__, ##arg);           \
+} while (0)
 
 static int debug;
 module_param(debug, int, 0644);
@@ -46,7 +59,8 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
        if (ret == 1) {
                ret = 0;
        } else {
-               warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
+               pr_warn("i2c wr failed ret:%d reg:%02x len:%d\n",
+                       ret, reg, len);
                ret = -EREMOTEIO;
        }
        return ret;
@@ -77,7 +91,8 @@ static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
                memcpy(val, buf, len);
                ret = 0;
        } else {
-               warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
+               pr_warn("i2c rd failed ret:%d reg:%02x len:%d\n",
+                       ret, reg, len);
                ret = -EREMOTEIO;
        }
 
@@ -129,8 +144,8 @@ static int tda18212_set_params(struct dvb_frontend *fe,
                { 0x92, 0x53, 0x03 }, /* DVB-C */
        };
 
-       dbg("%s: delsys=%d RF=%d BW=%d", __func__,
-               c->delivery_system, c->frequency, c->bandwidth_hz);
+       dbg("delsys=%d RF=%d BW=%d\n",
+           c->delivery_system, c->frequency, c->bandwidth_hz);
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
@@ -196,7 +211,7 @@ exit:
        return ret;
 
 error:
-       dbg("%s: failed:%d", __func__, ret);
+       dbg("failed:%d\n", ret);
        goto exit;
 }
 
@@ -245,13 +260,13 @@ struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 
-       dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
+       dbg("ret:%d chip ID:%02x\n", ret, val);
        if (ret || val != 0xc7) {
                kfree(priv);
                return NULL;
        }
 
-       info("NXP TDA18212HN successfully identified.");
+       pr_info("NXP TDA18212HN successfully identified\n");
 
        memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
                sizeof(struct dvb_tuner_ops));
diff --git a/drivers/media/common/tuners/tda18212_priv.h b/drivers/media/common/tuners/tda18212_priv.h
deleted file mode 100644 (file)
index 9adff93..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * NXP TDA18212HN silicon tuner driver
- *
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- *    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.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef TDA18212_PRIV_H
-#define TDA18212_PRIV_H
-
-#include "tda18212.h"
-
-#define LOG_PREFIX "tda18212"
-
-#undef dbg
-#define dbg(f, arg...) \
-       if (debug) \
-               printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
-#undef err
-#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
-#undef info
-#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
-#undef warn
-#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
-
-struct tda18212_priv {
-       struct tda18212_config *cfg;
-       struct i2c_adapter *i2c;
-};
-
-#endif
index aae40e5..39c6457 100644 (file)
@@ -676,10 +676,28 @@ fail:
        return ret;
 }
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+int _tda_printk(struct tda18271_priv *state, const char *level,
+               const char *func, const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+       int rtn;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       if (state)
+               rtn = printk("%s%s: [%d-%04x|%c] %pV",
+                            level, func, i2c_adapter_id(state->i2c_props.adap),
+                            state->i2c_props.addr,
+                            (state->role == TDA18271_MASTER) ? 'M' : 'S',
+                            &vaf);
+       else
+               rtn = printk("%s%s: %pV", level, func, &vaf);
+
+       va_end(args);
+
+       return rtn;
+}
index 57022e8..63cc400 100644 (file)
@@ -1230,7 +1230,7 @@ static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg)
        return 0;
 }
 
-static struct dvb_tuner_ops tda18271_tuner_ops = {
+static const struct dvb_tuner_ops tda18271_tuner_ops = {
        .info = {
                .name = "NXP TDA18271HD",
                .frequency_min  =  45000000,
index 9589ab0..94340f4 100644 (file)
@@ -136,29 +136,26 @@ extern int tda18271_debug;
 #define DBG_ADV  8
 #define DBG_CAL  16
 
-#define tda_printk(st, kern, fmt, arg...) do {\
-       if (st) { \
-               struct tda18271_priv *state = st; \
-               printk(kern "%s: [%d-%04x|%s] " fmt, __func__, \
-                       i2c_adapter_id(state->i2c_props.adap), \
-                       state->i2c_props.addr, \
-                       (state->role == TDA18271_MASTER) \
-                       ? "M" : "S", ##arg); \
-       } else \
-               printk(kern "%s: " fmt, __func__, ##arg); \
+__attribute__((format(printf, 4, 5)))
+int _tda_printk(struct tda18271_priv *state, const char *level,
+               const char *func, const char *fmt, ...);
+
+#define tda_printk(st, lvl, fmt, arg...)                       \
+       _tda_printk(st, lvl, __func__, fmt, ##arg)
+
+#define tda_dprintk(st, lvl, fmt, arg...)                      \
+do {                                                           \
+       if (tda18271_debug & lvl)                               \
+               tda_printk(st, KERN_DEBUG, fmt, ##arg);         \
 } while (0)
 
-#define tda_dprintk(st, lvl, fmt, arg...) do {\
-       if (tda18271_debug & lvl) \
-               tda_printk(st, KERN_DEBUG, fmt, ##arg); } while (0)
-
-#define tda_info(fmt, arg...)     printk(KERN_INFO     fmt, ##arg)
-#define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg)
-#define tda_err(fmt, arg...)  tda_printk(priv, KERN_ERR,     fmt, ##arg)
-#define tda_dbg(fmt, arg...)  tda_dprintk(priv, DBG_INFO,    fmt, ##arg)
-#define tda_map(fmt, arg...)  tda_dprintk(priv, DBG_MAP,     fmt, ##arg)
-#define tda_reg(fmt, arg...)  tda_dprintk(priv, DBG_REG,     fmt, ##arg)
-#define tda_cal(fmt, arg...)  tda_dprintk(priv, DBG_CAL,     fmt, ##arg)
+#define tda_info(fmt, arg...)  pr_info(fmt, ##arg)
+#define tda_warn(fmt, arg...)  tda_printk(priv, KERN_WARNING, fmt, ##arg)
+#define tda_err(fmt, arg...)   tda_printk(priv, KERN_ERR,     fmt, ##arg)
+#define tda_dbg(fmt, arg...)   tda_dprintk(priv, DBG_INFO,    fmt, ##arg)
+#define tda_map(fmt, arg...)   tda_dprintk(priv, DBG_MAP,     fmt, ##arg)
+#define tda_reg(fmt, arg...)   tda_dprintk(priv, DBG_REG,     fmt, ##arg)
+#define tda_cal(fmt, arg...)   tda_dprintk(priv, DBG_CAL,     fmt, ##arg)
 
 #define tda_fail(ret)                                                       \
 ({                                                                          \
index b21b6ea..e0d5b43 100644 (file)
@@ -176,7 +176,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
                if_freq = 5000000;
                break;
        }
-       tuner_freq = params->frequency + if_freq;
+       tuner_freq = params->frequency;
 
        i = 0;
        while (tda827x_table[i].lomax < tuner_freq) {
@@ -185,6 +185,8 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
                i++;
        }
 
+       tuner_freq += if_freq;
+
        N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2);
        buf[0] = 0;
        buf[1] = (N>>8) | 0x40;
@@ -540,7 +542,7 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
                if_freq = 5000000;
                break;
        }
-       tuner_freq = params->frequency + if_freq;
+       tuner_freq = params->frequency;
 
        if (fe->ops.info.type == FE_QAM) {
                dprintk("%s select tda827xa_dvbc\n", __func__);
@@ -554,6 +556,8 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
                i++;
        }
 
+       tuner_freq += if_freq;
+
        N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd;
        buf[0] = 0;            // subaddress
        buf[1] = N >> 8;
index 16fba6b..3acbaa0 100644 (file)
@@ -614,6 +614,13 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
                        p += len;
                        size -= len;
                }
+
+               /* silently fail if the frontend doesn't support I2C flush */
+               rc = do_tuner_callback(fe, XC2028_I2C_FLUSH, 0);
+               if ((rc < 0) && (rc != -EINVAL)) {
+                       tuner_err("error executing flush: %d\n", rc);
+                       return rc;
+               }
        }
        return 0;
 }
@@ -933,11 +940,16 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
         * that xc2028 will be in a safe state.
         * Maybe this might also be needed for DTV.
         */
-       if (new_type == V4L2_TUNER_ANALOG_TV) {
+       switch (new_type) {
+       case V4L2_TUNER_ANALOG_TV:
                rc = send_seq(priv, {0x00, 0x00});
 
-               /* Analog modes require offset = 0 */
-       } else {
+               /* Analog mode requires offset = 0 */
+               break;
+       case V4L2_TUNER_RADIO:
+               /* Radio mode requires offset = 0 */
+               break;
+       case V4L2_TUNER_DIGITAL_TV:
                /*
                 * Digital modes require an offset to adjust to the
                 * proper frequency. The offset depends on what
index 9778c96..9ebfb2d 100644 (file)
@@ -54,6 +54,7 @@ struct xc2028_config {
 /* xc2028 commands for callback */
 #define XC2028_TUNER_RESET     0
 #define XC2028_RESET_CLK       1
+#define XC2028_I2C_FLUSH       2
 
 #if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE))
 extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
index b97cf72..3d04a8d 100644 (file)
@@ -12,5 +12,5 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
 b2c2-flexcop-usb-objs = flexcop-usb.o
 obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
-EXTRA_CFLAGS += -Idrivers/media/common/tuners/
+ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+ccflags-y += -Idrivers/media/common/tuners/
index d98f1d4..0713b3a 100644 (file)
@@ -1,6 +1,6 @@
 obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-EXTRA_CFLAGS += -Idrivers/media/video/bt8xx
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/video/bt8xx
+ccflags-y += -Idrivers/media/common/tuners
index de4fe19..cf7214e 100644 (file)
@@ -6,9 +6,9 @@ ddbridge-objs := ddbridge-core.o
 
 obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/
-EXTRA_CFLAGS += -Idrivers/media/common/tuners/
+ccflags-y += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/dvb/frontends/
+ccflags-y += -Idrivers/media/common/tuners/
 
 # For the staging CI driver cxd2099
-EXTRA_CFLAGS += -Idrivers/staging/cxd2099/
+ccflags-y += -Idrivers/staging/cxd2099/
index 573d540..ba9a643 100644 (file)
@@ -507,15 +507,14 @@ static u32 ddb_input_avail(struct ddb_input *input)
        return 0;
 }
 
-static size_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
+static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
 {
        struct ddb *dev = input->port->dev;
        u32 left = count;
-       u32 idx, off, free, stat = input->stat;
+       u32 idx, free, stat = input->stat;
        int ret;
 
        idx = (stat >> 11) & 0x1f;
-       off = (stat & 0x7ff) << 7;
 
        while (left) {
                if (input->cbuf == idx)
@@ -525,6 +524,8 @@ static size_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
                        free = left;
                ret = copy_to_user(buf, input->vbuf[input->cbuf] +
                                   input->coff, free);
+               if (ret)
+                       return -EFAULT;
                input->coff += free;
                if (input->coff == input->dma_buf_size) {
                        input->coff = 0;
@@ -939,6 +940,8 @@ static ssize_t ts_read(struct file *file, char *buf,
                                break;
                }
                read = ddb_input_read(input, buf, left);
+               if (read < 0)
+                       return read;
                left -= read;
                buf += read;
        }
@@ -1438,7 +1441,7 @@ static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct ddb *dev = file->private_data;
        void *parg = (void *)arg;
-       int res = -EFAULT;
+       int res;
 
        switch (cmd) {
        case IOCTL_DDB_FLASHIO:
@@ -1447,29 +1450,29 @@ static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                u8 *rbuf, *wbuf;
 
                if (copy_from_user(&fio, parg, sizeof(fio)))
-                       break;
-               if (fio.write_len + fio.read_len > 1028) {
-                       printk(KERN_ERR "IOBUF too small\n");
-                       return -ENOMEM;
-               }
+                       return -EFAULT;
+
+               if (fio.write_len > 1028 || fio.read_len > 1028)
+                       return -EINVAL;
+               if (fio.write_len + fio.read_len > 1028)
+                       return -EINVAL;
+
                wbuf = &dev->iobuf[0];
-               if (!wbuf)
-                       return -ENOMEM;
                rbuf = wbuf + fio.write_len;
-               if (copy_from_user(wbuf, fio.write_buf, fio.write_len)) {
-                       vfree(wbuf);
-                       break;
-               }
-               res = flashio(dev, wbuf, fio.write_len,
-                             rbuf, fio.read_len);
+
+               if (copy_from_user(wbuf, fio.write_buf, fio.write_len))
+                       return -EFAULT;
+               res = flashio(dev, wbuf, fio.write_len, rbuf, fio.read_len);
+               if (res)
+                       return res;
                if (copy_to_user(fio.read_buf, rbuf, fio.read_len))
-                       res = -EFAULT;
+                       return -EFAULT;
                break;
        }
        default:
-               break;
+               return -ENOTTY;
        }
-       return res;
+       return 0;
 }
 
 static const struct file_operations ddb_fops = {
index 8ac28b0..95a008b 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_DM1105) += dm1105.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
index efe9c30..2c0acdb 100644 (file)
@@ -149,30 +149,25 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
 
        dprintk ("%s\n", __func__);
 
-       if (mutex_lock_interruptible (&events->mtx))
-               return;
+       if ((status & FE_HAS_LOCK) && fe->ops.get_frontend)
+               fe->ops.get_frontend(fe, &fepriv->parameters_out);
 
-       wp = (events->eventw + 1) % MAX_EVENT;
+       mutex_lock(&events->mtx);
 
+       wp = (events->eventw + 1) % MAX_EVENT;
        if (wp == events->eventr) {
                events->overflow = 1;
                events->eventr = (events->eventr + 1) % MAX_EVENT;
        }
 
        e = &events->events[events->eventw];
-
-       if (status & FE_HAS_LOCK)
-               if (fe->ops.get_frontend)
-                       fe->ops.get_frontend(fe, &fepriv->parameters_out);
-
+       e->status = status;
        e->parameters = fepriv->parameters_out;
 
        events->eventw = wp;
 
        mutex_unlock(&events->mtx);
 
-       e->status = status;
-
        wake_up_interruptible (&events->wait_queue);
 }
 
@@ -207,19 +202,24 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
                        return ret;
        }
 
-       if (mutex_lock_interruptible (&events->mtx))
-               return -ERESTARTSYS;
-
-       memcpy (event, &events->events[events->eventr],
-               sizeof(struct dvb_frontend_event));
-
+       mutex_lock(&events->mtx);
+       *event = events->events[events->eventr];
        events->eventr = (events->eventr + 1) % MAX_EVENT;
-
        mutex_unlock(&events->mtx);
 
        return 0;
 }
 
+static void dvb_frontend_clear_events(struct dvb_frontend *fe)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_fe_events *events = &fepriv->events;
+
+       mutex_lock(&events->mtx);
+       events->eventr = events->eventw;
+       mutex_unlock(&events->mtx);
+}
+
 static void dvb_frontend_init(struct dvb_frontend *fe)
 {
        dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
@@ -537,7 +537,6 @@ static int dvb_frontend_thread(void *data)
 {
        struct dvb_frontend *fe = data;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       unsigned long timeout;
        fe_status_t s;
        enum dvbfe_algo algo;
 
@@ -558,7 +557,7 @@ static int dvb_frontend_thread(void *data)
        while (1) {
                up(&fepriv->sem);           /* is locked when we enter the thread... */
 restart:
-               timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
+               wait_event_interruptible_timeout(fepriv->wait_queue,
                        dvb_frontend_should_wakeup(fe) || kthread_should_stop()
                                || freezing(current),
                        fepriv->delay);
@@ -577,12 +576,10 @@ restart:
 
                if (fepriv->reinitialise) {
                        dvb_frontend_init(fe);
-                       if (fepriv->tone != -1) {
+                       if (fe->ops.set_tone && fepriv->tone != -1)
                                fe->ops.set_tone(fe, fepriv->tone);
-                       }
-                       if (fepriv->voltage != -1) {
+                       if (fe->ops.set_voltage && fepriv->voltage != -1)
                                fe->ops.set_voltage(fe, fepriv->voltage);
-                       }
                        fepriv->reinitialise = 0;
                }
 
@@ -1019,6 +1016,29 @@ static int is_legacy_delivery_system(fe_delivery_system_t s)
        return 0;
 }
 
+/* Initialize the cache with some default values derived from the
+ * legacy frontend_info structure.
+ */
+static void dtv_property_cache_init(struct dvb_frontend *fe,
+                                   struct dtv_frontend_properties *c)
+{
+       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->delivery_system = SYS_DVBS;
+               break;
+       case FE_QAM:
+               c->delivery_system = SYS_DVBC_ANNEX_AC;
+               break;
+       case FE_OFDM:
+               c->delivery_system = SYS_DVBT;
+               break;
+       case FE_ATSC:
+               break;
+       }
+}
+
 /* 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.
@@ -1032,17 +1052,13 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe,
 
        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)
@@ -1060,7 +1076,6 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe,
                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;
@@ -1132,16 +1147,13 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
        p->frequency = c->frequency;
        p->inversion = c->inversion;
 
-       switch(c->modulation) {
-       case PSK_8:
-       case APSK_16:
-       case APSK_32:
-       case QPSK:
+       if (c->delivery_system == SYS_DSS ||
+           c->delivery_system == SYS_DVBS ||
+           c->delivery_system == SYS_DVBS2 ||
+           c->delivery_system == SYS_ISDBS ||
+           c->delivery_system == SYS_TURBO) {
                p->u.qpsk.symbol_rate = c->symbol_rate;
                p->u.qpsk.fec_inner = c->fec_inner;
-               break;
-       default:
-               break;
        }
 
        /* Fake out a generic DVB-T request so we pass validation in the ioctl */
@@ -1824,9 +1836,17 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
 
                        memcpy (&fepriv->parameters_in, parg,
                                sizeof (struct dvb_frontend_parameters));
+                       dtv_property_cache_init(fe, c);
                        dtv_property_cache_sync(fe, c, &fepriv->parameters_in);
                }
 
+               /*
+                * Initialize output parameters to match the values given by
+                * the user. FE_SET_FRONTEND triggers an initial frontend event
+                * with status = 0, which copies output parameters to userspace.
+                */
+               fepriv->parameters_out = fepriv->parameters_in;
+
                memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
                memcpy(&fetunesettings.parameters, parg,
                       sizeof (struct dvb_frontend_parameters));
@@ -1884,8 +1904,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
                /* Request the search algorithm to search */
                fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
 
-               dvb_frontend_wakeup(fe);
+               dvb_frontend_clear_events(fe);
                dvb_frontend_add_event(fe, 0);
+               dvb_frontend_wakeup(fe);
                fepriv->status = 0;
                err = 0;
                break;
index 5590eb6..67bbfa7 100644 (file)
@@ -209,6 +209,7 @@ struct dvb_tuner_ops {
 
        int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
        int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+       int (*get_if_frequency)(struct dvb_frontend *fe, u32 *frequency);
 
 #define TUNER_STATUS_LOCKED 1
 #define TUNER_STATUS_STEREO 2
index 5d73dec..5825716 100644 (file)
@@ -258,6 +258,19 @@ config DVB_USB_AF9005_REMOTE
          Say Y here to support the default remote control decoding for the
          Afatech AF9005 based receiver.
 
+config DVB_USB_PCTV452E
+       tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
+       depends on DVB_USB
+       select TTPCI_EEPROM
+       select DVB_LNBP22 if !DVB_FE_CUSTOMISE
+       select DVB_STB0899 if !DVB_FE_CUSTOMISE
+       select DVB_STB6100 if !DVB_FE_CUSTOMISE
+       help
+         Support for external USB adapter designed by Pinnacle,
+         shipped under the brand name 'PCTV HDTV Pro USB'.
+         Also supports TT Connect S2-3600/3650 cards.
+         Say Y if you own such a device and want to use it.
+
 config DVB_USB_DW2102
        tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support"
        depends on DVB_USB
@@ -374,3 +387,18 @@ config DVB_USB_TECHNISAT_USB2
        select DVB_STV6110x if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the Technisat USB2 DVB-S/S2 device
+
+config DVB_USB_IT913X
+       tristate "it913x driver"
+       depends on DVB_USB
+       select DVB_IT913X_FE
+       help
+         Say Y here to support the it913x device
+
+config DVB_USB_MXL111SF
+       tristate "MxL111SF DTV USB2.0 support"
+       depends on DVB_USB
+       select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+       select VIDEO_TVEEPROM
+       help
+         Say Y here to support the MxL111SF USB2.0 DTV receiver.
index 4bac13d..7d0710b 100644 (file)
@@ -64,6 +64,9 @@ obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
 dvb-usb-anysee-objs = anysee.o
 obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
 
+dvb-usb-pctv452e-objs = pctv452e.o
+obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
+
 dvb-usb-dw2102-objs = dw2102.o
 obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
 
@@ -94,7 +97,15 @@ obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
 dvb-usb-technisat-usb2-objs = technisat-usb2.o
 obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+dvb-usb-it913x-objs := it913x.o
+obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o
+
+dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o
+obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o
+obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
+
+ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/common/tuners
+EXTRA_CFLAGS += -Idrivers/media/dvb/ttpci
 
index b95a95e..2aef3c8 100644 (file)
@@ -127,6 +127,8 @@ static struct dvb_usb_device_properties a800_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .pid_filter_count = 32,
                        .streaming_ctrl   = dibusb2_0_streaming_ctrl,
@@ -147,7 +149,7 @@ static struct dvb_usb_device_properties a800_properties = {
                                        }
                                }
                        },
-
+               }},
                        .size_of_priv     = sizeof(struct dibusb_state),
                },
        },
index 6ad9474..3263e97 100644 (file)
@@ -63,11 +63,9 @@ static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi,
                                 u16 reglo, u8 pos, u8 len, u16 value)
 {
        int ret;
-       u8 temp;
 
        if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff))))
                return ret;
-       temp = (u8) ((value & 0x0300) >> 8);
        return af9005_write_register_bits(d, reghi, pos, len,
                                          (u8) ((value & 0x300) >> 8));
 }
index 0351c0e..bd51a76 100644 (file)
@@ -815,7 +815,7 @@ static int af9005_frontend_attach(struct dvb_usb_adapter *adap)
                        debug_dump(buf, 8, printk);
                }
        }
-       adap->fe = af9005_fe_attach(adap->dev);
+       adap->fe_adap[0].fe = af9005_fe_attach(adap->dev);
        return 0;
 }
 
@@ -999,6 +999,8 @@ static struct dvb_usb_device_properties af9005_properties = {
        .num_adapters = 1,
        .adapter = {
                    {
+                   .num_frontends = 1,
+                   .fe = {{
                     .caps =
                     DVB_USB_ADAP_HAS_PID_FILTER |
                     DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@@ -1018,6 +1020,7 @@ static struct dvb_usb_device_properties af9005_properties = {
                                               }
                                      }
                                },
+                    }},
                     }
                    },
        .power_ctrl = af9005_power_ctrl,
index d7ad05f..c6c275b 100644 (file)
@@ -744,29 +744,31 @@ static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
 };
 
 static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
-       { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_RC,
+       { (USB_VID_TERRATEC << 16) | USB_PID_TERRATEC_CINERGY_T_STICK_RC,
                RC_MAP_TERRATEC_SLIM_2 },
-       { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
+       { (USB_VID_TERRATEC << 16) | USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
                RC_MAP_TERRATEC_SLIM },
-       { (USB_VID_VISIONPLUS << 16) + USB_PID_AZUREWAVE_AD_TU700,
+       { (USB_VID_VISIONPLUS << 16) | USB_PID_AZUREWAVE_AD_TU700,
                RC_MAP_AZUREWAVE_AD_TU700 },
-       { (USB_VID_VISIONPLUS << 16) + USB_PID_TINYTWIN,
+       { (USB_VID_VISIONPLUS << 16) | USB_PID_TINYTWIN,
                RC_MAP_AZUREWAVE_AD_TU700 },
-       { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGI_VOX_MINI_III,
+       { (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGI_VOX_MINI_III,
                RC_MAP_MSI_DIGIVOX_III },
-       { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGIVOX_DUO,
+       { (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGIVOX_DUO,
                RC_MAP_MSI_DIGIVOX_III },
-       { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD,
+       { (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV_DONGLE_GOLD,
                RC_MAP_LEADTEK_Y04G0051 },
-       { (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X,
+       { (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV2000DS,
+               RC_MAP_LEADTEK_Y04G0051 },
+       { (USB_VID_AVERMEDIA << 16) | USB_PID_AVERMEDIA_VOLAR_X,
                RC_MAP_AVERMEDIA_M135A },
-       { (USB_VID_AFATECH << 16) + USB_PID_TREKSTOR_DVBT,
+       { (USB_VID_AFATECH << 16) | USB_PID_TREKSTOR_DVBT,
                RC_MAP_TREKSTOR },
-       { (USB_VID_KWORLD_2 << 16) + USB_PID_TINYTWIN_2,
+       { (USB_VID_KWORLD_2 << 16) | USB_PID_TINYTWIN_2,
                RC_MAP_DIGITALNOW_TINYTWIN },
-       { (USB_VID_GTEK << 16) + USB_PID_TINYTWIN_3,
+       { (USB_VID_GTEK << 16) | USB_PID_TINYTWIN_3,
                RC_MAP_DIGITALNOW_TINYTWIN },
-       { (USB_VID_KWORLD_2 << 16) + USB_PID_SVEON_STV22,
+       { (USB_VID_KWORLD_2 << 16) | USB_PID_SVEON_STV22,
                RC_MAP_MSI_DIGIVOX_III },
        { }
 };
@@ -859,13 +861,13 @@ static int af9015_read_config(struct usb_device *udev)
        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[0].stream.u.bulk.buffersize
+                       af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize
                                = TS_USB11_FRAME_SIZE;
                        /* disable 2nd adapter because we don't have
                           PID-filters */
                        af9015_config.dual_mode = 0;
                } else {
-                       af9015_properties[i].adapter[0].stream.u.bulk.buffersize
+                       af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize
                                = TS_USB20_FRAME_SIZE;
                }
        }
@@ -1111,10 +1113,10 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
        }
 
        /* attach demodulator */
-       adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
+       adap->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
                &adap->dev->i2c_adap);
 
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 static struct mt2060_config af9015_mt2060_config = {
@@ -1188,49 +1190,49 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
        switch (af9015_af9013_config[adap->id].tuner) {
        case AF9013_TUNER_MT2060:
        case AF9013_TUNER_MT2060_2:
-               ret = dvb_attach(mt2060_attach, adap->fe, &adap->dev->i2c_adap,
+               ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe, &adap->dev->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, &adap->dev->i2c_adap,
+               ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
                        &af9015_qt1010_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_TDA18271:
-               ret = dvb_attach(tda18271_attach, adap->fe, 0xc0,
+               ret = dvb_attach(tda18271_attach, adap->fe_adap[0].fe, 0xc0,
                        &adap->dev->i2c_adap,
                        &af9015_tda18271_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_TDA18218:
-               ret = dvb_attach(tda18218_attach, adap->fe,
+               ret = dvb_attach(tda18218_attach, adap->fe_adap[0].fe,
                        &adap->dev->i2c_adap,
                        &af9015_tda18218_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MXL5003D:
-               ret = dvb_attach(mxl5005s_attach, adap->fe,
+               ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
                        &adap->dev->i2c_adap,
                        &af9015_mxl5003_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MXL5005D:
        case AF9013_TUNER_MXL5005R:
-               ret = dvb_attach(mxl5005s_attach, adap->fe,
+               ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
                        &adap->dev->i2c_adap,
                        &af9015_mxl5005_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_ENV77H11D5:
-               ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0,
+               ret = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0xc0,
                        &adap->dev->i2c_adap,
                        DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MC44S803:
-               ret = dvb_attach(mc44s803_attach, adap->fe,
+               ret = dvb_attach(mc44s803_attach, adap->fe_adap[0].fe,
                        &adap->dev->i2c_adap,
                        &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MXL5007T:
-               ret = dvb_attach(mxl5007t_attach, adap->fe,
+               ret = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
                        &adap->dev->i2c_adap,
                        0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
                break;
@@ -1304,6 +1306,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                .num_adapters = 2,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER |
                                DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 
@@ -1319,8 +1323,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                        .count = 6,
                                        .endpoint = 0x84,
                                },
+                       }},
                        },
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .frontend_attach =
                                        af9015_af9013_frontend_attach,
                                .tuner_attach    = af9015_tuner_attach,
@@ -1335,6 +1342,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                                }
                                        }
                                },
+                       }},
                        }
                },
 
@@ -1432,6 +1440,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                .num_adapters = 2,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER |
                                DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 
@@ -1447,8 +1457,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                        .count = 6,
                                        .endpoint = 0x84,
                                },
+                       }},
                        },
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .frontend_attach =
                                        af9015_af9013_frontend_attach,
                                .tuner_attach    = af9015_tuner_attach,
@@ -1463,6 +1476,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                                }
                                        }
                                },
+                       }},
                        }
                },
 
@@ -1549,6 +1563,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                .num_adapters = 2,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER |
                                DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 
@@ -1564,8 +1580,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                        .count = 6,
                                        .endpoint = 0x84,
                                },
+                       }},
                        },
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .frontend_attach =
                                        af9015_af9013_frontend_attach,
                                .tuner_attach    = af9015_tuner_attach,
@@ -1580,6 +1599,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                                }
                                        }
                                },
+                       }},
                        }
                },
 
index 2cbf19a..5f2278b 100644 (file)
@@ -446,6 +446,114 @@ static struct isl6423_config anysee_isl6423_config = {
  * IOE[5] STV0903 1=enabled
  */
 
+static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct anysee_state *state = adap->dev->priv;
+       int ret;
+
+       deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+       /* no frontend sleep control */
+       if (onoff == 0)
+               return 0;
+
+       switch (state->hw) {
+       case ANYSEE_HW_507FA: /* 15 */
+               /* E30 Combo Plus */
+               /* E30 C Plus */
+
+               if ((fe->id ^ dvb_usb_anysee_delsys) == 0)  {
+                       /* disable DVB-T demod on IOD[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
+                               0x01);
+                       if (ret)
+                               goto error;
+
+                       /* enable DVB-C demod on IOD[5] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
+                               0x20);
+                       if (ret)
+                               goto error;
+
+                       /* enable DVB-C tuner on IOE[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
+                               0x01);
+                       if (ret)
+                               goto error;
+               } else {
+                       /* disable DVB-C demod on IOD[5] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
+                               0x20);
+                       if (ret)
+                               goto error;
+
+                       /* enable DVB-T demod on IOD[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
+                               0x01);
+                       if (ret)
+                               goto error;
+
+                       /* enable DVB-T tuner on IOE[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
+                               0x01);
+                       if (ret)
+                               goto error;
+               }
+
+               break;
+       case ANYSEE_HW_508TC: /* 18 */
+       case ANYSEE_HW_508PTC: /* 21 */
+               /* E7 TC */
+               /* E7 PTC */
+
+               if ((fe->id ^ dvb_usb_anysee_delsys) == 0)  {
+                       /* disable DVB-T demod on IOD[6] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
+                               0x40);
+                       if (ret)
+                               goto error;
+
+                       /* enable DVB-C demod on IOD[5] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
+                               0x20);
+                       if (ret)
+                               goto error;
+
+                       /* enable IF route on IOE[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
+                               0x01);
+                       if (ret)
+                               goto error;
+               } else {
+                       /* disable DVB-C demod on IOD[5] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
+                               0x20);
+                       if (ret)
+                               goto error;
+
+                       /* enable DVB-T demod on IOD[6] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
+                               0x40);
+                       if (ret)
+                               goto error;
+
+                       /* enable IF route on IOE[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
+                               0x01);
+                       if (ret)
+                               goto error;
+               }
+
+               break;
+       default:
+               ret = 0;
+       }
+
+error:
+       return ret;
+}
+
 static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
 {
        int ret;
@@ -466,41 +574,54 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                }
        };
 
-       /* Check which hardware we have.
-        * We must do this call two times to get reliable values (hw bug).
-        */
-       ret = anysee_get_hw_info(adap->dev, hw_info);
-       if (ret)
-               goto error;
+       /* detect hardware only once */
+       if (adap->fe_adap[0].fe == NULL) {
+               /* Check which hardware we have.
+                * We must do this call two times to get reliable values (hw bug).
+                */
+               ret = anysee_get_hw_info(adap->dev, hw_info);
+               if (ret)
+                       goto error;
 
-       ret = anysee_get_hw_info(adap->dev, hw_info);
-       if (ret)
-               goto error;
+               ret = anysee_get_hw_info(adap->dev, hw_info);
+               if (ret)
+                       goto error;
 
-       /* Meaning of these info bytes are guessed. */
-       info("firmware version:%d.%d hardware id:%d",
-               hw_info[1], hw_info[2], hw_info[0]);
+               /* Meaning of these info bytes are guessed. */
+               info("firmware version:%d.%d hardware id:%d",
+                       hw_info[1], hw_info[2], hw_info[0]);
 
-       state->hw = hw_info[0];
+               state->hw = hw_info[0];
+       }
+
+       /* set current frondend ID for devices having two frondends */
+       if (adap->fe_adap[0].fe)
+               state->fe_id++;
 
        switch (state->hw) {
        case ANYSEE_HW_507T: /* 2 */
                /* E30 */
 
+               if (state->fe_id)
+                       break;
+
                /* attach demod */
-               adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
+               adap->fe_adap[0].fe = dvb_attach(mt352_attach, &anysee_mt352_config,
                        &adap->dev->i2c_adap);
-               if (adap->fe)
+               if (adap->fe_adap[0].fe)
                        break;
 
                /* attach demod */
-               adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+               adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
                        &adap->dev->i2c_adap);
 
                break;
        case ANYSEE_HW_507CD: /* 6 */
                /* E30 Plus */
 
+               if (state->fe_id)
+                       break;
+
                /* enable DVB-T demod on IOD[0] */
                ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
                if (ret)
@@ -512,33 +633,39 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                        goto error;
 
                /* attach demod */
-               adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
-                       &adap->dev->i2c_adap);
+               adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
+                       &anysee_zl10353_config, &adap->dev->i2c_adap);
 
                break;
        case ANYSEE_HW_507DC: /* 10 */
                /* E30 C Plus */
 
+               if (state->fe_id)
+                       break;
+
                /* enable DVB-C demod on IOD[0] */
                ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
                if (ret)
                        goto error;
 
                /* attach demod */
-               adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config,
-                       &adap->dev->i2c_adap, 0x48);
+               adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
+                       &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48);
 
                break;
        case ANYSEE_HW_507SI: /* 11 */
                /* E30 S2 Plus */
 
+               if (state->fe_id)
+                       break;
+
                /* enable DVB-S/S2 demod on IOD[0] */
                ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
                if (ret)
                        goto error;
 
                /* attach demod */
-               adap->fe = dvb_attach(cx24116_attach, &anysee_cx24116_config,
+               adap->fe_adap[0].fe = dvb_attach(cx24116_attach, &anysee_cx24116_config,
                        &adap->dev->i2c_adap);
 
                break;
@@ -564,55 +691,59 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                if (ret)
                        goto error;
 
-               if (dvb_usb_anysee_delsys) {
-                       /* disable DVB-C demod on IOD[5] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
-                               0x20);
+               if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0)  {
+                       /* disable DVB-T demod on IOD[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
+                               0x01);
                        if (ret)
                                goto error;
 
-                       /* enable DVB-T demod on IOD[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
-                               0x01);
+                       /* enable DVB-C demod on IOD[5] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
+                               0x20);
                        if (ret)
                                goto error;
 
                        /* attach demod */
                        if (tmp == 0xc7) {
                                /* TDA18212 config */
-                               adap->fe = dvb_attach(zl10353_attach,
-                                       &anysee_zl10353_tda18212_config2,
-                                       &adap->dev->i2c_adap);
+                               adap->fe_adap[state->fe_id].fe = dvb_attach(
+                                       tda10023_attach,
+                                       &anysee_tda10023_tda18212_config,
+                                       &adap->dev->i2c_adap, 0x48);
                        } else {
                                /* PLL config */
-                               adap->fe = dvb_attach(zl10353_attach,
-                                       &anysee_zl10353_config,
-                                       &adap->dev->i2c_adap);
+                               adap->fe_adap[state->fe_id].fe = dvb_attach(
+                                       tda10023_attach,
+                                       &anysee_tda10023_config,
+                                       &adap->dev->i2c_adap, 0x48);
                        }
                } else {
-                       /* disable DVB-T demod on IOD[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
-                               0x01);
+                       /* disable DVB-C demod on IOD[5] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
+                               0x20);
                        if (ret)
                                goto error;
 
-                       /* enable DVB-C demod on IOD[5] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
-                               0x20);
+                       /* enable DVB-T demod on IOD[0] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
+                               0x01);
                        if (ret)
                                goto error;
 
                        /* attach demod */
                        if (tmp == 0xc7) {
                                /* TDA18212 config */
-                               adap->fe = dvb_attach(tda10023_attach,
-                                       &anysee_tda10023_tda18212_config,
-                                       &adap->dev->i2c_adap, 0x48);
+                               adap->fe_adap[state->fe_id].fe = dvb_attach(
+                                       zl10353_attach,
+                                       &anysee_zl10353_tda18212_config2,
+                                       &adap->dev->i2c_adap);
                        } else {
                                /* PLL config */
-                               adap->fe = dvb_attach(tda10023_attach,
-                                       &anysee_tda10023_config,
-                                       &adap->dev->i2c_adap, 0x48);
+                               adap->fe_adap[state->fe_id].fe = dvb_attach(
+                                       zl10353_attach,
+                                       &anysee_zl10353_config,
+                                       &adap->dev->i2c_adap);
                        }
                }
 
@@ -627,52 +758,40 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                if (ret)
                        goto error;
 
-               if (dvb_usb_anysee_delsys) {
-                       /* disable DVB-C demod on IOD[5] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
-                               0x20);
-                       if (ret)
-                               goto error;
-
-                       /* enable DVB-T demod on IOD[6] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
+               if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0)  {
+                       /* disable DVB-T demod on IOD[6] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
                                0x40);
                        if (ret)
                                goto error;
 
-                       /* enable IF route on IOE[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
-                               0x01);
+                       /* enable DVB-C demod on IOD[5] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
+                               0x20);
                        if (ret)
                                goto error;
 
                        /* attach demod */
-                       adap->fe = dvb_attach(zl10353_attach,
-                               &anysee_zl10353_tda18212_config,
-                               &adap->dev->i2c_adap);
+                       adap->fe_adap[state->fe_id].fe = dvb_attach(tda10023_attach,
+                               &anysee_tda10023_tda18212_config,
+                               &adap->dev->i2c_adap, 0x48);
                } else {
-                       /* disable DVB-T demod on IOD[6] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
-                               0x40);
-                       if (ret)
-                               goto error;
-
-                       /* enable DVB-C demod on IOD[5] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
+                       /* disable DVB-C demod on IOD[5] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
                                0x20);
                        if (ret)
                                goto error;
 
-                       /* enable IF route on IOE[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
-                               0x01);
+                       /* enable DVB-T demod on IOD[6] */
+                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
+                               0x40);
                        if (ret)
                                goto error;
 
                        /* attach demod */
-                       adap->fe = dvb_attach(tda10023_attach,
-                               &anysee_tda10023_tda18212_config,
-                               &adap->dev->i2c_adap, 0x48);
+                       adap->fe_adap[state->fe_id].fe = dvb_attach(zl10353_attach,
+                               &anysee_zl10353_tda18212_config,
+                               &adap->dev->i2c_adap);
                }
 
                break;
@@ -681,6 +800,9 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                /* E7 S2 */
                /* E7 PS2 */
 
+               if (state->fe_id)
+                       break;
+
                /* enable transport stream on IOA[7] */
                ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
                if (ret)
@@ -692,13 +814,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                        goto error;
 
                /* attach demod */
-               adap->fe = dvb_attach(stv0900_attach, &anysee_stv0900_config,
+               adap->fe_adap[0].fe = dvb_attach(stv0900_attach, &anysee_stv0900_config,
                        &adap->dev->i2c_adap, 0);
 
                break;
        }
 
-       if (!adap->fe) {
+       if (!adap->fe_adap[0].fe) {
                /* we have no frontend :-( */
                ret = -ENODEV;
                err("Unsupported Anysee version. " \
@@ -713,14 +835,14 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
        struct anysee_state *state = adap->dev->priv;
        struct dvb_frontend *fe;
        int ret;
-       deb_info("%s:\n", __func__);
+       deb_info("%s: fe=%d\n", __func__, state->fe_id);
 
        switch (state->hw) {
        case ANYSEE_HW_507T: /* 2 */
                /* E30 */
 
                /* attach tuner */
-               fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1),
+               fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1),
                        NULL, DVB_PLL_THOMSON_DTT7579);
 
                break;
@@ -728,7 +850,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                /* E30 Plus */
 
                /* attach tuner */
-               fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1),
+               fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1),
                        &adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579);
 
                break;
@@ -736,7 +858,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                /* E30 C Plus */
 
                /* attach tuner */
-               fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1),
+               fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc0 >> 1),
                        &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
 
                break;
@@ -744,28 +866,14 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                /* E30 S2 Plus */
 
                /* attach LNB controller */
-               fe = dvb_attach(isl6423_attach, adap->fe, &adap->dev->i2c_adap,
-                       &anysee_isl6423_config);
+               fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe,
+                       &adap->dev->i2c_adap, &anysee_isl6423_config);
 
                break;
        case ANYSEE_HW_507FA: /* 15 */
                /* E30 Combo Plus */
                /* E30 C Plus */
 
-               if (dvb_usb_anysee_delsys) {
-                       /* enable DVB-T tuner on IOE[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
-                               0x01);
-                       if (ret)
-                               goto error;
-               } else {
-                       /* enable DVB-C tuner on IOE[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
-                               0x01);
-                       if (ret)
-                               goto error;
-               }
-
                /* Try first attach TDA18212 silicon tuner on IOE[4], if that
                 * fails attach old simple PLL. */
 
@@ -775,8 +883,8 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                        goto error;
 
                /* attach tuner */
-               fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap,
-                       &anysee_tda18212_config);
+               fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
+                       &adap->dev->i2c_adap, &anysee_tda18212_config);
                if (fe)
                        break;
 
@@ -786,8 +894,9 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                        goto error;
 
                /* attach tuner */
-               fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1),
-                       &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+               fe = dvb_attach(dvb_pll_attach, adap->fe_adap[state->fe_id].fe,
+                       (0xc0 >> 1), &adap->dev->i2c_adap,
+                       DVB_PLL_SAMSUNG_DTOS403IH102A);
 
                break;
        case ANYSEE_HW_508TC: /* 18 */
@@ -801,8 +910,8 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                        goto error;
 
                /* attach tuner */
-               fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap,
-                       &anysee_tda18212_config);
+               fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
+                       &adap->dev->i2c_adap, &anysee_tda18212_config);
 
                break;
        case ANYSEE_HW_508S2: /* 19 */
@@ -811,12 +920,12 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                /* E7 PS2 */
 
                /* attach tuner */
-               fe = dvb_attach(stv6110_attach, adap->fe,
+               fe = dvb_attach(stv6110_attach, adap->fe_adap[0].fe,
                        &anysee_stv6110_config, &adap->dev->i2c_adap);
 
                if (fe) {
                        /* attach LNB controller */
-                       fe = dvb_attach(isl6423_attach, adap->fe,
+                       fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe,
                                &adap->dev->i2c_adap, &anysee_isl6423_config);
                }
 
@@ -918,6 +1027,23 @@ static struct dvb_usb_device_properties anysee_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends    = 2,
+               .frontend_ctrl    = anysee_frontend_ctrl,
+               .fe = {{
+                       .streaming_ctrl   = anysee_streaming_ctrl,
+                       .frontend_attach  = anysee_frontend_attach,
+                       .tuner_attach     = anysee_tuner_attach,
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 8,
+                               .endpoint = 0x82,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = (16*512),
+                                       }
+                               }
+                       },
+               }, {
                        .streaming_ctrl   = anysee_streaming_ctrl,
                        .frontend_attach  = anysee_frontend_attach,
                        .tuner_attach     = anysee_tuner_attach,
@@ -931,6 +1057,7 @@ static struct dvb_usb_device_properties anysee_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
 
index ad6ccd1..57ee500 100644 (file)
@@ -59,6 +59,7 @@ enum cmd {
 struct anysee_state {
        u8 hw; /* PCB ID */
        u8 seq;
+       u8 fe_id:1; /* frondend ID */
 };
 
 #define ANYSEE_HW_507T    2 /* E30 */
index 2351077..b779949 100644 (file)
@@ -140,9 +140,9 @@ static struct zl10353_config au6610_zl10353_config = {
 
 static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
+       adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
                &adap->dev->i2c_adap);
-       if (adap->fe == NULL)
+       if (adap->fe_adap[0].fe == NULL)
                return -ENODEV;
 
        return 0;
@@ -155,7 +155,7 @@ static struct qt1010_config au6610_qt1010_config = {
 static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
 {
        return dvb_attach(qt1010_attach,
-                         adap->fe, &adap->dev->i2c_adap,
+                         adap->fe_adap[0].fe, &adap->dev->i2c_adap,
                          &au6610_qt1010_config) == NULL ? -ENODEV : 0;
 }
 
@@ -204,6 +204,8 @@ static struct dvb_usb_device_properties au6610_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .frontend_attach  = au6610_zl10353_frontend_attach,
                        .tuner_attach     = au6610_qt1010_tuner_attach,
 
@@ -219,6 +221,7 @@ static struct dvb_usb_device_properties au6610_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
 
index 57e2444..bf67b4d 100644 (file)
@@ -40,7 +40,6 @@ static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = {
        { STB0899_DISRX_ST0             , 0x04 },
        { STB0899_DISRX_ST1             , 0x00 },
        { STB0899_DISPARITY             , 0x00 },
-       { STB0899_DISFIFO               , 0x00 },
        { STB0899_DISSTATUS             , 0x20 },
        { STB0899_DISF22                , 0x99 },
        { STB0899_DISF22RX              , 0xa8 },
@@ -782,7 +781,6 @@ static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
 
        u8 buf;
-       int ret;
        struct dvb_usb_adapter *adap = fe->dvb->priv;
 
        struct i2c_msg i2c_msg = {
@@ -800,17 +798,17 @@ static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
        switch (voltage) {
        case SEC_VOLTAGE_13:
                buf = 1;
-               ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
+               i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
                break;
 
        case SEC_VOLTAGE_18:
                buf = 2;
-               ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
+               i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
                break;
 
        case SEC_VOLTAGE_OFF:
                buf = 0;
-               ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
+               i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
                break;
 
        default:
@@ -910,16 +908,16 @@ static int az6027_frontend_attach(struct dvb_usb_adapter *adap)
        az6027_frontend_reset(adap);
 
        deb_info("adap = %p, dev = %p\n", adap, adap->dev);
-       adap->fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap);
+       adap->fe_adap[0].fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap);
 
-       if (adap->fe) {
+       if (adap->fe_adap[0].fe) {
                deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address);
-               if (stb6100_attach(adap->fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) {
+               if (stb6100_attach(adap->fe_adap[0].fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) {
                        deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address);
-                       adap->fe->ops.set_voltage = az6027_set_voltage;
+                       adap->fe_adap[0].fe->ops.set_voltage = az6027_set_voltage;
                        az6027_ci_init(adap);
                } else {
-                       adap->fe = NULL;
+                       adap->fe_adap[0].fe = NULL;
                }
        } else
                warn("no front-end attached\n");
@@ -954,7 +952,6 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int i = 0, j = 0, len = 0;
-       int ret;
        u16 index;
        u16 value;
        int length;
@@ -990,7 +987,7 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
                                index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
                                value = msg[i].addr + (msg[i].len << 8);
                                length = msg[i + 1].len + 6;
-                               ret = az6027_usb_in_op(d, req, value, index, data, length);
+                               az6027_usb_in_op(d, req, value, index, data, length);
                                len = msg[i + 1].len;
                                for (j = 0; j < len; j++)
                                        msg[i + 1].buf[j] = data[j + 5];
@@ -1017,7 +1014,7 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
                                index = 0x0;
                                value = msg[i].addr;
                                length = msg[i].len + 6;
-                               ret = az6027_usb_in_op(d, req, value, index, data, length);
+                               az6027_usb_in_op(d, req, value, index, data, length);
                                len = msg[i].len;
                                for (j = 0; j < len; j++)
                                        msg[i].buf[j] = data[j + 5];
@@ -1106,6 +1103,8 @@ static struct dvb_usb_device_properties az6027_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = az6027_streaming_ctrl,
                        .frontend_attach  = az6027_frontend_attach,
 
@@ -1120,6 +1119,7 @@ static struct dvb_usb_device_properties az6027_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
 /*
index 6d1a304..57afb5a 100644 (file)
@@ -186,9 +186,9 @@ static struct zl10353_config ce6230_zl10353_config = {
 static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
 {
        deb_info("%s:\n", __func__);
-       adap->fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
+       adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
                &adap->dev->i2c_adap);
-       if (adap->fe == NULL)
+       if (adap->fe_adap[0].fe == NULL)
                return -ENODEV;
        return 0;
 }
@@ -214,7 +214,7 @@ static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
 {
        int ret;
        deb_info("%s:\n", __func__);
-       ret = dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap,
+       ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
                        &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
        return ret;
 }
@@ -273,6 +273,8 @@ static struct dvb_usb_device_properties ce6230_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .frontend_attach  = ce6230_zl10353_frontend_attach,
                        .tuner_attach     = ce6230_mxl5003s_tuner_attach,
                        .stream = {
@@ -285,6 +287,7 @@ static struct dvb_usb_device_properties ce6230_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
 
index 16f2ce2..f9d9050 100644 (file)
@@ -69,7 +69,7 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
        char state[3];
        int ret;
 
-       adap->fe = cinergyt2_fe_attach(adap->dev);
+       adap->fe_adap[0].fe = cinergyt2_fe_attach(adap->dev);
 
        ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state,
                                sizeof(state), 0);
@@ -198,6 +198,8 @@ static struct dvb_usb_device_properties cinergyt2_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = cinergyt2_streaming_ctrl,
                        .frontend_attach  = cinergyt2_frontend_attach,
 
@@ -212,6 +214,7 @@ static struct dvb_usb_device_properties cinergyt2_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
 
index acb5fb2..9f2a02c 100644 (file)
@@ -347,7 +347,7 @@ static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d)
 
 static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d)
 {
-       struct usb_data_stream_properties *p = &d->props.adapter[0].stream;
+       struct usb_data_stream_properties *p = &d->props.adapter[0].fe[0].stream;
        const int timeout = 100;
        const int junk_len = p->u.bulk.buffersize;
        u8        *junk;
@@ -725,7 +725,7 @@ static struct max2165_config mygica_d689_max2165_cfg = {
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       dvb_attach(simple_tuner_attach, adap->fe,
+       dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
                   &adap->dev->i2c_adap, 0x61,
                   TUNER_PHILIPS_FMD1216ME_MK3);
        return 0;
@@ -733,27 +733,27 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 
 static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       dvb_attach(dvb_pll_attach, adap->fe, 0x61,
+       dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61,
                   NULL, DVB_PLL_THOMSON_DTT7579);
        return 0;
 }
 
 static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201);
+       dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_LG_Z201);
        return 0;
 }
 
 static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       dvb_attach(dvb_pll_attach, adap->fe, 0x60,
+       dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
                   NULL, DVB_PLL_THOMSON_DTT7579);
        return 0;
 }
 
 static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       dvb_attach(simple_tuner_attach, adap->fe,
+       dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
                   &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF);
        return 0;
 }
@@ -795,9 +795,9 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
        };
 
        /* FIXME: generalize & move to common area */
-       adap->fe->callback = dvico_bluebird_xc2028_callback;
+       adap->fe_adap[0].fe->callback = dvico_bluebird_xc2028_callback;
 
-       fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
+       fe = dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &cfg);
        if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
                return -EIO;
 
@@ -808,7 +808,7 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
 
 static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       dvb_attach(mxl5005s_attach, adap->fe,
+       dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
                   &adap->dev->i2c_adap, &aver_a868r_tuner);
        return 0;
 }
@@ -816,7 +816,7 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
 static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct dvb_frontend *fe;
-       fe = dvb_attach(mxl5005s_attach, adap->fe,
+       fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
                        &adap->dev->i2c_adap, &d680_dmb_tuner);
        return (fe == NULL) ? -EIO : 0;
 }
@@ -824,7 +824,7 @@ static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
 static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct dvb_frontend *fe;
-       fe = dvb_attach(max2165_attach, adap->fe,
+       fe = dvb_attach(max2165_attach, adap->fe_adap[0].fe,
                        &adap->dev->i2c_adap, &mygica_d689_max2165_cfg);
        return (fe == NULL) ? -EIO : 0;
 }
@@ -837,8 +837,9 @@ static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
 
        cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1);
 
-       if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config,
-                                  &adap->dev->i2c_adap)) != NULL)
+       adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config,
+                                        &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) != NULL)
                return 0;
 
        return -EIO;
@@ -851,8 +852,10 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
 
        cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
 
-       if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config,
-                                  &adap->dev->i2c_adap)) != NULL)
+       adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach,
+                                        &cxusb_lgdt3303_config,
+                                        &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) != NULL)
                return 0;
 
        return -EIO;
@@ -860,9 +863,9 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
 
 static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       adap->fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config,
+       adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config,
                              &adap->dev->i2c_adap);
-       if (adap->fe != NULL)
+       if (adap->fe_adap[0].fe != NULL)
                return 0;
 
        return -EIO;
@@ -876,8 +879,9 @@ static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
 
        cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
 
-       if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config,
-                                  &adap->dev->i2c_adap)) != NULL)
+       adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config,
+                                        &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) != NULL)
                return 0;
 
        return -EIO;
@@ -890,11 +894,15 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
 
        cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
 
-       if (((adap->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config,
-                                   &adap->dev->i2c_adap)) != NULL) ||
-               ((adap->fe = dvb_attach(zl10353_attach,
-                                       &cxusb_zl10353_dee1601_config,
-                                       &adap->dev->i2c_adap)) != NULL))
+       adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config,
+                                        &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) != NULL)
+               return 0;
+
+       adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
+                                        &cxusb_zl10353_dee1601_config,
+                                        &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) != NULL)
                return 0;
 
        return -EIO;
@@ -917,9 +925,11 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
        cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
        cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
 
-       if ((adap->fe = dvb_attach(zl10353_attach,
-                                  &cxusb_zl10353_xc3028_config_no_i2c_gate,
-                                  &adap->dev->i2c_adap)) == NULL)
+       adap->fe_adap[0].fe =
+               dvb_attach(zl10353_attach,
+                          &cxusb_zl10353_xc3028_config_no_i2c_gate,
+                          &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) == NULL)
                return -EIO;
 
        /* try to determine if there is no IR decoder on the I2C bus */
@@ -1031,9 +1041,9 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
                return -ENODEV;
        }
 
-       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
                              &cxusb_dualdig4_rev2_config);
-       if (adap->fe == NULL)
+       if (adap->fe_adap[0].fe == NULL)
                return -EIO;
 
        return 0;
@@ -1084,15 +1094,15 @@ static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct dib0700_adapter_state *st = adap->priv;
        struct i2c_adapter *tun_i2c =
-               dib7000p_get_i2c_master(adap->fe,
+               dib7000p_get_i2c_master(adap->fe_adap[0].fe,
                                        DIBX000_I2C_INTERFACE_TUNER, 1);
 
-       if (dvb_attach(dib0070_attach, adap->fe, tun_i2c,
+       if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
            &dib7070p_dib0070_config) == NULL)
                return -ENODEV;
 
-       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
-       adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override;
+       st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+       adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override;
        return 0;
 }
 
@@ -1108,14 +1118,16 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
        cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
        cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
 
-       if ((adap->fe = dvb_attach(zl10353_attach,
-                                  &cxusb_zl10353_xc3028_config,
-                                  &adap->dev->i2c_adap)) != NULL)
+       adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
+                                        &cxusb_zl10353_xc3028_config,
+                                        &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) != NULL)
                return 0;
 
-       if ((adap->fe = dvb_attach(mt352_attach,
-                                  &cxusb_mt352_xc3028_config,
-                                  &adap->dev->i2c_adap)) != NULL)
+       adap->fe_adap[0].fe = dvb_attach(mt352_attach,
+                                        &cxusb_mt352_xc3028_config,
+                                        &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) != NULL)
                return 0;
 
        return -EIO;
@@ -1150,7 +1162,7 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
        usb_clear_halt(d->udev,
                usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
        usb_clear_halt(d->udev,
-               usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint));
+               usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
 
        /* Drain USB pipes to avoid hang after reboot */
        for (n = 0;  n < 5;  n++) {
@@ -1172,8 +1184,8 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
        msleep(100);
 
        /* Attach frontend */
-       adap->fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap);
-       if (adap->fe == NULL)
+       adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap);
+       if (adap->fe_adap[0].fe == NULL)
                return -EIO;
 
        return 0;
@@ -1207,7 +1219,7 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
        usb_clear_halt(d->udev,
                usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
        usb_clear_halt(d->udev,
-               usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint));
+               usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
 
 
        /* Reset the tuner */
@@ -1223,9 +1235,9 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
        msleep(100);
 
        /* Attach frontend */
-       adap->fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg,
+       adap->fe_adap[0].fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg,
                &d->i2c_adap);
-       if (adap->fe == NULL)
+       if (adap->fe_adap[0].fe == NULL)
                return -EIO;
 
        return 0;
@@ -1383,6 +1395,8 @@ static struct dvb_usb_device_properties cxusb_medion_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = cxusb_streaming_ctrl,
                        .frontend_attach  = cxusb_cx22702_frontend_attach,
                        .tuner_attach     = cxusb_fmd1216me_tuner_attach,
@@ -1397,7 +1411,7 @@ static struct dvb_usb_device_properties cxusb_medion_properties = {
                                        }
                                }
                        },
-
+               }},
                },
        },
        .power_ctrl       = cxusb_power_ctrl,
@@ -1429,6 +1443,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = cxusb_streaming_ctrl,
                        .frontend_attach  = cxusb_lgdt3303_frontend_attach,
                        .tuner_attach     = cxusb_lgh064f_tuner_attach,
@@ -1444,6 +1460,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
                                        }
                                }
                        },
+               }},
                },
        },
 
@@ -1483,6 +1500,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = cxusb_streaming_ctrl,
                        .frontend_attach  = cxusb_dee1601_frontend_attach,
                        .tuner_attach     = cxusb_dee1601_tuner_attach,
@@ -1497,6 +1516,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
                                        }
                                }
                        },
+               }},
                },
        },
 
@@ -1544,6 +1564,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
        .num_adapters = 2,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = cxusb_streaming_ctrl,
                        .frontend_attach  = cxusb_mt352_frontend_attach,
                        .tuner_attach     = cxusb_lgz201_tuner_attach,
@@ -1559,6 +1581,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
                                        }
                                }
                        },
+               }},
                },
        },
        .power_ctrl       = cxusb_bluebird_power_ctrl,
@@ -1596,6 +1619,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = cxusb_streaming_ctrl,
                        .frontend_attach  = cxusb_mt352_frontend_attach,
                        .tuner_attach     = cxusb_dtt7579_tuner_attach,
@@ -1611,6 +1636,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
                                        }
                                }
                        },
+               }},
                },
        },
        .power_ctrl       = cxusb_bluebird_power_ctrl,
@@ -1645,6 +1671,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = cxusb_streaming_ctrl,
                        .frontend_attach  = cxusb_dualdig4_frontend_attach,
                        .tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
@@ -1659,6 +1687,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
                                        }
                                }
                        },
+               }},
                },
        },
 
@@ -1695,6 +1724,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = cxusb_streaming_ctrl,
                        .frontend_attach  = cxusb_nano2_frontend_attach,
                        .tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
@@ -1709,6 +1740,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
                                        }
                                }
                        },
+               }},
                },
        },
 
@@ -1747,6 +1779,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = cxusb_streaming_ctrl,
                        .frontend_attach  = cxusb_nano2_frontend_attach,
                        .tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
@@ -1761,6 +1795,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
                                        }
                                }
                        },
+               }},
                },
        },
 
@@ -1796,6 +1831,8 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = cxusb_aver_streaming_ctrl,
                        .frontend_attach  = cxusb_aver_lgdt3303_frontend_attach,
                        .tuner_attach     = cxusb_mxl5003s_tuner_attach,
@@ -1810,7 +1847,7 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
                                        }
                                }
                        },
-
+               }},
                },
        },
        .power_ctrl       = cxusb_aver_power_ctrl,
@@ -1839,10 +1876,12 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .size_of_priv    = sizeof(struct dib0700_adapter_state),
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl  = cxusb_streaming_ctrl,
                        .frontend_attach = cxusb_dualdig4_rev2_frontend_attach,
                        .tuner_attach    = cxusb_dualdig4_rev2_tuner_attach,
-                       .size_of_priv    = sizeof(struct dib0700_adapter_state),
                        /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
@@ -1854,6 +1893,7 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
                                        }
                                }
                        },
+               }},
                },
        },
 
@@ -1889,6 +1929,8 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
                        .frontend_attach  = cxusb_d680_dmb_frontend_attach,
                        .tuner_attach     = cxusb_d680_dmb_tuner_attach,
@@ -1904,6 +1946,7 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
                                        }
                                }
                        },
+               }},
                },
        },
 
@@ -1940,6 +1983,8 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
                        .frontend_attach  = cxusb_mygica_d689_frontend_attach,
                        .tuner_attach     = cxusb_mygica_d689_tuner_attach,
@@ -1955,6 +2000,7 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
                                        }
                                }
                        },
+               }},
                },
        },
 
index 5eb91b4..156cbfc 100644 (file)
@@ -30,6 +30,11 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
        struct dib0700_state *st = d->priv;
        int ret;
 
+       if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+               err("could not acquire lock");
+               return 0;
+       }
+
        ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
                                  REQUEST_GET_VERSION,
                                  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
@@ -46,6 +51,7 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
        if (fwtype != NULL)
                *fwtype     = (st->buf[12] << 24) | (st->buf[13] << 16) |
                        (st->buf[14] << 8) | st->buf[15];
+       mutex_unlock(&d->usb_mutex);
        return ret;
 }
 
@@ -108,7 +114,12 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen
 int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
 {
        struct dib0700_state *st = d->priv;
-       s16 ret;
+       int ret;
+
+       if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+               err("could not acquire lock");
+               return 0;
+       }
 
        st->buf[0] = REQUEST_SET_GPIO;
        st->buf[1] = gpio;
@@ -116,6 +127,7 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_
 
        ret = dib0700_ctrl_wr(d, st->buf, 3);
 
+       mutex_unlock(&d->usb_mutex);
        return ret;
 }
 
@@ -125,6 +137,11 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
        int ret;
 
        if (st->fw_version >= 0x10201) {
+               if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+                       err("could not acquire lock");
+                       return 0;
+               }
+
                st->buf[0] = REQUEST_SET_USB_XFER_LEN;
                st->buf[1] = (nb_ts_packets >> 8) & 0xff;
                st->buf[2] = nb_ts_packets & 0xff;
@@ -132,6 +149,7 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
                deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
 
                ret = dib0700_ctrl_wr(d, st->buf, 3);
+               mutex_unlock(&d->usb_mutex);
        } else {
                deb_info("this firmware does not allow to change the USB xfer len\n");
                ret = -EIO;
@@ -208,6 +226,10 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
 
                } else {
                        /* Write request */
+                       if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+                               err("could not acquire lock");
+                               return 0;
+                       }
                        st->buf[0] = REQUEST_NEW_I2C_WRITE;
                        st->buf[1] = msg[i].addr << 1;
                        st->buf[2] = (en_start << 7) | (en_stop << 6) |
@@ -227,6 +249,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                                                 USB_TYPE_VENDOR | USB_DIR_OUT,
                                                 0, 0, st->buf, msg[i].len + 4,
                                                 USB_CTRL_GET_TIMEOUT);
+                       mutex_unlock(&d->usb_mutex);
                        if (result < 0) {
                                deb_info("i2c write error (status = %d)\n", result);
                                break;
@@ -249,6 +272,10 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
 
        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
+       if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+               err("could not acquire lock");
+               return 0;
+       }
 
        for (i = 0; i < num; i++) {
                /* fill in the address */
@@ -279,6 +306,7 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
                                break;
                }
        }
+       mutex_unlock(&d->usb_mutex);
        mutex_unlock(&d->i2c_mutex);
 
        return i;
@@ -337,7 +365,12 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
        u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
 {
        struct dib0700_state *st = d->priv;
-       s16 ret;
+       int ret;
+
+       if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+               err("could not acquire lock");
+               return 0;
+       }
 
        st->buf[0] = REQUEST_SET_CLOCK;
        st->buf[1] = (en_pll << 7) | (pll_src << 6) |
@@ -352,6 +385,7 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
        st->buf[9] =  dsuScaler         & 0xff; /* LSB */
 
        ret = dib0700_ctrl_wr(d, st->buf, 10);
+       mutex_unlock(&d->usb_mutex);
 
        return ret;
 }
@@ -360,10 +394,16 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
 {
        struct dib0700_state *st = d->priv;
        u16 divider;
+       int ret;
 
        if (scl_kHz == 0)
                return -EINVAL;
 
+       if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+               err("could not acquire lock");
+               return 0;
+       }
+
        st->buf[0] = REQUEST_SET_I2C_PARAM;
        divider = (u16) (30000 / scl_kHz);
        st->buf[1] = 0;
@@ -379,7 +419,11 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
        deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
                (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
                st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
-       return dib0700_ctrl_wr(d, st->buf, 8);
+
+       ret = dib0700_ctrl_wr(d, st->buf, 8);
+       mutex_unlock(&d->usb_mutex);
+
+       return ret;
 }
 
 
@@ -484,13 +528,13 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
                for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
                                adap_num++) {
                        if (fw_version >= 0x10201) {
-                               dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
+                               dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
                        } else {
                                /* for fw version older than 1.20.1,
                                 * the buffersize has to be n times 512 */
-                               dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
-                               if (dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize < 512)
-                                       dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 512;
+                               dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
+                               if (dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize < 512)
+                                       dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 512;
                        }
                }
        }
@@ -515,6 +559,11 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
                }
        }
 
+       if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
+               err("could not acquire lock");
+               return 0;
+       }
+
        st->buf[0] = REQUEST_ENABLE_VIDEO;
        /* this bit gives a kind of command,
         * rather than enabling something or not */
@@ -530,25 +579,28 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
 
        st->channel_state &= ~0x3;
-       if ((adap->stream.props.endpoint != 2)
-                       && (adap->stream.props.endpoint != 3)) {
-               deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->stream.props.endpoint);
+       if ((adap->fe_adap[0].stream.props.endpoint != 2)
+                       && (adap->fe_adap[0].stream.props.endpoint != 3)) {
+               deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->fe_adap[0].stream.props.endpoint);
                if (onoff)
                        st->channel_state |=    1 << (adap->id);
                else
                        st->channel_state |=    1 << ~(adap->id);
        } else {
                if (onoff)
-                       st->channel_state |=    1 << (adap->stream.props.endpoint-2);
+                       st->channel_state |=    1 << (adap->fe_adap[0].stream.props.endpoint-2);
                else
-                       st->channel_state |=    1 << (3-adap->stream.props.endpoint);
+                       st->channel_state |=    1 << (3-adap->fe_adap[0].stream.props.endpoint);
        }
 
        st->buf[2] |= st->channel_state;
 
        deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
 
-       return dib0700_ctrl_wr(adap->dev, st->buf, 4);
+       ret = dib0700_ctrl_wr(adap->dev, st->buf, 4);
+       mutex_unlock(&adap->dev->usb_mutex);
+
+       return ret;
 }
 
 int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
@@ -557,6 +609,11 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
        struct dib0700_state *st = d->priv;
        int new_proto, ret;
 
+       if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+               err("could not acquire lock");
+               return 0;
+       }
+
        st->buf[0] = REQUEST_SET_RC;
        st->buf[1] = 0;
        st->buf[2] = 0;
@@ -567,23 +624,29 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
        else if (rc_type == RC_TYPE_NEC)
                new_proto = 0;
        else if (rc_type == RC_TYPE_RC6) {
-               if (st->fw_version < 0x10200)
-                       return -EINVAL;
+               if (st->fw_version < 0x10200) {
+                       ret = -EINVAL;
+                       goto out;
+               }
 
                new_proto = 2;
-       } else
-               return -EINVAL;
+       } else {
+               ret = -EINVAL;
+               goto out;
+       }
 
        st->buf[1] = new_proto;
 
        ret = dib0700_ctrl_wr(d, st->buf, 3);
        if (ret < 0) {
                err("ir protocol setup failed");
-               return ret;
+               goto out;
        }
 
        d->props.rc.core.protocol = rc_type;
 
+out:
+       mutex_unlock(&d->usb_mutex);
        return ret;
 }
 
index d0ea5b6..f313182 100644 (file)
@@ -101,7 +101,7 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
                }
        }
        st->mt2060_if1[adap->id] = 1220;
-       return (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap,
+       return (adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap,
                (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
 }
 
@@ -118,15 +118,16 @@ static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval)
 static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
-       struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
+       struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1);
        s8 a;
        int if1=1220;
        if (adap->dev->udev->descriptor.idVendor  == cpu_to_le16(USB_VID_HAUPPAUGE) &&
                adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) {
                if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a;
        }
-       return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id],
-               if1) == NULL ? -ENODEV : 0;
+       return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c,
+                         &bristol_mt2060_config[adap->id], if1) == NULL ?
+                         -ENODEV : 0;
 }
 
 /* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
@@ -279,10 +280,12 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
                }
        }
 
-       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
-                               &stk7700d_dib7000p_mt2266_config[adap->id]);
+       adap->fe_adap[0].fe =
+               dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+                          0x80 + (adap->id << 1),
+                          &stk7700d_dib7000p_mt2266_config[adap->id]);
 
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
@@ -306,17 +309,19 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
                }
        }
 
-       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
-                               &stk7700d_dib7000p_mt2266_config[adap->id]);
+       adap->fe_adap[0].fe =
+               dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+                          0x80 + (adap->id << 1),
+                          &stk7700d_dib7000p_mt2266_config[adap->id]);
 
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct i2c_adapter *tun_i2c;
-       tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
-       return dvb_attach(mt2266_attach, adap->fe, tun_i2c,
+       tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+       return dvb_attach(mt2266_attach, adap->fe_adap[0].fe, tun_i2c,
                &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;
 }
 
@@ -396,8 +401,8 @@ static int stk7700ph_xc3028_callback(void *ptr, int component,
        switch (command) {
        case XC2028_TUNER_RESET:
                /* Send the tuner in then out of reset */
-               dib7000p_set_gpio(adap->fe, 8, 0, 0); msleep(10);
-               dib7000p_set_gpio(adap->fe, 8, 0, 1);
+               dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0); msleep(10);
+               dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
                break;
        case XC2028_RESET_CLK:
                break;
@@ -447,25 +452,25 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap)
                return -ENODEV;
        }
 
-       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
                &stk7700ph_dib7700_xc3028_config);
 
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct i2c_adapter *tun_i2c;
 
-       tun_i2c = dib7000p_get_i2c_master(adap->fe,
+       tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe,
                DIBX000_I2C_INTERFACE_TUNER, 1);
 
        stk7700ph_xc3028_config.i2c_adap = tun_i2c;
 
        /* FIXME: generalize & move to common area */
-       adap->fe->callback = stk7700ph_xc3028_callback;
+       adap->fe_adap[0].fe->callback = stk7700ph_xc3028_callback;
 
-       return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config)
+       return dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &stk7700ph_xc3028_config)
                == NULL ? -ENODEV : 0;
 }
 
@@ -685,12 +690,12 @@ static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap)
        st->mt2060_if1[0] = 1220;
 
        if (dib7000pc_detection(&adap->dev->i2c_adap)) {
-               adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config);
+               adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config);
                st->is_dib7000pc = 1;
        } else
-               adap->fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config);
+               adap->fe_adap[0].fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config);
 
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 static struct mt2060_config stk7700p_mt2060_config = {
@@ -709,11 +714,11 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
                if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a;
        }
        if (st->is_dib7000pc)
-               tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+               tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
        else
-               tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+               tun_i2c = dib7000m_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
 
-       return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config,
+       return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk7700p_mt2060_config,
                if1) == NULL ? -ENODEV : 0;
 }
 
@@ -843,33 +848,33 @@ static int dib7770_set_param_override(struct dvb_frontend *fe,
 static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap)
 {
         struct dib0700_adapter_state *st = adap->priv;
-        struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe,
+        struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe,
                         DIBX000_I2C_INTERFACE_TUNER, 1);
 
-        if (dvb_attach(dib0070_attach, adap->fe, tun_i2c,
-                                &dib7770p_dib0070_config) == NULL)
+        if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
+                       &dib7770p_dib0070_config) == NULL)
                 return -ENODEV;
 
-        st->set_param_save = adap->fe->ops.tuner_ops.set_params;
-        adap->fe->ops.tuner_ops.set_params = dib7770_set_param_override;
+        st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+        adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7770_set_param_override;
         return 0;
 }
 
 static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct dib0700_adapter_state *st = adap->priv;
-       struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+       struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
 
        if (adap->id == 0) {
-               if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL)
+               if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL)
                        return -ENODEV;
        } else {
-               if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL)
+               if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL)
                        return -ENODEV;
        }
 
-       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
-       adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override;
+       st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+       adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override;
        return 0;
 }
 
@@ -878,26 +883,26 @@ static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index,
 {
        struct dib0700_state *st = adapter->dev->priv;
        if (st->is_dib7000pc)
-               return dib7000p_pid_filter(adapter->fe, index, pid, onoff);
-       return dib7000m_pid_filter(adapter->fe, index, pid, onoff);
+               return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
+       return dib7000m_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
 }
 
 static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
 {
        struct dib0700_state *st = adapter->dev->priv;
        if (st->is_dib7000pc)
-               return dib7000p_pid_filter_ctrl(adapter->fe, onoff);
-       return dib7000m_pid_filter_ctrl(adapter->fe, onoff);
+               return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
+       return dib7000m_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
 }
 
 static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
 {
-    return dib7000p_pid_filter(adapter->fe, index, pid, onoff);
+       return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
 }
 
 static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
 {
-    return dib7000p_pid_filter_ctrl(adapter->fe, onoff);
+       return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
 }
 
 static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
@@ -955,9 +960,9 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
                return -ENODEV;
        }
 
-       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
                &dib7070p_dib7000p_config);
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 /* STK7770P */
@@ -1007,9 +1012,9 @@ static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap)
                return -ENODEV;
        }
 
-       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
                &dib7770p_dib7000p_config);
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 /* DIB807x generic */
@@ -1225,34 +1230,34 @@ static int dib807x_set_param_override(struct dvb_frontend *fe,
 static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct dib0700_adapter_state *st = adap->priv;
-       struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe,
+       struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe,
                        DIBX000_I2C_INTERFACE_TUNER, 1);
 
        if (adap->id == 0) {
-               if (dvb_attach(dib0070_attach, adap->fe, tun_i2c,
+               if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
                                &dib807x_dib0070_config[0]) == NULL)
                        return -ENODEV;
        } else {
-               if (dvb_attach(dib0070_attach, adap->fe, tun_i2c,
+               if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
                                &dib807x_dib0070_config[1]) == NULL)
                        return -ENODEV;
        }
 
-       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
-       adap->fe->ops.tuner_ops.set_params = dib807x_set_param_override;
+       st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+       adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib807x_set_param_override;
        return 0;
 }
 
 static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index,
        u16 pid, int onoff)
 {
-       return dib8000_pid_filter(adapter->fe, index, pid, onoff);
+       return dib8000_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
 }
 
 static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter,
                int onoff)
 {
-       return dib8000_pid_filter_ctrl(adapter->fe, onoff);
+       return dib8000_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
 }
 
 /* STK807x */
@@ -1276,10 +1281,10 @@ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap)
        dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
                                0x80);
 
-       adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
+       adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
                              &dib807x_dib8000_config[0]);
 
-       return adap->fe == NULL ?  -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
 }
 
 /* STK807xPVR */
@@ -1305,10 +1310,10 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
        /* initialize IC 0 */
        dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80);
 
-       adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
+       adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
                              &dib807x_dib8000_config[0]);
 
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
@@ -1316,10 +1321,10 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
        /* initialize IC 1 */
        dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82);
 
-       adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82,
+       adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82,
                              &dib807x_dib8000_config[1]);
 
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 /* STK8096GP */
@@ -1546,13 +1551,13 @@ static int dib8096_set_param_override(struct dvb_frontend *fe,
 static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct dib0700_adapter_state *st = adap->priv;
-       struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+       struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
 
-       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL)
+       if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
                return -ENODEV;
 
-       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
-       adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override;
+       st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+       adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override;
        return 0;
 }
 
@@ -1575,30 +1580,30 @@ static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
 
        dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80);
 
-       adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
+       adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
 
-       return adap->fe == NULL ?  -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
 }
 
 static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct dib0700_adapter_state *st = adap->priv;
        struct i2c_adapter *tun_i2c;
-       struct dvb_frontend *fe_slave  = dib8000_get_slave_frontend(adap->fe, 1);
+       struct dvb_frontend *fe_slave  = dib8000_get_slave_frontend(adap->fe_adap[0].fe, 1);
 
        if (fe_slave) {
                tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1);
                if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL)
                        return -ENODEV;
-               fe_slave->dvb = adap->fe->dvb;
+               fe_slave->dvb = adap->fe_adap[0].fe->dvb;
                fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override;
        }
-       tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
-       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL)
+       tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+       if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
                return -ENODEV;
 
-       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
-       adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override;
+       st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+       adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override;
 
        return 0;
 }
@@ -1626,12 +1631,12 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
 
        dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80);
 
-       adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
-       if (adap->fe == NULL)
+       adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
+       if (adap->fe_adap[0].fe == NULL)
                return -ENODEV;
 
        fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]);
-       dib8000_set_slave_frontend(adap->fe, fe_slave);
+       dib8000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave);
 
        return fe_slave == NULL ?  -ENODEV : 0;
 }
@@ -1639,12 +1644,12 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
 /* STK9090M */
 static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
 {
-       return dib9000_fw_pid_filter(adapter->fe, index, pid, onoff);
+       return dib9000_fw_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
 }
 
 static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
 {
-       return dib9000_fw_pid_filter_ctrl(adapter->fe, onoff);
+       return dib9000_fw_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
 }
 
 static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff)
@@ -1856,15 +1861,15 @@ static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap)
        stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size;
        stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data;
 
-       adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config);
+       adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config);
 
-       return adap->fe == NULL ?  -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
 }
 
 static int dib9090_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct dib0700_adapter_state *state = adap->priv;
-       struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe);
+       struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe);
        u16 data_dib190[10] = {
                1, 0x1374,
                2, 0x01a2,
@@ -1873,13 +1878,13 @@ static int dib9090_tuner_attach(struct dvb_usb_adapter *adap)
                8, 0x0486,
        };
 
-       if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &dib9090_dib0090_config) == NULL)
+       if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &dib9090_dib0090_config) == NULL)
                return -ENODEV;
-       i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
+       i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
        if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0)
                return -ENODEV;
        dib0700_set_i2c_speed(adap->dev, 2000);
-       if (dib9000_firmware_post_pll_init(adap->fe) < 0)
+       if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0)
                return -ENODEV;
        release_firmware(state->frontend_firmware);
        return 0;
@@ -1925,16 +1930,16 @@ static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap)
        nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data;
 
        dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80);
-       adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]);
+       adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]);
 
-       if (adap->fe == NULL)
+       if (adap->fe_adap[0].fe == NULL)
                return -ENODEV;
 
-       i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0);
+       i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0);
        dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82);
 
        fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]);
-       dib9000_set_slave_frontend(adap->fe, fe_slave);
+       dib9000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave);
 
        return fe_slave == NULL ?  -ENODEV : 0;
 }
@@ -1951,26 +1956,26 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
                0, 0x00ef,
                8, 0x0406,
        };
-       i2c = dib9000_get_tuner_interface(adap->fe);
-       if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &nim9090md_dib0090_config[0]) == NULL)
+       i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe);
+       if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &nim9090md_dib0090_config[0]) == NULL)
                return -ENODEV;
-       i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
+       i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
        if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0)
                return -ENODEV;
        dib0700_set_i2c_speed(adap->dev, 2000);
-       if (dib9000_firmware_post_pll_init(adap->fe) < 0)
+       if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0)
                return -ENODEV;
 
-       fe_slave = dib9000_get_slave_frontend(adap->fe, 1);
+       fe_slave = dib9000_get_slave_frontend(adap->fe_adap[0].fe, 1);
        if (fe_slave != NULL) {
-               i2c = dib9000_get_component_bus_interface(adap->fe);
+               i2c = dib9000_get_component_bus_interface(adap->fe_adap[0].fe);
                dib9000_set_i2c_adapter(fe_slave, i2c);
 
                i2c = dib9000_get_tuner_interface(fe_slave);
                if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL)
                        return -ENODEV;
-               fe_slave->dvb = adap->fe->dvb;
-               dib9000_fw_set_component_bus_speed(adap->fe, 2000);
+               fe_slave->dvb = adap->fe_adap[0].fe->dvb;
+               dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 2000);
                if (dib9000_firmware_post_pll_init(fe_slave) < 0)
                        return -ENODEV;
        }
@@ -2393,23 +2398,23 @@ static int nim7090_frontend_attach(struct dvb_usb_adapter *adap)
                err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
                return -ENODEV;
        }
-       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config);
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config);
 
-       return adap->fe == NULL ?  -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
 }
 
 static int nim7090_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct dib0700_adapter_state *st = adap->priv;
-       struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe);
+       struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
 
-       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &nim7090_dib0090_config) == NULL)
+       if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &nim7090_dib0090_config) == NULL)
                return -ENODEV;
 
-       dib7000p_set_gpio(adap->fe, 8, 0, 1);
+       dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
 
-       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
-       adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+       st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+       adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
        return 0;
 }
 
@@ -2439,11 +2444,11 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap)
        }
 
        dib0700_set_i2c_speed(adap->dev, 340);
-       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]);
-       if (adap->fe == NULL)
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]);
+       if (adap->fe_adap[0].fe == NULL)
                return -ENODEV;
 
-       dib7090_slave_reset(adap->fe);
+       dib7090_slave_reset(adap->fe_adap[0].fe);
 
        return 0;
 }
@@ -2452,50 +2457,50 @@ static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap)
 {
        struct i2c_adapter *i2c;
 
-       if (adap->dev->adapter[0].fe == NULL) {
+       if (adap->dev->adapter[0].fe_adap[0].fe == NULL) {
                err("the master dib7090 has to be initialized first");
                return -ENODEV; /* the master device has not been initialized */
        }
 
-       i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1);
+       i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1);
        if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) {
                err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
                return -ENODEV;
        }
 
-       adap->fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]);
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]);
        dib0700_set_i2c_speed(adap->dev, 200);
 
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap)
 {
        struct dib0700_adapter_state *st = adap->priv;
-       struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe);
+       struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
 
-       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL)
+       if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL)
                return -ENODEV;
 
-       dib7000p_set_gpio(adap->fe, 8, 0, 1);
+       dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
 
-       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
-       adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+       st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+       adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
        return 0;
 }
 
 static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap)
 {
        struct dib0700_adapter_state *st = adap->priv;
-       struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe);
+       struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
 
-       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL)
+       if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL)
                return -ENODEV;
 
-       dib7000p_set_gpio(adap->fe, 8, 0, 1);
+       dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
 
-       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
-       adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+       st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+       adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
        return 0;
 }
 
@@ -2555,14 +2560,14 @@ static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
                return -ENODEV;
        }
 
-       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
-       return adap->fe == NULL ? -ENODEV : 0;
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
 {
-       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]);
-       return adap->fe == NULL ? -ENODEV : 0;
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]);
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 /* S5H1411 */
@@ -2617,9 +2622,9 @@ static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap)
        dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1);
 
        /* GPIOs are initialized, do the attach */
-       adap->fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config,
+       adap->fe_adap[0].fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config,
                              &adap->dev->i2c_adap);
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 static int dib0700_xc5000_tuner_callback(void *priv, int component,
@@ -2649,9 +2654,9 @@ static struct xc5000_config s5h1411_xc5000_tunerconfig = {
 static int xc5000_tuner_attach(struct dvb_usb_adapter *adap)
 {
        /* FIXME: generalize & move to common area */
-       adap->fe->callback = dib0700_xc5000_tuner_callback;
+       adap->fe_adap[0].fe->callback = dib0700_xc5000_tuner_callback;
 
-       return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap,
+       return dvb_attach(xc5000_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
                          &s5h1411_xc5000_tunerconfig)
                == NULL ? -ENODEV : 0;
 }
@@ -2663,9 +2668,9 @@ static int dib0700_xc4000_tuner_callback(void *priv, int component,
 
        if (command == XC4000_TUNER_RESET) {
                /* Reset the tuner */
-               dib7000p_set_gpio(adap->fe, 8, 0, 0);
+               dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0);
                msleep(10);
-               dib7000p_set_gpio(adap->fe, 8, 0, 1);
+               dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
        } else {
                err("xc4000: unknown tuner callback command: %d\n", command);
                return -EINVAL;
@@ -2771,11 +2776,11 @@ static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap)
                return -ENODEV;
        }
 
-       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12,
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12,
                              &pctv_340e_config);
        st->is_dib7000pc = 1;
 
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 static struct xc4000_config dib7000p_xc4000_tunerconfig = {
@@ -2791,7 +2796,7 @@ static int xc4000_tuner_attach(struct dvb_usb_adapter *adap)
        struct i2c_adapter *tun_i2c;
 
        /* The xc4000 is not on the main i2c bus */
-       tun_i2c = dib7000p_get_i2c_master(adap->fe,
+       tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe,
                                          DIBX000_I2C_INTERFACE_TUNER, 1);
        if (tun_i2c == NULL) {
                printk(KERN_ERR "Could not reach tuner i2c bus\n");
@@ -2799,9 +2804,9 @@ static int xc4000_tuner_attach(struct dvb_usb_adapter *adap)
        }
 
        /* Setup the reset callback */
-       adap->fe->callback = dib0700_xc4000_tuner_callback;
+       adap->fe_adap[0].fe->callback = dib0700_xc4000_tuner_callback;
 
-       return dvb_attach(xc4000_attach, adap->fe, tun_i2c,
+       return dvb_attach(xc4000_attach, adap->fe_adap[0].fe, tun_i2c,
                          &dib7000p_xc4000_tunerconfig)
                == NULL ? -ENODEV : 0;
 }
@@ -2857,16 +2862,16 @@ static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap)
        dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
        msleep(30);
 
-       adap->fe = dvb_attach(lgdt3305_attach,
+       adap->fe_adap[0].fe = dvb_attach(lgdt3305_attach,
                              &hcw_lgdt3305_config,
                              &adap->dev->i2c_adap);
 
-       return adap->fe == NULL ? -ENODEV : 0;
+       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       return dvb_attach(mxl5007t_attach, adap->fe,
+       return dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
                          &adap->dev->i2c_adap, 0x60,
                          &hcw_mxl5007t_config) == NULL ? -ENODEV : 0;
 }
@@ -2989,6 +2994,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter       = stk7700p_pid_filter,
@@ -2997,6 +3004,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = stk7700p_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+                       }},
                        },
                },
 
@@ -3050,15 +3058,21 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 2,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .frontend_attach  = bristol_frontend_attach,
                                .tuner_attach     = bristol_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+                       }},
                        }, {
+                       .num_frontends = 1,
+                       .fe = {{
                                .frontend_attach  = bristol_frontend_attach,
                                .tuner_attach     = bristol_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+                       }},
                        }
                },
 
@@ -3084,6 +3098,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 2,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter       = stk70x0p_pid_filter,
@@ -3092,7 +3108,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = stk7700d_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+                       }},
                        }, {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter       = stk70x0p_pid_filter,
@@ -3101,6 +3120,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = stk7700d_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+                       }},
                        }
                },
 
@@ -3143,6 +3163,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter       = stk70x0p_pid_filter,
@@ -3151,6 +3173,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = stk7700d_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+                       }},
                        },
                },
 
@@ -3185,6 +3208,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter       = stk70x0p_pid_filter,
@@ -3193,7 +3218,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = dib7070p_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv     = sizeof(struct dib0700_adapter_state),
                        },
                },
@@ -3261,6 +3286,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter       = stk70x0p_pid_filter,
@@ -3269,7 +3296,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = dib7070p_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv     = sizeof(struct dib0700_adapter_state),
                        },
                },
@@ -3305,6 +3332,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 2,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter       = stk70x0p_pid_filter,
@@ -3313,9 +3342,11 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = dib7070p_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv     = sizeof(struct dib0700_adapter_state),
                        }, {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter       = stk70x0p_pid_filter,
@@ -3324,7 +3355,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = dib7070p_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
-
+                       }},
                                .size_of_priv     = sizeof(struct dib0700_adapter_state),
                        }
                },
@@ -3373,6 +3404,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 2,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter       = stk70x0p_pid_filter,
@@ -3381,9 +3414,11 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = dib7070p_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv     = sizeof(struct dib0700_adapter_state),
                        }, {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter       = stk70x0p_pid_filter,
@@ -3392,7 +3427,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = dib7070p_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
-
+                       }},
                                .size_of_priv     = sizeof(struct dib0700_adapter_state),
                        }
                },
@@ -3420,6 +3455,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter       = stk70x0p_pid_filter,
@@ -3428,7 +3465,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = stk7700ph_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv = sizeof(struct
                                                dib0700_adapter_state),
                        },
@@ -3488,11 +3525,13 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .frontend_attach  = s5h1411_frontend_attach,
                                .tuner_attach     = xc5000_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv = sizeof(struct
                                                dib0700_adapter_state),
                        },
@@ -3524,11 +3563,13 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .frontend_attach  = lgdt3305_frontend_attach,
                                .tuner_attach     = mxl5007t_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv = sizeof(struct
                                                dib0700_adapter_state),
                        },
@@ -3550,6 +3591,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter       = stk70x0p_pid_filter,
@@ -3558,7 +3601,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = dib7770p_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv =
                                        sizeof(struct dib0700_adapter_state),
                        },
@@ -3600,6 +3643,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps  = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter = stk80xx_pid_filter,
@@ -3608,7 +3653,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = dib807x_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv =
                                        sizeof(struct dib0700_adapter_state),
                        },
@@ -3644,6 +3689,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 2,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps  = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter = stk80xx_pid_filter,
@@ -3652,11 +3699,13 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = dib807x_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv =
                                        sizeof(struct dib0700_adapter_state),
                        },
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps  = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
                                .pid_filter = stk80xx_pid_filter,
@@ -3665,7 +3714,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = dib807x_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
-
+                       }},
                                .size_of_priv =
                                        sizeof(struct dib0700_adapter_state),
                        },
@@ -3693,6 +3742,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
                                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
@@ -3702,7 +3753,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = dib809x_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv =
                                        sizeof(struct dib0700_adapter_state),
                        },
@@ -3730,6 +3781,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
                                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
@@ -3739,7 +3792,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = dib9090_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv =
                                        sizeof(struct dib0700_adapter_state),
                        },
@@ -3767,6 +3820,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
                                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
@@ -3776,7 +3831,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = nim8096md_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv =
                                        sizeof(struct dib0700_adapter_state),
                        },
@@ -3804,6 +3859,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
                                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
@@ -3813,7 +3870,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = nim9090md_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv =
                                        sizeof(struct dib0700_adapter_state),
                        },
@@ -3841,6 +3898,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
                                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
@@ -3850,7 +3909,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = nim7090_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv =
                                        sizeof(struct dib0700_adapter_state),
                        },
@@ -3878,6 +3937,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 2,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
                                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
@@ -3887,11 +3948,13 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = tfe7090pvr_tuner0_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
-
+                       }},
                                .size_of_priv =
                                        sizeof(struct dib0700_adapter_state),
                        },
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
                                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
@@ -3901,7 +3964,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                .tuner_attach     = tfe7090pvr_tuner1_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv =
                                        sizeof(struct dib0700_adapter_state),
                        },
@@ -3929,11 +3992,13 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_adapters = 1,
                .adapter = {
                        {
+                       .num_frontends = 1,
+                       .fe = {{
                                .frontend_attach  = pctv340e_frontend_attach,
                                .tuner_attach     = xc4000_tuner_attach,
 
                                DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
+                       }},
                                .size_of_priv = sizeof(struct
                                                dib0700_adapter_state),
                        },
index 4c2a689..a76bbb2 100644 (file)
@@ -23,7 +23,7 @@ int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        if (adap->priv != NULL) {
                struct dibusb_state *st = adap->priv;
                if (st->ops.fifo_ctrl != NULL)
-                       if (st->ops.fifo_ctrl(adap->fe,onoff)) {
+                       if (st->ops.fifo_ctrl(adap->fe_adap[0].fe, onoff)) {
                                err("error while controlling the fifo of the demod.");
                                return -ENODEV;
                        }
@@ -37,7 +37,8 @@ int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onof
        if (adap->priv != NULL) {
                struct dibusb_state *st = adap->priv;
                if (st->ops.pid_ctrl != NULL)
-                       st->ops.pid_ctrl(adap->fe,index,pid,onoff);
+                       st->ops.pid_ctrl(adap->fe_adap[0].fe,
+                                        index, pid, onoff);
        }
        return 0;
 }
@@ -48,7 +49,7 @@ int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
        if (adap->priv != NULL) {
                struct dibusb_state *st = adap->priv;
                if (st->ops.pid_parse != NULL)
-                       if (st->ops.pid_parse(adap->fe,onoff) < 0)
+                       if (st->ops.pid_parse(adap->fe_adap[0].fe, onoff) < 0)
                                err("could not handle pid_parser");
        }
        return 0;
@@ -254,8 +255,16 @@ int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap)
                msleep(1000);
        }
 
-       if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS,  &mod3000p_dib3000p_config)) != NULL ||
-               (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) {
+       adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach,
+                                        &adap->dev->i2c_adap,
+                                        DEFAULT_DIB3000P_I2C_ADDRESS,
+                                        &mod3000p_dib3000p_config);
+       if ((adap->fe_adap[0].fe) == NULL)
+               adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach,
+                                                &adap->dev->i2c_adap,
+                                                DEFAULT_DIB3000MC_I2C_ADDRESS,
+                                                &mod3000p_dib3000p_config);
+       if ((adap->fe_adap[0].fe) != NULL) {
                if (adap->priv != NULL) {
                        struct dibusb_state *st = adap->priv;
                        st->ops.pid_parse = dib3000mc_pid_parse;
@@ -309,15 +318,15 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
                }
        }
 
-       tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
-       if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
+       tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1);
+       if (dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
                /* not found - use panasonic pll parameters */
-               if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
+               if (dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
                        return -ENOMEM;
        } else {
                st->mt2060_present = 1;
                /* set the correct parameters for the dib3000p */
-               dib3000mc_set_config(adap->fe, &stk3000p_dib3000p_config);
+               dib3000mc_set_config(adap->fe_adap[0].fe, &stk3000p_dib3000p_config);
        }
        return 0;
 }
index 04d91bd..7270791 100644 (file)
@@ -31,11 +31,12 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
 
        demod_cfg.demod_address = 0x8;
 
-       if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg,
-                                  &adap->dev->i2c_adap, &st->ops)) == NULL)
+       adap->fe_adap[0].fe = dvb_attach(dib3000mb_attach, &demod_cfg,
+                                        &adap->dev->i2c_adap, &st->ops);
+       if ((adap->fe_adap[0].fe) == NULL)
                return -ENODEV;
 
-       adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
+       adap->fe_adap[0].fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
 
        return 0;
 }
@@ -46,7 +47,7 @@ static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
 
        st->tuner_addr = 0x61;
 
-       dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+       dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap,
                   DVB_PLL_TUA6010XS);
        return 0;
 }
@@ -57,7 +58,7 @@ static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap)
 
        st->tuner_addr = 0x60;
 
-       dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap,
+       dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap,
                   DVB_PLL_TDA665X);
        return 0;
 }
@@ -78,16 +79,16 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
        /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
        msg[0].addr = msg[1].addr = st->tuner_addr = 0x60;
 
-       if (adap->fe->ops.i2c_gate_ctrl)
-               adap->fe->ops.i2c_gate_ctrl(adap->fe,1);
+       if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
+               adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1);
 
        if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
                err("tuner i2c write failed.");
                ret = -EREMOTEIO;
        }
 
-       if (adap->fe->ops.i2c_gate_ctrl)
-               adap->fe->ops.i2c_gate_ctrl(adap->fe,0);
+       if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
+               adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0);
 
        if (b2[0] == 0xfe) {
                info("This device has the Thomson Cable onboard. Which is default.");
@@ -185,6 +186,8 @@ static struct dvb_usb_device_properties dibusb1_1_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .pid_filter_count = 16,
 
@@ -205,6 +208,7 @@ static struct dvb_usb_device_properties dibusb1_1_properties = {
                                        }
                                }
                        },
+               }},
                        .size_of_priv     = sizeof(struct dibusb_state),
                }
        },
@@ -272,6 +276,8 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER,
                        .pid_filter_count = 16,
 
@@ -292,6 +298,7 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
                                        }
                                }
                        },
+               }},
                        .size_of_priv     = sizeof(struct dibusb_state),
                },
        },
@@ -338,6 +345,8 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .pid_filter_count = 16,
 
@@ -358,6 +367,7 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = {
                                        }
                                }
                        },
+               }},
                        .size_of_priv     = sizeof(struct dibusb_state),
                }
        },
@@ -398,6 +408,8 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .pid_filter_count = 16,
 
@@ -417,6 +429,7 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = {
                                        }
                                }
                        },
+               }},
                        .size_of_priv     = sizeof(struct dibusb_state),
                }
        },
index c1d9094..9c165e2 100644 (file)
@@ -57,6 +57,8 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .pid_filter_count = 32,
                        .streaming_ctrl   = dibusb2_0_streaming_ctrl,
@@ -76,6 +78,7 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
                                        }
                                }
                        },
+               }},
                        .size_of_priv     = sizeof(struct dibusb_state),
                }
        },
index f6344cd..f718411 100644 (file)
@@ -137,11 +137,16 @@ static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
 {
        struct digitv_state *st = adap->dev->priv;
 
-       if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) {
+       adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config,
+                                        &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) != NULL) {
                st->is_nxt6000 = 0;
                return 0;
        }
-       if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) {
+       adap->fe_adap[0].fe = dvb_attach(nxt6000_attach,
+                                        &digitv_nxt6000_config,
+                                        &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) != NULL) {
                st->is_nxt6000 = 1;
                return 0;
        }
@@ -152,11 +157,11 @@ static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct digitv_state *st = adap->dev->priv;
 
-       if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4))
+       if (!dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, NULL, DVB_PLL_TDED4))
                return -ENODEV;
 
        if (st->is_nxt6000)
-               adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+               adap->fe_adap[0].fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
 
        return 0;
 }
@@ -292,6 +297,8 @@ static struct dvb_usb_device_properties digitv_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .frontend_attach  = digitv_frontend_attach,
                        .tuner_attach     = digitv_tuner_attach,
 
@@ -306,6 +313,7 @@ static struct dvb_usb_device_properties digitv_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
        .identify_state   = digitv_identify_state,
index ecd86ec..106dfd5 100644 (file)
@@ -90,7 +90,7 @@ static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 
 static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       adap->fe = dtt200u_fe_attach(adap->dev);
+       adap->fe_adap[0].fe = dtt200u_fe_attach(adap->dev);
        return 0;
 }
 
@@ -140,6 +140,8 @@ static struct dvb_usb_device_properties dtt200u_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
                        .pid_filter_count = 15,
 
@@ -157,6 +159,7 @@ static struct dvb_usb_device_properties dtt200u_properties = {
                        }
                }
        },
+               }},
                }
        },
        .power_ctrl      = dtt200u_power_ctrl,
@@ -187,6 +190,8 @@ static struct dvb_usb_device_properties wt220u_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
                        .pid_filter_count = 15,
 
@@ -204,6 +209,7 @@ static struct dvb_usb_device_properties wt220u_properties = {
                        }
                }
        },
+               }},
                }
        },
        .power_ctrl      = dtt200u_power_ctrl,
@@ -234,6 +240,8 @@ static struct dvb_usb_device_properties wt220u_fc_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
                        .pid_filter_count = 15,
 
@@ -251,6 +259,7 @@ static struct dvb_usb_device_properties wt220u_fc_properties = {
                        }
                }
        },
+               }},
                }
        },
        .power_ctrl      = dtt200u_power_ctrl,
@@ -281,6 +290,8 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
                        .pid_filter_count = 15,
 
@@ -298,6 +309,7 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
        .power_ctrl      = dtt200u_power_ctrl,
index 078ce92..7373132 100644 (file)
@@ -115,13 +115,13 @@ static struct zl10353_config dtv5100_zl10353_config = {
 
 static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       adap->fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config,
+       adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config,
                              &adap->dev->i2c_adap);
-       if (adap->fe == NULL)
+       if (adap->fe_adap[0].fe == NULL)
                return -EIO;
 
        /* disable i2c gate, or it won't work... is this safe? */
-       adap->fe->ops.i2c_gate_ctrl = NULL;
+       adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL;
 
        return 0;
 }
@@ -133,7 +133,7 @@ static struct qt1010_config dtv5100_qt1010_config = {
 static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap)
 {
        return dvb_attach(qt1010_attach,
-                         adap->fe, &adap->dev->i2c_adap,
+                         adap->fe_adap[0].fe, &adap->dev->i2c_adap,
                          &dtv5100_qt1010_config) == NULL ? -ENODEV : 0;
 }
 
@@ -180,6 +180,8 @@ static struct dvb_usb_device_properties dtv5100_properties = {
 
        .num_adapters = 1,
        .adapter = {{
+               .num_frontends = 1,
+               .fe = {{
                .frontend_attach = dtv5100_frontend_attach,
                .tuner_attach    = dtv5100_tuner_attach,
 
@@ -193,6 +195,7 @@ static struct dvb_usb_device_properties dtv5100_properties = {
                                }
                        }
                },
+               }},
        } },
 
        .i2c_algo = &dtv5100_i2c_algo,
index b3cb626..ba4a751 100644 (file)
@@ -17,15 +17,20 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
        if (adap == NULL)
                return -ENODEV;
 
+       if ((adap->active_fe < 0) ||
+           (adap->active_fe >= adap->num_frontends_initialized)) {
+               return -EINVAL;
+       }
+
        newfeedcount = adap->feedcount + (onoff ? 1 : -1);
 
        /* stop feed before setting a new pid if there will be no pid anymore */
        if (newfeedcount == 0) {
                deb_ts("stop feeding\n");
-               usb_urb_kill(&adap->stream);
+               usb_urb_kill(&adap->fe_adap[adap->active_fe].stream);
 
-               if (adap->props.streaming_ctrl != NULL) {
-                       ret = adap->props.streaming_ctrl(adap, 0);
+               if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
+                       ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0);
                        if (ret < 0) {
                                err("error while stopping stream.");
                                return ret;
@@ -36,36 +41,37 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
        adap->feedcount = newfeedcount;
 
        /* activate the pid on the device specific pid_filter */
-       deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",adap->pid_filtering ?
-               "yes" : "no", dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ?
-               "on" : "off");
-       if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
-               adap->pid_filtering &&
-               adap->props.pid_filter != NULL)
-               adap->props.pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid,onoff);
+       deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",
+               adap->fe_adap[adap->active_fe].pid_filtering ?
+               "yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid,
+               dvbdmxfeed->index, onoff ? "on" : "off");
+       if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+               adap->fe_adap[adap->active_fe].pid_filtering &&
+               adap->props.fe[adap->active_fe].pid_filter != NULL)
+               adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
 
        /* start the feed if this was the first feed and there is still a feed
         * for reception.
         */
        if (adap->feedcount == onoff && adap->feedcount > 0) {
                deb_ts("submitting all URBs\n");
-               usb_urb_submit(&adap->stream);
+               usb_urb_submit(&adap->fe_adap[adap->active_fe].stream);
 
                deb_ts("controlling pid parser\n");
-               if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
-                       adap->props.caps &
+               if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+                       adap->props.fe[adap->active_fe].caps &
                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
-                       adap->props.pid_filter_ctrl != NULL) {
-                       ret = adap->props.pid_filter_ctrl(adap,
-                               adap->pid_filtering);
+                       adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) {
+                       ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap,
+                               adap->fe_adap[adap->active_fe].pid_filtering);
                        if (ret < 0) {
                                err("could not handle pid_parser");
                                return ret;
                        }
                }
                deb_ts("start feeding\n");
-               if (adap->props.streaming_ctrl != NULL) {
-                       ret = adap->props.streaming_ctrl(adap, 1);
+               if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
+                       ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1);
                        if (ret < 0) {
                                err("error while enabling fifo.");
                                return ret;
@@ -90,6 +96,7 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 
 int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
 {
+       int i;
        int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
                                       adap->dev->owner, &adap->dev->udev->dev,
                                       adapter_nums);
@@ -112,7 +119,12 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
        adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
        adap->demux.priv             = adap;
 
-       adap->demux.feednum          = adap->demux.filternum = adap->max_feed_count;
+       adap->demux.filternum        = 0;
+       for (i = 0; i < adap->props.num_frontends; i++) {
+               if (adap->demux.filternum < adap->fe_adap[i].max_feed_count)
+                       adap->demux.filternum = adap->fe_adap[i].max_feed_count;
+       }
+       adap->demux.feednum          = adap->demux.filternum;
        adap->demux.start_feed       = dvb_usb_start_feed;
        adap->demux.stop_feed        = dvb_usb_stop_feed;
        adap->demux.write_to_decoder = NULL;
@@ -156,14 +168,33 @@ int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+       int ret = (adap->props.frontend_ctrl) ?
+               adap->props.frontend_ctrl(fe, onoff) : 0;
+
+       if (ret < 0) {
+               err("frontend_ctrl request failed");
+               return ret;
+       }
+       if (onoff)
+               adap->active_fe = fe->id;
+
+       return 0;
+}
+
 static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
 {
        struct dvb_usb_adapter *adap = fe->dvb->priv;
 
        dvb_usb_device_power_ctrl(adap->dev, 1);
 
-       if (adap->fe_init)
-               adap->fe_init(fe);
+       dvb_usb_set_active_fe(fe, 1);
+
+       if (adap->fe_adap[fe->id].fe_init)
+               adap->fe_adap[fe->id].fe_init(fe);
 
        return 0;
 }
@@ -172,45 +203,81 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
 {
        struct dvb_usb_adapter *adap = fe->dvb->priv;
 
-       if (adap->fe_sleep)
-               adap->fe_sleep(fe);
+       if (adap->fe_adap[fe->id].fe_sleep)
+               adap->fe_adap[fe->id].fe_sleep(fe);
+
+       dvb_usb_set_active_fe(fe, 0);
 
        return dvb_usb_device_power_ctrl(adap->dev, 0);
 }
 
 int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
 {
-       if (adap->props.frontend_attach == NULL) {
-               err("strange: '%s' #%d doesn't want to attach a frontend.",adap->dev->desc->name, adap->id);
-               return 0;
-       }
+       int ret, i;
 
-       /* re-assign sleep and wakeup functions */
-       if (adap->props.frontend_attach(adap) == 0 && adap->fe != NULL) {
-               adap->fe_init  = adap->fe->ops.init;  adap->fe->ops.init  = dvb_usb_fe_wakeup;
-               adap->fe_sleep = adap->fe->ops.sleep; adap->fe->ops.sleep = dvb_usb_fe_sleep;
+       /* register all given adapter frontends */
+       for (i = 0; i < adap->props.num_frontends; i++) {
 
-               if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) {
-                       err("Frontend registration failed.");
-                       dvb_frontend_detach(adap->fe);
-                       adap->fe = NULL;
-                       return -ENODEV;
+               if (adap->props.fe[i].frontend_attach == NULL) {
+                       err("strange: '%s' #%d,%d "
+                           "doesn't want to attach a frontend.",
+                           adap->dev->desc->name, adap->id, i);
+
+                       return 0;
+               }
+
+               ret = adap->props.fe[i].frontend_attach(adap);
+               if (ret || adap->fe_adap[i].fe == NULL) {
+                       /* only print error when there is no FE at all */
+                       if (i == 0)
+                               err("no frontend was attached by '%s'",
+                                       adap->dev->desc->name);
+
+                       return 0;
+               }
+
+               adap->fe_adap[i].fe->id = i;
+
+               /* re-assign sleep and wakeup functions */
+               adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init;
+               adap->fe_adap[i].fe->ops.init  = dvb_usb_fe_wakeup;
+               adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep;
+               adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep;
+
+               if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) {
+                       err("Frontend %d registration failed.", i);
+                       dvb_frontend_detach(adap->fe_adap[i].fe);
+                       adap->fe_adap[i].fe = NULL;
+                       /* In error case, do not try register more FEs,
+                        * still leaving already registered FEs alive. */
+                       if (i == 0)
+                               return -ENODEV;
+                       else
+                               return 0;
                }
 
                /* only attach the tuner if the demod is there */
-               if (adap->props.tuner_attach != NULL)
-                       adap->props.tuner_attach(adap);
-       } else
-               err("no frontend was attached by '%s'",adap->dev->desc->name);
+               if (adap->props.fe[i].tuner_attach != NULL)
+                       adap->props.fe[i].tuner_attach(adap);
+
+               adap->num_frontends_initialized++;
+       }
 
        return 0;
 }
 
 int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap)
 {
-       if (adap->fe != NULL) {
-               dvb_unregister_frontend(adap->fe);
-               dvb_frontend_detach(adap->fe);
+       int i = adap->num_frontends_initialized - 1;
+
+       /* unregister all given adapter frontends */
+       for (; i >= 0; i--) {
+               if (adap->fe_adap[i].fe != NULL) {
+                       dvb_unregister_frontend(adap->fe_adap[i].fe);
+                       dvb_frontend_detach(adap->fe_adap[i].fe);
+               }
        }
+       adap->num_frontends_initialized = 0;
+
        return 0;
 }
index 2a79b8f..2ad33ba 100644 (file)
 #define USB_PID_KWORLD_PC160_2T                                0xc160
 #define USB_PID_KWORLD_PC160_T                         0xc161
 #define USB_PID_KWORLD_UB383_T                         0xe383
+#define USB_PID_KWORLD_UB499_2T_T09                    0xe409
 #define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
 #define USB_PID_TERRATEC_CINERGY_T_USB_XE              0x0055
 #define USB_PID_PCTV_200E                              0x020e
 #define USB_PID_PCTV_400E                              0x020f
 #define USB_PID_PCTV_450E                              0x0222
+#define USB_PID_PCTV_452E                              0x021f
+#define USB_PID_TECHNOTREND_CONNECT_S2_3600            0x3007
+#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI         0x300a
 #define USB_PID_NEBULA_DIGITV                          0x0201
 #define USB_PID_DVICO_BLUEBIRD_LGDT                    0xd820
 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD             0xd500
index 2e3ea0f..169196e 100644 (file)
@@ -29,7 +29,7 @@ MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID
 static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
 {
        struct dvb_usb_adapter *adap;
-       int ret, n;
+       int ret, n, o;
 
        for (n = 0; n < d->props.num_adapters; n++) {
                adap = &d->adapter[n];
@@ -38,31 +38,42 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
 
                memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
 
+       for (o = 0; o < adap->props.num_frontends; o++) {
+               struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o];
                /* speed - when running at FULL speed we need a HW PID filter */
-               if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
+               if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
                        err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
                        return -ENODEV;
                }
 
-               if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
-                       (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
-                       info("will use the device's hardware PID filter (table count: %d).", adap->props.pid_filter_count);
-                       adap->pid_filtering  = 1;
-                       adap->max_feed_count = adap->props.pid_filter_count;
+               if ((d->udev->speed == USB_SPEED_FULL && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
+                       (props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
+                       info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count);
+                       adap->fe_adap[o].pid_filtering  = 1;
+                       adap->fe_adap[o].max_feed_count = props->pid_filter_count;
                } else {
                        info("will pass the complete MPEG2 transport stream to the software demuxer.");
-                       adap->pid_filtering  = 0;
-                       adap->max_feed_count = 255;
+                       adap->fe_adap[o].pid_filtering  = 0;
+                       adap->fe_adap[o].max_feed_count = 255;
                }
 
-               if (!adap->pid_filtering &&
+               if (!adap->fe_adap[o].pid_filtering &&
                        dvb_usb_force_pid_filter_usage &&
-                       adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) {
+                       props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
                        info("pid filter enabled by module option.");
-                       adap->pid_filtering  = 1;
-                       adap->max_feed_count = adap->props.pid_filter_count;
+                       adap->fe_adap[o].pid_filtering  = 1;
+                       adap->fe_adap[o].max_feed_count = props->pid_filter_count;
                }
 
+               if (props->size_of_priv > 0) {
+                       adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL);
+                       if (adap->fe_adap[o].priv == NULL) {
+                               err("no memory for priv for adapter %d fe %d.", n, o);
+                               return -ENOMEM;
+                       }
+               }
+       }
+
                if (adap->props.size_of_priv > 0) {
                        adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL);
                        if (adap->priv == NULL) {
@@ -77,6 +88,10 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
                        return ret;
                }
 
+               /* use exclusive FE lock if there is multiple shared FEs */
+               if (adap->fe_adap[1].fe)
+                       adap->dvb_adap.mfe_shared = 1;
+
                d->num_adapters_initialized++;
                d->state |= DVB_USB_STATE_DVB;
        }
index bb46ba6..53a5c30 100644 (file)
@@ -82,16 +82,28 @@ static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer
 
 int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
 {
-       adap->stream.udev      = adap->dev->udev;
-       if (adap->props.caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
-               adap->stream.complete = dvb_usb_data_complete_204;
-       else
-       adap->stream.complete  = dvb_usb_data_complete;
-       adap->stream.user_priv = adap;
-       return usb_urb_init(&adap->stream, &adap->props.stream);
+       int i, ret = 0;
+       for (i = 0; i < adap->props.num_frontends; i++) {
+
+               adap->fe_adap[i].stream.udev      = adap->dev->udev;
+               if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
+                       adap->fe_adap[i].stream.complete =
+                               dvb_usb_data_complete_204;
+               else
+               adap->fe_adap[i].stream.complete  = dvb_usb_data_complete;
+               adap->fe_adap[i].stream.user_priv = adap;
+               ret = usb_urb_init(&adap->fe_adap[i].stream,
+                                  &adap->props.fe[i].stream);
+               if (ret < 0)
+                       break;
+       }
+       return ret;
 }
 
 int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap)
 {
-       return usb_urb_exit(&adap->stream);
+       int i;
+       for (i = 0; i < adap->props.num_frontends; i++)
+               usb_urb_exit(&adap->fe_adap[i].stream);
+       return 0;
 }
index 7d35d07..6d7d13f 100644 (file)
@@ -124,6 +124,8 @@ struct usb_data_stream_properties {
  * @caps: capabilities of the DVB USB device.
  * @pid_filter_count: number of PID filter position in the optional hardware
  *  PID-filter.
+ * @num_frontends: number of frontends of the DVB USB adapter.
+ * @frontend_ctrl: called to power on/off active frontend.
  * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the
  *  device (not URB submitting/killing).
  * @pid_filter_ctrl: called to en/disable the PID filter, if any.
@@ -134,7 +136,7 @@ struct usb_data_stream_properties {
  *  pll_desc and pll_init_buf of struct dvb_usb_device).
  * @stream: configuration of the USB streaming
  */
-struct dvb_usb_adapter_properties {
+struct dvb_usb_adapter_fe_properties {
 #define DVB_USB_ADAP_HAS_PID_FILTER               0x01
 #define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
 #define DVB_USB_ADAP_NEED_PID_FILTERING           0x04
@@ -152,9 +154,18 @@ struct dvb_usb_adapter_properties {
        struct usb_data_stream_properties stream;
 
        int size_of_priv;
+};
+
+#define MAX_NO_OF_FE_PER_ADAP 2
+struct dvb_usb_adapter_properties {
+       int size_of_priv;
 
+       int (*frontend_ctrl)   (struct dvb_frontend *, int);
        int (*fe_ioctl_override) (struct dvb_frontend *,
                                  unsigned int, void *, unsigned int);
+
+       int num_frontends;
+       struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP];
 };
 
 /**
@@ -345,6 +356,20 @@ struct usb_data_stream {
  *
  * @stream: the usb data stream.
  */
+struct dvb_usb_fe_adapter {
+       struct dvb_frontend *fe;
+
+       int (*fe_init)  (struct dvb_frontend *);
+       int (*fe_sleep) (struct dvb_frontend *);
+
+       struct usb_data_stream stream;
+
+       int pid_filtering;
+       int max_feed_count;
+
+       void *priv;
+};
+
 struct dvb_usb_adapter {
        struct dvb_usb_device *dev;
        struct dvb_usb_adapter_properties props;
@@ -356,20 +381,16 @@ struct dvb_usb_adapter {
        u8  id;
 
        int feedcount;
-       int pid_filtering;
 
        /* dvb */
        struct dvb_adapter   dvb_adap;
        struct dmxdev        dmxdev;
        struct dvb_demux     demux;
        struct dvb_net       dvb_net;
-       struct dvb_frontend *fe;
-       int                  max_feed_count;
-
-       int (*fe_init)  (struct dvb_frontend *);
-       int (*fe_sleep) (struct dvb_frontend *);
 
-       struct usb_data_stream stream;
+       struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP];
+       int active_fe;
+       int num_frontends_initialized;
 
        void *priv;
 };
index 058b231..f103ec1 100644 (file)
@@ -992,18 +992,18 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
        struct dvb_tuner_ops *tuner_ops = NULL;
 
        if (demod_probe & 4) {
-               d->fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config,
+               d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config,
                                &d->dev->i2c_adap, 0);
-               if (d->fe != NULL) {
-                       if (dvb_attach(stb6100_attach, d->fe,
+               if (d->fe_adap[0].fe != NULL) {
+                       if (dvb_attach(stb6100_attach, d->fe_adap[0].fe,
                                        &dw2104a_stb6100_config,
                                        &d->dev->i2c_adap)) {
-                               tuner_ops = &d->fe->ops.tuner_ops;
+                               tuner_ops = &d->fe_adap[0].fe->ops.tuner_ops;
                                tuner_ops->set_frequency = stb6100_set_freq;
                                tuner_ops->get_frequency = stb6100_get_freq;
                                tuner_ops->set_bandwidth = stb6100_set_bandw;
                                tuner_ops->get_bandwidth = stb6100_get_bandw;
-                               d->fe->ops.set_voltage = dw210x_set_voltage;
+                               d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
                                info("Attached STV0900+STB6100!\n");
                                return 0;
                        }
@@ -1011,13 +1011,13 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
        }
 
        if (demod_probe & 2) {
-               d->fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config,
+               d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config,
                                &d->dev->i2c_adap, 0);
-               if (d->fe != NULL) {
-                       if (dvb_attach(stv6110_attach, d->fe,
+               if (d->fe_adap[0].fe != NULL) {
+                       if (dvb_attach(stv6110_attach, d->fe_adap[0].fe,
                                        &dw2104_stv6110_config,
                                        &d->dev->i2c_adap)) {
-                               d->fe->ops.set_voltage = dw210x_set_voltage;
+                               d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
                                info("Attached STV0900+STV6110A!\n");
                                return 0;
                        }
@@ -1025,19 +1025,19 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
        }
 
        if (demod_probe & 1) {
-               d->fe = dvb_attach(cx24116_attach, &dw2104_config,
+               d->fe_adap[0].fe = dvb_attach(cx24116_attach, &dw2104_config,
                                &d->dev->i2c_adap);
-               if (d->fe != NULL) {
-                       d->fe->ops.set_voltage = dw210x_set_voltage;
+               if (d->fe_adap[0].fe != NULL) {
+                       d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
                        info("Attached cx24116!\n");
                        return 0;
                }
        }
 
-       d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
+       d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
                        &d->dev->i2c_adap);
-       if (d->fe != NULL) {
-               d->fe->ops.set_voltage = dw210x_set_voltage;
+       if (d->fe_adap[0].fe != NULL) {
+               d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
                info("Attached DS3000!\n");
                return 0;
        }
@@ -1053,22 +1053,22 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 {
        if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
                /*dw2102_properties.adapter->tuner_attach = NULL;*/
-               d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
+               d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
                                        &d->dev->i2c_adap);
-               if (d->fe != NULL) {
-                       d->fe->ops.set_voltage = dw210x_set_voltage;
+               if (d->fe_adap[0].fe != NULL) {
+                       d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
                        info("Attached si21xx!\n");
                        return 0;
                }
        }
 
        if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) {
-               d->fe = dvb_attach(stv0288_attach, &earda_config,
+               d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
                                        &d->dev->i2c_adap);
-               if (d->fe != NULL) {
-                       if (dvb_attach(stb6000_attach, d->fe, 0x61,
+               if (d->fe_adap[0].fe != NULL) {
+                       if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61,
                                        &d->dev->i2c_adap)) {
-                               d->fe->ops.set_voltage = dw210x_set_voltage;
+                               d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
                                info("Attached stv0288!\n");
                                return 0;
                        }
@@ -1077,10 +1077,10 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 
        if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
                /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
-               d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
+               d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
                                        &d->dev->i2c_adap);
-               if (d->fe != NULL) {
-                       d->fe->ops.set_voltage = dw210x_set_voltage;
+               if (d->fe_adap[0].fe != NULL) {
+                       d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
                        info("Attached stv0299!\n");
                        return 0;
                }
@@ -1090,9 +1090,9 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 
 static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
 {
-       d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
+       d->fe_adap[0].fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
                                &d->dev->i2c_adap, 0x48);
-       if (d->fe != NULL) {
+       if (d->fe_adap[0].fe != NULL) {
                info("Attached tda10023!\n");
                return 0;
        }
@@ -1101,12 +1101,12 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
 
 static int zl100313_frontend_attach(struct dvb_usb_adapter *d)
 {
-       d->fe = dvb_attach(mt312_attach, &zl313_config,
+       d->fe_adap[0].fe = dvb_attach(mt312_attach, &zl313_config,
                        &d->dev->i2c_adap);
-       if (d->fe != NULL) {
-               if (dvb_attach(zl10039_attach, d->fe, 0x60,
+       if (d->fe_adap[0].fe != NULL) {
+               if (dvb_attach(zl10039_attach, d->fe_adap[0].fe, 0x60,
                                &d->dev->i2c_adap)) {
-                       d->fe->ops.set_voltage = dw210x_set_voltage;
+                       d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
                        info("Attached zl100313+zl10039!\n");
                        return 0;
                }
@@ -1119,16 +1119,16 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d)
 {
        u8 obuf[] = {7, 1};
 
-       d->fe = dvb_attach(stv0288_attach, &earda_config,
+       d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
                        &d->dev->i2c_adap);
 
-       if (d->fe == NULL)
+       if (d->fe_adap[0].fe == NULL)
                return -EIO;
 
-       if (NULL == dvb_attach(stb6000_attach, d->fe, 0x61, &d->dev->i2c_adap))
+       if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap))
                return -EIO;
 
-       d->fe->ops.set_voltage = dw210x_set_voltage;
+       d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
 
        dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
 
@@ -1143,14 +1143,14 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
        struct s6x0_state *st = (struct s6x0_state *)d->dev->priv;
        u8 obuf[] = {7, 1};
 
-       d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
+       d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
                        &d->dev->i2c_adap);
 
-       if (d->fe == NULL)
+       if (d->fe_adap[0].fe == NULL)
                return -EIO;
 
-       st->old_set_voltage = d->fe->ops.set_voltage;
-       d->fe->ops.set_voltage = s660_set_voltage;
+       st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage;
+       d->fe_adap[0].fe->ops.set_voltage = s660_set_voltage;
 
        dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
 
@@ -1163,12 +1163,12 @@ static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
 {
        u8 obuf[] = {7, 1};
 
-       d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
+       d->fe_adap[0].fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
                                        &d->dev->i2c_adap, 0);
-       if (d->fe == NULL)
+       if (d->fe_adap[0].fe == NULL)
                return -EIO;
 
-       d->fe->ops.set_voltage = dw210x_set_voltage;
+       d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
 
        dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
 
@@ -1204,9 +1204,9 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
        if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
                err("command 0x51 transfer failed.");
 
-       d->fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
+       d->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
                                        &d->dev->i2c_adap);
-       if (d->fe == NULL)
+       if (d->fe_adap[0].fe == NULL)
                return -EIO;
 
        info("Attached DS3000!\n");
@@ -1216,14 +1216,14 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
 
 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       dvb_attach(dvb_pll_attach, adap->fe, 0x60,
+       dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
                &adap->dev->i2c_adap, DVB_PLL_OPERA1);
        return 0;
 }
 
 static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       dvb_attach(dvb_pll_attach, adap->fe, 0x60,
+       dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
                &adap->dev->i2c_adap, DVB_PLL_TUA6034);
 
        return 0;
@@ -1535,7 +1535,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
                                        DW210X_READ_MSG);
                        if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
                                dw2102_properties.i2c_algo = &dw2102_i2c_algo;
-                               dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach;
+                               dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach;
                                break;
                        } else {
                                /* check STV0288 frontend  */
@@ -1591,6 +1591,8 @@ static struct dvb_usb_device_properties dw2102_properties = {
        .read_mac_address = dw210x_read_mac_address,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .frontend_attach = dw2102_frontend_attach,
                        .stream = {
                                .type = USB_BULK,
@@ -1602,6 +1604,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
        .num_device_descs = 3,
@@ -1642,6 +1645,8 @@ static struct dvb_usb_device_properties dw2104_properties = {
        .read_mac_address = dw210x_read_mac_address,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .frontend_attach = dw2104_frontend_attach,
                        .stream = {
                                .type = USB_BULK,
@@ -1653,6 +1658,7 @@ static struct dvb_usb_device_properties dw2104_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
        .num_device_descs = 2,
@@ -1689,6 +1695,8 @@ static struct dvb_usb_device_properties dw3101_properties = {
        .read_mac_address = dw210x_read_mac_address,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .frontend_attach = dw3101_frontend_attach,
                        .tuner_attach = dw3101_tuner_attach,
                        .stream = {
@@ -1701,6 +1709,7 @@ static struct dvb_usb_device_properties dw3101_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
        .num_device_descs = 1,
@@ -1733,6 +1742,8 @@ static struct dvb_usb_device_properties s6x0_properties = {
        .read_mac_address = s6x0_read_mac_address,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .frontend_attach = zl100313_frontend_attach,
                        .stream = {
                                .type = USB_BULK,
@@ -1744,6 +1755,7 @@ static struct dvb_usb_device_properties s6x0_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
        .num_device_descs = 1,
@@ -1810,6 +1822,8 @@ static struct dvb_usb_device_properties su3000_properties = {
 
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = su3000_streaming_ctrl,
                        .frontend_attach  = su3000_frontend_attach,
                        .stream = {
@@ -1822,6 +1836,7 @@ static struct dvb_usb_device_properties su3000_properties = {
                                        }
                                }
                        }
+               }},
                }
        },
        .num_device_descs = 3,
@@ -1855,7 +1870,7 @@ static int dw2102_probe(struct usb_interface *intf,
        p1100->devices[0] = d1100;
        p1100->rc.legacy.rc_map_table = rc_map_tbs_table;
        p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
-       p1100->adapter->frontend_attach = stv0288_frontend_attach;
+       p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach;
 
        s660 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
        if (!s660) {
@@ -1869,7 +1884,7 @@ static int dw2102_probe(struct usb_interface *intf,
        s660->devices[0] = d660;
        s660->devices[1] = d480_1;
        s660->devices[2] = d480_2;
-       s660->adapter->frontend_attach = ds3000_frontend_attach;
+       s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach;
 
        p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
        if (!p7500) {
@@ -1883,7 +1898,7 @@ static int dw2102_probe(struct usb_interface *intf,
        p7500->devices[0] = d7500;
        p7500->rc.legacy.rc_map_table = rc_map_tbs_table;
        p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
-       p7500->adapter->frontend_attach = prof_7500_frontend_attach;
+       p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach;
 
        if (0 == dvb_usb_device_init(intf, &dw2102_properties,
                        THIS_MODULE, NULL, adapter_nr) ||
index 1ba3e5d..78442fe 100644 (file)
@@ -200,9 +200,9 @@ static struct ec100_config ec168_ec100_config = {
 static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap)
 {
        deb_info("%s:\n", __func__);
-       adap->fe = dvb_attach(ec100_attach, &ec168_ec100_config,
+       adap->fe_adap[0].fe = dvb_attach(ec100_attach, &ec168_ec100_config,
                &adap->dev->i2c_adap);
-       if (adap->fe == NULL)
+       if (adap->fe_adap[0].fe == NULL)
                return -ENODEV;
 
        return 0;
@@ -228,7 +228,7 @@ static struct mxl5005s_config ec168_mxl5003s_config = {
 static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
 {
        deb_info("%s:\n", __func__);
-       return dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap,
+       return dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
                &ec168_mxl5003s_config) == NULL ? -ENODEV : 0;
 }
 
@@ -382,6 +382,8 @@ static struct dvb_usb_device_properties ec168_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = ec168_streaming_ctrl,
                        .frontend_attach  = ec168_ec100_frontend_attach,
                        .tuner_attach     = ec168_mxl5003s_tuner_attach,
@@ -395,6 +397,7 @@ static struct dvb_usb_device_properties ec168_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
 
index 76159ae..b092dc2 100644 (file)
@@ -403,8 +403,8 @@ static int friio_frontend_attach(struct dvb_usb_adapter *adap)
        if (friio_initialize(adap->dev) < 0)
                return -EIO;
 
-       adap->fe = jdvbt90502_attach(adap->dev);
-       if (adap->fe == NULL)
+       adap->fe_adap[0].fe = jdvbt90502_attach(adap->dev);
+       if (adap->fe_adap[0].fe == NULL)
                return -EIO;
 
        return 0;
@@ -473,6 +473,8 @@ static struct dvb_usb_device_properties friio_properties = {
                /* caps:0 =>  no pid filter, 188B TS packet */
                /* GL861 has a HW pid filter, but no info available. */
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps  = 0,
 
                        .frontend_attach  = friio_frontend_attach,
@@ -490,6 +492,7 @@ static struct dvb_usb_device_properties friio_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
        .i2c_algo = &gl861_i2c_algo,
index 6f596ed..63681df 100644 (file)
@@ -103,9 +103,9 @@ static struct zl10353_config gl861_zl10353_config = {
 static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
 {
 
-       adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
+       adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
                &adap->dev->i2c_adap);
-       if (adap->fe == NULL)
+       if (adap->fe_adap[0].fe == NULL)
                return -EIO;
 
        return 0;
@@ -118,7 +118,7 @@ static struct qt1010_config gl861_qt1010_config = {
 static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
 {
        return dvb_attach(qt1010_attach,
-                         adap->fe, &adap->dev->i2c_adap,
+                         adap->fe_adap[0].fe, &adap->dev->i2c_adap,
                          &gl861_qt1010_config) == NULL ? -ENODEV : 0;
 }
 
@@ -167,6 +167,8 @@ static struct dvb_usb_device_properties gl861_properties = {
 
        .num_adapters = 1,
        .adapter = {{
+               .num_frontends = 1,
+               .fe = {{
 
                .frontend_attach  = gl861_frontend_attach,
                .tuner_attach     = gl861_tuner_attach,
@@ -181,6 +183,7 @@ static struct dvb_usb_device_properties gl861_properties = {
                                }
                        }
                },
+               }},
        } },
        .i2c_algo         = &gl861_i2c_algo,
 
index 60d11e5..5426267 100644 (file)
@@ -144,19 +144,25 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
        cmd[6] = (freq >> 16) & 0xff;
        cmd[7] = (freq >> 24) & 0xff;
 
+       /* backwards compatibility: DVB-S + 8-PSK were used for Turbo-FEC */
+       if (c->delivery_system == SYS_DVBS && c->modulation == PSK_8)
+               c->delivery_system = SYS_TURBO;
+
        switch (c->delivery_system) {
        case SYS_DVBS:
-               /* Allow QPSK and 8PSK (even for DVB-S) */
-               if (c->modulation != QPSK && c->modulation != PSK_8) {
+               if (c->modulation != QPSK) {
                        deb_fe("%s: unsupported modulation selected (%d)\n",
                                __func__, c->modulation);
                        return -EOPNOTSUPP;
                }
                c->fec_inner = FEC_AUTO;
                break;
-       case SYS_DVBS2:
+       case SYS_DVBS2: /* kept for backwards compatibility */
                deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
                break;
+       case SYS_TURBO:
+               deb_fe("%s: Turbo-FEC delivery system selected\n", __func__);
+               break;
 
        default:
                deb_fe("%s: unsupported delivery system selected (%d)\n",
@@ -189,7 +195,10 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
                default:
                        cmd[9] = 5; break;
                }
-               cmd[8] = ADV_MOD_DVB_QPSK;
+               if (c->delivery_system == SYS_TURBO)
+                       cmd[8] = ADV_MOD_TURBO_QPSK;
+               else
+                       cmd[8] = ADV_MOD_DVB_QPSK;
                break;
        case PSK_8: /* PSK_8 is for compatibility with DN */
                cmd[8] = ADV_MOD_TURBO_8PSK;
index 1cb3d9a..5f71284 100644 (file)
@@ -230,7 +230,7 @@ static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 
 static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       adap->fe = gp8psk_fe_attach(adap->dev);
+       adap->fe_adap[0].fe = gp8psk_fe_attach(adap->dev);
        return 0;
 }
 
@@ -268,6 +268,8 @@ static struct dvb_usb_device_properties gp8psk_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = gp8psk_streaming_ctrl,
                        .frontend_attach  = gp8psk_frontend_attach,
                        /* parameter for the MPEG2-data transfer */
@@ -281,6 +283,7 @@ static struct dvb_usb_device_properties gp8psk_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
        .power_ctrl       = gp8psk_power_ctrl,
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c
new file mode 100644 (file)
index 0000000..f027a2c
--- /dev/null
@@ -0,0 +1,651 @@
+/* DVB USB compliant linux driver for IT9137
+ *
+ * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
+ * IT9137 (C) ITE Tech Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/dvb/it9137.txt for firmware information
+ *
+ */
+#define DVB_USB_LOG_PREFIX "it913x"
+
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+#include "dvb-usb.h"
+#include "it913x-fe.h"
+
+/* debug */
+static int dvb_usb_it913x_debug;
+#define l_dprintk(var, level, args...) do { \
+       if ((var >= level)) \
+               printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \
+} while (0)
+
+#define deb_info(level, args...) l_dprintk(dvb_usb_it913x_debug, level, args)
+#define debug_data_snipet(level, name, p) \
+        deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
+               *p, *(p+1), *(p+2), *(p+3), *(p+4), \
+                       *(p+5), *(p+6), *(p+7));
+
+
+module_param_named(debug, dvb_usb_it913x_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."
+                       DVB_USB_DEBUG_STATUS);
+
+static int pid_filter;
+module_param_named(pid, pid_filter, int, 0644);
+MODULE_PARM_DESC(pid, "set default 0=on 1=off");
+
+int cmd_counter;
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct it913x_state {
+       u8 id;
+};
+
+static int it913x_bulk_write(struct usb_device *dev,
+                               u8 *snd, int len, u8 pipe)
+{
+       int ret, actual_l;
+
+       ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
+                               snd, len , &actual_l, 100);
+       return ret;
+}
+
+static int it913x_bulk_read(struct usb_device *dev,
+                               u8 *rev, int len, u8 pipe)
+{
+       int ret, actual_l;
+
+       ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
+                                rev, len , &actual_l, 200);
+       return ret;
+}
+
+static u16 check_sum(u8 *p, u8 len)
+{
+       u16 sum = 0;
+       u8 i = 1;
+       while (i < len)
+               sum += (i++ & 1) ? (*p++) << 8 : *p++;
+       return ~sum;
+}
+
+static int it913x_io(struct usb_device *udev, u8 mode, u8 pro,
+                       u8 cmd, u32 reg, u8 addr, u8 *data, u8 len)
+{
+       int ret = 0, i, buf_size = 1;
+       u8 *buff;
+       u8 rlen;
+       u16 chk_sum;
+
+       buff = kzalloc(256, GFP_KERNEL);
+       if (!buff) {
+               info("USB Buffer Failed");
+               return -ENOMEM;
+       }
+
+       buff[buf_size++] = pro;
+       buff[buf_size++] = cmd;
+       buff[buf_size++] = cmd_counter;
+
+       switch (mode) {
+       case READ_LONG:
+       case WRITE_LONG:
+               buff[buf_size++] = len;
+               buff[buf_size++] = 2;
+               buff[buf_size++] = (reg >> 24);
+               buff[buf_size++] = (reg >> 16) & 0xff;
+               buff[buf_size++] = (reg >> 8) & 0xff;
+               buff[buf_size++] = reg & 0xff;
+       break;
+       case READ_SHORT:
+               buff[buf_size++] = addr;
+               break;
+       case WRITE_SHORT:
+               buff[buf_size++] = len;
+               buff[buf_size++] = addr;
+               buff[buf_size++] = (reg >> 8) & 0xff;
+               buff[buf_size++] = reg & 0xff;
+       break;
+       case READ_DATA:
+       case WRITE_DATA:
+               break;
+       case WRITE_CMD:
+               mode = 7;
+               break;
+       default:
+               kfree(buff);
+               return -EINVAL;
+       }
+
+       if (mode & 1) {
+               for (i = 0; i < len ; i++)
+                       buff[buf_size++] = data[i];
+       }
+       chk_sum = check_sum(&buff[1], buf_size);
+
+       buff[buf_size++] = chk_sum >> 8;
+       buff[0] = buf_size;
+       buff[buf_size++] = (chk_sum & 0xff);
+
+       ret = it913x_bulk_write(udev, buff, buf_size , 0x02);
+
+       ret |= it913x_bulk_read(udev, buff, (mode & 1) ?
+                       5 : len + 5 , 0x01);
+
+       rlen = (mode & 0x1) ? 0x1 : len;
+
+       if (mode & 1)
+               ret |= buff[2];
+       else
+               memcpy(data, &buff[3], rlen);
+
+       cmd_counter++;
+
+       kfree(buff);
+
+       return (ret < 0) ? -ENODEV : 0;
+}
+
+static int it913x_wr_reg(struct usb_device *udev, u8 pro, u32 reg , u8 data)
+{
+       int ret;
+       u8 b[1];
+       b[0] = data;
+       ret = it913x_io(udev, WRITE_LONG, pro,
+                       CMD_DEMOD_WRITE, reg, 0, b, sizeof(b));
+
+       return ret;
+}
+
+static int it913x_read_reg(struct usb_device *udev, u32 reg)
+{
+       int ret;
+       u8 data[1];
+
+       ret = it913x_io(udev, READ_LONG, DEV_0,
+                       CMD_DEMOD_READ, reg, 0, &data[0], 1);
+
+       return (ret < 0) ? ret : data[0];
+}
+
+static u32 it913x_query(struct usb_device *udev, u8 pro)
+{
+       int ret;
+       u32 res = 0;
+       u8 data[4];
+       ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ,
+               0x1222, 0, &data[0], 1);
+       if (data[0] == 0x1) {
+               ret = it913x_io(udev, READ_SHORT, pro,
+                       CMD_QUERYINFO, 0, 0x1, &data[0], 4);
+               res = (data[0] << 24) + (data[1] << 16) +
+                       (data[2] << 8) + data[3];
+       }
+
+       return (ret < 0) ? 0 : res;
+}
+
+static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+       int ret = 0;
+       u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
+
+       if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
+                       return -EAGAIN;
+       deb_info(1, "PID_C  (%02x)", onoff);
+
+       if (!onoff)
+               ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1);
+
+       mutex_unlock(&adap->dev->i2c_mutex);
+       return ret;
+}
+
+static int it913x_pid_filter(struct dvb_usb_adapter *adap,
+               int index, u16 pid, int onoff)
+{
+       struct usb_device *udev = adap->dev->udev;
+       int ret = 0;
+       u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
+
+       if (pid_filter > 0)
+               return 0;
+
+       if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
+                       return -EAGAIN;
+       deb_info(1, "PID_F  (%02x)", onoff);
+       if (onoff) {
+               ret = it913x_wr_reg(udev, pro, PID_EN, 0x1);
+
+               ret |= it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff));
+
+               ret |= it913x_wr_reg(udev, pro, PID_MSB, (u8)(pid >> 8));
+
+               ret |= it913x_wr_reg(udev, pro, PID_INX_EN, (u8)onoff);
+
+               ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f));
+
+       }
+
+       mutex_unlock(&adap->dev->i2c_mutex);
+       return 0;
+}
+
+
+static int it913x_return_status(struct usb_device *udev)
+{
+       u32 firm = 0;
+
+       firm = it913x_query(udev, DEV_0);
+       if (firm > 0)
+               info("Firmware Version %d", firm);
+
+       return (firm > 0) ? firm : 0;
+}
+
+static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                                int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       static u8 data[256];
+       int ret;
+       u32 reg;
+       u8 pro;
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+                       return -EAGAIN;
+
+       debug_data_snipet(1, "Message out", msg[0].buf);
+       deb_info(2, "num of messages %d address %02x", num, msg[0].addr);
+
+       pro = (msg[0].addr & 0x2) ?  DEV_0_DMOD : 0x0;
+       pro |= (msg[0].addr & 0x20) ? DEV_1 : DEV_0;
+       memcpy(data, msg[0].buf, msg[0].len);
+       reg = (data[0] << 24) + (data[1] << 16) +
+                       (data[2] << 8) + data[3];
+       if (num == 2) {
+               ret = it913x_io(d->udev, READ_LONG, pro,
+                       CMD_DEMOD_READ, reg, 0, data, msg[1].len);
+               memcpy(msg[1].buf, data, msg[1].len);
+       } else
+               ret = it913x_io(d->udev, WRITE_LONG, pro, CMD_DEMOD_WRITE,
+                       reg, 0, &data[4], msg[0].len - 4);
+
+       mutex_unlock(&d->i2c_mutex);
+
+       return ret;
+}
+
+static u32 it913x_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm it913x_i2c_algo = {
+       .master_xfer   = it913x_i2c_xfer,
+       .functionality = it913x_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+#define IT913X_POLL 250
+static int it913x_rc_query(struct dvb_usb_device *d)
+{
+       u8 ibuf[4];
+       int ret;
+       u32 key;
+       /* Avoid conflict with frontends*/
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+                       return -EAGAIN;
+
+       ret = it913x_io(d->udev, READ_LONG, PRO_LINK, CMD_IR_GET,
+               0, 0, &ibuf[0], sizeof(ibuf));
+
+       if ((ibuf[2] + ibuf[3]) == 0xff) {
+               key = ibuf[2];
+               key += ibuf[0] << 8;
+               deb_info(1, "INT Key =%08x", key);
+               if (d->rc_dev != NULL)
+                       rc_keydown(d->rc_dev, key, 0);
+       }
+       mutex_unlock(&d->i2c_mutex);
+
+       return ret;
+}
+static int it913x_identify_state(struct usb_device *udev,
+               struct dvb_usb_device_properties *props,
+               struct dvb_usb_device_description **desc,
+               int *cold)
+{
+       int ret = 0, firm_no;
+       u8 reg, adap, ep, tun0, tun1;
+
+       firm_no = it913x_return_status(udev);
+
+       ep = it913x_read_reg(udev, 0x49ac);
+       adap = it913x_read_reg(udev, 0x49c5);
+       tun0 = it913x_read_reg(udev, 0x49d0);
+       info("No. Adapters=%x Endpoints=%x Tuner Type=%x", adap, ep, tun0);
+
+       if (firm_no > 0) {
+               *cold = 0;
+               return 0;
+       }
+
+       if (adap > 2) {
+               tun1 = it913x_read_reg(udev, 0x49e0);
+               ret = it913x_wr_reg(udev, DEV_0, GPIOH1_EN, 0x1);
+               ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_ON, 0x1);
+               ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1);
+               msleep(50); /* Delay noticed reset cycle ? */
+               ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0);
+               msleep(50);
+               reg = it913x_read_reg(udev, GPIOH1_O);
+               if (reg == 0) {
+                       ret |= it913x_wr_reg(udev, DEV_0,  GPIOH1_O, 0x1);
+                       ret |= it913x_return_status(udev);
+                       if (ret != 0)
+                               ret = it913x_wr_reg(udev, DEV_0,
+                                       GPIOH1_O, 0x0);
+               }
+       } else
+               props->num_adapters = 1;
+
+       reg = it913x_read_reg(udev, IO_MUX_POWER_CLK);
+
+       ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR);
+
+       ret |= it913x_wr_reg(udev, DEV_0,  CLK_O_EN, 0x1);
+
+       *cold = 1;
+
+       return (ret < 0) ? -ENODEV : 0;
+}
+
+static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+       int ret = 0;
+       u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
+
+       if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
+                       return -EAGAIN;
+       deb_info(1, "STM  (%02x)", onoff);
+
+       if (!onoff)
+               ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1);
+
+
+       mutex_unlock(&adap->dev->i2c_mutex);
+
+       return ret;
+}
+
+
+static int it913x_download_firmware(struct usb_device *udev,
+                                       const struct firmware *fw)
+{
+       int ret = 0, i;
+       u8 packet_size, dlen, tun1;
+       u8 *fw_data;
+
+       packet_size = 0x29;
+
+       tun1 = it913x_read_reg(udev, 0x49e0);
+
+       ret = it913x_wr_reg(udev, DEV_0,  I2C_CLK, I2C_CLK_100);
+
+       info("FRM Starting Firmware Download");
+       /* This uses scatter write firmware headers follow */
+       /* 03 XX 00     XX = chip number? */ 
+
+       for (i = 0; i < fw->size; i += packet_size) {
+                       if (i > 0)
+                               packet_size = 0x39;
+                       fw_data = (u8 *)(fw->data + i);
+                       dlen = ((i + packet_size) > fw->size)
+                               ? (fw->size - i) : packet_size;
+                       ret |= it913x_io(udev, WRITE_DATA, DEV_0,
+                               CMD_SCATTER_WRITE, 0, 0, fw_data, dlen);
+                       udelay(1000);
+       }
+
+       ret |= it913x_io(udev, WRITE_CMD, DEV_0,
+                       CMD_BOOT, 0, 0, NULL, 0);
+
+       msleep(100);
+
+       if (ret < 0)
+               info("FRM Firmware Download Failed (%04x)" , ret);
+       else
+               info("FRM Firmware Download Completed - Resetting Device");
+
+       ret |= it913x_return_status(udev);
+
+       msleep(30);
+
+       ret |= it913x_wr_reg(udev, DEV_0,  I2C_CLK, I2C_CLK_400);
+
+       /* Tuner function */
+       ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0);
+
+       ret |= it913x_wr_reg(udev, DEV_0,  PADODPU, 0x0);
+       ret |= it913x_wr_reg(udev, DEV_0,  AGC_O_D, 0x0);
+       if (tun1 > 0) {
+               ret |= it913x_wr_reg(udev, DEV_1,  PADODPU, 0x0);
+               ret |= it913x_wr_reg(udev, DEV_1,  AGC_O_D, 0x0);
+       }
+
+       return (ret < 0) ? -ENODEV : 0;
+}
+
+static int it913x_name(struct dvb_usb_adapter *adap)
+{
+       const char *desc = adap->dev->desc->name;
+       char *fe_name[] = {"_1", "_2", "_3", "_4"};
+       char *name = adap->fe_adap[0].fe->ops.info.name;
+
+       strlcpy(name, desc, 128);
+       strlcat(name, fe_name[adap->id], 128);
+
+       return 0;
+}
+
+static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct usb_device *udev = adap->dev->udev;
+       int ret = 0;
+       u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK);
+       u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5);
+       u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize;
+
+       adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach,
+               &adap->dev->i2c_adap, adap_addr, adf, IT9137);
+
+       if (adap->id == 0 && adap->fe_adap[0].fe) {
+               ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1);
+               ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_SW_RST, 0x1);
+               ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x0f);
+               ret = it913x_wr_reg(udev, DEV_0, EP0_TX_NAK, 0x1b);
+               ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x2f);
+               ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_LSB,
+                                       ep_size & 0xff);
+               ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8);
+               ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, 0x80);
+       } else if (adap->id == 1 && adap->fe_adap[0].fe) {
+               ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x6f);
+               ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_LSB,
+                                       ep_size & 0xff);
+               ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8);
+               ret = it913x_wr_reg(udev, DEV_0, EP5_MAX_PKT, 0x80);
+               ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_EN, 0x1);
+               ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_SERIAL, 0x1);
+               ret = it913x_wr_reg(udev, DEV_1, TOP_HOSTB_SER_MODE, 0x1);
+               ret = it913x_wr_reg(udev, DEV_0_DMOD, TSIS_ENABLE, 0x1);
+               ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x0);
+               ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_SW_RST, 0x0);
+               ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_HALF_PSB, 0x0);
+               ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF_STOP_EN, 0x1);
+               ret = it913x_wr_reg(udev, DEV_1_DMOD, MPEG_FULL_SPEED, 0x0);
+               ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_STOP_EN, 0x0);
+       } else
+               return -ENODEV;
+
+       ret = it913x_name(adap);
+
+       return ret;
+}
+
+/* DVB USB Driver */
+static struct dvb_usb_device_properties it913x_properties;
+
+static int it913x_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       cmd_counter = 0;
+       if (0 == dvb_usb_device_init(intf, &it913x_properties,
+                                    THIS_MODULE, NULL, adapter_nr)) {
+               info("DEV registering device driver");
+               return 0;
+       }
+
+       info("DEV it913x Error");
+       return -ENODEV;
+
+}
+
+static struct usb_device_id it913x_table[] = {
+       { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) },
+       {}              /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, it913x_table);
+
+static struct dvb_usb_device_properties it913x_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .download_firmware = it913x_download_firmware,
+       .firmware = "dvb-usb-it9137-01.fw",
+       .no_reconnect = 1,
+       .size_of_priv = sizeof(struct it913x_state),
+       .num_adapters = 2,
+       .adapter = {
+               {
+               .num_frontends = 1,
+               .fe = {{
+                       .caps = DVB_USB_ADAP_HAS_PID_FILTER|
+                               DVB_USB_ADAP_NEED_PID_FILTERING|
+                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                       .streaming_ctrl   = it913x_streaming_ctrl,
+                       .pid_filter_count = 31,
+                       .pid_filter = it913x_pid_filter,
+                       .pid_filter_ctrl  = it913x_pid_filter_ctrl,
+                       .frontend_attach  = it913x_frontend_attach,
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 10,
+                               .endpoint = 0x04,
+                               .u = {/* Keep Low if PID filter on */
+                                       .bulk = {
+                                               .buffersize = 3584,
+
+                                       }
+                               }
+                       }
+               }},
+               },
+                       {
+               .num_frontends = 1,
+               .fe = {{
+                       .caps = DVB_USB_ADAP_HAS_PID_FILTER|
+                               DVB_USB_ADAP_NEED_PID_FILTERING|
+                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                       .streaming_ctrl   = it913x_streaming_ctrl,
+                       .pid_filter_count = 31,
+                       .pid_filter = it913x_pid_filter,
+                       .pid_filter_ctrl  = it913x_pid_filter_ctrl,
+                       .frontend_attach  = it913x_frontend_attach,
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 5,
+                               .endpoint = 0x05,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 3584,
+
+                                       }
+                               }
+                       }
+               }},
+               }
+       },
+       .identify_state   = it913x_identify_state,
+       .rc.core = {
+               .protocol       = RC_TYPE_NEC,
+               .module_name    = "it913x",
+               .rc_query       = it913x_rc_query,
+               .rc_interval    = IT913X_POLL,
+               .allowed_protos = RC_TYPE_NEC,
+               .rc_codes       = RC_MAP_KWORLD_315U,
+       },
+       .i2c_algo         = &it913x_i2c_algo,
+       .num_device_descs = 1,
+       .devices = {
+               {   "Kworld UB499-2T T09(IT9137)",
+                       { &it913x_table[0], NULL },
+                       },
+
+       }
+};
+
+static struct usb_driver it913x_driver = {
+       .name           = "it913x",
+       .probe          = it913x_probe,
+       .disconnect     = dvb_usb_device_exit,
+       .id_table       = it913x_table,
+};
+
+/* module stuff */
+static int __init it913x_module_init(void)
+{
+       int result = usb_register(&it913x_driver);
+       if (result) {
+               err("usb_register failed. Error number %d", result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit it913x_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&it913x_driver);
+}
+
+module_init(it913x_module_init);
+module_exit(it913x_module_exit);
+
+MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
+MODULE_DESCRIPTION("it913x USB 2 Driver");
+MODULE_VERSION("1.06");
+MODULE_LICENSE("GPL");
index 37b1469..b922824 100644 (file)
@@ -162,7 +162,7 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
        int ret = 0;
 
        if (st->usb_buffer == NULL) {
-               st->usb_buffer = kmalloc(512, GFP_KERNEL);
+               st->usb_buffer = kmalloc(64, GFP_KERNEL);
                if (st->usb_buffer == NULL) {
                        info("MEM Error no memory");
                        return -ENOMEM;
@@ -175,8 +175,8 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
        if (ret < 0)
                return -EAGAIN;
 
-       /* the read/write capped at 512 */
-       memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen);
+       /* the read/write capped at 64 */
+       memcpy(buff, wbuf, (wlen < 64) ? wlen : 64);
 
        ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01));
 
@@ -186,8 +186,8 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
 
        ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01));
 
-       ret |= lme2510_bulk_read(d->udev, buff, (rlen > 512) ?
-                       512 : rlen , 0x01);
+       ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ?
+                       rlen : 64 , 0x01);
 
        if (rlen > 0)
                memcpy(rbuf, buff, rlen);
@@ -333,7 +333,7 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
        if (lme_int->lme_urb == NULL)
                        return -ENOMEM;
 
-       lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 5000, GFP_ATOMIC,
+       lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 128, GFP_ATOMIC,
                                        &lme_int->lme_urb->transfer_dma);
 
        if (lme_int->buffer == NULL)
@@ -343,10 +343,10 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
                                adap->dev->udev,
                                usb_rcvintpipe(adap->dev->udev, 0xa),
                                lme_int->buffer,
-                               4096,
+                               128,
                                lme2510_int_response,
                                adap,
-                               11);
+                               8);
 
        lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
@@ -580,7 +580,7 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        struct lme2510_state *st = d->priv;
-       static u8 obuf[64], ibuf[512];
+       static u8 obuf[64], ibuf[64];
        int i, read, read_o;
        u16 len;
        u8 gate = st->i2c_gate;
@@ -621,7 +621,7 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                        len = msg[i].len+3;
                }
 
-               if (lme2510_msg(d, obuf, len, ibuf, 512) < 0) {
+               if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) {
                        deb_info(1, "i2c transfer failed.");
                        return -EAGAIN;
                }
@@ -941,7 +941,7 @@ static int lme_name(struct dvb_usb_adapter *adap)
        const char *desc = adap->dev->desc->name;
        char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395",
                                " SHARP:BS2F7HZ0194"};
-       char *name = adap->fe->ops.info.name;
+       char *name = adap->fe_adap[0].fe->ops.info.name;
 
        strlcpy(name, desc, 128);
        strlcat(name, fe_name[st->tuner_config], 128);
@@ -958,10 +958,10 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
        st->i2c_talk_onoff = 1;
 
        st->i2c_gate = 4;
-       adap->fe = dvb_attach(tda10086_attach, &tda10086_config,
+       adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config,
                &adap->dev->i2c_adap);
 
-       if (adap->fe) {
+       if (adap->fe_adap[0].fe) {
                info("TUN Found Frontend TDA10086");
                st->i2c_tuner_gate_w = 4;
                st->i2c_tuner_gate_r = 4;
@@ -975,9 +975,9 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
        }
 
        st->i2c_gate = 4;
-       adap->fe = dvb_attach(stv0299_attach, &sharp_z0194_config,
+       adap->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194_config,
                        &adap->dev->i2c_adap);
-       if (adap->fe) {
+       if (adap->fe_adap[0].fe) {
                info("FE Found Stv0299");
                st->i2c_tuner_gate_w = 4;
                st->i2c_tuner_gate_r = 5;
@@ -991,9 +991,9 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
        }
 
        st->i2c_gate = 5;
-       adap->fe = dvb_attach(stv0288_attach, &lme_config,
+       adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config,
                        &adap->dev->i2c_adap);
-       if (adap->fe) {
+       if (adap->fe_adap[0].fe) {
                info("FE Found Stv0288");
                st->i2c_tuner_gate_w = 4;
                st->i2c_tuner_gate_r = 5;
@@ -1010,15 +1010,15 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
 
 
 end:   if (ret) {
-               if (adap->fe) {
-                       dvb_frontend_detach(adap->fe);
-                       adap->fe = NULL;
+               if (adap->fe_adap[0].fe) {
+                       dvb_frontend_detach(adap->fe_adap[0].fe);
+                       adap->fe_adap[0].fe = NULL;
                }
                adap->dev->props.rc.core.rc_codes = NULL;
                return -ENODEV;
        }
 
-       adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
+       adap->fe_adap[0].fe->ops.set_voltage = dm04_lme2510_set_voltage;
        ret = lme_name(adap);
        return ret;
 }
@@ -1031,17 +1031,17 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
 
        switch (st->tuner_config) {
        case TUNER_LG:
-               if (dvb_attach(tda826x_attach, adap->fe, 0xc0,
+               if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0xc0,
                        &adap->dev->i2c_adap, 1))
                        ret = st->tuner_config;
                break;
        case TUNER_S7395:
-               if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner,
+               if (dvb_attach(ix2505v_attach , adap->fe_adap[0].fe, &lme_tuner,
                        &adap->dev->i2c_adap))
                        ret = st->tuner_config;
                break;
        case TUNER_S0194:
-               if (dvb_attach(dvb_pll_attach , adap->fe, 0xc0,
+               if (dvb_attach(dvb_pll_attach , adap->fe_adap[0].fe, 0xc0,
                        &adap->dev->i2c_adap, DVB_PLL_OPERA1))
                        ret = st->tuner_config;
                break;
@@ -1145,6 +1145,8 @@ static struct dvb_usb_device_properties lme2510_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER|
                                DVB_USB_ADAP_NEED_PID_FILTERING|
                                DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@@ -1166,6 +1168,7 @@ static struct dvb_usb_device_properties lme2510_properties = {
                                        }
                                }
                        }
+               }},
                }
        },
        .rc.core = {
@@ -1193,6 +1196,8 @@ static struct dvb_usb_device_properties lme2510c_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER|
                                DVB_USB_ADAP_NEED_PID_FILTERING|
                                DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
@@ -1214,6 +1219,7 @@ static struct dvb_usb_device_properties lme2510c_properties = {
                                        }
                                }
                        }
+               }},
                }
        },
        .rc.core = {
@@ -1241,7 +1247,7 @@ static void *lme2510_exit_int(struct dvb_usb_device *d)
        void *buffer = NULL;
 
        if (adap != NULL) {
-               lme2510_kill_urb(&adap->stream);
+               lme2510_kill_urb(&adap->fe_adap[0].stream);
                adap->feedcount = 0;
        }
 
@@ -1255,7 +1261,7 @@ static void *lme2510_exit_int(struct dvb_usb_device *d)
 
        if (st->lme_urb != NULL) {
                usb_kill_urb(st->lme_urb);
-               usb_free_coherent(d->udev, 5000, st->buffer,
+               usb_free_coherent(d->udev, 128, st->buffer,
                                  st->lme_urb->transfer_dma);
                info("Interrupt Service Stopped");
        }
@@ -1306,5 +1312,5 @@ module_exit(lme2510_module_exit);
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.88");
+MODULE_VERSION("1.90");
 MODULE_LICENSE("GPL");
index 9456792..a1e1287 100644 (file)
@@ -86,12 +86,12 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
        }
 
        for (i = 0; i < d->props.num_adapters; i++)
-               flags |= d->adapter[i].props.caps;
+               flags |= d->adapter[i].props.fe[0].caps;
 
        /* Some devices(Dposh) might crash if we attempt touch at all. */
        if (flags & DVB_USB_ADAP_HAS_PID_FILTER) {
                for (i = 0; i < d->props.num_adapters; i++) {
-                       epi = d->adapter[i].props.stream.endpoint - 0x81;
+                       epi = d->adapter[i].props.fe[0].stream.endpoint - 0x81;
 
                        if (epi < 0 || epi >= M9206_MAX_ADAPTERS) {
                                printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n");
@@ -292,7 +292,7 @@ static int m920x_update_filters(struct dvb_usb_adapter *adap)
        struct m920x_state *m = adap->dev->priv;
        int enabled = m->filtering_enabled[adap->id];
        int i, ret = 0, filter = 0;
-       int ep = adap->props.stream.endpoint;
+       int ep = adap->props.fe[0].stream.endpoint;
 
        for (i = 0; i < M9206_MAX_FILTERS; i++)
                if (m->filters[adap->id][i] == 8192)
@@ -501,9 +501,10 @@ static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap)
 {
        deb("%s\n",__func__);
 
-       if ((adap->fe = dvb_attach(mt352_attach,
-                                  &m920x_mt352_config,
-                                  &adap->dev->i2c_adap)) == NULL)
+       adap->fe_adap[0].fe = dvb_attach(mt352_attach,
+                                        &m920x_mt352_config,
+                                        &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) == NULL)
                return -EIO;
 
        return 0;
@@ -513,9 +514,10 @@ static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap)
 {
        deb("%s\n",__func__);
 
-       if ((adap->fe = dvb_attach(tda10046_attach,
-                                  &m920x_tda10046_08_config,
-                                  &adap->dev->i2c_adap)) == NULL)
+       adap->fe_adap[0].fe = dvb_attach(tda10046_attach,
+                                        &m920x_tda10046_08_config,
+                                        &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) == NULL)
                return -EIO;
 
        return 0;
@@ -525,9 +527,10 @@ static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap)
 {
        deb("%s\n",__func__);
 
-       if ((adap->fe = dvb_attach(tda10046_attach,
-                                  &m920x_tda10046_0b_config,
-                                  &adap->dev->i2c_adap)) == NULL)
+       adap->fe_adap[0].fe = dvb_attach(tda10046_attach,
+                                        &m920x_tda10046_0b_config,
+                                        &adap->dev->i2c_adap);
+       if ((adap->fe_adap[0].fe) == NULL)
                return -EIO;
 
        return 0;
@@ -537,7 +540,7 @@ static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
 {
        deb("%s\n",__func__);
 
-       if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL)
+       if (dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL)
                return -ENODEV;
 
        return 0;
@@ -547,7 +550,7 @@ static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap)
 {
        deb("%s\n",__func__);
 
-       if (dvb_attach(tda827x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL)
+       if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL)
                return -ENODEV;
 
        return 0;
@@ -557,7 +560,7 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap)
 {
        deb("%s\n",__func__);
 
-       if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL)
+       if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL)
                return -ENODEV;
 
        return 0;
@@ -565,7 +568,7 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap)
 
 static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       dvb_attach(simple_tuner_attach, adap->fe,
+       dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
                   &adap->dev->i2c_adap, 0x61,
                   TUNER_PHILIPS_FMD1216ME_MK3);
        return 0;
@@ -807,6 +810,9 @@ static struct dvb_usb_device_properties megasky_properties = {
        .identify_state   = m920x_identify_state,
        .num_adapters = 1,
        .adapter = {{
+               .num_frontends = 1,
+               .fe = {{
+
                .caps = DVB_USB_ADAP_HAS_PID_FILTER |
                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 
@@ -827,6 +833,7 @@ static struct dvb_usb_device_properties megasky_properties = {
                                }
                        }
                },
+               }},
        }},
        .i2c_algo         = &m920x_i2c_algo,
 
@@ -851,6 +858,9 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties = {
        .identify_state   = m920x_identify_state,
        .num_adapters = 1,
        .adapter = {{
+               .num_frontends = 1,
+               .fe = {{
+
                .caps = DVB_USB_ADAP_HAS_PID_FILTER |
                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 
@@ -871,6 +881,7 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties = {
                                }
                        }
                },
+               }},
        }},
        .i2c_algo         = &m920x_i2c_algo,
 
@@ -910,6 +921,9 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
        .identify_state   = m920x_identify_state,
        .num_adapters = 2,
        .adapter = {{
+               .num_frontends = 1,
+               .fe = {{
+
                .caps = DVB_USB_ADAP_HAS_PID_FILTER |
                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 
@@ -929,7 +943,11 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
                                         .buffersize = 512,
                                 }
                        }
+               }},
                }},{
+               .num_frontends = 1,
+               .fe = {{
+
                .caps = DVB_USB_ADAP_HAS_PID_FILTER |
                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 
@@ -949,6 +967,7 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
                                         .buffersize = 512,
                                 }
                        }
+               }},
                },
        }},
        .i2c_algo         = &m920x_i2c_algo,
@@ -974,6 +993,8 @@ static struct dvb_usb_device_properties dposh_properties = {
        .identify_state   = m920x_identify_state,
        .num_adapters = 1,
        .adapter = {{
+               .num_frontends = 1,
+               .fe = {{
                /* Hardware pid filters don't work with this device/firmware */
 
                .frontend_attach  = m920x_mt352_frontend_attach,
@@ -989,6 +1010,7 @@ static struct dvb_usb_device_properties dposh_properties = {
                                 }
                        }
                },
+               }},
        }},
        .i2c_algo         = &m920x_i2c_algo,
 
@@ -1019,6 +1041,9 @@ static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
        .identify_state   = m920x_identify_state,
        .num_adapters = 1,
        .adapter = {{
+               .num_frontends = 1,
+               .fe = {{
+
                .caps = DVB_USB_ADAP_HAS_PID_FILTER |
                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 
@@ -1041,6 +1066,7 @@ static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
                                }
                        }
                },
+               }},
        } },
        .i2c_algo         = &m920x_i2c_algo,
 
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c b/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c
new file mode 100644 (file)
index 0000000..e4121cb
--- /dev/null
@@ -0,0 +1,763 @@
+/*
+ *  mxl111sf-gpio.c - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  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 "mxl111sf-gpio.h"
+#include "mxl111sf-i2c.h"
+#include "mxl111sf.h"
+
+/* ------------------------------------------------------------------------- */
+
+#define MXL_GPIO_MUX_REG_0 0x84
+#define MXL_GPIO_MUX_REG_1 0x89
+#define MXL_GPIO_MUX_REG_2 0x82
+
+#define MXL_GPIO_DIR_INPUT  0
+#define MXL_GPIO_DIR_OUTPUT 1
+
+
+static int mxl111sf_set_gpo_state(struct mxl111sf_state *state, u8 pin, u8 val)
+{
+       int ret;
+       u8 tmp;
+
+       mxl_debug_adv("(%d, %d)", pin, val);
+
+       if ((pin > 0) && (pin < 8)) {
+               ret = mxl111sf_read_reg(state, 0x19, &tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+               tmp &= ~(1 << (pin - 1));
+               tmp |= (val << (pin - 1));
+               ret = mxl111sf_write_reg(state, 0x19, tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+       } else if (pin <= 10) {
+               if (pin == 0)
+                       pin += 7;
+               ret = mxl111sf_read_reg(state, 0x30, &tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+               tmp &= ~(1 << (pin - 3));
+               tmp |= (val << (pin - 3));
+               ret = mxl111sf_write_reg(state, 0x30, tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+       } else
+               ret = -EINVAL;
+fail:
+       return ret;
+}
+
+static int mxl111sf_get_gpi_state(struct mxl111sf_state *state, u8 pin, u8 *val)
+{
+       int ret;
+       u8 tmp;
+
+       mxl_debug("(0x%02x)", pin);
+
+       *val = 0;
+
+       switch (pin) {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+               ret = mxl111sf_read_reg(state, 0x23, &tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+               *val = (tmp >> (pin + 4)) & 0x01;
+               break;
+       case 4:
+       case 5:
+       case 6:
+       case 7:
+               ret = mxl111sf_read_reg(state, 0x2f, &tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+               *val = (tmp >> pin) & 0x01;
+               break;
+       case 8:
+       case 9:
+       case 10:
+               ret = mxl111sf_read_reg(state, 0x22, &tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+               *val = (tmp >> (pin - 3)) & 0x01;
+               break;
+       default:
+               return -EINVAL; /* invalid pin */
+       }
+fail:
+       return ret;
+}
+
+struct mxl_gpio_cfg {
+       u8 pin;
+       u8 dir;
+       u8 val;
+};
+
+static int mxl111sf_config_gpio_pins(struct mxl111sf_state *state,
+                                    struct mxl_gpio_cfg *gpio_cfg)
+{
+       int ret;
+       u8 tmp;
+
+       mxl_debug_adv("(%d, %d)", gpio_cfg->pin, gpio_cfg->dir);
+
+       switch (gpio_cfg->pin) {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+               ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_0, &tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+               tmp &= ~(1 << (gpio_cfg->pin + 4));
+               tmp |= (gpio_cfg->dir << (gpio_cfg->pin + 4));
+               ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_0, tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+               break;
+       case 4:
+       case 5:
+       case 6:
+       case 7:
+               ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_1, &tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+               tmp &= ~(1 << gpio_cfg->pin);
+               tmp |= (gpio_cfg->dir << gpio_cfg->pin);
+               ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_1, tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+               break;
+       case 8:
+       case 9:
+       case 10:
+               ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_2, &tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+               tmp &= ~(1 << (gpio_cfg->pin - 3));
+               tmp |= (gpio_cfg->dir << (gpio_cfg->pin - 3));
+               ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_2, tmp);
+               if (mxl_fail(ret))
+                       goto fail;
+               break;
+       default:
+               return -EINVAL; /* invalid pin */
+       }
+
+       ret = (MXL_GPIO_DIR_OUTPUT == gpio_cfg->dir) ?
+               mxl111sf_set_gpo_state(state,
+                                      gpio_cfg->pin, gpio_cfg->val) :
+               mxl111sf_get_gpi_state(state,
+                                      gpio_cfg->pin, &gpio_cfg->val);
+       mxl_fail(ret);
+fail:
+       return ret;
+}
+
+static int mxl111sf_hw_do_set_gpio(struct mxl111sf_state *state,
+                                  int gpio, int direction, int val)
+{
+       struct mxl_gpio_cfg gpio_config = {
+               .pin = gpio,
+               .dir = direction,
+               .val = val,
+       };
+
+       mxl_debug("(%d, %d, %d)", gpio, direction, val);
+
+       return mxl111sf_config_gpio_pins(state, &gpio_config);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#define PIN_MUX_MPEG_MODE_MASK          0x40   /* 0x17 <6> */
+#define PIN_MUX_MPEG_PAR_EN_MASK        0x01   /* 0x18 <0> */
+#define PIN_MUX_MPEG_SER_EN_MASK        0x02   /* 0x18 <1> */
+#define PIN_MUX_MPG_IN_MUX_MASK         0x80   /* 0x3D <7> */
+#define PIN_MUX_BT656_ENABLE_MASK       0x04   /* 0x12 <2> */
+#define PIN_MUX_I2S_ENABLE_MASK         0x40   /* 0x15 <6> */
+#define PIN_MUX_SPI_MODE_MASK           0x10   /* 0x3D <4> */
+#define PIN_MUX_MCLK_EN_CTRL_MASK       0x10   /* 0x82 <4> */
+#define PIN_MUX_MPSYN_EN_CTRL_MASK      0x20   /* 0x82 <5> */
+#define PIN_MUX_MDVAL_EN_CTRL_MASK      0x40   /* 0x82 <6> */
+#define PIN_MUX_MPERR_EN_CTRL_MASK      0x80   /* 0x82 <7> */
+#define PIN_MUX_MDAT_EN_0_MASK          0x10   /* 0x84 <4> */
+#define PIN_MUX_MDAT_EN_1_MASK          0x20   /* 0x84 <5> */
+#define PIN_MUX_MDAT_EN_2_MASK          0x40   /* 0x84 <6> */
+#define PIN_MUX_MDAT_EN_3_MASK          0x80   /* 0x84 <7> */
+#define PIN_MUX_MDAT_EN_4_MASK          0x10   /* 0x89 <4> */
+#define PIN_MUX_MDAT_EN_5_MASK          0x20   /* 0x89 <5> */
+#define PIN_MUX_MDAT_EN_6_MASK          0x40   /* 0x89 <6> */
+#define PIN_MUX_MDAT_EN_7_MASK          0x80   /* 0x89 <7> */
+
+int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state,
+                                 enum mxl111sf_mux_config pin_mux_config)
+{
+       u8 r12, r15, r17, r18, r3D, r82, r84, r89;
+       int ret;
+
+       mxl_debug("(%d)", pin_mux_config);
+
+       ret = mxl111sf_read_reg(state, 0x17, &r17);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_read_reg(state, 0x18, &r18);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_read_reg(state, 0x12, &r12);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_read_reg(state, 0x15, &r15);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_read_reg(state, 0x82, &r82);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_read_reg(state, 0x84, &r84);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_read_reg(state, 0x89, &r89);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_read_reg(state, 0x3D, &r3D);
+       if (mxl_fail(ret))
+               goto fail;
+
+       switch (pin_mux_config) {
+       case PIN_MUX_TS_OUT_PARALLEL:
+               /* mpeg_mode = 1 */
+               r17 |= PIN_MUX_MPEG_MODE_MASK;
+               /* mpeg_par_en = 1 */
+               r18 |= PIN_MUX_MPEG_PAR_EN_MASK;
+               /* mpeg_ser_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
+               /* mpg_in_mux = 0 */
+               r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+               /* bt656_enable = 0 */
+               r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+               /* i2s_enable = 0 */
+               r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+               /* spi_mode = 0 */
+               r3D &= ~PIN_MUX_SPI_MODE_MASK;
+               /* mclk_en_ctrl = 1 */
+               r82 |= PIN_MUX_MCLK_EN_CTRL_MASK;
+               /* mperr_en_ctrl = 1 */
+               r82 |= PIN_MUX_MPERR_EN_CTRL_MASK;
+               /* mdval_en_ctrl = 1 */
+               r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK;
+               /* mpsyn_en_ctrl = 1 */
+               r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK;
+               /* mdat_en_ctrl[3:0] = 0xF */
+               r84 |= 0xF0;
+               /* mdat_en_ctrl[7:4] = 0xF */
+               r89 |= 0xF0;
+               break;
+       case PIN_MUX_TS_OUT_SERIAL:
+               /* mpeg_mode = 1 */
+               r17 |= PIN_MUX_MPEG_MODE_MASK;
+               /* mpeg_par_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+               /* mpeg_ser_en = 1 */
+               r18 |= PIN_MUX_MPEG_SER_EN_MASK;
+               /* mpg_in_mux = 0 */
+               r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+               /* bt656_enable = 0 */
+               r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+               /* i2s_enable = 0 */
+               r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+               /* spi_mode = 0 */
+               r3D &= ~PIN_MUX_SPI_MODE_MASK;
+               /* mclk_en_ctrl = 1 */
+               r82 |= PIN_MUX_MCLK_EN_CTRL_MASK;
+               /* mperr_en_ctrl = 1 */
+               r82 |= PIN_MUX_MPERR_EN_CTRL_MASK;
+               /* mdval_en_ctrl = 1 */
+               r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK;
+               /* mpsyn_en_ctrl = 1 */
+               r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK;
+               /* mdat_en_ctrl[3:0] = 0xF */
+               r84 |= 0xF0;
+               /* mdat_en_ctrl[7:4] = 0xF */
+               r89 |= 0xF0;
+               break;
+       case PIN_MUX_GPIO_MODE:
+               /* mpeg_mode = 0 */
+               r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+               /* mpeg_par_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+               /* mpeg_ser_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
+               /* mpg_in_mux = 0 */
+               r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+               /* bt656_enable = 0 */
+               r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+               /* i2s_enable = 0 */
+               r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+               /* spi_mode = 0 */
+               r3D &= ~PIN_MUX_SPI_MODE_MASK;
+               /* mclk_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+               /* mperr_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+               /* mdval_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+               /* mpsyn_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+               /* mdat_en_ctrl[3:0] = 0x0 */
+               r84 &= 0x0F;
+               /* mdat_en_ctrl[7:4] = 0x0 */
+               r89 &= 0x0F;
+               break;
+       case PIN_MUX_TS_SERIAL_IN_MODE_0:
+               /* mpeg_mode = 0 */
+               r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+               /* mpeg_par_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+               /* mpeg_ser_en = 1 */
+               r18 |= PIN_MUX_MPEG_SER_EN_MASK;
+               /* mpg_in_mux = 0 */
+               r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+               /* bt656_enable = 0 */
+               r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+               /* i2s_enable = 0 */
+               r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+               /* spi_mode = 0 */
+               r3D &= ~PIN_MUX_SPI_MODE_MASK;
+               /* mclk_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+               /* mperr_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+               /* mdval_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+               /* mpsyn_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+               /* mdat_en_ctrl[3:0] = 0x0 */
+               r84 &= 0x0F;
+               /* mdat_en_ctrl[7:4] = 0x0 */
+               r89 &= 0x0F;
+               break;
+       case PIN_MUX_TS_SERIAL_IN_MODE_1:
+               /* mpeg_mode = 0 */
+               r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+               /* mpeg_par_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+               /* mpeg_ser_en = 1 */
+               r18 |= PIN_MUX_MPEG_SER_EN_MASK;
+               /* mpg_in_mux = 1 */
+               r3D |= PIN_MUX_MPG_IN_MUX_MASK;
+               /* bt656_enable = 0 */
+               r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+               /* i2s_enable = 0 */
+               r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+               /* spi_mode = 0 */
+               r3D &= ~PIN_MUX_SPI_MODE_MASK;
+               /* mclk_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+               /* mperr_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+               /* mdval_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+               /* mpsyn_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+               /* mdat_en_ctrl[3:0] = 0x0 */
+               r84 &= 0x0F;
+               /* mdat_en_ctrl[7:4] = 0x0 */
+               r89 &= 0x0F;
+               break;
+       case PIN_MUX_TS_SPI_IN_MODE_1:
+               /* mpeg_mode = 0 */
+               r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+               /* mpeg_par_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+               /* mpeg_ser_en = 1 */
+               r18 |= PIN_MUX_MPEG_SER_EN_MASK;
+               /* mpg_in_mux = 1 */
+               r3D |= PIN_MUX_MPG_IN_MUX_MASK;
+               /* bt656_enable = 0 */
+               r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+               /* i2s_enable = 1 */
+               r15 |= PIN_MUX_I2S_ENABLE_MASK;
+               /* spi_mode = 1 */
+               r3D |= PIN_MUX_SPI_MODE_MASK;
+               /* mclk_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+               /* mperr_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+               /* mdval_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+               /* mpsyn_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+               /* mdat_en_ctrl[3:0] = 0x0 */
+               r84 &= 0x0F;
+               /* mdat_en_ctrl[7:4] = 0x0 */
+               r89 &= 0x0F;
+               break;
+       case PIN_MUX_TS_SPI_IN_MODE_0:
+               /* mpeg_mode = 0 */
+               r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+               /* mpeg_par_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+               /* mpeg_ser_en = 1 */
+               r18 |= PIN_MUX_MPEG_SER_EN_MASK;
+               /* mpg_in_mux = 0 */
+               r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+               /* bt656_enable = 0 */
+               r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+               /* i2s_enable = 1 */
+               r15 |= PIN_MUX_I2S_ENABLE_MASK;
+               /* spi_mode = 1 */
+               r3D |= PIN_MUX_SPI_MODE_MASK;
+               /* mclk_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+               /* mperr_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+               /* mdval_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+               /* mpsyn_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+               /* mdat_en_ctrl[3:0] = 0x0 */
+               r84 &= 0x0F;
+               /* mdat_en_ctrl[7:4] = 0x0 */
+               r89 &= 0x0F;
+               break;
+       case PIN_MUX_TS_PARALLEL_IN:
+               /* mpeg_mode = 0 */
+               r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+               /* mpeg_par_en = 1 */
+               r18 |= PIN_MUX_MPEG_PAR_EN_MASK;
+               /* mpeg_ser_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
+               /* mpg_in_mux = 0 */
+               r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+               /* bt656_enable = 0 */
+               r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+               /* i2s_enable = 0 */
+               r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+               /* spi_mode = 0 */
+               r3D &= ~PIN_MUX_SPI_MODE_MASK;
+               /* mclk_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+               /* mperr_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+               /* mdval_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+               /* mpsyn_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+               /* mdat_en_ctrl[3:0] = 0x0 */
+               r84 &= 0x0F;
+               /* mdat_en_ctrl[7:4] = 0x0 */
+               r89 &= 0x0F;
+               break;
+       case PIN_MUX_BT656_I2S_MODE:
+               /* mpeg_mode = 0 */
+               r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+               /* mpeg_par_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+               /* mpeg_ser_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
+               /* mpg_in_mux = 0 */
+               r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+               /* bt656_enable = 1 */
+               r12 |= PIN_MUX_BT656_ENABLE_MASK;
+               /* i2s_enable = 1 */
+               r15 |= PIN_MUX_I2S_ENABLE_MASK;
+               /* spi_mode = 0 */
+               r3D &= ~PIN_MUX_SPI_MODE_MASK;
+               /* mclk_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+               /* mperr_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+               /* mdval_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+               /* mpsyn_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+               /* mdat_en_ctrl[3:0] = 0x0 */
+               r84 &= 0x0F;
+               /* mdat_en_ctrl[7:4] = 0x0 */
+               r89 &= 0x0F;
+               break;
+       case PIN_MUX_DEFAULT:
+       default:
+               /* mpeg_mode = 1 */
+               r17 |= PIN_MUX_MPEG_MODE_MASK;
+               /* mpeg_par_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+               /* mpeg_ser_en = 0 */
+               r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
+               /* mpg_in_mux = 0 */
+               r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+               /* bt656_enable = 0 */
+               r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+               /* i2s_enable = 0 */
+               r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+               /* spi_mode = 0 */
+               r3D &= ~PIN_MUX_SPI_MODE_MASK;
+               /* mclk_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+               /* mperr_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+               /* mdval_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+               /* mpsyn_en_ctrl = 0 */
+               r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+               /* mdat_en_ctrl[3:0] = 0x0 */
+               r84 &= 0x0F;
+               /* mdat_en_ctrl[7:4] = 0x0 */
+               r89 &= 0x0F;
+               break;
+       }
+
+       ret = mxl111sf_write_reg(state, 0x17, r17);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_write_reg(state, 0x18, r18);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_write_reg(state, 0x12, r12);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_write_reg(state, 0x15, r15);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_write_reg(state, 0x82, r82);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_write_reg(state, 0x84, r84);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_write_reg(state, 0x89, r89);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_write_reg(state, 0x3D, r3D);
+       if (mxl_fail(ret))
+               goto fail;
+fail:
+       return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl111sf_hw_set_gpio(struct mxl111sf_state *state, int gpio, int val)
+{
+       return mxl111sf_hw_do_set_gpio(state, gpio, MXL_GPIO_DIR_OUTPUT, val);
+}
+
+static int mxl111sf_hw_gpio_initialize(struct mxl111sf_state *state)
+{
+       u8 gpioval = 0x07; /* write protect enabled, signal LEDs off */
+       int i, ret;
+
+       mxl_debug("()");
+
+       for (i = 3; i < 8; i++) {
+               ret = mxl111sf_hw_set_gpio(state, i, (gpioval >> i) & 0x01);
+               if (mxl_fail(ret))
+                       break;
+       }
+
+       return ret;
+}
+
+#define PCA9534_I2C_ADDR (0x40 >> 1)
+static int pca9534_set_gpio(struct mxl111sf_state *state, int gpio, int val)
+{
+       u8 w[2] = { 1, 0 };
+       u8 r = 0;
+       struct i2c_msg msg[] = {
+               { .addr = PCA9534_I2C_ADDR,
+                 .flags = 0, .buf = w, .len = 1 },
+               { .addr = PCA9534_I2C_ADDR,
+                 .flags = I2C_M_RD, .buf = &r, .len = 1 },
+       };
+
+       mxl_debug("(%d, %d)", gpio, val);
+
+       /* read current GPIO levels from flip-flop */
+       i2c_transfer(&state->d->i2c_adap, msg, 2);
+
+       /* prepare write buffer with current GPIO levels */
+       msg[0].len = 2;
+#if 0
+       w[0] = 1;
+#endif
+       w[1] = r;
+
+       /* clear the desired GPIO */
+       w[1] &= ~(1 << gpio);
+
+       /* set the desired GPIO value */
+       w[1] |= ((val ? 1 : 0) << gpio);
+
+       /* write new GPIO levels to flip-flop */
+       i2c_transfer(&state->d->i2c_adap, &msg[0], 1);
+
+       return 0;
+}
+
+static int pca9534_init_port_expander(struct mxl111sf_state *state)
+{
+       u8 w[2] = { 1, 0x07 }; /* write protect enabled, signal LEDs off */
+
+       struct i2c_msg msg = {
+               .addr = PCA9534_I2C_ADDR,
+               .flags = 0, .buf = w, .len = 2
+       };
+
+       mxl_debug("()");
+
+       i2c_transfer(&state->d->i2c_adap, &msg, 1);
+
+       /* configure all pins as outputs */
+       w[0] = 3;
+       w[1] = 0;
+
+       i2c_transfer(&state->d->i2c_adap, &msg, 1);
+
+       return 0;
+}
+
+int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val)
+{
+       mxl_debug("(%d, %d)", gpio, val);
+
+       switch (state->gpio_port_expander) {
+       default:
+               mxl_printk(KERN_ERR,
+                          "gpio_port_expander undefined, assuming PCA9534");
+               /* fall-thru */
+       case mxl111sf_PCA9534:
+               return pca9534_set_gpio(state, gpio, val);
+       case mxl111sf_gpio_hw:
+               return mxl111sf_hw_set_gpio(state, gpio, val);
+       }
+}
+
+static int mxl111sf_probe_port_expander(struct mxl111sf_state *state)
+{
+       int ret;
+       u8 w = 1;
+       u8 r = 0;
+       struct i2c_msg msg[] = {
+               { .flags = 0,        .buf = &w, .len = 1 },
+               { .flags = I2C_M_RD, .buf = &r, .len = 1 },
+       };
+
+       mxl_debug("()");
+
+       msg[0].addr = 0x70 >> 1;
+       msg[1].addr = 0x70 >> 1;
+
+       /* read current GPIO levels from flip-flop */
+       ret = i2c_transfer(&state->d->i2c_adap, msg, 2);
+       if (ret == 2) {
+               state->port_expander_addr = msg[0].addr;
+               state->gpio_port_expander = mxl111sf_PCA9534;
+               mxl_debug("found port expander at 0x%02x",
+                         state->port_expander_addr);
+               return 0;
+       }
+
+       msg[0].addr = 0x40 >> 1;
+       msg[1].addr = 0x40 >> 1;
+
+       ret = i2c_transfer(&state->d->i2c_adap, msg, 2);
+       if (ret == 2) {
+               state->port_expander_addr = msg[0].addr;
+               state->gpio_port_expander = mxl111sf_PCA9534;
+               mxl_debug("found port expander at 0x%02x",
+                         state->port_expander_addr);
+               return 0;
+       }
+       state->port_expander_addr = 0xff;
+       state->gpio_port_expander = mxl111sf_gpio_hw;
+       mxl_debug("using hardware gpio");
+       return 0;
+}
+
+int mxl111sf_init_port_expander(struct mxl111sf_state *state)
+{
+       mxl_debug("()");
+
+       if (0x00 == state->port_expander_addr)
+               mxl111sf_probe_port_expander(state);
+
+       switch (state->gpio_port_expander) {
+       default:
+               mxl_printk(KERN_ERR,
+                          "gpio_port_expander undefined, assuming PCA9534");
+               /* fall-thru */
+       case mxl111sf_PCA9534:
+               return pca9534_init_port_expander(state);
+       case mxl111sf_gpio_hw:
+               return mxl111sf_hw_gpio_initialize(state);
+       }
+}
+
+/* ------------------------------------------------------------------------ */
+
+int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode)
+{
+/*     GPO:
+ *     3 - ATSC/MH#   | 1 = ATSC transport, 0 = MH transport      | default 0
+ *     4 - ATSC_RST## | 1 = ATSC enable, 0 = ATSC Reset           | default 0
+ *     5 - ATSC_EN    | 1 = ATSC power enable, 0 = ATSC power off | default 0
+ *     6 - MH_RESET#  | 1 = MH enable, 0 = MH Reset               | default 0
+ *     7 - MH_EN      | 1 = MH power enable, 0 = MH power off     | default 0
+ */
+       mxl_debug("(%d)", mode);
+
+       switch (mode) {
+       case MXL111SF_GPIO_MOD_MH:
+               mxl111sf_set_gpio(state, 4, 0);
+               mxl111sf_set_gpio(state, 5, 0);
+               msleep(50);
+               mxl111sf_set_gpio(state, 7, 1);
+               msleep(50);
+               mxl111sf_set_gpio(state, 6, 1);
+               msleep(50);
+
+               mxl111sf_set_gpio(state, 3, 0);
+               break;
+       case MXL111SF_GPIO_MOD_ATSC:
+               mxl111sf_set_gpio(state, 6, 0);
+               mxl111sf_set_gpio(state, 7, 0);
+               msleep(50);
+               mxl111sf_set_gpio(state, 5, 1);
+               msleep(50);
+               mxl111sf_set_gpio(state, 4, 1);
+               msleep(50);
+               mxl111sf_set_gpio(state, 3, 1);
+               break;
+       default: /* DVBT / STANDBY */
+               mxl111sf_init_port_expander(state);
+               break;
+       }
+       return 0;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h b/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h
new file mode 100644 (file)
index 0000000..0220f54
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  mxl111sf-gpio.h - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  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 _DVB_USB_MXL111SF_GPIO_H_
+#define _DVB_USB_MXL111SF_GPIO_H_
+
+#include "mxl111sf.h"
+
+int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val);
+int mxl111sf_init_port_expander(struct mxl111sf_state *state);
+
+#define MXL111SF_GPIO_MOD_DVBT 0
+#define MXL111SF_GPIO_MOD_MH   1
+#define MXL111SF_GPIO_MOD_ATSC 2
+int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode);
+
+enum mxl111sf_mux_config {
+       PIN_MUX_DEFAULT = 0,
+       PIN_MUX_TS_OUT_PARALLEL,
+       PIN_MUX_TS_OUT_SERIAL,
+       PIN_MUX_GPIO_MODE,
+       PIN_MUX_TS_SERIAL_IN_MODE_0,
+       PIN_MUX_TS_SERIAL_IN_MODE_1,
+       PIN_MUX_TS_SPI_IN_MODE_0,
+       PIN_MUX_TS_SPI_IN_MODE_1,
+       PIN_MUX_TS_PARALLEL_IN,
+       PIN_MUX_BT656_I2S_MODE,
+};
+
+int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state,
+                                 enum mxl111sf_mux_config pin_mux_config);
+
+#endif /* _DVB_USB_MXL111SF_GPIO_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c
new file mode 100644 (file)
index 0000000..2e8c288
--- /dev/null
@@ -0,0 +1,851 @@
+/*
+ *  mxl111sf-i2c.c - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  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 "mxl111sf-i2c.h"
+#include "mxl111sf.h"
+
+/* SW-I2C ----------------------------------------------------------------- */
+
+#define SW_I2C_ADDR            0x1a
+#define SW_I2C_EN              0x02
+#define SW_SCL_OUT             0x04
+#define SW_SDA_OUT             0x08
+#define SW_SDA_IN              0x04
+
+#define SW_I2C_BUSY_ADDR       0x2f
+#define SW_I2C_BUSY            0x02
+
+static int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state,
+                                        u8 byte)
+{
+       int i, ret;
+       u8 data = 0;
+
+       mxl_i2c("(0x%02x)", byte);
+
+       ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
+       if (mxl_fail(ret))
+               goto fail;
+
+       for (i = 0; i < 8; i++) {
+
+               data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0;
+
+               ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                        0x10 | SW_I2C_EN | data);
+               if (mxl_fail(ret))
+                       goto fail;
+
+               ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                        0x10 | SW_I2C_EN | data | SW_SCL_OUT);
+               if (mxl_fail(ret))
+                       goto fail;
+
+               ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                        0x10 | SW_I2C_EN | data);
+               if (mxl_fail(ret))
+                       goto fail;
+       }
+
+       /* last bit was 0 so we need to release SDA */
+       if (!(byte & 1)) {
+               ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                        0x10 | SW_I2C_EN | SW_SDA_OUT);
+               if (mxl_fail(ret))
+                       goto fail;
+       }
+
+       /* CLK high for ACK readback */
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
+       if (mxl_fail(ret))
+               goto fail;
+
+       /* drop the CLK after getting ACK, SDA will go high right away */
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN | SW_SDA_OUT);
+       if (mxl_fail(ret))
+               goto fail;
+
+       if (data & SW_SDA_IN)
+               ret = -EIO;
+fail:
+       return ret;
+}
+
+static int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state,
+                                        u8 *pbyte)
+{
+       int i, ret;
+       u8 byte = 0;
+       u8 data = 0;
+
+       mxl_i2c("()");
+
+       *pbyte = 0;
+
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN | SW_SDA_OUT);
+       if (mxl_fail(ret))
+               goto fail;
+
+       for (i = 0; i < 8; i++) {
+               ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                        0x10 | SW_I2C_EN |
+                                        SW_SCL_OUT | SW_SDA_OUT);
+               if (mxl_fail(ret))
+                       goto fail;
+
+               ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
+               if (mxl_fail(ret))
+                       goto fail;
+
+               if (data & SW_SDA_IN)
+                       byte |= (0x80 >> i);
+
+               ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                        0x10 | SW_I2C_EN | SW_SDA_OUT);
+               if (mxl_fail(ret))
+                       goto fail;
+       }
+       *pbyte = byte;
+fail:
+       return ret;
+}
+
+static int mxl111sf_i2c_start(struct mxl111sf_state *state)
+{
+       int ret;
+
+       mxl_i2c("()");
+
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN | SW_SCL_OUT);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN); /* start */
+       mxl_fail(ret);
+fail:
+       return ret;
+}
+
+static int mxl111sf_i2c_stop(struct mxl111sf_state *state)
+{
+       int ret;
+
+       mxl_i2c("()");
+
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN); /* stop */
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN | SW_SCL_OUT);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_SCL_OUT | SW_SDA_OUT);
+       mxl_fail(ret);
+fail:
+       return ret;
+}
+
+static int mxl111sf_i2c_ack(struct mxl111sf_state *state)
+{
+       int ret;
+       u8 b = 0;
+
+       mxl_i2c("()");
+
+       ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN);
+       if (mxl_fail(ret))
+               goto fail;
+
+       /* pull SDA low */
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN | SW_SCL_OUT);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN | SW_SDA_OUT);
+       mxl_fail(ret);
+fail:
+       return ret;
+}
+
+static int mxl111sf_i2c_nack(struct mxl111sf_state *state)
+{
+       int ret;
+
+       mxl_i2c("()");
+
+       /* SDA high to signal last byte read from slave */
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+                                0x10 | SW_I2C_EN | SW_SDA_OUT);
+       mxl_fail(ret);
+fail:
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state,
+                                   struct i2c_msg *msg)
+{
+       int i, ret;
+
+       mxl_i2c("()");
+
+       if (msg->flags & I2C_M_RD) {
+
+               ret = mxl111sf_i2c_start(state);
+               if (mxl_fail(ret))
+                       goto fail;
+
+               ret = mxl111sf_i2c_bitbang_sendbyte(state,
+                                                   (msg->addr << 1) | 0x01);
+               if (mxl_fail(ret)) {
+                       mxl111sf_i2c_stop(state);
+                       goto fail;
+               }
+
+               for (i = 0; i < msg->len; i++) {
+                       ret = mxl111sf_i2c_bitbang_recvbyte(state,
+                                                           &msg->buf[i]);
+                       if (mxl_fail(ret)) {
+                               mxl111sf_i2c_stop(state);
+                               goto fail;
+                       }
+
+                       if (i < msg->len - 1)
+                               mxl111sf_i2c_ack(state);
+               }
+
+               mxl111sf_i2c_nack(state);
+
+               ret = mxl111sf_i2c_stop(state);
+               if (mxl_fail(ret))
+                       goto fail;
+
+       } else {
+
+               ret = mxl111sf_i2c_start(state);
+               if (mxl_fail(ret))
+                       goto fail;
+
+               ret = mxl111sf_i2c_bitbang_sendbyte(state,
+                                                   (msg->addr << 1) & 0xfe);
+               if (mxl_fail(ret)) {
+                       mxl111sf_i2c_stop(state);
+                       goto fail;
+               }
+
+               for (i = 0; i < msg->len; i++) {
+                       ret = mxl111sf_i2c_bitbang_sendbyte(state,
+                                                           msg->buf[i]);
+                       if (mxl_fail(ret)) {
+                               mxl111sf_i2c_stop(state);
+                               goto fail;
+                       }
+               }
+
+               /* FIXME: we only want to do this on the last transaction */
+               mxl111sf_i2c_stop(state);
+       }
+fail:
+       return ret;
+}
+
+/* HW-I2C ----------------------------------------------------------------- */
+
+#define USB_WRITE_I2C_CMD     0x99
+#define USB_READ_I2C_CMD      0xdd
+#define USB_END_I2C_CMD       0xfe
+
+#define USB_WRITE_I2C_CMD_LEN   26
+#define USB_READ_I2C_CMD_LEN    24
+
+#define I2C_MUX_REG           0x30
+#define I2C_CONTROL_REG       0x00
+#define I2C_SLAVE_ADDR_REG    0x08
+#define I2C_DATA_REG          0x0c
+#define I2C_INT_STATUS_REG    0x10
+
+static int mxl111sf_i2c_send_data(struct mxl111sf_state *state,
+                                 u8 index, u8 *wdata)
+{
+       int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
+                                   &wdata[1], 25, NULL, 0);
+       mxl_fail(ret);
+
+       return ret;
+}
+
+static int mxl111sf_i2c_get_data(struct mxl111sf_state *state,
+                                u8 index, u8 *wdata, u8 *rdata)
+{
+       int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
+                                   &wdata[1], 25, rdata, 24);
+       mxl_fail(ret);
+
+       return ret;
+}
+
+static u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state)
+{
+       u8 status = 0;
+       u8 buf[26];
+
+       mxl_i2c_adv("()");
+
+       buf[0] = USB_READ_I2C_CMD;
+       buf[1] = 0x00;
+
+       buf[2] = I2C_INT_STATUS_REG;
+       buf[3] = 0x00;
+       buf[4] = 0x00;
+
+       buf[5] = USB_END_I2C_CMD;
+
+       mxl111sf_i2c_get_data(state, 0, buf, buf);
+
+       if (buf[1] & 0x04)
+               status = 1;
+
+       return status;
+}
+
+static u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state)
+{
+       u8 status = 0;
+       u8 buf[26];
+
+       mxl_i2c("()");
+
+       buf[0] = USB_READ_I2C_CMD;
+       buf[1] = 0x00;
+
+       buf[2] = I2C_MUX_REG;
+       buf[3] = 0x00;
+       buf[4] = 0x00;
+
+       buf[5] = I2C_INT_STATUS_REG;
+       buf[6] = 0x00;
+       buf[7] = 0x00;
+       buf[8] = USB_END_I2C_CMD;
+
+       mxl111sf_i2c_get_data(state, 0, buf, buf);
+
+       if (0x08 == (buf[1] & 0x08))
+               status = 1;
+
+       if ((buf[5] & 0x02) == 0x02)
+               mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */
+
+       return status;
+}
+
+static int mxl111sf_i2c_readagain(struct mxl111sf_state *state,
+                                 u8 count, u8 *rbuf)
+{
+       u8 i2c_w_data[26];
+       u8 i2c_r_data[24];
+       u8 i = 0;
+       u8 fifo_status = 0;
+       int ret;
+       int status = 0;
+
+       mxl_i2c("read %d bytes", count);
+
+       while ((fifo_status == 0) && (i++ < 5))
+               fifo_status = mxl111sf_i2c_check_fifo(state);
+
+       i2c_w_data[0] = 0xDD;
+       i2c_w_data[1] = 0x00;
+
+       for (i = 2; i < 26; i++)
+               i2c_w_data[i] = 0xFE;
+
+       for (i = 0; i < count; i++) {
+               i2c_w_data[2+(i*3)] = 0x0C;
+               i2c_w_data[3+(i*3)] = 0x00;
+               i2c_w_data[4+(i*3)] = 0x00;
+       }
+
+       ret = mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data);
+
+       /* Check for I2C NACK status */
+       if (mxl111sf_i2c_check_status(state) == 1) {
+               mxl_i2c("error!");
+       } else {
+               for (i = 0; i < count; i++) {
+                       rbuf[i] = i2c_r_data[(i*3)+1];
+                       mxl_i2c("%02x\t %02x",
+                               i2c_r_data[(i*3)+1],
+                               i2c_r_data[(i*3)+2]);
+               }
+
+               status = 1;
+       }
+
+       return status;
+}
+
+#define HWI2C400 1
+static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state,
+                                   struct i2c_msg *msg)
+{
+       int i, k, ret = 0;
+       u16 index = 0;
+       u8 buf[26];
+       u8 i2c_r_data[24];
+       u16 block_len;
+       u16 left_over_len;
+       u8 rd_status[8];
+       u8 ret_status;
+       u8 readbuff[26];
+
+       mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d",
+               msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0,
+               (!(msg->flags & I2C_M_RD)) ? msg->len : 0);
+
+       for (index = 0; index < 26; index++)
+               buf[index] = USB_END_I2C_CMD;
+
+       /* command to indicate data payload is destined for I2C interface */
+       buf[0] = USB_WRITE_I2C_CMD;
+       buf[1] = 0x00;
+
+       /* enable I2C interface */
+       buf[2] = I2C_MUX_REG;
+       buf[3] = 0x80;
+       buf[4] = 0x00;
+
+       /* enable I2C interface */
+       buf[5] = I2C_MUX_REG;
+       buf[6] = 0x81;
+       buf[7] = 0x00;
+
+       /* set Timeout register on I2C interface */
+       buf[8] = 0x14;
+       buf[9] = 0xff;
+       buf[10] = 0x00;
+#if 0
+       /* enable Interrupts on I2C interface */
+       buf[8] = 0x24;
+       buf[9] = 0xF7;
+       buf[10] = 0x00;
+#endif
+       buf[11] = 0x24;
+       buf[12] = 0xF7;
+       buf[13] = 0x00;
+
+       ret = mxl111sf_i2c_send_data(state, 0, buf);
+
+       /* write data on I2C bus */
+       if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) {
+               mxl_i2c("%d\t%02x", msg->len, msg->buf[0]);
+
+               /* control register on I2C interface to initialize I2C bus */
+               buf[2] = I2C_CONTROL_REG;
+               buf[3] = 0x5E;
+               buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+
+               /* I2C Slave device Address */
+               buf[5] = I2C_SLAVE_ADDR_REG;
+               buf[6] = (msg->addr);
+               buf[7] = 0x00;
+               buf[8] = USB_END_I2C_CMD;
+               ret = mxl111sf_i2c_send_data(state, 0, buf);
+
+               /* check for slave device status */
+               if (mxl111sf_i2c_check_status(state) == 1) {
+                       mxl_i2c("NACK writing slave address %02x",
+                               msg->addr);
+                       /* if NACK, stop I2C bus and exit */
+                       buf[2] = I2C_CONTROL_REG;
+                       buf[3] = 0x4E;
+                       buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+                       ret = -EIO;
+                       goto exit;
+               }
+
+               /* I2C interface can do I2C operations in block of 8 bytes of
+                  I2C data. calculation to figure out number of blocks of i2c
+                  data required to program */
+               block_len = (msg->len / 8);
+               left_over_len = (msg->len % 8);
+               index = 0;
+
+               mxl_i2c("block_len %d, left_over_len %d",
+                       block_len, left_over_len);
+
+               for (index = 0; index < block_len; index++) {
+                       for (i = 0; i < 8; i++) {
+                               /* write data on I2C interface */
+                               buf[2+(i*3)] = I2C_DATA_REG;
+                               buf[3+(i*3)] = msg->buf[(index*8)+i];
+                               buf[4+(i*3)] = 0x00;
+                       }
+
+                       ret = mxl111sf_i2c_send_data(state, 0, buf);
+
+                       /* check for I2C NACK status */
+                       if (mxl111sf_i2c_check_status(state) == 1) {
+                               mxl_i2c("NACK writing slave address %02x",
+                                       msg->addr);
+
+                               /* if NACK, stop I2C bus and exit */
+                               buf[2] = I2C_CONTROL_REG;
+                               buf[3] = 0x4E;
+                               buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+                               ret = -EIO;
+                               goto exit;
+                       }
+
+               }
+
+               if (left_over_len) {
+                       for (k = 0; k < 26; k++)
+                               buf[k] = USB_END_I2C_CMD;
+
+                       buf[0] = 0x99;
+                       buf[1] = 0x00;
+
+                       for (i = 0; i < left_over_len; i++) {
+                               buf[2+(i*3)] = I2C_DATA_REG;
+                               buf[3+(i*3)] = msg->buf[(index*8)+i];
+                               mxl_i2c("index = %d %d data %d",
+                                       index, i, msg->buf[(index*8)+i]);
+                               buf[4+(i*3)] = 0x00;
+                       }
+                       ret = mxl111sf_i2c_send_data(state, 0, buf);
+
+                       /* check for I2C NACK status */
+                       if (mxl111sf_i2c_check_status(state) == 1) {
+                               mxl_i2c("NACK writing slave address %02x",
+                                       msg->addr);
+
+                               /* if NACK, stop I2C bus and exit */
+                               buf[2] = I2C_CONTROL_REG;
+                               buf[3] = 0x4E;
+                               buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+                               ret = -EIO;
+                               goto exit;
+                       }
+
+               }
+
+               /* issue I2C STOP after write */
+               buf[2] = I2C_CONTROL_REG;
+               buf[3] = 0x4E;
+               buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+
+       }
+
+       /* read data from I2C bus */
+       if ((msg->flags & I2C_M_RD) && (msg->len > 0)) {
+               mxl_i2c("read buf len %d", msg->len);
+
+               /* command to indicate data payload is
+                  destined for I2C interface */
+               buf[2] = I2C_CONTROL_REG;
+               buf[3] = 0xDF;
+               buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+
+               /* I2C xfer length */
+               buf[5] = 0x14;
+               buf[6] = (msg->len & 0xFF);
+               buf[7] = 0;
+
+               /* I2C slave device Address */
+               buf[8] = I2C_SLAVE_ADDR_REG;
+               buf[9] = msg->addr;
+               buf[10] = 0x00;
+               buf[11] = USB_END_I2C_CMD;
+               ret = mxl111sf_i2c_send_data(state, 0, buf);
+
+               /* check for I2C NACK status */
+               if (mxl111sf_i2c_check_status(state) == 1) {
+                       mxl_i2c("NACK reading slave address %02x",
+                               msg->addr);
+
+                       /* if NACK, stop I2C bus and exit */
+                       buf[2] = I2C_CONTROL_REG;
+                       buf[3] = 0xC7;
+                       buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+                       ret = -EIO;
+                       goto exit;
+               }
+
+               /* I2C interface can do I2C operations in block of 8 bytes of
+                  I2C data. calculation to figure out number of blocks of
+                  i2c data required to program */
+               block_len = ((msg->len) / 8);
+               left_over_len = ((msg->len) % 8);
+               index = 0;
+
+               mxl_i2c("block_len %d, left_over_len %d",
+                       block_len, left_over_len);
+
+               /* command to read data from I2C interface */
+               buf[0] = USB_READ_I2C_CMD;
+               buf[1] = 0x00;
+
+               for (index = 0; index < block_len; index++) {
+                       /* setup I2C read request packet on I2C interface */
+                       for (i = 0; i < 8; i++) {
+                               buf[2+(i*3)] = I2C_DATA_REG;
+                               buf[3+(i*3)] = 0x00;
+                               buf[4+(i*3)] = 0x00;
+                       }
+
+                       ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data);
+
+                       /* check for I2C NACK status */
+                       if (mxl111sf_i2c_check_status(state) == 1) {
+                               mxl_i2c("NACK reading slave address %02x",
+                                       msg->addr);
+
+                               /* if NACK, stop I2C bus and exit */
+                               buf[2] = I2C_CONTROL_REG;
+                               buf[3] = 0xC7;
+                               buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+                               ret = -EIO;
+                               goto exit;
+                       }
+
+                       /* copy data from i2c data payload to read buffer */
+                       for (i = 0; i < 8; i++) {
+                               rd_status[i] = i2c_r_data[(i*3)+2];
+
+                               if (rd_status[i] == 0x04) {
+                                       if (i < 7) {
+                                               mxl_i2c("i2c fifo empty!"
+                                                       " @ %d", i);
+                                               msg->buf[(index*8)+i] =
+                                                       i2c_r_data[(i*3)+1];
+                                               /* read again */
+                                               ret_status =
+                                                       mxl111sf_i2c_readagain(
+                                                               state, 8-(i+1),
+                                                               readbuff);
+                                               if (ret_status == 1) {
+                                                       for (k = 0;
+                                                            k < 8-(i+1);
+                                                            k++) {
+
+                                       msg->buf[(index*8)+(k+i+1)] =
+                                               readbuff[k];
+                                       mxl_i2c("read data: %02x\t %02x",
+                                               msg->buf[(index*8)+(k+i)],
+                                               (index*8)+(k+i));
+                                       mxl_i2c("read data: %02x\t %02x",
+                                               msg->buf[(index*8)+(k+i+1)],
+                                               readbuff[k]);
+
+                                                       }
+                                                       goto stop_copy;
+                                               } else {
+                                                       mxl_i2c("readagain "
+                                                               "ERROR!");
+                                               }
+                                       } else {
+                                               msg->buf[(index*8)+i] =
+                                                       i2c_r_data[(i*3)+1];
+                                       }
+                               } else {
+                                       msg->buf[(index*8)+i] =
+                                               i2c_r_data[(i*3)+1];
+                               }
+                       }
+stop_copy:
+                       ;
+
+               }
+
+               if (left_over_len) {
+                       for (k = 0; k < 26; k++)
+                               buf[k] = USB_END_I2C_CMD;
+
+                       buf[0] = 0xDD;
+                       buf[1] = 0x00;
+
+                       for (i = 0; i < left_over_len; i++) {
+                               buf[2+(i*3)] = I2C_DATA_REG;
+                               buf[3+(i*3)] = 0x00;
+                               buf[4+(i*3)] = 0x00;
+                       }
+                       ret = mxl111sf_i2c_get_data(state, 0, buf,
+                                                   i2c_r_data);
+
+                       /* check for I2C NACK status */
+                       if (mxl111sf_i2c_check_status(state) == 1) {
+                               mxl_i2c("NACK reading slave address %02x",
+                                       msg->addr);
+
+                               /* if NACK, stop I2C bus and exit */
+                               buf[2] = I2C_CONTROL_REG;
+                               buf[3] = 0xC7;
+                               buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+                               ret = -EIO;
+                               goto exit;
+                       }
+
+                       for (i = 0; i < left_over_len; i++) {
+                               msg->buf[(block_len*8)+i] =
+                                       i2c_r_data[(i*3)+1];
+                               mxl_i2c("read data: %02x\t %02x",
+                                       i2c_r_data[(i*3)+1],
+                                       i2c_r_data[(i*3)+2]);
+                       }
+               }
+
+               /* indicate I2C interface to issue NACK
+                  after next I2C read op */
+               buf[0] = USB_WRITE_I2C_CMD;
+               buf[1] = 0x00;
+
+               /* control register */
+               buf[2] = I2C_CONTROL_REG;
+               buf[3] = 0x17;
+               buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+
+               buf[5] = USB_END_I2C_CMD;
+               ret = mxl111sf_i2c_send_data(state, 0, buf);
+
+               /* control register */
+               buf[2] = I2C_CONTROL_REG;
+               buf[3] = 0xC7;
+               buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+
+       }
+exit:
+       /* STOP and disable I2C MUX */
+       buf[0] = USB_WRITE_I2C_CMD;
+       buf[1] = 0x00;
+
+       /* de-initilize I2C BUS */
+       buf[5] = USB_END_I2C_CMD;
+       mxl111sf_i2c_send_data(state, 0, buf);
+
+       /* Control Register */
+       buf[2] = I2C_CONTROL_REG;
+       buf[3] = 0xDF;
+       buf[4] = 0x03;
+
+       /* disable I2C interface */
+       buf[5] = I2C_MUX_REG;
+       buf[6] = 0x00;
+       buf[7] = 0x00;
+
+       /* de-initilize I2C BUS */
+       buf[8] = USB_END_I2C_CMD;
+       mxl111sf_i2c_send_data(state, 0, buf);
+
+       /* disable I2C interface */
+       buf[2] = I2C_MUX_REG;
+       buf[3] = 0x81;
+       buf[4] = 0x00;
+
+       /* disable I2C interface */
+       buf[5] = I2C_MUX_REG;
+       buf[6] = 0x00;
+       buf[7] = 0x00;
+
+       /* disable I2C interface */
+       buf[8] = I2C_MUX_REG;
+       buf[9] = 0x00;
+       buf[10] = 0x00;
+
+       buf[11] = USB_END_I2C_CMD;
+       mxl111sf_i2c_send_data(state, 0, buf);
+
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
+                     struct i2c_msg msg[], int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct mxl111sf_state *state = d->priv;
+       int hwi2c = (state->chip_rev > MXL111SF_V6);
+       int i, ret;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       for (i = 0; i < num; i++) {
+               ret = (hwi2c) ?
+                       mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) :
+                       mxl111sf_i2c_sw_xfer_msg(state, &msg[i]);
+               if (mxl_fail(ret)) {
+                       mxl_debug_adv("failed with error %d on i2c "
+                                     "transaction %d of %d, %sing %d bytes "
+                                     "to/from 0x%02x", ret, i+1, num,
+                                     (msg[i].flags & I2C_M_RD) ?
+                                     "read" : "writ",
+                                     msg[i].len, msg[i].addr);
+
+                       break;
+               }
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+
+       return i == num ? num : -EREMOTEIO;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h
new file mode 100644 (file)
index 0000000..a57a45f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  mxl111sf-i2c.h - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  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 _DVB_USB_MXL111SF_I2C_H_
+#define _DVB_USB_MXL111SF_I2C_H_
+
+#include <linux/i2c.h>
+
+int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
+                     struct i2c_msg msg[], int num);
+
+#endif /* _DVB_USB_MXL111SF_I2C_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.c b/drivers/media/dvb/dvb-usb/mxl111sf-phy.c
new file mode 100644 (file)
index 0000000..91dc1fc
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ *  mxl111sf-phy.c - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  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 "mxl111sf-phy.h"
+#include "mxl111sf-reg.h"
+
+int mxl111sf_init_tuner_demod(struct mxl111sf_state *state)
+{
+       struct mxl111sf_reg_ctrl_info mxl_111_overwrite_default[] = {
+               {0x07, 0xff, 0x0c},
+               {0x58, 0xff, 0x9d},
+               {0x09, 0xff, 0x00},
+               {0x06, 0xff, 0x06},
+               {0xc8, 0xff, 0x40}, /* ED_LE_WIN_OLD = 0 */
+               {0x8d, 0x01, 0x01}, /* NEGATE_Q */
+               {0x32, 0xff, 0xac}, /* DIG_RFREFSELECT = 12 */
+               {0x42, 0xff, 0x43}, /* DIG_REG_AMP = 4 */
+               {0x74, 0xff, 0xc4}, /* SSPUR_FS_PRIO = 4 */
+               {0x71, 0xff, 0xe6}, /* SPUR_ROT_PRIO_VAL = 1 */
+               {0x83, 0xff, 0x64}, /* INF_FILT1_THD_SC = 100 */
+               {0x85, 0xff, 0x64}, /* INF_FILT2_THD_SC = 100 */
+               {0x88, 0xff, 0xf0}, /* INF_THD = 240 */
+               {0x6f, 0xf0, 0xb0}, /* DFE_DLY = 11 */
+               {0x00, 0xff, 0x01}, /* Change to page 1 */
+               {0x81, 0xff, 0x11}, /* DSM_FERR_BYPASS = 1 */
+               {0xf4, 0xff, 0x07}, /* DIG_FREQ_CORR = 1 */
+               {0xd4, 0x1f, 0x0f}, /* SPUR_TEST_NOISE_TH = 15 */
+               {0xd6, 0xff, 0x0c}, /* SPUR_TEST_NOISE_PAPR = 12 */
+               {0x00, 0xff, 0x00}, /* Change to page 0 */
+               {0,    0,    0}
+       };
+
+       mxl_debug("()");
+
+       return mxl111sf_ctrl_program_regs(state, mxl_111_overwrite_default);
+}
+
+int mxl1x1sf_soft_reset(struct mxl111sf_state *state)
+{
+       int ret;
+       mxl_debug("()");
+
+       ret = mxl111sf_write_reg(state, 0xff, 0x00); /* AIC */
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_write_reg(state, 0x02, 0x01); /* get out of reset */
+       mxl_fail(ret);
+fail:
+       return ret;
+}
+
+int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode)
+{
+       int ret;
+
+       mxl_debug("(%s)", MXL_SOC_MODE == mode ?
+               "MXL_SOC_MODE" : "MXL_TUNER_MODE");
+
+       /* set device mode */
+       ret = mxl111sf_write_reg(state, 0x03,
+                                MXL_SOC_MODE == mode ? 0x01 : 0x00);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_write_reg_mask(state,
+                                     0x7d, 0x40, MXL_SOC_MODE == mode ?
+                                     0x00 : /* enable impulse noise filter,
+                                               INF_BYP = 0 */
+                                     0x40); /* disable impulse noise filter,
+                                               INF_BYP = 1 */
+       if (mxl_fail(ret))
+               goto fail;
+
+       state->device_mode = mode;
+fail:
+       return ret;
+}
+
+/* power up tuner */
+int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff)
+{
+       mxl_debug("(%d)", onoff);
+
+       return mxl111sf_write_reg(state, 0x01, onoff ? 0x01 : 0x00);
+}
+
+int mxl111sf_disable_656_port(struct mxl111sf_state *state)
+{
+       mxl_debug("()");
+
+       return mxl111sf_write_reg_mask(state, 0x12, 0x04, 0x00);
+}
+
+int mxl111sf_enable_usb_output(struct mxl111sf_state *state)
+{
+       mxl_debug("()");
+
+       return mxl111sf_write_reg_mask(state, 0x17, 0x40, 0x00);
+}
+
+/* initialize TSIF as input port of MxL1X1SF for MPEG2 data transfer */
+int mxl111sf_config_mpeg_in(struct mxl111sf_state *state,
+                           unsigned int parallel_serial,
+                           unsigned int msb_lsb_1st,
+                           unsigned int clock_phase,
+                           unsigned int mpeg_valid_pol,
+                           unsigned int mpeg_sync_pol)
+{
+       int ret;
+       u8 mode, tmp;
+
+       mxl_debug("(%u,%u,%u,%u,%u)", parallel_serial, msb_lsb_1st,
+                 clock_phase, mpeg_valid_pol, mpeg_sync_pol);
+
+       /* Enable PIN MUX */
+       ret = mxl111sf_write_reg(state, V6_PIN_MUX_MODE_REG, V6_ENABLE_PIN_MUX);
+       mxl_fail(ret);
+
+       /* Configure MPEG Clock phase */
+       mxl111sf_read_reg(state, V6_MPEG_IN_CLK_INV_REG, &mode);
+
+       if (clock_phase == TSIF_NORMAL)
+               mode &= ~V6_INVERTED_CLK_PHASE;
+       else
+               mode |= V6_INVERTED_CLK_PHASE;
+
+       ret = mxl111sf_write_reg(state, V6_MPEG_IN_CLK_INV_REG, mode);
+       mxl_fail(ret);
+
+       /* Configure data input mode, MPEG Valid polarity, MPEG Sync polarity
+        * Get current configuration */
+       ret = mxl111sf_read_reg(state, V6_MPEG_IN_CTRL_REG, &mode);
+       mxl_fail(ret);
+
+       /* Data Input mode */
+       if (parallel_serial == TSIF_INPUT_PARALLEL) {
+               /* Disable serial mode */
+               mode &= ~V6_MPEG_IN_DATA_SERIAL;
+
+               /* Enable Parallel mode */
+               mode |= V6_MPEG_IN_DATA_PARALLEL;
+       } else {
+               /* Disable Parallel mode */
+               mode &= ~V6_MPEG_IN_DATA_PARALLEL;
+
+               /* Enable Serial Mode */
+               mode |= V6_MPEG_IN_DATA_SERIAL;
+
+               /* If serial interface is chosen, configure
+                  MSB or LSB order in transmission */
+               ret = mxl111sf_read_reg(state,
+                                       V6_MPEG_INOUT_BIT_ORDER_CTRL_REG,
+                                       &tmp);
+               mxl_fail(ret);
+
+               if (msb_lsb_1st == MPEG_SER_MSB_FIRST_ENABLED)
+                       tmp |= V6_MPEG_SER_MSB_FIRST;
+               else
+                       tmp &= ~V6_MPEG_SER_MSB_FIRST;
+
+               ret = mxl111sf_write_reg(state,
+                                        V6_MPEG_INOUT_BIT_ORDER_CTRL_REG,
+                                        tmp);
+               mxl_fail(ret);
+       }
+
+       /* MPEG Sync polarity */
+       if (mpeg_sync_pol == TSIF_NORMAL)
+               mode &= ~V6_INVERTED_MPEG_SYNC;
+       else
+               mode |= V6_INVERTED_MPEG_SYNC;
+
+       /* MPEG Valid polarity */
+       if (mpeg_valid_pol == 0)
+               mode &= ~V6_INVERTED_MPEG_VALID;
+       else
+               mode |= V6_INVERTED_MPEG_VALID;
+
+       ret = mxl111sf_write_reg(state, V6_MPEG_IN_CTRL_REG, mode);
+       mxl_fail(ret);
+
+       return ret;
+}
+
+int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size)
+{
+       static struct mxl111sf_reg_ctrl_info init_i2s[] = {
+               {0x1b, 0xff, 0x1e}, /* pin mux mode, Choose 656/I2S input */
+               {0x15, 0x60, 0x60}, /* Enable I2S */
+               {0x17, 0xe0, 0x20}, /* Input, MPEG MODE USB,
+                                      Inverted 656 Clock, I2S_SOFT_RESET,
+                                      0 : Normal operation, 1 : Reset State */
+#if 0
+               {0x12, 0x01, 0x00}, /* AUDIO_IRQ_CLR (Overflow Indicator) */
+#endif
+               {0x00, 0xff, 0x02}, /* Change to Control Page */
+               {0x26, 0x0d, 0x0d}, /* I2S_MODE & BT656_SRC_SEL for FPGA only */
+               {0x00, 0xff, 0x00},
+               {0,    0,    0}
+       };
+       int ret;
+
+       mxl_debug("(0x%02x)", sample_size);
+
+       ret = mxl111sf_ctrl_program_regs(state, init_i2s);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_write_reg(state, V6_I2S_NUM_SAMPLES_REG, sample_size);
+       mxl_fail(ret);
+fail:
+       return ret;
+}
+
+int mxl111sf_disable_i2s_port(struct mxl111sf_state *state)
+{
+       static struct mxl111sf_reg_ctrl_info disable_i2s[] = {
+               {0x15, 0x40, 0x00},
+               {0,    0,    0}
+       };
+
+       mxl_debug("()");
+
+       return mxl111sf_ctrl_program_regs(state, disable_i2s);
+}
+
+int mxl111sf_config_i2s(struct mxl111sf_state *state,
+                       u8 msb_start_pos, u8 data_width)
+{
+       int ret;
+       u8 tmp;
+
+       mxl_debug("(0x%02x, 0x%02x)", msb_start_pos, data_width);
+
+       ret = mxl111sf_read_reg(state, V6_I2S_STREAM_START_BIT_REG, &tmp);
+       if (mxl_fail(ret))
+               goto fail;
+
+       tmp &= 0xe0;
+       tmp |= msb_start_pos;
+       ret = mxl111sf_write_reg(state, V6_I2S_STREAM_START_BIT_REG, tmp);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_read_reg(state, V6_I2S_STREAM_END_BIT_REG, &tmp);
+       if (mxl_fail(ret))
+               goto fail;
+
+       tmp &= 0xe0;
+       tmp |= data_width;
+       ret = mxl111sf_write_reg(state, V6_I2S_STREAM_END_BIT_REG, tmp);
+       mxl_fail(ret);
+fail:
+       return ret;
+}
+
+int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff)
+{
+       u8 val;
+       int ret;
+
+       mxl_debug("(%d)", onoff);
+
+       ret = mxl111sf_write_reg(state, 0x00, 0x02);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_read_reg(state, V8_SPI_MODE_REG, &val);
+       if (mxl_fail(ret))
+               goto fail;
+
+       if (onoff)
+               val |= 0x04;
+       else
+               val &= ~0x04;
+
+       ret = mxl111sf_write_reg(state, V8_SPI_MODE_REG, val);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_write_reg(state, 0x00, 0x00);
+       if (mxl_fail(ret))
+               goto fail;
+fail:
+       return ret;
+}
+
+int mxl111sf_idac_config(struct mxl111sf_state *state,
+                        u8 control_mode, u8 current_setting,
+                        u8 current_value, u8 hysteresis_value)
+{
+       int ret;
+       u8 val;
+       /* current value will be set for both automatic & manual IDAC control */
+       val = current_value;
+
+       if (control_mode == IDAC_MANUAL_CONTROL) {
+               /* enable manual control of IDAC */
+               val |= IDAC_MANUAL_CONTROL_BIT_MASK;
+
+               if (current_setting == IDAC_CURRENT_SINKING_ENABLE)
+                       /* enable current sinking in manual mode */
+                       val |= IDAC_CURRENT_SINKING_BIT_MASK;
+               else
+                       /* disable current sinking in manual mode */
+                       val &= ~IDAC_CURRENT_SINKING_BIT_MASK;
+       } else {
+               /* disable manual control of IDAC */
+               val &= ~IDAC_MANUAL_CONTROL_BIT_MASK;
+
+               /* set hysteresis value  reg: 0x0B<5:0> */
+               ret = mxl111sf_write_reg(state, V6_IDAC_HYSTERESIS_REG,
+                                        (hysteresis_value & 0x3F));
+       }
+
+       ret = mxl111sf_write_reg(state, V6_IDAC_SETTINGS_REG, val);
+
+       return val;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.h b/drivers/media/dvb/dvb-usb/mxl111sf-phy.h
new file mode 100644 (file)
index 0000000..f075607
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  mxl111sf-phy.h - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  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 _DVB_USB_MXL111SF_PHY_H_
+#define _DVB_USB_MXL111SF_PHY_H_
+
+#include "mxl111sf.h"
+
+int mxl1x1sf_soft_reset(struct mxl111sf_state *state);
+int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode);
+int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff);
+int mxl111sf_disable_656_port(struct mxl111sf_state *state);
+int mxl111sf_init_tuner_demod(struct mxl111sf_state *state);
+int mxl111sf_enable_usb_output(struct mxl111sf_state *state);
+int mxl111sf_config_mpeg_in(struct mxl111sf_state *state,
+                           unsigned int parallel_serial,
+                           unsigned int msb_lsb_1st,
+                           unsigned int clock_phase,
+                           unsigned int mpeg_valid_pol,
+                           unsigned int mpeg_sync_pol);
+int mxl111sf_config_i2s(struct mxl111sf_state *state,
+                       u8 msb_start_pos, u8 data_width);
+int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size);
+int mxl111sf_disable_i2s_port(struct mxl111sf_state *state);
+int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff);
+int mxl111sf_idac_config(struct mxl111sf_state *state,
+                        u8 control_mode, u8 current_setting,
+                        u8 current_value, u8 hysteresis_value);
+
+#endif /* _DVB_USB_MXL111SF_PHY_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-reg.h b/drivers/media/dvb/dvb-usb/mxl111sf-reg.h
new file mode 100644 (file)
index 0000000..17831b0
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ *  mxl111sf-reg.h - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  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 _DVB_USB_MXL111SF_REG_H_
+#define _DVB_USB_MXL111SF_REG_H_
+
+#define CHIP_ID_REG                  0xFC
+#define TOP_CHIP_REV_ID_REG          0xFA
+
+#define V6_SNR_RB_LSB_REG            0x27
+#define V6_SNR_RB_MSB_REG            0x28
+
+#define V6_N_ACCUMULATE_REG          0x11
+#define V6_RS_AVG_ERRORS_LSB_REG     0x2C
+#define V6_RS_AVG_ERRORS_MSB_REG     0x2D
+
+#define V6_IRQ_STATUS_REG            0x24
+#define  IRQ_MASK_FEC_LOCK       0x10
+
+#define V6_SYNC_LOCK_REG             0x28
+#define SYNC_LOCK_MASK           0x10
+
+#define V6_RS_LOCK_DET_REG           0x28
+#define  RS_LOCK_DET_MASK        0x08
+
+#define V6_INITACQ_NODETECT_REG    0x20
+#define V6_FORCE_NFFT_CPSIZE_REG   0x20
+
+#define V6_CODE_RATE_TPS_REG       0x29
+#define V6_CODE_RATE_TPS_MASK      0x07
+
+
+#define V6_CP_LOCK_DET_REG        0x28
+#define V6_CP_LOCK_DET_MASK       0x04
+
+#define V6_TPS_HIERACHY_REG        0x29
+#define V6_TPS_HIERARCHY_INFO_MASK  0x40
+
+#define V6_MODORDER_TPS_REG        0x2A
+#define V6_PARAM_CONSTELLATION_MASK   0x30
+
+#define V6_MODE_TPS_REG            0x2A
+#define V6_PARAM_FFT_MODE_MASK        0x0C
+
+
+#define V6_CP_TPS_REG             0x29
+#define V6_PARAM_GI_MASK              0x30
+
+#define V6_TPS_LOCK_REG           0x2A
+#define V6_PARAM_TPS_LOCK_MASK        0x40
+
+#define V6_FEC_PER_COUNT_REG      0x2E
+#define V6_FEC_PER_SCALE_REG      0x2B
+#define V6_FEC_PER_SCALE_MASK        0x03
+#define V6_FEC_PER_CLR_REG        0x20
+#define V6_FEC_PER_CLR_MASK          0x01
+
+#define V6_PIN_MUX_MODE_REG       0x1B
+#define V6_ENABLE_PIN_MUX            0x1E
+
+#define V6_I2S_NUM_SAMPLES_REG    0x16
+
+#define V6_MPEG_IN_CLK_INV_REG    0x17
+#define V6_MPEG_IN_CTRL_REG       0x18
+
+#define V6_INVERTED_CLK_PHASE       0x20
+#define V6_MPEG_IN_DATA_PARALLEL    0x01
+#define V6_MPEG_IN_DATA_SERIAL      0x02
+
+#define V6_INVERTED_MPEG_SYNC       0x04
+#define V6_INVERTED_MPEG_VALID      0x08
+
+#define TSIF_INPUT_PARALLEL         0
+#define TSIF_INPUT_SERIAL           1
+#define TSIF_NORMAL                 0
+
+#define V6_MPEG_INOUT_BIT_ORDER_CTRL_REG  0x19
+#define V6_MPEG_SER_MSB_FIRST                0x80
+#define MPEG_SER_MSB_FIRST_ENABLED        0x01
+
+#define V6_656_I2S_BUFF_STATUS_REG   0x2F
+#define V6_656_OVERFLOW_MASK_BIT         0x08
+#define V6_I2S_OVERFLOW_MASK_BIT         0x01
+
+#define V6_I2S_STREAM_START_BIT_REG  0x14
+#define V6_I2S_STREAM_END_BIT_REG    0x15
+#define I2S_RIGHT_JUSTIFIED     0
+#define I2S_LEFT_JUSTIFIED      1
+#define I2S_DATA_FORMAT         2
+
+#define V6_TUNER_LOOP_THRU_CONTROL_REG  0x09
+#define V6_ENABLE_LOOP_THRU               0x01
+
+#define TOTAL_NUM_IF_OUTPUT_FREQ       16
+
+#define TUNER_NORMAL_IF_SPECTRUM       0x0
+#define TUNER_INVERT_IF_SPECTRUM       0x10
+
+#define V6_TUNER_IF_SEL_REG              0x06
+#define V6_TUNER_IF_FCW_REG              0x3C
+#define V6_TUNER_IF_FCW_BYP_REG          0x3D
+#define V6_RF_LOCK_STATUS_REG            0x23
+
+#define NUM_DIG_TV_CHANNEL     1000
+
+#define V6_DIG_CLK_FREQ_SEL_REG  0x07
+#define V6_REF_SYNTH_INT_REG     0x5C
+#define V6_REF_SYNTH_REMAIN_REG  0x58
+#define V6_DIG_RFREFSELECT_REG   0x32
+#define V6_XTAL_CLK_OUT_GAIN_REG   0x31
+#define V6_TUNER_LOOP_THRU_CTRL_REG      0x09
+#define V6_DIG_XTAL_ENABLE_REG  0x06
+#define V6_DIG_XTAL_BIAS_REG  0x66
+#define V6_XTAL_CAP_REG    0x08
+
+#define V6_GPO_CTRL_REG     0x18
+#define MXL_GPO_0           0x00
+#define MXL_GPO_1           0x01
+#define V6_GPO_0_MASK       0x10
+#define V6_GPO_1_MASK       0x20
+
+#define V6_111SF_GPO_CTRL_REG     0x19
+#define MXL_111SF_GPO_1               0x00
+#define MXL_111SF_GPO_2               0x01
+#define MXL_111SF_GPO_3               0x02
+#define MXL_111SF_GPO_4               0x03
+#define MXL_111SF_GPO_5               0x04
+#define MXL_111SF_GPO_6               0x05
+#define MXL_111SF_GPO_7               0x06
+
+#define MXL_111SF_GPO_0_MASK          0x01
+#define MXL_111SF_GPO_1_MASK          0x02
+#define MXL_111SF_GPO_2_MASK          0x04
+#define MXL_111SF_GPO_3_MASK          0x08
+#define MXL_111SF_GPO_4_MASK          0x10
+#define MXL_111SF_GPO_5_MASK          0x20
+#define MXL_111SF_GPO_6_MASK          0x40
+
+#define V6_ATSC_CONFIG_REG  0x0A
+
+#define MXL_MODE_REG    0x03
+#define START_TUNE_REG  0x1C
+
+#define V6_IDAC_HYSTERESIS_REG    0x0B
+#define V6_IDAC_SETTINGS_REG      0x0C
+#define IDAC_MANUAL_CONTROL             1
+#define IDAC_CURRENT_SINKING_ENABLE     1
+#define IDAC_MANUAL_CONTROL_BIT_MASK      0x80
+#define IDAC_CURRENT_SINKING_BIT_MASK     0x40
+
+#define V8_SPI_MODE_REG  0xE9
+
+#define V6_DIG_RF_PWR_LSB_REG  0x46
+#define V6_DIG_RF_PWR_MSB_REG  0x47
+
+#endif /* _DVB_USB_MXL111SF_REG_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
new file mode 100644 (file)
index 0000000..a634105
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+ *  mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  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 "mxl111sf-tuner.h"
+#include "mxl111sf-phy.h"
+#include "mxl111sf-reg.h"
+
+/* debug */
+static int mxl111sf_tuner_debug;
+module_param_named(debug, mxl111sf_tuner_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+#define mxl_dbg(fmt, arg...) \
+       if (mxl111sf_tuner_debug) \
+               mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+/* ------------------------------------------------------------------------ */
+
+struct mxl111sf_tuner_state {
+       struct mxl111sf_state *mxl_state;
+
+       struct mxl111sf_tuner_config *cfg;
+
+       u32 frequency;
+       u32 bandwidth;
+};
+
+static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state,
+                                  u8 addr, u8 *data)
+{
+       return (state->cfg->read_reg) ?
+               state->cfg->read_reg(state->mxl_state, addr, data) :
+               -EINVAL;
+}
+
+static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state,
+                                   u8 addr, u8 data)
+{
+       return (state->cfg->write_reg) ?
+               state->cfg->write_reg(state->mxl_state, addr, data) :
+               -EINVAL;
+}
+
+static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state,
+                              struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
+{
+       return (state->cfg->program_regs) ?
+               state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
+               -EINVAL;
+}
+
+static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state,
+                                         int onoff)
+{
+       return (state->cfg->top_master_ctrl) ?
+               state->cfg->top_master_ctrl(state->mxl_state, onoff) :
+               -EINVAL;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = {
+       {0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3,
+                              DIG_MODEINDEX, _A, _CSF, */
+       {0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */
+       {0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */
+       {0,    0,    0}
+};
+
+/* ------------------------------------------------------------------------ */
+
+static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq,
+                                                                 u8 bw)
+{
+       u8 filt_bw;
+
+       /* set channel bandwidth */
+       switch (bw) {
+       case 0: /* ATSC */
+               filt_bw = 25;
+               break;
+       case 1: /* QAM */
+               filt_bw = 69;
+               break;
+       case 6:
+               filt_bw = 21;
+               break;
+       case 7:
+               filt_bw = 42;
+               break;
+       case 8:
+               filt_bw = 63;
+               break;
+       default:
+               err("%s: invalid bandwidth setting!", __func__);
+               return NULL;
+       }
+
+       /* calculate RF channel */
+       freq /= 1000000;
+
+       freq *= 64;
+#if 0
+       /* do round */
+       freq += 0.5;
+#endif
+       /* set bandwidth */
+       mxl_phy_tune_rf[0].data = filt_bw;
+
+       /* set RF */
+       mxl_phy_tune_rf[1].data = (freq & 0xff);
+       mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff;
+
+       /* start tune */
+       return mxl_phy_tune_rf;
+}
+
+static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state)
+{
+       int ret;
+       u8 ctrl;
+#if 0
+       u16 iffcw;
+       u32 if_freq;
+#endif
+       mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)",
+               state->cfg->invert_spectrum, state->cfg->if_freq);
+
+       /* set IF polarity */
+       ctrl = state->cfg->invert_spectrum;
+
+       ctrl |= state->cfg->if_freq;
+
+       ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl);
+       if (mxl_fail(ret))
+               goto fail;
+
+#if 0
+       if_freq /= 1000000;
+
+       /* do round */
+       if_freq += 0.5;
+
+       if (MXL_IF_LO == state->cfg->if_freq) {
+               ctrl = 0x08;
+               iffcw = (u16)(if_freq / (108 * 4096));
+       } else if (MXL_IF_HI == state->cfg->if_freq) {
+               ctrl = 0x08;
+               iffcw = (u16)(if_freq / (216 * 4096));
+       } else {
+               ctrl = 0;
+               iffcw = 0;
+       }
+
+       ctrl |= (iffcw >> 8);
+#endif
+       ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ctrl &= 0xf0;
+       ctrl |= 0x90;
+
+       ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl);
+       if (mxl_fail(ret))
+               goto fail;
+
+#if 0
+       ctrl = iffcw & 0x00ff;
+#endif
+       ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl);
+       mxl_fail(ret);
+fail:
+       return ret;
+}
+
+static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw)
+{
+       struct mxl111sf_tuner_state *state = fe->tuner_priv;
+       static struct mxl111sf_reg_ctrl_info *reg_ctrl_array;
+       int ret;
+       u8 mxl_mode;
+
+       mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw);
+
+       /* stop tune */
+       ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0);
+       if (mxl_fail(ret))
+               goto fail;
+
+       /* check device mode */
+       ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode);
+       if (mxl_fail(ret))
+               goto fail;
+
+       /* Fill out registers for channel tune */
+       reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw);
+       if (!reg_ctrl_array)
+               return -EINVAL;
+
+       ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array);
+       if (mxl_fail(ret))
+               goto fail;
+
+       if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) {
+               /* IF tuner mode only */
+               mxl1x1sf_tuner_top_master_ctrl(state, 0);
+               mxl1x1sf_tuner_top_master_ctrl(state, 1);
+               mxl1x1sf_tuner_set_if_output_freq(state);
+       }
+
+       ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1);
+       if (mxl_fail(ret))
+               goto fail;
+
+       if (state->cfg->ant_hunt)
+               state->cfg->ant_hunt(fe);
+fail:
+       return ret;
+}
+
+static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state,
+                                         int *rf_synth_lock,
+                                         int *ref_synth_lock)
+{
+       int ret;
+       u8 data;
+
+       *rf_synth_lock = 0;
+       *ref_synth_lock = 0;
+
+       ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data);
+       if (mxl_fail(ret))
+               goto fail;
+
+       *ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0;
+       *rf_synth_lock  = ((data & 0x0c) == 0x0c) ? 1 : 0;
+fail:
+       return ret;
+}
+
+#if 0
+static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state,
+                                        int onoff)
+{
+       return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG,
+                                       onoff ? 1 : 0);
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_tuner_set_params(struct dvb_frontend *fe,
+                                    struct dvb_frontend_parameters *params)
+{
+       struct mxl111sf_tuner_state *state = fe->tuner_priv;
+       int ret;
+       u8 bw;
+
+       mxl_dbg("()");
+
+       if (fe->ops.info.type == FE_ATSC) {
+               switch (params->u.vsb.modulation) {
+               case VSB_8:
+               case VSB_16:
+                       bw = 0; /* ATSC */
+                       break;
+               case QAM_64:
+               case QAM_256:
+                       bw = 1; /* US CABLE */
+                       break;
+               default:
+                       err("%s: modulation not set!", __func__);
+                       return -EINVAL;
+               }
+       } else if (fe->ops.info.type == FE_OFDM) {
+               switch (params->u.ofdm.bandwidth) {
+               case BANDWIDTH_6_MHZ:
+                       bw = 6;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       bw = 7;
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       bw = 8;
+                       break;
+               default:
+                       err("%s: bandwidth not set!", __func__);
+                       return -EINVAL;
+               }
+       } else {
+               err("%s: modulation type not supported!", __func__);
+               return -EINVAL;
+       }
+       ret = mxl1x1sf_tune_rf(fe, params->frequency, bw);
+       if (mxl_fail(ret))
+               goto fail;
+
+       state->frequency = params->frequency;
+       state->bandwidth = (fe->ops.info.type == FE_OFDM) ?
+               params->u.ofdm.bandwidth : 0;
+fail:
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#if 0
+static int mxl111sf_tuner_init(struct dvb_frontend *fe)
+{
+       struct mxl111sf_tuner_state *state = fe->tuner_priv;
+       int ret;
+
+       /* wake from standby handled by usb driver */
+
+       return ret;
+}
+
+static int mxl111sf_tuner_sleep(struct dvb_frontend *fe)
+{
+       struct mxl111sf_tuner_state *state = fe->tuner_priv;
+       int ret;
+
+       /* enter standby mode handled by usb driver */
+
+       return ret;
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status)
+{
+       struct mxl111sf_tuner_state *state = fe->tuner_priv;
+       int rf_locked, ref_locked, ret;
+
+       *status = 0;
+
+       ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked);
+       if (mxl_fail(ret))
+               goto fail;
+       mxl_info("%s%s", rf_locked ? "rf locked " : "",
+                ref_locked ? "ref locked" : "");
+
+       if ((rf_locked) || (ref_locked))
+               *status |= TUNER_STATUS_LOCKED;
+fail:
+       return ret;
+}
+
+static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct mxl111sf_tuner_state *state = fe->tuner_priv;
+       u8 val1, val2;
+       int ret;
+
+       *strength = 0;
+
+       ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2);
+       if (mxl_fail(ret))
+               goto fail;
+
+       *strength = val1 | ((val2 & 0x07) << 8);
+fail:
+       ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00);
+       mxl_fail(ret);
+
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct mxl111sf_tuner_state *state = fe->tuner_priv;
+       *frequency = state->frequency;
+       return 0;
+}
+
+static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       struct mxl111sf_tuner_state *state = fe->tuner_priv;
+       *bandwidth = state->bandwidth;
+       return 0;
+}
+
+static int mxl111sf_tuner_release(struct dvb_frontend *fe)
+{
+       struct mxl111sf_tuner_state *state = fe->tuner_priv;
+       mxl_dbg("()");
+       kfree(state);
+       fe->tuner_priv = NULL;
+       return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = {
+       .info = {
+               .name = "MaxLinear MxL111SF",
+#if 0
+               .frequency_min  = ,
+               .frequency_max  = ,
+               .frequency_step = ,
+#endif
+       },
+#if 0
+       .init              = mxl111sf_tuner_init,
+       .sleep             = mxl111sf_tuner_sleep,
+#endif
+       .set_params        = mxl111sf_tuner_set_params,
+       .get_status        = mxl111sf_tuner_get_status,
+       .get_rf_strength   = mxl111sf_get_rf_strength,
+       .get_frequency     = mxl111sf_tuner_get_frequency,
+       .get_bandwidth     = mxl111sf_tuner_get_bandwidth,
+       .release           = mxl111sf_tuner_release,
+};
+
+struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
+                                          struct mxl111sf_state *mxl_state,
+                                          struct mxl111sf_tuner_config *cfg)
+{
+       struct mxl111sf_tuner_state *state = NULL;
+
+       mxl_dbg("()");
+
+       state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL);
+       if (state == NULL)
+               return NULL;
+
+       state->mxl_state = mxl_state;
+       state->cfg = cfg;
+
+       memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops,
+              sizeof(struct dvb_tuner_ops));
+
+       fe->tuner_priv = state;
+       return fe;
+}
+EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach);
+
+MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h
new file mode 100644 (file)
index 0000000..ff33396
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  mxl111sf-tuner.h - driver for the MaxLinear MXL111SF CMOS tuner
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  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 __MXL111SF_TUNER_H__
+#define __MXL111SF_TUNER_H__
+
+#include "dvb_frontend.h"
+
+#include "mxl111sf.h"
+
+enum mxl_if_freq {
+#if 0
+       MXL_IF_LO    = 0x00, /* other IF < 9MHz */
+#endif
+       MXL_IF_4_0   = 0x01, /* 4.0   MHz */
+       MXL_IF_4_5   = 0x02, /* 4.5   MHz */
+       MXL_IF_4_57  = 0x03, /* 4.57  MHz */
+       MXL_IF_5_0   = 0x04, /* 5.0   MHz */
+       MXL_IF_5_38  = 0x05, /* 5.38  MHz */
+       MXL_IF_6_0   = 0x06, /* 6.0   MHz */
+       MXL_IF_6_28  = 0x07, /* 6.28  MHz */
+       MXL_IF_7_2   = 0x08, /* 7.2   MHz */
+       MXL_IF_35_25 = 0x09, /* 35.25 MHz */
+       MXL_IF_36    = 0x0a, /* 36    MHz */
+       MXL_IF_36_15 = 0x0b, /* 36.15 MHz */
+       MXL_IF_44    = 0x0c, /* 44    MHz */
+#if 0
+       MXL_IF_HI    = 0x0f, /* other IF > 35 MHz and < 45 MHz */
+#endif
+};
+
+struct mxl111sf_tuner_config {
+       enum mxl_if_freq if_freq;
+       unsigned int invert_spectrum:1;
+
+       int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data);
+       int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data);
+       int (*program_regs)(struct mxl111sf_state *state,
+                           struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
+       int (*top_master_ctrl)(struct mxl111sf_state *state, int onoff);
+       int (*ant_hunt)(struct dvb_frontend *fe);
+};
+
+/* ------------------------------------------------------------------------ */
+
+#if defined(CONFIG_DVB_USB_MXL111SF) || \
+       (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE))
+extern
+struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
+                                          struct mxl111sf_state *mxl_state,
+                                          struct mxl111sf_tuner_config *cfg);
+#else
+static inline
+struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
+                                          struct mxl111sf_state *mxl_state
+                                          struct mxl111sf_tuner_config *cfg)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif /* __MXL111SF_TUNER_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c
new file mode 100644 (file)
index 0000000..546ba59
--- /dev/null
@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com)
+ *
+ *   This program is free software; you can redistribute it and/or modify it
+ *   under the terms of the GNU General Public License as published by the Free
+ *   Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/i2c.h>
+
+#include "mxl111sf.h"
+#include "mxl111sf-reg.h"
+#include "mxl111sf-phy.h"
+#include "mxl111sf-i2c.h"
+#include "mxl111sf-gpio.h"
+
+#include "mxl111sf-tuner.h"
+
+#include "lgdt3305.h"
+
+int dvb_usb_mxl111sf_debug;
+module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level "
+                "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able)).");
+
+int dvb_usb_mxl111sf_isoc;
+module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
+MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
+
+#define ANT_PATH_AUTO 0
+#define ANT_PATH_EXTERNAL 1
+#define ANT_PATH_INTERNAL 2
+
+int dvb_usb_mxl111sf_rfswitch =
+#if 0
+               ANT_PATH_AUTO;
+#else
+               ANT_PATH_EXTERNAL;
+#endif
+
+module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644);
+MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define deb_info(args...)   dprintk(dvb_usb_mxl111sf_debug, 0x13, args)
+#define deb_reg(args...)    dprintk(dvb_usb_mxl111sf_debug, 0x08, args)
+#define deb_adv(args...)    dprintk(dvb_usb_mxl111sf_debug, MXL_ADV_DBG, args)
+
+int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
+                     u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+       int wo = (rbuf == NULL || rlen == 0); /* write-only */
+       int ret;
+       u8 sndbuf[1+wlen];
+
+       deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
+
+       memset(sndbuf, 0, 1+wlen);
+
+       sndbuf[0] = cmd;
+       memcpy(&sndbuf[1], wbuf, wlen);
+
+       ret = (wo) ? dvb_usb_generic_write(d, sndbuf, 1+wlen) :
+               dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
+       mxl_fail(ret);
+
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#define MXL_CMD_REG_READ       0xaa
+#define MXL_CMD_REG_WRITE      0x55
+
+int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data)
+{
+       u8 buf[2];
+       int ret;
+
+       ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2);
+       if (mxl_fail(ret)) {
+               mxl_debug("error reading reg: 0x%02x", addr);
+               goto fail;
+       }
+
+       if (buf[0] == addr)
+               *data = buf[1];
+       else {
+               err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
+                   addr, buf[0], buf[1]);
+               ret = -EINVAL;
+       }
+
+       deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data);
+fail:
+       return ret;
+}
+
+int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data)
+{
+       u8 buf[] = { addr, data };
+       int ret;
+
+       deb_reg("W: (0x%02x, 0x%02x)\n", addr, data);
+
+       ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
+       if (mxl_fail(ret))
+               err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
+                                  u8 addr, u8 mask, u8 data)
+{
+       int ret;
+       u8 val;
+
+       if (mask != 0xff) {
+               ret = mxl111sf_read_reg(state, addr, &val);
+#if 1
+               /* dont know why this usually errors out on the first try */
+               if (mxl_fail(ret))
+                       err("error writing addr: 0x%02x, mask: 0x%02x, "
+                           "data: 0x%02x, retrying...", addr, mask, data);
+
+               ret = mxl111sf_read_reg(state, addr, &val);
+#endif
+               if (mxl_fail(ret))
+                       goto fail;
+       }
+       val &= ~mask;
+       val |= data;
+
+       ret = mxl111sf_write_reg(state, addr, val);
+       mxl_fail(ret);
+fail:
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
+                              struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
+{
+       int i, ret = 0;
+
+       for (i = 0;  ctrl_reg_info[i].addr |
+                    ctrl_reg_info[i].mask |
+                    ctrl_reg_info[i].data;  i++) {
+
+               ret = mxl111sf_write_reg_mask(state,
+                                             ctrl_reg_info[i].addr,
+                                             ctrl_reg_info[i].mask,
+                                             ctrl_reg_info[i].data);
+               if (mxl_fail(ret)) {
+                       err("failed on reg #%d (0x%02x)", i,
+                           ctrl_reg_info[i].addr);
+                       break;
+               }
+       }
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state)
+{
+       int ret;
+       u8 id, ver;
+       char *mxl_chip, *mxl_rev;
+
+       if ((state->chip_id) && (state->chip_ver))
+               return 0;
+
+       ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id);
+       if (mxl_fail(ret))
+               goto fail;
+       state->chip_id = id;
+
+       ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver);
+       if (mxl_fail(ret))
+               goto fail;
+       state->chip_ver = ver;
+
+       switch (id) {
+       case 0x61:
+               mxl_chip = "MxL101SF";
+               break;
+       case 0x63:
+               mxl_chip = "MxL111SF";
+               break;
+       default:
+               mxl_chip = "UNKNOWN MxL1X1";
+               break;
+       }
+       switch (ver) {
+       case 0x36:
+               state->chip_rev = MXL111SF_V6;
+               mxl_rev = "v6";
+               break;
+       case 0x08:
+               state->chip_rev = MXL111SF_V8_100;
+               mxl_rev = "v8_100";
+               break;
+       case 0x18:
+               state->chip_rev = MXL111SF_V8_200;
+               mxl_rev = "v8_200";
+               break;
+       default:
+               state->chip_rev = 0;
+               mxl_rev = "UNKNOWN REVISION";
+               break;
+       }
+       info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver);
+fail:
+       return ret;
+}
+
+#define get_chip_info(state)                                           \
+({                                                                     \
+       int ___ret;                                                     \
+       ___ret = mxl1x1sf_get_chip_info(state);                         \
+       if (mxl_fail(___ret)) {                                         \
+               mxl_debug("failed to get chip info"                     \
+                         " on first probe attempt");                   \
+               ___ret = mxl1x1sf_get_chip_info(state);                 \
+               if (mxl_fail(___ret))                                   \
+                       err("failed to get chip info during probe");    \
+               else                                                    \
+                       mxl_debug("probe needed a retry "               \
+                                 "in order to succeed.");              \
+       }                                                               \
+       ___ret;                                                         \
+})
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       /* power control depends on which adapter is being woken:
+        * save this for init, instead, via mxl111sf_adap_fe_init */
+       return 0;
+}
+
+static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dvb_usb_device *d = adap->dev;
+       struct mxl111sf_state *state = d->priv;
+       struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv;
+
+       int err;
+
+       /* exit if we didnt initialize the driver yet */
+       if (!state->chip_id) {
+               mxl_debug("driver not yet initialized, exit.");
+               goto fail;
+       }
+
+       deb_info("%s()\n", __func__);
+
+       mutex_lock(&state->fe_lock);
+
+       state->alt_mode = adap_state->alt_mode;
+
+       if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
+               err("set interface failed");
+
+       err = mxl1x1sf_soft_reset(state);
+       mxl_fail(err);
+       err = mxl111sf_init_tuner_demod(state);
+       mxl_fail(err);
+       err = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+
+       mxl_fail(err);
+       mxl111sf_enable_usb_output(state);
+       mxl_fail(err);
+       mxl1x1sf_top_master_ctrl(state, 1);
+       mxl_fail(err);
+
+       if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) &&
+           (state->chip_rev > MXL111SF_V6)) {
+               mxl111sf_config_pin_mux_modes(state,
+                                             PIN_MUX_TS_SPI_IN_MODE_1);
+               mxl_fail(err);
+       }
+       err = mxl111sf_init_port_expander(state);
+       if (!mxl_fail(err)) {
+               state->gpio_mode = adap_state->gpio_mode;
+               err = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+               mxl_fail(err);
+#if 0
+               err = fe->ops.init(fe);
+#endif
+               msleep(100); /* add short delay after enabling
+                             * the demod before touching it */
+       }
+
+       return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0;
+fail:
+       return -ENODEV;
+}
+
+static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dvb_usb_device *d = adap->dev;
+       struct mxl111sf_state *state = d->priv;
+       struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv;
+       int err;
+
+       /* exit if we didnt initialize the driver yet */
+       if (!state->chip_id) {
+               mxl_debug("driver not yet initialized, exit.");
+               goto fail;
+       }
+
+       deb_info("%s()\n", __func__);
+
+       err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0;
+
+       mutex_unlock(&state->fe_lock);
+
+       return err;
+fail:
+       return -ENODEV;
+}
+
+
+static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+       struct dvb_usb_device *d = adap->dev;
+       struct mxl111sf_state *state = d->priv;
+       struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv;
+       int ret = 0;
+       u8 tmp;
+
+       deb_info("%s(%d)\n", __func__, onoff);
+
+       if (onoff) {
+               ret = mxl111sf_enable_usb_output(state);
+               mxl_fail(ret);
+               ret = mxl111sf_config_mpeg_in(state, 1, 1,
+                                             adap_state->ep6_clockphase,
+                                             0, 0);
+               mxl_fail(ret);
+       } else {
+               ret = mxl111sf_disable_656_port(state);
+               mxl_fail(ret);
+       }
+
+       mxl111sf_read_reg(state, 0x12, &tmp);
+       tmp &= ~0x04;
+       mxl111sf_write_reg(state, 0x12, tmp);
+
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static struct lgdt3305_config hauppauge_lgdt3305_config = {
+       .i2c_addr           = 0xb2 >> 1,
+       .mpeg_mode          = LGDT3305_MPEG_SERIAL,
+       .tpclk_edge         = LGDT3305_TPCLK_RISING_EDGE,
+       .tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+       .deny_i2c_rptr      = 1,
+       .spectral_inversion = 0,
+       .qam_if_khz         = 6000,
+       .vsb_if_khz         = 6000,
+};
+
+static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dvb_usb_device *d = adap->dev;
+       struct mxl111sf_state *state = d->priv;
+       int fe_id = adap->num_frontends_initialized;
+       struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
+       int ret;
+
+       deb_adv("%s()\n", __func__);
+
+       /* save a pointer to the dvb_usb_device in device state */
+       state->d = d;
+       adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+       state->alt_mode = adap_state->alt_mode;
+
+       if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
+               err("set interface failed");
+
+       state->gpio_mode = MXL111SF_GPIO_MOD_ATSC;
+       adap_state->gpio_mode = state->gpio_mode;
+       adap_state->device_mode = MXL_TUNER_MODE;
+       adap_state->ep6_clockphase = 1;
+
+       ret = mxl1x1sf_soft_reset(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_init_tuner_demod(state);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_enable_usb_output(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl1x1sf_top_master_ctrl(state, 1);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_init_port_expander(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+       if (mxl_fail(ret))
+               goto fail;
+
+       adap->fe_adap[fe_id].fe = dvb_attach(lgdt3305_attach,
+                                &hauppauge_lgdt3305_config,
+                                &adap->dev->i2c_adap);
+       if (adap->fe_adap[fe_id].fe) {
+               adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
+               adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
+               adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
+               adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
+               return 0;
+       }
+       ret = -EIO;
+fail:
+       return ret;
+}
+
+static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state,
+                                       int antpath)
+{
+       return mxl111sf_idac_config(state, 1, 1,
+                                   (antpath == ANT_PATH_INTERNAL) ?
+                                   0x3f : 0x00, 0);
+}
+
+#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \
+       err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \
+           __func__, __LINE__, \
+           (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \
+           pwr0, pwr1, pwr2, pwr3)
+
+#define ANT_HUNT_SLEEP 90
+#define ANT_EXT_TWEAK 0
+
+static int mxl111sf_ant_hunt(struct dvb_frontend *fe)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dvb_usb_device *d = adap->dev;
+       struct mxl111sf_state *state = d->priv;
+
+       int antctrl = dvb_usb_mxl111sf_rfswitch;
+
+       u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2;
+
+       /* FIXME: must force EXTERNAL for QAM - done elsewhere */
+       mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ?
+                             ANT_PATH_EXTERNAL : antctrl);
+
+       if (antctrl == ANT_PATH_AUTO) {
+#if 0
+               msleep(ANT_HUNT_SLEEP);
+#endif
+               fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA);
+
+               mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
+               msleep(ANT_HUNT_SLEEP);
+               fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0);
+
+               mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
+               msleep(ANT_HUNT_SLEEP);
+               fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1);
+
+               mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL);
+               msleep(ANT_HUNT_SLEEP);
+               fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2);
+
+               if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) {
+                       /* return with EXTERNAL enabled */
+                       mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
+                       DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA,
+                                  rxPwr0, rxPwr1, rxPwr2);
+               } else {
+                       /* return with INTERNAL enabled */
+                       DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA,
+                                  rxPwr0, rxPwr1, rxPwr2);
+               }
+       }
+       return 0;
+}
+
+static struct mxl111sf_tuner_config mxl_tuner_config = {
+       .if_freq         = MXL_IF_6_0, /* applies to external IF output, only */
+       .invert_spectrum = 0,
+       .read_reg        = mxl111sf_read_reg,
+       .write_reg       = mxl111sf_write_reg,
+       .program_regs    = mxl111sf_ctrl_program_regs,
+       .top_master_ctrl = mxl1x1sf_top_master_ctrl,
+       .ant_hunt        = mxl111sf_ant_hunt,
+};
+
+static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
+{
+       struct dvb_usb_device *d = adap->dev;
+       struct mxl111sf_state *state = d->priv;
+       int fe_id = adap->num_frontends_initialized;
+
+       deb_adv("%s()\n", __func__);
+
+       if (NULL != dvb_attach(mxl111sf_tuner_attach,
+                              adap->fe_adap[fe_id].fe, state,
+                              &mxl_tuner_config))
+               return 0;
+
+       return -EIO;
+}
+
+static int mxl111sf_fe_ioctl_override(struct dvb_frontend *fe,
+                                     unsigned int cmd, void *parg,
+                                     unsigned int stage)
+{
+       int err = 0;
+
+       switch (stage) {
+       case DVB_FE_IOCTL_PRE:
+
+               switch (cmd) {
+               case FE_READ_SIGNAL_STRENGTH:
+                       err = fe->ops.tuner_ops.get_rf_strength(fe, parg);
+                       /* If no error occurs, prevent dvb-core from handling
+                        * this IOCTL, otherwise return the error */
+                       if (0 == err)
+                               err = 1;
+                       break;
+               }
+               break;
+
+       case DVB_FE_IOCTL_POST:
+               /* no post-ioctl handling required */
+               break;
+       }
+       return err;
+};
+
+static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+struct i2c_algorithm mxl111sf_i2c_algo = {
+       .master_xfer   = mxl111sf_i2c_xfer,
+       .functionality = mxl111sf_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+       .algo_control = dummy_algo_control,
+#endif
+};
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties;
+
+static int mxl111sf_probe(struct usb_interface *intf,
+                         const struct usb_device_id *id)
+{
+       struct dvb_usb_device *d = NULL;
+
+       deb_adv("%s()\n", __func__);
+
+       if (((dvb_usb_mxl111sf_isoc) &&
+            (0 == dvb_usb_device_init(intf,
+                                      &mxl111sf_atsc_isoc_properties,
+                                      THIS_MODULE, &d, adapter_nr))) ||
+           0 == dvb_usb_device_init(intf,
+                                    &mxl111sf_atsc_bulk_properties,
+                                    THIS_MODULE, &d, adapter_nr) || 0) {
+
+               struct mxl111sf_state *state = d->priv;
+               static u8 eeprom[256];
+               struct i2c_client c;
+               int ret;
+
+               ret = get_chip_info(state);
+               if (mxl_fail(ret))
+                       err("failed to get chip info during probe");
+
+               mutex_init(&state->fe_lock);
+
+               if (state->chip_rev > MXL111SF_V6)
+                       mxl111sf_config_pin_mux_modes(state,
+                                                     PIN_MUX_TS_SPI_IN_MODE_1);
+
+               c.adapter = &d->i2c_adap;
+               c.addr = 0xa0 >> 1;
+
+               ret = tveeprom_read(&c, eeprom, sizeof(eeprom));
+               if (mxl_fail(ret))
+                       return 0;
+               tveeprom_hauppauge_analog(&c, &state->tv,
+                                         (0x84 == eeprom[0xa0]) ?
+                                         eeprom + 0xa0 : eeprom + 0x80);
+#if 0
+               switch (state->tv.model) {
+               case 117001:
+               case 126001:
+               case 138001:
+                       break;
+               default:
+                       printk(KERN_WARNING "%s: warning: "
+                              "unknown hauppauge model #%d\n",
+                              __func__, state->tv.model);
+               }
+#endif
+               return 0;
+       }
+       err("Your device is not yet supported by this driver. "
+           "See kernellabs.com for more info");
+       return -EINVAL;
+}
+
+static struct usb_device_id mxl111sf_table[] = {
+/* 0 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600) }, /* ATSC+ IR     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601) }, /* ATSC         */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602) }, /*     +        */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603) }, /* ATSC+        */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604) }, /* DVBT         */
+/* 5 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609) }, /* ATSC  IR     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a) }, /*     + IR     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b) }, /* ATSC+ IR     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c) }, /* DVBT  IR     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653) }, /* ATSC+        */
+/*10 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b) }, /* ATSC+ IR     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700) }, /* ATSC+ sw     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701) }, /* ATSC  sw     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702) }, /*     + sw     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703) }, /* ATSC+ sw     */
+/*15 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704) }, /* DVBT  sw     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753) }, /* ATSC+ sw     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763) }, /* ATSC+ no     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764) }, /* DVBT  no     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853) }, /* ATSC+ sw     */
+/*20 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854) }, /* DVBT  sw     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863) }, /* ATSC+ no     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864) }, /* DVBT  no     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3) }, /* ATSC+ sw     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4) }, /* DVBT  sw     */
+/*25 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3) }, /* ATSC+ no     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4) }, /* DVBT  no     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff) }, /* ATSC+        */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612) }, /*     +        */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613) }, /* ATSC+        */
+/*30 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a) }, /*     + IR     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b) }, /* ATSC+ IR     */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757) }, /* ATSC+DVBT sw */
+       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767) }, /* ATSC+DVBT no */
+       {}              /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, mxl111sf_table);
+
+
+#define MXL111SF_EP6_BULK_STREAMING_CONFIG             \
+       .streaming_ctrl = mxl111sf_ep6_streaming_ctrl,  \
+       .stream = {                                     \
+               .type = USB_BULK,                       \
+               .count = 5,                             \
+               .endpoint = 0x06,                       \
+               .u = {                                  \
+                       .bulk = {                       \
+                               .buffersize = 8192,     \
+                       }                               \
+               }                                       \
+       }
+
+/* FIXME */
+#define MXL111SF_EP6_ISOC_STREAMING_CONFIG             \
+       .streaming_ctrl = mxl111sf_ep6_streaming_ctrl,  \
+       .stream = {                                     \
+               .type = USB_ISOC,                       \
+               .count = 5,                             \
+               .endpoint = 0x06,                       \
+               .u = {                                  \
+                       .isoc = {                       \
+                               .framesperurb = 24,     \
+                               .framesize = 3072,      \
+                               .interval = 1,          \
+                       }                               \
+               }                                       \
+       }
+
+#define MXL111SF_DEFAULT_DEVICE_PROPERTIES                     \
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,                      \
+       .usb_ctrl = DEVICE_SPECIFIC,                            \
+       /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t), \
+                                    EP6 BULK transfer (atsc/qam), \
+          use usb alt setting 2 for EP4 BULK transfer (dvb-t), \
+                                    EP6 ISOC transfer (atsc/qam), \
+       */                                                      \
+       .power_ctrl       = mxl111sf_power_ctrl,                \
+       .i2c_algo         = &mxl111sf_i2c_algo,                 \
+       .generic_bulk_ctrl_endpoint          = MXL_EP2_REG_WRITE, \
+       .generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \
+       .size_of_priv     = sizeof(struct mxl111sf_state)
+
+static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
+       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+               .num_frontends = 1,
+               .fe = {{
+                       .size_of_priv     = sizeof(struct mxl111sf_adap_state),
+
+                       .frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
+                       .tuner_attach     = mxl111sf_attach_tuner,
+
+                       MXL111SF_EP6_BULK_STREAMING_CONFIG,
+               }},
+               },
+       },
+       .num_device_descs = 6,
+       .devices = {
+               {   "Hauppauge 126xxx ATSC (bulk)",
+                       { NULL },
+                       { &mxl111sf_table[1], &mxl111sf_table[5],
+                         NULL },
+               },
+               {   "Hauppauge 117xxx ATSC (bulk)",
+                       { NULL },
+                       { &mxl111sf_table[12],
+                         NULL },
+               },
+               {   "Hauppauge 126xxx ATSC+ (bulk)",
+                       { NULL },
+                       { &mxl111sf_table[0], &mxl111sf_table[3],
+                         &mxl111sf_table[7], &mxl111sf_table[9],
+                         &mxl111sf_table[10], NULL },
+               },
+               {   "Hauppauge 117xxx ATSC+ (bulk)",
+                       { NULL },
+                       { &mxl111sf_table[11], &mxl111sf_table[14],
+                         &mxl111sf_table[16], &mxl111sf_table[17],
+                         &mxl111sf_table[32], &mxl111sf_table[33],
+                         NULL },
+               },
+               {   "Hauppauge Mercury (tp-bulk)",
+                       { NULL },
+                       { &mxl111sf_table[19], &mxl111sf_table[21],
+                         &mxl111sf_table[23], &mxl111sf_table[25],
+                         &mxl111sf_table[27], NULL },
+               },
+               {   "Hauppauge WinTV-Aero-M",
+                       { NULL },
+                       { &mxl111sf_table[29], &mxl111sf_table[31],
+                         NULL },
+               },
+       }
+};
+
+static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
+       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+               .num_frontends = 1,
+               .fe = {{
+                       .size_of_priv     = sizeof(struct mxl111sf_adap_state),
+
+                       .frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
+                       .tuner_attach     = mxl111sf_attach_tuner,
+
+                       MXL111SF_EP6_ISOC_STREAMING_CONFIG,
+               }},
+               },
+       },
+       .num_device_descs = 6,
+       .devices = {
+               {   "Hauppauge 126xxx ATSC (isoc)",
+                       { NULL },
+                       { &mxl111sf_table[1], &mxl111sf_table[5],
+                         NULL },
+               },
+               {   "Hauppauge 117xxx ATSC (isoc)",
+                       { NULL },
+                       { &mxl111sf_table[12],
+                         NULL },
+               },
+               {   "Hauppauge 126xxx ATSC+ (isoc)",
+                       { NULL },
+                       { &mxl111sf_table[0], &mxl111sf_table[3],
+                         &mxl111sf_table[7], &mxl111sf_table[9],
+                         &mxl111sf_table[10], NULL },
+               },
+               {   "Hauppauge 117xxx ATSC+ (isoc)",
+                       { NULL },
+                       { &mxl111sf_table[11], &mxl111sf_table[14],
+                         &mxl111sf_table[16], &mxl111sf_table[17],
+                         &mxl111sf_table[32], &mxl111sf_table[33],
+                         NULL },
+               },
+               {   "Hauppauge Mercury (tp-isoc)",
+                       { NULL },
+                       { &mxl111sf_table[19], &mxl111sf_table[21],
+                         &mxl111sf_table[23], &mxl111sf_table[25],
+                         &mxl111sf_table[27], NULL },
+               },
+               {   "Hauppauge WinTV-Aero-M (tp-isoc)",
+                       { NULL },
+                       { &mxl111sf_table[29], &mxl111sf_table[31],
+                         NULL },
+               },
+       }
+};
+
+static struct usb_driver mxl111sf_driver = {
+       .name           = "dvb_usb_mxl111sf",
+       .probe          = mxl111sf_probe,
+       .disconnect     = dvb_usb_device_exit,
+       .id_table       = mxl111sf_table,
+};
+
+static int __init mxl111sf_module_init(void)
+{
+       int result = usb_register(&mxl111sf_driver);
+       if (result) {
+               err("usb_register failed. Error number %d", result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit mxl111sf_module_exit(void)
+{
+       usb_deregister(&mxl111sf_driver);
+}
+
+module_init(mxl111sf_module_init);
+module_exit(mxl111sf_module_exit);
+
+MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
+MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.h b/drivers/media/dvb/dvb-usb/mxl111sf.h
new file mode 100644 (file)
index 0000000..5a2c7bb
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com)
+ *
+ *   This program is free software; you can redistribute it and/or modify it
+ *   under the terms of the GNU General Public License as published by the Free
+ *   Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#ifndef _DVB_USB_MXL111SF_H_
+#define _DVB_USB_MXL111SF_H_
+
+#ifdef DVB_USB_LOG_PREFIX
+#undef DVB_USB_LOG_PREFIX
+#endif
+#define DVB_USB_LOG_PREFIX "mxl111sf"
+#include "dvb-usb.h"
+#include <media/tveeprom.h>
+
+#define MXL_EP1_REG_READ     1
+#define MXL_EP2_REG_WRITE    2
+#define MXL_EP3_INTERRUPT    3
+#define MXL_EP4_MPEG2        4
+#define MXL_EP5_I2S          5
+#define MXL_EP6_656          6
+#define MXL_EP6_MPEG2        6
+
+#ifdef USING_ENUM_mxl111sf_current_mode
+enum mxl111sf_current_mode {
+       mxl_mode_dvbt = MXL_EP4_MPEG2,
+       mxl_mode_mh   = MXL_EP5_I2S,
+       mxl_mode_atsc = MXL_EP6_MPEG2,
+};
+#endif
+
+enum mxl111sf_gpio_port_expander {
+       mxl111sf_gpio_hw,
+       mxl111sf_PCA9534,
+};
+
+struct mxl111sf_state {
+       struct dvb_usb_device *d;
+
+       enum mxl111sf_gpio_port_expander gpio_port_expander;
+       u8 port_expander_addr;
+
+       u8 chip_id;
+       u8 chip_ver;
+#define MXL111SF_V6     1
+#define MXL111SF_V8_100 2
+#define MXL111SF_V8_200 3
+       u8 chip_rev;
+
+#ifdef USING_ENUM_mxl111sf_current_mode
+       enum mxl111sf_current_mode current_mode;
+#endif
+
+#define MXL_TUNER_MODE         0
+#define MXL_SOC_MODE           1
+#define MXL_DEV_MODE_MASK      0x01
+#if 1
+       int device_mode;
+#endif
+       /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t),
+                                    EP5 BULK transfer (atsc-mh),
+                                    EP6 BULK transfer (atsc/qam),
+          use usb alt setting 2 for EP4 BULK transfer (dvb-t),
+                                    EP5 ISOC transfer (atsc-mh),
+                                    EP6 ISOC transfer (atsc/qam),
+        */
+       int alt_mode;
+       int gpio_mode;
+       struct tveeprom tv;
+
+       struct mutex fe_lock;
+};
+
+struct mxl111sf_adap_state {
+       int alt_mode;
+       int gpio_mode;
+       int device_mode;
+       int ep6_clockphase;
+       int (*fe_init)(struct dvb_frontend *);
+       int (*fe_sleep)(struct dvb_frontend *);
+};
+
+int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data);
+int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data);
+
+struct mxl111sf_reg_ctrl_info {
+       u8 addr;
+       u8 mask;
+       u8 data;
+};
+
+int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
+                           u8 addr, u8 mask, u8 data);
+int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
+                              struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
+
+/* needed for hardware i2c functions in mxl111sf-i2c.c:
+ * mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */
+int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
+                     u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen);
+
+#define mxl_printk(kern, fmt, arg...) \
+       printk(kern "%s: " fmt "\n", __func__, ##arg)
+
+#define mxl_info(fmt, arg...) \
+       mxl_printk(KERN_INFO, fmt, ##arg)
+
+extern int dvb_usb_mxl111sf_debug;
+#define mxl_debug(fmt, arg...) \
+       if (dvb_usb_mxl111sf_debug) \
+               mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+#define MXL_I2C_DBG 0x04
+#define MXL_ADV_DBG 0x10
+#define mxl_debug_adv(fmt, arg...) \
+       if (dvb_usb_mxl111sf_debug & MXL_ADV_DBG) \
+               mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+#define mxl_i2c(fmt, arg...) \
+       if (dvb_usb_mxl111sf_debug & MXL_I2C_DBG) \
+               mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+#define mxl_i2c_adv(fmt, arg...) \
+       if ((dvb_usb_mxl111sf_debug & (MXL_I2C_DBG | MXL_ADV_DBG)) == \
+               (MXL_I2C_DBG | MXL_ADV_DBG)) \
+                       mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+/* The following allows the mxl_fail() macro defined below to work
+ * in externel modules, such as mxl111sf-tuner.ko, even though
+ * dvb_usb_mxl111sf_debug is not defined within those modules */
+#ifdef __MXL111SF_TUNER_H__
+#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG
+#else
+#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug
+#endif
+
+#define mxl_fail(ret)                                                  \
+({                                                                     \
+       int __ret;                                                      \
+       __ret = (ret < 0);                                              \
+       if ((__ret) && (MXL_ADV_DEBUG_ENABLED & MXL_ADV_DBG))           \
+               mxl_printk(KERN_ERR, "error %d on line %d",             \
+                          ret, __LINE__);                              \
+       __ret;                                                          \
+})
+
+#endif /* _DVB_USB_MXL111SF_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
index bc350e9..21384da 100644 (file)
@@ -166,6 +166,8 @@ static struct dvb_usb_device_properties nova_t_properties = {
        .num_adapters     = 1,
        .adapter          = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .pid_filter_count = 32,
 
@@ -186,7 +188,7 @@ static struct dvb_usb_device_properties nova_t_properties = {
                                        }
                                }
                        },
-
+               }},
                        .size_of_priv     = sizeof(struct dibusb_state),
                }
        },
index 2e4fab7..98fd9a6 100644 (file)
@@ -263,10 +263,10 @@ static struct stv0299_config opera1_stv0299_config = {
 
 static int opera1_frontend_attach(struct dvb_usb_adapter *d)
 {
-       if ((d->fe =
-            dvb_attach(stv0299_attach, &opera1_stv0299_config,
-                       &d->dev->i2c_adap)) != NULL) {
-               d->fe->ops.set_voltage = opera1_set_voltage;
+       d->fe_adap[0].fe = dvb_attach(stv0299_attach, &opera1_stv0299_config,
+                                     &d->dev->i2c_adap);
+       if ((d->fe_adap[0].fe) != NULL) {
+               d->fe_adap[0].fe->ops.set_voltage = opera1_set_voltage;
                return 0;
        }
        info("not attached stv0299");
@@ -276,7 +276,7 @@ static int opera1_frontend_attach(struct dvb_usb_adapter *d)
 static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(
-               dvb_pll_attach, adap->fe, 0xc0>>1,
+               dvb_pll_attach, adap->fe_adap[0].fe, 0xc0>>1,
                &adap->dev->i2c_adap, DVB_PLL_OPERA1
        );
        return 0;
@@ -516,6 +516,8 @@ static struct dvb_usb_device_properties opera1_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .frontend_attach = opera1_frontend_attach,
                        .streaming_ctrl = opera1_streaming_ctrl,
                        .tuner_attach = opera1_tuner_attach,
@@ -535,6 +537,7 @@ static struct dvb_usb_device_properties opera1_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
        .num_device_descs = 1,
diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c
new file mode 100644 (file)
index 0000000..f9aec5c
--- /dev/null
@@ -0,0 +1,1079 @@
+/*
+ * PCTV 452e DVB driver
+ *
+ * Copyright (c) 2006-2008 Dominik Kuhlen <dkuhlen@gmx.net>
+ *
+ * TT connect S2-3650-CI Common Interface support, MAC readout
+ * Copyright (C) 2008 Michael H. Schimek <mschimek@gmx.at>
+ *
+ * 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.
+ */
+
+/* dvb usb framework */
+#define DVB_USB_LOG_PREFIX "pctv452e"
+#include "dvb-usb.h"
+
+/* Demodulator */
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+#include "stb0899_cfg.h"
+/* Tuner */
+#include "stb6100.h"
+#include "stb6100_cfg.h"
+/* FE Power */
+#include "lnbp22.h"
+
+#include "dvb_ca_en50221.h"
+#include "ttpci-eeprom.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define ISOC_INTERFACE_ALTERNATIVE 3
+
+#define SYNC_BYTE_OUT 0xaa
+#define SYNC_BYTE_IN  0x55
+
+/* guessed: (copied from ttusb-budget) */
+#define PCTV_CMD_RESET 0x15
+/* command to poll IR receiver */
+#define PCTV_CMD_IR    0x1b
+/* command to send I2C  */
+#define PCTV_CMD_I2C   0x31
+
+#define I2C_ADDR_STB0899 (0xd0 >> 1)
+#define I2C_ADDR_STB6100 (0xc0 >> 1)
+#define I2C_ADDR_LNBP22  (0x10 >> 1)
+#define I2C_ADDR_24C16   (0xa0 >> 1)
+#define I2C_ADDR_24C64   (0xa2 >> 1)
+
+
+/* pctv452e sends us this amount of data for each issued usb-command */
+#define PCTV_ANSWER_LEN 64
+/* Wait up to 1000ms for device  */
+#define PCTV_TIMEOUT 1000
+
+
+#define PCTV_LED_GPIO   STB0899_GPIO01
+#define PCTV_LED_GREEN  0x82
+#define PCTV_LED_ORANGE 0x02
+
+#define ci_dbg(format, arg...)                         \
+do {                                                   \
+       if (0)                                          \
+               printk(KERN_DEBUG DVB_USB_LOG_PREFIX    \
+                       ": " format "\n" , ## arg);     \
+} while (0)
+
+enum {
+       TT3650_CMD_CI_TEST = 0x40,
+       TT3650_CMD_CI_RD_CTRL,
+       TT3650_CMD_CI_WR_CTRL,
+       TT3650_CMD_CI_RD_ATTR,
+       TT3650_CMD_CI_WR_ATTR,
+       TT3650_CMD_CI_RESET,
+       TT3650_CMD_CI_SET_VIDEO_PORT
+};
+
+
+static struct stb0899_postproc pctv45e_postproc[] = {
+       { PCTV_LED_GPIO, STB0899_GPIOPULLUP },
+       { 0, 0 }
+};
+
+/*
+ * stores all private variables for communication with the PCTV452e DVB-S2
+ */
+struct pctv452e_state {
+       struct dvb_ca_en50221 ca;
+       struct mutex ca_mutex;
+
+       u8 c;      /* transaction counter, wraps around...  */
+       u8 initialized; /* set to 1 if 0x15 has been sent */
+       u16 last_rc_key;
+};
+
+static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data,
+                        unsigned int write_len, unsigned int read_len)
+{
+       struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+       u8 buf[64];
+       u8 id;
+       unsigned int rlen;
+       int ret;
+
+       BUG_ON(NULL == data && 0 != (write_len | read_len));
+       BUG_ON(write_len > 64 - 4);
+       BUG_ON(read_len > 64 - 4);
+
+       id = state->c++;
+
+       buf[0] = SYNC_BYTE_OUT;
+       buf[1] = id;
+       buf[2] = cmd;
+       buf[3] = write_len;
+
+       memcpy(buf + 4, data, write_len);
+
+       rlen = (read_len > 0) ? 64 : 0;
+       ret = dvb_usb_generic_rw(d, buf, 4 + write_len,
+                                 buf, rlen, /* delay_ms */ 0);
+       if (0 != ret)
+               goto failed;
+
+       ret = -EIO;
+       if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+               goto failed;
+
+       memcpy(data, buf + 4, read_len);
+
+       return 0;
+
+failed:
+       err("CI error %d; %02X %02X %02X -> %02X %02X %02X.",
+            ret, SYNC_BYTE_OUT, id, cmd, buf[0], buf[1], buf[2]);
+
+       return ret;
+}
+
+static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
+                               u8 cmd, u8 *data, unsigned int write_len,
+                               unsigned int read_len)
+{
+       struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+       struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+       int ret;
+
+       mutex_lock(&state->ca_mutex);
+       ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
+       mutex_unlock(&state->ca_mutex);
+
+       return ret;
+}
+
+static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+                                int slot, int address)
+{
+       u8 buf[3];
+       int ret;
+
+       if (0 != slot)
+               return -EINVAL;
+
+       buf[0] = (address >> 8) & 0x0F;
+       buf[1] = address;
+
+       ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
+
+       ci_dbg("%s %04x -> %d 0x%02x",
+               __func__, address, ret, buf[2]);
+
+       if (ret < 0)
+               return ret;
+
+       return buf[2];
+}
+
+static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+                                int slot, int address, u8 value)
+{
+       u8 buf[3];
+
+       ci_dbg("%s %d 0x%04x 0x%02x",
+               __func__, slot, address, value);
+
+       if (0 != slot)
+               return -EINVAL;
+
+       buf[0] = (address >> 8) & 0x0F;
+       buf[1] = address;
+       buf[2] = value;
+
+       return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
+}
+
+static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+                                int                    slot,
+                                u8                     address)
+{
+       u8 buf[2];
+       int ret;
+
+       if (0 != slot)
+               return -EINVAL;
+
+       buf[0] = address & 3;
+
+       ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
+
+       ci_dbg("%s 0x%02x -> %d 0x%02x",
+               __func__, address, ret, buf[1]);
+
+       if (ret < 0)
+               return ret;
+
+       return buf[1];
+}
+
+static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+                                int                    slot,
+                                u8                     address,
+                                u8                     value)
+{
+       u8 buf[2];
+
+       ci_dbg("%s %d 0x%02x 0x%02x",
+               __func__, slot, address, value);
+
+       if (0 != slot)
+               return -EINVAL;
+
+       buf[0] = address;
+       buf[1] = value;
+
+       return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
+}
+
+static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca,
+                                int                    slot,
+                                int                    enable)
+{
+       u8 buf[1];
+       int ret;
+
+       ci_dbg("%s %d %d", __func__, slot, enable);
+
+       if (0 != slot)
+               return -EINVAL;
+
+       enable = !!enable;
+       buf[0] = enable;
+
+       ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+       if (ret < 0)
+               return ret;
+
+       if (enable != buf[0]) {
+               err("CI not %sabled.", enable ? "en" : "dis");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+       return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
+}
+
+static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+       return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
+}
+
+static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+       struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+       u8 buf[1];
+       int ret;
+
+       ci_dbg("%s %d", __func__, slot);
+
+       if (0 != slot)
+               return -EINVAL;
+
+       buf[0] = 0;
+
+       mutex_lock(&state->ca_mutex);
+
+       ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+       if (0 != ret)
+               goto failed;
+
+       msleep(500);
+
+       buf[0] = 1;
+
+       ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+       if (0 != ret)
+               goto failed;
+
+       msleep(500);
+
+       buf[0] = 0; /* FTA */
+
+       ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+
+ failed:
+       mutex_unlock(&state->ca_mutex);
+
+       return ret;
+}
+
+static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca,
+                                int                    slot,
+                                int                    open)
+{
+       u8 buf[1];
+       int ret;
+
+       if (0 != slot)
+               return -EINVAL;
+
+       ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
+       if (0 != ret)
+               return ret;
+
+       if (1 == buf[0])
+               return DVB_CA_EN50221_POLL_CAM_PRESENT |
+                       DVB_CA_EN50221_POLL_CAM_READY;
+
+       return 0;
+
+}
+
+static void tt3650_ci_uninit(struct dvb_usb_device *d)
+{
+       struct pctv452e_state *state;
+
+       ci_dbg("%s", __func__);
+
+       if (NULL == d)
+               return;
+
+       state = (struct pctv452e_state *)d->priv;
+       if (NULL == state)
+               return;
+
+       if (NULL == state->ca.data)
+               return;
+
+       /* Error ignored. */
+       tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
+
+       dvb_ca_en50221_release(&state->ca);
+
+       memset(&state->ca, 0, sizeof(state->ca));
+}
+
+static int tt3650_ci_init(struct dvb_usb_adapter *a)
+{
+       struct dvb_usb_device *d = a->dev;
+       struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+       int ret;
+
+       ci_dbg("%s", __func__);
+
+       mutex_init(&state->ca_mutex);
+
+       state->ca.owner = THIS_MODULE;
+       state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
+       state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
+       state->ca.read_cam_control = tt3650_ci_read_cam_control;
+       state->ca.write_cam_control = tt3650_ci_write_cam_control;
+       state->ca.slot_reset = tt3650_ci_slot_reset;
+       state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
+       state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
+       state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
+       state->ca.data = d;
+
+       ret = dvb_ca_en50221_init(&a->dvb_adap,
+                                  &state->ca,
+                                  /* flags */ 0,
+                                  /* n_slots */ 1);
+       if (0 != ret) {
+               err("Cannot initialize CI: Error %d.", ret);
+               memset(&state->ca, 0, sizeof(state->ca));
+               return ret;
+       }
+
+       info("CI initialized.");
+
+       return 0;
+}
+
+#define CMD_BUFFER_SIZE 0x28
+static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr,
+                               const u8 *snd_buf, u8 snd_len,
+                               u8 *rcv_buf, u8 rcv_len)
+{
+       struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+       u8 buf[64];
+       u8 id;
+       int ret;
+
+       id = state->c++;
+
+       ret = -EINVAL;
+       if (snd_len > 64 - 7 || rcv_len > 64 - 7)
+               goto failed;
+
+       buf[0] = SYNC_BYTE_OUT;
+       buf[1] = id;
+       buf[2] = PCTV_CMD_I2C;
+       buf[3] = snd_len + 3;
+       buf[4] = addr << 1;
+       buf[5] = snd_len;
+       buf[6] = rcv_len;
+
+       memcpy(buf + 7, snd_buf, snd_len);
+
+       ret = dvb_usb_generic_rw(d, buf, 7 + snd_len,
+                                 buf, /* rcv_len */ 64,
+                                 /* delay_ms */ 0);
+       if (ret < 0)
+               goto failed;
+
+       /* TT USB protocol error. */
+       ret = -EIO;
+       if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+               goto failed;
+
+       /* I2C device didn't respond as expected. */
+       ret = -EREMOTEIO;
+       if (buf[5] < snd_len || buf[6] < rcv_len)
+               goto failed;
+
+       memcpy(rcv_buf, buf + 7, rcv_len);
+
+       return rcv_len;
+
+failed:
+       err("I2C error %d; %02X %02X  %02X %02X %02X -> "
+            "%02X %02X  %02X %02X %02X.",
+            ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
+            buf[0], buf[1], buf[4], buf[5], buf[6]);
+
+       return ret;
+}
+
+static int pctv452e_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
+                               int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adapter);
+       int i;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       for (i = 0; i < num; i++) {
+               u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
+               int ret;
+
+               if (msg[i].flags & I2C_M_RD) {
+                       addr = msg[i].addr;
+                       snd_buf = NULL;
+                       snd_len = 0;
+                       rcv_buf = msg[i].buf;
+                       rcv_len = msg[i].len;
+               } else {
+                       addr = msg[i].addr;
+                       snd_buf = msg[i].buf;
+                       snd_len = msg[i].len;
+                       rcv_buf = NULL;
+                       rcv_len = 0;
+               }
+
+               ret = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf,
+                                       rcv_len);
+               if (ret < rcv_len)
+                       break;
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return i;
+}
+
+static u32 pctv452e_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i)
+{
+       struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+       u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 };
+       u8 rx[PCTV_ANSWER_LEN];
+       int ret;
+
+       info("%s: %d\n", __func__, i);
+
+       if (!i)
+               return 0;
+
+       if (state->initialized)
+               return 0;
+
+       /* hmm where shoud this should go? */
+       ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
+       if (ret != 0)
+               info("%s: Warning set interface returned: %d\n",
+                       __func__, ret);
+
+       /* this is a one-time initialization, dont know where to put */
+       b0[1] = state->c++;
+       /* reset board */
+       ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
+       if (ret)
+               return ret;
+
+       b0[1] = state->c++;
+       b0[4] = 1;
+       /* reset board (again?) */
+       ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
+       if (ret)
+               return ret;
+
+       state->initialized = 1;
+
+       return 0;
+}
+
+static int pctv452e_rc_query(struct dvb_usb_device *d)
+{
+       struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+       u8 b[CMD_BUFFER_SIZE];
+       u8 rx[PCTV_ANSWER_LEN];
+       int ret, i;
+       u8 id = state->c++;
+
+       /* prepare command header  */
+       b[0] = SYNC_BYTE_OUT;
+       b[1] = id;
+       b[2] = PCTV_CMD_IR;
+       b[3] = 0;
+
+       /* send ir request */
+       ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
+       if (ret != 0)
+               return ret;
+
+       if (debug > 3) {
+               info("%s: read: %2d: %02x %02x %02x: ", __func__,
+                               ret, rx[0], rx[1], rx[2]);
+               for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++)
+                       info(" %02x", rx[i+3]);
+
+               info("\n");
+       }
+
+       if ((rx[3] == 9) &&  (rx[12] & 0x01)) {
+               /* got a "press" event */
+               state->last_rc_key = (rx[7] << 8) | rx[6];
+               if (debug > 2)
+                       info("%s: cmd=0x%02x sys=0x%02x\n",
+                               __func__, rx[6], rx[7]);
+
+               rc_keydown(d->rc_dev, state->last_rc_key, 0);
+       } else if (state->last_rc_key) {
+               rc_keyup(d->rc_dev);
+               state->last_rc_key = 0;
+       }
+
+       return 0;
+}
+
+static int pctv452e_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+       const u8 mem_addr[] = { 0x1f, 0xcc };
+       u8 encoded_mac[20];
+       int ret;
+
+       ret = -EAGAIN;
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               goto failed;
+
+       ret = pctv452e_i2c_msg(d, I2C_ADDR_24C16,
+                               mem_addr + 1, /* snd_len */ 1,
+                               encoded_mac, /* rcv_len */ 20);
+       if (-EREMOTEIO == ret)
+               /* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a
+                  byte write if /WC is low. */
+               ret = pctv452e_i2c_msg(d, I2C_ADDR_24C64,
+                                       mem_addr, 2,
+                                       encoded_mac, 20);
+
+       mutex_unlock(&d->i2c_mutex);
+
+       if (20 != ret)
+               goto failed;
+
+       ret = ttpci_eeprom_decode_mac(mac, encoded_mac);
+       if (0 != ret)
+               goto failed;
+
+       return 0;
+
+failed:
+       memset(mac, 0, 6);
+
+       return ret;
+}
+
+static const struct stb0899_s1_reg pctv452e_init_dev[] = {
+       { STB0899_DISCNTRL1,    0x26 },
+       { STB0899_DISCNTRL2,    0x80 },
+       { STB0899_DISRX_ST0,    0x04 },
+       { STB0899_DISRX_ST1,    0x20 },
+       { STB0899_DISPARITY,    0x00 },
+       { STB0899_DISFIFO,      0x00 },
+       { STB0899_DISF22,       0x99 },
+       { STB0899_DISF22RX,     0x85 }, /* 0xa8 */
+       { STB0899_ACRPRESC,     0x11 },
+       { STB0899_ACRDIV1,      0x0a },
+       { STB0899_ACRDIV2,      0x05 },
+       { STB0899_DACR1 ,       0x00 },
+       { STB0899_DACR2 ,       0x00 },
+       { STB0899_OUTCFG,       0x00 },
+       { STB0899_MODECFG,      0x00 }, /* Inversion */
+       { STB0899_IRQMSK_3,     0xf3 },
+       { STB0899_IRQMSK_2,     0xfc },
+       { STB0899_IRQMSK_1,     0xff },
+       { STB0899_IRQMSK_0,     0xff },
+       { STB0899_I2CCFG,       0x88 },
+       { STB0899_I2CRPT,       0x58 },
+       { STB0899_GPIO00CFG,    0x82 },
+       { STB0899_GPIO01CFG,    0x82 }, /* LED: 0x02 green, 0x82 orange */
+       { STB0899_GPIO02CFG,    0x82 },
+       { STB0899_GPIO03CFG,    0x82 },
+       { STB0899_GPIO04CFG,    0x82 },
+       { STB0899_GPIO05CFG,    0x82 },
+       { STB0899_GPIO06CFG,    0x82 },
+       { STB0899_GPIO07CFG,    0x82 },
+       { STB0899_GPIO08CFG,    0x82 },
+       { STB0899_GPIO09CFG,    0x82 },
+       { STB0899_GPIO10CFG,    0x82 },
+       { STB0899_GPIO11CFG,    0x82 },
+       { STB0899_GPIO12CFG,    0x82 },
+       { STB0899_GPIO13CFG,    0x82 },
+       { STB0899_GPIO14CFG,    0x82 },
+       { STB0899_GPIO15CFG,    0x82 },
+       { STB0899_GPIO16CFG,    0x82 },
+       { STB0899_GPIO17CFG,    0x82 },
+       { STB0899_GPIO18CFG,    0x82 },
+       { STB0899_GPIO19CFG,    0x82 },
+       { STB0899_GPIO20CFG,    0x82 },
+       { STB0899_SDATCFG,      0xb8 },
+       { STB0899_SCLTCFG,      0xba },
+       { STB0899_AGCRFCFG,     0x1c }, /* 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm) */
+       { STB0899_GPIO22,       0x82 },
+       { STB0899_GPIO21,       0x91 },
+       { STB0899_DIRCLKCFG,    0x82 },
+       { STB0899_CLKOUT27CFG,  0x7e },
+       { STB0899_STDBYCFG,     0x82 },
+       { STB0899_CS0CFG,       0x82 },
+       { STB0899_CS1CFG,       0x82 },
+       { STB0899_DISEQCOCFG,   0x20 },
+       { STB0899_NCOARSE,      0x15 }, /* 0x15 27Mhz, F/3 198MHz, F/6 108MHz */
+       { STB0899_SYNTCTRL,     0x00 }, /* 0x00 CLKI, 0x02 XTALI */
+       { STB0899_FILTCTRL,     0x00 },
+       { STB0899_SYSCTRL,      0x00 },
+       { STB0899_STOPCLK1,     0x20 }, /* orig: 0x00 budget-ci: 0x20 */
+       { STB0899_STOPCLK2,     0x00 },
+       { STB0899_INTBUFCTRL,   0x0a },
+       { STB0899_AGC2I1,       0x00 },
+       { STB0899_AGC2I2,       0x00 },
+       { STB0899_AGCIQIN,      0x00 },
+       { STB0899_TSTRES,       0x40 }, /* rjkm */
+       { 0xffff,               0xff },
+};
+
+static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = {
+       { STB0899_DEMOD,        0x00 },
+       { STB0899_RCOMPC,       0xc9 },
+       { STB0899_AGC1CN,       0x01 },
+       { STB0899_AGC1REF,      0x10 },
+       { STB0899_RTC,          0x23 },
+       { STB0899_TMGCFG,       0x4e },
+       { STB0899_AGC2REF,      0x34 },
+       { STB0899_TLSR,         0x84 },
+       { STB0899_CFD,          0xf7 },
+       { STB0899_ACLC,         0x87 },
+       { STB0899_BCLC,         0x94 },
+       { STB0899_EQON,         0x41 },
+       { STB0899_LDT,          0xf1 },
+       { STB0899_LDT2,         0xe3 },
+       { STB0899_EQUALREF,     0xb4 },
+       { STB0899_TMGRAMP,      0x10 },
+       { STB0899_TMGTHD,       0x30 },
+       { STB0899_IDCCOMP,      0xfd },
+       { STB0899_QDCCOMP,      0xff },
+       { STB0899_POWERI,       0x0c },
+       { STB0899_POWERQ,       0x0f },
+       { STB0899_RCOMP,        0x6c },
+       { STB0899_AGCIQIN,      0x80 },
+       { STB0899_AGC2I1,       0x06 },
+       { STB0899_AGC2I2,       0x00 },
+       { STB0899_TLIR,         0x30 },
+       { STB0899_RTF,          0x7f },
+       { STB0899_DSTATUS,      0x00 },
+       { STB0899_LDI,          0xbc },
+       { STB0899_CFRM,         0xea },
+       { STB0899_CFRL,         0x31 },
+       { STB0899_NIRM,         0x2b },
+       { STB0899_NIRL,         0x80 },
+       { STB0899_ISYMB,        0x1d },
+       { STB0899_QSYMB,        0xa6 },
+       { STB0899_SFRH,         0x2f },
+       { STB0899_SFRM,         0x68 },
+       { STB0899_SFRL,         0x40 },
+       { STB0899_SFRUPH,       0x2f },
+       { STB0899_SFRUPM,       0x68 },
+       { STB0899_SFRUPL,       0x40 },
+       { STB0899_EQUAI1,       0x02 },
+       { STB0899_EQUAQ1,       0xff },
+       { STB0899_EQUAI2,       0x04 },
+       { STB0899_EQUAQ2,       0x05 },
+       { STB0899_EQUAI3,       0x02 },
+       { STB0899_EQUAQ3,       0xfd },
+       { STB0899_EQUAI4,       0x03 },
+       { STB0899_EQUAQ4,       0x07 },
+       { STB0899_EQUAI5,       0x08 },
+       { STB0899_EQUAQ5,       0xf5 },
+       { STB0899_DSTATUS2,     0x00 },
+       { STB0899_VSTATUS,      0x00 },
+       { STB0899_VERROR,       0x86 },
+       { STB0899_IQSWAP,       0x2a },
+       { STB0899_ECNT1M,       0x00 },
+       { STB0899_ECNT1L,       0x00 },
+       { STB0899_ECNT2M,       0x00 },
+       { STB0899_ECNT2L,       0x00 },
+       { STB0899_ECNT3M,       0x0a },
+       { STB0899_ECNT3L,       0xad },
+       { STB0899_FECAUTO1,     0x06 },
+       { STB0899_FECM,         0x01 },
+       { STB0899_VTH12,        0xb0 },
+       { STB0899_VTH23,        0x7a },
+       { STB0899_VTH34,        0x58 },
+       { STB0899_VTH56,        0x38 },
+       { STB0899_VTH67,        0x34 },
+       { STB0899_VTH78,        0x24 },
+       { STB0899_PRVIT,        0xff },
+       { STB0899_VITSYNC,      0x19 },
+       { STB0899_RSULC,        0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+       { STB0899_TSULC,        0x42 },
+       { STB0899_RSLLC,        0x41 },
+       { STB0899_TSLPL,        0x12 },
+       { STB0899_TSCFGH,       0x0c },
+       { STB0899_TSCFGM,       0x00 },
+       { STB0899_TSCFGL,       0x00 },
+       { STB0899_TSOUT,        0x69 }, /* 0x0d for CAM */
+       { STB0899_RSSYNCDEL,    0x00 },
+       { STB0899_TSINHDELH,    0x02 },
+       { STB0899_TSINHDELM,    0x00 },
+       { STB0899_TSINHDELL,    0x00 },
+       { STB0899_TSLLSTKM,     0x1b },
+       { STB0899_TSLLSTKL,     0xb3 },
+       { STB0899_TSULSTKM,     0x00 },
+       { STB0899_TSULSTKL,     0x00 },
+       { STB0899_PCKLENUL,     0xbc },
+       { STB0899_PCKLENLL,     0xcc },
+       { STB0899_RSPCKLEN,     0xbd },
+       { STB0899_TSSTATUS,     0x90 },
+       { STB0899_ERRCTRL1,     0xb6 },
+       { STB0899_ERRCTRL2,     0x95 },
+       { STB0899_ERRCTRL3,     0x8d },
+       { STB0899_DMONMSK1,     0x27 },
+       { STB0899_DMONMSK0,     0x03 },
+       { STB0899_DEMAPVIT,     0x5c },
+       { STB0899_PLPARM,       0x19 },
+       { STB0899_PDELCTRL,     0x48 },
+       { STB0899_PDELCTRL2,    0x00 },
+       { STB0899_BBHCTRL1,     0x00 },
+       { STB0899_BBHCTRL2,     0x00 },
+       { STB0899_HYSTTHRESH,   0x77 },
+       { STB0899_MATCSTM,      0x00 },
+       { STB0899_MATCSTL,      0x00 },
+       { STB0899_UPLCSTM,      0x00 },
+       { STB0899_UPLCSTL,      0x00 },
+       { STB0899_DFLCSTM,      0x00 },
+       { STB0899_DFLCSTL,      0x00 },
+       { STB0899_SYNCCST,      0x00 },
+       { STB0899_SYNCDCSTM,    0x00 },
+       { STB0899_SYNCDCSTL,    0x00 },
+       { STB0899_ISI_ENTRY,    0x00 },
+       { STB0899_ISI_BIT_EN,   0x00 },
+       { STB0899_MATSTRM,      0xf0 },
+       { STB0899_MATSTRL,      0x02 },
+       { STB0899_UPLSTRM,      0x45 },
+       { STB0899_UPLSTRL,      0x60 },
+       { STB0899_DFLSTRM,      0xe3 },
+       { STB0899_DFLSTRL,      0x00 },
+       { STB0899_SYNCSTR,      0x47 },
+       { STB0899_SYNCDSTRM,    0x05 },
+       { STB0899_SYNCDSTRL,    0x18 },
+       { STB0899_CFGPDELSTATUS1, 0x19 },
+       { STB0899_CFGPDELSTATUS2, 0x2b },
+       { STB0899_BBFERRORM,    0x00 },
+       { STB0899_BBFERRORL,    0x01 },
+       { STB0899_UPKTERRORM,   0x00 },
+       { STB0899_UPKTERRORL,   0x00 },
+       { 0xffff,               0xff },
+};
+
+static struct stb0899_config stb0899_config = {
+       .init_dev       = pctv452e_init_dev,
+       .init_s2_demod  = stb0899_s2_init_2,
+       .init_s1_demod  = pctv452e_init_s1_demod,
+       .init_s2_fec    = stb0899_s2_init_4,
+       .init_tst       = stb0899_s1_init_5,
+
+       .demod_address   = I2C_ADDR_STB0899, /* I2C Address */
+       .block_sync_mode = STB0899_SYNC_FORCED, /* ? */
+
+       .xtal_freq       = 27000000,     /* Assume Hz ? */
+       .inversion       = IQ_SWAP_ON,       /* ? */
+
+       .lo_clk   = 76500000,
+       .hi_clk   = 99000000,
+
+       .ts_output_mode  = 0,   /* Use parallel mode */
+       .clock_polarity  = 0,
+       .data_clk_parity = 0,
+       .fec_mode       = 0,
+
+       .esno_ave           = STB0899_DVBS2_ESNO_AVE,
+       .esno_quant       = STB0899_DVBS2_ESNO_QUANT,
+       .avframes_coarse     = STB0899_DVBS2_AVFRAMES_COARSE,
+       .avframes_fine       = STB0899_DVBS2_AVFRAMES_FINE,
+       .miss_threshold      = STB0899_DVBS2_MISS_THRESHOLD,
+       .uwp_threshold_acq   = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+       .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+       .uwp_threshold_sof   = STB0899_DVBS2_UWP_THRESHOLD_SOF,
+       .sof_search_timeout  = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+       .btr_nco_bits     = STB0899_DVBS2_BTR_NCO_BITS,
+       .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+       .crl_nco_bits     = STB0899_DVBS2_CRL_NCO_BITS,
+       .ldpc_max_iter   = STB0899_DVBS2_LDPC_MAX_ITER,
+
+       .tuner_get_frequency    = stb6100_get_frequency,
+       .tuner_set_frequency    = stb6100_set_frequency,
+       .tuner_set_bandwidth    = stb6100_set_bandwidth,
+       .tuner_get_bandwidth    = stb6100_get_bandwidth,
+       .tuner_set_rfsiggain    = NULL,
+
+       /* helper for switching LED green/orange */
+       .postproc = pctv45e_postproc
+};
+
+static struct stb6100_config stb6100_config = {
+       .tuner_address = I2C_ADDR_STB6100,
+       .refclock      = 27000000
+};
+
+
+static struct i2c_algorithm pctv452e_i2c_algo = {
+       .master_xfer   = pctv452e_i2c_xfer,
+       .functionality = pctv452e_i2c_func
+};
+
+static int pctv452e_frontend_attach(struct dvb_usb_adapter *a)
+{
+       struct usb_device_id *id;
+
+       a->fe_adap[0].fe = dvb_attach(stb0899_attach, &stb0899_config,
+                                               &a->dev->i2c_adap);
+       if (!a->fe_adap[0].fe)
+               return -ENODEV;
+       if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe,
+                                       &a->dev->i2c_adap)) == 0)
+               err("Cannot attach lnbp22\n");
+
+       id = a->dev->desc->warm_ids[0];
+       if (USB_VID_TECHNOTREND == id->idVendor
+           && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct)
+               /* Error ignored. */
+               tt3650_ci_init(a);
+
+       return 0;
+}
+
+static int pctv452e_tuner_attach(struct dvb_usb_adapter *a)
+{
+       if (!a->fe_adap[0].fe)
+               return -ENODEV;
+       if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config,
+                                       &a->dev->i2c_adap) == 0) {
+               err("%s failed\n", __func__);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static struct usb_device_id pctv452e_usb_table[] = {
+       {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)},
+       {USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)},
+       {USB_DEVICE(USB_VID_TECHNOTREND,
+                               USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, pctv452e_usb_table);
+
+static struct dvb_usb_device_properties pctv452e_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
+       .usb_ctrl = DEVICE_SPECIFIC,
+
+       .size_of_priv     = sizeof(struct pctv452e_state),
+
+       .power_ctrl       = pctv452e_power_ctrl,
+
+       .rc.core = {
+               .rc_codes       = RC_MAP_DIB0700_RC5_TABLE,
+               .allowed_protos = RC_TYPE_UNKNOWN,
+               .rc_query       = pctv452e_rc_query,
+               .rc_interval    = 100,
+       },
+
+       .num_adapters     = 1,
+       .adapter = {{
+               .num_frontends = 1,
+               .fe = {{
+                       .frontend_attach  = pctv452e_frontend_attach,
+                       .tuner_attach     = pctv452e_tuner_attach,
+
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type     = USB_ISOC,
+                               .count    = 4,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .isoc = {
+                                               .framesperurb = 4,
+                                               .framesize    = 940,
+                                               .interval     = 1
+                                       }
+                               }
+                       },
+               } },
+       } },
+
+       .i2c_algo = &pctv452e_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 1, /* allow generice rw function */
+
+       .num_device_descs = 1,
+       .devices = {
+               { .name = "PCTV HDTV USB",
+                 .cold_ids = { NULL, NULL }, /* this is a warm only device */
+                 .warm_ids = { &pctv452e_usb_table[0], NULL }
+               },
+               { 0 },
+       }
+};
+
+static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
+       .usb_ctrl = DEVICE_SPECIFIC,
+
+       .size_of_priv           = sizeof(struct pctv452e_state),
+
+       .power_ctrl             = pctv452e_power_ctrl,
+       .read_mac_address       = pctv452e_read_mac_address,
+
+       .rc.core = {
+               .rc_codes       = RC_MAP_TT_1500,
+               .allowed_protos = RC_TYPE_UNKNOWN,
+               .rc_query       = pctv452e_rc_query,
+               .rc_interval    = 100,
+       },
+
+       .num_adapters           = 1,
+       .adapter = {{
+               .num_frontends = 1,
+               .fe = {{
+                       .frontend_attach = pctv452e_frontend_attach,
+                       .tuner_attach = pctv452e_tuner_attach,
+
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_ISOC,
+                               .count = 7,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .isoc = {
+                                               .framesperurb = 4,
+                                               .framesize = 940,
+                                               .interval = 1
+                                       }
+                               }
+                       },
+
+               } },
+       } },
+
+       .i2c_algo = &pctv452e_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 1, /* allow generic rw function*/
+
+       .num_device_descs = 2,
+       .devices = {
+               { .name = "Technotrend TT Connect S2-3600",
+                 .cold_ids = { NULL, NULL }, /* this is a warm only device */
+                 .warm_ids = { &pctv452e_usb_table[1], NULL }
+               },
+               { .name = "Technotrend TT Connect S2-3650-CI",
+                 .cold_ids = { NULL, NULL },
+                 .warm_ids = { &pctv452e_usb_table[2], NULL }
+               },
+               { 0 },
+       }
+};
+
+static void pctv452e_usb_disconnect(struct usb_interface *intf)
+{
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+
+       tt3650_ci_uninit(d);
+       dvb_usb_device_exit(intf);
+}
+
+static int pctv452e_usb_probe(struct usb_interface *intf,
+                               const struct usb_device_id *id)
+{
+       if (0 == dvb_usb_device_init(intf, &pctv452e_properties,
+                                       THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf, &tt_connect_s2_3600_properties,
+                                       THIS_MODULE, NULL, adapter_nr))
+               return 0;
+
+       return -ENODEV;
+}
+
+static struct usb_driver pctv452e_usb_driver = {
+       .name       = "pctv452e",
+       .probe      = pctv452e_usb_probe,
+       .disconnect = pctv452e_usb_disconnect,
+       .id_table   = pctv452e_usb_table,
+};
+
+static int __init pctv452e_usb_init(void)
+{
+       int ret = usb_register(&pctv452e_usb_driver);
+       if (ret)
+               err("%s: usb_register failed! Error %d", __FILE__, ret);
+
+       return ret;
+}
+
+static void __exit pctv452e_usb_exit(void)
+{
+       usb_deregister(&pctv452e_usb_driver);
+}
+
+module_init(pctv452e_usb_init);
+module_exit(pctv452e_usb_exit);
+
+MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
+MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
+MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");
+MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver");
+MODULE_LICENSE("GPL");
index 473b95e..0998fe9 100644 (file)
@@ -292,7 +292,7 @@ static void technisat_usb2_green_led_control(struct work_struct *work)
 {
        struct technisat_usb2_state *state =
                container_of(work, struct technisat_usb2_state, green_led_work.work);
-       struct dvb_frontend *fe = state->dev->adapter[0].fe;
+       struct dvb_frontend *fe = state->dev->adapter[0].fe_adap[0].fe;
 
        if (state->power_state == 0)
                goto schedule;
@@ -505,14 +505,14 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
        struct usb_device *udev = a->dev->udev;
        int ret;
 
-       a->fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config,
+       a->fe_adap[0].fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config,
                        &a->dev->i2c_adap, STV090x_DEMODULATOR_0);
 
-       if (a->fe) {
+       if (a->fe_adap[0].fe) {
                struct stv6110x_devctl *ctl;
 
                ctl = dvb_attach(stv6110x_attach,
-                               a->fe,
+                               a->fe_adap[0].fe,
                                &technisat_usb2_stv6110x_config,
                                &a->dev->i2c_adap);
 
@@ -532,8 +532,8 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
                        /* call the init function once to initialize
                           tuner's clock output divider and demod's
                           master clock */
-                       if (a->fe->ops.init)
-                               a->fe->ops.init(a->fe);
+                       if (a->fe_adap[0].fe->ops.init)
+                               a->fe_adap[0].fe->ops.init(a->fe_adap[0].fe);
 
                        if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0)
                                return -EAGAIN;
@@ -548,20 +548,20 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
                        if (ret != 0)
                                err("could not set IF_CLK to external");
 
-                       a->fe->ops.set_voltage = technisat_usb2_set_voltage;
+                       a->fe_adap[0].fe->ops.set_voltage = technisat_usb2_set_voltage;
 
                        /* if everything was successful assign a nice name to the frontend */
-                       strlcpy(a->fe->ops.info.name, a->dev->desc->name,
-                                       sizeof(a->fe->ops.info.name));
+                       strlcpy(a->fe_adap[0].fe->ops.info.name, a->dev->desc->name,
+                                       sizeof(a->fe_adap[0].fe->ops.info.name));
                } else {
-                       dvb_frontend_detach(a->fe);
-                       a->fe = NULL;
+                       dvb_frontend_detach(a->fe_adap[0].fe);
+                       a->fe_adap[0].fe = NULL;
                }
        }
 
        technisat_usb2_set_led_timer(a->dev, 1, 1);
 
-       return a->fe == NULL ? -ENODEV : 0;
+       return a->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
 /* Remote control */
@@ -697,6 +697,8 @@ static struct dvb_usb_device_properties technisat_usb2_devices = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .frontend_attach  = technisat_usb2_frontend_attach,
 
                        .stream = {
@@ -711,7 +713,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = {
                                        }
                                }
                        },
-
+               }},
                        .size_of_priv = 0,
                },
        },
index 0d4709f..ea4eab8 100644 (file)
 #include "tda826x.h"
 #include "tda10086.h"
 #include "tda1002x.h"
+#include "tda10048.h"
 #include "tda827x.h"
 #include "lnbp21.h"
+/* CA */
+#include "dvb_ca_en50221.h"
 
 /* debug */
 static int dvb_usb_ttusb2_debug;
 #define deb_info(args...)   dprintk(dvb_usb_ttusb2_debug,0x01,args)
 module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS);
+static int dvb_usb_ttusb2_debug_ci;
+module_param_named(debug_ci,dvb_usb_ttusb2_debug_ci, int, 0644);
+MODULE_PARM_DESC(debug_ci, "set debugging ci." DVB_USB_DEBUG_STATUS);
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
+#define ci_dbg(format, arg...)                \
+do {                                          \
+       if (dvb_usb_ttusb2_debug_ci)                                    \
+               printk(KERN_DEBUG DVB_USB_LOG_PREFIX \
+                       ": %s " format "\n" , __func__, ## arg);       \
+} while (0)
+
+enum {
+       TT3650_CMD_CI_TEST = 0x40,
+       TT3650_CMD_CI_RD_CTRL,
+       TT3650_CMD_CI_WR_CTRL,
+       TT3650_CMD_CI_RD_ATTR,
+       TT3650_CMD_CI_WR_ATTR,
+       TT3650_CMD_CI_RESET,
+       TT3650_CMD_CI_SET_VIDEO_PORT
+};
+
 struct ttusb2_state {
+       struct dvb_ca_en50221 ca;
+       struct mutex ca_mutex;
        u8 id;
        u16 last_rc_key;
 };
@@ -78,11 +103,260 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
        return 0;
 }
 
+/* ci */
+static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
+{
+       int ret;
+       u8 rx[60];/* (64 -4) */
+       ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len);
+       if (!ret)
+               memcpy(data, rx, read_len);
+       return ret;
+}
+
+static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
+{
+       struct dvb_usb_device *d = ca->data;
+       struct ttusb2_state *state = d->priv;
+       int ret;
+
+       mutex_lock(&state->ca_mutex);
+       ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
+       mutex_unlock(&state->ca_mutex);
+
+       return ret;
+}
+
+static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
+{
+       u8 buf[3];
+       int ret = 0;
+
+       if (slot)
+               return -EINVAL;
+
+       buf[0] = (address >> 8) & 0x0F;
+       buf[1] = address;
+
+
+       ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
+
+       ci_dbg("%04x -> %d 0x%02x", address, ret, buf[2]);
+
+       if (ret < 0)
+               return ret;
+
+       return buf[2];
+}
+
+static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
+{
+       u8 buf[3];
+
+       ci_dbg("%d 0x%04x 0x%02x", slot, address, value);
+
+       if (slot)
+               return -EINVAL;
+
+       buf[0] = (address >> 8) & 0x0F;
+       buf[1] = address;
+       buf[2] = value;
+
+       return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
+}
+
+static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
+{
+       u8 buf[2];
+       int ret;
+
+       if (slot)
+               return -EINVAL;
+
+       buf[0] = address & 3;
+
+       ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
+
+       ci_dbg("0x%02x -> %d 0x%02x", address, ret, buf[1]);
+
+       if (ret < 0)
+               return ret;
+
+       return buf[1];
+}
+
+static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
+{
+       u8 buf[2];
+
+       ci_dbg("%d 0x%02x 0x%02x", slot, address, value);
+
+       if (slot)
+               return -EINVAL;
+
+       buf[0] = address;
+       buf[1] = value;
+
+       return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
+}
+
+static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int slot, int enable)
+{
+       u8 buf[1];
+       int ret;
+
+       ci_dbg("%d %d", slot, enable);
+
+       if (slot)
+               return -EINVAL;
+
+       buf[0] = enable;
+
+       ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+       if (ret < 0)
+               return ret;
+
+       if (enable != buf[0]) {
+               err("CI not %sabled.", enable ? "en" : "dis");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+       return tt3650_ci_set_video_port(ca, slot, 0);
+}
+
+static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+       return tt3650_ci_set_video_port(ca, slot, 1);
+}
+
+static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct dvb_usb_device *d = ca->data;
+       struct ttusb2_state *state = d->priv;
+       u8 buf[1];
+       int ret;
+
+       ci_dbg("%d", slot);
+
+       if (slot)
+               return -EINVAL;
+
+       buf[0] = 0;
+
+       mutex_lock(&state->ca_mutex);
+
+       ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+       if (ret)
+               goto failed;
+
+       msleep(500);
+
+       buf[0] = 1;
+
+       ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+       if (ret)
+               goto failed;
+
+       msleep(500);
+
+       buf[0] = 0; /* FTA */
+
+       ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+
+       msleep(1100);
+
+ failed:
+       mutex_unlock(&state->ca_mutex);
+
+       return ret;
+}
+
+static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+       u8 buf[1];
+       int ret;
+
+       if (slot)
+               return -EINVAL;
+
+       ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
+       if (ret)
+               return ret;
+
+       if (1 == buf[0]) {
+               return DVB_CA_EN50221_POLL_CAM_PRESENT |
+                       DVB_CA_EN50221_POLL_CAM_READY;
+       }
+       return 0;
+}
+
+static void tt3650_ci_uninit(struct dvb_usb_device *d)
+{
+       struct ttusb2_state *state;
+
+       ci_dbg("");
+
+       if (NULL == d)
+               return;
+
+       state = d->priv;
+       if (NULL == state)
+               return;
+
+       if (NULL == state->ca.data)
+               return;
+
+       dvb_ca_en50221_release(&state->ca);
+
+       memset(&state->ca, 0, sizeof(state->ca));
+}
+
+static int tt3650_ci_init(struct dvb_usb_adapter *a)
+{
+       struct dvb_usb_device *d = a->dev;
+       struct ttusb2_state *state = d->priv;
+       int ret;
+
+       ci_dbg("");
+
+       mutex_init(&state->ca_mutex);
+
+       state->ca.owner = THIS_MODULE;
+       state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
+       state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
+       state->ca.read_cam_control = tt3650_ci_read_cam_control;
+       state->ca.write_cam_control = tt3650_ci_write_cam_control;
+       state->ca.slot_reset = tt3650_ci_slot_reset;
+       state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
+       state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
+       state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
+       state->ca.data = d;
+
+       ret = dvb_ca_en50221_init(&a->dvb_adap,
+                                 &state->ca,
+                                 /* flags */ 0,
+                                 /* n_slots */ 1);
+       if (ret) {
+               err("Cannot initialize CI: Error %d.", ret);
+               memset(&state->ca, 0, sizeof(state->ca));
+               return ret;
+       }
+
+       info("CI initialized.");
+
+       return 0;
+}
+
 static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        static u8 obuf[60], ibuf[60];
-       int i,read;
+       int i, write_read, read;
 
        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
@@ -91,28 +365,35 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
                warn("more than 2 i2c messages at a time is not handled yet. TODO.");
 
        for (i = 0; i < num; i++) {
-               read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+               write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+               read = msg[i].flags & I2C_M_RD;
 
-               obuf[0] = (msg[i].addr << 1) | read;
-               obuf[1] = msg[i].len;
+               obuf[0] = (msg[i].addr << 1) | (write_read | read);
+               if (read)
+                       obuf[1] = 0;
+               else
+                       obuf[1] = msg[i].len;
 
                /* read request */
-               if (read)
+               if (write_read)
                        obuf[2] = msg[i+1].len;
+               else if (read)
+                       obuf[2] = msg[i].len;
                else
                        obuf[2] = 0;
 
-               memcpy(&obuf[3],msg[i].buf,msg[i].len);
+               memcpy(&obuf[3], msg[i].buf, msg[i].len);
 
                if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) {
                        err("i2c transfer failed.");
                        break;
                }
 
-               if (read) {
-                       memcpy(msg[i+1].buf,&ibuf[3],msg[i+1].len);
+               if (write_read) {
+                       memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len);
                        i++;
-               }
+               } else if (read)
+                       memcpy(msg[i].buf, &ibuf[3], msg[i].len);
        }
 
        mutex_unlock(&d->i2c_mutex);
@@ -190,12 +471,31 @@ static struct tda10023_config tda10023_config = {
        .deltaf = 0xa511,
 };
 
+static struct tda10048_config tda10048_config = {
+       .demod_address    = 0x10 >> 1,
+       .output_mode      = TDA10048_PARALLEL_OUTPUT,
+       .inversion        = TDA10048_INVERSION_ON,
+       .dtv6_if_freq_khz = TDA10048_IF_4000,
+       .dtv7_if_freq_khz = TDA10048_IF_4500,
+       .dtv8_if_freq_khz = TDA10048_IF_5000,
+       .clk_freq_khz     = TDA10048_CLK_16000,
+       .no_firmware      = 1,
+       .set_pll          = true ,
+       .pll_m            = 5,
+       .pll_n            = 3,
+       .pll_p            = 0,
+};
+
+static struct tda827x_config tda827x_config = {
+       .config = 0,
+};
+
 static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
 {
        if (usb_set_interface(adap->dev->udev,0,3) < 0)
                err("set interface to alts=3 failed");
 
-       if ((adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
+       if ((adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
                deb_info("TDA10086 attach failed\n");
                return -ENODEV;
        }
@@ -203,20 +503,57 @@ static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+       return adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, enable);
+}
+
 static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
 {
        if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
                err("set interface to alts=3 failed");
-       if ((adap->fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) {
-               deb_info("TDA10023 attach failed\n");
-               return -ENODEV;
+
+       if (adap->fe_adap[0].fe == NULL) {
+               /* FE 0 DVB-C */
+               adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
+                       &tda10023_config, &adap->dev->i2c_adap, 0x48);
+
+               if (adap->fe_adap[0].fe == NULL) {
+                       deb_info("TDA10023 attach failed\n");
+                       return -ENODEV;
+               }
+               tt3650_ci_init(adap);
+       } else {
+               adap->fe_adap[1].fe = dvb_attach(tda10048_attach,
+                       &tda10048_config, &adap->dev->i2c_adap);
+
+               if (adap->fe_adap[1].fe == NULL) {
+                       deb_info("TDA10048 attach failed\n");
+                       return -ENODEV;
+               }
+
+               /* tuner is behind TDA10023 I2C-gate */
+               adap->fe_adap[1].fe->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl;
+
        }
+
        return 0;
 }
 
 static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
 {
-       if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) {
+       struct dvb_frontend *fe;
+
+       /* MFE: select correct FE to attach tuner since that's called twice */
+       if (adap->fe_adap[1].fe == NULL)
+               fe = adap->fe_adap[0].fe;
+       else
+               fe = adap->fe_adap[1].fe;
+
+       /* attach tuner */
+       if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) {
                printk(KERN_ERR "%s: No tda827x found!\n", __func__);
                return -ENODEV;
        }
@@ -225,12 +562,12 @@ static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
 
 static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap)
 {
-       if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
+       if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
                deb_info("TDA8263 attach failed\n");
                return -ENODEV;
        }
 
-       if (dvb_attach(lnbp21_attach, adap->fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
+       if (dvb_attach(lnbp21_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
                deb_info("LNBP21 attach failed\n");
                return -ENODEV;
        }
@@ -242,6 +579,14 @@ static struct dvb_usb_device_properties ttusb2_properties;
 static struct dvb_usb_device_properties ttusb2_properties_s2400;
 static struct dvb_usb_device_properties ttusb2_properties_ct3650;
 
+static void ttusb2_usb_disconnect(struct usb_interface *intf)
+{
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+
+       tt3650_ci_uninit(d);
+       dvb_usb_device_exit(intf);
+}
+
 static int ttusb2_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
@@ -277,6 +622,8 @@ static struct dvb_usb_device_properties ttusb2_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = NULL, // ttusb2_streaming_ctrl,
 
                        .frontend_attach  = ttusb2_frontend_tda10086_attach,
@@ -295,6 +642,7 @@ static struct dvb_usb_device_properties ttusb2_properties = {
                                        }
                                }
                        }
+               }},
                }
        },
 
@@ -329,6 +677,8 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = NULL,
 
                        .frontend_attach  = ttusb2_frontend_tda10086_attach,
@@ -347,6 +697,7 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
                                        }
                                }
                        }
+               }},
                }
        },
 
@@ -383,6 +734,27 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 2,
+               .fe = {{
+                       .streaming_ctrl   = NULL,
+
+                       .frontend_attach  = ttusb2_frontend_tda10023_attach,
+                       .tuner_attach = ttusb2_tuner_tda827x_attach,
+
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_ISOC,
+                               .count = 5,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .isoc = {
+                                               .framesperurb = 4,
+                                               .framesize = 940,
+                                               .interval = 1,
+                                       }
+                               }
+                       }
+               }, {
                        .streaming_ctrl   = NULL,
 
                        .frontend_attach  = ttusb2_frontend_tda10023_attach,
@@ -401,6 +773,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
                                        }
                                }
                        }
+               }},
                },
        },
 
@@ -422,7 +795,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
 static struct usb_driver ttusb2_driver = {
        .name           = "dvb_usb_ttusb2",
        .probe          = ttusb2_probe,
-       .disconnect = dvb_usb_device_exit,
+       .disconnect     = ttusb2_usb_disconnect,
        .id_table       = ttusb2_table,
 };
 
index 118aab1..463673a 100644 (file)
@@ -60,14 +60,14 @@ static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap)
        umt_config.demod_init = umt_mt352_demod_init;
        umt_config.demod_address = 0xf;
 
-       adap->fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap);
+       adap->fe_adap[0].fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap);
 
        return 0;
 }
 
 static int umt_tuner_attach (struct dvb_usb_adapter *adap)
 {
-       dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034);
+       dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_TUA6034);
        return 0;
 }
 
@@ -100,6 +100,8 @@ static struct dvb_usb_device_properties umt_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .streaming_ctrl   = dibusb2_0_streaming_ctrl,
                        .frontend_attach  = umt_mt352_frontend_attach,
                        .tuner_attach     = umt_tuner_attach,
@@ -115,7 +117,7 @@ static struct dvb_usb_device_properties umt_properties = {
                                        }
                                }
                        },
-
+               }},
                        .size_of_priv     = sizeof(struct dibusb_state),
                }
        },
index 86d6893..d62ee0f 100644 (file)
@@ -148,7 +148,7 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream)
                if (!stream->urb_list[i]) {
                        deb_mem("not enough memory for urb_alloc_urb!.\n");
                        for (j = 0; j < i; j++)
-                               usb_free_urb(stream->urb_list[i]);
+                               usb_free_urb(stream->urb_list[j]);
                        return -ENOMEM;
                }
                usb_fill_bulk_urb( stream->urb_list[i], stream->udev,
@@ -181,7 +181,7 @@ static int usb_isoc_urb_init(struct usb_data_stream *stream)
                if (!stream->urb_list[i]) {
                        deb_mem("not enough memory for urb_alloc_urb!\n");
                        for (j = 0; j < i; j++)
-                               usb_free_urb(stream->urb_list[i]);
+                               usb_free_urb(stream->urb_list[j]);
                        return -ENOMEM;
                }
 
index 54355f8..45e31f2 100644 (file)
@@ -320,7 +320,7 @@ static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
 
        vp702x_init_pid_filter(adap);
 
-       adap->fe = vp702x_fe_attach(adap->dev);
+       adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev);
        vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
 
        return 0;
@@ -383,6 +383,8 @@ static struct dvb_usb_device_properties vp702x_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .caps             = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
 
                        .streaming_ctrl   = vp702x_streaming_ctrl,
@@ -399,6 +401,7 @@ static struct dvb_usb_device_properties vp702x_properties = {
                                        }
                                }
                        },
+               }},
                        .size_of_priv     = sizeof(struct vp702x_adapter_state),
                }
        },
index 536c16c..90873af 100644 (file)
@@ -214,7 +214,7 @@ static int vp7045_frontend_attach(struct dvb_usb_adapter *adap)
 /*     Dump the EEPROM */
 /*     vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */
 
-       adap->fe = vp7045_fe_attach(adap->dev);
+       adap->fe_adap[0].fe = vp7045_fe_attach(adap->dev);
 
        return 0;
 }
@@ -245,6 +245,8 @@ static struct dvb_usb_device_properties vp7045_properties = {
        .num_adapters = 1,
        .adapter = {
                {
+               .num_frontends = 1,
+               .fe = {{
                        .frontend_attach  = vp7045_frontend_attach,
                        /* parameter for the MPEG2-data transfer */
                        .stream = {
@@ -257,6 +259,7 @@ static struct dvb_usb_device_properties vp7045_properties = {
                                        }
                                }
                        },
+               }},
                }
        },
        .power_ctrl       = vp7045_power_ctrl,
index 32e08e3..4a2d2e6 100644 (file)
@@ -236,6 +236,13 @@ config DVB_MB86A16
          A DVB-S/DSS Direct Conversion reveiver.
          Say Y when you want to support this frontend.
 
+config DVB_TDA10071
+       tristate "NXP TDA10071"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         Say Y when you want to support this frontend.
+
 comment "DVB-T (terrestrial) frontends"
        depends on DVB_CORE
 
@@ -600,6 +607,16 @@ config DVB_LNBP21
        help
          An SEC control chips.
 
+config DVB_LNBP22
+       tristate "LNBP22 SEC controllers"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         LNB power supply and control voltage
+         regulator chip with step-up converter
+         and I2C interface.
+         Say Y when you want to support this chip.
+
 config DVB_ISL6405
        tristate "ISL6405 SEC controller"
        depends on DVB_CORE && I2C
@@ -621,6 +638,11 @@ config DVB_ISL6423
        help
          A SEC controller chip from Intersil
 
+config DVB_A8293
+       tristate "Allegro A8293"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+
 config DVB_LGS8GL5
        tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
        depends on DVB_CORE && I2C
@@ -661,6 +683,14 @@ config DVB_IX2505V
        help
          A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_IT913X_FE
+       tristate "it913x frontend and it9137 tuner"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-T tuner module.
+         Say Y when you want to support this frontend.
+
 comment "Tools to develop new frontends"
 
 config DVB_DUMMY_FE
index 6a6ba05..f639f67 100644 (file)
@@ -2,8 +2,8 @@
 # Makefile for the kernel DVB frontend device drivers.
 #
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
-EXTRA_CFLAGS += -Idrivers/media/common/tuners/
+ccflags-y += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/common/tuners/
 
 stb0899-objs = stb0899_drv.o stb0899_algo.o
 stv0900-objs = stv0900_core.o stv0900_sw.o
@@ -52,6 +52,7 @@ obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
 obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
 obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
 obj-$(CONFIG_DVB_ISL6405) += isl6405.o
 obj-$(CONFIG_DVB_ISL6421) += isl6421.o
 obj-$(CONFIG_DVB_TDA10086) += tda10086.o
@@ -91,4 +92,7 @@ obj-$(CONFIG_DVB_STV0367) += stv0367.o
 obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
 obj-$(CONFIG_DVB_DRXK) += drxk.o
 obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
+obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
+obj-$(CONFIG_DVB_A8293) += a8293.o
+obj-$(CONFIG_DVB_TDA10071) += tda10071.o
 
diff --git a/drivers/media/dvb/frontends/a8293.c b/drivers/media/dvb/frontends/a8293.c
new file mode 100644 (file)
index 0000000..bb56497
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Allegro A8293 SEC driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dvb_frontend.h"
+#include "a8293.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define LOG_PREFIX "a8293"
+
+#undef dbg
+#define dbg(f, arg...) \
+       if (debug) \
+               printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+
+struct a8293_priv {
+       struct i2c_adapter *i2c;
+       const struct a8293_config *cfg;
+       u8 reg[2];
+};
+
+static int a8293_i2c(struct a8293_priv *priv, u8 *val, int len, bool rd)
+{
+       int ret;
+       struct i2c_msg msg[1] = {
+               {
+                       .addr = priv->cfg->i2c_addr,
+                       .len = len,
+                       .buf = val,
+               }
+       };
+
+       if (rd)
+               msg[0].flags = I2C_M_RD;
+       else
+               msg[0].flags = 0;
+
+       ret = i2c_transfer(priv->i2c, msg, 1);
+       if (ret == 1) {
+               ret = 0;
+       } else {
+               warn("i2c failed=%d rd=%d", ret, rd);
+               ret = -EREMOTEIO;
+       }
+
+       return ret;
+}
+
+static int a8293_wr(struct a8293_priv *priv, u8 *val, int len)
+{
+       return a8293_i2c(priv, val, len, 0);
+}
+
+static int a8293_rd(struct a8293_priv *priv, u8 *val, int len)
+{
+       return a8293_i2c(priv, val, len, 1);
+}
+
+static int a8293_set_voltage(struct dvb_frontend *fe,
+       fe_sec_voltage_t fe_sec_voltage)
+{
+       struct a8293_priv *priv = fe->sec_priv;
+       int ret;
+
+       dbg("%s: fe_sec_voltage=%d", __func__, fe_sec_voltage);
+
+       switch (fe_sec_voltage) {
+       case SEC_VOLTAGE_OFF:
+               /* ENB=0 */
+               priv->reg[0] = 0x10;
+               break;
+       case SEC_VOLTAGE_13:
+               /* VSEL0=1, VSEL1=0, VSEL2=0, VSEL3=0, ENB=1*/
+               priv->reg[0] = 0x31;
+               break;
+       case SEC_VOLTAGE_18:
+               /* VSEL0=0, VSEL1=0, VSEL2=0, VSEL3=1, ENB=1*/
+               priv->reg[0] = 0x38;
+               break;
+       default:
+               ret = -EINVAL;
+               goto err;
+       };
+
+       ret = a8293_wr(priv, &priv->reg[0], 1);
+       if (ret)
+               goto err;
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static void a8293_release_sec(struct dvb_frontend *fe)
+{
+       dbg("%s:", __func__);
+
+       a8293_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+       kfree(fe->sec_priv);
+       fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, const struct a8293_config *cfg)
+{
+       int ret;
+       struct a8293_priv *priv = NULL;
+       u8 buf[2];
+
+       /* allocate memory for the internal priv */
+       priv = kzalloc(sizeof(struct a8293_priv), GFP_KERNEL);
+       if (priv == NULL) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       /* setup the priv */
+       priv->i2c = i2c;
+       priv->cfg = cfg;
+       fe->sec_priv = priv;
+
+       /* check if the SEC is there */
+       ret = a8293_rd(priv, buf, 2);
+       if (ret)
+               goto err;
+
+       /* ENB=0 */
+       priv->reg[0] = 0x10;
+       ret = a8293_wr(priv, &priv->reg[1], 1);
+       if (ret)
+               goto err;
+
+       /* TMODE=0, TGATE=1 */
+       priv->reg[1] = 0x82;
+       ret = a8293_wr(priv, &priv->reg[1], 1);
+       if (ret)
+               goto err;
+
+       info("Allegro A8293 SEC attached.");
+
+       fe->ops.release_sec = a8293_release_sec;
+
+       /* override frontend ops */
+       fe->ops.set_voltage = a8293_set_voltage;
+
+       return fe;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       kfree(priv);
+       return NULL;
+}
+EXPORT_SYMBOL(a8293_attach);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Allegro A8293 SEC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/a8293.h b/drivers/media/dvb/frontends/a8293.h
new file mode 100644 (file)
index 0000000..ed29e55
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Allegro A8293 SEC driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef A8293_H
+#define A8293_H
+
+struct a8293_config {
+       u8 i2c_addr;
+};
+
+#if defined(CONFIG_DVB_A8293) || \
+       (defined(CONFIG_DVB_A8293_MODULE) && defined(MODULE))
+extern struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, const struct a8293_config *cfg);
+#else
+static inline struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, const struct a8293_config *cfg)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif /* A8293_H */
index 2906582..03cab7b 100644 (file)
@@ -93,9 +93,6 @@ extern struct dvb_frontend *cxd2820r_attach(
        struct i2c_adapter *i2c,
        struct dvb_frontend *fe
 );
-extern struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(
-       struct dvb_frontend *fe
-);
 #else
 static inline struct dvb_frontend *cxd2820r_attach(
        const struct cxd2820r_config *config,
@@ -106,12 +103,6 @@ static inline struct dvb_frontend *cxd2820r_attach(
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
-static inline struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(
-       struct dvb_frontend *fe
-)
-{
-       return NULL;
-}
 
 #endif
 
index 3c07d40..b85f501 100644 (file)
@@ -335,4 +335,3 @@ int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
 
        return 0;
 }
-
index d416e85..036480f 100644 (file)
@@ -727,72 +727,22 @@ static void cxd2820r_release(struct dvb_frontend *fe)
        struct cxd2820r_priv *priv = fe->demodulator_priv;
        dbg("%s", __func__);
 
-       if (fe->ops.info.type == FE_OFDM) {
-               i2c_del_adapter(&priv->tuner_i2c_adapter);
+       if (fe->ops.info.type == FE_OFDM)
                kfree(priv);
-       }
 
        return;
 }
 
-static u32 cxd2820r_tuner_i2c_func(struct i2c_adapter *adapter)
-{
-       return I2C_FUNC_I2C;
-}
-
-static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
-       struct i2c_msg msg[], int num)
-{
-       struct cxd2820r_priv *priv = i2c_get_adapdata(i2c_adap);
-       int ret;
-       u8 *obuf = kmalloc(msg[0].len + 2, GFP_KERNEL);
-       struct i2c_msg msg2[2] = {
-               {
-                       .addr = priv->cfg.i2c_address,
-                       .flags = 0,
-                       .len = msg[0].len + 2,
-                       .buf = obuf,
-               }, {
-                       .addr = priv->cfg.i2c_address,
-                       .flags = I2C_M_RD,
-                       .len = msg[1].len,
-                       .buf = msg[1].buf,
-               }
-       };
-
-       if (!obuf)
-               return -ENOMEM;
-
-       obuf[0] = 0x09;
-       obuf[1] = (msg[0].addr << 1);
-       if (num == 2) { /* I2C read */
-               obuf[1] = (msg[0].addr << 1) | I2C_M_RD; /* I2C RD flag */
-               msg2[0].len = msg[0].len + 2 - 1; /* '-1' maybe HW bug ? */
-       }
-       memcpy(&obuf[2], msg[0].buf, msg[0].len);
-
-       ret = i2c_transfer(priv->i2c, msg2, num);
-       if (ret < 0)
-               warn("tuner i2c failed ret:%d", ret);
-
-       kfree(obuf);
-
-       return ret;
-}
-
-static struct i2c_algorithm cxd2820r_tuner_i2c_algo = {
-       .master_xfer   = cxd2820r_tuner_i2c_xfer,
-       .functionality = cxd2820r_tuner_i2c_func,
-};
-
-struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
        struct cxd2820r_priv *priv = fe->demodulator_priv;
-       return &priv->tuner_i2c_adapter;
+       dbg("%s: %d", __func__, enable);
+
+       /* Bit 0 of reg 0xdb in bank 0x00 controls I2C repeater */
+       return cxd2820r_wr_reg_mask(priv, 0xdb, enable ? 1 : 0, 0x1);
 }
-EXPORT_SYMBOL(cxd2820r_get_tuner_i2c_adapter);
 
-static struct dvb_frontend_ops cxd2820r_ops[2];
+static const struct dvb_frontend_ops cxd2820r_ops[2];
 
 struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
        struct i2c_adapter *i2c, struct dvb_frontend *fe)
@@ -831,18 +781,6 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
                priv->fe[0].demodulator_priv = priv;
                priv->fe[1].demodulator_priv = priv;
 
-               /* create tuner i2c adapter */
-               strlcpy(priv->tuner_i2c_adapter.name,
-                       "CXD2820R tuner I2C adapter",
-                       sizeof(priv->tuner_i2c_adapter.name));
-               priv->tuner_i2c_adapter.algo = &cxd2820r_tuner_i2c_algo;
-               priv->tuner_i2c_adapter.algo_data = NULL;
-               i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
-               if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
-                       err("tuner I2C bus could not be initialized");
-                       goto error;
-               }
-
                return &priv->fe[0];
 
        } else {
@@ -858,7 +796,7 @@ error:
 }
 EXPORT_SYMBOL(cxd2820r_attach);
 
-static struct dvb_frontend_ops cxd2820r_ops[2] = {
+static const struct dvb_frontend_ops cxd2820r_ops[2] = {
        {
                /* DVB-T/T2 */
                .info = {
@@ -883,6 +821,7 @@ static struct dvb_frontend_ops cxd2820r_ops[2] = {
                .sleep = cxd2820r_sleep,
 
                .get_tune_settings = cxd2820r_get_tune_settings,
+               .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl,
 
                .get_frontend = cxd2820r_get_frontend,
 
@@ -911,6 +850,7 @@ static struct dvb_frontend_ops cxd2820r_ops[2] = {
                .sleep = cxd2820r_sleep,
 
                .get_tune_settings = cxd2820r_get_tune_settings,
+               .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl,
 
                .set_frontend = cxd2820r_set_frontend,
                .get_frontend = cxd2820r_get_frontend,
index 0c0ebc9..9553913 100644 (file)
@@ -50,7 +50,6 @@ struct cxd2820r_priv {
        struct i2c_adapter *i2c;
        struct dvb_frontend fe[2];
        struct cxd2820r_config cfg;
-       struct i2c_adapter tuner_i2c_adapter;
 
        struct mutex fe_lock; /* FE lock */
        int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */
index 6582564..a04f9c8 100644 (file)
@@ -446,4 +446,3 @@ int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
 
        return 0;
 }
-
index c47b35c..6548588 100644 (file)
@@ -420,4 +420,3 @@ int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,
 
        return 0;
 }
-
index 1d47d4d..dc1cb17 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 
@@ -78,10 +79,18 @@ struct dib0070_state {
        struct i2c_msg msg[2];
        u8 i2c_write_buffer[3];
        u8 i2c_read_buffer[2];
+       struct mutex i2c_buffer_lock;
 };
 
-static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
+static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
 {
+       u16 ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return 0;
+       }
+
        state->i2c_write_buffer[0] = reg;
 
        memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
@@ -96,13 +105,23 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
 
        if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
                printk(KERN_WARNING "DiB0070 I2C read failed\n");
-               return 0;
-       }
-       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+               ret = 0;
+       } else
+               ret = (state->i2c_read_buffer[0] << 8)
+                       | state->i2c_read_buffer[1];
+
+       mutex_unlock(&state->i2c_buffer_lock);
+       return ret;
 }
 
 static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
 {
+       int ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return -EINVAL;
+       }
        state->i2c_write_buffer[0] = reg;
        state->i2c_write_buffer[1] = val >> 8;
        state->i2c_write_buffer[2] = val & 0xff;
@@ -115,9 +134,12 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
 
        if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
                printk(KERN_WARNING "DiB0070 I2C write failed\n");
-               return -EREMOTEIO;
-       }
-       return 0;
+               ret = -EREMOTEIO;
+       } else
+               ret = 0;
+
+       mutex_unlock(&state->i2c_buffer_lock);
+       return ret;
 }
 
 #define HARD_RESET(state) do { \
@@ -734,6 +756,7 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter
        state->cfg = cfg;
        state->i2c = i2c;
        state->fe  = fe;
+       mutex_init(&state->i2c_buffer_lock);
        fe->tuner_priv = state;
 
        if (dib0070_reset(fe) != 0)
index c9c935a..b174d1c 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 
@@ -196,6 +197,7 @@ struct dib0090_state {
        struct i2c_msg msg[2];
        u8 i2c_write_buffer[3];
        u8 i2c_read_buffer[2];
+       struct mutex i2c_buffer_lock;
 };
 
 struct dib0090_fw_state {
@@ -208,10 +210,18 @@ struct dib0090_fw_state {
        struct i2c_msg msg;
        u8 i2c_write_buffer[2];
        u8 i2c_read_buffer[2];
+       struct mutex i2c_buffer_lock;
 };
 
 static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
 {
+       u16 ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return 0;
+       }
+
        state->i2c_write_buffer[0] = reg;
 
        memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
@@ -226,14 +236,24 @@ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
 
        if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
                printk(KERN_WARNING "DiB0090 I2C read failed\n");
-               return 0;
-       }
+               ret = 0;
+       } else
+               ret = (state->i2c_read_buffer[0] << 8)
+                       | state->i2c_read_buffer[1];
 
-       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+       mutex_unlock(&state->i2c_buffer_lock);
+       return ret;
 }
 
 static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
 {
+       int ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return -EINVAL;
+       }
+
        state->i2c_write_buffer[0] = reg & 0xff;
        state->i2c_write_buffer[1] = val >> 8;
        state->i2c_write_buffer[2] = val & 0xff;
@@ -246,13 +266,23 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
 
        if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
                printk(KERN_WARNING "DiB0090 I2C write failed\n");
-               return -EREMOTEIO;
-       }
-       return 0;
+               ret = -EREMOTEIO;
+       } else
+               ret = 0;
+
+       mutex_unlock(&state->i2c_buffer_lock);
+       return ret;
 }
 
 static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
 {
+       u16 ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return 0;
+       }
+
        state->i2c_write_buffer[0] = reg;
 
        memset(&state->msg, 0, sizeof(struct i2c_msg));
@@ -262,13 +292,24 @@ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
        state->msg.len = 2;
        if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
                printk(KERN_WARNING "DiB0090 I2C read failed\n");
-               return 0;
-       }
-       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+               ret = 0;
+       } else
+               ret = (state->i2c_read_buffer[0] << 8)
+                       | state->i2c_read_buffer[1];
+
+       mutex_unlock(&state->i2c_buffer_lock);
+       return ret;
 }
 
 static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
 {
+       int ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return -EINVAL;
+       }
+
        state->i2c_write_buffer[0] = val >> 8;
        state->i2c_write_buffer[1] = val & 0xff;
 
@@ -279,9 +320,12 @@ static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
        state->msg.len = 2;
        if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
                printk(KERN_WARNING "DiB0090 I2C write failed\n");
-               return -EREMOTEIO;
-       }
-       return 0;
+               ret = -EREMOTEIO;
+       } else
+               ret = 0;
+
+       mutex_unlock(&state->i2c_buffer_lock);
+       return ret;
 }
 
 #define HARD_RESET(state) do {  if (cfg->reset) {  if (cfg->sleep) cfg->sleep(fe, 0); msleep(10);  cfg->reset(fe, 1); msleep(10);  cfg->reset(fe, 0); msleep(10);  }  } while (0)
@@ -2440,6 +2484,7 @@ struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapte
        st->config = config;
        st->i2c = i2c;
        st->fe = fe;
+       mutex_init(&st->i2c_buffer_lock);
        fe->tuner_priv = st;
 
        if (config->wbd == NULL)
@@ -2471,6 +2516,7 @@ struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_ada
        st->config = config;
        st->i2c = i2c;
        st->fe = fe;
+       mutex_init(&st->i2c_buffer_lock);
        fe->tuner_priv = st;
 
        if (dib0090_fw_reset_digital(fe, st->config) != 0)
index 79cb1c2..dbb76d7 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 
@@ -55,6 +56,7 @@ struct dib7000m_state {
        struct i2c_msg msg[2];
        u8 i2c_write_buffer[4];
        u8 i2c_read_buffer[2];
+       struct mutex i2c_buffer_lock;
 };
 
 enum dib7000m_power_mode {
@@ -69,6 +71,13 @@ enum dib7000m_power_mode {
 
 static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
 {
+       u16 ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return 0;
+       }
+
        state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
        state->i2c_write_buffer[1] = reg & 0xff;
 
@@ -85,11 +94,21 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
        if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
                dprintk("i2c read error on %d",reg);
 
-       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+       ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+       mutex_unlock(&state->i2c_buffer_lock);
+
+       return ret;
 }
 
 static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
 {
+       int ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return -EINVAL;
+       }
+
        state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
        state->i2c_write_buffer[1] = reg & 0xff;
        state->i2c_write_buffer[2] = (val >> 8) & 0xff;
@@ -101,7 +120,10 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
        state->msg[0].buf = state->i2c_write_buffer;
        state->msg[0].len = 4;
 
-       return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
+       ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
+                       -EREMOTEIO : 0);
+       mutex_unlock(&state->i2c_buffer_lock);
+       return ret;
 }
 static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
 {
@@ -1385,6 +1407,7 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
        demod                   = &st->demod;
        demod->demodulator_priv = st;
        memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
+       mutex_init(&st->i2c_buffer_lock);
 
        st->timf_default = cfg->bw->timf;
 
index a64a538..ce8534f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 #include "dvb_math.h"
 #include "dvb_frontend.h"
@@ -68,6 +69,7 @@ struct dib7000p_state {
        struct i2c_msg msg[2];
        u8 i2c_write_buffer[4];
        u8 i2c_read_buffer[2];
+       struct mutex i2c_buffer_lock;
 };
 
 enum dib7000p_power_mode {
@@ -81,6 +83,13 @@ static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
 
 static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
 {
+       u16 ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return 0;
+       }
+
        state->i2c_write_buffer[0] = reg >> 8;
        state->i2c_write_buffer[1] = reg & 0xff;
 
@@ -97,11 +106,20 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
        if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
                dprintk("i2c read error on %d", reg);
 
-       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+       ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+       mutex_unlock(&state->i2c_buffer_lock);
+       return ret;
 }
 
 static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
 {
+       int ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return -EINVAL;
+       }
+
        state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
        state->i2c_write_buffer[1] = reg & 0xff;
        state->i2c_write_buffer[2] = (val >> 8) & 0xff;
@@ -113,7 +131,10 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
        state->msg[0].buf = state->i2c_write_buffer;
        state->msg[0].len = 4;
 
-       return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
+       ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
+                       -EREMOTEIO : 0);
+       mutex_unlock(&state->i2c_buffer_lock);
+       return ret;
 }
 
 static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
@@ -1577,8 +1598,8 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
                return -ENOMEM;
        rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
        if (!rx) {
-               goto rx_memory_error;
                ret = -ENOMEM;
+               goto rx_memory_error;
        }
 
        msg[0].buf = tx;
@@ -1646,6 +1667,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
                return -ENOMEM;
 
        dpst->i2c_adap = i2c;
+       mutex_init(&dpst->i2c_buffer_lock);
 
        for (k = no_of_demods - 1; k >= 0; k--) {
                dpst->cfg = cfg[k];
@@ -2324,6 +2346,7 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
        demod = &st->demod;
        demod->demodulator_priv = st;
        memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
+       mutex_init(&st->i2c_buffer_lock);
 
        dib7000p_write_word(st, 1287, 0x0003);  /* sram lead in, rdy */
 
@@ -2333,8 +2356,9 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
        st->version = dib7000p_read_word(st, 897);
 
        /* FIXME: make sure the dev.parent field is initialized, or else
-               request_firmware() will hit an OOPS (this should be moved somewhere
-               more common) */
+          request_firmware() will hit an OOPS (this should be moved somewhere
+          more common) */
+       st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
 
        /* FIXME: make sure the dev.parent field is initialized, or else
           request_firmware() will hit an OOPS (this should be moved somewhere
index 7d2ea11..fe284d5 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
+
 #include "dvb_math.h"
 
 #include "dvb_frontend.h"
@@ -37,6 +39,7 @@ struct i2c_device {
        u8 addr;
        u8 *i2c_write_buffer;
        u8 *i2c_read_buffer;
+       struct mutex *i2c_buffer_lock;
 };
 
 struct dib8000_state {
@@ -77,6 +80,7 @@ struct dib8000_state {
        struct i2c_msg msg[2];
        u8 i2c_write_buffer[4];
        u8 i2c_read_buffer[2];
+       struct mutex i2c_buffer_lock;
 };
 
 enum dib8000_power_mode {
@@ -86,24 +90,39 @@ enum dib8000_power_mode {
 
 static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
 {
+       u16 ret;
        struct i2c_msg msg[2] = {
-               {.addr = i2c->addr >> 1, .flags = 0,
-                       .buf = i2c->i2c_write_buffer, .len = 2},
-               {.addr = i2c->addr >> 1, .flags = I2C_M_RD,
-                       .buf = i2c->i2c_read_buffer, .len = 2},
+               {.addr = i2c->addr >> 1, .flags = 0, .len = 2},
+               {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
        };
 
+       if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return 0;
+       }
+
+       msg[0].buf    = i2c->i2c_write_buffer;
        msg[0].buf[0] = reg >> 8;
        msg[0].buf[1] = reg & 0xff;
+       msg[1].buf    = i2c->i2c_read_buffer;
 
        if (i2c_transfer(i2c->adap, msg, 2) != 2)
                dprintk("i2c read error on %d", reg);
 
-       return (msg[1].buf[0] << 8) | msg[1].buf[1];
+       ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
+       mutex_unlock(i2c->i2c_buffer_lock);
+       return ret;
 }
 
 static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
 {
+       u16 ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return 0;
+       }
+
        state->i2c_write_buffer[0] = reg >> 8;
        state->i2c_write_buffer[1] = reg & 0xff;
 
@@ -120,7 +139,10 @@ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
        if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
                dprintk("i2c read error on %d", reg);
 
-       return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+       ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+       mutex_unlock(&state->i2c_buffer_lock);
+
+       return ret;
 }
 
 static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
@@ -135,22 +157,35 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
 
 static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
 {
-       struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0,
-               .buf = i2c->i2c_write_buffer, .len = 4};
+       struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
        int ret = 0;
 
+       if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return -EINVAL;
+       }
+
+       msg.buf    = i2c->i2c_write_buffer;
        msg.buf[0] = (reg >> 8) & 0xff;
        msg.buf[1] = reg & 0xff;
        msg.buf[2] = (val >> 8) & 0xff;
        msg.buf[3] = val & 0xff;
 
        ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+       mutex_unlock(i2c->i2c_buffer_lock);
 
        return ret;
 }
 
 static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
 {
+       int ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return -EINVAL;
+       }
+
        state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
        state->i2c_write_buffer[1] = reg & 0xff;
        state->i2c_write_buffer[2] = (val >> 8) & 0xff;
@@ -162,7 +197,11 @@ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
        state->msg[0].buf = state->i2c_write_buffer;
        state->msg[0].len = 4;
 
-       return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
+       ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
+                       -EREMOTEIO : 0);
+       mutex_unlock(&state->i2c_buffer_lock);
+
+       return ret;
 }
 
 static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
@@ -2434,8 +2473,15 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
        if (!client.i2c_read_buffer) {
                dprintk("%s: not enough memory", __func__);
                ret = -ENOMEM;
-               goto error_memory;
+               goto error_memory_read;
+       }
+       client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
+       if (!client.i2c_buffer_lock) {
+               dprintk("%s: not enough memory", __func__);
+               ret = -ENOMEM;
+               goto error_memory_lock;
        }
+       mutex_init(client.i2c_buffer_lock);
 
        for (k = no_of_demods - 1; k >= 0; k--) {
                /* designated i2c address */
@@ -2476,8 +2522,10 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
        }
 
 error:
+       kfree(client.i2c_buffer_lock);
+error_memory_lock:
        kfree(client.i2c_read_buffer);
-error_memory:
+error_memory_read:
        kfree(client.i2c_write_buffer);
 
        return ret;
@@ -2581,6 +2629,8 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s
        state->i2c.addr = i2c_addr;
        state->i2c.i2c_write_buffer = state->i2c_write_buffer;
        state->i2c.i2c_read_buffer = state->i2c_read_buffer;
+       mutex_init(&state->i2c_buffer_lock);
+       state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
        state->gpio_val = cfg->gpio_val;
        state->gpio_dir = cfg->gpio_dir;
 
index a085588..660f806 100644 (file)
@@ -38,6 +38,15 @@ struct i2c_device {
 #define DibInitLock(lock) mutex_init(lock)
 #define DibFreeLock(lock)
 
+struct dib9000_pid_ctrl {
+#define DIB9000_PID_FILTER_CTRL 0
+#define DIB9000_PID_FILTER      1
+       u8 cmd;
+       u8 id;
+       u16 pid;
+       u8 onoff;
+};
+
 struct dib9000_state {
        struct i2c_device i2c;
 
@@ -99,6 +108,10 @@ struct dib9000_state {
        struct i2c_msg msg[2];
        u8 i2c_write_buffer[255];
        u8 i2c_read_buffer[255];
+       DIB_LOCK demod_lock;
+       u8 get_frontend_internal;
+       struct dib9000_pid_ctrl pid_ctrl[10];
+       s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */
 };
 
 static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -1167,8 +1180,8 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
 
        DibAcquireLock(&state->platform.risc.mem_mbx_lock);
        if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
-               goto error;
                ret = -EIO;
+               goto error;
        }
 
        dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION,
@@ -1743,19 +1756,56 @@ EXPORT_SYMBOL(dib9000_set_gpio);
 int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
 {
        struct dib9000_state *state = fe->demodulator_priv;
-       u16 val = dib9000_read_word(state, 294 + 1) & 0xffef;
+       u16 val;
+       int ret;
+
+       if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) {
+               /* postpone the pid filtering cmd */
+               dprintk("pid filter cmd postpone");
+               state->pid_ctrl_index++;
+               state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL;
+               state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
+               return 0;
+       }
+
+       DibAcquireLock(&state->demod_lock);
+
+       val = dib9000_read_word(state, 294 + 1) & 0xffef;
        val |= (onoff & 0x1) << 4;
 
        dprintk("PID filter enabled %d", onoff);
-       return dib9000_write_word(state, 294 + 1, val);
+       ret = dib9000_write_word(state, 294 + 1, val);
+       DibReleaseLock(&state->demod_lock);
+       return ret;
+
 }
 EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl);
 
 int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
 {
        struct dib9000_state *state = fe->demodulator_priv;
+       int ret;
+
+       if (state->pid_ctrl_index != -2) {
+               /* postpone the pid filtering cmd */
+               dprintk("pid filter postpone");
+               if (state->pid_ctrl_index < 9) {
+                       state->pid_ctrl_index++;
+                       state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER;
+                       state->pid_ctrl[state->pid_ctrl_index].id = id;
+                       state->pid_ctrl[state->pid_ctrl_index].pid = pid;
+                       state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
+               } else
+                       dprintk("can not add any more pid ctrl cmd");
+               return 0;
+       }
+
+       DibAcquireLock(&state->demod_lock);
        dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
-       return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0);
+       ret = dib9000_write_word(state, 300 + 1 + id,
+                       onoff ? (1 << 13) | pid : 0);
+       DibReleaseLock(&state->demod_lock);
+       return ret;
 }
 EXPORT_SYMBOL(dib9000_fw_pid_filter);
 
@@ -1778,6 +1828,7 @@ static void dib9000_release(struct dvb_frontend *demod)
        DibFreeLock(&state->platform.risc.mbx_lock);
        DibFreeLock(&state->platform.risc.mem_lock);
        DibFreeLock(&state->platform.risc.mem_mbx_lock);
+       DibFreeLock(&state->demod_lock);
        dibx000_exit_i2c_master(&st->i2c_master);
 
        i2c_del_adapter(&st->tuner_adap);
@@ -1795,14 +1846,19 @@ static int dib9000_sleep(struct dvb_frontend *fe)
 {
        struct dib9000_state *state = fe->demodulator_priv;
        u8 index_frontend;
-       int ret;
+       int ret = 0;
 
+       DibAcquireLock(&state->demod_lock);
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
                ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
                if (ret < 0)
-                       return ret;
+                       goto error;
        }
-       return dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
+       ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
+
+error:
+       DibReleaseLock(&state->demod_lock);
+       return ret;
 }
 
 static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
@@ -1816,7 +1872,10 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
        struct dib9000_state *state = fe->demodulator_priv;
        u8 index_frontend, sub_index_frontend;
        fe_status_t stat;
-       int ret;
+       int ret = 0;
+
+       if (state->get_frontend_internal == 0)
+               DibAcquireLock(&state->demod_lock);
 
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
                state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
@@ -1846,14 +1905,15 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
                                            state->fe[index_frontend]->dtv_property_cache.rolloff;
                                }
                        }
-                       return 0;
+                       ret = 0;
+                       goto return_value;
                }
        }
 
        /* get the channel from master chip */
        ret = dib9000_fw_get_channel(fe, fep);
        if (ret != 0)
-               return ret;
+               goto return_value;
 
        /* synchronize the cache with the other frontends */
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
@@ -1866,8 +1926,12 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
                state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP;
                state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff;
        }
+       ret = 0;
 
-       return 0;
+return_value:
+       if (state->get_frontend_internal == 0)
+               DibReleaseLock(&state->demod_lock);
+       return ret;
 }
 
 static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
@@ -1912,6 +1976,10 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
                dprintk("dib9000: must specify bandwidth ");
                return 0;
        }
+
+       state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
+       DibAcquireLock(&state->demod_lock);
+
        fe->dtv_property_cache.delivery_system = SYS_DVBT;
 
        /* set the master status */
@@ -1974,13 +2042,18 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
        /* check the tune result */
        if (exit_condition == 1) {      /* tune failed */
                dprintk("tune failed");
+               DibReleaseLock(&state->demod_lock);
+               /* tune failed; put all the pid filtering cmd to junk */
+               state->pid_ctrl_index = -1;
                return 0;
        }
 
        dprintk("tune success on frontend%i", index_frontend_success);
 
        /* synchronize all the channel cache */
+       state->get_frontend_internal = 1;
        dib9000_get_frontend(state->fe[0], fep);
+       state->get_frontend_internal = 0;
 
        /* retune the other frontends with the found channel */
        channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
@@ -2025,6 +2098,28 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
        /* turn off the diversity for the last frontend */
        dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0);
 
+       DibReleaseLock(&state->demod_lock);
+       if (state->pid_ctrl_index >= 0) {
+               u8 index_pid_filter_cmd;
+               u8 pid_ctrl_index = state->pid_ctrl_index;
+
+               state->pid_ctrl_index = -2;
+               for (index_pid_filter_cmd = 0;
+                               index_pid_filter_cmd <= pid_ctrl_index;
+                               index_pid_filter_cmd++) {
+                       if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL)
+                               dib9000_fw_pid_filter_ctrl(state->fe[0],
+                                               state->pid_ctrl[index_pid_filter_cmd].onoff);
+                       else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER)
+                               dib9000_fw_pid_filter(state->fe[0],
+                                               state->pid_ctrl[index_pid_filter_cmd].id,
+                                               state->pid_ctrl[index_pid_filter_cmd].pid,
+                                               state->pid_ctrl[index_pid_filter_cmd].onoff);
+               }
+       }
+       /* do not postpone any more the pid filtering */
+       state->pid_ctrl_index = -2;
+
        return 0;
 }
 
@@ -2041,6 +2136,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
        u8 index_frontend;
        u16 lock = 0, lock_slave = 0;
 
+       DibAcquireLock(&state->demod_lock);
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
                lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
 
@@ -2059,6 +2155,8 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
        if ((lock & 0x0008) || (lock_slave & 0x0008))
                *stat |= FE_HAS_LOCK;
 
+       DibReleaseLock(&state->demod_lock);
+
        return 0;
 }
 
@@ -2066,10 +2164,15 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
 {
        struct dib9000_state *state = fe->demodulator_priv;
        u16 *c;
+       int ret = 0;
 
+       DibAcquireLock(&state->demod_lock);
        DibAcquireLock(&state->platform.risc.mem_mbx_lock);
-       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
-               return -EIO;
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+               DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+               ret = -EIO;
+               goto error;
+       }
        dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
                        state->i2c_read_buffer, 16 * 2);
        DibReleaseLock(&state->platform.risc.mem_mbx_lock);
@@ -2077,7 +2180,10 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
        c = (u16 *)state->i2c_read_buffer;
 
        *ber = c[10] << 16 | c[11];
-       return 0;
+
+error:
+       DibReleaseLock(&state->demod_lock);
+       return ret;
 }
 
 static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
@@ -2086,7 +2192,9 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
        u8 index_frontend;
        u16 *c = (u16 *)state->i2c_read_buffer;
        u16 val;
+       int ret = 0;
 
+       DibAcquireLock(&state->demod_lock);
        *strength = 0;
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
                state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
@@ -2097,8 +2205,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
        }
 
        DibAcquireLock(&state->platform.risc.mem_mbx_lock);
-       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
-               return -EIO;
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+               ret = -EIO;
+               goto error;
+       }
        dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
        DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 
@@ -2107,7 +2217,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
                *strength = 65535;
        else
                *strength += val;
-       return 0;
+
+error:
+       DibReleaseLock(&state->demod_lock);
+       return ret;
 }
 
 static u32 dib9000_get_snr(struct dvb_frontend *fe)
@@ -2151,6 +2264,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
        u8 index_frontend;
        u32 snr_master;
 
+       DibAcquireLock(&state->demod_lock);
        snr_master = dib9000_get_snr(fe);
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
                snr_master += dib9000_get_snr(state->fe[index_frontend]);
@@ -2161,6 +2275,8 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
        } else
                *snr = 0;
 
+       DibReleaseLock(&state->demod_lock);
+
        return 0;
 }
 
@@ -2168,15 +2284,22 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
 {
        struct dib9000_state *state = fe->demodulator_priv;
        u16 *c = (u16 *)state->i2c_read_buffer;
+       int ret = 0;
 
+       DibAcquireLock(&state->demod_lock);
        DibAcquireLock(&state->platform.risc.mem_mbx_lock);
-       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
-               return -EIO;
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+               ret = -EIO;
+               goto error;
+       }
        dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
        DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 
        *unc = c[12];
-       return 0;
+
+error:
+       DibReleaseLock(&state->demod_lock);
+       return ret;
 }
 
 int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
@@ -2322,6 +2445,10 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c
        DibInitLock(&st->platform.risc.mbx_lock);
        DibInitLock(&st->platform.risc.mem_lock);
        DibInitLock(&st->platform.risc.mem_mbx_lock);
+       DibInitLock(&st->demod_lock);
+       st->get_frontend_internal = 0;
+
+       st->pid_ctrl_index = -2;
 
        st->fe[0] = fe;
        fe->demodulator_priv = st;
index dc5d17a..774d507 100644 (file)
@@ -1,4 +1,5 @@
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 #include "dibx000_common.h"
 
@@ -10,6 +11,13 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 
 static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
 {
+       int ret;
+
+       if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return -EINVAL;
+       }
+
        mst->i2c_write_buffer[0] = (reg >> 8) & 0xff;
        mst->i2c_write_buffer[1] = reg & 0xff;
        mst->i2c_write_buffer[2] = (val >> 8) & 0xff;
@@ -21,11 +29,21 @@ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
        mst->msg[0].buf = mst->i2c_write_buffer;
        mst->msg[0].len = 4;
 
-       return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
+       ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
+       mutex_unlock(&mst->i2c_buffer_lock);
+
+       return ret;
 }
 
 static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
 {
+       u16 ret;
+
+       if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return 0;
+       }
+
        mst->i2c_write_buffer[0] = reg >> 8;
        mst->i2c_write_buffer[1] = reg & 0xff;
 
@@ -42,7 +60,10 @@ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
        if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
                dprintk("i2c read error on %d", reg);
 
-       return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
+       ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
+       mutex_unlock(&mst->i2c_buffer_lock);
+
+       return ret;
 }
 
 static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
@@ -257,6 +278,7 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
                                        struct i2c_msg msg[], int num)
 {
        struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+       int ret;
 
        if (num > 32) {
                dprintk("%s: too much I2C message to be transmitted (%i).\
@@ -264,10 +286,15 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
                return -ENOMEM;
        }
 
-       memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
-
        dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
 
+       if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return -EINVAL;
+       }
+
+       memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
+
        /* open the gate */
        dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
        mst->msg[0].addr = mst->i2c_addr;
@@ -282,7 +309,11 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
        mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
        mst->msg[num + 1].len = 4;
 
-       return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
+       ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
+                       num : -EIO);
+
+       mutex_unlock(&mst->i2c_buffer_lock);
+       return ret;
 }
 
 static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
@@ -294,6 +325,7 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
                                        struct i2c_msg msg[], int num)
 {
        struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+       int ret;
 
        if (num > 32) {
                dprintk("%s: too much I2C message to be transmitted (%i).\
@@ -301,10 +333,14 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
                return -ENOMEM;
        }
 
-       memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
-
        dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
 
+       if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return -EINVAL;
+       }
+       memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
+
        /* open the gate */
        dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
        mst->msg[0].addr = mst->i2c_addr;
@@ -319,7 +355,10 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
        mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
        mst->msg[num + 1].len = 4;
 
-       return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
+       ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
+                       num : -EIO);
+       mutex_unlock(&mst->i2c_buffer_lock);
+       return ret;
 }
 
 static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
@@ -390,8 +429,18 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
 int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
                                struct i2c_adapter *i2c_adap, u8 i2c_addr)
 {
-       u8 tx[4];
-       struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 };
+       int ret;
+
+       mutex_init(&mst->i2c_buffer_lock);
+       if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return -EINVAL;
+       }
+       memset(mst->msg, 0, sizeof(struct i2c_msg));
+       mst->msg[0].addr = i2c_addr >> 1;
+       mst->msg[0].flags = 0;
+       mst->msg[0].buf = mst->i2c_write_buffer;
+       mst->msg[0].len = 4;
 
        mst->device_rev = device_rev;
        mst->i2c_adap = i2c_adap;
@@ -431,9 +480,12 @@ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
                                "DiBX000: could not initialize the master i2c_adapter\n");
 
        /* initialize the i2c-master by closing the gate */
-       dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
+       dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0);
+
+       ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1);
+       mutex_unlock(&mst->i2c_buffer_lock);
 
-       return i2c_transfer(i2c_adap, &m, 1) == 1;
+       return ret;
 }
 
 EXPORT_SYMBOL(dibx000_init_i2c_master);
index f031165..5e01147 100644 (file)
@@ -33,6 +33,7 @@ struct dibx000_i2c_master {
        struct i2c_msg msg[34];
        u8 i2c_write_buffer[8];
        u8 i2c_read_buffer[2];
+       struct mutex i2c_buffer_lock;
 };
 
 extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
index 2238bf0..88e46f4 100644 (file)
@@ -889,10 +889,15 @@ static int ReadIFAgc(struct drxd_state *state, u32 * pValue)
                        u32 R2 = state->if_agc_cfg.R2;
                        u32 R3 = state->if_agc_cfg.R3;
 
-                       u32 Vmax = (3300 * R2) / (R1 + R2);
-                       u32 Rpar = (R2 * R3) / (R3 + R2);
-                       u32 Vmin = (3300 * Rpar) / (R1 + Rpar);
-                       u32 Vout = Vmin + ((Vmax - Vmin) * Value) / 1024;
+                       u32 Vmax, Rpar, Vmin, Vout;
+
+                       if (R2 == 0 && (R1 == 0 || R3 == 0))
+                               return 0;
+
+                       Vmax = (3300 * R2) / (R1 + R2);
+                       Rpar = (R2 * R3) / (R3 + R2);
+                       Vmin = (3300 * Rpar) / (R1 + Rpar);
+                       Vout = Vmin + ((Vmax - Vmin) * Value) / 1024;
 
                        *pValue = Vout;
                }
@@ -926,16 +931,15 @@ static int DownloadMicrocode(struct drxd_state *state,
                             const u8 *pMCImage, u32 Length)
 {
        u8 *pSrc;
-       u16 Flags;
        u32 Address;
        u16 nBlocks;
        u16 BlockSize;
-       u16 BlockCRC;
        u32 offset = 0;
        int i, status = 0;
 
        pSrc = (u8 *) pMCImage;
-       Flags = (pSrc[0] << 8) | pSrc[1];
+       /* We're not using Flags */
+       /* Flags = (pSrc[0] << 8) | pSrc[1]; */
        pSrc += sizeof(u16);
        offset += sizeof(u16);
        nBlocks = (pSrc[0] << 8) | pSrc[1];
@@ -952,11 +956,13 @@ static int DownloadMicrocode(struct drxd_state *state,
                pSrc += sizeof(u16);
                offset += sizeof(u16);
 
-               Flags = (pSrc[0] << 8) | pSrc[1];
+               /* We're not using Flags */
+               /* u16 Flags = (pSrc[0] << 8) | pSrc[1]; */
                pSrc += sizeof(u16);
                offset += sizeof(u16);
 
-               BlockCRC = (pSrc[0] << 8) | pSrc[1];
+               /* We're not using BlockCRC */
+               /* u16 BlockCRC = (pSrc[0] << 8) | pSrc[1]; */
                pSrc += sizeof(u16);
                offset += sizeof(u16);
 
index 41b0838..f6431ef 100644 (file)
@@ -6211,6 +6211,14 @@ static int drxk_set_parameters(struct dvb_frontend *fe,
        u32 IF;
 
        dprintk(1, "\n");
+
+       if (!fe->ops.tuner_ops.get_if_frequency) {
+               printk(KERN_ERR
+                      "drxk: Error: get_if_frequency() not defined at tuner. Can't work without it!\n");
+               return -EINVAL;
+       }
+
+
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
        if (fe->ops.tuner_ops.set_params)
@@ -6218,7 +6226,7 @@ static int drxk_set_parameters(struct dvb_frontend *fe,
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
        state->param = *p;
-       fe->ops.tuner_ops.get_frequency(fe, &IF);
+       fe->ops.tuner_ops.get_if_frequency(fe, &IF);
        Start(state, 0, IF);
 
        /* printk(KERN_DEBUG "drxk: %s IF=%d done\n", __func__, IF); */
diff --git a/drivers/media/dvb/frontends/it913x-fe-priv.h b/drivers/media/dvb/frontends/it913x-fe-priv.h
new file mode 100644 (file)
index 0000000..1c6fb4b
--- /dev/null
@@ -0,0 +1,336 @@
+
+struct it913xset {     u32 pro;
+                       u32 address;
+                       u8 reg[15];
+                       u8 count;
+};
+
+struct adctable {      u32 adcFrequency;
+                       u32 bandwidth;
+                       u32 coeff_1_2048;
+                       u32 coeff_1_4096;
+                       u32 coeff_1_8191;
+                       u32 coeff_1_8192;
+                       u32 coeff_1_8193;
+                       u32 coeff_2_2k;
+                       u32 coeff_2_4k;
+                       u32 coeff_2_8k;
+                       u16 bfsfcw_fftinx_ratio;
+                       u16 fftinx_bfsfcw_ratio;
+};
+
+/* clock and coeff tables only table 3 is used with IT9137*/
+/* TODO other tables relate AF9035 may be removed */
+static struct adctable tab1[] = {
+       {       20156250, BANDWIDTH_6_MHZ,
+               0x02b8ba6e, 0x015c5d37, 0x00ae340d, 0x00ae2e9b, 0x00ae292a,
+               0x015c5d37, 0x00ae2e9b, 0x0057174e, 0x02f1, 0x015c      },
+       {       20156250, BANDWIDTH_7_MHZ,
+               0x032cd980, 0x01966cc0, 0x00cb3cba, 0x00cb3660, 0x00cb3007,
+               0x01966cc0, 0x00cb3660, 0x00659b30, 0x0285, 0x0196      },
+       {       20156250, BANDWIDTH_8_MHZ,
+               0x03a0f893, 0x01d07c49, 0x00e84567, 0x00e83e25, 0x00e836e3,
+               0x01d07c49, 0x00e83e25, 0x00741f12, 0x0234, 0x01d0      },
+       {       20156250, BANDWIDTH_5_MHZ,
+               0x02449b5c, 0x01224dae, 0x00912b60, 0x009126d7, 0x0091224e,
+               0x01224dae, 0x009126d7, 0x0048936b, 0x0387, 0x0122      }
+};
+
+static struct adctable tab2[] = {
+       {       20187500, BANDWIDTH_6_MHZ,
+               0x02b7a654, 0x015bd32a, 0x00adef04, 0x00ade995, 0x00ade426,
+               0x015bd32a, 0x00ade995, 0x0056f4ca, 0x02f2, 0x015c      },
+       {       20187500, BANDWIDTH_7_MHZ,
+               0x032b9761, 0x0195cbb1, 0x00caec30, 0x00cae5d8, 0x00cadf81,
+               0x0195cbb1, 0x00cae5d8, 0x006572ec, 0x0286, 0x0196      },
+       {       20187500, BANDWIDTH_8_MHZ,
+               0x039f886f, 0x01cfc438, 0x00e7e95b, 0x00e7e21c, 0x00e7dadd,
+               0x01cfc438, 0x00e7e21c, 0x0073f10e, 0x0235, 0x01d0      },
+       {       20187500, BANDWIDTH_5_MHZ,
+               0x0243b546, 0x0121daa3, 0x0090f1d9, 0x0090ed51, 0x0090e8ca,
+               0x0121daa3, 0x0090ed51, 0x004876a9, 0x0388, 0x0122      }
+
+};
+
+static struct adctable tab3[] = {
+       {       20250000, BANDWIDTH_6_MHZ,
+               0x02b580ad, 0x015ac057, 0x00ad6597, 0x00ad602b, 0x00ad5ac1,
+               0x015ac057, 0x00ad602b, 0x0056b016, 0x02f4, 0x015b      },
+       {       20250000, BANDWIDTH_7_MHZ,
+               0x03291620, 0x01948b10, 0x00ca4bda, 0x00ca4588, 0x00ca3f36,
+               0x01948b10, 0x00ca4588, 0x006522c4, 0x0288, 0x0195      },
+       {       20250000, BANDWIDTH_8_MHZ,
+               0x039cab92, 0x01ce55c9, 0x00e7321e, 0x00e72ae4, 0x00e723ab,
+               0x01ce55c9, 0x00e72ae4, 0x00739572, 0x0237, 0x01ce      },
+       {       20250000, BANDWIDTH_5_MHZ,
+               0x0241eb3b, 0x0120f59e, 0x00907f53, 0x00907acf, 0x0090764b,
+               0x0120f59e, 0x00907acf, 0x00483d67, 0x038b, 0x0121      }
+
+};
+
+static struct adctable tab4[] = {
+       {       20583333, BANDWIDTH_6_MHZ,
+               0x02aa4598, 0x015522cc, 0x00aa96bb, 0x00aa9166, 0x00aa8c12,
+               0x015522cc, 0x00aa9166, 0x005548b3, 0x0300, 0x0155      },
+       {       20583333, BANDWIDTH_7_MHZ,
+               0x031bfbdc, 0x018dfdee, 0x00c7052f, 0x00c6fef7, 0x00c6f8bf,
+               0x018dfdee, 0x00c6fef7, 0x00637f7b, 0x0293, 0x018e      },
+       {       20583333, BANDWIDTH_8_MHZ,
+               0x038db21f, 0x01c6d910, 0x00e373a3, 0x00e36c88, 0x00e3656d,
+               0x01c6d910, 0x00e36c88, 0x0071b644, 0x0240, 0x01c7      },
+       {       20583333, BANDWIDTH_5_MHZ,
+               0x02388f54, 0x011c47aa, 0x008e2846, 0x008e23d5, 0x008e1f64,
+               0x011c47aa, 0x008e23d5, 0x004711ea, 0x039a, 0x011c      }
+
+};
+
+static struct adctable tab5[] = {
+       {       20416667, BANDWIDTH_6_MHZ,
+               0x02afd765, 0x0157ebb3, 0x00abfb39, 0x00abf5d9, 0x00abf07a,
+               0x0157ebb3, 0x00abf5d9, 0x0055faed, 0x02fa, 0x0158      },
+       {       20416667, BANDWIDTH_7_MHZ,
+               0x03227b4b, 0x01913da6, 0x00c8a518, 0x00c89ed3, 0x00c8988e,
+               0x01913da6, 0x00c89ed3, 0x00644f69, 0x028d, 0x0191      },
+       {       20416667, BANDWIDTH_8_MHZ,
+               0x03951f32, 0x01ca8f99, 0x00e54ef7, 0x00e547cc, 0x00e540a2,
+               0x01ca8f99, 0x00e547cc, 0x0072a3e6, 0x023c, 0x01cb      },
+       {       20416667, BANDWIDTH_5_MHZ,
+               0x023d337f, 0x011e99c0, 0x008f515a, 0x008f4ce0, 0x008f4865,
+               0x011e99c0, 0x008f4ce0, 0x0047a670, 0x0393, 0x011f      }
+
+};
+
+static struct adctable tab6[] = {
+       {       20480000, BANDWIDTH_6_MHZ,
+               0x02adb6db, 0x0156db6e, 0x00ab7312, 0x00ab6db7, 0x00ab685c,
+               0x0156db6e, 0x00ab6db7, 0x0055b6db, 0x02fd, 0x0157      },
+       {       20480000, BANDWIDTH_7_MHZ,
+               0x03200000, 0x01900000, 0x00c80640, 0x00c80000, 0x00c7f9c0,
+               0x01900000, 0x00c80000, 0x00640000, 0x028f, 0x0190      },
+       {       20480000, BANDWIDTH_8_MHZ,
+               0x03924925, 0x01c92492, 0x00e4996e, 0x00e49249, 0x00e48b25,
+               0x01c92492, 0x00e49249, 0x00724925, 0x023d, 0x01c9      },
+       {       20480000, BANDWIDTH_5_MHZ,
+               0x023b6db7, 0x011db6db, 0x008edfe5, 0x008edb6e, 0x008ed6f7,
+               0x011db6db, 0x008edb6e, 0x00476db7, 0x0396, 0x011e      }
+};
+
+static struct adctable tab7[] = {
+       {       20500000, BANDWIDTH_6_MHZ,
+               0x02ad0b99, 0x015685cc, 0x00ab4840, 0x00ab42e6, 0x00ab3d8c,
+               0x015685cc, 0x00ab42e6, 0x0055a173, 0x02fd, 0x0157      },
+       {       20500000, BANDWIDTH_7_MHZ,
+               0x031f3832, 0x018f9c19, 0x00c7d44b, 0x00c7ce0c, 0x00c7c7ce,
+               0x018f9c19, 0x00c7ce0c, 0x0063e706, 0x0290, 0x0190      },
+       {       20500000, BANDWIDTH_8_MHZ,
+               0x039164cb, 0x01c8b266, 0x00e46056, 0x00e45933, 0x00e45210,
+               0x01c8b266, 0x00e45933, 0x00722c99, 0x023e, 0x01c9      },
+       {       20500000, BANDWIDTH_5_MHZ,
+               0x023adeff, 0x011d6f80, 0x008ebc36, 0x008eb7c0, 0x008eb34a,
+               0x011d6f80, 0x008eb7c0, 0x00475be0, 0x0396, 0x011d      }
+
+};
+
+static struct adctable tab8[] = {
+       {       20625000, BANDWIDTH_6_MHZ,
+               0x02a8e4bd, 0x0154725e, 0x00aa3e81, 0x00aa392f, 0x00aa33de,
+               0x0154725e, 0x00aa392f, 0x00551c98, 0x0302, 0x0154      },
+       {       20625000, BANDWIDTH_7_MHZ,
+               0x031a6032, 0x018d3019, 0x00c69e41, 0x00c6980c, 0x00c691d8,
+               0x018d3019, 0x00c6980c, 0x00634c06, 0x0294, 0x018d      },
+       {       20625000, BANDWIDTH_8_MHZ,
+               0x038bdba6, 0x01c5edd3, 0x00e2fe02, 0x00e2f6ea, 0x00e2efd2,
+               0x01c5edd3, 0x00e2f6ea, 0x00717b75, 0x0242, 0x01c6      },
+       {       20625000, BANDWIDTH_5_MHZ,
+               0x02376948, 0x011bb4a4, 0x008ddec1, 0x008dda52, 0x008dd5e3,
+               0x011bb4a4, 0x008dda52, 0x0046ed29, 0x039c, 0x011c      }
+
+};
+
+struct table {
+               u32 xtal;
+               struct adctable *table;
+};
+
+static struct table fe_clockTable[] = {
+               {12000000, tab3},       /* FPGA     */
+               {16384000, tab6},       /* 16.38MHz */
+               {20480000, tab6},       /* 20.48MHz */
+               {36000000, tab3},       /* 36.00MHz */
+               {30000000, tab1},       /* 30.00MHz */
+               {26000000, tab4},       /* 26.00MHz */
+               {28000000, tab5},       /* 28.00MHz */
+               {32000000, tab7},       /* 32.00MHz */
+               {34000000, tab2},       /* 34.00MHz */
+               {24000000, tab1},       /* 24.00MHz */
+               {22000000, tab8},       /* 22.00MHz */
+               {12000000, tab3}        /* 12.00MHz */
+};
+
+/* fe get */
+fe_code_rate_t fe_code[] = {
+       FEC_1_2,
+       FEC_2_3,
+       FEC_3_4,
+       FEC_5_6,
+       FEC_7_8,
+       FEC_NONE,
+};
+
+fe_guard_interval_t fe_gi[] = {
+       GUARD_INTERVAL_1_32,
+       GUARD_INTERVAL_1_16,
+       GUARD_INTERVAL_1_8,
+       GUARD_INTERVAL_1_4,
+};
+
+fe_hierarchy_t fe_hi[] = {
+       HIERARCHY_NONE,
+       HIERARCHY_1,
+       HIERARCHY_2,
+       HIERARCHY_4,
+};
+
+fe_transmit_mode_t fe_mode[] = {
+       TRANSMISSION_MODE_2K,
+       TRANSMISSION_MODE_8K,
+       TRANSMISSION_MODE_4K,
+};
+
+fe_modulation_t fe_con[] = {
+       QPSK,
+       QAM_16,
+       QAM_64,
+};
+
+/* Standard demodulator functions */
+static struct it913xset set_solo_fe[] = {
+       {PRO_LINK, DVBT_INTEN, {0x04}, 0x01},
+       {PRO_LINK, DVBT_ENABLE, {0x05}, 0x01},
+       {PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01},
+       {PRO_LINK, HOSTB_MPEG_SER_MODE, {0x00}, 0x01},
+       {PRO_LINK, HOSTB_MPEG_PAR_MODE, {0x00}, 0x01},
+       {PRO_DMOD, DCA_UPPER_CHIP, {0x00}, 0x01},
+       {PRO_LINK, HOSTB_DCA_UPPER, {0x00}, 0x01},
+       {PRO_DMOD, DCA_LOWER_CHIP, {0x00}, 0x01},
+       {PRO_LINK, HOSTB_DCA_LOWER, {0x00}, 0x01},
+       {PRO_DMOD, DCA_PLATCH, {0x00}, 0x01},
+       {PRO_DMOD, DCA_FPGA_LATCH, {0x00}, 0x01},
+       {PRO_DMOD, DCA_STAND_ALONE, {0x01}, 0x01},
+       {PRO_DMOD, DCA_ENABLE, {0x00}, 0x01},
+       {PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01},
+       {PRO_DMOD, BFS_FCW, {0x00, 0x00, 0x00}, 0x03},
+       {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
+
+
+static struct it913xset init_1[] = {
+       {PRO_LINK, LOCK3_OUT, {0x01}, 0x01},
+       {PRO_LINK, PADMISCDRSR, {0x01}, 0x01},
+       {PRO_LINK, PADMISCDR2, {0x00}, 0x01},
+       {PRO_LINK, PADMISCDR4, {0x00}, 0x01}, /* Power up */
+       {PRO_LINK, PADMISCDR8, {0x00}, 0x01},
+       {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+/* ---------IT9137 0x38 tuner init---------- */
+static struct it913xset it9137_set[] = {
+       {PRO_DMOD, 0x0043, {0x00}, 0x01},
+       {PRO_DMOD, 0x0046, {0x38}, 0x01},
+       {PRO_DMOD, 0x0051, {0x01}, 0x01},
+       {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0x0068, {0x0a}, 0x01},
+       {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+       {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05},
+       {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
+       {PRO_DMOD, 0x0081, {    0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc8, 0xb8,
+                               0xd0, 0xc3, 0x01        }, 0x0a},
+       {PRO_DMOD, 0x008e, {0x01}, 0x01},
+       {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+       {PRO_DMOD, 0x0099, {0x01}, 0x01},
+       {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+       {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+       {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
+       {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+       {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+       {PRO_DMOD, 0x00b3, {0x02, 0x32}, 0x02},
+       {PRO_DMOD, 0x00b6, {0x14}, 0x01},
+       {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
+       {PRO_DMOD, 0x00c4, {0x00}, 0x01},
+       {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+       {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
+       {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
+       {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+       {PRO_DMOD, 0x00fc, {    0x02, 0x02, 0x02, 0x09, 0x50, 0x7b, 0x77,
+                               0x00, 0x02, 0xc8, 0x05, 0x7b    }, 0x0c},
+       {PRO_DMOD, 0x0109, {0x02}, 0x01},
+       {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
+       {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0xbc, 0xa0}, 0x04},
+       {PRO_DMOD, 0x0122, {0x02, 0x18, 0xc3}, 0x03},
+       {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
+       {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
+       {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05},
+       {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8}, 0x04},
+       {PRO_DMOD, 0xf130, {0x04}, 0x01},
+       {PRO_DMOD, 0xf132, {0x04}, 0x01},
+       {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+       {PRO_DMOD, 0xf146, {0x00}, 0x01},
+       {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+       {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+       {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+       {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+       {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+       {PRO_DMOD, 0xf163, {0x05}, 0x01},
+       {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+       {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0xf183, {0x01}, 0x01},
+       {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+       {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+       {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+       {PRO_DMOD, 0xf204, {0x10}, 0x01},
+       {PRO_DMOD, 0xf214, {0x00}, 0x01},
+       {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+       {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+       {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+       {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+       {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+       {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+       {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
+       {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+       {PRO_DMOD, 0xf5f8, {0x01}, 0x01},
+       {PRO_DMOD, 0xf5fd, {0x01}, 0x01},
+       {PRO_DMOD, 0xf600, {    0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+                               0x1f    }, 0x08},
+       {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+       {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+       {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+       {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+       {PRO_DMOD, 0xf905, {0x01}, 0x01},
+       {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+       {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+       {PRO_LINK, GPIOH5_EN, {0x01}, 0x01},
+       {PRO_LINK, GPIOH5_ON, {0x01}, 0x01},
+       {PRO_LINK, GPIOH5_O, {0x00}, 0x01},
+       {PRO_LINK, GPIOH5_O, {0x01}, 0x01},
+       {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
+
+static struct it913xset it9137_tuner_off[] = {
+       {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off  */
+       {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */
+       {PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04},
+       {PRO_DMOD, 0xec3f, {0x01}, 0x01},
+       {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
+
+static struct it913xset set_it9137_template[] = {
+       {PRO_DMOD, 0xee06, {0x00}, 0x01},
+       {PRO_DMOD, 0xec56, {0x00}, 0x01},
+       {PRO_DMOD, 0xec4c, {0x00}, 0x01},
+       {PRO_DMOD, 0xec4d, {0x00}, 0x01},
+       {PRO_DMOD, 0xec4e, {0x00}, 0x01},
+       {PRO_DMOD, 0xec4f, {0x00}, 0x01},
+       {PRO_DMOD, 0xec50, {0x00}, 0x01},
+       {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c
new file mode 100644 (file)
index 0000000..d4bd24e
--- /dev/null
@@ -0,0 +1,839 @@
+/*
+ *  Driver for it913x-fe Frontend
+ *
+ *  with support for on chip it9137 integral tuner
+ *
+ *  Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
+ *  IT9137 Copyright (C) ITE Tech Inc.
+ *
+ *  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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "dvb_frontend.h"
+#include "it913x-fe.h"
+#include "it913x-fe-priv.h"
+
+static int it913x_debug;
+
+module_param_named(debug, it913x_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+#define dprintk(level, args...) do { \
+       if (level & it913x_debug) \
+               printk(KERN_DEBUG "it913x-fe: " args); \
+} while (0)
+
+#define deb_info(args...)  dprintk(0x01, args)
+#define debug_data_snipet(level, name, p) \
+         dprintk(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
+               *p, *(p+1), *(p+2), *(p+3), *(p+4), \
+                       *(p+5), *(p+6), *(p+7));
+
+struct it913x_fe_state {
+       struct dvb_frontend frontend;
+       struct i2c_adapter *i2c_adap;
+       u8 i2c_addr;
+       u32 frequency;
+       u8 adf;
+       u32 crystalFrequency;
+       u32 adcFrequency;
+       u8 tuner_type;
+       struct adctable *table;
+       fe_status_t it913x_status;
+       u16 tun_xtal;
+       u8 tun_fdiv;
+       u8 tun_clk_mode;
+       u32 tun_fn_min;
+};
+
+static int it913x_read_reg(struct it913x_fe_state *state,
+               u32 reg, u8 *data, u8 count)
+{
+       int ret;
+       u8 pro = PRO_DMOD; /* All reads from demodulator */
+       u8 b[4];
+       struct i2c_msg msg[2] = {
+               { .addr = state->i2c_addr + (pro << 1), .flags = 0,
+                       .buf = b, .len = sizeof(b) },
+               { .addr = state->i2c_addr + (pro << 1), .flags = I2C_M_RD,
+                       .buf = data, .len = count }
+       };
+       b[0] = (u8) reg >> 24;
+       b[1] = (u8)(reg >> 16) & 0xff;
+       b[2] = (u8)(reg >> 8) & 0xff;
+       b[3] = (u8) reg & 0xff;
+
+       ret = i2c_transfer(state->i2c_adap, msg, 2);
+
+       return ret;
+}
+
+static int it913x_read_reg_u8(struct it913x_fe_state *state, u32 reg)
+{
+       int ret;
+       u8 b[1];
+       ret = it913x_read_reg(state, reg, &b[0], sizeof(b));
+       return (ret < 0) ? -ENODEV : b[0];
+}
+
+static int it913x_write(struct it913x_fe_state *state,
+               u8 pro, u32 reg, u8 buf[], u8 count)
+{
+       u8 b[256];
+       struct i2c_msg msg[1] = {
+               { .addr = state->i2c_addr + (pro << 1), .flags = 0,
+                 .buf = b, .len = count + 4 }
+       };
+       int ret;
+
+       b[0] = (u8) reg >> 24;
+       b[1] = (u8)(reg >> 16) & 0xff;
+       b[2] = (u8)(reg >> 8) & 0xff;
+       b[3] = (u8) reg & 0xff;
+       memcpy(&b[4], buf, count);
+
+       ret = i2c_transfer(state->i2c_adap, msg, 1);
+
+       if (ret < 0)
+               return -EIO;
+
+       return 0;
+}
+
+static int it913x_write_reg(struct it913x_fe_state *state,
+               u8 pro, u32 reg, u32 data)
+{
+       int ret;
+       u8 b[4];
+       u8 s;
+
+       b[0] = data >> 24;
+       b[1] = (data >> 16) & 0xff;
+       b[2] = (data >> 8) & 0xff;
+       b[3] = data & 0xff;
+       /* expand write as needed */
+       if (data < 0x100)
+               s = 3;
+       else if (data < 0x1000)
+               s = 2;
+       else if (data < 0x100000)
+               s = 1;
+       else
+               s = 0;
+
+       ret = it913x_write(state, pro, reg, &b[s], sizeof(b) - s);
+
+       return ret;
+}
+
+static int it913x_fe_script_loader(struct it913x_fe_state *state,
+               struct it913xset *loadscript)
+{
+       int ret, i;
+       if (loadscript == NULL)
+               return -EINVAL;
+
+       for (i = 0; i < 1000; ++i) {
+               if (loadscript[i].pro == 0xff)
+                       break;
+               ret = it913x_write(state, loadscript[i].pro,
+                       loadscript[i].address,
+                       loadscript[i].reg, loadscript[i].count);
+               if (ret < 0)
+                       return -ENODEV;
+       }
+       return 0;
+}
+
+static int it913x_init_tuner(struct it913x_fe_state *state)
+{
+       int ret, i, reg;
+       u8 val, nv_val;
+       u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
+       u8 b[2];
+
+       reg = it913x_read_reg_u8(state, 0xec86);
+       switch (reg) {
+       case 0:
+               state->tun_clk_mode = reg;
+               state->tun_xtal = 2000;
+               state->tun_fdiv = 3;
+               val = 16;
+               break;
+       case -ENODEV:
+               return -ENODEV;
+       case 1:
+       default:
+               state->tun_clk_mode = reg;
+               state->tun_xtal = 640;
+               state->tun_fdiv = 1;
+               val = 6;
+               break;
+       }
+
+       reg = it913x_read_reg_u8(state, 0xed03);
+
+       if (reg < 0)
+               return -ENODEV;
+       else if (reg < sizeof(nv))
+               nv_val = nv[reg];
+       else
+               nv_val = 2;
+
+       for (i = 0; i < 50; i++) {
+               ret = it913x_read_reg(state, 0xed23, &b[0], sizeof(b));
+               reg = (b[1] << 8) + b[0];
+               if (reg > 0)
+                       break;
+               if (ret < 0)
+                       return -ENODEV;
+               udelay(2000);
+       }
+       state->tun_fn_min = state->tun_xtal * reg;
+       state->tun_fn_min /= (state->tun_fdiv * nv_val);
+       deb_info("Tuner fn_min %d", state->tun_fn_min);
+
+       for (i = 0; i < 50; i++) {
+               reg = it913x_read_reg_u8(state, 0xec82);
+               if (reg > 0)
+                       break;
+               if (reg < 0)
+                       return -ENODEV;
+               udelay(2000);
+       }
+
+       return it913x_write_reg(state, PRO_DMOD, 0xed81, val);
+}
+
+static int it9137_set_tuner(struct it913x_fe_state *state,
+               enum fe_bandwidth bandwidth, u32 frequency_m)
+{
+       struct it913xset *set_tuner = set_it9137_template;
+       int ret, reg;
+       u32 frequency = frequency_m / 1000;
+       u32 freq, temp_f, tmp;
+       u16 iqik_m_cal;
+       u16 n_div;
+       u8 n;
+       u8 l_band;
+       u8 lna_band;
+       u8 bw;
+
+       deb_info("Tuner Frequency %d Bandwidth %d", frequency, bandwidth);
+
+       if (frequency >= 51000 && frequency <= 440000) {
+               l_band = 0;
+               lna_band = 0;
+       } else if (frequency > 440000 && frequency <= 484000) {
+               l_band = 1;
+               lna_band = 1;
+       } else if (frequency > 484000 && frequency <= 533000) {
+               l_band = 1;
+               lna_band = 2;
+       } else if (frequency > 533000 && frequency <= 587000) {
+               l_band = 1;
+               lna_band = 3;
+       } else if (frequency > 587000 && frequency <= 645000) {
+               l_band = 1;
+               lna_band = 4;
+       } else if (frequency > 645000 && frequency <= 710000) {
+               l_band = 1;
+               lna_band = 5;
+       } else if (frequency > 710000 && frequency <= 782000) {
+               l_band = 1;
+               lna_band = 6;
+       } else if (frequency > 782000 && frequency <= 860000) {
+               l_band = 1;
+               lna_band = 7;
+       } else if (frequency > 1450000 && frequency <= 1492000) {
+               l_band = 1;
+               lna_band = 0;
+       } else if (frequency > 1660000 && frequency <= 1685000) {
+               l_band = 1;
+               lna_band = 1;
+       } else
+               return -EINVAL;
+       set_tuner[0].reg[0] = lna_band;
+
+       if (bandwidth == BANDWIDTH_5_MHZ)
+               bw = 0;
+       else if (bandwidth == BANDWIDTH_6_MHZ)
+               bw = 2;
+       else if (bandwidth == BANDWIDTH_7_MHZ)
+               bw = 4;
+       else if (bandwidth == BANDWIDTH_8_MHZ)
+               bw = 6;
+       else
+               bw = 6;
+
+       set_tuner[1].reg[0] = bw;
+       set_tuner[2].reg[0] = 0xa0 | (l_band << 3);
+
+       if (frequency > 53000 && frequency <= 74000) {
+               n_div = 48;
+               n = 0;
+       } else if (frequency > 74000 && frequency <= 111000) {
+               n_div = 32;
+               n = 1;
+       } else if (frequency > 111000 && frequency <= 148000) {
+               n_div = 24;
+               n = 2;
+       } else if (frequency > 148000 && frequency <= 222000) {
+               n_div = 16;
+               n = 3;
+       } else if (frequency > 222000 && frequency <= 296000) {
+               n_div = 12;
+               n = 4;
+       } else if (frequency > 296000 && frequency <= 445000) {
+               n_div = 8;
+               n = 5;
+       } else if (frequency > 445000 && frequency <= state->tun_fn_min) {
+               n_div = 6;
+               n = 6;
+       } else if (frequency > state->tun_fn_min && frequency <= 950000) {
+               n_div = 4;
+               n = 7;
+       } else if (frequency > 1450000 && frequency <= 1680000) {
+               n_div = 2;
+               n = 0;
+       } else
+               return -EINVAL;
+
+       reg = it913x_read_reg_u8(state, 0xed81);
+       iqik_m_cal = (u16)reg * n_div;
+
+       if (reg < 0x20) {
+               if (state->tun_clk_mode == 0)
+                       iqik_m_cal = (iqik_m_cal * 9) >> 5;
+               else
+                       iqik_m_cal >>= 1;
+       } else {
+               iqik_m_cal = 0x40 - iqik_m_cal;
+               if (state->tun_clk_mode == 0)
+                       iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
+               else
+                       iqik_m_cal = ~(iqik_m_cal >> 1);
+       }
+
+       temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv;
+       freq = temp_f / state->tun_xtal;
+       tmp = freq * state->tun_xtal;
+
+       if ((temp_f - tmp) >= (state->tun_xtal >> 1))
+               freq++;
+
+       freq += (u32) n << 13;
+       /* Frequency OMEGA_IQIK_M_CAL_MID*/
+       temp_f = freq + (u32)iqik_m_cal;
+
+       set_tuner[3].reg[0] =  temp_f & 0xff;
+       set_tuner[4].reg[0] =  (temp_f >> 8) & 0xff;
+
+       deb_info("High Frequency = %04x", temp_f);
+
+       /* Lower frequency */
+       set_tuner[5].reg[0] =  freq & 0xff;
+       set_tuner[6].reg[0] =  (freq >> 8) & 0xff;
+
+       deb_info("low Frequency = %04x", freq);
+
+       ret = it913x_fe_script_loader(state, set_tuner);
+
+       return (ret < 0) ? -ENODEV : 0;
+}
+
+static int it913x_fe_select_bw(struct it913x_fe_state *state,
+                       enum fe_bandwidth bandwidth, u32 adcFrequency)
+{
+       int ret, i;
+       u8 buffer[256];
+       u32 coeff[8];
+       u16 bfsfcw_fftinx_ratio;
+       u16 fftinx_bfsfcw_ratio;
+       u8 count;
+       u8 bw;
+       u8 adcmultiplier;
+
+       deb_info("Bandwidth %d Adc %d", bandwidth, adcFrequency);
+
+       if (bandwidth == BANDWIDTH_5_MHZ)
+               bw = 3;
+       else if (bandwidth == BANDWIDTH_6_MHZ)
+               bw = 0;
+       else if (bandwidth == BANDWIDTH_7_MHZ)
+               bw = 1;
+       else if (bandwidth == BANDWIDTH_8_MHZ)
+               bw = 2;
+       else
+               bw = 2;
+
+       ret = it913x_write_reg(state, PRO_DMOD, REG_BW, bw);
+
+       if (state->table == NULL)
+               return -EINVAL;
+
+       /* In write order */
+       coeff[0] = state->table[bw].coeff_1_2048;
+       coeff[1] = state->table[bw].coeff_2_2k;
+       coeff[2] = state->table[bw].coeff_1_8191;
+       coeff[3] = state->table[bw].coeff_1_8192;
+       coeff[4] = state->table[bw].coeff_1_8193;
+       coeff[5] = state->table[bw].coeff_2_8k;
+       coeff[6] = state->table[bw].coeff_1_4096;
+       coeff[7] = state->table[bw].coeff_2_4k;
+       bfsfcw_fftinx_ratio = state->table[bw].bfsfcw_fftinx_ratio;
+       fftinx_bfsfcw_ratio = state->table[bw].fftinx_bfsfcw_ratio;
+
+       /* ADC multiplier */
+       ret = it913x_read_reg_u8(state, ADC_X_2);
+       if (ret < 0)
+               return -EINVAL;
+
+       adcmultiplier = ret;
+
+       count = 0;
+
+       /*  Build Buffer for COEFF Registers */
+       for (i = 0; i < 8; i++) {
+               if (adcmultiplier == 1)
+                       coeff[i] /= 2;
+               buffer[count++] = (coeff[i] >> 24) & 0x3;
+               buffer[count++] = (coeff[i] >> 16) & 0xff;
+               buffer[count++] = (coeff[i] >> 8) & 0xff;
+               buffer[count++] = coeff[i] & 0xff;
+       }
+
+       /* bfsfcw_fftinx_ratio register 0x21-0x22 */
+       buffer[count++] = bfsfcw_fftinx_ratio & 0xff;
+       buffer[count++] = (bfsfcw_fftinx_ratio >> 8) & 0xff;
+       /* fftinx_bfsfcw_ratio register 0x23-0x24 */
+       buffer[count++] = fftinx_bfsfcw_ratio & 0xff;
+       buffer[count++] = (fftinx_bfsfcw_ratio >> 8) & 0xff;
+       /* start at COEFF_1_2048 and write through to fftinx_bfsfcw_ratio*/
+       ret = it913x_write(state, PRO_DMOD, COEFF_1_2048, buffer, count);
+
+       for (i = 0; i < 42; i += 8)
+               debug_data_snipet(0x1, "Buffer", &buffer[i]);
+
+       return ret;
+}
+
+
+
+static int it913x_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct it913x_fe_state *state = fe->demodulator_priv;
+       int ret, i;
+       fe_status_t old_status = state->it913x_status;
+       *status = 0;
+
+       if (state->it913x_status == 0) {
+               ret = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
+               if (ret == 0x1) {
+                       *status |= FE_HAS_SIGNAL;
+                       for (i = 0; i < 40; i++) {
+                               ret = it913x_read_reg_u8(state, MP2IF_SYNC_LK);
+                               if (ret == 0x1)
+                                       break;
+                               msleep(25);
+                       }
+                       if (ret == 0x1)
+                               *status |= FE_HAS_CARRIER
+                                       | FE_HAS_VITERBI
+                                       | FE_HAS_SYNC;
+                       state->it913x_status = *status;
+               }
+       }
+
+       if (state->it913x_status & FE_HAS_SYNC) {
+               ret = it913x_read_reg_u8(state, TPSD_LOCK);
+               if (ret == 0x1)
+                       *status |= FE_HAS_LOCK
+                               | state->it913x_status;
+               else
+                       state->it913x_status = 0;
+               if (old_status != state->it913x_status)
+                       ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, ret);
+       }
+
+       return 0;
+}
+
+static int it913x_fe_read_signal_strength(struct dvb_frontend *fe,
+               u16 *strength)
+{
+       struct it913x_fe_state *state = fe->demodulator_priv;
+       int ret = it913x_read_reg_u8(state, SIGNAL_LEVEL);
+       /*SIGNAL_LEVEL always returns 100%! so using FE_HAS_SIGNAL as switch*/
+       if (state->it913x_status & FE_HAS_SIGNAL)
+               ret = (ret * 0xff) / 0x64;
+       else
+               ret = 0x0;
+       ret |= ret << 0x8;
+       *strength = ret;
+       return 0;
+}
+
+static int it913x_fe_read_snr(struct dvb_frontend *fe, u16* snr)
+{
+       struct it913x_fe_state *state = fe->demodulator_priv;
+       int ret = it913x_read_reg_u8(state, SIGNAL_QUALITY);
+       ret = (ret * 0xff) / 0x64;
+       ret |= (ret << 0x8);
+       *snr = ~ret;
+       return 0;
+}
+
+static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       *ber = 0;
+       return 0;
+}
+
+static int it913x_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       *ucblocks = 0;
+       return 0;
+}
+
+static int it913x_fe_get_frontend(struct dvb_frontend *fe,
+                       struct dvb_frontend_parameters *p)
+{
+       struct it913x_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u8 reg[8];
+
+       ret = it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg));
+
+       if (reg[3] < 3)
+               p->u.ofdm.constellation = fe_con[reg[3]];
+
+       if (reg[0] < 3)
+               p->u.ofdm.transmission_mode = fe_mode[reg[0]];
+
+       if (reg[1] < 4)
+               p->u.ofdm.guard_interval = fe_gi[reg[1]];
+
+       if (reg[2] < 4)
+               p->u.ofdm.hierarchy_information = fe_hi[reg[2]];
+
+       p->u.ofdm.code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE;
+       p->u.ofdm.code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE;
+
+       return 0;
+}
+
+static int it913x_fe_set_frontend(struct dvb_frontend *fe,
+                       struct dvb_frontend_parameters *p)
+{
+       struct it913x_fe_state *state = fe->demodulator_priv;
+       int ret, i;
+       u8 empty_ch, last_ch;
+
+       state->it913x_status = 0;
+
+       /* Set bw*/
+       ret = it913x_fe_select_bw(state, p->u.ofdm.bandwidth,
+               state->adcFrequency);
+
+       /* Training Mode Off */
+       ret = it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0);
+
+       /* Clear Empty Channel */
+       ret = it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0);
+
+       /* Clear bits */
+       ret = it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0);
+       /* LED on */
+       ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
+       /* Select Band*/
+       if ((p->frequency >= 51000000) && (p->frequency <= 230000000))
+               i = 0;
+       else if ((p->frequency >= 350000000) && (p->frequency <= 900000000))
+                       i = 1;
+       else if ((p->frequency >= 1450000000) && (p->frequency <= 1680000000))
+                       i = 2;
+               else
+                       return -EOPNOTSUPP;
+
+       ret = it913x_write_reg(state, PRO_DMOD, FREE_BAND, i);
+
+       deb_info("Frontend Set Tuner Type %02x", state->tuner_type);
+       switch (state->tuner_type) {
+       case IT9137: /* Tuner type 0x38 */
+               ret = it9137_set_tuner(state,
+                       p->u.ofdm.bandwidth, p->frequency);
+               break;
+       default:
+               if (fe->ops.tuner_ops.set_params) {
+                       fe->ops.tuner_ops.set_params(fe, p);
+                       if (fe->ops.i2c_gate_ctrl)
+                               fe->ops.i2c_gate_ctrl(fe, 0);
+               }
+               break;
+       }
+       /* LED off */
+       ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
+       /* Trigger ofsm */
+       ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
+       last_ch = 2;
+       for (i = 0; i < 40; ++i) {
+               empty_ch = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
+               if (last_ch == 1 && empty_ch == 1)
+                       break;
+               if (last_ch == 2 && empty_ch == 2)
+                       return 0;
+               last_ch = empty_ch;
+               msleep(25);
+       }
+       for (i = 0; i < 40; ++i) {
+               if (it913x_read_reg_u8(state, D_TPSD_LOCK) == 1)
+                       break;
+               msleep(25);
+       }
+
+       state->frequency = p->frequency;
+       return 0;
+}
+
+static int it913x_fe_suspend(struct it913x_fe_state *state)
+{
+       int ret, i;
+       u8 b;
+
+       ret = it913x_write_reg(state, PRO_DMOD, SUSPEND_FLAG, 0x1);
+
+       ret |= it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
+
+       for (i = 0; i < 128; i++) {
+               ret = it913x_read_reg(state, SUSPEND_FLAG, &b, 1);
+               if (ret < 0)
+                       return -ENODEV;
+               if (b == 0)
+                       break;
+
+       }
+
+       ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x8);
+       /* Turn LED off */
+       ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
+
+       ret |= it913x_fe_script_loader(state, it9137_tuner_off);
+
+       return (ret < 0) ? -ENODEV : 0;
+}
+
+/* Power sequence */
+/* Power Up    Tuner on -> Frontend suspend off -> Tuner clk on */
+/* Power Down  Frontend suspend on -> Tuner clk off -> Tuner off */
+
+static int it913x_fe_sleep(struct dvb_frontend *fe)
+{
+       struct it913x_fe_state *state = fe->demodulator_priv;
+       return it913x_fe_suspend(state);
+}
+
+static u32 compute_div(u32 a, u32 b, u32 x)
+{
+       u32 res = 0;
+       u32 c = 0;
+       u32 i = 0;
+
+       if (a > b) {
+               c = a / b;
+               a = a - c * b;
+       }
+
+       for (i = 0; i < x; i++) {
+               if (a >= b) {
+                       res += 1;
+                       a -= b;
+               }
+               a <<= 1;
+               res <<= 1;
+       }
+
+       res = (c << x) + res;
+
+       return res;
+}
+
+static int it913x_fe_start(struct it913x_fe_state *state)
+{
+       struct it913xset *set_fe;
+       struct it913xset *set_mode;
+       int ret;
+       u8 adf = (state->adf & 0xf);
+       u32 adc, xtal;
+       u8 b[4];
+
+       ret = it913x_init_tuner(state);
+
+       if (adf < 12) {
+               state->crystalFrequency = fe_clockTable[adf].xtal ;
+               state->table = fe_clockTable[adf].table;
+               state->adcFrequency = state->table->adcFrequency;
+
+               adc = compute_div(state->adcFrequency, 1000000ul, 19ul);
+               xtal = compute_div(state->crystalFrequency, 1000000ul, 19ul);
+
+       } else
+               return -EINVAL;
+
+       deb_info("Xtal Freq :%d Adc Freq :%d Adc %08x Xtal %08x",
+               state->crystalFrequency, state->adcFrequency, adc, xtal);
+
+       /* Set LED indicator on GPIOH3 */
+       ret = it913x_write_reg(state, PRO_LINK, GPIOH3_EN, 0x1);
+       ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_ON, 0x1);
+       ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
+
+       ret |= it913x_write_reg(state, PRO_LINK, 0xf641, state->tuner_type);
+       ret |= it913x_write_reg(state, PRO_DMOD, 0xf5ca, 0x01);
+       ret |= it913x_write_reg(state, PRO_DMOD, 0xf715, 0x01);
+
+       b[0] = xtal & 0xff;
+       b[1] = (xtal >> 8) & 0xff;
+       b[2] = (xtal >> 16) & 0xff;
+       b[3] = (xtal >> 24);
+       ret |= it913x_write(state, PRO_DMOD, XTAL_CLK, b , 4);
+
+       b[0] = adc & 0xff;
+       b[1] = (adc >> 8) & 0xff;
+       b[2] = (adc >> 16) & 0xff;
+       ret |= it913x_write(state, PRO_DMOD, ADC_FREQ, b, 3);
+
+       switch (state->tuner_type) {
+       case IT9137: /* Tuner type 0x38 */
+               set_fe = it9137_set;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set the demod */
+       ret = it913x_fe_script_loader(state, set_fe);
+       /* Always solo frontend */
+       set_mode = set_solo_fe;
+       ret |= it913x_fe_script_loader(state, set_mode);
+
+       ret |= it913x_fe_suspend(state);
+       return 0;
+}
+
+static int it913x_fe_init(struct dvb_frontend *fe)
+{
+       struct it913x_fe_state *state = fe->demodulator_priv;
+       int ret = 0;
+       /* Power Up Tuner - common all versions */
+       ret = it913x_write_reg(state, PRO_DMOD, 0xec40, 0x1);
+
+       ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0);
+
+       ret |= it913x_fe_script_loader(state, init_1);
+
+       switch (state->tuner_type) {
+       case IT9137:
+               ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return (ret < 0) ? -ENODEV : 0;
+}
+
+static void it913x_fe_release(struct dvb_frontend *fe)
+{
+       struct it913x_fe_state *state = fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops it913x_fe_ofdm_ops;
+
+struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
+               u8 i2c_addr, u8 adf, u8 type)
+{
+       struct it913x_fe_state *state = NULL;
+       int ret;
+       /* allocate memory for the internal state */
+       state = kzalloc(sizeof(struct it913x_fe_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       state->i2c_adap = i2c_adap;
+       state->i2c_addr = i2c_addr;
+       state->adf = adf;
+       state->tuner_type = type;
+
+       ret = it913x_fe_start(state);
+       if (ret < 0)
+               goto error;
+
+
+       /* create dvb_frontend */
+       memcpy(&state->frontend.ops, &it913x_fe_ofdm_ops,
+                       sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+
+       return &state->frontend;
+error:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(it913x_fe_attach);
+
+static struct dvb_frontend_ops it913x_fe_ofdm_ops = {
+
+       .info = {
+               .name                   = "it913x-fe DVB-T",
+               .type                   = FE_OFDM,
+               .frequency_min          = 51000000,
+               .frequency_max          = 1680000000,
+               .frequency_stepsize     = 62500,
+               .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+                       FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .release = it913x_fe_release,
+
+       .init = it913x_fe_init,
+       .sleep = it913x_fe_sleep,
+
+       .set_frontend = it913x_fe_set_frontend,
+       .get_frontend = it913x_fe_get_frontend,
+
+       .read_status = it913x_fe_read_status,
+       .read_signal_strength = it913x_fe_read_signal_strength,
+       .read_snr = it913x_fe_read_snr,
+       .read_ber = it913x_fe_read_ber,
+       .read_ucblocks = it913x_fe_read_ucblocks,
+};
+
+MODULE_DESCRIPTION("it913x Frontend and it9137 tuner");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
+MODULE_VERSION("1.07");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/it913x-fe.h b/drivers/media/dvb/frontends/it913x-fe.h
new file mode 100644 (file)
index 0000000..9d97f32
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *  Driver for it913x Frontend
+ *
+ *
+ *  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 IT913X_FE_H
+#define IT913X_FE_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+#if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \
+defined(MODULE))
+extern struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
+                       u8 i2c_addr, u8 adf, u8 type);
+#else
+static inline struct dvb_frontend *it913x_fe_attach(
+               struct i2c_adapter *i2c_adap,   u8 i2c_addr, u8 adf, u8 type)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_IT913X_FE */
+#define I2C_BASE_ADDR          0x10
+#define DEV_0                  0x0
+#define DEV_1                  0x10
+#define PRO_LINK               0x0
+#define PRO_DMOD               0x1
+#define DEV_0_DMOD             (PRO_DMOD << 0x7)
+#define DEV_1_DMOD             (DEV_0_DMOD | DEV_1)
+#define CHIP2_I2C_ADDR         0x3a
+
+#define AFE_MEM0               0xfb24
+
+#define MP2_SW_RST             0xf99d
+#define MP2IF2_SW_RST          0xf9a4
+
+#define        PADODPU                 0xd827
+#define THIRDODPU              0xd828
+#define AGC_O_D                        0xd829
+
+#define EP0_TX_EN              0xdd11
+#define EP0_TX_NAK             0xdd13
+#define EP4_TX_LEN_LSB         0xdd88
+#define EP4_TX_LEN_MSB         0xdd89
+#define EP4_MAX_PKT            0xdd0c
+#define EP5_TX_LEN_LSB         0xdd8a
+#define EP5_TX_LEN_MSB         0xdd8b
+#define EP5_MAX_PKT            0xdd0d
+
+#define IO_MUX_POWER_CLK       0xd800
+#define CLK_O_EN               0xd81a
+#define I2C_CLK                        0xf103
+#define I2C_CLK_100            0x7
+#define I2C_CLK_400            0x1a
+
+#define D_TPSD_LOCK            0xf5a9
+#define MP2IF2_EN              0xf9a3
+#define MP2IF_SERIAL           0xf985
+#define TSIS_ENABLE            0xf9cd
+#define MP2IF2_HALF_PSB                0xf9a5
+#define MP2IF_STOP_EN          0xf9b5
+#define MPEG_FULL_SPEED                0xf990
+#define TOP_HOSTB_SER_MODE     0xd91c
+
+#define PID_RST                        0xf992
+#define PID_EN                 0xf993
+#define PID_INX_EN             0xf994
+#define PID_INX                        0xf995
+#define PID_LSB                        0xf996
+#define PID_MSB                        0xf997
+
+#define MP2IF_MPEG_PAR_MODE    0xf986
+#define DCA_UPPER_CHIP         0xf731
+#define DCA_LOWER_CHIP         0xf732
+#define DCA_PLATCH             0xf730
+#define DCA_FPGA_LATCH         0xf778
+#define DCA_STAND_ALONE                0xf73c
+#define DCA_ENABLE             0xf776
+
+#define DVBT_INTEN             0xf41f
+#define DVBT_ENABLE            0xf41a
+#define HOSTB_DCA_LOWER                0xd91f
+#define HOSTB_MPEG_PAR_MODE    0xd91b
+#define HOSTB_MPEG_SER_MODE    0xd91c
+#define HOSTB_MPEG_SER_DO7     0xd91d
+#define HOSTB_DCA_UPPER                0xd91e
+#define PADMISCDR2             0xd830
+#define PADMISCDR4             0xd831
+#define PADMISCDR8             0xd832
+#define PADMISCDRSR            0xd833
+#define LOCK3_OUT              0xd8fd
+
+#define GPIOH1_O               0xd8af
+#define GPIOH1_EN              0xd8b0
+#define GPIOH1_ON              0xd8b1
+#define GPIOH3_O               0xd8b3
+#define GPIOH3_EN              0xd8b4
+#define GPIOH3_ON              0xd8b5
+#define GPIOH5_O               0xd8bb
+#define GPIOH5_EN              0xd8bc
+#define GPIOH5_ON              0xd8bd
+
+#define AFE_MEM0               0xfb24
+
+#define REG_TPSD_TX_MODE       0xf900
+#define REG_TPSD_GI            0xf901
+#define REG_TPSD_HIER          0xf902
+#define REG_TPSD_CONST         0xf903
+#define REG_BW                 0xf904
+#define REG_PRIV               0xf905
+#define REG_TPSD_HP_CODE       0xf906
+#define REG_TPSD_LP_CODE       0xf907
+
+#define MP2IF_SYNC_LK          0xf999
+#define ADC_FREQ               0xf1cd
+
+#define TRIGGER_OFSM           0x0000
+/* COEFF Registers start at 0x0001 to 0x0020 */
+#define COEFF_1_2048           0x0001
+#define XTAL_CLK               0x0025
+#define BFS_FCW                        0x0029
+#define TPSD_LOCK              0x003c
+#define TRAINING_MODE          0x0040
+#define ADC_X_2                        0x0045
+#define TUNER_ID               0x0046
+#define EMPTY_CHANNEL_STATUS   0x0047
+#define SIGNAL_LEVEL           0x0048
+#define SIGNAL_QUALITY         0x0049
+#define EST_SIGNAL_LEVEL       0x004a
+#define FREE_BAND              0x004b
+#define SUSPEND_FLAG           0x004c
+/* Build in tuners */
+#define IT9137 0x38
+
+enum {
+       CMD_DEMOD_READ = 0,
+       CMD_DEMOD_WRITE,
+       CMD_TUNER_READ,
+       CMD_TUNER_WRITE,
+       CMD_REG_EEPROM_READ,
+       CMD_REG_EEPROM_WRITE,
+       CMD_DATA_READ,
+       CMD_VAR_READ = 8,
+       CMD_VAR_WRITE,
+       CMD_PLATFORM_GET,
+       CMD_PLATFORM_SET,
+       CMD_IP_CACHE,
+       CMD_IP_ADD,
+       CMD_IP_REMOVE,
+       CMD_PID_ADD,
+       CMD_PID_REMOVE,
+       CMD_SIPSI_GET,
+       CMD_SIPSI_MPE_RESET,
+       CMD_H_PID_ADD = 0x15,
+       CMD_H_PID_REMOVE,
+       CMD_ABORT,
+       CMD_IR_GET,
+       CMD_IR_SET,
+       CMD_FW_DOWNLOAD = 0x21,
+       CMD_QUERYINFO,
+       CMD_BOOT,
+       CMD_FW_DOWNLOAD_BEGIN,
+       CMD_FW_DOWNLOAD_END,
+       CMD_RUN_CODE,
+       CMD_SCATTER_READ = 0x28,
+       CMD_SCATTER_WRITE,
+       CMD_GENERIC_READ,
+       CMD_GENERIC_WRITE
+};
+
+enum {
+       READ_LONG,
+       WRITE_LONG,
+       READ_SHORT,
+       WRITE_SHORT,
+       READ_DATA,
+       WRITE_DATA,
+       WRITE_CMD,
+};
+
+#endif /* IT913X_FE_H */
diff --git a/drivers/media/dvb/frontends/lnbp22.c b/drivers/media/dvb/frontends/lnbp22.c
new file mode 100644 (file)
index 0000000..84ad039
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * lnbp22.h - driver for lnb supply and control ic lnbp22
+ *
+ * Copyright (C) 2006 Dominik Kuhlen
+ * Based on lnbp21 driver
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbp22.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+
+#define dprintk(lvl, arg...) if (debug >= (lvl)) printk(arg)
+
+struct lnbp22 {
+       u8                  config[4];
+       struct i2c_adapter *i2c;
+};
+
+static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+       struct lnbp22 *lnbp22 = (struct lnbp22 *)fe->sec_priv;
+       struct i2c_msg msg = {
+               .addr = 0x08,
+               .flags = 0,
+               .buf = (char *)&lnbp22->config,
+               .len = sizeof(lnbp22->config),
+       };
+
+       dprintk(1, "%s: %d (18V=%d 13V=%d)\n", __func__, voltage,
+              SEC_VOLTAGE_18, SEC_VOLTAGE_13);
+
+       lnbp22->config[3] = 0x60; /* Power down */
+       switch (voltage) {
+       case SEC_VOLTAGE_OFF:
+               break;
+       case SEC_VOLTAGE_13:
+               lnbp22->config[3] |= LNBP22_EN;
+               break;
+       case SEC_VOLTAGE_18:
+               lnbp22->config[3] |= (LNBP22_EN | LNBP22_VSEL);
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       dprintk(1, "%s: 0x%02x)\n", __func__, lnbp22->config[3]);
+       return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp22_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+       struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
+       struct i2c_msg msg = {
+               .addr = 0x08,
+               .flags = 0,
+               .buf = (char *)&lnbp22->config,
+               .len = sizeof(lnbp22->config),
+       };
+
+       dprintk(1, "%s: %d\n", __func__, (int)arg);
+       if (arg)
+               lnbp22->config[3] |= LNBP22_LLC;
+       else
+               lnbp22->config[3] &= ~LNBP22_LLC;
+
+       return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp22_release(struct dvb_frontend *fe)
+{
+       dprintk(1, "%s\n", __func__);
+       /* LNBP power off */
+       lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+       /* free data */
+       kfree(fe->sec_priv);
+       fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
+                                       struct i2c_adapter *i2c)
+{
+       struct lnbp22 *lnbp22 = kmalloc(sizeof(struct lnbp22), GFP_KERNEL);
+       if (!lnbp22)
+               return NULL;
+
+       /* default configuration */
+       lnbp22->config[0] = 0x00; /* ? */
+       lnbp22->config[1] = 0x28; /* ? */
+       lnbp22->config[2] = 0x48; /* ? */
+       lnbp22->config[3] = 0x60; /* Power down */
+       lnbp22->i2c = i2c;
+       fe->sec_priv = lnbp22;
+
+       /* detect if it is present or not */
+       if (lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+               dprintk(0, "%s LNBP22 not found\n", __func__);
+               kfree(lnbp22);
+               fe->sec_priv = NULL;
+               return NULL;
+       }
+
+       /* install release callback */
+       fe->ops.release_sec = lnbp22_release;
+
+       /* override frontend ops */
+       fe->ops.set_voltage = lnbp22_set_voltage;
+       fe->ops.enable_high_lnb_voltage = lnbp22_enable_high_lnb_voltage;
+
+       return fe;
+}
+EXPORT_SYMBOL(lnbp22_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22");
+MODULE_AUTHOR("Dominik Kuhlen");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lnbp22.h b/drivers/media/dvb/frontends/lnbp22.h
new file mode 100644 (file)
index 0000000..63e2dec
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * lnbp22.h - driver for lnb supply and control ic lnbp22
+ *
+ * Copyright (C) 2006 Dominik Kuhlen
+ * Based on lnbp21.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _LNBP22_H
+#define _LNBP22_H
+
+/* Enable */
+#define LNBP22_EN        0x10
+/* Voltage selection */
+#define LNBP22_VSEL    0x02
+/* Plus 1 Volt Bit */
+#define LNBP22_LLC     0x01
+
+#include <linux/dvb/frontend.h>
+
+#if defined(CONFIG_DVB_LNBP22) || \
+               (defined(CONFIG_DVB_LNBP22_MODULE) && defined(MODULE))
+/*
+ * override_set and override_clear control which system register bits (above)
+ * to always set & clear
+ */
+extern struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
+                                               struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
+                                               struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_LNBP22 */
+
+#endif /* _LNBP22_H */
index d70eee0..117a569 100644 (file)
@@ -358,6 +358,9 @@ static enum stb0899_status stb0899_check_data(struct stb0899_state *state)
        else
                dataTime = 500;
 
+       /* clear previous failed END_LOOPVIT */
+       stb0899_read_reg(state, STB0899_VSTATUS);
+
        stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop  */
        while (1) {
                /* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP    */
index 37a222d..8408ef8 100644 (file)
@@ -706,7 +706,7 @@ static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_ma
        stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
        for (i = 0; i < cmd->msg_len; i++) {
                /* wait for FIFO empty  */
-               if (stb0899_wait_diseqc_fifo_empty(state, 10) < 0)
+               if (stb0899_wait_diseqc_fifo_empty(state, 100) < 0)
                        return -ETIMEDOUT;
 
                stb0899_write_reg(state, STB0899_DISFIFO, cmd->msg[i]);
@@ -1426,9 +1426,9 @@ static void stb0899_set_iterations(struct stb0899_state *state)
        if (iter_scale > config->ldpc_max_iter)
                iter_scale = config->ldpc_max_iter;
 
-       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, MAX_ITER);
+       reg = STB0899_READ_S2REG(STB0899_S2FEC, MAX_ITER);
        STB0899_SETFIELD_VAL(MAX_ITERATIONS, reg, iter_scale);
-       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg);
+       stb0899_write_s2reg(state, STB0899_S2FEC, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg);
 }
 
 static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
index 8e0cfad..0aa3962 100644 (file)
@@ -127,6 +127,11 @@ static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate)
        if ((srate < 1000000) || (srate > 45000000))
                return -EINVAL;
 
+       stv0288_writeregI(state, 0x22, 0);
+       stv0288_writeregI(state, 0x23, 0);
+       stv0288_writeregI(state, 0x2b, 0xff);
+       stv0288_writeregI(state, 0x2c, 0xf7);
+
        temp = (unsigned int)srate / 1000;
 
                temp = temp * 32768;
@@ -461,6 +466,7 @@ static int stv0288_set_frontend(struct dvb_frontend *fe,
 
        char tm;
        unsigned char tda[3];
+       u8 reg, time_out = 0;
 
        dprintk("%s : FE_SET_FRONTEND\n", __func__);
 
@@ -488,22 +494,29 @@ static int stv0288_set_frontend(struct dvb_frontend *fe,
        /* Carrier lock control register */
        stv0288_writeregI(state, 0x15, 0xc5);
 
-       tda[0] = 0x2b; /* CFRM */
        tda[2] = 0x0; /* CFRL */
-       for (tm = -6; tm < 7;) {
+       for (tm = -9; tm < 7;) {
                /* Viterbi status */
-               if (stv0288_readreg(state, 0x24) & 0x8)
-                       break;
-
-               tda[2] += 40;
-               if (tda[2] < 40)
+               reg = stv0288_readreg(state, 0x24);
+               if (reg & 0x8)
+                               break;
+               if (reg & 0x80) {
+                       time_out++;
+                       if (time_out > 10)
+                               break;
+                       tda[2] += 40;
+                       if (tda[2] < 40)
+                               tm++;
+               } else {
                        tm++;
+                       tda[2] = 0;
+                       time_out = 0;
+               }
                tda[1] = (unsigned char)tm;
                stv0288_writeregI(state, 0x2b, tda[1]);
                stv0288_writeregI(state, 0x2c, tda[2]);
                udelay(30);
        }
-
        state->tuner_frequency = c->frequency;
        state->fec_inner = FEC_AUTO;
        state->symbol_rate = c->symbol_rate;
index 52d8712..ebda419 100644 (file)
@@ -3463,9 +3463,15 @@ static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_fron
 static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
 {
        struct stv090x_state *state = fe->demodulator_priv;
-       u32 reg;
+       u32 reg, dstatus;
        u8 search_state;
 
+       *status = 0;
+
+       dstatus = STV090x_READ_DEMOD(state, DSTATUS);
+       if (STV090x_GETFIELD_Px(dstatus, CAR_LOCK_FIELD))
+               *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
        reg = STV090x_READ_DEMOD(state, DMDSTATE);
        search_state = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
 
@@ -3474,41 +3480,30 @@ static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
        case 1: /* first PLH detected */
        default:
                dprintk(FE_DEBUG, 1, "Status: Unlocked (Searching ..)");
-               *status = 0;
                break;
 
        case 2: /* DVB-S2 mode */
                dprintk(FE_DEBUG, 1, "Delivery system: DVB-S2");
-               reg = STV090x_READ_DEMOD(state, DSTATUS);
-               if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) {
+               if (STV090x_GETFIELD_Px(dstatus, LOCK_DEFINITIF_FIELD)) {
                        reg = STV090x_READ_DEMOD(state, PDELSTATUS1);
                        if (STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD)) {
+                               *status |= FE_HAS_VITERBI;
                                reg = STV090x_READ_DEMOD(state, TSSTATUS);
-                               if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
-                                       *status = FE_HAS_SIGNAL |
-                                                 FE_HAS_CARRIER |
-                                                 FE_HAS_VITERBI |
-                                                 FE_HAS_SYNC |
-                                                 FE_HAS_LOCK;
-                               }
+                               if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD))
+                                       *status |= FE_HAS_SYNC | FE_HAS_LOCK;
                        }
                }
                break;
 
        case 3: /* DVB-S1/legacy mode */
                dprintk(FE_DEBUG, 1, "Delivery system: DVB-S");
-               reg = STV090x_READ_DEMOD(state, DSTATUS);
-               if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) {
+               if (STV090x_GETFIELD_Px(dstatus, LOCK_DEFINITIF_FIELD)) {
                        reg = STV090x_READ_DEMOD(state, VSTATUSVIT);
                        if (STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD)) {
+                               *status |= FE_HAS_VITERBI;
                                reg = STV090x_READ_DEMOD(state, TSSTATUS);
-                               if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
-                                       *status = FE_HAS_SIGNAL |
-                                                 FE_HAS_CARRIER |
-                                                 FE_HAS_VITERBI |
-                                                 FE_HAS_SYNC |
-                                                 FE_HAS_LOCK;
-                               }
+                               if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD))
+                                       *status |= FE_HAS_SYNC | FE_HAS_LOCK;
                        }
                }
                break;
index 93f6a75..7f10594 100644 (file)
@@ -206,15 +206,16 @@ static struct init_tab {
 static struct pll_tab {
        u32     clk_freq_khz;
        u32     if_freq_khz;
-       u8      m, n, p;
 } pll_tab[] = {
-       { TDA10048_CLK_4000,  TDA10048_IF_36130, 10, 0, 0 },
-       { TDA10048_CLK_16000, TDA10048_IF_3300,  10, 3, 0 },
-       { TDA10048_CLK_16000, TDA10048_IF_3500,  10, 3, 0 },
-       { TDA10048_CLK_16000, TDA10048_IF_3800,  10, 3, 0 },
-       { TDA10048_CLK_16000, TDA10048_IF_4000,  10, 3, 0 },
-       { TDA10048_CLK_16000, TDA10048_IF_4300,  10, 3, 0 },
-       { TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 },
+       { TDA10048_CLK_4000,  TDA10048_IF_36130 },
+       { TDA10048_CLK_16000, TDA10048_IF_3300 },
+       { TDA10048_CLK_16000, TDA10048_IF_3500 },
+       { TDA10048_CLK_16000, TDA10048_IF_3800 },
+       { TDA10048_CLK_16000, TDA10048_IF_4000 },
+       { TDA10048_CLK_16000, TDA10048_IF_4300 },
+       { TDA10048_CLK_16000, TDA10048_IF_4500 },
+       { TDA10048_CLK_16000, TDA10048_IF_5000 },
+       { TDA10048_CLK_16000, TDA10048_IF_36130 },
 };
 
 static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
@@ -460,9 +461,6 @@ static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw)
 
                        state->freq_if_hz = pll_tab[i].if_freq_khz * 1000;
                        state->xtal_hz = pll_tab[i].clk_freq_khz * 1000;
-                       state->pll_mfactor = pll_tab[i].m;
-                       state->pll_nfactor = pll_tab[i].n;
-                       state->pll_pfactor = pll_tab[i].p;
                        break;
                }
        }
@@ -781,6 +779,10 @@ static int tda10048_init(struct dvb_frontend *fe)
 
        dprintk(1, "%s()\n", __func__);
 
+       /* PLL */
+       init_tab[4].data = (u8)(state->pll_mfactor);
+       init_tab[5].data = (u8)(state->pll_nfactor) | 0x40;
+
        /* Apply register defaults */
        for (i = 0; i < ARRAY_SIZE(init_tab); i++)
                tda10048_writereg(state, init_tab[i].reg, init_tab[i].data);
@@ -1123,7 +1125,7 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
        /* setup the state and clone the config */
        memcpy(&state->config, config, sizeof(*config));
        state->i2c = i2c;
-       state->fwloaded = 0;
+       state->fwloaded = config->no_firmware;
        state->bandwidth = BANDWIDTH_8_MHZ;
 
        /* check if the demod is present */
@@ -1135,6 +1137,17 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
                sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
+       /* set pll */
+       if (config->set_pll) {
+               state->pll_mfactor = config->pll_m;
+               state->pll_nfactor = config->pll_n;
+               state->pll_pfactor = config->pll_p;
+       } else {
+               state->pll_mfactor = 10;
+               state->pll_nfactor = 3;
+               state->pll_pfactor = 0;
+       }
+
        /* Establish any defaults the the user didn't pass */
        tda10048_establish_defaults(&state->frontend);
 
index 8828cea..fb2ef5a 100644 (file)
@@ -51,6 +51,7 @@ struct tda10048_config {
 #define TDA10048_IF_4300  4300
 #define TDA10048_IF_4500  4500
 #define TDA10048_IF_4750  4750
+#define TDA10048_IF_5000  5000
 #define TDA10048_IF_36130 36130
        u16 dtv6_if_freq_khz;
        u16 dtv7_if_freq_khz;
@@ -62,6 +63,13 @@ struct tda10048_config {
 
        /* Disable I2C gate access */
        u8 disable_gate_access;
+
+       bool no_firmware;
+
+       bool set_pll;
+       u8 pll_m;
+       u8 pll_p;
+       u8 pll_n;
 };
 
 #if defined(CONFIG_DVB_TDA10048) || \
diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb/frontends/tda10071.c
new file mode 100644 (file)
index 0000000..0c37434
--- /dev/null
@@ -0,0 +1,1269 @@
+/*
+ * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "tda10071_priv.h"
+
+int tda10071_debug;
+module_param_named(debug, tda10071_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+static struct dvb_frontend_ops tda10071_ops;
+
+/* write multiple registers */
+static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
+       int len)
+{
+       int ret;
+       u8 buf[len+1];
+       struct i2c_msg msg[1] = {
+               {
+                       .addr = priv->cfg.i2c_address,
+                       .flags = 0,
+                       .len = sizeof(buf),
+                       .buf = buf,
+               }
+       };
+
+       buf[0] = reg;
+       memcpy(&buf[1], val, len);
+
+       ret = i2c_transfer(priv->i2c, msg, 1);
+       if (ret == 1) {
+               ret = 0;
+       } else {
+               warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+               ret = -EREMOTEIO;
+       }
+       return ret;
+}
+
+/* read multiple registers */
+static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
+       int len)
+{
+       int ret;
+       u8 buf[len];
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = priv->cfg.i2c_address,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &reg,
+               }, {
+                       .addr = priv->cfg.i2c_address,
+                       .flags = I2C_M_RD,
+                       .len = sizeof(buf),
+                       .buf = buf,
+               }
+       };
+
+       ret = i2c_transfer(priv->i2c, msg, 2);
+       if (ret == 2) {
+               memcpy(val, buf, len);
+               ret = 0;
+       } else {
+               warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+               ret = -EREMOTEIO;
+       }
+       return ret;
+}
+
+/* write single register */
+static int tda10071_wr_reg(struct tda10071_priv *priv, u8 reg, u8 val)
+{
+       return tda10071_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+static int tda10071_rd_reg(struct tda10071_priv *priv, u8 reg, u8 *val)
+{
+       return tda10071_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+int tda10071_wr_reg_mask(struct tda10071_priv *priv, u8 reg, u8 val, u8 mask)
+{
+       int ret;
+       u8 tmp;
+
+       /* no need for read if whole reg is written */
+       if (mask != 0xff) {
+               ret = tda10071_rd_regs(priv, reg, &tmp, 1);
+               if (ret)
+                       return ret;
+
+               val &= mask;
+               tmp &= ~mask;
+               val |= tmp;
+       }
+
+       return tda10071_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register with mask */
+int tda10071_rd_reg_mask(struct tda10071_priv *priv, u8 reg, u8 *val, u8 mask)
+{
+       int ret, i;
+       u8 tmp;
+
+       ret = tda10071_rd_regs(priv, reg, &tmp, 1);
+       if (ret)
+               return ret;
+
+       tmp &= mask;
+
+       /* find position of the first bit */
+       for (i = 0; i < 8; i++) {
+               if ((mask >> i) & 0x01)
+                       break;
+       }
+       *val = tmp >> i;
+
+       return 0;
+}
+
+/* execute firmware command */
+static int tda10071_cmd_execute(struct tda10071_priv *priv,
+       struct tda10071_cmd *cmd)
+{
+       int ret, i;
+       u8 tmp;
+
+       if (!priv->warm) {
+               ret = -EFAULT;
+               goto error;
+       }
+
+       /* write cmd and args for firmware */
+       ret = tda10071_wr_regs(priv, 0x00, cmd->args, cmd->len);
+       if (ret)
+               goto error;
+
+       /* start cmd execution */
+       ret = tda10071_wr_reg(priv, 0x1f, 1);
+       if (ret)
+               goto error;
+
+       /* wait cmd execution terminate */
+       for (i = 1000, tmp = 1; i && tmp; i--) {
+               ret = tda10071_rd_reg(priv, 0x1f, &tmp);
+               if (ret)
+                       goto error;
+
+               usleep_range(200, 5000);
+       }
+
+       dbg("%s: loop=%d", __func__, i);
+
+       if (i == 0) {
+               ret = -ETIMEDOUT;
+               goto error;
+       }
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_set_tone(struct dvb_frontend *fe,
+       fe_sec_tone_mode_t fe_sec_tone_mode)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       struct tda10071_cmd cmd;
+       int ret;
+       u8 tone;
+
+       if (!priv->warm) {
+               ret = -EFAULT;
+               goto error;
+       }
+
+       dbg("%s: tone_mode=%d", __func__, fe_sec_tone_mode);
+
+       switch (fe_sec_tone_mode) {
+       case SEC_TONE_ON:
+               tone = 1;
+               break;
+       case SEC_TONE_OFF:
+               tone = 0;
+               break;
+       default:
+               dbg("%s: invalid fe_sec_tone_mode", __func__);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       cmd.args[0x00] = CMD_LNB_PCB_CONFIG;
+       cmd.args[0x01] = 0;
+       cmd.args[0x02] = 0x00;
+       cmd.args[0x03] = 0x00;
+       cmd.args[0x04] = tone;
+       cmd.len = 0x05;
+       ret = tda10071_cmd_execute(priv, &cmd);
+       if (ret)
+               goto error;
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_set_voltage(struct dvb_frontend *fe,
+       fe_sec_voltage_t fe_sec_voltage)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       struct tda10071_cmd cmd;
+       int ret;
+       u8 voltage;
+
+       if (!priv->warm) {
+               ret = -EFAULT;
+               goto error;
+       }
+
+       dbg("%s: voltage=%d", __func__, fe_sec_voltage);
+
+       switch (fe_sec_voltage) {
+       case SEC_VOLTAGE_13:
+               voltage = 0;
+               break;
+       case SEC_VOLTAGE_18:
+               voltage = 1;
+               break;
+       case SEC_VOLTAGE_OFF:
+               voltage = 0;
+               break;
+       default:
+               dbg("%s: invalid fe_sec_voltage", __func__);
+               ret = -EINVAL;
+               goto error;
+       };
+
+       cmd.args[0x00] = CMD_LNB_SET_DC_LEVEL;
+       cmd.args[0x01] = 0;
+       cmd.args[0x02] = voltage;
+       cmd.len = 0x03;
+       ret = tda10071_cmd_execute(priv, &cmd);
+       if (ret)
+               goto error;
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe,
+       struct dvb_diseqc_master_cmd *diseqc_cmd)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       struct tda10071_cmd cmd;
+       int ret, i;
+       u8 tmp;
+
+       if (!priv->warm) {
+               ret = -EFAULT;
+               goto error;
+       }
+
+       dbg("%s: msg_len=%d", __func__, diseqc_cmd->msg_len);
+
+       if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 16) {
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* wait LNB TX */
+       for (i = 500, tmp = 0; i && !tmp; i--) {
+               ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x01);
+               if (ret)
+                       goto error;
+
+               usleep_range(10000, 20000);
+       }
+
+       dbg("%s: loop=%d", __func__, i);
+
+       if (i == 0) {
+               ret = -ETIMEDOUT;
+               goto error;
+       }
+
+       ret = tda10071_wr_reg_mask(priv, 0x47, 0x00, 0x01);
+       if (ret)
+               goto error;
+
+       cmd.args[0x00] = CMD_LNB_SEND_DISEQC;
+       cmd.args[0x01] = 0;
+       cmd.args[0x02] = 0;
+       cmd.args[0x03] = 0;
+       cmd.args[0x04] = 2;
+       cmd.args[0x05] = 0;
+       cmd.args[0x06] = diseqc_cmd->msg_len;
+       memcpy(&cmd.args[0x07], diseqc_cmd->msg, diseqc_cmd->msg_len);
+       cmd.len = 0x07 + diseqc_cmd->msg_len;
+       ret = tda10071_cmd_execute(priv, &cmd);
+       if (ret)
+               goto error;
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe,
+       struct dvb_diseqc_slave_reply *reply)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       struct tda10071_cmd cmd;
+       int ret, i;
+       u8 tmp;
+
+       if (!priv->warm) {
+               ret = -EFAULT;
+               goto error;
+       }
+
+       dbg("%s:", __func__);
+
+       /* wait LNB RX */
+       for (i = 500, tmp = 0; i && !tmp; i--) {
+               ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x02);
+               if (ret)
+                       goto error;
+
+               usleep_range(10000, 20000);
+       }
+
+       dbg("%s: loop=%d", __func__, i);
+
+       if (i == 0) {
+               ret = -ETIMEDOUT;
+               goto error;
+       }
+
+       /* reply len */
+       ret = tda10071_rd_reg(priv, 0x46, &tmp);
+       if (ret)
+               goto error;
+
+       reply->msg_len = tmp & 0x1f; /* [4:0] */;
+       if (reply->msg_len > sizeof(reply->msg))
+               reply->msg_len = sizeof(reply->msg); /* truncate API max */
+
+       /* read reply */
+       cmd.args[0x00] = CMD_LNB_UPDATE_REPLY;
+       cmd.args[0x01] = 0;
+       cmd.len = 0x02;
+       ret = tda10071_cmd_execute(priv, &cmd);
+       if (ret)
+               goto error;
+
+       ret = tda10071_rd_regs(priv, cmd.len, reply->msg, reply->msg_len);
+       if (ret)
+               goto error;
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_diseqc_send_burst(struct dvb_frontend *fe,
+       fe_sec_mini_cmd_t fe_sec_mini_cmd)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       struct tda10071_cmd cmd;
+       int ret, i;
+       u8 tmp, burst;
+
+       if (!priv->warm) {
+               ret = -EFAULT;
+               goto error;
+       }
+
+       dbg("%s: fe_sec_mini_cmd=%d", __func__, fe_sec_mini_cmd);
+
+       switch (fe_sec_mini_cmd) {
+       case SEC_MINI_A:
+               burst = 0;
+               break;
+       case SEC_MINI_B:
+               burst = 1;
+               break;
+       default:
+               dbg("%s: invalid fe_sec_mini_cmd", __func__);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* wait LNB TX */
+       for (i = 500, tmp = 0; i && !tmp; i--) {
+               ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x01);
+               if (ret)
+                       goto error;
+
+               usleep_range(10000, 20000);
+       }
+
+       dbg("%s: loop=%d", __func__, i);
+
+       if (i == 0) {
+               ret = -ETIMEDOUT;
+               goto error;
+       }
+
+       ret = tda10071_wr_reg_mask(priv, 0x47, 0x00, 0x01);
+       if (ret)
+               goto error;
+
+       cmd.args[0x00] = CMD_LNB_SEND_TONEBURST;
+       cmd.args[0x01] = 0;
+       cmd.args[0x02] = burst;
+       cmd.len = 0x03;
+       ret = tda10071_cmd_execute(priv, &cmd);
+       if (ret)
+               goto error;
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 tmp;
+
+       *status = 0;
+
+       if (!priv->warm) {
+               ret = 0;
+               goto error;
+       }
+
+       ret = tda10071_rd_reg(priv, 0x39, &tmp);
+       if (ret)
+               goto error;
+
+       if (tmp & 0x01) /* tuner PLL */
+               *status |= FE_HAS_SIGNAL;
+       if (tmp & 0x02) /* demod PLL */
+               *status |= FE_HAS_CARRIER;
+       if (tmp & 0x04) /* viterbi or LDPC*/
+               *status |= FE_HAS_VITERBI;
+       if (tmp & 0x08) /* RS or BCH */
+               *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+
+       priv->fe_status = *status;
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 buf[2];
+
+       if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
+               *snr = 0;
+               ret = 0;
+               goto error;
+       }
+
+       ret = tda10071_rd_regs(priv, 0x3a, buf, 2);
+       if (ret)
+               goto error;
+
+       /* Es/No dBx10 */
+       *snr = buf[0] << 8 | buf[1];
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       struct tda10071_cmd cmd;
+       int ret;
+       u8 tmp;
+
+       if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
+               *strength = 0;
+               ret = 0;
+               goto error;
+       }
+
+       cmd.args[0x00] = CMD_GET_AGCACC;
+       cmd.args[0x01] = 0;
+       cmd.len = 0x02;
+       ret = tda10071_cmd_execute(priv, &cmd);
+       if (ret)
+               goto error;
+
+       /* input power estimate dBm */
+       ret = tda10071_rd_reg(priv, 0x50, &tmp);
+       if (ret)
+               goto error;
+
+       if (tmp < 181)
+               tmp = 181; /* -75 dBm */
+       else if (tmp > 236)
+               tmp = 236; /* -20 dBm */
+
+       /* scale value to 0x0000-0xffff */
+       *strength = (tmp-181) * 0xffff / (236-181);
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       struct tda10071_cmd cmd;
+       int ret, i, len;
+       u8 tmp, reg, buf[8];
+
+       if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
+               *ber = priv->ber = 0;
+               ret = 0;
+               goto error;
+       }
+
+       switch (priv->delivery_system) {
+       case SYS_DVBS:
+               reg = 0x4c;
+               len = 8;
+               i = 1;
+               break;
+       case SYS_DVBS2:
+               reg = 0x4d;
+               len = 4;
+               i = 0;
+               break;
+       default:
+               *ber = priv->ber = 0;
+               return 0;
+       }
+
+       ret = tda10071_rd_reg(priv, reg, &tmp);
+       if (ret)
+               goto error;
+
+       if (priv->meas_count[i] == tmp) {
+               dbg("%s: meas not ready=%02x", __func__, tmp);
+               *ber = priv->ber;
+               return 0;
+       } else {
+               priv->meas_count[i] = tmp;
+       }
+
+       cmd.args[0x00] = CMD_BER_UPDATE_COUNTERS;
+       cmd.args[0x01] = 0;
+       cmd.args[0x02] = i;
+       cmd.len = 0x03;
+       ret = tda10071_cmd_execute(priv, &cmd);
+       if (ret)
+               goto error;
+
+       ret = tda10071_rd_regs(priv, cmd.len, buf, len);
+       if (ret)
+               goto error;
+
+       if (priv->delivery_system == SYS_DVBS) {
+               *ber = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+               priv->ucb += (buf[4] << 8) | buf[5];
+       } else {
+               *ber = (buf[0] << 8) | buf[1];
+       }
+       priv->ber = *ber;
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       int ret = 0;
+
+       if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
+               *ucblocks = 0;
+               goto error;
+       }
+
+       /* UCB is updated when BER is read. Assume BER is read anyway. */
+
+       *ucblocks = priv->ucb;
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_set_frontend(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       struct tda10071_cmd cmd;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret, i;
+       u8 mode, rolloff, pilot, inversion, div;
+
+       dbg("%s: delivery_system=%d modulation=%d frequency=%d " \
+               "symbol_rate=%d inversion=%d pilot=%d rolloff=%d", __func__,
+               c->delivery_system, c->modulation, c->frequency,
+               c->symbol_rate, c->inversion, c->pilot, c->rolloff);
+
+       priv->delivery_system = SYS_UNDEFINED;
+
+       if (!priv->warm) {
+               ret = -EFAULT;
+               goto error;
+       }
+
+       switch (c->inversion) {
+       case INVERSION_OFF:
+               inversion = 1;
+               break;
+       case INVERSION_ON:
+               inversion = 0;
+               break;
+       case INVERSION_AUTO:
+               /* 2 = auto; try first on then off
+                * 3 = auto; try first off then on */
+               inversion = 3;
+               break;
+       default:
+               dbg("%s: invalid inversion", __func__);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+               rolloff = 0;
+               pilot = 2;
+               break;
+       case SYS_DVBS2:
+               switch (c->rolloff) {
+               case ROLLOFF_20:
+                       rolloff = 2;
+                       break;
+               case ROLLOFF_25:
+                       rolloff = 1;
+                       break;
+               case ROLLOFF_35:
+                       rolloff = 0;
+                       break;
+               case ROLLOFF_AUTO:
+               default:
+                       dbg("%s: invalid rolloff", __func__);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               switch (c->pilot) {
+               case PILOT_OFF:
+                       pilot = 0;
+                       break;
+               case PILOT_ON:
+                       pilot = 1;
+                       break;
+               case PILOT_AUTO:
+                       pilot = 2;
+                       break;
+               default:
+                       dbg("%s: invalid pilot", __func__);
+                       ret = -EINVAL;
+                       goto error;
+               }
+               break;
+       default:
+               dbg("%s: invalid delivery_system", __func__);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       for (i = 0, mode = 0xff; i < ARRAY_SIZE(TDA10071_MODCOD); i++) {
+               if (c->delivery_system == TDA10071_MODCOD[i].delivery_system &&
+                       c->modulation == TDA10071_MODCOD[i].modulation &&
+                       c->fec_inner == TDA10071_MODCOD[i].fec) {
+                       mode = TDA10071_MODCOD[i].val;
+                       dbg("%s: mode found=%02x", __func__, mode);
+                       break;
+               }
+       }
+
+       if (mode == 0xff) {
+               dbg("%s: invalid parameter combination", __func__);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       if (c->symbol_rate <= 5000000)
+               div = 14;
+       else
+               div = 4;
+
+       ret = tda10071_wr_reg(priv, 0x81, div);
+       if (ret)
+               goto error;
+
+       ret = tda10071_wr_reg(priv, 0xe3, div);
+       if (ret)
+               goto error;
+
+       cmd.args[0x00] = CMD_CHANGE_CHANNEL;
+       cmd.args[0x01] = 0;
+       cmd.args[0x02] = mode;
+       cmd.args[0x03] = (c->frequency >> 16) & 0xff;
+       cmd.args[0x04] = (c->frequency >>  8) & 0xff;
+       cmd.args[0x05] = (c->frequency >>  0) & 0xff;
+       cmd.args[0x06] = ((c->symbol_rate / 1000) >> 8) & 0xff;
+       cmd.args[0x07] = ((c->symbol_rate / 1000) >> 0) & 0xff;
+       cmd.args[0x08] = (tda10071_ops.info.frequency_tolerance >> 8) & 0xff;
+       cmd.args[0x09] = (tda10071_ops.info.frequency_tolerance >> 0) & 0xff;
+       cmd.args[0x0a] = rolloff;
+       cmd.args[0x0b] = inversion;
+       cmd.args[0x0c] = pilot;
+       cmd.args[0x0d] = 0x00;
+       cmd.args[0x0e] = 0x00;
+       cmd.len = 0x0f;
+       ret = tda10071_cmd_execute(priv, &cmd);
+       if (ret)
+               goto error;
+
+       priv->delivery_system = c->delivery_system;
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_get_frontend(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret, i;
+       u8 buf[5], tmp;
+
+       if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
+               ret = -EFAULT;
+               goto error;
+       }
+
+       ret = tda10071_rd_regs(priv, 0x30, buf, 5);
+       if (ret)
+               goto error;
+
+       tmp = buf[0] & 0x3f;
+       for (i = 0; i < ARRAY_SIZE(TDA10071_MODCOD); i++) {
+               if (tmp == TDA10071_MODCOD[i].val) {
+                       c->modulation = TDA10071_MODCOD[i].modulation;
+                       c->fec_inner = TDA10071_MODCOD[i].fec;
+                       c->delivery_system = TDA10071_MODCOD[i].delivery_system;
+               }
+       }
+
+       switch ((buf[1] >> 0) & 0x01) {
+       case 0:
+               c->inversion = INVERSION_OFF;
+               break;
+       case 1:
+               c->inversion = INVERSION_ON;
+               break;
+       }
+
+       switch ((buf[1] >> 7) & 0x01) {
+       case 0:
+               c->pilot = PILOT_OFF;
+               break;
+       case 1:
+               c->pilot = PILOT_ON;
+               break;
+       }
+
+       c->frequency = (buf[2] << 16) | (buf[3] << 8) | (buf[4] << 0);
+
+       ret = tda10071_rd_regs(priv, 0x52, buf, 3);
+       if (ret)
+               goto error;
+
+       c->symbol_rate = (buf[0] << 16) | (buf[1] << 8) | (buf[2] << 0);
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_init(struct dvb_frontend *fe)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       struct tda10071_cmd cmd;
+       int ret, i, len, remaining, fw_size;
+       const struct firmware *fw;
+       u8 *fw_file = TDA10071_DEFAULT_FIRMWARE;
+       u8 tmp, buf[4];
+       struct tda10071_reg_val_mask tab[] = {
+               { 0xcd, 0x00, 0x07 },
+               { 0x80, 0x00, 0x02 },
+               { 0xcd, 0x00, 0xc0 },
+               { 0xce, 0x00, 0x1b },
+               { 0x9d, 0x00, 0x01 },
+               { 0x9d, 0x00, 0x02 },
+               { 0x9e, 0x00, 0x01 },
+               { 0x87, 0x00, 0x80 },
+               { 0xce, 0x00, 0x08 },
+               { 0xce, 0x00, 0x10 },
+       };
+       struct tda10071_reg_val_mask tab2[] = {
+               { 0xf1, 0x70, 0xff },
+               { 0x88, priv->cfg.pll_multiplier, 0x3f },
+               { 0x89, 0x00, 0x10 },
+               { 0x89, 0x10, 0x10 },
+               { 0xc0, 0x01, 0x01 },
+               { 0xc0, 0x00, 0x01 },
+               { 0xe0, 0xff, 0xff },
+               { 0xe0, 0x00, 0xff },
+               { 0x96, 0x1e, 0x7e },
+               { 0x8b, 0x08, 0x08 },
+               { 0x8b, 0x00, 0x08 },
+               { 0x8f, 0x1a, 0x7e },
+               { 0x8c, 0x68, 0xff },
+               { 0x8d, 0x08, 0xff },
+               { 0x8e, 0x4c, 0xff },
+               { 0x8f, 0x01, 0x01 },
+               { 0x8b, 0x04, 0x04 },
+               { 0x8b, 0x00, 0x04 },
+               { 0x87, 0x05, 0x07 },
+               { 0x80, 0x00, 0x20 },
+               { 0xc8, 0x01, 0xff },
+               { 0xb4, 0x47, 0xff },
+               { 0xb5, 0x9c, 0xff },
+               { 0xb6, 0x7d, 0xff },
+               { 0xba, 0x00, 0x03 },
+               { 0xb7, 0x47, 0xff },
+               { 0xb8, 0x9c, 0xff },
+               { 0xb9, 0x7d, 0xff },
+               { 0xba, 0x00, 0x0c },
+               { 0xc8, 0x00, 0xff },
+               { 0xcd, 0x00, 0x04 },
+               { 0xcd, 0x00, 0x20 },
+               { 0xe8, 0x02, 0xff },
+               { 0xcf, 0x20, 0xff },
+               { 0x9b, 0xd7, 0xff },
+               { 0x9a, 0x01, 0x03 },
+               { 0xa8, 0x05, 0x0f },
+               { 0xa8, 0x65, 0xf0 },
+               { 0xa6, 0xa0, 0xf0 },
+               { 0x9d, 0x50, 0xfc },
+               { 0x9e, 0x20, 0xe0 },
+               { 0xa3, 0x1c, 0x7c },
+               { 0xd5, 0x03, 0x03 },
+       };
+
+       /* firmware status */
+       ret = tda10071_rd_reg(priv, 0x51, &tmp);
+       if (ret)
+               goto error;
+
+       if (!tmp) {
+               /* warm state - wake up device from sleep */
+               priv->warm = 1;
+
+               for (i = 0; i < ARRAY_SIZE(tab); i++) {
+                       ret = tda10071_wr_reg_mask(priv, tab[i].reg,
+                               tab[i].val, tab[i].mask);
+                       if (ret)
+                               goto error;
+               }
+
+               cmd.args[0x00] = CMD_SET_SLEEP_MODE;
+               cmd.args[0x01] = 0;
+               cmd.args[0x02] = 0;
+               cmd.len = 0x03;
+               ret = tda10071_cmd_execute(priv, &cmd);
+               if (ret)
+                       goto error;
+       } else {
+               /* cold state - try to download firmware */
+               priv->warm = 0;
+
+               /* request the firmware, this will block and timeout */
+               ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent);
+               if (ret) {
+                       err("did not find the firmware file. (%s) "
+                               "Please see linux/Documentation/dvb/ for more" \
+                               " details on firmware-problems. (%d)",
+                               fw_file, ret);
+                       goto error;
+               }
+
+               /* init */
+               for (i = 0; i < ARRAY_SIZE(tab2); i++) {
+                       ret = tda10071_wr_reg_mask(priv, tab2[i].reg,
+                               tab2[i].val, tab2[i].mask);
+                       if (ret)
+                               goto error_release_firmware;
+               }
+
+               /*  download firmware */
+               ret = tda10071_wr_reg(priv, 0xe0, 0x7f);
+               if (ret)
+                       goto error_release_firmware;
+
+               ret = tda10071_wr_reg(priv, 0xf7, 0x81);
+               if (ret)
+                       goto error_release_firmware;
+
+               ret = tda10071_wr_reg(priv, 0xf8, 0x00);
+               if (ret)
+                       goto error_release_firmware;
+
+               ret = tda10071_wr_reg(priv, 0xf9, 0x00);
+               if (ret)
+                       goto error_release_firmware;
+
+               info("found a '%s' in cold state, will try to load a firmware",
+                       tda10071_ops.info.name);
+
+               info("downloading firmware from file '%s'", fw_file);
+
+               /* do not download last byte */
+               fw_size = fw->size - 1;
+
+               for (remaining = fw_size; remaining > 0;
+                       remaining -= (priv->cfg.i2c_wr_max - 1)) {
+                       len = remaining;
+                       if (len > (priv->cfg.i2c_wr_max - 1))
+                               len = (priv->cfg.i2c_wr_max - 1);
+
+                       ret = tda10071_wr_regs(priv, 0xfa,
+                               (u8 *) &fw->data[fw_size - remaining], len);
+                       if (ret) {
+                               err("firmware download failed=%d", ret);
+                               if (ret)
+                                       goto error_release_firmware;
+                       }
+               }
+               release_firmware(fw);
+
+               ret = tda10071_wr_reg(priv, 0xf7, 0x0c);
+               if (ret)
+                       goto error;
+
+               ret = tda10071_wr_reg(priv, 0xe0, 0x00);
+               if (ret)
+                       goto error;
+
+               /* wait firmware start */
+               msleep(250);
+
+               /* firmware status */
+               ret = tda10071_rd_reg(priv, 0x51, &tmp);
+               if (ret)
+                       goto error;
+
+               if (tmp) {
+                       info("firmware did not run");
+                       ret = -EFAULT;
+                       goto error;
+               } else {
+                       priv->warm = 1;
+               }
+
+               cmd.args[0x00] = CMD_GET_FW_VERSION;
+               cmd.len = 0x01;
+               ret = tda10071_cmd_execute(priv, &cmd);
+               if (ret)
+                       goto error;
+
+               ret = tda10071_rd_regs(priv, cmd.len, buf, 4);
+               if (ret)
+                       goto error;
+
+               info("firmware version %d.%d.%d.%d",
+                       buf[0], buf[1], buf[2], buf[3]);
+               info("found a '%s' in warm state.", tda10071_ops.info.name);
+
+               ret = tda10071_rd_regs(priv, 0x81, buf, 2);
+               if (ret)
+                       goto error;
+
+               cmd.args[0x00] = CMD_DEMOD_INIT;
+               cmd.args[0x01] = ((priv->cfg.xtal / 1000) >> 8) & 0xff;
+               cmd.args[0x02] = ((priv->cfg.xtal / 1000) >> 0) & 0xff;
+               cmd.args[0x03] = buf[0];
+               cmd.args[0x04] = buf[1];
+               cmd.args[0x05] = priv->cfg.pll_multiplier;
+               cmd.args[0x06] = priv->cfg.spec_inv;
+               cmd.args[0x07] = 0x00;
+               cmd.len = 0x08;
+               ret = tda10071_cmd_execute(priv, &cmd);
+               if (ret)
+                       goto error;
+
+               cmd.args[0x00] = CMD_TUNER_INIT;
+               cmd.args[0x01] = 0x00;
+               cmd.args[0x02] = 0x00;
+               cmd.args[0x03] = 0x00;
+               cmd.args[0x04] = 0x00;
+               cmd.args[0x05] = 0x14;
+               cmd.args[0x06] = 0x00;
+               cmd.args[0x07] = 0x03;
+               cmd.args[0x08] = 0x02;
+               cmd.args[0x09] = 0x02;
+               cmd.args[0x0a] = 0x00;
+               cmd.args[0x0b] = 0x00;
+               cmd.args[0x0c] = 0x00;
+               cmd.args[0x0d] = 0x00;
+               cmd.args[0x0e] = 0x00;
+               cmd.len = 0x0f;
+               ret = tda10071_cmd_execute(priv, &cmd);
+               if (ret)
+                       goto error;
+
+               cmd.args[0x00] = CMD_MPEG_CONFIG;
+               cmd.args[0x01] = 0;
+               cmd.args[0x02] = priv->cfg.ts_mode;
+               cmd.args[0x03] = 0x00;
+               cmd.args[0x04] = 0x04;
+               cmd.args[0x05] = 0x00;
+               cmd.len = 0x06;
+               ret = tda10071_cmd_execute(priv, &cmd);
+               if (ret)
+                       goto error;
+
+               ret = tda10071_wr_reg_mask(priv, 0xf0, 0x01, 0x01);
+               if (ret)
+                       goto error;
+
+               cmd.args[0x00] = CMD_LNB_CONFIG;
+               cmd.args[0x01] = 0;
+               cmd.args[0x02] = 150;
+               cmd.args[0x03] = 3;
+               cmd.args[0x04] = 22;
+               cmd.args[0x05] = 1;
+               cmd.args[0x06] = 1;
+               cmd.args[0x07] = 30;
+               cmd.args[0x08] = 30;
+               cmd.args[0x09] = 30;
+               cmd.args[0x0a] = 30;
+               cmd.len = 0x0b;
+               ret = tda10071_cmd_execute(priv, &cmd);
+               if (ret)
+                       goto error;
+
+               cmd.args[0x00] = CMD_BER_CONTROL;
+               cmd.args[0x01] = 0;
+               cmd.args[0x02] = 14;
+               cmd.args[0x03] = 14;
+               cmd.len = 0x04;
+               ret = tda10071_cmd_execute(priv, &cmd);
+               if (ret)
+                       goto error;
+       }
+
+       return ret;
+error_release_firmware:
+       release_firmware(fw);
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_sleep(struct dvb_frontend *fe)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       struct tda10071_cmd cmd;
+       int ret, i;
+       struct tda10071_reg_val_mask tab[] = {
+               { 0xcd, 0x07, 0x07 },
+               { 0x80, 0x02, 0x02 },
+               { 0xcd, 0xc0, 0xc0 },
+               { 0xce, 0x1b, 0x1b },
+               { 0x9d, 0x01, 0x01 },
+               { 0x9d, 0x02, 0x02 },
+               { 0x9e, 0x01, 0x01 },
+               { 0x87, 0x80, 0x80 },
+               { 0xce, 0x08, 0x08 },
+               { 0xce, 0x10, 0x10 },
+       };
+
+       if (!priv->warm) {
+               ret = -EFAULT;
+               goto error;
+       }
+
+       cmd.args[0x00] = CMD_SET_SLEEP_MODE;
+       cmd.args[0x01] = 0;
+       cmd.args[0x02] = 1;
+       cmd.len = 0x03;
+       ret = tda10071_cmd_execute(priv, &cmd);
+       if (ret)
+               goto error;
+
+       for (i = 0; i < ARRAY_SIZE(tab); i++) {
+               ret = tda10071_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+                       tab[i].mask);
+               if (ret)
+                       goto error;
+       }
+
+       return ret;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int tda10071_get_tune_settings(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *s)
+{
+       s->min_delay_ms = 8000;
+       s->step_size = 0;
+       s->max_drift = 0;
+
+       return 0;
+}
+
+static void tda10071_release(struct dvb_frontend *fe)
+{
+       struct tda10071_priv *priv = fe->demodulator_priv;
+       kfree(priv);
+}
+
+struct dvb_frontend *tda10071_attach(const struct tda10071_config *config,
+       struct i2c_adapter *i2c)
+{
+       int ret;
+       struct tda10071_priv *priv = NULL;
+       u8 tmp;
+
+       /* allocate memory for the internal priv */
+       priv = kzalloc(sizeof(struct tda10071_priv), GFP_KERNEL);
+       if (priv == NULL) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       /* setup the priv */
+       priv->i2c = i2c;
+       memcpy(&priv->cfg, config, sizeof(struct tda10071_config));
+
+       /* chip ID */
+       ret = tda10071_rd_reg(priv, 0xff, &tmp);
+       if (ret || tmp != 0x0f)
+               goto error;
+
+       /* chip type */
+       ret = tda10071_rd_reg(priv, 0xdd, &tmp);
+       if (ret || tmp != 0x00)
+               goto error;
+
+       /* chip version */
+       ret = tda10071_rd_reg(priv, 0xfe, &tmp);
+       if (ret || tmp != 0x01)
+               goto error;
+
+       /* create dvb_frontend */
+       memcpy(&priv->fe.ops, &tda10071_ops, sizeof(struct dvb_frontend_ops));
+       priv->fe.demodulator_priv = priv;
+
+       return &priv->fe;
+error:
+       dbg("%s: failed=%d", __func__, ret);
+       kfree(priv);
+       return NULL;
+}
+EXPORT_SYMBOL(tda10071_attach);
+
+static struct dvb_frontend_ops tda10071_ops = {
+       .info = {
+               .name = "NXP TDA10071",
+               .type = FE_QPSK,
+               .frequency_min = 950000,
+               .frequency_max = 2150000,
+               .frequency_tolerance = 5000,
+               .symbol_rate_min = 1000000,
+               .symbol_rate_max = 45000000,
+               .caps = FE_CAN_INVERSION_AUTO |
+                       FE_CAN_FEC_1_2 |
+                       FE_CAN_FEC_2_3 |
+                       FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_4_5 |
+                       FE_CAN_FEC_5_6 |
+                       FE_CAN_FEC_6_7 |
+                       FE_CAN_FEC_7_8 |
+                       FE_CAN_FEC_8_9 |
+                       FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK |
+                       FE_CAN_RECOVER |
+                       FE_CAN_2G_MODULATION
+       },
+
+       .release = tda10071_release,
+
+       .get_tune_settings = tda10071_get_tune_settings,
+
+       .init = tda10071_init,
+       .sleep = tda10071_sleep,
+
+       .set_frontend = tda10071_set_frontend,
+       .get_frontend = tda10071_get_frontend,
+
+       .read_status = tda10071_read_status,
+       .read_snr = tda10071_read_snr,
+       .read_signal_strength = tda10071_read_signal_strength,
+       .read_ber = tda10071_read_ber,
+       .read_ucblocks = tda10071_read_ucblocks,
+
+       .diseqc_send_master_cmd = tda10071_diseqc_send_master_cmd,
+       .diseqc_recv_slave_reply = tda10071_diseqc_recv_slave_reply,
+       .diseqc_send_burst = tda10071_diseqc_send_burst,
+
+       .set_tone = tda10071_set_tone,
+       .set_voltage = tda10071_set_voltage,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("NXP TDA10071 DVB-S/S2 demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda10071.h b/drivers/media/dvb/frontends/tda10071.h
new file mode 100644 (file)
index 0000000..21163c4
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TDA10071_H
+#define TDA10071_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda10071_config {
+       /* Demodulator I2C address.
+        * Default: none, must set
+        * Values: 0x55,
+        */
+       u8 i2c_address;
+
+       /* Max bytes I2C provider can write at once.
+        * Note: Buffer is taken from the stack currently!
+        * Default: none, must set
+        * Values:
+        */
+       u16 i2c_wr_max;
+
+       /* TS output mode.
+        * Default: TDA10071_TS_SERIAL
+        * Values:
+        */
+#define TDA10071_TS_SERIAL        0
+#define TDA10071_TS_PARALLEL      1
+       u8 ts_mode;
+
+       /* Input spectrum inversion.
+        * Default: 0
+        * Values: 0, 1
+        */
+       bool spec_inv;
+
+       /* Xtal frequency Hz
+        * Default: none, must set
+        * Values:
+        */
+       u32 xtal;
+
+       /* PLL multiplier.
+        * Default: none, must set
+        * Values:
+        */
+       u8 pll_multiplier;
+};
+
+
+#if defined(CONFIG_DVB_TDA10071) || \
+       (defined(CONFIG_DVB_TDA10071_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda10071_attach(
+       const struct tda10071_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *tda10071_attach(
+       const struct tda10071_config *config, struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif /* TDA10071_H */
diff --git a/drivers/media/dvb/frontends/tda10071_priv.h b/drivers/media/dvb/frontends/tda10071_priv.h
new file mode 100644 (file)
index 0000000..93c5e63
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TDA10071_PRIV
+#define TDA10071_PRIV
+
+#include "dvb_frontend.h"
+#include "tda10071.h"
+#include <linux/firmware.h>
+
+#define LOG_PREFIX "tda10071"
+
+#undef dbg
+#define dbg(f, arg...) \
+       if (tda10071_debug) \
+               printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct tda10071_priv {
+       struct i2c_adapter *i2c;
+       struct dvb_frontend fe;
+       struct tda10071_config cfg;
+
+       u8 meas_count[2];
+       u32 ber;
+       u32 ucb;
+       fe_status_t fe_status;
+       fe_delivery_system_t delivery_system;
+       bool warm; /* FW running */
+};
+
+static struct tda10071_modcod {
+       fe_delivery_system_t delivery_system;
+       fe_modulation_t modulation;
+       fe_code_rate_t fec;
+       u8 val;
+} TDA10071_MODCOD[] = {
+       /* NBC-QPSK */
+       { SYS_DVBS2, QPSK,  FEC_AUTO, 0x00 },
+       { SYS_DVBS2, QPSK,  FEC_1_2,  0x04 },
+       { SYS_DVBS2, QPSK,  FEC_3_5,  0x05 },
+       { SYS_DVBS2, QPSK,  FEC_2_3,  0x06 },
+       { SYS_DVBS2, QPSK,  FEC_3_4,  0x07 },
+       { SYS_DVBS2, QPSK,  FEC_4_5,  0x08 },
+       { SYS_DVBS2, QPSK,  FEC_5_6,  0x09 },
+       { SYS_DVBS2, QPSK,  FEC_8_9,  0x0a },
+       { SYS_DVBS2, QPSK,  FEC_9_10, 0x0b },
+       /* 8PSK */
+       { SYS_DVBS2, PSK_8, FEC_3_5,  0x0c },
+       { SYS_DVBS2, PSK_8, FEC_2_3,  0x0d },
+       { SYS_DVBS2, PSK_8, FEC_3_4,  0x0e },
+       { SYS_DVBS2, PSK_8, FEC_5_6,  0x0f },
+       { SYS_DVBS2, PSK_8, FEC_8_9,  0x10 },
+       { SYS_DVBS2, PSK_8, FEC_9_10, 0x11 },
+       /* QPSK */
+       { SYS_DVBS,  QPSK,  FEC_AUTO, 0x2d },
+       { SYS_DVBS,  QPSK,  FEC_1_2,  0x2e },
+       { SYS_DVBS,  QPSK,  FEC_2_3,  0x2f },
+       { SYS_DVBS,  QPSK,  FEC_3_4,  0x30 },
+       { SYS_DVBS,  QPSK,  FEC_5_6,  0x31 },
+       { SYS_DVBS,  QPSK,  FEC_7_8,  0x32 },
+};
+
+struct tda10071_reg_val_mask {
+       u8 reg;
+       u8 val;
+       u8 mask;
+};
+
+/* firmware filename */
+#define TDA10071_DEFAULT_FIRMWARE      "dvb-fe-tda10071.fw"
+
+/* firmware commands */
+#define CMD_DEMOD_INIT          0x10
+#define CMD_CHANGE_CHANNEL      0x11
+#define CMD_MPEG_CONFIG         0x13
+#define CMD_TUNER_INIT          0x15
+#define CMD_GET_AGCACC          0x1a
+
+#define CMD_LNB_CONFIG          0x20
+#define CMD_LNB_SEND_DISEQC     0x21
+#define CMD_LNB_SET_DC_LEVEL    0x22
+#define CMD_LNB_PCB_CONFIG      0x23
+#define CMD_LNB_SEND_TONEBURST  0x24
+#define CMD_LNB_UPDATE_REPLY    0x25
+
+#define CMD_GET_FW_VERSION      0x35
+#define CMD_SET_SLEEP_MODE      0x36
+#define CMD_BER_CONTROL         0x3e
+#define CMD_BER_UPDATE_COUNTERS 0x3f
+
+/* firmare command struct */
+#define TDA10071_ARGLEN      0x1e
+struct tda10071_cmd {
+       u8 args[TDA10071_ARGLEN];
+       u8 len;
+};
+
+
+#endif /* TDA10071_PRIV */
index 0384e8d..1b1bf20 100644 (file)
@@ -1195,7 +1195,7 @@ static int GetSignalStrength(s32 *pSignalStrength, u32 RFAgc, u32 IFAgc)
 }
 #endif
 
-static int get_frequency(struct dvb_frontend *fe, u32 *frequency)
+static int get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
        struct tda_state *state = fe->tuner_priv;
 
@@ -1222,7 +1222,7 @@ static struct dvb_tuner_ops tuner_ops = {
        .sleep             = sleep,
        .set_params        = set_params,
        .release           = release,
-       .get_frequency     = get_frequency,
+       .get_if_frequency  = get_if_frequency,
        .get_bandwidth     = get_bandwidth,
 };
 
index 98dc5cd..ec8116d 100644 (file)
@@ -25,4 +25,4 @@ obj-$(CONFIG_MANTIS_CORE)     += mantis_core.o
 obj-$(CONFIG_DVB_MANTIS)       += mantis.o
 obj-$(CONFIG_DVB_HOPPER)       += hopper.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
index 1402062..71622f6 100644 (file)
@@ -65,7 +65,7 @@ static int devs;
 
 static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
 {
-       u32 stat = 0, mask = 0, lstat = 0, mstat = 0;
+       u32 stat = 0, mask = 0, lstat = 0;
        u32 rst_stat = 0, rst_mask = 0;
 
        struct mantis_pci *mantis;
@@ -80,7 +80,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
 
        stat = mmread(MANTIS_INT_STAT);
        mask = mmread(MANTIS_INT_MASK);
-       mstat = lstat = stat & ~MANTIS_INT_RISCSTAT;
+       lstat = stat & ~MANTIS_INT_RISCSTAT;
        if (!(stat & mask))
                return IRQ_NONE;
 
@@ -126,7 +126,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
        }
        if (stat & MANTIS_INT_RISCI) {
                dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
-               mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+               mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
                tasklet_schedule(&mantis->tasklet);
        }
        if (stat & MANTIS_INT_I2CDONE) {
index 05cbb9d..c2bb90b 100644 (file)
@@ -73,7 +73,7 @@ static char *label[10] = {
 
 static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
 {
-       u32 stat = 0, mask = 0, lstat = 0, mstat = 0;
+       u32 stat = 0, mask = 0, lstat = 0;
        u32 rst_stat = 0, rst_mask = 0;
 
        struct mantis_pci *mantis;
@@ -88,7 +88,7 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
 
        stat = mmread(MANTIS_INT_STAT);
        mask = mmread(MANTIS_INT_MASK);
-       mstat = lstat = stat & ~MANTIS_INT_RISCSTAT;
+       lstat = stat & ~MANTIS_INT_RISCSTAT;
        if (!(stat & mask))
                return IRQ_NONE;
 
@@ -134,7 +134,7 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
        }
        if (stat & MANTIS_INT_RISCI) {
                dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
-               mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+               mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
                tasklet_schedule(&mantis->tasklet);
        }
        if (stat & MANTIS_INT_I2CDONE) {
index 49dbca1..f2410cf 100644 (file)
@@ -123,11 +123,8 @@ struct mantis_pci {
        unsigned int            num;
 
        /*      RISC Core               */
-       u32                     finished_block;
+       u32                     busy_block;
        u32                     last_block;
-       u32                     line_bytes;
-       u32                     line_count;
-       u32                     risc_pos;
        u8                      *buf_cpu;
        dma_addr_t              buf_dma;
        u32                     *risc_cpu;
index 46202a4..c61ca7d 100644 (file)
 #define RISC_IRQ               (0x01 << 24)
 
 #define RISC_STATUS(status)    ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16))
-#define RISC_FLUSH()           (mantis->risc_pos = 0)
-#define RISC_INSTR(opcode)     (mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode))
+#define RISC_FLUSH(risc_pos)           (risc_pos = 0)
+#define RISC_INSTR(risc_pos, opcode)   (mantis->risc_cpu[risc_pos++] = cpu_to_le32(opcode))
 
 #define MANTIS_BUF_SIZE                (64 * 1024)
-#define MANTIS_BLOCK_BYTES     (MANTIS_BUF_SIZE >> 4)
-#define MANTIS_BLOCK_COUNT     (1 << 4)
-#define MANTIS_RISC_SIZE       PAGE_SIZE
+#define MANTIS_BLOCK_BYTES      (MANTIS_BUF_SIZE / 4)
+#define MANTIS_DMA_TR_BYTES     (2 * 1024) /* upper limit: 4095 bytes. */
+#define MANTIS_BLOCK_COUNT     (MANTIS_BUF_SIZE / MANTIS_BLOCK_BYTES)
+
+#define MANTIS_DMA_TR_UNITS     (MANTIS_BLOCK_BYTES / MANTIS_DMA_TR_BYTES)
+/* MANTIS_BUF_SIZE / MANTIS_DMA_TR_UNITS must not exceed MANTIS_RISC_SIZE (4k RISC cmd buffer) */
+#define MANTIS_RISC_SIZE       PAGE_SIZE /* RISC program must fit here. */
 
 int mantis_dma_exit(struct mantis_pci *mantis)
 {
@@ -124,27 +128,6 @@ err:
        return -ENOMEM;
 }
 
-static inline int mantis_calc_lines(struct mantis_pci *mantis)
-{
-       mantis->line_bytes = MANTIS_BLOCK_BYTES;
-       mantis->line_count = MANTIS_BLOCK_COUNT;
-
-       while (mantis->line_bytes > 4095) {
-               mantis->line_bytes >>= 1;
-               mantis->line_count <<= 1;
-       }
-
-       dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]",
-               MANTIS_BLOCK_BYTES, mantis->line_bytes, mantis->line_count);
-
-       if (mantis->line_count > 255) {
-               dprintk(MANTIS_ERROR, 1, "Buffer size error");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 int mantis_dma_init(struct mantis_pci *mantis)
 {
        int err = 0;
@@ -158,12 +141,6 @@ int mantis_dma_init(struct mantis_pci *mantis)
 
                goto err;
        }
-       err = mantis_calc_lines(mantis);
-       if (err < 0) {
-               dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed");
-
-               goto err;
-       }
 
        return 0;
 err:
@@ -174,31 +151,32 @@ EXPORT_SYMBOL_GPL(mantis_dma_init);
 static inline void mantis_risc_program(struct mantis_pci *mantis)
 {
        u32 buf_pos = 0;
-       u32 line;
+       u32 line, step;
+       u32 risc_pos;
 
        dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program");
-       RISC_FLUSH();
-
-       dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u",
-               mantis->line_count, mantis->line_bytes);
-
-       for (line = 0; line < mantis->line_count; line++) {
-               dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line);
-               if (!(buf_pos % MANTIS_BLOCK_BYTES)) {
-                       RISC_INSTR(RISC_WRITE   |
-                                  RISC_IRQ     |
-                                  RISC_STATUS(((buf_pos / MANTIS_BLOCK_BYTES) +
-                                  (MANTIS_BLOCK_COUNT - 1)) %
-                                   MANTIS_BLOCK_COUNT) |
-                                   mantis->line_bytes);
-               } else {
-                       RISC_INSTR(RISC_WRITE   | mantis->line_bytes);
-               }
-               RISC_INSTR(mantis->buf_dma + buf_pos);
-               buf_pos += mantis->line_bytes;
+       RISC_FLUSH(risc_pos);
+
+       dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u, bytes per DMA tr %u",
+               MANTIS_BLOCK_COUNT, MANTIS_BLOCK_BYTES, MANTIS_DMA_TR_BYTES);
+
+       for (line = 0; line < MANTIS_BLOCK_COUNT; line++) {
+               for (step = 0; step < MANTIS_DMA_TR_UNITS; step++) {
+                       dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d], step=[%d]", line, step);
+                       if (step == 0) {
+                               RISC_INSTR(risc_pos, RISC_WRITE |
+                                          RISC_IRQ     |
+                                          RISC_STATUS(line) |
+                                          MANTIS_DMA_TR_BYTES);
+                       } else {
+                               RISC_INSTR(risc_pos, RISC_WRITE | MANTIS_DMA_TR_BYTES);
+                       }
+                       RISC_INSTR(risc_pos, mantis->buf_dma + buf_pos);
+                       buf_pos += MANTIS_DMA_TR_BYTES;
+                 }
        }
-       RISC_INSTR(RISC_JUMP);
-       RISC_INSTR(mantis->risc_dma);
+       RISC_INSTR(risc_pos, RISC_JUMP);
+       RISC_INSTR(risc_pos, mantis->risc_dma);
 }
 
 void mantis_dma_start(struct mantis_pci *mantis)
@@ -210,7 +188,7 @@ void mantis_dma_start(struct mantis_pci *mantis)
        mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
 
        mmwrite(0, MANTIS_DMA_CTL);
-       mantis->last_block = mantis->finished_block = 0;
+       mantis->last_block = mantis->busy_block = 0;
 
        mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK);
 
@@ -245,9 +223,9 @@ void mantis_dma_xfer(unsigned long data)
        struct mantis_pci *mantis = (struct mantis_pci *) data;
        struct mantis_hwconfig *config = mantis->hwconfig;
 
-       while (mantis->last_block != mantis->finished_block) {
+       while (mantis->last_block != mantis->busy_block) {
                dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]",
-                       mantis->last_block, mantis->finished_block);
+                       mantis->last_block, mantis->busy_block);
 
                (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
                (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES);
index 38a436c..07aa887 100644 (file)
@@ -51,7 +51,6 @@ static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = {
        { STB0899_DISRX_ST0             , 0x04 },
        { STB0899_DISRX_ST1             , 0x00 },
        { STB0899_DISPARITY             , 0x00 },
-       { STB0899_DISFIFO               , 0x00 },
        { STB0899_DISSTATUS             , 0x20 },
        { STB0899_DISF22                , 0x99 },
        { STB0899_DISF22RX              , 0xa8 },
index 2bc9687..8987361 100644 (file)
@@ -6,9 +6,9 @@ ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o
 
 obj-$(CONFIG_DVB_NGENE) += ngene.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/
-EXTRA_CFLAGS += -Idrivers/media/common/tuners/
+ccflags-y += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/dvb/frontends/
+ccflags-y += -Idrivers/media/common/tuners/
 
 # For the staging CI driver cxd2099
-EXTRA_CFLAGS += -Idrivers/staging/cxd2099/
+ccflags-y += -Idrivers/staging/cxd2099/
index 7ac1287..7008223 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
index a66da17..d80d8e8 100644 (file)
@@ -2,4 +2,4 @@ earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o
 
 obj-$(CONFIG_DVB_PT1) += earth-pt1.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/dvb/dvb-core -Idrivers/media/dvb/frontends
index c54140b..f233b57 100644 (file)
@@ -5,7 +5,7 @@ obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o
 obj-$(CONFIG_SMS_USB_DRV) += smsusb.o
 obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/dvb-core
 
-EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
 
index 8a4d5bb..f6e8693 100644 (file)
@@ -17,5 +17,5 @@ obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
 obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
 obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+ccflags-y += -Idrivers/media/common/tuners
index cdd31ca..ee8ee1d 100644 (file)
@@ -25,6 +25,8 @@
  * the project's page is at http://www.linuxtv.org/ 
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/delay.h>
@@ -253,7 +255,7 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
 
                switch (av7110->current_input) {
                case 1:
-                       dprintk(1, "switching SAA7113 to Analog Tuner Input.\n");
+                       dprintk(1, "switching SAA7113 to Analog Tuner Input\n");
                        msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source
                        msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source
                        msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source
@@ -263,7 +265,7 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
 
                        if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
                                if (ves1820_writereg(dev, 0x09, 0x0f, 0x60))
-                                       dprintk(1, "setting band in demodulator failed.\n");
+                                       dprintk(1, "setting band in demodulator failed\n");
                        } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
                                saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD)
                                saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF)
@@ -272,17 +274,17 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
                                dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
                        break;
                case 2:
-                       dprintk(1, "switching SAA7113 to Video AV CVBS Input.\n");
+                       dprintk(1, "switching SAA7113 to Video AV CVBS Input\n");
                        if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1)
                                dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
                        break;
                case 3:
-                       dprintk(1, "switching SAA7113 to Video AV Y/C Input.\n");
+                       dprintk(1, "switching SAA7113 to Video AV Y/C Input\n");
                        if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1)
                                dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
                        break;
                default:
-                       dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input.\n");
+                       dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input\n");
                }
        } else {
                adswitch = 0;
@@ -299,7 +301,7 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
 
                if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
                        if (ves1820_writereg(dev, 0x09, 0x0f, 0x20))
-                               dprintk(1, "setting band in demodulator failed.\n");
+                               dprintk(1, "setting band in demodulator failed\n");
                } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
                        saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
                        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
@@ -413,7 +415,7 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency
        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
        struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
 
-       dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
+       dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x\n", f->frequency);
 
        if (!av7110->analog_tuner_flags || av7110->current_input != 1)
                return -EINVAL;
@@ -429,7 +431,7 @@ static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency
        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
        struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
 
-       dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
+       dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x\n", f->frequency);
 
        if (!av7110->analog_tuner_flags || av7110->current_input != 1)
                return -EINVAL;
@@ -689,12 +691,12 @@ int av7110_init_analog_module(struct av7110 *av7110)
 
        if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 &&
            i2c_writereg(av7110, 0x80, 0x0, 0) == 1) {
-               printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
+               pr_info("DVB-C analog module @ card %d detected, initializing MSP3400\n",
                        av7110->dvb_adapter.num);
                av7110->adac_type = DVB_ADAC_MSP34x0;
        } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 &&
                   i2c_writereg(av7110, 0x84, 0x0, 0) == 1) {
-               printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3415\n",
+               pr_info("DVB-C analog module @ card %d detected, initializing MSP3415\n",
                        av7110->dvb_adapter.num);
                av7110->adac_type = DVB_ADAC_MSP34x5;
        } else
@@ -715,7 +717,7 @@ int av7110_init_analog_module(struct av7110 *av7110)
        msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART
 
        if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) {
-               INFO(("saa7113 not accessible.\n"));
+               pr_info("saa7113 not accessible\n");
        } else {
                u8 *i = saa7113_init_regs;
 
@@ -733,7 +735,7 @@ int av7110_init_analog_module(struct av7110 *av7110)
                /* setup for DVB by default */
                if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
                        if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20))
-                               dprintk(1, "setting band in demodulator failed.\n");
+                               dprintk(1, "setting band in demodulator failed\n");
                } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
                        saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
                        saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
@@ -797,7 +799,7 @@ int av7110_init_v4l(struct av7110 *av7110)
        ret = saa7146_vv_init(dev, vv_data);
 
        if (ret) {
-               ERR(("cannot init capture device. skipping.\n"));
+               ERR("cannot init capture device. skipping\n");
                return -ENODEV;
        }
        vv_data->ops.vidioc_enum_input = vidioc_enum_input;
@@ -814,12 +816,12 @@ int av7110_init_v4l(struct av7110 *av7110)
        vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
 
        if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
-               ERR(("cannot register capture device. skipping.\n"));
+               ERR("cannot register capture device. skipping\n");
                saa7146_vv_release(dev);
                return -ENODEV;
        }
        if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
-               ERR(("cannot register vbi v4l2 device. skipping.\n"));
+               ERR("cannot register vbi v4l2 device. skipping\n");
        return 0;
 }
 
index e957d76..78d32f7 100644 (file)
@@ -33,6 +33,8 @@
  * the project's page is at http://www.linuxtv.org/ 
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "budget.h"
 #include "stv0299.h"
 #include "stb0899_drv.h"
@@ -149,7 +151,7 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad
        result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
        if (result == -ETIMEDOUT) {
                ciintf_slot_shutdown(ca, slot);
-               printk(KERN_INFO "budget-av: cam ejected 1\n");
+               pr_info("cam ejected 1\n");
        }
        return result;
 }
@@ -168,7 +170,7 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a
        result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
        if (result == -ETIMEDOUT) {
                ciintf_slot_shutdown(ca, slot);
-               printk(KERN_INFO "budget-av: cam ejected 2\n");
+               pr_info("cam ejected 2\n");
        }
        return result;
 }
@@ -187,7 +189,7 @@ static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addre
        result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
        if (result == -ETIMEDOUT) {
                ciintf_slot_shutdown(ca, slot);
-               printk(KERN_INFO "budget-av: cam ejected 3\n");
+               pr_info("cam ejected 3\n");
                return -ETIMEDOUT;
        }
        return result;
@@ -207,7 +209,7 @@ static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addr
        result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
        if (result == -ETIMEDOUT) {
                ciintf_slot_shutdown(ca, slot);
-               printk(KERN_INFO "budget-av: cam ejected 5\n");
+               pr_info("cam ejected 5\n");
        }
        return result;
 }
@@ -289,7 +291,7 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open
                if (saa7146_read(saa, PSR) & MASK_06) {
                        if (budget_av->slot_status == SLOTSTATUS_NONE) {
                                budget_av->slot_status = SLOTSTATUS_PRESENT;
-                               printk(KERN_INFO "budget-av: cam inserted A\n");
+                               pr_info("cam inserted A\n");
                        }
                }
                saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
@@ -306,11 +308,11 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open
                result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1);
                if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) {
                        budget_av->slot_status = SLOTSTATUS_PRESENT;
-                       printk(KERN_INFO "budget-av: cam inserted B\n");
+                       pr_info("cam inserted B\n");
                } else if (result < 0) {
                        if (budget_av->slot_status != SLOTSTATUS_NONE) {
                                ciintf_slot_shutdown(ca, slot);
-                               printk(KERN_INFO "budget-av: cam ejected 5\n");
+                               pr_info("cam ejected 5\n");
                                return 0;
                        }
                }
@@ -365,11 +367,11 @@ static int ciintf_init(struct budget_av *budget_av)
 
        if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter,
                                          &budget_av->ca, 0, 1)) != 0) {
-               printk(KERN_ERR "budget-av: ci initialisation failed.\n");
+               pr_err("ci initialisation failed\n");
                goto error;
        }
 
-       printk(KERN_INFO "budget-av: ci interface initialised.\n");
+       pr_info("ci interface initialised\n");
        return 0;
 
 error:
@@ -896,7 +898,6 @@ static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = {
        { STB0899_DISRX_ST0             , 0x04 },
        { STB0899_DISRX_ST1             , 0x00 },
        { STB0899_DISPARITY             , 0x00 },
-       { STB0899_DISFIFO               , 0x00 },
        { STB0899_DISSTATUS             , 0x20 },
        { STB0899_DISF22                , 0x8c },
        { STB0899_DISF22RX              , 0x9a },
@@ -1197,6 +1198,7 @@ static u8 read_pwm(struct budget_av *budget_av)
 #define SUBID_DVBC_KNC1                        0x0020
 #define SUBID_DVBC_KNC1_PLUS           0x0021
 #define SUBID_DVBC_KNC1_MK3            0x0022
+#define SUBID_DVBC_KNC1_TDA10024       0x0028
 #define SUBID_DVBC_KNC1_PLUS_MK3       0x0023
 #define SUBID_DVBC_CINERGY1200         0x1156
 #define SUBID_DVBC_CINERGY1200_MK3     0x1176
@@ -1316,6 +1318,7 @@ static void frontend_init(struct budget_av *budget_av)
        case SUBID_DVBC_EASYWATCH_MK3:
        case SUBID_DVBC_CINERGY1200_MK3:
        case SUBID_DVBC_KNC1_MK3:
+       case SUBID_DVBC_KNC1_TDA10024:
        case SUBID_DVBC_KNC1_PLUS_MK3:
                budget_av->reinitialise_demod = 1;
                budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
@@ -1343,8 +1346,7 @@ static void frontend_init(struct budget_av *budget_av)
        }
 
        if (fe == NULL) {
-               printk(KERN_ERR "budget-av: A frontend driver was not found "
-                               "for device [%04x:%04x] subsystem [%04x:%04x]\n",
+               pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
                       saa->pci->vendor,
                       saa->pci->device,
                       saa->pci->subsystem_vendor,
@@ -1356,7 +1358,7 @@ static void frontend_init(struct budget_av *budget_av)
 
        if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
                                  budget_av->budget.dvb_frontend)) {
-               printk(KERN_ERR "budget-av: Frontend registration failed!\n");
+               pr_err("Frontend registration failed!\n");
                dvb_frontend_detach(budget_av->budget.dvb_frontend);
                budget_av->budget.dvb_frontend = NULL;
        }
@@ -1414,7 +1416,7 @@ static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
 
 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
-       dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
+       dprintk(1, "VIDIOC_ENUMINPUT %d\n", i->index);
        if (i->index >= KNC1_INPUTS)
                return -EINVAL;
        memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
@@ -1428,7 +1430,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
 
        *i = budget_av->cur_input;
 
-       dprintk(1, "VIDIOC_G_INPUT %d.\n", *i);
+       dprintk(1, "VIDIOC_G_INPUT %d\n", *i);
        return 0;
 }
 
@@ -1437,7 +1439,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
        struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
 
-       dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
+       dprintk(1, "VIDIOC_S_INPUT %d\n", input);
        return saa7113_setinput(budget_av, input);
 }
 
@@ -1476,7 +1478,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
 
                if (0 != saa7146_vv_init(dev, &vv_data)) {
                        /* fixme: proper cleanup here */
-                       ERR(("cannot init vv subsystem.\n"));
+                       ERR("cannot init vv subsystem\n");
                        return err;
                }
                vv_data.ops.vidioc_enum_input = vidioc_enum_input;
@@ -1485,7 +1487,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
 
                if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
                        /* fixme: proper cleanup here */
-                       ERR(("cannot register capture v4l2 device.\n"));
+                       ERR("cannot register capture v4l2 device\n");
                        saa7146_vv_release(dev);
                        return err;
                }
@@ -1502,13 +1504,12 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
 
        mac = budget_av->budget.dvb_adapter.proposed_mac;
        if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) {
-               printk(KERN_ERR "KNC1-%d: Could not read MAC from KNC1 card\n",
+               pr_err("KNC1-%d: Could not read MAC from KNC1 card\n",
                       budget_av->budget.dvb_adapter.num);
                memset(mac, 0, 6);
        } else {
-               printk(KERN_INFO "KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-                      budget_av->budget.dvb_adapter.num,
-                      mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+               pr_info("KNC1-%d: MAC addr = %pM\n",
+                       budget_av->budget.dvb_adapter.num, mac);
        }
 
        budget_av->budget.dvb_adapter.priv = budget_av;
@@ -1558,6 +1559,7 @@ MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
 MAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP);
 MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
 MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3);
+MAKE_BUDGET_INFO(knc1ctda10024, "KNC1 DVB-C TDA10024", BUDGET_KNC1C_TDA10024);
 MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3);
 MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
 MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
@@ -1587,6 +1589,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
        MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
        MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022),
+       MAKE_EXTENSION_PCI(knc1ctda10024, 0x1894, 0x0028),
        MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023),
        MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
        MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031),
index 926f299..ca02e97 100644 (file)
@@ -1053,7 +1053,6 @@ static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = {
        { STB0899_DISRX_ST0             , 0x04 },
        { STB0899_DISRX_ST1             , 0x00 },
        { STB0899_DISPARITY             , 0x00 },
-       { STB0899_DISFIFO               , 0x00 },
        { STB0899_DISSTATUS             , 0x20 },
        { STB0899_DISF22                , 0x8c },
        { STB0899_DISF22RX              , 0x9a },
index 37666d4..37d02fe 100644 (file)
@@ -110,6 +110,7 @@ static int start_ts_capture(struct budget *budget)
                break;
        case BUDGET_CIN1200C_MK3:
        case BUDGET_KNC1C_MK3:
+       case BUDGET_KNC1C_TDA10024:
        case BUDGET_KNC1CP_MK3:
                if (budget->video_port == BUDGET_VIDEO_PORTA) {
                        saa7146_write(dev, DD1_INIT, 0x06000200);
@@ -434,6 +435,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
        case BUDGET_KNC1CP:
        case BUDGET_CIN1200C:
        case BUDGET_KNC1C_MK3:
+       case BUDGET_KNC1C_TDA10024:
        case BUDGET_KNC1CP_MK3:
        case BUDGET_CIN1200C_MK3:
                budget->buffer_width = TS_WIDTH_DVBC;
index 3ad0c67..3d8a806 100644 (file)
@@ -104,6 +104,7 @@ static struct saa7146_pci_extension_data x_var = { \
 #define BUDGET_KNC1C_MK3          16
 #define BUDGET_KNC1CP_MK3         17
 #define BUDGET_KNC1S2              18
+#define BUDGET_KNC1C_TDA10024     19
 
 #define BUDGET_VIDEO_PORTA         0
 #define BUDGET_VIDEO_PORTB         1
index 7dd54b3..32d4315 100644 (file)
@@ -85,6 +85,35 @@ static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC)
        return 0;
 }
 
+int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC)
+{
+       u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c,
+                      0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6,
+                      0x1d, 0x36, 0x64, 0x78};
+       u8 data[20];
+       int i;
+
+       memcpy(data, encodedMAC, 20);
+
+       for (i = 0; i < 20; i++)
+               data[i] ^= xor[i];
+       for (i = 0; i < 10; i++)
+               data[i] = ((data[2 * i + 1] << 8) | data[2 * i])
+                       >> ((data[2 * i + 1] >> 6) & 3);
+
+       if (check_mac_tt(data))
+               return -ENODEV;
+
+       decodedMAC[0] = data[2];
+       decodedMAC[1] = data[1];
+       decodedMAC[2] = data[0];
+       decodedMAC[3] = data[6];
+       decodedMAC[4] = data[5];
+       decodedMAC[5] = data[4];
+       return 0;
+}
+EXPORT_SYMBOL(ttpci_eeprom_decode_mac);
+
 static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC)
 {
        int ret;
index e2dc6cf..dcc33d5 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/types.h>
 #include <linux/i2c.h>
 
+extern int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC);
 extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac);
 
 #endif
index fbe2b95..8d6c4ac 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
index 2d70a82..ed28b53 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/dvb/dvb-core/
index f484a6e..390daf9 100644 (file)
@@ -27,4 +27,4 @@ obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
 obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o
 obj-$(CONFIG_RADIO_WL128X) += wl128x/
 
-EXTRA_CFLAGS += -Isound
+ccflags-y += -Isound
index 444b4cf..d1fab58 100644 (file)
@@ -92,10 +92,6 @@ static int radio_si4713_s_audout(struct file *file, void *priv,
 static int radio_si4713_querycap(struct file *file, void *priv,
                                        struct v4l2_capability *capability)
 {
-       struct radio_si4713_device *rsdev;
-
-       rsdev = video_get_drvdata(video_devdata(file));
-
        strlcpy(capability->driver, "radio-si4713", sizeof(capability->driver));
        strlcpy(capability->card, "Silicon Labs Si4713 Modulator",
                                sizeof(capability->card));
index 46cacf8..6d1e4e7 100644 (file)
@@ -2109,7 +2109,7 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
                                 V4L2_CID_TUNE_ANTENNA_CAPACITOR,
                                 0, 255, 1, 255);
        if (ctrl)
-               ctrl->is_volatile = 1;
+               ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
 
        if (radio->ctrl_handler.error) {
                r = radio->ctrl_handler.error;
index 4cf5370..a6ad707 100644 (file)
@@ -395,7 +395,6 @@ int si470x_disconnect_check(struct si470x_device *radio)
 static void si470x_int_in_callback(struct urb *urb)
 {
        struct si470x_device *radio = urb->context;
-       unsigned char buf[RDS_REPORT_SIZE];
        int retval;
        unsigned char regnr;
        unsigned char blocknum;
@@ -423,7 +422,6 @@ static void si470x_int_in_callback(struct urb *urb)
 
        if (urb->actual_length > 0) {
                /* Update RDS registers with URB data */
-               buf[0] = RDS_REPORT;
                for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
                        radio->registers[STATUSRSSI + regnr] =
                            get_unaligned_be16(&radio->int_in_buffer[
index ec1d52f..b93d8cf 100644 (file)
@@ -84,12 +84,14 @@ static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
        ret = copy_from_user(&rds, buf, sizeof(rds));
        fmdbg("(%d)type: %d, text %s, af %d\n",
                   ret, rds.text_type, rds.text, rds.af_freq);
+       if (ret)
+               return -EFAULT;
 
        fmdev = video_drvdata(file);
        fm_tx_set_radio_text(fmdev, rds.text, rds.text_type);
        fm_tx_set_af(fmdev, rds.af_freq);
 
-       return 0;
+       return sizeof(rds);
 }
 
 static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts)
@@ -557,7 +559,7 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
                        255, 1, 255);
 
        if (ctrl)
-               ctrl->is_volatile = 1;
+               ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
 
        return 0;
 }
index 899f783..aeb7f43 100644 (file)
@@ -4,8 +4,8 @@ menuconfig RC_CORE
        default INPUT
        ---help---
          Enable support for Remote Controllers on Linux. This is
-         needed in order to support several video capture adapters.
-         Currently, all supported devices use InfraRed.
+         needed in order to support several video capture adapters,
+         standalone IR receivers/transmitters, and RF receivers.
 
          Enable this option if you have a video capture board even
          if you don't need IR, as otherwise, you may not be able to
@@ -108,6 +108,25 @@ config IR_LIRC_CODEC
           Enable this option to pass raw IR to and from userspace via
           the LIRC interface.
 
+config RC_ATI_REMOTE
+       tristate "ATI / X10 based USB RF remote controls"
+       depends on USB_ARCH_HAS_HCD
+       depends on RC_CORE
+       select USB
+       help
+          Say Y here if you want to use an X10 based USB remote control.
+          These are RF remotes with USB receivers.
+
+          Such devices include the ATI remote that comes with many of ATI's
+          All-In-Wonder video cards, the X10 "Lola" remote, NVIDIA RF remote,
+          Medion RF remote, and SnapStream FireFly remote.
+
+          This driver provides mouse pointer, left and right mouse buttons,
+          and maps all the other remote buttons to keypress events.
+
+          To compile this driver as a module, choose M here: the module will be
+          called ati_remote.
+
 config IR_ENE
        tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)"
        depends on PNP
index f224db0..2156e78 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
 obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
 
 # stand-alone IR receivers/transmitters
+obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o
 obj-$(CONFIG_IR_IMON) += imon.o
 obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
 obj-$(CONFIG_IR_MCEUSB) += mceusb.o
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
new file mode 100644 (file)
index 0000000..303f22e
--- /dev/null
@@ -0,0 +1,946 @@
+/*
+ *  USB ATI Remote support
+ *
+ *                Copyright (c) 2011 Anssi Hannula <anssi.hannula@iki.fi>
+ *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
+ *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
+ *
+ *  This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
+ *  porting to the 2.6 kernel interfaces, along with other modification
+ *  to better match the style of the existing usb/input drivers.  However, the
+ *  protocol and hardware handling is essentially unchanged from 2.1.1.
+ *
+ *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
+ *  Vojtech Pavlik.
+ *
+ *  Changes:
+ *
+ *  Feb 2004: Torrey Hoffman <thoffman@arnor.net>
+ *            Version 2.2.0
+ *  Jun 2004: Torrey Hoffman <thoffman@arnor.net>
+ *            Version 2.2.1
+ *            Added key repeat support contributed by:
+ *                Vincent Vanackere <vanackere@lif.univ-mrs.fr>
+ *            Added support for the "Lola" remote contributed by:
+ *                Seth Cohn <sethcohn@yahoo.com>
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * Hardware & software notes
+ *
+ * These remote controls are distributed by ATI as part of their
+ * "All-In-Wonder" video card packages.  The receiver self-identifies as a
+ * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
+ *
+ * The "Lola" remote is available from X10.  See:
+ *    http://www.x10.com/products/lola_sg1.htm
+ * The Lola is similar to the ATI remote but has no mouse support, and slightly
+ * different keys.
+ *
+ * It is possible to use multiple receivers and remotes on multiple computers
+ * simultaneously by configuring them to use specific channels.
+ *
+ * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
+ * Actually, it may even support more, at least in some revisions of the
+ * hardware.
+ *
+ * Each remote can be configured to transmit on one channel as follows:
+ *   - Press and hold the "hand icon" button.
+ *   - When the red LED starts to blink, let go of the "hand icon" button.
+ *   - When it stops blinking, input the channel code as two digits, from 01
+ *     to 16, and press the hand icon again.
+ *
+ * The timing can be a little tricky.  Try loading the module with debug=1
+ * to have the kernel print out messages about the remote control number
+ * and mask.  Note: debugging prints remote numbers as zero-based hexadecimal.
+ *
+ * The driver has a "channel_mask" parameter. This bitmask specifies which
+ * channels will be ignored by the module.  To mask out channels, just add
+ * all the 2^channel_number values together.
+ *
+ * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
+ * ignore signals coming from remote controls transmitting on channel 4, but
+ * accept all other channels.
+ *
+ * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
+ * ignored.
+ *
+ * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
+ * parameter are unused.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/usb/input.h>
+#include <linux/wait.h>
+#include <linux/jiffies.h>
+#include <media/rc-core.h>
+
+/*
+ * Module and Version Information, Module Parameters
+ */
+
+#define ATI_REMOTE_VENDOR_ID           0x0bc7
+#define LOLA_REMOTE_PRODUCT_ID         0x0002
+#define LOLA2_REMOTE_PRODUCT_ID                0x0003
+#define ATI_REMOTE_PRODUCT_ID          0x0004
+#define NVIDIA_REMOTE_PRODUCT_ID       0x0005
+#define MEDION_REMOTE_PRODUCT_ID       0x0006
+#define FIREFLY_REMOTE_PRODUCT_ID      0x0008
+
+#define DRIVER_VERSION         "2.2.1"
+#define DRIVER_AUTHOR           "Torrey Hoffman <thoffman@arnor.net>"
+#define DRIVER_DESC             "ATI/X10 RF USB Remote Control"
+
+#define NAME_BUFSIZE      80    /* size of product name, path buffers */
+#define DATA_BUFSIZE      63    /* size of URB data buffers */
+
+/*
+ * Duplicate event filtering time.
+ * Sequential, identical KIND_FILTERED inputs with less than
+ * FILTER_TIME milliseconds between them are considered as repeat
+ * events. The hardware generates 5 events for the first keypress
+ * and we have to take this into account for an accurate repeat
+ * behaviour.
+ */
+#define FILTER_TIME    60 /* msec */
+#define REPEAT_DELAY   500 /* msec */
+
+static unsigned long channel_mask;
+module_param(channel_mask, ulong, 0644);
+MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+static int repeat_filter = FILTER_TIME;
+module_param(repeat_filter, int, 0644);
+MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec");
+
+static int repeat_delay = REPEAT_DELAY;
+module_param(repeat_delay, int, 0644);
+MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec");
+
+static bool mouse = true;
+module_param(mouse, bool, 0444);
+MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes");
+
+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
+#undef err
+#define err(format, arg...) printk(KERN_ERR format , ## arg)
+
+static struct usb_device_id ati_remote_table[] = {
+       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID),     .driver_info = (unsigned long)RC_MAP_ATI_X10 },
+       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID),    .driver_info = (unsigned long)RC_MAP_ATI_X10 },
+       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID),      .driver_info = (unsigned long)RC_MAP_ATI_X10 },
+       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID),   .driver_info = (unsigned long)RC_MAP_ATI_X10 },
+       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID),   .driver_info = (unsigned long)RC_MAP_MEDION_X10 },
+       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, FIREFLY_REMOTE_PRODUCT_ID),  .driver_info = (unsigned long)RC_MAP_SNAPSTREAM_FIREFLY },
+       {}      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, ati_remote_table);
+
+/* Get hi and low bytes of a 16-bits int */
+#define HI(a)  ((unsigned char)((a) >> 8))
+#define LO(a)  ((unsigned char)((a) & 0xff))
+
+#define SEND_FLAG_IN_PROGRESS  1
+#define SEND_FLAG_COMPLETE     2
+
+/* Device initialization strings */
+static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
+static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
+
+struct ati_remote {
+       struct input_dev *idev;
+       struct rc_dev *rdev;
+       struct usb_device *udev;
+       struct usb_interface *interface;
+
+       struct urb *irq_urb;
+       struct urb *out_urb;
+       struct usb_endpoint_descriptor *endpoint_in;
+       struct usb_endpoint_descriptor *endpoint_out;
+       unsigned char *inbuf;
+       unsigned char *outbuf;
+       dma_addr_t inbuf_dma;
+       dma_addr_t outbuf_dma;
+
+       unsigned char old_data[2];  /* Detect duplicate events */
+       unsigned long old_jiffies;
+       unsigned long acc_jiffies;  /* handle acceleration */
+       unsigned long first_jiffies;
+
+       unsigned int repeat_count;
+
+       char rc_name[NAME_BUFSIZE];
+       char rc_phys[NAME_BUFSIZE];
+       char mouse_name[NAME_BUFSIZE];
+       char mouse_phys[NAME_BUFSIZE];
+
+       wait_queue_head_t wait;
+       int send_flags;
+
+       int users; /* 0-2, users are rc and input */
+       struct mutex open_mutex;
+};
+
+/* "Kinds" of messages sent from the hardware to the driver. */
+#define KIND_END        0
+#define KIND_LITERAL    1   /* Simply pass to input system */
+#define KIND_FILTERED   2   /* Add artificial key-up events, drop keyrepeats */
+#define KIND_LU         3   /* Directional keypad diagonals - left up, */
+#define KIND_RU         4   /*   right up,  */
+#define KIND_LD         5   /*   left down, */
+#define KIND_RD         6   /*   right down */
+#define KIND_ACCEL      7   /* Directional keypad - left, right, up, down.*/
+
+/* Translation table from hardware messages to input events. */
+static const struct {
+       short kind;
+       unsigned char data1, data2;
+       int type;
+       unsigned int code;
+       int value;
+}  ati_remote_tbl[] = {
+       /* Directional control pad axes */
+       {KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},   /* left */
+       {KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
+       {KIND_ACCEL,   0x37, 0x72, EV_REL, REL_Y, -1},   /* up */
+       {KIND_ACCEL,   0x38, 0x73, EV_REL, REL_Y, 1},    /* down */
+       /* Directional control pad diagonals */
+       {KIND_LU,      0x39, 0x74, EV_REL, 0, 0},        /* left up */
+       {KIND_RU,      0x3a, 0x75, EV_REL, 0, 0},        /* right up */
+       {KIND_LD,      0x3c, 0x77, EV_REL, 0, 0},        /* left down */
+       {KIND_RD,      0x3b, 0x76, EV_REL, 0, 0},        /* right down */
+
+       /* "Mouse button" buttons */
+       {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */
+       {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */
+       {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
+       {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
+
+       /* Artificial "doubleclick" events are generated by the hardware.
+        * They are mapped to the "side" and "extra" mouse buttons here. */
+       {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
+       {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
+
+       /* Non-mouse events are handled by rc-core */
+       {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
+};
+
+/* Local function prototypes */
+static int ati_remote_sendpacket       (struct ati_remote *ati_remote, u16 cmd, unsigned char *data);
+static void ati_remote_irq_out         (struct urb *urb);
+static void ati_remote_irq_in          (struct urb *urb);
+static void ati_remote_input_report    (struct urb *urb);
+static int ati_remote_initialize       (struct ati_remote *ati_remote);
+static int ati_remote_probe            (struct usb_interface *interface, const struct usb_device_id *id);
+static void ati_remote_disconnect      (struct usb_interface *interface);
+
+/* usb specific object to register with the usb subsystem */
+static struct usb_driver ati_remote_driver = {
+       .name         = "ati_remote",
+       .probe        = ati_remote_probe,
+       .disconnect   = ati_remote_disconnect,
+       .id_table     = ati_remote_table,
+};
+
+/*
+ *     ati_remote_dump_input
+ */
+static void ati_remote_dump(struct device *dev, unsigned char *data,
+                           unsigned int len)
+{
+       if (len == 1) {
+               if (data[0] != (unsigned char)0xff && data[0] != 0x00)
+                       dev_warn(dev, "Weird byte 0x%02x\n", data[0]);
+       } else if (len == 4)
+               dev_warn(dev, "Weird key %02x %02x %02x %02x\n",
+                    data[0], data[1], data[2], data[3]);
+       else
+               dev_warn(dev, "Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n",
+                    len, data[0], data[1], data[2], data[3], data[4], data[5]);
+}
+
+/*
+ *     ati_remote_open
+ */
+static int ati_remote_open(struct ati_remote *ati_remote)
+{
+       int err = 0;
+
+       mutex_lock(&ati_remote->open_mutex);
+
+       if (ati_remote->users++ != 0)
+               goto out; /* one was already active */
+
+       /* On first open, submit the read urb which was set up previously. */
+       ati_remote->irq_urb->dev = ati_remote->udev;
+       if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
+               dev_err(&ati_remote->interface->dev,
+                       "%s: usb_submit_urb failed!\n", __func__);
+               err = -EIO;
+       }
+
+out:   mutex_unlock(&ati_remote->open_mutex);
+       return err;
+}
+
+/*
+ *     ati_remote_close
+ */
+static void ati_remote_close(struct ati_remote *ati_remote)
+{
+       mutex_lock(&ati_remote->open_mutex);
+       if (--ati_remote->users == 0)
+               usb_kill_urb(ati_remote->irq_urb);
+       mutex_unlock(&ati_remote->open_mutex);
+}
+
+static int ati_remote_input_open(struct input_dev *inputdev)
+{
+       struct ati_remote *ati_remote = input_get_drvdata(inputdev);
+       return ati_remote_open(ati_remote);
+}
+
+static void ati_remote_input_close(struct input_dev *inputdev)
+{
+       struct ati_remote *ati_remote = input_get_drvdata(inputdev);
+       ati_remote_close(ati_remote);
+}
+
+static int ati_remote_rc_open(struct rc_dev *rdev)
+{
+       struct ati_remote *ati_remote = rdev->priv;
+       return ati_remote_open(ati_remote);
+}
+
+static void ati_remote_rc_close(struct rc_dev *rdev)
+{
+       struct ati_remote *ati_remote = rdev->priv;
+       ati_remote_close(ati_remote);
+}
+
+/*
+ *             ati_remote_irq_out
+ */
+static void ati_remote_irq_out(struct urb *urb)
+{
+       struct ati_remote *ati_remote = urb->context;
+
+       if (urb->status) {
+               dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
+                       __func__, urb->status);
+               return;
+       }
+
+       ati_remote->send_flags |= SEND_FLAG_COMPLETE;
+       wmb();
+       wake_up(&ati_remote->wait);
+}
+
+/*
+ *     ati_remote_sendpacket
+ *
+ *     Used to send device initialization strings
+ */
+static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
+{
+       int retval = 0;
+
+       /* Set up out_urb */
+       memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
+       ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
+
+       ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
+       ati_remote->out_urb->dev = ati_remote->udev;
+       ati_remote->send_flags = SEND_FLAG_IN_PROGRESS;
+
+       retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
+       if (retval) {
+               dev_dbg(&ati_remote->interface->dev,
+                        "sendpacket: usb_submit_urb failed: %d\n", retval);
+               return retval;
+       }
+
+       wait_event_timeout(ati_remote->wait,
+               ((ati_remote->out_urb->status != -EINPROGRESS) ||
+                       (ati_remote->send_flags & SEND_FLAG_COMPLETE)),
+               HZ);
+       usb_kill_urb(ati_remote->out_urb);
+
+       return retval;
+}
+
+/*
+ *     ati_remote_event_lookup
+ */
+static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
+{
+       int i;
+
+       for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
+               /*
+                * Decide if the table entry matches the remote input.
+                */
+               if (ati_remote_tbl[i].data1 == d1 &&
+                   ati_remote_tbl[i].data2 == d2)
+                       return i;
+
+       }
+       return -1;
+}
+
+/*
+ *     ati_remote_compute_accel
+ *
+ * Implements acceleration curve for directional control pad
+ * If elapsed time since last event is > 1/4 second, user "stopped",
+ * so reset acceleration. Otherwise, user is probably holding the control
+ * pad down, so we increase acceleration, ramping up over two seconds to
+ * a maximum speed.
+ */
+static int ati_remote_compute_accel(struct ati_remote *ati_remote)
+{
+       static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
+       unsigned long now = jiffies;
+       int acc;
+
+       if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) {
+               acc = 1;
+               ati_remote->acc_jiffies = now;
+       }
+       else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125)))
+               acc = accel[0];
+       else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250)))
+               acc = accel[1];
+       else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500)))
+               acc = accel[2];
+       else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000)))
+               acc = accel[3];
+       else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500)))
+               acc = accel[4];
+       else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000)))
+               acc = accel[5];
+       else
+               acc = accel[6];
+
+       return acc;
+}
+
+/*
+ *     ati_remote_report_input
+ */
+static void ati_remote_input_report(struct urb *urb)
+{
+       struct ati_remote *ati_remote = urb->context;
+       unsigned char *data= ati_remote->inbuf;
+       struct input_dev *dev = ati_remote->idev;
+       int index = -1;
+       int acc;
+       int remote_num;
+       unsigned char scancode[2];
+
+       /* Deal with strange looking inputs */
+       if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
+               ((data[3] & 0x0f) != 0x00) ) {
+               ati_remote_dump(&urb->dev->dev, data, urb->actual_length);
+               return;
+       }
+
+       /* Mask unwanted remote channels.  */
+       /* note: remote_num is 0-based, channel 1 on remote == 0 here */
+       remote_num = (data[3] >> 4) & 0x0f;
+       if (channel_mask & (1 << (remote_num + 1))) {
+               dbginfo(&ati_remote->interface->dev,
+                       "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
+                       remote_num, data[1], data[2], channel_mask);
+               return;
+       }
+
+       scancode[0] = (((data[1] - ((remote_num + 1) << 4)) & 0xf0) | (data[1] & 0x0f));
+
+       /*
+        * Some devices (e.g. SnapStream Firefly) use 8080 as toggle code,
+        * so we have to clear them. The first bit is a bit tricky as the
+        * "non-toggled" state depends on remote_num, so we xor it with the
+        * second bit which is only used for toggle.
+        */
+       scancode[0] ^= (data[2] & 0x80);
+
+       scancode[1] = data[2] & ~0x80;
+
+       /* Look up event code index in mouse translation table. */
+       index = ati_remote_event_lookup(remote_num, scancode[0], scancode[1]);
+
+       if (index >= 0) {
+               dbginfo(&ati_remote->interface->dev,
+                       "channel 0x%02x; mouse data %02x,%02x; index %d; keycode %d\n",
+                       remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
+               if (!dev)
+                       return; /* no mouse device */
+       } else
+               dbginfo(&ati_remote->interface->dev,
+                       "channel 0x%02x; key data %02x,%02x, scancode %02x,%02x\n",
+                       remote_num, data[1], data[2], scancode[0], scancode[1]);
+
+
+       if (index >= 0 && ati_remote_tbl[index].kind == KIND_LITERAL) {
+               input_event(dev, ati_remote_tbl[index].type,
+                       ati_remote_tbl[index].code,
+                       ati_remote_tbl[index].value);
+               input_sync(dev);
+
+               ati_remote->old_jiffies = jiffies;
+               return;
+       }
+
+       if (index < 0 || ati_remote_tbl[index].kind == KIND_FILTERED) {
+               unsigned long now = jiffies;
+
+               /* Filter duplicate events which happen "too close" together. */
+               if (ati_remote->old_data[0] == data[1] &&
+                   ati_remote->old_data[1] == data[2] &&
+                   time_before(now, ati_remote->old_jiffies +
+                                    msecs_to_jiffies(repeat_filter))) {
+                       ati_remote->repeat_count++;
+               } else {
+                       ati_remote->repeat_count = 0;
+                       ati_remote->first_jiffies = now;
+               }
+
+               ati_remote->old_data[0] = data[1];
+               ati_remote->old_data[1] = data[2];
+               ati_remote->old_jiffies = now;
+
+               /* Ensure we skip at least the 4 first duplicate events (generated
+                * by a single keypress), and continue skipping until repeat_delay
+                * msecs have passed
+                */
+               if (ati_remote->repeat_count > 0 &&
+                   (ati_remote->repeat_count < 5 ||
+                    time_before(now, ati_remote->first_jiffies +
+                                     msecs_to_jiffies(repeat_delay))))
+                       return;
+
+               if (index < 0) {
+                       /* Not a mouse event, hand it to rc-core. */
+                       u32 rc_code = (scancode[0] << 8) | scancode[1];
+
+                       /*
+                        * We don't use the rc-core repeat handling yet as
+                        * it would cause ghost repeats which would be a
+                        * regression for this driver.
+                        */
+                       rc_keydown_notimeout(ati_remote->rdev, rc_code,
+                                            data[2]);
+                       rc_keyup(ati_remote->rdev);
+                       return;
+               }
+
+               input_event(dev, ati_remote_tbl[index].type,
+                       ati_remote_tbl[index].code, 1);
+               input_sync(dev);
+               input_event(dev, ati_remote_tbl[index].type,
+                       ati_remote_tbl[index].code, 0);
+               input_sync(dev);
+
+       } else {
+
+               /*
+                * Other event kinds are from the directional control pad, and have an
+                * acceleration factor applied to them.  Without this acceleration, the
+                * control pad is mostly unusable.
+                */
+               acc = ati_remote_compute_accel(ati_remote);
+
+               switch (ati_remote_tbl[index].kind) {
+               case KIND_ACCEL:
+                       input_event(dev, ati_remote_tbl[index].type,
+                               ati_remote_tbl[index].code,
+                               ati_remote_tbl[index].value * acc);
+                       break;
+               case KIND_LU:
+                       input_report_rel(dev, REL_X, -acc);
+                       input_report_rel(dev, REL_Y, -acc);
+                       break;
+               case KIND_RU:
+                       input_report_rel(dev, REL_X, acc);
+                       input_report_rel(dev, REL_Y, -acc);
+                       break;
+               case KIND_LD:
+                       input_report_rel(dev, REL_X, -acc);
+                       input_report_rel(dev, REL_Y, acc);
+                       break;
+               case KIND_RD:
+                       input_report_rel(dev, REL_X, acc);
+                       input_report_rel(dev, REL_Y, acc);
+                       break;
+               default:
+                       dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
+                               ati_remote_tbl[index].kind);
+               }
+               input_sync(dev);
+
+               ati_remote->old_jiffies = jiffies;
+               ati_remote->old_data[0] = data[1];
+               ati_remote->old_data[1] = data[2];
+       }
+}
+
+/*
+ *     ati_remote_irq_in
+ */
+static void ati_remote_irq_in(struct urb *urb)
+{
+       struct ati_remote *ati_remote = urb->context;
+       int retval;
+
+       switch (urb->status) {
+       case 0:                 /* success */
+               ati_remote_input_report(urb);
+               break;
+       case -ECONNRESET:       /* unlink */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
+                       __func__);
+               return;
+       default:                /* error */
+               dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
+                       __func__, urb->status);
+       }
+
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
+               dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
+                       __func__, retval);
+}
+
+/*
+ *     ati_remote_alloc_buffers
+ */
+static int ati_remote_alloc_buffers(struct usb_device *udev,
+                                   struct ati_remote *ati_remote)
+{
+       ati_remote->inbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
+                                              &ati_remote->inbuf_dma);
+       if (!ati_remote->inbuf)
+               return -1;
+
+       ati_remote->outbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
+                                               &ati_remote->outbuf_dma);
+       if (!ati_remote->outbuf)
+               return -1;
+
+       ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!ati_remote->irq_urb)
+               return -1;
+
+       ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!ati_remote->out_urb)
+               return -1;
+
+       return 0;
+}
+
+/*
+ *     ati_remote_free_buffers
+ */
+static void ati_remote_free_buffers(struct ati_remote *ati_remote)
+{
+       usb_free_urb(ati_remote->irq_urb);
+       usb_free_urb(ati_remote->out_urb);
+
+       usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
+               ati_remote->inbuf, ati_remote->inbuf_dma);
+
+       usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
+               ati_remote->outbuf, ati_remote->outbuf_dma);
+}
+
+static void ati_remote_input_init(struct ati_remote *ati_remote)
+{
+       struct input_dev *idev = ati_remote->idev;
+       int i;
+
+       idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+       idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+               BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
+       idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+       for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
+               if (ati_remote_tbl[i].type == EV_KEY)
+                       set_bit(ati_remote_tbl[i].code, idev->keybit);
+
+       input_set_drvdata(idev, ati_remote);
+
+       idev->open = ati_remote_input_open;
+       idev->close = ati_remote_input_close;
+
+       idev->name = ati_remote->mouse_name;
+       idev->phys = ati_remote->mouse_phys;
+
+       usb_to_input_id(ati_remote->udev, &idev->id);
+       idev->dev.parent = &ati_remote->interface->dev;
+}
+
+static void ati_remote_rc_init(struct ati_remote *ati_remote)
+{
+       struct rc_dev *rdev = ati_remote->rdev;
+
+       rdev->priv = ati_remote;
+       rdev->driver_type = RC_DRIVER_SCANCODE;
+       rdev->allowed_protos = RC_TYPE_OTHER;
+       rdev->driver_name = "ati_remote";
+
+       rdev->open = ati_remote_rc_open;
+       rdev->close = ati_remote_rc_close;
+
+       rdev->input_name = ati_remote->rc_name;
+       rdev->input_phys = ati_remote->rc_phys;
+
+       usb_to_input_id(ati_remote->udev, &rdev->input_id);
+       rdev->dev.parent = &ati_remote->interface->dev;
+}
+
+static int ati_remote_initialize(struct ati_remote *ati_remote)
+{
+       struct usb_device *udev = ati_remote->udev;
+       int pipe, maxp;
+
+       init_waitqueue_head(&ati_remote->wait);
+
+       /* Set up irq_urb */
+       pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
+       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+       maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
+
+       usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
+                        maxp, ati_remote_irq_in, ati_remote,
+                        ati_remote->endpoint_in->bInterval);
+       ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
+       ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       /* Set up out_urb */
+       pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
+       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+       maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
+
+       usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
+                        maxp, ati_remote_irq_out, ati_remote,
+                        ati_remote->endpoint_out->bInterval);
+       ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
+       ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       /* send initialization strings */
+       if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
+           (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
+               dev_err(&ati_remote->interface->dev,
+                        "Initializing ati_remote hardware failed.\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ *     ati_remote_probe
+ */
+static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct usb_host_interface *iface_host = interface->cur_altsetting;
+       struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
+       struct ati_remote *ati_remote;
+       struct input_dev *input_dev;
+       struct rc_dev *rc_dev;
+       int err = -ENOMEM;
+
+       if (iface_host->desc.bNumEndpoints != 2) {
+               err("%s: Unexpected desc.bNumEndpoints\n", __func__);
+               return -ENODEV;
+       }
+
+       endpoint_in = &iface_host->endpoint[0].desc;
+       endpoint_out = &iface_host->endpoint[1].desc;
+
+       if (!usb_endpoint_is_int_in(endpoint_in)) {
+               err("%s: Unexpected endpoint_in\n", __func__);
+               return -ENODEV;
+       }
+       if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {
+               err("%s: endpoint_in message size==0? \n", __func__);
+               return -ENODEV;
+       }
+
+       ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
+       rc_dev = rc_allocate_device();
+       if (!ati_remote || !rc_dev)
+               goto fail1;
+
+       /* Allocate URB buffers, URBs */
+       if (ati_remote_alloc_buffers(udev, ati_remote))
+               goto fail2;
+
+       ati_remote->endpoint_in = endpoint_in;
+       ati_remote->endpoint_out = endpoint_out;
+       ati_remote->udev = udev;
+       ati_remote->rdev = rc_dev;
+       ati_remote->interface = interface;
+
+       usb_make_path(udev, ati_remote->rc_phys, sizeof(ati_remote->rc_phys));
+       strlcpy(ati_remote->mouse_phys, ati_remote->rc_phys,
+               sizeof(ati_remote->mouse_phys));
+
+       strlcat(ati_remote->rc_phys, "/input0", sizeof(ati_remote->rc_phys));
+       strlcat(ati_remote->mouse_phys, "/input1", sizeof(ati_remote->mouse_phys));
+
+       if (udev->manufacturer)
+               strlcpy(ati_remote->rc_name, udev->manufacturer,
+                       sizeof(ati_remote->rc_name));
+
+       if (udev->product)
+               snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name),
+                        "%s %s", ati_remote->rc_name, udev->product);
+
+       if (!strlen(ati_remote->rc_name))
+               snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name),
+                       DRIVER_DESC "(%04x,%04x)",
+                       le16_to_cpu(ati_remote->udev->descriptor.idVendor),
+                       le16_to_cpu(ati_remote->udev->descriptor.idProduct));
+
+       snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name),
+                "%s mouse", ati_remote->rc_name);
+
+       if (id->driver_info)
+               rc_dev->map_name = (const char *)id->driver_info;
+       else
+               rc_dev->map_name = RC_MAP_ATI_X10;
+
+       ati_remote_rc_init(ati_remote);
+       mutex_init(&ati_remote->open_mutex);
+
+       /* Device Hardware Initialization - fills in ati_remote->idev from udev. */
+       err = ati_remote_initialize(ati_remote);
+       if (err)
+               goto fail3;
+
+       /* Set up and register rc device */
+       err = rc_register_device(ati_remote->rdev);
+       if (err)
+               goto fail3;
+
+       /* use our delay for rc_dev */
+       ati_remote->rdev->input_dev->rep[REP_DELAY] = repeat_delay;
+
+       /* Set up and register mouse input device */
+       if (mouse) {
+               input_dev = input_allocate_device();
+               if (!input_dev)
+                       goto fail4;
+
+               ati_remote->idev = input_dev;
+               ati_remote_input_init(ati_remote);
+               err = input_register_device(input_dev);
+
+               if (err)
+                       goto fail5;
+       }
+
+       usb_set_intfdata(interface, ati_remote);
+       return 0;
+
+ fail5:        input_free_device(input_dev);
+ fail4:        rc_unregister_device(rc_dev);
+       rc_dev = NULL;
+ fail3:        usb_kill_urb(ati_remote->irq_urb);
+       usb_kill_urb(ati_remote->out_urb);
+ fail2:        ati_remote_free_buffers(ati_remote);
+ fail1:        rc_free_device(rc_dev);
+       kfree(ati_remote);
+       return err;
+}
+
+/*
+ *     ati_remote_disconnect
+ */
+static void ati_remote_disconnect(struct usb_interface *interface)
+{
+       struct ati_remote *ati_remote;
+
+       ati_remote = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+       if (!ati_remote) {
+               dev_warn(&interface->dev, "%s - null device?\n", __func__);
+               return;
+       }
+
+       usb_kill_urb(ati_remote->irq_urb);
+       usb_kill_urb(ati_remote->out_urb);
+       if (ati_remote->idev)
+               input_unregister_device(ati_remote->idev);
+       rc_unregister_device(ati_remote->rdev);
+       ati_remote_free_buffers(ati_remote);
+       kfree(ati_remote);
+}
+
+/*
+ *     ati_remote_init
+ */
+static int __init ati_remote_init(void)
+{
+       int result;
+
+       result = usb_register(&ati_remote_driver);
+       if (result)
+               printk(KERN_ERR KBUILD_MODNAME
+                      ": usb_register error #%d\n", result);
+       else
+               printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+                      DRIVER_DESC "\n");
+
+       return result;
+}
+
+/*
+ *     ati_remote_exit
+ */
+static void __exit ati_remote_exit(void)
+{
+       usb_deregister(&ati_remote_driver);
+}
+
+/*
+ *     module specification
+ */
+
+module_init(ati_remote_init);
+module_exit(ati_remote_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
index 2b9c256..cf10ecf 100644 (file)
@@ -30,6 +30,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pnp.h>
@@ -118,31 +120,31 @@ static int ene_hw_detect(struct ene_device *dev)
                        dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 2 : 4;
 
        if (hw_revision == 0xFF) {
-               ene_warn("device seems to be disabled");
-               ene_warn("send a mail to lirc-list@lists.sourceforge.net");
-               ene_warn("please attach output of acpidump and dmidecode");
+               pr_warn("device seems to be disabled\n");
+               pr_warn("send a mail to lirc-list@lists.sourceforge.net\n");
+               pr_warn("please attach output of acpidump and dmidecode\n");
                return -ENODEV;
        }
 
-       ene_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x",
-               chip_major, chip_minor, old_ver, hw_revision);
+       pr_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x\n",
+                 chip_major, chip_minor, old_ver, hw_revision);
 
-       ene_notice("PLL freq = %d", dev->pll_freq);
+       pr_notice("PLL freq = %d\n", dev->pll_freq);
 
        if (chip_major == 0x33) {
-               ene_warn("chips 0x33xx aren't supported");
+               pr_warn("chips 0x33xx aren't supported\n");
                return -ENODEV;
        }
 
        if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) {
                dev->hw_revision = ENE_HW_C;
-               ene_notice("KB3926C detected");
+               pr_notice("KB3926C detected\n");
        } else if (old_ver == 0x24 && hw_revision == 0xC0) {
                dev->hw_revision = ENE_HW_B;
-               ene_notice("KB3926B detected");
+               pr_notice("KB3926B detected\n");
        } else {
                dev->hw_revision = ENE_HW_D;
-               ene_notice("KB3926D or higher detected");
+               pr_notice("KB3926D or higher detected\n");
        }
 
        /* detect features hardware supports */
@@ -152,7 +154,7 @@ static int ene_hw_detect(struct ene_device *dev)
        fw_reg1 = ene_read_reg(dev, ENE_FW1);
        fw_reg2 = ene_read_reg(dev, ENE_FW2);
 
-       ene_notice("Firmware regs: %02x %02x", fw_reg1, fw_reg2);
+       pr_notice("Firmware regs: %02x %02x\n", fw_reg1, fw_reg2);
 
        dev->hw_use_gpio_0a = !!(fw_reg2 & ENE_FW2_GP0A);
        dev->hw_learning_and_tx_capable = !!(fw_reg2 & ENE_FW2_LEARNING);
@@ -161,30 +163,29 @@ static int ene_hw_detect(struct ene_device *dev)
        if (dev->hw_learning_and_tx_capable)
                dev->hw_fan_input = !!(fw_reg2 & ENE_FW2_FAN_INPUT);
 
-       ene_notice("Hardware features:");
+       pr_notice("Hardware features:\n");
 
        if (dev->hw_learning_and_tx_capable) {
-               ene_notice("* Supports transmitting & learning mode");
-               ene_notice("   This feature is rare and therefore,");
-               ene_notice("   you are welcome to test it,");
-               ene_notice("   and/or contact the author via:");
-               ene_notice("   lirc-list@lists.sourceforge.net");
-               ene_notice("   or maximlevitsky@gmail.com");
+               pr_notice("* Supports transmitting & learning mode\n");
+               pr_notice("   This feature is rare and therefore,\n");
+               pr_notice("   you are welcome to test it,\n");
+               pr_notice("   and/or contact the author via:\n");
+               pr_notice("   lirc-list@lists.sourceforge.net\n");
+               pr_notice("   or maximlevitsky@gmail.com\n");
 
-               ene_notice("* Uses GPIO %s for IR raw input",
-                       dev->hw_use_gpio_0a ? "40" : "0A");
+               pr_notice("* Uses GPIO %s for IR raw input\n",
+                         dev->hw_use_gpio_0a ? "40" : "0A");
 
                if (dev->hw_fan_input)
-                       ene_notice("* Uses unused fan feedback input as source"
-                                       " of demodulated IR data");
+                       pr_notice("* Uses unused fan feedback input as source of demodulated IR data\n");
        }
 
        if (!dev->hw_fan_input)
-               ene_notice("* Uses GPIO %s for IR demodulated input",
-                       dev->hw_use_gpio_0a ? "0A" : "40");
+               pr_notice("* Uses GPIO %s for IR demodulated input\n",
+                         dev->hw_use_gpio_0a ? "0A" : "40");
 
        if (dev->hw_extra_buffer)
-               ene_notice("* Uses new style input buffer");
+               pr_notice("* Uses new style input buffer\n");
        return 0;
 }
 
@@ -215,13 +216,13 @@ static void ene_rx_setup_hw_buffer(struct ene_device *dev)
 
        dev->buffer_len = dev->extra_buf1_len + dev->extra_buf2_len + 8;
 
-       ene_notice("Hardware uses 2 extended buffers:");
-       ene_notice("  0x%04x - len : %d", dev->extra_buf1_address,
-                                               dev->extra_buf1_len);
-       ene_notice("  0x%04x - len : %d", dev->extra_buf2_address,
-                                               dev->extra_buf2_len);
+       pr_notice("Hardware uses 2 extended buffers:\n");
+       pr_notice("  0x%04x - len : %d\n",
+                 dev->extra_buf1_address, dev->extra_buf1_len);
+       pr_notice("  0x%04x - len : %d\n",
+                 dev->extra_buf2_address, dev->extra_buf2_len);
 
-       ene_notice("Total buffer len = %d", dev->buffer_len);
+       pr_notice("Total buffer len = %d\n", dev->buffer_len);
 
        if (dev->buffer_len > 64 || dev->buffer_len < 16)
                goto error;
@@ -240,7 +241,7 @@ static void ene_rx_setup_hw_buffer(struct ene_device *dev)
        ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
        return;
 error:
-       ene_warn("Error validating extra buffers, device probably won't work");
+       pr_warn("Error validating extra buffers, device probably won't work\n");
        dev->hw_extra_buffer = false;
        ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
 }
@@ -588,7 +589,7 @@ static void ene_tx_enable(struct ene_device *dev)
                dbg("TX: Transmitter #2 is connected");
 
        if (!(fwreg2 & (ENE_FW2_EMMITER1_CONN | ENE_FW2_EMMITER2_CONN)))
-               ene_warn("TX: transmitter cable isn't connected!");
+               pr_warn("TX: transmitter cable isn't connected!\n");
 
        /* disable receive on revc */
        if (dev->hw_revision == ENE_HW_C)
@@ -615,7 +616,7 @@ static void ene_tx_sample(struct ene_device *dev)
        bool pulse = dev->tx_sample_pulse;
 
        if (!dev->tx_buffer) {
-               ene_warn("TX: BUG: attempt to transmit NULL buffer");
+               pr_warn("TX: BUG: attempt to transmit NULL buffer\n");
                return;
        }
 
@@ -1049,7 +1050,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
                dev->hw_learning_and_tx_capable = true;
                setup_timer(&dev->tx_sim_timer, ene_tx_irqsim,
                                                (long unsigned int)dev);
-               ene_warn("Simulation of TX activated");
+               pr_warn("Simulation of TX activated\n");
        }
 
        if (!dev->hw_learning_and_tx_capable)
@@ -1089,7 +1090,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
        if (error < 0)
                goto error;
 
-       ene_notice("driver has been successfully loaded");
+       pr_notice("driver has been successfully loaded\n");
        return 0;
 error:
        if (dev && dev->irq >= 0)
index 017c209..fd108d9 100644 (file)
 #define  ENE_HW_C              2       /* 3926C */
 #define  ENE_HW_D              3       /* 3926D or later */
 
-#define ene_printk(level, text, ...) \
-       printk(level ENE_DRIVER_NAME ": " text "\n", ## __VA_ARGS__)
-
-#define ene_notice(text, ...) ene_printk(KERN_NOTICE, text, ## __VA_ARGS__)
-#define ene_warn(text, ...) ene_printk(KERN_WARNING, text, ## __VA_ARGS__)
-
-
-#define __dbg(level, format, ...) \
-       do { \
-               if (debug >= level) \
-                       printk(KERN_DEBUG ENE_DRIVER_NAME \
-                               ": " format "\n", ## __VA_ARGS__); \
-       } while (0)
-
+#define __dbg(level, format, ...)                              \
+do {                                                           \
+       if (debug >= level)                                     \
+               pr_debug(format "\n", ## __VA_ARGS__);          \
+} while (0)
 
 #define dbg(format, ...)               __dbg(1, format, ## __VA_ARGS__)
 #define dbg_verbose(format, ...)       __dbg(2, format, ## __VA_ARGS__)
index 6bc35ee..6ed9646 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include <linux/ratelimit.h>
 
 #include <linux/input.h>
 #include <linux/usb.h>
@@ -516,19 +517,19 @@ static int send_packet(struct imon_context *ictx)
        if (retval) {
                ictx->tx.busy = false;
                smp_rmb(); /* ensure later readers know we're not busy */
-               pr_err("error submitting urb(%d)\n", retval);
+               pr_err_ratelimited("error submitting urb(%d)\n", retval);
        } else {
                /* Wait for transmission to complete (or abort) */
                mutex_unlock(&ictx->lock);
                retval = wait_for_completion_interruptible(
                                &ictx->tx.finished);
                if (retval)
-                       pr_err("task interrupted\n");
+                       pr_err_ratelimited("task interrupted\n");
                mutex_lock(&ictx->lock);
 
                retval = ictx->tx.status;
                if (retval)
-                       pr_err("packet tx failed (%d)\n", retval);
+                       pr_err_ratelimited("packet tx failed (%d)\n", retval);
        }
 
        kfree(control_req);
@@ -830,20 +831,20 @@ static ssize_t vfd_write(struct file *file, const char *buf,
 
        ictx = file->private_data;
        if (!ictx) {
-               pr_err("no context for device\n");
+               pr_err_ratelimited("no context for device\n");
                return -ENODEV;
        }
 
        mutex_lock(&ictx->lock);
 
        if (!ictx->dev_present_intf0) {
-               pr_err("no iMON device present\n");
+               pr_err_ratelimited("no iMON device present\n");
                retval = -ENODEV;
                goto exit;
        }
 
        if (n_bytes <= 0 || n_bytes > 32) {
-               pr_err("invalid payload size\n");
+               pr_err_ratelimited("invalid payload size\n");
                retval = -EINVAL;
                goto exit;
        }
@@ -869,7 +870,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
 
                retval = send_packet(ictx);
                if (retval) {
-                       pr_err("send packet failed for packet #%d\n", seq / 2);
+                       pr_err_ratelimited("send packet #%d failed\n", seq / 2);
                        goto exit;
                } else {
                        seq += 2;
@@ -883,7 +884,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
        ictx->usb_tx_buf[7] = (unsigned char) seq;
        retval = send_packet(ictx);
        if (retval)
-               pr_err("send packet failed for packet #%d\n", seq / 2);
+               pr_err_ratelimited("send packet #%d failed\n", seq / 2);
 
 exit:
        mutex_unlock(&ictx->lock);
@@ -912,20 +913,21 @@ static ssize_t lcd_write(struct file *file, const char *buf,
 
        ictx = file->private_data;
        if (!ictx) {
-               pr_err("no context for device\n");
+               pr_err_ratelimited("no context for device\n");
                return -ENODEV;
        }
 
        mutex_lock(&ictx->lock);
 
        if (!ictx->display_supported) {
-               pr_err("no iMON display present\n");
+               pr_err_ratelimited("no iMON display present\n");
                retval = -ENODEV;
                goto exit;
        }
 
        if (n_bytes != 8) {
-               pr_err("invalid payload size: %d (expected 8)\n", (int)n_bytes);
+               pr_err_ratelimited("invalid payload size: %d (expected 8)\n",
+                                  (int)n_bytes);
                retval = -EINVAL;
                goto exit;
        }
@@ -937,7 +939,7 @@ static ssize_t lcd_write(struct file *file, const char *buf,
 
        retval = send_packet(ictx);
        if (retval) {
-               pr_err("send packet failed!\n");
+               pr_err_ratelimited("send packet failed!\n");
                goto exit;
        } else {
                dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n",
@@ -1656,7 +1658,7 @@ static void usb_rx_callback_intf0(struct urb *urb)
                return;
 
        ictx = (struct imon_context *)urb->context;
-       if (!ictx)
+       if (!ictx || !ictx->dev_present_intf0)
                return;
 
        switch (urb->status) {
@@ -1688,7 +1690,7 @@ static void usb_rx_callback_intf1(struct urb *urb)
                return;
 
        ictx = (struct imon_context *)urb->context;
-       if (!ictx)
+       if (!ictx || !ictx->dev_present_intf1)
                return;
 
        switch (urb->status) {
@@ -2116,7 +2118,6 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
 
        ictx->dev = dev;
        ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf));
-       ictx->dev_present_intf0 = true;
        ictx->rx_urb_intf0 = rx_urb;
        ictx->tx_urb = tx_urb;
        ictx->rf_device = false;
@@ -2155,6 +2156,8 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
                goto rdev_setup_failed;
        }
 
+       ictx->dev_present_intf0 = true;
+
        mutex_unlock(&ictx->lock);
        return ictx;
 
@@ -2198,7 +2201,6 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
        }
 
        ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf));
-       ictx->dev_present_intf1 = true;
        ictx->rx_urb_intf1 = rx_urb;
 
        ret = -ENODEV;
@@ -2227,6 +2229,8 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
                goto urb_submit_failed;
        }
 
+       ictx->dev_present_intf1 = true;
+
        mutex_unlock(&ictx->lock);
        return ictx;
 
index e5eeec4..ec2e67f 100644 (file)
@@ -98,7 +98,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
        return 0;
 }
 
-static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
+static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
                                   size_t n, loff_t *ppos)
 {
        struct lirc_codec *lirc;
@@ -140,10 +140,11 @@ out:
 }
 
 static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
-                       unsigned long __user arg)
+                       unsigned long arg)
 {
        struct lirc_codec *lirc;
        struct rc_dev *dev;
+       u32 __user *argp = (u32 __user *)(arg);
        int ret = 0;
        __u32 val = 0, tmp;
 
@@ -156,7 +157,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
                return -EFAULT;
 
        if (_IOC_DIR(cmd) & _IOC_WRITE) {
-               ret = get_user(val, (__u32 *)arg);
+               ret = get_user(val, argp);
                if (ret)
                        return ret;
        }
@@ -265,7 +266,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
        }
 
        if (_IOC_DIR(cmd) & _IOC_READ)
-               ret = put_user(val, (__u32 *)arg);
+               ret = put_user(val, argp);
 
        return ret;
 }
index b57fc83..36e4d5e 100644 (file)
@@ -4,6 +4,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-apac-viewcomp.o \
                        rc-asus-pc39.o \
                        rc-ati-tv-wonder-hd-600.o \
+                       rc-ati-x10.o \
                        rc-avermedia-a16d.o \
                        rc-avermedia.o \
                        rc-avermedia-cardbus.o \
@@ -47,6 +48,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-lirc.o \
                        rc-lme2510.o \
                        rc-manli.o \
+                       rc-medion-x10.o \
                        rc-msi-digivox-ii.o \
                        rc-msi-digivox-iii.o \
                        rc-msi-tvanywhere.o \
@@ -70,6 +72,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-hauppauge.o \
                        rc-rc6-mce.o \
                        rc-real-audio-220-32-keys.o \
+                       rc-snapstream-firefly.o \
                        rc-streamzap.o \
                        rc-tbs-nec.o \
                        rc-technisat-usb2.o \
diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c
new file mode 100644 (file)
index 0000000..e1b8b26
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * ATI X10 RF remote keytable
+ *
+ * Copyright (C) 2011 Anssi Hannula <anssi.hannula@?ki.fi>
+ *
+ * This file is based on the static generic keytable previously found in
+ * ati_remote.c, which is
+ * Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
+ * Copyright (c) 2002 Vladimir Dergachev
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <media/rc-map.h>
+
+static struct rc_map_table ati_x10[] = {
+       { 0xd20d, KEY_1 },
+       { 0xd30e, KEY_2 },
+       { 0xd40f, KEY_3 },
+       { 0xd510, KEY_4 },
+       { 0xd611, KEY_5 },
+       { 0xd712, KEY_6 },
+       { 0xd813, KEY_7 },
+       { 0xd914, KEY_8 },
+       { 0xda15, KEY_9 },
+       { 0xdc17, KEY_0 },
+       { 0xc500, KEY_A },
+       { 0xc601, KEY_B },
+       { 0xde19, KEY_C },
+       { 0xe01b, KEY_D },
+       { 0xe621, KEY_E },
+       { 0xe823, KEY_F },
+
+       { 0xdd18, KEY_KPENTER },    /* "check" */
+       { 0xdb16, KEY_MENU },       /* "menu" */
+       { 0xc702, KEY_POWER },      /* Power */
+       { 0xc803, KEY_TV },         /* TV */
+       { 0xc904, KEY_DVD },        /* DVD */
+       { 0xca05, KEY_WWW },        /* WEB */
+       { 0xcb06, KEY_BOOKMARKS },  /* "book" */
+       { 0xcc07, KEY_EDIT },       /* "hand" */
+       { 0xe11c, KEY_COFFEE },     /* "timer" */
+       { 0xe520, KEY_FRONT },      /* "max" */
+       { 0xe21d, KEY_LEFT },       /* left */
+       { 0xe41f, KEY_RIGHT },      /* right */
+       { 0xe722, KEY_DOWN },       /* down */
+       { 0xdf1a, KEY_UP },         /* up */
+       { 0xe31e, KEY_OK },         /* "OK" */
+       { 0xce09, KEY_VOLUMEDOWN }, /* VOL + */
+       { 0xcd08, KEY_VOLUMEUP },   /* VOL - */
+       { 0xcf0a, KEY_MUTE },       /* MUTE  */
+       { 0xd00b, KEY_CHANNELUP },  /* CH + */
+       { 0xd10c, KEY_CHANNELDOWN },/* CH - */
+       { 0xec27, KEY_RECORD },     /* ( o) red */
+       { 0xea25, KEY_PLAY },       /* ( >) */
+       { 0xe924, KEY_REWIND },     /* (<<) */
+       { 0xeb26, KEY_FORWARD },    /* (>>) */
+       { 0xed28, KEY_STOP },       /* ([]) */
+       { 0xee29, KEY_PAUSE },      /* ('') */
+       { 0xf02b, KEY_PREVIOUS },   /* (<-) */
+       { 0xef2a, KEY_NEXT },       /* (>+) */
+       { 0xf22d, KEY_INFO },       /* PLAYING */
+       { 0xf32e, KEY_HOME },       /* TOP */
+       { 0xf42f, KEY_END },        /* END */
+       { 0xf530, KEY_SELECT },     /* SELECT */
+};
+
+static struct rc_map_list ati_x10_map = {
+       .map = {
+               .scan    = ati_x10,
+               .size    = ARRAY_SIZE(ati_x10),
+               .rc_type = RC_TYPE_OTHER,
+               .name    = RC_MAP_ATI_X10,
+       }
+};
+
+static int __init init_rc_map_ati_x10(void)
+{
+       return rc_map_register(&ati_x10_map);
+}
+
+static void __exit exit_rc_map_ati_x10(void)
+{
+       rc_map_unregister(&ati_x10_map);
+}
+
+module_init(init_rc_map_ati_x10)
+module_exit(exit_rc_map_ati_x10)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c
new file mode 100644 (file)
index 0000000..09e2cc0
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Medion X10 RF remote keytable
+ *
+ * Copyright (C) 2011 Anssi Hannula <anssi.hannula@?ki.fi>
+ *
+ * This file is based on a keytable provided by
+ * Jan Losinski <losinski@wh2.tu-dresden.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <media/rc-map.h>
+
+static struct rc_map_table medion_x10[] = {
+       { 0xf12c, KEY_TV },    /* TV */
+       { 0xf22d, KEY_VCR },   /* VCR */
+       { 0xc904, KEY_DVD },   /* DVD */
+       { 0xcb06, KEY_AUDIO }, /* MUSIC */
+
+       { 0xf32e, KEY_RADIO },     /* RADIO */
+       { 0xca05, KEY_DIRECTORY }, /* PHOTO */
+       { 0xf42f, KEY_INFO },      /* TV-PREVIEW */
+       { 0xf530, KEY_LIST },      /* CHANNEL-LST */
+
+       { 0xe01b, KEY_SETUP }, /* SETUP */
+       { 0xf631, KEY_VIDEO }, /* VIDEO DESKTOP */
+
+       { 0xcd08, KEY_VOLUMEDOWN },  /* VOL - */
+       { 0xce09, KEY_VOLUMEUP },    /* VOL + */
+       { 0xd00b, KEY_CHANNELUP },   /* CHAN + */
+       { 0xd10c, KEY_CHANNELDOWN }, /* CHAN - */
+       { 0xc500, KEY_MUTE },        /* MUTE */
+
+       { 0xf732, KEY_RED }, /* red */
+       { 0xf833, KEY_GREEN }, /* green */
+       { 0xf934, KEY_YELLOW }, /* yellow */
+       { 0xfa35, KEY_BLUE }, /* blue */
+       { 0xdb16, KEY_TEXT }, /* TXT */
+
+       { 0xd20d, KEY_1 },
+       { 0xd30e, KEY_2 },
+       { 0xd40f, KEY_3 },
+       { 0xd510, KEY_4 },
+       { 0xd611, KEY_5 },
+       { 0xd712, KEY_6 },
+       { 0xd813, KEY_7 },
+       { 0xd914, KEY_8 },
+       { 0xda15, KEY_9 },
+       { 0xdc17, KEY_0 },
+       { 0xe11c, KEY_SEARCH }, /* TV/RAD, CH SRC */
+       { 0xe520, KEY_DELETE }, /* DELETE */
+
+       { 0xfb36, KEY_KEYBOARD }, /* RENAME */
+       { 0xdd18, KEY_SCREEN },   /* SNAPSHOT */
+
+       { 0xdf1a, KEY_UP },    /* up */
+       { 0xe722, KEY_DOWN },  /* down */
+       { 0xe21d, KEY_LEFT },  /* left */
+       { 0xe41f, KEY_RIGHT }, /* right */
+       { 0xe31e, KEY_OK },    /* OK */
+
+       { 0xfc37, KEY_SELECT }, /* ACQUIRE IMAGE */
+       { 0xfd38, KEY_EDIT },   /* EDIT IMAGE */
+
+       { 0xe924, KEY_REWIND },   /* rewind  (<<) */
+       { 0xea25, KEY_PLAY },     /* play    ( >) */
+       { 0xeb26, KEY_FORWARD },  /* forward (>>) */
+       { 0xec27, KEY_RECORD },   /* record  ( o) */
+       { 0xed28, KEY_STOP },     /* stop    ([]) */
+       { 0xee29, KEY_PAUSE },    /* pause   ('') */
+
+       { 0xe621, KEY_PREVIOUS },        /* prev */
+       { 0xfe39, KEY_SWITCHVIDEOMODE }, /* F SCR */
+       { 0xe823, KEY_NEXT },            /* next */
+       { 0xde19, KEY_MENU },            /* MENU */
+       { 0xff3a, KEY_LANGUAGE },        /* AUDIO */
+
+       { 0xc702, KEY_POWER }, /* POWER */
+};
+
+static struct rc_map_list medion_x10_map = {
+       .map = {
+               .scan    = medion_x10,
+               .size    = ARRAY_SIZE(medion_x10),
+               .rc_type = RC_TYPE_OTHER,
+               .name    = RC_MAP_MEDION_X10,
+       }
+};
+
+static int __init init_rc_map_medion_x10(void)
+{
+       return rc_map_register(&medion_x10_map);
+}
+
+static void __exit exit_rc_map_medion_x10(void)
+{
+       rc_map_unregister(&medion_x10_map);
+}
+
+module_init(init_rc_map_medion_x10)
+module_exit(exit_rc_map_medion_x10)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
index 8d558ae..31fc64c 100644 (file)
@@ -20,6 +20,7 @@ static struct rc_map_table pinnacle_pctv_hd[] = {
        { 0x0701, KEY_MENU }, /* Pinnacle logo */
        { 0x0739, KEY_POWER },
        { 0x0703, KEY_VOLUMEUP },
+       { 0x0705, KEY_OK },
        { 0x0709, KEY_VOLUMEDOWN },
        { 0x0706, KEY_CHANNELUP },
        { 0x070c, KEY_CHANNELDOWN },
diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c
new file mode 100644 (file)
index 0000000..ef14652
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * SnapStream Firefly X10 RF remote keytable
+ *
+ * Copyright (C) 2011 Anssi Hannula <anssi.hannula@?ki.fi>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <media/rc-map.h>
+
+static struct rc_map_table snapstream_firefly[] = {
+       { 0xf12c, KEY_ZOOM },       /* Maximize */
+       { 0xc702, KEY_CLOSE },
+
+       { 0xd20d, KEY_1 },
+       { 0xd30e, KEY_2 },
+       { 0xd40f, KEY_3 },
+       { 0xd510, KEY_4 },
+       { 0xd611, KEY_5 },
+       { 0xd712, KEY_6 },
+       { 0xd813, KEY_7 },
+       { 0xd914, KEY_8 },
+       { 0xda15, KEY_9 },
+       { 0xdc17, KEY_0 },
+       { 0xdb16, KEY_BACK },
+       { 0xdd18, KEY_KPENTER },    /* ent */
+
+       { 0xce09, KEY_VOLUMEUP },
+       { 0xcd08, KEY_VOLUMEDOWN },
+       { 0xcf0a, KEY_MUTE },
+       { 0xd00b, KEY_CHANNELUP },
+       { 0xd10c, KEY_CHANNELDOWN },
+       { 0xc500, KEY_VENDOR },     /* firefly */
+
+       { 0xf32e, KEY_INFO },
+       { 0xf42f, KEY_OPTION },
+
+       { 0xe21d, KEY_LEFT },
+       { 0xe41f, KEY_RIGHT },
+       { 0xe722, KEY_DOWN },
+       { 0xdf1a, KEY_UP },
+       { 0xe31e, KEY_OK },
+
+       { 0xe11c, KEY_MENU },
+       { 0xe520, KEY_EXIT },
+
+       { 0xec27, KEY_RECORD },
+       { 0xea25, KEY_PLAY },
+       { 0xed28, KEY_STOP },
+       { 0xe924, KEY_REWIND },
+       { 0xeb26, KEY_FORWARD },
+       { 0xee29, KEY_PAUSE },
+       { 0xf02b, KEY_PREVIOUS },
+       { 0xef2a, KEY_NEXT },
+
+       { 0xcb06, KEY_AUDIO },      /* Music */
+       { 0xca05, KEY_IMAGES },     /* Photos */
+       { 0xc904, KEY_DVD },
+       { 0xc803, KEY_TV },
+       { 0xcc07, KEY_VIDEO },
+
+       { 0xc601, KEY_HELP },
+       { 0xf22d, KEY_MODE },       /* Mouse */
+
+       { 0xde19, KEY_A },
+       { 0xe01b, KEY_B },
+       { 0xe621, KEY_C },
+       { 0xe823, KEY_D },
+};
+
+static struct rc_map_list snapstream_firefly_map = {
+       .map = {
+               .scan    = snapstream_firefly,
+               .size    = ARRAY_SIZE(snapstream_firefly),
+               .rc_type = RC_TYPE_OTHER,
+               .name    = RC_MAP_SNAPSTREAM_FIREFLY,
+       }
+};
+
+static int __init init_rc_map_snapstream_firefly(void)
+{
+       return rc_map_register(&snapstream_firefly_map);
+}
+
+static void __exit exit_rc_map_snapstream_firefly(void)
+{
+       rc_map_unregister(&snapstream_firefly_map);
+}
+
+module_init(init_rc_map_snapstream_firefly)
+module_exit(exit_rc_map_snapstream_firefly)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
index 85ff9a1..60d3c1e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers
  *
- * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ * Copyright (c) 2010-2011, Jarod Wilson <jarod@redhat.com>
  *
  * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan
  * Conti, Martin Blatter and Daniel Melander, the latter of which was
  * Jon Smirl, which included enhancements and simplifications to the
  * incoming IR buffer parsing routines.
  *
+ * Updated in July of 2011 with the aid of Microsoft's official
+ * remote/transceiver requirements and specification document, found at
+ * download.microsoft.com, title
+ * Windows-Media-Center-RC-IR-Collection-Green-Button-Specification-03-08-2011-V2.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
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/usb/input.h>
+#include <linux/pm_wakeup.h>
 #include <media/rc-core.h>
 
-#define DRIVER_VERSION "1.91"
-#define DRIVER_AUTHOR  "Jarod Wilson <jarod@wilsonet.com>"
+#define DRIVER_VERSION "1.92"
+#define DRIVER_AUTHOR  "Jarod Wilson <jarod@redhat.com>"
 #define DRIVER_DESC    "Windows Media Center Ed. eHome Infrared Transceiver " \
                        "device driver"
 #define DRIVER_NAME    "mceusb"
 #define MCE_PULSE_MASK         0x7f /* Pulse mask */
 #define MCE_MAX_PULSE_LENGTH   0x7f /* Longest transmittable pulse symbol */
 
-#define MCE_HW_CMD_HEADER      0xff    /* MCE hardware command header */
-#define MCE_COMMAND_HEADER     0x9f    /* MCE command header */
-#define MCE_COMMAND_MASK       0xe0    /* Mask out command bits */
-#define MCE_COMMAND_NULL       0x00    /* These show up various places... */
-/* if buf[i] & MCE_COMMAND_MASK == 0x80 and buf[i] != MCE_COMMAND_HEADER,
- * then we're looking at a raw IR data sample */
-#define MCE_COMMAND_IRDATA     0x80
-#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */
-
-/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */
+/*
+ * The interface between the host and the IR hardware is command-response
+ * based. All commands and responses have a consistent format, where a lead
+ * byte always identifies the type of data following it. The lead byte has
+ * a port value in the 3 highest bits and a length value in the 5 lowest
+ * bits.
+ *
+ * The length field is overloaded, with a value of 11111 indicating that the
+ * following byte is a command or response code, and the length of the entire
+ * message is determined by the code. If the length field is not 11111, then
+ * it specifies the number of bytes of port data that follow.
+ */
+#define MCE_CMD                        0x1f
+#define MCE_PORT_IR            0x4     /* (0x4 << 5) | MCE_CMD = 0x9f */
+#define MCE_PORT_SYS           0x7     /* (0x7 << 5) | MCE_CMD = 0xff */
+#define MCE_PORT_SER           0x6     /* 0xc0 thru 0xdf flush & 0x1f bytes */
+#define MCE_PORT_MASK  0xe0    /* Mask out command bits */
+
+/* Command port headers */
+#define MCE_CMD_PORT_IR                0x9f    /* IR-related cmd/rsp */
+#define MCE_CMD_PORT_SYS       0xff    /* System (non-IR) device cmd/rsp */
+
+/* Commands that set device state  (2-4 bytes in length) */
+#define MCE_CMD_RESET          0xfe    /* Reset device, 2 bytes */
+#define MCE_CMD_RESUME         0xaa    /* Resume device after error, 2 bytes */
+#define MCE_CMD_SETIRCFS       0x06    /* Set tx carrier, 4 bytes */
+#define MCE_CMD_SETIRTIMEOUT   0x0c    /* Set timeout, 4 bytes */
+#define MCE_CMD_SETIRTXPORTS   0x08    /* Set tx ports, 3 bytes */
+#define MCE_CMD_SETIRRXPORTEN  0x14    /* Set rx ports, 3 bytes */
+#define MCE_CMD_FLASHLED       0x23    /* Flash receiver LED, 2 bytes */
+
+/* Commands that query device state (all 2 bytes, unless noted) */
+#define MCE_CMD_GETIRCFS       0x07    /* Get carrier */
+#define MCE_CMD_GETIRTIMEOUT   0x0d    /* Get timeout */
+#define MCE_CMD_GETIRTXPORTS   0x13    /* Get tx ports */
+#define MCE_CMD_GETIRRXPORTEN  0x15    /* Get rx ports */
+#define MCE_CMD_GETPORTSTATUS  0x11    /* Get tx port status, 3 bytes */
+#define MCE_CMD_GETIRNUMPORTS  0x16    /* Get number of ports */
+#define MCE_CMD_GETWAKESOURCE  0x17    /* Get wake source */
+#define MCE_CMD_GETEMVER       0x22    /* Get emulator interface version */
+#define MCE_CMD_GETDEVDETAILS  0x21    /* Get device details (em ver2 only) */
+#define MCE_CMD_GETWAKESUPPORT 0x20    /* Get wake details (em ver2 only) */
+#define MCE_CMD_GETWAKEVERSION 0x18    /* Get wake pattern (em ver2 only) */
+
+/* Misc commands */
+#define MCE_CMD_NOP            0xff    /* No operation */
+
+/* Responses to commands (non-error cases) */
+#define MCE_RSP_EQIRCFS                0x06    /* tx carrier, 4 bytes */
+#define MCE_RSP_EQIRTIMEOUT    0x0c    /* rx timeout, 4 bytes */
+#define MCE_RSP_GETWAKESOURCE  0x17    /* wake source, 3 bytes */
+#define MCE_RSP_EQIRTXPORTS    0x08    /* tx port mask, 3 bytes */
+#define MCE_RSP_EQIRRXPORTEN   0x14    /* rx port mask, 3 bytes */
+#define MCE_RSP_GETPORTSTATUS  0x11    /* tx port status, 7 bytes */
+#define MCE_RSP_EQIRRXCFCNT    0x15    /* rx carrier count, 4 bytes */
+#define MCE_RSP_EQIRNUMPORTS   0x16    /* number of ports, 4 bytes */
+#define MCE_RSP_EQWAKESUPPORT  0x20    /* wake capabilities, 3 bytes */
+#define MCE_RSP_EQWAKEVERSION  0x18    /* wake pattern details, 6 bytes */
+#define MCE_RSP_EQDEVDETAILS   0x21    /* device capabilities, 3 bytes */
+#define MCE_RSP_EQEMVER                0x22    /* emulator interface ver, 3 bytes */
+#define MCE_RSP_FLASHLED       0x23    /* success flashing LED, 2 bytes */
+
+/* Responses to error cases, must send MCE_CMD_RESUME to clear them */
+#define MCE_RSP_CMD_ILLEGAL    0xfe    /* illegal command for port, 2 bytes */
+#define MCE_RSP_TX_TIMEOUT     0x81    /* tx timed out, 2 bytes */
+
+/* Misc commands/responses not defined in the MCE remote/transceiver spec */
 #define MCE_CMD_SIG_END                0x01    /* End of signal */
 #define MCE_CMD_PING           0x03    /* Ping device */
 #define MCE_CMD_UNKNOWN                0x04    /* Unknown */
 #define MCE_CMD_UNKNOWN2       0x05    /* Unknown */
-#define MCE_CMD_S_CARRIER      0x06    /* Set TX carrier frequency */
-#define MCE_CMD_G_CARRIER      0x07    /* Get TX carrier frequency */
-#define MCE_CMD_S_TXMASK       0x08    /* Set TX port bitmask */
 #define MCE_CMD_UNKNOWN3       0x09    /* Unknown */
 #define MCE_CMD_UNKNOWN4       0x0a    /* Unknown */
 #define MCE_CMD_G_REVISION     0x0b    /* Get hw/sw revision */
-#define MCE_CMD_S_TIMEOUT      0x0c    /* Set RX timeout value */
-#define MCE_CMD_G_TIMEOUT      0x0d    /* Get RX timeout value */
 #define MCE_CMD_UNKNOWN5       0x0e    /* Unknown */
 #define MCE_CMD_UNKNOWN6       0x0f    /* Unknown */
-#define MCE_CMD_G_RXPORTSTS    0x11    /* Get RX port status */
-#define MCE_CMD_G_TXMASK       0x13    /* Set TX port bitmask */
-#define MCE_CMD_S_RXSENSOR     0x14    /* Set RX sensor (std/learning) */
-#define MCE_CMD_G_RXSENSOR     0x15    /* Get RX sensor (std/learning) */
-#define MCE_RSP_PULSE_COUNT    0x15    /* RX pulse count (only if learning) */
-#define MCE_CMD_TX_PORTS       0x16    /* Get number of TX ports */
-#define MCE_CMD_G_WAKESRC      0x17    /* Get wake source */
-#define MCE_CMD_UNKNOWN7       0x18    /* Unknown */
 #define MCE_CMD_UNKNOWN8       0x19    /* Unknown */
 #define MCE_CMD_UNKNOWN9       0x1b    /* Unknown */
-#define MCE_CMD_DEVICE_RESET   0xaa    /* Reset the hardware */
-#define MCE_RSP_CMD_INVALID    0xfe    /* Invalid command issued */
+#define MCE_CMD_NULL           0x00    /* These show up various places... */
 
+/* if buf[i] & MCE_PORT_MASK == 0x80 and buf[i] != MCE_CMD_PORT_IR,
+ * then we're looking at a raw IR data sample */
+#define MCE_COMMAND_IRDATA     0x80
+#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */
 
 /* module parameters */
 #ifdef CONFIG_USB_DEBUG
@@ -388,48 +441,37 @@ struct mceusb_dev {
        char name[128];
        char phys[64];
        enum mceusb_model_type model;
+
+       bool need_reset;        /* flag to issue a device resume cmd */
+       u8 emver;               /* emulator interface version */
+       u8 num_txports;         /* number of transmit ports */
+       u8 num_rxports;         /* number of receive sensors */
+       u8 txports_cabled;      /* bitmask of transmitters with cable */
+       u8 rxports_active;      /* bitmask of active receive sensors */
 };
 
-/*
- * MCE Device Command Strings
- * Device command responses vary from device to device...
- * - DEVICE_RESET resets the hardware to its default state
- * - GET_REVISION fetches the hardware/software revision, common
- *   replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42
- * - GET_CARRIER_FREQ gets the carrier mode and frequency of the
- *   device, with replies in the form of 9f 06 MM FF, where MM is 0-3,
- *   meaning clk of 10000000, 2500000, 625000 or 156250, and FF is
- *   ((clk / frequency) - 1)
- * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us,
- *   response in the form of 9f 0c msb lsb
- * - GET_TX_BITMASK fetches the transmitter bitmask, replies in
- *   the form of 9f 08 bm, where bm is the bitmask
- * - GET_RX_SENSOR fetches the RX sensor setting -- long-range
- *   general use one or short-range learning one, in the form of
- *   9f 14 ss, where ss is either 01 for long-range or 02 for short
- * - SET_CARRIER_FREQ sets a new carrier mode and frequency
- * - SET_TX_BITMASK sets the transmitter bitmask
- * - SET_RX_TIMEOUT sets the receiver timeout
- * - SET_RX_SENSOR sets which receiver sensor to use
- */
-static char DEVICE_RESET[]     = {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER,
-                                  MCE_CMD_DEVICE_RESET};
-static char GET_REVISION[]     = {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION};
-static char GET_UNKNOWN[]      = {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7};
-static char GET_UNKNOWN2[]     = {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2};
-static char GET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER};
-static char GET_RX_TIMEOUT[]   = {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT};
-static char GET_TX_BITMASK[]   = {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK};
-static char GET_RX_SENSOR[]    = {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR};
+/* MCE Device Command Strings, generally a port and command pair */
+static char DEVICE_RESUME[]    = {MCE_CMD_NULL, MCE_CMD_PORT_SYS,
+                                  MCE_CMD_RESUME};
+static char GET_REVISION[]     = {MCE_CMD_PORT_SYS, MCE_CMD_G_REVISION};
+static char GET_EMVER[]                = {MCE_CMD_PORT_SYS, MCE_CMD_GETEMVER};
+static char GET_WAKEVERSION[]  = {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION};
+static char FLASH_LED[]                = {MCE_CMD_PORT_SYS, MCE_CMD_FLASHLED};
+static char GET_UNKNOWN2[]     = {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2};
+static char GET_CARRIER_FREQ[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS};
+static char GET_RX_TIMEOUT[]   = {MCE_CMD_PORT_IR, MCE_CMD_GETIRTIMEOUT};
+static char GET_NUM_PORTS[]    = {MCE_CMD_PORT_IR, MCE_CMD_GETIRNUMPORTS};
+static char GET_TX_BITMASK[]   = {MCE_CMD_PORT_IR, MCE_CMD_GETIRTXPORTS};
+static char GET_RX_SENSOR[]    = {MCE_CMD_PORT_IR, MCE_CMD_GETIRRXPORTEN};
 /* sub in desired values in lower byte or bytes for full command */
 /* FIXME: make use of these for transmit.
-static char SET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER,
-                                  MCE_CMD_S_CARRIER, 0x00, 0x00};
-static char SET_TX_BITMASK[]   = {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00};
-static char SET_RX_TIMEOUT[]   = {MCE_COMMAND_HEADER,
-                                  MCE_CMD_S_TIMEOUT, 0x00, 0x00};
-static char SET_RX_SENSOR[]    = {MCE_COMMAND_HEADER,
-                                  MCE_CMD_S_RXSENSOR, 0x00};
+static char SET_CARRIER_FREQ[] = {MCE_CMD_PORT_IR,
+                                  MCE_CMD_SETIRCFS, 0x00, 0x00};
+static char SET_TX_BITMASK[]   = {MCE_CMD_PORT_IR, MCE_CMD_SETIRTXPORTS, 0x00};
+static char SET_RX_TIMEOUT[]   = {MCE_CMD_PORT_IR,
+                                  MCE_CMD_SETIRTIMEOUT, 0x00, 0x00};
+static char SET_RX_SENSOR[]    = {MCE_CMD_PORT_IR,
+                                  MCE_RSP_EQIRRXPORTEN, 0x00};
 */
 
 static int mceusb_cmdsize(u8 cmd, u8 subcmd)
@@ -437,27 +479,33 @@ static int mceusb_cmdsize(u8 cmd, u8 subcmd)
        int datasize = 0;
 
        switch (cmd) {
-       case MCE_COMMAND_NULL:
-               if (subcmd == MCE_HW_CMD_HEADER)
+       case MCE_CMD_NULL:
+               if (subcmd == MCE_CMD_PORT_SYS)
                        datasize = 1;
                break;
-       case MCE_HW_CMD_HEADER:
+       case MCE_CMD_PORT_SYS:
                switch (subcmd) {
+               case MCE_RSP_EQWAKEVERSION:
+                       datasize = 4;
+                       break;
                case MCE_CMD_G_REVISION:
                        datasize = 2;
                        break;
+               case MCE_RSP_EQWAKESUPPORT:
+                       datasize = 1;
+                       break;
                }
-       case MCE_COMMAND_HEADER:
+       case MCE_CMD_PORT_IR:
                switch (subcmd) {
                case MCE_CMD_UNKNOWN:
-               case MCE_CMD_S_CARRIER:
-               case MCE_CMD_S_TIMEOUT:
-               case MCE_RSP_PULSE_COUNT:
+               case MCE_RSP_EQIRCFS:
+               case MCE_RSP_EQIRTIMEOUT:
+               case MCE_RSP_EQIRRXCFCNT:
                        datasize = 2;
                        break;
                case MCE_CMD_SIG_END:
-               case MCE_CMD_S_TXMASK:
-               case MCE_CMD_S_RXSENSOR:
+               case MCE_RSP_EQIRTXPORTS:
+               case MCE_RSP_EQIRRXPORTEN:
                        datasize = 1;
                        break;
                }
@@ -470,9 +518,10 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 {
        char codes[USB_BUFLEN * 3 + 1];
        char inout[9];
-       u8 cmd, subcmd, data1, data2;
+       u8 cmd, subcmd, data1, data2, data3, data4, data5;
        struct device *dev = ir->dev;
        int i, start, skip = 0;
+       u32 carrier, period;
 
        if (!debug)
                return;
@@ -500,18 +549,28 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
        subcmd = buf[start + 1] & 0xff;
        data1  = buf[start + 2] & 0xff;
        data2  = buf[start + 3] & 0xff;
+       data3  = buf[start + 4] & 0xff;
+       data4  = buf[start + 5] & 0xff;
+       data5  = buf[start + 6] & 0xff;
 
        switch (cmd) {
-       case MCE_COMMAND_NULL:
-               if ((subcmd == MCE_HW_CMD_HEADER) &&
-                   (data1 == MCE_CMD_DEVICE_RESET))
-                       dev_info(dev, "Device reset requested\n");
+       case MCE_CMD_NULL:
+               if (subcmd == MCE_CMD_NULL)
+                       break;
+               if ((subcmd == MCE_CMD_PORT_SYS) &&
+                   (data1 == MCE_CMD_RESUME))
+                       dev_info(dev, "Device resume requested\n");
                else
                        dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
                                 cmd, subcmd);
                break;
-       case MCE_HW_CMD_HEADER:
+       case MCE_CMD_PORT_SYS:
                switch (subcmd) {
+               case MCE_RSP_EQEMVER:
+                       if (!out)
+                               dev_info(dev, "Emulator interface version %x\n",
+                                        data1);
+                       break;
                case MCE_CMD_G_REVISION:
                        if (len == 2)
                                dev_info(dev, "Get hw/sw rev?\n");
@@ -520,21 +579,35 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
                                         "0x%02x 0x%02x\n", data1, data2,
                                         buf[start + 4], buf[start + 5]);
                        break;
-               case MCE_CMD_DEVICE_RESET:
-                       dev_info(dev, "Device reset requested\n");
+               case MCE_CMD_RESUME:
+                       dev_info(dev, "Device resume requested\n");
+                       break;
+               case MCE_RSP_CMD_ILLEGAL:
+                       dev_info(dev, "Illegal PORT_SYS command\n");
                        break;
-               case MCE_RSP_CMD_INVALID:
-                       dev_info(dev, "Previous command not supported\n");
+               case MCE_RSP_EQWAKEVERSION:
+                       if (!out)
+                               dev_info(dev, "Wake version, proto: 0x%02x, "
+                                        "payload: 0x%02x, address: 0x%02x, "
+                                        "version: 0x%02x\n",
+                                        data1, data2, data3, data4);
+                       break;
+               case MCE_RSP_GETPORTSTATUS:
+                       if (!out)
+                               /* We use data1 + 1 here, to match hw labels */
+                               dev_info(dev, "TX port %d: blaster is%s connected\n",
+                                        data1 + 1, data4 ? " not" : "");
+                       break;
+               case MCE_CMD_FLASHLED:
+                       dev_info(dev, "Attempting to flash LED\n");
                        break;
-               case MCE_CMD_UNKNOWN7:
-               case MCE_CMD_UNKNOWN9:
                default:
                        dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
                                 cmd, subcmd);
                        break;
                }
                break;
-       case MCE_COMMAND_HEADER:
+       case MCE_CMD_PORT_IR:
                switch (subcmd) {
                case MCE_CMD_SIG_END:
                        dev_info(dev, "End of signal\n");
@@ -546,47 +619,55 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
                        dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
                                 data1, data2);
                        break;
-               case MCE_CMD_S_CARRIER:
-                       dev_info(dev, "%s carrier mode and freq of "
-                                "0x%02x 0x%02x\n", inout, data1, data2);
+               case MCE_RSP_EQIRCFS:
+                       period = DIV_ROUND_CLOSEST(
+                                       (1 << data1 * 2) * (data2 + 1), 10);
+                       if (!period)
+                               break;
+                       carrier = (1000 * 1000) / period;
+                       dev_info(dev, "%s carrier of %u Hz (period %uus)\n",
+                                inout, carrier, period);
                        break;
-               case MCE_CMD_G_CARRIER:
+               case MCE_CMD_GETIRCFS:
                        dev_info(dev, "Get carrier mode and freq\n");
                        break;
-               case MCE_CMD_S_TXMASK:
+               case MCE_RSP_EQIRTXPORTS:
                        dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
                                 inout, data1);
                        break;
-               case MCE_CMD_S_TIMEOUT:
+               case MCE_RSP_EQIRTIMEOUT:
                        /* value is in units of 50us, so x*50/1000 ms */
+                       period = ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000;
                        dev_info(dev, "%s receive timeout of %d ms\n",
-                                inout,
-                                ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000);
+                                inout, period);
                        break;
-               case MCE_CMD_G_TIMEOUT:
+               case MCE_CMD_GETIRTIMEOUT:
                        dev_info(dev, "Get receive timeout\n");
                        break;
-               case MCE_CMD_G_TXMASK:
+               case MCE_CMD_GETIRTXPORTS:
                        dev_info(dev, "Get transmit blaster mask\n");
                        break;
-               case MCE_CMD_S_RXSENSOR:
+               case MCE_RSP_EQIRRXPORTEN:
                        dev_info(dev, "%s %s-range receive sensor in use\n",
                                 inout, data1 == 0x02 ? "short" : "long");
                        break;
-               case MCE_CMD_G_RXSENSOR:
-               /* aka MCE_RSP_PULSE_COUNT */
+               case MCE_CMD_GETIRRXPORTEN:
+               /* aka MCE_RSP_EQIRRXCFCNT */
                        if (out)
                                dev_info(dev, "Get receive sensor\n");
                        else if (ir->learning_enabled)
                                dev_info(dev, "RX pulse count: %d\n",
                                         ((data1 << 8) | data2));
                        break;
-               case MCE_RSP_CMD_INVALID:
-                       dev_info(dev, "Error! Hardware is likely wedged...\n");
+               case MCE_RSP_EQIRNUMPORTS:
+                       if (out)
+                               break;
+                       dev_info(dev, "Num TX ports: %x, num RX ports: %x\n",
+                                data1, data2);
+                       break;
+               case MCE_RSP_CMD_ILLEGAL:
+                       dev_info(dev, "Illegal PORT_IR command\n");
                        break;
-               case MCE_CMD_UNKNOWN2:
-               case MCE_CMD_UNKNOWN3:
-               case MCE_CMD_UNKNOWN5:
                default:
                        dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
                                 cmd, subcmd);
@@ -599,8 +680,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 
        if (cmd == MCE_IRDATA_TRAILER)
                dev_info(dev, "End of raw IR data\n");
-       else if ((cmd != MCE_COMMAND_HEADER) &&
-                ((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA))
+       else if ((cmd != MCE_CMD_PORT_IR) &&
+                ((cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA))
                dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem);
 }
 
@@ -616,9 +697,6 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
        if (ir) {
                len = urb->actual_length;
 
-               mce_dbg(ir->dev, "callback called (status=%d len=%d)\n",
-                       urb->status, len);
-
                mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true);
        }
 
@@ -683,7 +761,16 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
 
 static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
 {
+       int rsize = sizeof(DEVICE_RESUME);
+
+       if (ir->need_reset) {
+               ir->need_reset = false;
+               mce_request_packet(ir, DEVICE_RESUME, rsize, MCEUSB_TX);
+               msleep(10);
+       }
+
        mce_request_packet(ir, data, size, MCEUSB_TX);
+       msleep(10);
 }
 
 static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size)
@@ -708,8 +795,8 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
                return -ENOMEM;
 
        /* MCE tx init header */
-       cmdbuf[cmdcount++] = MCE_COMMAND_HEADER;
-       cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK;
+       cmdbuf[cmdcount++] = MCE_CMD_PORT_IR;
+       cmdbuf[cmdcount++] = MCE_CMD_SETIRTXPORTS;
        cmdbuf[cmdcount++] = ir->tx_mask;
 
        /* Generate mce packet data */
@@ -795,8 +882,8 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
        struct mceusb_dev *ir = dev->priv;
        int clk = 10000000;
        int prescaler = 0, divisor = 0;
-       unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER,
-                                   MCE_CMD_S_CARRIER, 0x00, 0x00 };
+       unsigned char cmdbuf[4] = { MCE_CMD_PORT_IR,
+                                   MCE_CMD_SETIRCFS, 0x00, 0x00 };
 
        /* Carrier has changed */
        if (ir->carrier != carrier) {
@@ -844,17 +931,34 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
        u8 lo = ir->buf_in[index + 2] & 0xff;
 
        switch (ir->buf_in[index]) {
+       /* the one and only 5-byte return value command */
+       case MCE_RSP_GETPORTSTATUS:
+               if ((ir->buf_in[index + 4] & 0xff) == 0x00)
+                       ir->txports_cabled |= 1 << hi;
+               break;
+
        /* 2-byte return value commands */
-       case MCE_CMD_S_TIMEOUT:
+       case MCE_RSP_EQIRTIMEOUT:
                ir->rc->timeout = US_TO_NS((hi << 8 | lo) * MCE_TIME_UNIT);
                break;
+       case MCE_RSP_EQIRNUMPORTS:
+               ir->num_txports = hi;
+               ir->num_rxports = lo;
+               break;
 
        /* 1-byte return value commands */
-       case MCE_CMD_S_TXMASK:
+       case MCE_RSP_EQEMVER:
+               ir->emver = hi;
+               break;
+       case MCE_RSP_EQIRTXPORTS:
                ir->tx_mask = hi;
                break;
-       case MCE_CMD_S_RXSENSOR:
-               ir->learning_enabled = (hi == 0x02);
+       case MCE_RSP_EQIRRXPORTEN:
+               ir->learning_enabled = ((hi & 0x02) == 0x02);
+               ir->rxports_active = hi;
+               break;
+       case MCE_RSP_CMD_ILLEGAL:
+               ir->need_reset = true;
                break;
        default:
                break;
@@ -903,8 +1007,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
                        /* decode mce packets of the form (84),AA,BB,CC,DD */
                        /* IR data packets can span USB messages - rem */
                        ir->cmd = ir->buf_in[i];
-                       if ((ir->cmd == MCE_COMMAND_HEADER) ||
-                           ((ir->cmd & MCE_COMMAND_MASK) !=
+                       if ((ir->cmd == MCE_CMD_PORT_IR) ||
+                           ((ir->cmd & MCE_PORT_MASK) !=
                             MCE_COMMAND_IRDATA)) {
                                ir->parser_state = SUBCMD;
                                continue;
@@ -969,6 +1073,13 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
        usb_submit_urb(urb, GFP_ATOMIC);
 }
 
+static void mceusb_get_emulator_version(struct mceusb_dev *ir)
+{
+       /* If we get no reply or an illegal command reply, its ver 1, says MS */
+       ir->emver = 1;
+       mce_async_out(ir, GET_EMVER, sizeof(GET_EMVER));
+}
+
 static void mceusb_gen1_init(struct mceusb_dev *ir)
 {
        int ret;
@@ -1011,8 +1122,8 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
                              0x0000, 0x0100, NULL, 0, HZ * 3);
        mce_dbg(dev, "%s - retC = %d\n", __func__, ret);
 
-       /* device reset */
-       mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+       /* device resume */
+       mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME));
 
        /* get hw/sw revision? */
        mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
@@ -1022,23 +1133,36 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
 
 static void mceusb_gen2_init(struct mceusb_dev *ir)
 {
-       /* device reset */
-       mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+       /* device resume */
+       mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME));
 
        /* get hw/sw revision? */
        mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
 
-       /* unknown what the next two actually return... */
-       mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN));
+       /* get wake version (protocol, key, address) */
+       mce_async_out(ir, GET_WAKEVERSION, sizeof(GET_WAKEVERSION));
+
+       /* unknown what this one actually returns... */
        mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2));
 }
 
 static void mceusb_get_parameters(struct mceusb_dev *ir)
 {
+       int i;
+       unsigned char cmdbuf[3] = { MCE_CMD_PORT_SYS,
+                                   MCE_CMD_GETPORTSTATUS, 0x00 };
+
+       /* defaults, if the hardware doesn't support querying */
+       ir->num_txports = 2;
+       ir->num_rxports = 2;
+
+       /* get number of tx and rx ports */
+       mce_async_out(ir, GET_NUM_PORTS, sizeof(GET_NUM_PORTS));
+
        /* get the carrier and frequency */
        mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ));
 
-       if (!ir->flags.no_tx)
+       if (ir->num_txports && !ir->flags.no_tx)
                /* get the transmitter bitmask */
                mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
 
@@ -1047,6 +1171,19 @@ static void mceusb_get_parameters(struct mceusb_dev *ir)
 
        /* get receiver sensor setting */
        mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR));
+
+       for (i = 0; i < ir->num_txports; i++) {
+               cmdbuf[2] = i;
+               mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+       }
+}
+
+static void mceusb_flash_led(struct mceusb_dev *ir)
+{
+       if (ir->emver < 2)
+               return;
+
+       mce_async_out(ir, FLASH_LED, sizeof(FLASH_LED));
 }
 
 static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
@@ -1220,6 +1357,9 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
        mce_dbg(&intf->dev, "Flushing receive buffers\n");
        mce_flush_rx_buffer(ir, maxp);
 
+       /* figure out which firmware/emulator version this hardware has */
+       mceusb_get_emulator_version(ir);
+
        /* initialize device */
        if (ir->flags.microsoft_gen1)
                mceusb_gen1_init(ir);
@@ -1228,13 +1368,23 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
 
        mceusb_get_parameters(ir);
 
+       mceusb_flash_led(ir);
+
        if (!ir->flags.no_tx)
                mceusb_set_tx_mask(ir->rc, MCE_DEFAULT_TX_MASK);
 
        usb_set_intfdata(intf, ir);
 
-       dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name,
-                dev->bus->busnum, dev->devnum);
+       /* enable wake via this device */
+       device_set_wakeup_capable(ir->dev, true);
+       device_set_wakeup_enable(ir->dev, true);
+
+       dev_info(&intf->dev, "Registered %s with mce emulator interface "
+                "version %x\n", name, ir->emver);
+       dev_info(&intf->dev, "%x tx ports (0x%x cabled) and "
+                "%x rx sensors (0x%x active)\n",
+                ir->num_txports, ir->txports_cabled,
+                ir->num_rxports, ir->rxports_active);
 
        return 0;
 
index 04c2c72..c6ca870 100644 (file)
@@ -162,49 +162,49 @@ void ir_raw_init(void);
 #ifdef CONFIG_IR_NEC_DECODER_MODULE
 #define load_nec_decode()      request_module("ir-nec-decoder")
 #else
-#define load_nec_decode()      0
+static inline void load_nec_decode(void) { }
 #endif
 
 /* from ir-rc5-decoder.c */
 #ifdef CONFIG_IR_RC5_DECODER_MODULE
 #define load_rc5_decode()      request_module("ir-rc5-decoder")
 #else
-#define load_rc5_decode()      0
+static inline void load_rc5_decode(void) { }
 #endif
 
 /* from ir-rc6-decoder.c */
 #ifdef CONFIG_IR_RC6_DECODER_MODULE
 #define load_rc6_decode()      request_module("ir-rc6-decoder")
 #else
-#define load_rc6_decode()      0
+static inline void load_rc6_decode(void) { }
 #endif
 
 /* from ir-jvc-decoder.c */
 #ifdef CONFIG_IR_JVC_DECODER_MODULE
 #define load_jvc_decode()      request_module("ir-jvc-decoder")
 #else
-#define load_jvc_decode()      0
+static inline void load_jvc_decode(void) { }
 #endif
 
 /* from ir-sony-decoder.c */
 #ifdef CONFIG_IR_SONY_DECODER_MODULE
 #define load_sony_decode()     request_module("ir-sony-decoder")
 #else
-#define load_sony_decode()     0
+static inline void load_sony_decode(void) { }
 #endif
 
 /* from ir-mce_kbd-decoder.c */
 #ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE
 #define load_mce_kbd_decode()  request_module("ir-mce_kbd-decoder")
 #else
-#define load_mce_kbd_decode()  0
+static inline void load_mce_kbd_decode(void) { }
 #endif
 
 /* from ir-lirc-codec.c */
 #ifdef CONFIG_IR_LIRC_CODEC_MODULE
 #define load_lirc_codec()      request_module("ir-lirc-codec")
 #else
-#define load_lirc_codec()      0
+static inline void load_lirc_codec(void) { }
 #endif
 
 
index 51a23f4..666d4bb 100644 (file)
@@ -928,10 +928,6 @@ out:
 
 static void rc_dev_release(struct device *device)
 {
-       struct rc_dev *dev = to_rc_dev(device);
-
-       kfree(dev);
-       module_put(THIS_MODULE);
 }
 
 #define ADD_HOTPLUG_VAR(fmt, val...)                                   \
@@ -945,6 +941,9 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 {
        struct rc_dev *dev = to_rc_dev(device);
 
+       if (!dev || !dev->input_dev)
+               return -ENODEV;
+
        if (dev->rc_map.name)
                ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name);
        if (dev->driver_name)
@@ -1013,10 +1012,16 @@ EXPORT_SYMBOL_GPL(rc_allocate_device);
 
 void rc_free_device(struct rc_dev *dev)
 {
-       if (dev) {
+       if (!dev)
+               return;
+
+       if (dev->input_dev)
                input_free_device(dev->input_dev);
-               put_device(&dev->dev);
-       }
+
+       put_device(&dev->dev);
+
+       kfree(dev);
+       module_put(THIS_MODULE);
 }
 EXPORT_SYMBOL_GPL(rc_free_device);
 
@@ -1143,14 +1148,18 @@ void rc_unregister_device(struct rc_dev *dev)
        if (dev->driver_type == RC_DRIVER_IR_RAW)
                ir_raw_event_unregister(dev);
 
+       /* Freeing the table should also call the stop callback */
+       ir_free_table(&dev->rc_map);
+       IR_dprintk(1, "Freed keycode table\n");
+
        input_unregister_device(dev->input_dev);
        dev->input_dev = NULL;
 
-       ir_free_table(&dev->rc_map);
-       IR_dprintk(1, "Freed keycode table\n");
+       device_del(&dev->dev);
 
-       device_unregister(&dev->dev);
+       rc_free_device(dev);
 }
+
 EXPORT_SYMBOL_GPL(rc_unregister_device);
 
 /*
index a166044..61287fc 100644 (file)
@@ -195,11 +195,6 @@ struct redrat3_dev {
        dma_addr_t dma_in;
        dma_addr_t dma_out;
 
-       /* true if write urb is busy */
-       bool write_busy;
-       /* wait for the write to finish */
-       struct completion write_finished;
-
        /* locks this structure */
        struct mutex lock;
 
@@ -207,8 +202,6 @@ struct redrat3_dev {
        struct timer_list rx_timeout;
        u32 hw_timeout;
 
-       /* Is the device currently receiving? */
-       bool recv_in_progress;
        /* is the detector enabled*/
        bool det_enabled;
        /* Is the device currently transmitting?*/
index bec8abc..13f54b5 100644 (file)
@@ -41,6 +41,8 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/pnp.h>
 #include <linux/interrupt.h>
@@ -1155,12 +1157,12 @@ wbcir_init(void)
        case IR_PROTOCOL_RC6:
                break;
        default:
-               printk(KERN_ERR DRVNAME ": Invalid power-on protocol\n");
+               pr_err("Invalid power-on protocol\n");
        }
 
        ret = pnp_register_driver(&wbcir_driver);
        if (ret)
-               printk(KERN_ERR DRVNAME ": Unable to register driver\n");
+               pr_err("Unable to register driver\n");
 
        return ret;
 }
index f574dc0..d285c8c 100644 (file)
@@ -467,6 +467,20 @@ config VIDEO_OV7670
          OV7670 VGA camera.  It currently only works with the M88ALP01
          controller.
 
+config VIDEO_MT9P031
+       tristate "Aptina MT9P031 support"
+       depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       ---help---
+         This is a Video4Linux2 sensor-level driver for the Aptina
+         (Micron) mt9p031 5 Mpixel camera.
+
+config VIDEO_MT9T001
+       tristate "Aptina MT9T001 support"
+       depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       ---help---
+         This is a Video4Linux2 sensor-level driver for the Aptina
+         (Micron) mt0t001 3 Mpixel camera.
+
 config VIDEO_MT9V011
        tristate "Micron mt9v011 sensor support"
        depends on I2C && VIDEO_V4L2
@@ -489,6 +503,20 @@ config VIDEO_TCM825X
          This is a driver for the Toshiba TCM825x VGA camera sensor.
          It is used for example in Nokia N800.
 
+config VIDEO_SR030PC30
+       tristate "Siliconfile SR030PC30 sensor support"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         This driver supports SR030PC30 VGA camera from Siliconfile
+
+config VIDEO_NOON010PC30
+       tristate "Siliconfile NOON010PC30 sensor support"
+       depends on I2C && VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_SUBDEV_API
+       ---help---
+         This driver supports NOON010PC30 CIF camera from Siliconfile
+
+source "drivers/media/video/m5mols/Kconfig"
+
 comment "Flash devices"
 
 config VIDEO_ADP1653
@@ -737,12 +765,6 @@ config VIDEO_M32R_AR_M64278
          To compile this driver as a module, choose M here: the
          module will be called arv.
 
-config VIDEO_SR030PC30
-       tristate "SR030PC30 VGA camera sensor support"
-       depends on I2C && VIDEO_V4L2
-       ---help---
-         This driver supports SR030PC30 VGA camera from Siliconfile
-
 config VIDEO_VIA_CAMERA
        tristate "VIAFB camera controller support"
        depends on FB_VIA
@@ -753,18 +775,9 @@ config VIDEO_VIA_CAMERA
           Chrome9 chipsets.  Currently only tested on OLPC xo-1.5 systems
           with ov7670 sensors.
 
-config VIDEO_NOON010PC30
-       tristate "NOON010PC30 CIF camera sensor support"
-       depends on I2C && VIDEO_V4L2
-       ---help---
-         This driver supports NOON010PC30 CIF camera from Siliconfile
-
-source "drivers/media/video/m5mols/Kconfig"
-
 config VIDEO_OMAP3
        tristate "OMAP 3 Camera support (EXPERIMENTAL)"
-       select OMAP_IOMMU
-       depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL
+       depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL
        ---help---
          Driver for an OMAP 3 camera controller.
 
@@ -949,8 +962,9 @@ config VIDEO_MX2
          Interface
 
 config  VIDEO_SAMSUNG_S5P_FIMC
-       tristate "Samsung S5P and EXYNOS4 camera host interface driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
+       tristate "Samsung S5P and EXYNOS4 camera interface driver (EXPERIMENTAL)"
+       depends on VIDEO_V4L2 && I2C && PLAT_S5P && PM_RUNTIME && \
+               VIDEO_V4L2_SUBDEV_API && EXPERIMENTAL
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        ---help---
@@ -1004,6 +1018,8 @@ source "drivers/media/video/tlg2300/Kconfig"
 
 source "drivers/media/video/cx231xx/Kconfig"
 
+source "drivers/media/video/tm6000/Kconfig"
+
 source "drivers/media/video/usbvision/Kconfig"
 
 source "drivers/media/video/et61x251/Kconfig"
index 2723900..11fff97 100644 (file)
@@ -65,6 +65,8 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
 obj-$(CONFIG_VIDEO_OV7670)     += ov7670.o
 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
+obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
+obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
 obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
 obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
 obj-$(CONFIG_VIDEO_SR030PC30)  += sr030pc30.o
@@ -105,6 +107,7 @@ obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
+obj-$(CONFIG_VIDEO_TM6000) += tm6000/
 obj-$(CONFIG_VIDEO_MXB) += mxb.o
 obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
 obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
@@ -190,6 +193,6 @@ obj-y       += davinci/
 
 obj-$(CONFIG_ARCH_OMAP)        += omap/
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/common/tuners
index be7befd..5914390 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <linux/delay.h>
 #include <linux/i2c.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/version.h>
 #include <media/adp1653.h>
@@ -258,7 +259,7 @@ static int adp1653_init_controls(struct adp1653_flash *flash)
        if (flash->ctrls.error)
                return flash->ctrls.error;
 
-       fault->is_volatile = 1;
+       fault->flags |= V4L2_CTRL_FLAG_VOLATILE;
 
        flash->subdev.ctrl_handler = &flash->ctrls;
        return 0;
@@ -413,6 +414,10 @@ static int adp1653_probe(struct i2c_client *client,
        struct adp1653_flash *flash;
        int ret;
 
+       /* we couldn't work without platform data */
+       if (client->dev.platform_data == NULL)
+               return -ENODEV;
+
        flash = kzalloc(sizeof(*flash), GFP_KERNEL);
        if (flash == NULL)
                return -ENOMEM;
@@ -425,12 +430,21 @@ static int adp1653_probe(struct i2c_client *client,
        flash->subdev.internal_ops = &adp1653_internal_ops;
        flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
-       adp1653_init_controls(flash);
+       ret = adp1653_init_controls(flash);
+       if (ret)
+               goto free_and_quit;
 
        ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0);
        if (ret < 0)
-               kfree(flash);
+               goto free_and_quit;
+
+       flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+
+       return 0;
 
+free_and_quit:
+       v4l2_ctrl_handler_free(&flash->ctrls);
+       kfree(flash);
        return ret;
 }
 
index d2327db..206078e 100644 (file)
@@ -61,6 +61,11 @@ static inline struct adv7175 *to_adv7175(struct v4l2_subdev *sd)
 
 static char *inputs[] = { "pass_through", "play_back", "color_bar" };
 
+static enum v4l2_mbus_pixelcode adv7175_codes[] = {
+       V4L2_MBUS_FMT_UYVY8_2X8,
+       V4L2_MBUS_FMT_UYVY8_1X16,
+};
+
 /* ----------------------------------------------------------------------- */
 
 static inline int adv7175_write(struct v4l2_subdev *sd, u8 reg, u8 value)
@@ -296,6 +301,60 @@ static int adv7175_s_routing(struct v4l2_subdev *sd,
        return 0;
 }
 
+static int adv7175_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+                               enum v4l2_mbus_pixelcode *code)
+{
+       if (index >= ARRAY_SIZE(adv7175_codes))
+               return -EINVAL;
+
+       *code = adv7175_codes[index];
+       return 0;
+}
+
+static int adv7175_g_fmt(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_framefmt *mf)
+{
+       u8 val = adv7175_read(sd, 0x7);
+
+       if ((val & 0x40) == (1 << 6))
+               mf->code = V4L2_MBUS_FMT_UYVY8_1X16;
+       else
+               mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+
+       mf->colorspace  = V4L2_COLORSPACE_SMPTE170M;
+       mf->width       = 0;
+       mf->height      = 0;
+       mf->field       = V4L2_FIELD_ANY;
+
+       return 0;
+}
+
+static int adv7175_s_fmt(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_framefmt *mf)
+{
+       u8 val = adv7175_read(sd, 0x7);
+       int ret;
+
+       switch (mf->code) {
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+               val &= ~0x40;
+               break;
+
+       case V4L2_MBUS_FMT_UYVY8_1X16:
+               val |= 0x40;
+               break;
+
+       default:
+               v4l2_dbg(1, debug, sd,
+                       "illegal v4l2_mbus_framefmt code: %d\n", mf->code);
+               return -EINVAL;
+       }
+
+       ret = adv7175_write(sd, 0x7, val);
+
+       return ret;
+}
+
 static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -324,6 +383,9 @@ static const struct v4l2_subdev_core_ops adv7175_core_ops = {
 static const struct v4l2_subdev_video_ops adv7175_video_ops = {
        .s_std_output = adv7175_s_std_output,
        .s_routing = adv7175_s_routing,
+       .s_mbus_fmt = adv7175_s_fmt,
+       .g_mbus_fmt = adv7175_g_fmt,
+       .enum_mbus_fmt  = adv7175_enum_fmt,
 };
 
 static const struct v4l2_subdev_ops adv7175_ops = {
index 7b89f00..774715d 100644 (file)
@@ -249,7 +249,7 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset)
        Videobuf operations
    ------------------------------------------------------------------*/
 static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
-                               unsigned int *nplanes, unsigned long sizes[],
+                               unsigned int *nplanes, unsigned int sizes[],
                                void *alloc_ctxs[])
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
@@ -341,7 +341,7 @@ static int buffer_prepare(struct vb2_buffer *vb)
 
                        /* Initialize the dma descriptor */
                        desc->p_fbd->fb_address =
-                                       vb2_dma_contig_plane_paddr(vb, 0);
+                                       vb2_dma_contig_plane_dma_addr(vb, 0);
                        desc->p_fbd->next_fbd_address = 0;
                        set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB);
 
@@ -404,12 +404,13 @@ static void buffer_queue(struct vb2_buffer *vb)
 
        if (isi->active == NULL) {
                isi->active = buf;
-               start_dma(isi, buf);
+               if (vb2_is_streaming(vb->vb2_queue))
+                       start_dma(isi, buf);
        }
        spin_unlock_irqrestore(&isi->lock, flags);
 }
 
-static int start_streaming(struct vb2_queue *vq)
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -431,17 +432,26 @@ static int start_streaming(struct vb2_queue *vq)
        ret = wait_event_interruptible(isi->vsync_wq,
                                       isi->state != ISI_STATE_IDLE);
        if (ret)
-               return ret;
+               goto err;
 
-       if (isi->state != ISI_STATE_READY)
-               return -EIO;
+       if (isi->state != ISI_STATE_READY) {
+               ret = -EIO;
+               goto err;
+       }
 
        spin_lock_irq(&isi->lock);
        isi->state = ISI_STATE_WAIT_SOF;
        isi_writel(isi, ISI_INTDIS, ISI_SR_VSYNC);
+       if (count)
+               start_dma(isi, isi->active);
        spin_unlock_irq(&isi->lock);
 
        return 0;
+err:
+       isi->active = NULL;
+       isi->sequence = 0;
+       INIT_LIST_HEAD(&isi->video_buffer_list);
+       return ret;
 }
 
 /* abort streaming and wait for last buffer */
index 5c7f2f7..bd22223 100644 (file)
@@ -2,8 +2,8 @@ au0828-objs     := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-vid
 
 obj-$(CONFIG_VIDEO_AU0828) += au0828.o
 
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
 
-EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
index f872044..859eabf 100644 (file)
@@ -229,7 +229,7 @@ static int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
        if (pstd)
                *pstd = std;
        if (pstatus)
-               *pstatus = status;
+               *pstatus = res;
 
        v4l2_dbg(1, debug, sd, "get status %x\n", status);
        return 0;
index e415f6f..3f9a2b2 100644 (file)
@@ -8,6 +8,6 @@ bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
 
 obj-$(CONFIG_VIDEO_BT848) += bttv.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/video
+ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
index 5b15f63..5939021 100644 (file)
@@ -25,6 +25,8 @@
 
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/kmod.h>
@@ -2905,19 +2907,17 @@ void __devinit bttv_idcard(struct bttv *btv)
 
                if (type != -1) {
                        /* found it */
-                       printk(KERN_INFO "bttv%d: detected: %s [card=%d], "
-                              "PCI subsystem ID is %04x:%04x\n",
-                              btv->c.nr,cards[type].name,cards[type].cardnr,
-                              btv->cardid & 0xffff,
-                              (btv->cardid >> 16) & 0xffff);
+                       pr_info("%d: detected: %s [card=%d], PCI subsystem ID is %04x:%04x\n",
+                               btv->c.nr, cards[type].name, cards[type].cardnr,
+                               btv->cardid & 0xffff,
+                               (btv->cardid >> 16) & 0xffff);
                        btv->c.type = cards[type].cardnr;
                } else {
                        /* 404 */
-                       printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n",
-                              btv->c.nr, btv->cardid & 0xffff,
-                              (btv->cardid >> 16) & 0xffff);
-                       printk(KERN_DEBUG "please mail id, board name and "
-                              "the correct card= insmod option to linux-media@vger.kernel.org\n");
+                       pr_info("%d: subsystem: %04x:%04x (UNKNOWN)\n",
+                               btv->c.nr, btv->cardid & 0xffff,
+                               (btv->cardid >> 16) & 0xffff);
+                       pr_debug("please mail id, board name and the correct card= insmod option to linux-media@vger.kernel.org\n");
                }
        }
 
@@ -2926,10 +2926,10 @@ void __devinit bttv_idcard(struct bttv *btv)
                btv->c.type=card[btv->c.nr];
 
        /* print which card config we are using */
-       printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->c.nr,
-              bttv_tvcards[btv->c.type].name, btv->c.type,
-              card[btv->c.nr] < bttv_num_tvcards
-              ? "insmod option" : "autodetected");
+       pr_info("%d: using: %s [card=%d,%s]\n",
+               btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type,
+               card[btv->c.nr] < bttv_num_tvcards
+               ? "insmod option" : "autodetected");
 
        /* overwrite gpio stuff ?? */
        if (UNSET == audioall && UNSET == audiomux[0])
@@ -2948,12 +2948,13 @@ void __devinit bttv_idcard(struct bttv *btv)
                }
        }
        bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits;
-       printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=",
-              btv->c.nr,bttv_tvcards[btv->c.type].gpiomask);
+       pr_info("%d: gpio config override: mask=0x%x, mux=",
+               btv->c.nr, bttv_tvcards[btv->c.type].gpiomask);
        for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) {
-               printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]);
+               pr_cont("%s0x%x",
+                       i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]);
        }
-       printk("\n");
+       pr_cont("\n");
 }
 
 /*
@@ -2974,8 +2975,8 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
 
        if (-1 != type) {
                btv->c.type = type;
-               printk("bttv%d: detected by eeprom: %s [card=%d]\n",
-                      btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type);
+               pr_info("%d: detected by eeprom: %s [card=%d]\n",
+                       btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type);
        }
 }
 
@@ -3019,7 +3020,7 @@ static void flyvideo_gpio(struct bttv *btv)
                tuner_type = 3;  /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */
                break;
        default:
-               printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr);
+               pr_info("%d: FlyVideo_gpio: unknown tuner type\n", btv->c.nr);
                break;
        }
 
@@ -3036,13 +3037,13 @@ static void flyvideo_gpio(struct bttv *btv)
        if (is_capture_only)
                tuner_type = TUNER_ABSENT; /* No tuner present */
 
-       printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
-               btv->c.nr, has_radio ? "yes" : "no ",
-               has_remote ? "yes" : "no ", tuner_type, gpio);
-       printk(KERN_INFO "bttv%d: FlyVideo  LR90=%s tda9821/tda9820=%s capture_only=%s\n",
-               btv->c.nr, is_lr90 ? "yes" : "no ",
-               has_tda9820_tda9821 ? "yes" : "no ",
-               is_capture_only ? "yes" : "no ");
+       pr_info("%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
+               btv->c.nr, has_radio ? "yes" : "no",
+               has_remote ? "yes" : "no", tuner_type, gpio);
+       pr_info("%d: FlyVideo  LR90=%s tda9821/tda9820=%s capture_only=%s\n",
+               btv->c.nr, is_lr90 ? "yes" : "no",
+               has_tda9820_tda9821 ? "yes" : "no",
+               is_capture_only ? "yes" : "no");
 
        if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */
                btv->tuner_type = tuner_type;
@@ -3091,12 +3092,11 @@ static void miro_pinnacle_gpio(struct bttv *btv)
                        if (btv->c.type == BTTV_BOARD_PINNACLE)
                                btv->c.type = BTTV_BOARD_PINNACLEPRO;
                }
-               printk(KERN_INFO
-                      "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
-                      btv->c.nr, id+1, btv->tuner_type,
-                      !btv->has_radio ? "no" :
-                      (btv->has_matchbox ? "matchbox" : "fmtuner"),
-                      (-1 == msp) ? "no" : "yes");
+               pr_info("%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
+                       btv->c.nr, id+1, btv->tuner_type,
+                       !btv->has_radio ? "no" :
+                       (btv->has_matchbox ? "matchbox" : "fmtuner"),
+                       (-1 == msp) ? "no" : "yes");
        } else {
                /* new cards with microtune tuner */
                id = 63 - id;
@@ -3138,9 +3138,8 @@ static void miro_pinnacle_gpio(struct bttv *btv)
                }
                if (-1 != msp)
                        btv->c.type = BTTV_BOARD_PINNACLEPRO;
-               printk(KERN_INFO
-                      "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
-                      btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
+               pr_info("%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
+                       btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
                btv->tuner_type = TUNER_MT2032;
        }
 }
@@ -3202,7 +3201,7 @@ static void gvc1100_muxsel(struct bttv *btv, unsigned int input)
 
 static void init_lmlbt4x(struct bttv *btv)
 {
-       printk(KERN_DEBUG "LMLBT4x init\n");
+       pr_debug("LMLBT4x init\n");
        btwrite(0x000000, BT848_GPIO_REG_INP);
        gpio_inout(0xffffff, 0x0006C0);
        gpio_write(0x000000);
@@ -3246,7 +3245,7 @@ static void bttv_reset_audio(struct bttv *btv)
                return;
 
        if (bttv_debug)
-               printk("bttv%d: BT878A ARESET\n",btv->c.nr);
+               pr_debug("%d: BT878A ARESET\n", btv->c.nr);
        btwrite((1<<7), 0x058);
        udelay(10);
        btwrite(     0, 0x058);
@@ -3349,7 +3348,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
        case BTTV_BOARD_MAGICTVIEW061:
                if (btv->cardid == 0x3002144f) {
                        btv->has_radio=1;
-                       printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr);
+                       pr_info("%d: radio detected by subsystem id (CPH05x)\n",
+                               btv->c.nr);
                }
                break;
        case BTTV_BOARD_STB2:
@@ -3438,17 +3438,16 @@ void __devinit bttv_init_card2(struct bttv *btv)
                btv->tuner_type = tuner[btv->c.nr];
 
        if (btv->tuner_type == TUNER_ABSENT)
-               printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr);
-       else if(btv->tuner_type == UNSET)
-               printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr);
+               pr_info("%d: tuner absent\n", btv->c.nr);
+       else if (btv->tuner_type == UNSET)
+               pr_warn("%d: tuner type unset\n", btv->c.nr);
        else
-               printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr,
-                      btv->tuner_type);
+               pr_info("%d: tuner type=%d\n", btv->c.nr, btv->tuner_type);
 
        if (autoload != UNSET) {
-               printk(KERN_WARNING "bttv%d: the autoload option is obsolete.\n", btv->c.nr);
-               printk(KERN_WARNING "bttv%d: use option msp3400, tda7432 or tvaudio to\n", btv->c.nr);
-               printk(KERN_WARNING "bttv%d: override which audio module should be used.\n", btv->c.nr);
+               pr_warn("%d: the autoload option is obsolete\n", btv->c.nr);
+               pr_warn("%d: use option msp3400, tda7432 or tvaudio to override which audio module should be used\n",
+                       btv->c.nr);
        }
 
        if (UNSET == btv->tuner_type)
@@ -3541,8 +3540,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
        }
 
        default:
-               printk(KERN_WARNING "bttv%d: unknown audiodev value!\n",
-                       btv->c.nr);
+               pr_warn("%d: unknown audiodev value!\n", btv->c.nr);
                return;
        }
 
@@ -3585,8 +3583,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
                return;
 
 no_audio:
-       printk(KERN_WARNING "bttv%d: audio absent, no audio device found!\n",
-                       btv->c.nr);
+       pr_warn("%d: audio absent, no audio device found!\n", btv->c.nr);
 }
 
 
@@ -3639,19 +3636,19 @@ static void modtec_eeprom(struct bttv *btv)
 {
        if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) {
                btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I;
-               printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
-                      btv->c.nr,&eeprom_data[0x1e]);
+               pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n",
+                       btv->c.nr, &eeprom_data[0x1e]);
        } else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) {
                btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I;
-               printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
-                      btv->c.nr,&eeprom_data[0x1e]);
+               pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n",
+                       btv->c.nr, &eeprom_data[0x1e]);
        } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
                btv->tuner_type=TUNER_PHILIPS_NTSC;
-               printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
-                      btv->c.nr,&eeprom_data[0x1e]);
+               pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n",
+                       btv->c.nr, &eeprom_data[0x1e]);
        } else {
-               printk("bttv%d: Modtec: Unknown TunerString: %s\n",
-                      btv->c.nr,&eeprom_data[0x1e]);
+               pr_info("%d: Modtec: Unknown TunerString: %s\n",
+                       btv->c.nr, &eeprom_data[0x1e]);
        }
 }
 
@@ -3663,7 +3660,7 @@ static void __devinit hauppauge_eeprom(struct bttv *btv)
        btv->tuner_type = tv.tuner_type;
        btv->has_radio  = tv.has_radio;
 
-       printk("bttv%d: Hauppauge eeprom indicates model#%d\n",
+       pr_info("%d: Hauppauge eeprom indicates model#%d\n",
                btv->c.nr, tv.model);
 
        /*
@@ -3671,7 +3668,7 @@ static void __devinit hauppauge_eeprom(struct bttv *btv)
         * type based on model #.
         */
        if(tv.model == 64900) {
-               printk("bttv%d: Switching board type from %s to %s\n",
+               pr_info("%d: Switching board type from %s to %s\n",
                        btv->c.nr,
                        bttv_tvcards[btv->c.type].name,
                        bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name);
@@ -3698,8 +3695,7 @@ static int terratec_active_radio_upgrade(struct bttv *btv)
        freq=88000/62.5;
        tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */
        if (0x1ed8 == tea5757_read(btv)) {
-               printk("bttv%d: Terratec Active Radio Upgrade found.\n",
-                      btv->c.nr);
+               pr_info("%d: Terratec Active Radio Upgrade found\n", btv->c.nr);
                btv->has_radio    = 1;
                btv->has_saa6588  = 1;
                btv->has_matchbox = 1;
@@ -3771,13 +3767,12 @@ static int __devinit pvr_boot(struct bttv *btv)
 
        rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev);
        if (rc != 0) {
-               printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n",
-                      btv->c.nr);
+               pr_warn("%d: no altera firmware [via hotplug]\n", btv->c.nr);
                return rc;
        }
        rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size);
-       printk(KERN_INFO "bttv%d: altera firmware upload %s\n",
-              btv->c.nr, (rc < 0) ? "failed" : "ok");
+       pr_info("%d: altera firmware upload %s\n",
+               btv->c.nr, (rc < 0) ? "failed" : "ok");
        release_firmware(fw_entry);
        return rc;
 }
@@ -3873,29 +3868,27 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
                        break;
                default:
                        /* unknown...leave generic, but get serial # */
-                       printk(KERN_INFO "bttv%d: "
-                              "osprey eeprom: unknown card type 0x%04x\n",
-                              btv->c.nr, type);
+                       pr_info("%d: osprey eeprom: unknown card type 0x%04x\n",
+                               btv->c.nr, type);
                        break;
                }
                serial = get_unaligned_be32((__be32 *)(ee+6));
        }
 
-       printk(KERN_INFO "bttv%d: osprey eeprom: card=%d '%s' serial=%u\n",
-              btv->c.nr, cardid,
-              cardid>0 ? bttv_tvcards[cardid].name : "Unknown", serial);
+       pr_info("%d: osprey eeprom: card=%d '%s' serial=%u\n",
+               btv->c.nr, cardid,
+               cardid > 0 ? bttv_tvcards[cardid].name : "Unknown", serial);
 
        if (cardid<0 || btv->c.type == cardid)
                return;
 
        /* card type isn't set correctly */
        if (card[btv->c.nr] < bttv_num_tvcards) {
-               printk(KERN_WARNING "bttv%d: osprey eeprom: "
-                      "Not overriding user specified card type\n", btv->c.nr);
+               pr_warn("%d: osprey eeprom: Not overriding user specified card type\n",
+                       btv->c.nr);
        } else {
-               printk(KERN_INFO "bttv%d: osprey eeprom: "
-                      "Changing card type from %d to %d\n", btv->c.nr,
-                      btv->c.type, cardid);
+               pr_info("%d: osprey eeprom: Changing card type from %d to %d\n",
+                       btv->c.nr, btv->c.type, cardid);
                btv->c.type = cardid;
        }
 }
@@ -3938,14 +3931,14 @@ static void __devinit avermedia_eeprom(struct bttv *btv)
                if (tuner_format == 0x09)
                        tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */
 
-       printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=",
+       pr_info("%d: Avermedia eeprom[0x%02x%02x]: tuner=",
                btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]);
        if (tuner_type) {
                btv->tuner_type = tuner_type;
-               printk(KERN_CONT "%d", tuner_type);
+               pr_cont("%d", tuner_type);
        } else
-               printk(KERN_CONT "Unknown type");
-       printk(KERN_CONT " radio:%s remote control:%s\n",
+               pr_cont("Unknown type");
+       pr_cont(" radio:%s remote control:%s\n",
               tuner_tv_fm     ? "yes" : "no",
               btv->has_remote ? "yes" : "no");
 }
@@ -3993,8 +3986,8 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin)
        if (bttv_gpio)
                bttv_gpio_tracking(btv,"msp34xx");
        if (bttv_verbose)
-               printk(KERN_INFO "bttv%d: Hauppauge/Voodoo msp34xx: reset line "
-                      "init [%d]\n", btv->c.nr, pin);
+               pr_info("%d: Hauppauge/Voodoo msp34xx: reset line init [%d]\n",
+                       btv->c.nr, pin);
 }
 
 /* ----------------------------------------------------------------------- */
@@ -4034,7 +4027,7 @@ static void __devinit init_PXC200(struct bttv *btv)
        btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC);
 
        /*      Initialise MAX517 DAC */
-       printk(KERN_INFO "Setting DAC reference voltage level ...\n");
+       pr_info("Setting DAC reference voltage level ...\n");
        bttv_I2CWrite(btv,0x5E,0,0x80,1);
 
        /*      Initialise 12C508 PIC */
@@ -4043,7 +4036,7 @@ static void __devinit init_PXC200(struct bttv *btv)
         *      argument so the numbers are different */
 
 
-       printk(KERN_INFO "Initialising 12C508 PIC chip ...\n");
+       pr_info("Initialising 12C508 PIC chip ...\n");
 
        /* First of all, enable the clock line. This is used in the PXC200-F */
        val = btread(BT848_GPIO_DMA_CTL);
@@ -4062,13 +4055,12 @@ static void __devinit init_PXC200(struct bttv *btv)
        for (i = 0; i < ARRAY_SIZE(vals); i++) {
                tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1);
                if (tmp != -1) {
-                       printk(KERN_INFO
-                              "I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n",
+                       pr_info("I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n",
                               vals[i],tmp,bttv_I2CRead(btv,0x1F,NULL));
                }
        }
 
-       printk(KERN_INFO "PXC200 Initialised.\n");
+       pr_info("PXC200 Initialised\n");
 }
 
 
@@ -4107,8 +4099,7 @@ init_RTV24 (struct bttv *btv)
        uint32_t dataRead = 0;
        long watchdog_value = 0x0E;
 
-       printk (KERN_INFO
-               "bttv%d: Adlink RTV-24 initialisation in progress ...\n",
+       pr_info("%d: Adlink RTV-24 initialisation in progress ...\n",
                btv->c.nr);
 
        btwrite (0x00c3feff, BT848_GPIO_OUT_EN);
@@ -4122,8 +4113,7 @@ init_RTV24 (struct bttv *btv)
        dataRead = btread (BT848_GPIO_DATA);
 
        if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 1)) {
-               printk (KERN_INFO
-                       "bttv%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n",
+               pr_info("%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n",
                        btv->c.nr, dataRead);
        }
 
@@ -4136,15 +4126,13 @@ init_RTV24 (struct bttv *btv)
        dataRead = btread (BT848_GPIO_DATA);
 
        if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 0)) {
-               printk (KERN_INFO
-                       "bttv%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n",
+               pr_info("%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n",
                        btv->c.nr, dataRead);
 
                return;
        }
 
-       printk (KERN_INFO
-               "bttv%d: Adlink RTV-24 initialisation complete.\n", btv->c.nr);
+       pr_info("%d: Adlink RTV-24 initialisation complete\n", btv->c.nr);
 }
 
 
@@ -4261,22 +4249,25 @@ static int tea5757_read(struct bttv *btv)
        while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
                schedule();
        if (bus_in(btv,btv->mbox_data)) {
-               printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->c.nr);
+               pr_warn("%d: tea5757: read timeout\n", btv->c.nr);
                return -1;
        }
 
-       dprintk("bttv%d: tea5757:",btv->c.nr);
+       dprintk("%d: tea5757:", btv->c.nr);
        for (i = 0; i < 24; i++) {
                udelay(5);
                bus_high(btv,btv->mbox_clk);
                udelay(5);
-               dprintk("%c",(bus_in(btv,btv->mbox_most) == 0)?'T':'-');
+               dprintk_cont("%c",
+                            bus_in(btv, btv->mbox_most) == 0 ? 'T' : '-');
                bus_low(btv,btv->mbox_clk);
                value <<= 1;
                value |= (bus_in(btv,btv->mbox_data) == 0)?0:1;  /* MSB first */
-               dprintk("%c", (bus_in(btv,btv->mbox_most) == 0)?'S':'M');
+               dprintk_cont("%c",
+                            bus_in(btv, btv->mbox_most) == 0 ? 'S' : 'M');
        }
-       dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->c.nr, value);
+       dprintk_cont("\n");
+       dprintk("%d: tea5757: read 0x%X\n", btv->c.nr, value);
        return value;
 }
 
@@ -4295,7 +4286,7 @@ static int tea5757_write(struct bttv *btv, int value)
        if (bttv_gpio)
                bttv_gpio_tracking(btv,"tea5757 write");
 
-       dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value);
+       dprintk("%d: tea5757: write 0x%X\n", btv->c.nr, value);
        bus_low(btv,btv->mbox_clk);
        bus_high(btv,btv->mbox_we);
        for (i = 0; i < 25; i++) {
@@ -4547,7 +4538,7 @@ static void picolo_tetra_init(struct bttv *btv)
 static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input)
 {
 
-       dprintk (KERN_DEBUG "bttv%d : picolo_tetra_muxsel =>  input = %d\n",btv->c.nr,input);
+       dprintk("%d : picolo_tetra_muxsel =>  input = %d\n", btv->c.nr, input);
        /*Just set the right path in the analog multiplexers : channel 1 -> 4 ==> Analog Mux ==> MUX0*/
        /*GPIO[20]&GPIO[21] used to choose the right input*/
        btwrite (input<<20,BT848_GPIO_DATA);
@@ -4592,7 +4583,7 @@ static void ivc120_muxsel(struct bttv *btv, unsigned int input)
        int key = input % 4;
        int matrix = input / 4;
 
-       dprintk("bttv%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n",
+       dprintk("%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n",
                btv->c.nr, input, matrix, key);
 
        /* Handles the input selection on the TDA8540's */
@@ -4649,15 +4640,17 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input)
        buf[1]=0;
        rc=bttv_I2CWrite(btv,(PX_I2C_PIC<<1),buf[0],buf[1],1);
        if (rc) {
-         printk(KERN_DEBUG "bttv%d: PXC200_muxsel: pic cfg write failed:%d\n", btv->c.nr,rc);
+               pr_debug("%d: PXC200_muxsel: pic cfg write failed:%d\n",
+                        btv->c.nr, rc);
          /* not PXC ? do nothing */
-         return;
+               return;
        }
 
        rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL);
        if (!(rc & PX_CFG_PXC200F)) {
-         printk(KERN_DEBUG "bttv%d: PXC200_muxsel: not PXC200F rc:%d \n", btv->c.nr,rc);
-         return;
+               pr_debug("%d: PXC200_muxsel: not PXC200F rc:%d\n",
+                        btv->c.nr, rc);
+               return;
        }
 
 
@@ -4696,7 +4689,7 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input)
        else /* older device */
          btand(~BT848_IFORM_MUXSEL,BT848_IFORM);
 
-       printk(KERN_DEBUG "bttv%d: setting input channel to:%d\n", btv->c.nr,(int)mux);
+       pr_debug("%d: setting input channel to:%d\n", btv->c.nr, (int)mux);
 }
 
 static void phytec_muxsel(struct bttv *btv, unsigned int input)
@@ -4847,29 +4840,27 @@ void __init bttv_check_chipset(void)
 
        /* print warnings about any quirks found */
        if (triton1)
-               printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n");
+               pr_info("Host bridge needs ETBF enabled\n");
        if (vsfx)
-               printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n");
+               pr_info("Host bridge needs VSFX enabled\n");
        if (pcipci_fail) {
-               printk(KERN_INFO "bttv: bttv and your chipset may not work "
-                                                       "together.\n");
+               pr_info("bttv and your chipset may not work together\n");
                if (!no_overlay) {
-                       printk(KERN_INFO "bttv: overlay will be disabled.\n");
+                       pr_info("overlay will be disabled\n");
                        no_overlay = 1;
                } else {
-                       printk(KERN_INFO "bttv: overlay forced. Use this "
-                                               "option at your own risk.\n");
+                       pr_info("overlay forced. Use this option at your own risk.\n");
                }
        }
        if (UNSET != latency)
-               printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency);
+               pr_info("pci latency fixup [%d]\n", latency);
        while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                      PCI_DEVICE_ID_INTEL_82441, dev))) {
                unsigned char b;
                pci_read_config_byte(dev, 0x53, &b);
                if (bttv_debug)
-                       printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "
-                              "bufcon=0x%02x\n",b);
+                       pr_info("Host bridge: 82441FX Natoma, bufcon=0x%02x\n",
+                               b);
        }
 }
 
@@ -4882,12 +4873,13 @@ int __devinit bttv_handle_chipset(struct bttv *btv)
 
        if (bttv_verbose) {
                if (triton1)
-                       printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->c.nr);
+                       pr_info("%d: enabling ETBF (430FX/VP3 compatibility)\n",
+                               btv->c.nr);
                if (vsfx && btv->id >= 878)
-                       printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->c.nr);
+                       pr_info("%d: enabling VSFX\n", btv->c.nr);
                if (UNSET != latency)
-                       printk(KERN_INFO "bttv%d: setting pci timer to %d\n",
-                              btv->c.nr,latency);
+                       pr_info("%d: setting pci timer to %d\n",
+                               btv->c.nr, latency);
        }
 
        if (btv->id < 878) {
index 14444de..3dd0660 100644 (file)
@@ -34,6 +34,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -942,8 +944,8 @@ static
 void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)
 {
        if ((fh->resources & bits) != bits) {
-               /* trying to free ressources not allocated by us ... */
-               printk("bttv: BUG! (btres)\n");
+               /* trying to free resources not allocated by us ... */
+               pr_err("BUG! (btres)\n");
        }
        fh->resources  &= ~bits;
        btv->resources &= ~bits;
@@ -1000,7 +1002,7 @@ static void set_pll(struct bttv *btv)
                return;
 
        if (btv->pll.pll_ofreq == btv->pll.pll_current) {
-               dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
+               dprintk("%d: PLL: no change required\n", btv->c.nr);
                return;
        }
 
@@ -1008,21 +1010,23 @@ static void set_pll(struct bttv *btv)
                /* no PLL needed */
                if (btv->pll.pll_current == 0)
                        return;
-               bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
-                       btv->c.nr,btv->pll.pll_ifreq);
+               if (bttv_verbose)
+                       pr_info("%d: PLL can sleep, using XTAL (%d)\n",
+                               btv->c.nr, btv->pll.pll_ifreq);
                btwrite(0x00,BT848_TGCTRL);
                btwrite(0x00,BT848_PLL_XCI);
                btv->pll.pll_current = 0;
                return;
        }
 
-       bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
-               btv->pll.pll_ifreq, btv->pll.pll_ofreq);
+       if (bttv_verbose)
+               pr_info("%d: Setting PLL: %d => %d (needs up to 100ms)\n",
+                       btv->c.nr,
+                       btv->pll.pll_ifreq, btv->pll.pll_ofreq);
        set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
 
        for (i=0; i<10; i++) {
                /*  Let other people run while the PLL stabilizes */
-               bttv_printk(".");
                msleep(10);
 
                if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
@@ -1030,12 +1034,14 @@ static void set_pll(struct bttv *btv)
                } else {
                        btwrite(0x08,BT848_TGCTRL);
                        btv->pll.pll_current = btv->pll.pll_ofreq;
-                       bttv_printk(" ok\n");
+                       if (bttv_verbose)
+                               pr_info("PLL set ok\n");
                        return;
                }
        }
        btv->pll.pll_current = -1;
-       bttv_printk("failed\n");
+       if (bttv_verbose)
+               pr_info("Setting PLL failed\n");
        return;
 }
 
@@ -1047,7 +1053,7 @@ static void bt848A_set_timing(struct bttv *btv)
        int fsc       = bttv_tvnorms[btv->tvnorm].Fsc;
 
        if (btv->input == btv->dig) {
-               dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
+               dprintk("%d: load digital timing table (table_idx=%d)\n",
                        btv->c.nr,table_idx);
 
                /* timing change...reset timing generator address */
@@ -1076,7 +1082,7 @@ static void bt848_bright(struct bttv *btv, int bright)
 {
        int value;
 
-       // printk("bttv: set bright: %d\n",bright); // DEBUG
+       // printk("set bright: %d\n", bright); // DEBUG
        btv->bright = bright;
 
        /* We want -128 to 127 we get 0-65535 */
@@ -1150,8 +1156,7 @@ video_mux(struct bttv *btv, unsigned int input)
        }
        mux = bttv_muxsel(btv, input);
        btaor(mux<<5, ~(3<<5), BT848_IFORM);
-       dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
-               btv->c.nr,input,mux);
+       dprintk("%d: video mux: input=%d mux=%d\n", btv->c.nr, input, mux);
 
        /* card specific hook */
        if(bttv_tvcards[btv->c.type].muxsel_hook)
@@ -1440,7 +1445,7 @@ static void bttv_reinit_bt848(struct bttv *btv)
        unsigned long flags;
 
        if (bttv_verbose)
-               printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
+               pr_info("%d: reset, reinitialize\n", btv->c.nr);
        spin_lock_irqsave(&btv->s_lock,flags);
        btv->errors=0;
        bttv_set_dma(btv,0);
@@ -1622,8 +1627,8 @@ void bttv_gpio_tracking(struct bttv *btv, char *comment)
        unsigned int outbits, data;
        outbits = btread(BT848_GPIO_OUT_EN);
        data    = btread(BT848_GPIO_DATA);
-       printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
-              btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
+       pr_debug("%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
+                btv->c.nr, outbits, data & outbits, data & ~outbits, comment);
 }
 
 static void bttv_field_count(struct bttv *btv)
@@ -1668,7 +1673,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
        unsigned long flags;
        int retval = 0;
 
-       dprintk("switch_overlay: enter [new=%p]\n",new);
+       dprintk("switch_overlay: enter [new=%p]\n", new);
        if (new)
                new->vb.state = VIDEOBUF_DONE;
        spin_lock_irqsave(&btv->s_lock,flags);
@@ -1678,7 +1683,8 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
        bttv_set_dma(btv, 0x03);
        spin_unlock_irqrestore(&btv->s_lock,flags);
        if (NULL != old) {
-               dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
+               dprintk("switch_overlay: old=%p state is %d\n",
+                       old, old->vb.state);
                bttv_dma_free(&fh->cap,btv, old);
                kfree(old);
        }
@@ -2029,11 +2035,11 @@ static int bttv_log_status(struct file *file, void *f)
        struct bttv_fh *fh  = f;
        struct bttv *btv = fh->btv;
 
-       printk(KERN_INFO "bttv%d: ========  START STATUS CARD #%d  ========\n",
-                       btv->c.nr, btv->c.nr);
+       pr_info("%d: ========  START STATUS CARD #%d  ========\n",
+               btv->c.nr, btv->c.nr);
        bttv_call_all(btv, core, log_status);
-       printk(KERN_INFO "bttv%d: ========  END STATUS CARD   #%d  ========\n",
-                       btv->c.nr, btv->c.nr);
+       pr_info("%d: ========  END STATUS CARD   #%d  ========\n",
+               btv->c.nr, btv->c.nr);
        return 0;
 }
 
@@ -2598,7 +2604,7 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
        struct bttv *btv = fh->btv;
 
        if (no_overlay > 0) {
-               printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+               pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
                return -EINVAL;
        }
 
@@ -2673,7 +2679,7 @@ static int bttv_enum_fmt_vid_overlay(struct file *file, void  *priv,
        int rc;
 
        if (no_overlay > 0) {
-               printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+               pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
                return -EINVAL;
        }
 
@@ -2714,7 +2720,7 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
                        return -EINVAL;
                }
                if (unlikely(!fh->ov.setup_ok)) {
-                       dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);
+                       dprintk("%d: overlay: !setup_ok\n", btv->c.nr);
                        retval = -EINVAL;
                }
                if (retval)
@@ -3091,8 +3097,8 @@ static ssize_t bttv_read(struct file *file, char __user *data,
 
        if (fh->btv->errors)
                bttv_reinit_bt848(fh->btv);
-       dprintk("bttv%d: read count=%d type=%s\n",
-               fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
+       dprintk("%d: read count=%d type=%s\n",
+               fh->btv->c.nr, (int)count, v4l2_type_names[fh->type]);
 
        switch (fh->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -3174,7 +3180,7 @@ static int bttv_open(struct file *file)
        struct bttv_fh *fh;
        enum v4l2_buf_type type = 0;
 
-       dprintk(KERN_DEBUG "bttv: open dev=%s\n", video_device_node_name(vdev));
+       dprintk("open dev=%s\n", video_device_node_name(vdev));
 
        if (vdev->vfl_type == VFL_TYPE_GRABBER) {
                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -3185,8 +3191,8 @@ static int bttv_open(struct file *file)
                return -ENODEV;
        }
 
-       dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
-               btv->c.nr,v4l2_type_names[type]);
+       dprintk("%d: open called (type=%s)\n",
+               btv->c.nr, v4l2_type_names[type]);
 
        /* allocate per filehandle data */
        fh = kmalloc(sizeof(*fh), GFP_KERNEL);
@@ -3288,7 +3294,7 @@ bttv_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct bttv_fh *fh = file->private_data;
 
-       dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
+       dprintk("%d: mmap type=%s 0x%lx+%ld\n",
                fh->btv->c.nr, v4l2_type_names[fh->type],
                vma->vm_start, vma->vm_end - vma->vm_start);
        return videobuf_mmap_mapper(bttv_queue(fh),vma);
@@ -3370,9 +3376,9 @@ static int radio_open(struct file *file)
        struct bttv *btv = video_drvdata(file);
        struct bttv_fh *fh;
 
-       dprintk("bttv: open dev=%s\n", video_device_node_name(vdev));
+       dprintk("open dev=%s\n", video_device_node_name(vdev));
 
-       dprintk("bttv%d: open called (radio)\n",btv->c.nr);
+       dprintk("%d: open called (radio)\n", btv->c.nr);
 
        /* allocate per filehandle data */
        fh = kmalloc(sizeof(*fh), GFP_KERNEL);
@@ -3616,12 +3622,12 @@ static int bttv_risc_decode(u32 risc)
        };
        int i;
 
-       printk("0x%08x [ %s", risc,
+       pr_cont("0x%08x [ %s", risc,
               instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
        for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
                if (risc & (1 << (i + 12)))
-                       printk(" %s",bits[i]);
-       printk(" count=%d ]\n", risc & 0xfff);
+                       pr_cont(" %s", bits[i]);
+       pr_cont(" count=%d ]\n", risc & 0xfff);
        return incr[risc >> 28] ? incr[risc >> 28] : 1;
 }
 
@@ -3630,16 +3636,18 @@ static void bttv_risc_disasm(struct bttv *btv,
 {
        unsigned int i,j,n;
 
-       printk("%s: risc disasm: %p [dma=0x%08lx]\n",
-              btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma);
+       pr_info("%s: risc disasm: %p [dma=0x%08lx]\n",
+               btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma);
        for (i = 0; i < (risc->size >> 2); i += n) {
-               printk("%s:   0x%lx: ", btv->c.v4l2_dev.name,
-                      (unsigned long)(risc->dma + (i<<2)));
+               pr_info("%s:   0x%lx: ",
+                       btv->c.v4l2_dev.name,
+                       (unsigned long)(risc->dma + (i<<2)));
                n = bttv_risc_decode(le32_to_cpu(risc->cpu[i]));
                for (j = 1; j < n; j++)
-                       printk("%s:   0x%lx: 0x%08x [ arg #%d ]\n",
-                              btv->c.v4l2_dev.name, (unsigned long)(risc->dma + ((i+j)<<2)),
-                              risc->cpu[i+j], j);
+                       pr_info("%s:   0x%lx: 0x%08x [ arg #%d ]\n",
+                               btv->c.v4l2_dev.name,
+                               (unsigned long)(risc->dma + ((i+j)<<2)),
+                               risc->cpu[i+j], j);
                if (0 == risc->cpu[i])
                        break;
        }
@@ -3647,17 +3655,18 @@ static void bttv_risc_disasm(struct bttv *btv,
 
 static void bttv_print_riscaddr(struct bttv *btv)
 {
-       printk("  main: %08Lx\n",
-              (unsigned long long)btv->main.dma);
-       printk("  vbi : o=%08Lx e=%08Lx\n",
-              btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
-              btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
-       printk("  cap : o=%08Lx e=%08Lx\n",
-              btv->curr.top    ? (unsigned long long)btv->curr.top->top.dma : 0,
-              btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
-       printk("  scr : o=%08Lx e=%08Lx\n",
-              btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
-              btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
+       pr_info("  main: %08llx\n", (unsigned long long)btv->main.dma);
+       pr_info("  vbi : o=%08llx e=%08llx\n",
+               btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
+               btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
+       pr_info("  cap : o=%08llx e=%08llx\n",
+               btv->curr.top
+               ? (unsigned long long)btv->curr.top->top.dma : 0,
+               btv->curr.bottom
+               ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
+       pr_info("  scr : o=%08llx e=%08llx\n",
+               btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
+               btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
        bttv_risc_disasm(btv, &btv->main);
 }
 
@@ -3690,34 +3699,34 @@ static void bttv_print_irqbits(u32 print, u32 mark)
 {
        unsigned int i;
 
-       printk("bits:");
+       pr_cont("bits:");
        for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
                if (print & (1 << i))
-                       printk(" %s",irq_name[i]);
+                       pr_cont(" %s", irq_name[i]);
                if (mark & (1 << i))
-                       printk("*");
+                       pr_cont("*");
        }
 }
 
 static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
 {
-       printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
-              btv->c.nr,
-              (unsigned long)btv->main.dma,
-              (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]),
-              (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]),
-              (unsigned long)rc);
+       pr_warn("%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
+               btv->c.nr,
+               (unsigned long)btv->main.dma,
+               (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]),
+               (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]),
+               (unsigned long)rc);
 
        if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
-               printk("bttv%d: Oh, there (temporarely?) is no input signal. "
-                      "Ok, then this is harmless, don't worry ;)\n",
-                      btv->c.nr);
+               pr_notice("%d: Oh, there (temporarily?) is no input signal. "
+                         "Ok, then this is harmless, don't worry ;)\n",
+                         btv->c.nr);
                return;
        }
-       printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
-              btv->c.nr);
-       printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
-              btv->c.nr);
+       pr_notice("%d: Uhm. Looks like we have unusual high IRQ latencies\n",
+                 btv->c.nr);
+       pr_notice("%d: Lets try to catch the culpit red-handed ...\n",
+                 btv->c.nr);
        dump_stack();
 }
 
@@ -3798,9 +3807,9 @@ bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
                }
        }
 
-       dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
-               btv->c.nr,set->top, set->bottom,
-               btv->screen,set->frame_irq,set->top_irq);
+       dprintk("%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
+               btv->c.nr, set->top, set->bottom,
+               btv->screen, set->frame_irq, set->top_irq);
        return 0;
 }
 
@@ -3815,7 +3824,8 @@ bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
        if (wakeup->top == wakeup->bottom) {
                if (NULL != wakeup->top && curr->top != wakeup->top) {
                        if (irq_debug > 1)
-                               printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
+                               pr_debug("%d: wakeup: both=%p\n",
+                                        btv->c.nr, wakeup->top);
                        wakeup->top->vb.ts = ts;
                        wakeup->top->vb.field_count = btv->field_count;
                        wakeup->top->vb.state = state;
@@ -3824,7 +3834,8 @@ bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
        } else {
                if (NULL != wakeup->top && curr->top != wakeup->top) {
                        if (irq_debug > 1)
-                               printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
+                               pr_debug("%d: wakeup: top=%p\n",
+                                        btv->c.nr, wakeup->top);
                        wakeup->top->vb.ts = ts;
                        wakeup->top->vb.field_count = btv->field_count;
                        wakeup->top->vb.state = state;
@@ -3832,7 +3843,8 @@ bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
                }
                if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
                        if (irq_debug > 1)
-                               printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
+                               pr_debug("%d: wakeup: bottom=%p\n",
+                                        btv->c.nr, wakeup->bottom);
                        wakeup->bottom->vb.ts = ts;
                        wakeup->bottom->vb.field_count = btv->field_count;
                        wakeup->bottom->vb.state = state;
@@ -3866,11 +3878,11 @@ static void bttv_irq_timeout(unsigned long data)
        unsigned long flags;
 
        if (bttv_verbose) {
-               printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
-                      btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
-                      btread(BT848_RISC_COUNT));
+               pr_info("%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
+                       btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
+                       btread(BT848_RISC_COUNT));
                bttv_print_irqbits(btread(BT848_INT_STAT),0);
-               printk("\n");
+               pr_cont("\n");
        }
 
        spin_lock_irqsave(&btv->s_lock,flags);
@@ -4033,21 +4045,23 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
                dstat=btread(BT848_DSTATUS);
 
                if (irq_debug) {
-                       printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
-                              "riscs=%x, riscc=%08x, ",
-                              btv->c.nr, count, btv->field_count,
-                              stat>>28, btread(BT848_RISC_COUNT));
+                       pr_debug("%d: irq loop=%d fc=%d riscs=%x, riscc=%08x, ",
+                                btv->c.nr, count, btv->field_count,
+                                stat>>28, btread(BT848_RISC_COUNT));
                        bttv_print_irqbits(stat,astat);
                        if (stat & BT848_INT_HLOCK)
-                               printk("   HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
-                                      ? "yes" : "no");
+                               pr_cont("   HLOC => %s",
+                                       dstat & BT848_DSTATUS_HLOC
+                                       ? "yes" : "no");
                        if (stat & BT848_INT_VPRES)
-                               printk("   PRES => %s", (dstat & BT848_DSTATUS_PRES)
-                                      ? "yes" : "no");
+                               pr_cont("   PRES => %s",
+                                       dstat & BT848_DSTATUS_PRES
+                                       ? "yes" : "no");
                        if (stat & BT848_INT_FMTCHG)
-                               printk("   NUML => %s", (dstat & BT848_DSTATUS_NUML)
-                                      ? "625" : "525");
-                       printk("\n");
+                               pr_cont("   NUML => %s",
+                                       dstat & BT848_DSTATUS_NUML
+                                       ? "625" : "525");
+                       pr_cont("\n");
                }
 
                if (astat&BT848_INT_VSYNC)
@@ -4075,18 +4089,19 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
                        audio_mute(btv, btv->mute);  /* trigger automute */
 
                if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
-                       printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
-                              (astat & BT848_INT_SCERR) ? "SCERR" : "",
-                              (astat & BT848_INT_OCERR) ? "OCERR" : "",
-                              btread(BT848_RISC_COUNT));
+                       pr_info("%d: %s%s @ %08x,",
+                               btv->c.nr,
+                               (astat & BT848_INT_SCERR) ? "SCERR" : "",
+                               (astat & BT848_INT_OCERR) ? "OCERR" : "",
+                               btread(BT848_RISC_COUNT));
                        bttv_print_irqbits(stat,astat);
-                       printk("\n");
+                       pr_cont("\n");
                        if (bttv_debug)
                                bttv_print_riscaddr(btv);
                }
                if (fdsr && astat & BT848_INT_FDSR) {
-                       printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
-                              btv->c.nr,btread(BT848_RISC_COUNT));
+                       pr_info("%d: FDSR @ %08x\n",
+                               btv->c.nr, btread(BT848_RISC_COUNT));
                        if (bttv_debug)
                                bttv_print_riscaddr(btv);
                }
@@ -4097,11 +4112,11 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
                        if (count > 8 || !(astat & BT848_INT_GPINT)) {
                                btwrite(0, BT848_INT_MASK);
 
-                               printk(KERN_ERR
-                                          "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
+                               pr_err("%d: IRQ lockup, cleared int mask [",
+                                      btv->c.nr);
                        } else {
-                               printk(KERN_ERR
-                                          "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
+                               pr_err("%d: IRQ lockup, clearing GPINT from int mask [",
+                                      btv->c.nr);
 
                                btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
                                                BT848_INT_MASK);
@@ -4109,7 +4124,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
 
                        bttv_print_irqbits(stat,astat);
 
-                       printk("]\n");
+                       pr_cont("]\n");
                }
        }
        btv->irq_total++;
@@ -4171,7 +4186,7 @@ static void bttv_unregister_video(struct bttv *btv)
 static int __devinit bttv_register_video(struct bttv *btv)
 {
        if (no_overlay > 0)
-               printk("bttv: Overlay support disabled.\n");
+               pr_notice("Overlay support disabled\n");
 
        /* video */
        btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
@@ -4181,12 +4196,11 @@ static int __devinit bttv_register_video(struct bttv *btv)
        if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER,
                                  video_nr[btv->c.nr]) < 0)
                goto err;
-       printk(KERN_INFO "bttv%d: registered device %s\n",
-              btv->c.nr, video_device_node_name(btv->video_dev));
+       pr_info("%d: registered device %s\n",
+               btv->c.nr, video_device_node_name(btv->video_dev));
        if (device_create_file(&btv->video_dev->dev,
                                     &dev_attr_card)<0) {
-               printk(KERN_ERR "bttv%d: device_create_file 'card' "
-                      "failed\n", btv->c.nr);
+               pr_err("%d: device_create_file 'card' failed\n", btv->c.nr);
                goto err;
        }
 
@@ -4198,8 +4212,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
        if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI,
                                  vbi_nr[btv->c.nr]) < 0)
                goto err;
-       printk(KERN_INFO "bttv%d: registered device %s\n",
-              btv->c.nr, video_device_node_name(btv->vbi_dev));
+       pr_info("%d: registered device %s\n",
+               btv->c.nr, video_device_node_name(btv->vbi_dev));
 
        if (!btv->has_radio)
                return 0;
@@ -4210,8 +4224,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
        if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,
                                  radio_nr[btv->c.nr]) < 0)
                goto err;
-       printk(KERN_INFO "bttv%d: registered device %s\n",
-              btv->c.nr, video_device_node_name(btv->radio_dev));
+       pr_info("%d: registered device %s\n",
+               btv->c.nr, video_device_node_name(btv->radio_dev));
 
        /* all done */
        return 0;
@@ -4244,10 +4258,10 @@ static int __devinit bttv_probe(struct pci_dev *dev,
 
        if (bttv_num == BTTV_MAX)
                return -ENOMEM;
-       printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
+       pr_info("Bt8xx card found (%d)\n", bttv_num);
        bttvs[bttv_num] = btv = kzalloc(sizeof(*btv), GFP_KERNEL);
        if (btv == NULL) {
-               printk(KERN_ERR "bttv: out of memory.\n");
+               pr_err("out of memory\n");
                return -ENOMEM;
        }
        btv->c.nr  = bttv_num;
@@ -4277,21 +4291,19 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        btv->c.pci = dev;
        btv->id  = dev->device;
        if (pci_enable_device(dev)) {
-               printk(KERN_WARNING "bttv%d: Can't enable device.\n",
-                      btv->c.nr);
+               pr_warn("%d: Can't enable device\n", btv->c.nr);
                return -EIO;
        }
        if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) {
-               printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
-                      btv->c.nr);
+               pr_warn("%d: No suitable DMA available\n", btv->c.nr);
                return -EIO;
        }
        if (!request_mem_region(pci_resource_start(dev,0),
                                pci_resource_len(dev,0),
                                btv->c.v4l2_dev.name)) {
-               printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
-                      btv->c.nr,
-                      (unsigned long long)pci_resource_start(dev,0));
+               pr_warn("%d: can't request iomem (0x%llx)\n",
+                       btv->c.nr,
+                       (unsigned long long)pci_resource_start(dev, 0));
                return -EBUSY;
        }
        pci_set_master(dev);
@@ -4299,22 +4311,21 @@ static int __devinit bttv_probe(struct pci_dev *dev,
 
        result = v4l2_device_register(&dev->dev, &btv->c.v4l2_dev);
        if (result < 0) {
-               printk(KERN_WARNING "bttv%d: v4l2_device_register() failed\n", btv->c.nr);
+               pr_warn("%d: v4l2_device_register() failed\n", btv->c.nr);
                goto fail0;
        }
 
        btv->revision = dev->revision;
        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-       printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
-              bttv_num,btv->id, btv->revision, pci_name(dev));
-       printk("irq: %d, latency: %d, mmio: 0x%llx\n",
-              btv->c.pci->irq, lat,
-              (unsigned long long)pci_resource_start(dev,0));
+       pr_info("%d: Bt%d (rev %d) at %s, irq: %d, latency: %d, mmio: 0x%llx\n",
+               bttv_num, btv->id, btv->revision, pci_name(dev),
+               btv->c.pci->irq, lat,
+               (unsigned long long)pci_resource_start(dev, 0));
        schedule();
 
        btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
        if (NULL == btv->bt848_mmio) {
-               printk("bttv%d: ioremap() failed\n", btv->c.nr);
+               pr_err("%d: ioremap() failed\n", btv->c.nr);
                result = -EIO;
                goto fail1;
        }
@@ -4327,8 +4338,8 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        result = request_irq(btv->c.pci->irq, bttv_irq,
            IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv);
        if (result < 0) {
-               printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
-                      bttv_num,btv->c.pci->irq);
+               pr_err("%d: can't get IRQ %d\n",
+                      bttv_num, btv->c.pci->irq);
                goto fail1;
        }
 
@@ -4433,7 +4444,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
        struct bttv *btv = to_bttv(v4l2_dev);
 
        if (bttv_verbose)
-               printk("bttv%d: unloading\n",btv->c.nr);
+               pr_info("%d: unloading\n", btv->c.nr);
 
        if (bttv_tvcards[btv->c.type].has_dvb)
                flush_request_modules(btv);
@@ -4481,7 +4492,7 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
        struct bttv_buffer_set idle;
        unsigned long flags;
 
-       dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
+       dprintk("%d: suspend %d\n", btv->c.nr, state.event);
 
        /* stop dma + irqs */
        spin_lock_irqsave(&btv->s_lock,flags);
@@ -4517,14 +4528,13 @@ static int bttv_resume(struct pci_dev *pci_dev)
        unsigned long flags;
        int err;
 
-       dprintk("bttv%d: resume\n", btv->c.nr);
+       dprintk("%d: resume\n", btv->c.nr);
 
        /* restore pci state */
        if (btv->state.disabled) {
                err=pci_enable_device(pci_dev);
                if (err) {
-                       printk(KERN_WARNING "bttv%d: Can't enable device.\n",
-                                                               btv->c.nr);
+                       pr_warn("%d: Can't enable device\n", btv->c.nr);
                        return err;
                }
                btv->state.disabled = 0;
@@ -4532,8 +4542,7 @@ static int bttv_resume(struct pci_dev *pci_dev)
        err=pci_set_power_state(pci_dev, PCI_D0);
        if (err) {
                pci_disable_device(pci_dev);
-               printk(KERN_WARNING "bttv%d: Can't enable device.\n",
-                                                       btv->c.nr);
+               pr_warn("%d: Can't enable device\n", btv->c.nr);
                btv->state.disabled = 1;
                return err;
        }
@@ -4585,22 +4594,21 @@ static int __init bttv_init_module(void)
 
        bttv_num = 0;
 
-       printk(KERN_INFO "bttv: driver version %s loaded\n",
-              BTTV_VERSION);
+       pr_info("driver version %s loaded\n", BTTV_VERSION);
        if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
                gbuffers = 2;
        if (gbufsize > BTTV_MAX_FBUF)
                gbufsize = BTTV_MAX_FBUF;
        gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
        if (bttv_verbose)
-               printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
-                      gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
+               pr_info("using %d buffers with %dk (%d pages) each for capture\n",
+                       gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
 
        bttv_check_chipset();
 
        ret = bus_register(&bttv_sub_bus_type);
        if (ret < 0) {
-               printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
+               pr_warn("bus_register error: %d\n", ret);
                return ret;
        }
        ret = pci_register_driver(&bttv_pci_driver);
index 13ce72c..922e823 100644 (file)
@@ -26,6 +26,8 @@
 
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -99,7 +101,7 @@ int bttv_sub_add_device(struct bttv_core *core, char *name)
                kfree(sub);
                return err;
        }
-       printk("bttv%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev));
+       pr_info("%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev));
        list_add_tail(&sub->list,&core->subs);
        return 0;
 }
index d49b675..e3952af 100644 (file)
@@ -27,6 +27,8 @@
 
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -154,9 +156,7 @@ bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
        if (retval == 0)
                goto eio;
        if (i2c_debug) {
-               printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
-               if (!(xmit & BT878_I2C_NOSTOP))
-                       printk(" >\n");
+               pr_cont(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
        }
 
        for (cnt = 1; cnt < msg->len; cnt++ ) {
@@ -170,19 +170,18 @@ bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
                        goto err;
                if (retval == 0)
                        goto eio;
-               if (i2c_debug) {
-                       printk(" %02x", msg->buf[cnt]);
-                       if (!(xmit & BT878_I2C_NOSTOP))
-                               printk(" >\n");
-               }
+               if (i2c_debug)
+                       pr_cont(" %02x", msg->buf[cnt]);
        }
+       if (!(xmit & BT878_I2C_NOSTOP))
+               pr_cont(">\n");
        return msg->len;
 
  eio:
        retval = -EIO;
  err:
        if (i2c_debug)
-               printk(" ERR: %d\n",retval);
+               pr_cont(" ERR: %d\n",retval);
        return retval;
 }
 
@@ -193,7 +192,7 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
        u32 cnt;
        int retval;
 
-       for(cnt = 0; cnt < msg->len; cnt++) {
+       for (cnt = 0; cnt < msg->len; cnt++) {
                xmit = (msg->addr << 25) | (1 << 24) | I2C_HW;
                if (cnt < msg->len-1)
                        xmit |= BT848_I2C_W3B;
@@ -201,6 +200,12 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
                        xmit |= BT878_I2C_NOSTOP;
                if (cnt)
                        xmit |= BT878_I2C_NOSTART;
+
+               if (i2c_debug) {
+                       if (!(xmit & BT878_I2C_NOSTART))
+                               pr_cont(" <R %02x", (msg->addr << 1) +1);
+               }
+
                btwrite(xmit, BT848_I2C);
                retval = bttv_i2c_wait_done(btv);
                if (retval < 0)
@@ -209,20 +214,20 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
                        goto eio;
                msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff;
                if (i2c_debug) {
-                       if (!(xmit & BT878_I2C_NOSTART))
-                               printk(" <R %02x", (msg->addr << 1) +1);
-                       printk(" =%02x", msg->buf[cnt]);
-                       if (!(xmit & BT878_I2C_NOSTOP))
-                               printk(" >\n");
+                       pr_cont(" =%02x", msg->buf[cnt]);
                }
+               if (i2c_debug && !(xmit & BT878_I2C_NOSTOP))
+                       pr_cont(" >\n");
        }
+
+
        return msg->len;
 
  eio:
        retval = -EIO;
  err:
        if (i2c_debug)
-               printk(" ERR: %d\n",retval);
+               pr_cont(" ERR: %d\n",retval);
        return retval;
 }
 
@@ -234,7 +239,8 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int
        int i;
 
        if (i2c_debug)
-               printk("bt-i2c:");
+               pr_debug("bt-i2c:");
+
        btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT);
        for (i = 0 ; i < num; i++) {
                if (msgs[i].flags & I2C_M_RD) {
@@ -271,20 +277,20 @@ int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
        if (0 != btv->i2c_rc)
                return -1;
        if (bttv_verbose && NULL != probe_for)
-               printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
-                      btv->c.nr,probe_for,addr);
+               pr_info("%d: i2c: checking for %s @ 0x%02x... ",
+                       btv->c.nr, probe_for, addr);
        btv->i2c_client.addr = addr >> 1;
        if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
                if (NULL != probe_for) {
                        if (bttv_verbose)
-                               printk("not found\n");
+                               pr_cont("not found\n");
                } else
-                       printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n",
-                              btv->c.nr,addr);
+                       pr_warn("%d: i2c read 0x%x: error\n",
+                               btv->c.nr, addr);
                return -1;
        }
        if (bttv_verbose && NULL != probe_for)
-               printk("found\n");
+               pr_cont("found\n");
        return buffer;
 }
 
@@ -335,8 +341,8 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
                rc = i2c_master_recv(c,&buf,0);
                if (rc < 0)
                        continue;
-               printk("%s: i2c scan: found device @ 0x%x  [%s]\n",
-                      name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+               pr_info("%s: i2c scan: found device @ 0x%x  [%s]\n",
+                       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
        }
 }
 
index 677d70c..ef4c7cd 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -36,9 +38,10 @@ static int ir_rc5_remote_gap = 885;
 module_param(ir_rc5_remote_gap, int, 0644);
 
 #undef dprintk
-#define dprintk(arg...) do {   \
-       if (ir_debug >= 1)      \
-               printk(arg);    \
+#define dprintk(fmt, ...)                      \
+do {                                           \
+       if (ir_debug >= 1)                      \
+               pr_info(fmt, ##__VA_ARGS__);    \
 } while (0)
 
 #define DEVNAME "bttv-input"
@@ -62,7 +65,7 @@ static void ir_handle_key(struct bttv *btv)
 
        /* extract data */
        data = ir_extract_bits(gpio, ir->mask_keycode);
-       dprintk(KERN_INFO DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n",
+       dprintk("irq gpio=0x%x code=%d | %s%s%s\n",
                gpio, data,
                ir->polling               ? "poll"  : "irq",
                (gpio & ir->mask_keydown) ? " down" : "",
@@ -96,7 +99,7 @@ static void ir_enltv_handle_key(struct bttv *btv)
        keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0;
 
        if ((ir->last_gpio & 0x7f) != data) {
-               dprintk(KERN_INFO DEVNAME ": gpio=0x%x code=%d | %s\n",
+               dprintk("gpio=0x%x code=%d | %s\n",
                        gpio, data,
                        (gpio & ir->mask_keyup) ? " up" : "up/down");
 
@@ -107,7 +110,7 @@ static void ir_enltv_handle_key(struct bttv *btv)
                if ((ir->last_gpio & 1 << 31) == keyup)
                        return;
 
-               dprintk(KERN_INFO DEVNAME ":(cnt) gpio=0x%x code=%d | %s\n",
+               dprintk("(cnt) gpio=0x%x code=%d | %s\n",
                        gpio, data,
                        (gpio & ir->mask_keyup) ? " up" : "down");
 
@@ -177,13 +180,12 @@ static u32 bttv_rc5_decode(unsigned int code)
                        rc5 |= 1;
                break;
                case 3:
-                       dprintk(KERN_INFO DEVNAME ":rc5_decode(%x) bad code\n",
+                       dprintk("rc5_decode(%x) bad code\n",
                                org_code);
                        return 0;
                }
        }
-       dprintk(KERN_INFO DEVNAME ":"
-               "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+       dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
                "instr=%x\n", rc5, org_code, RC5_START(rc5),
                RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
        return rc5;
@@ -212,20 +214,20 @@ static void bttv_rc5_timer_end(unsigned long data)
 
        /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */
        if (gap < 28000) {
-               dprintk(KERN_INFO DEVNAME ": spurious timer_end\n");
+               dprintk("spurious timer_end\n");
                return;
        }
 
        if (ir->last_bit < 20) {
                /* ignore spurious codes (caused by light/other remotes) */
-               dprintk(KERN_INFO DEVNAME ": short code: %x\n", ir->code);
+               dprintk("short code: %x\n", ir->code);
        } else {
                ir->code = (ir->code << ir->shift_by) | 1;
                rc5 = bttv_rc5_decode(ir->code);
 
                /* two start bits? */
                if (RC5_START(rc5) != ir->start) {
-                       printk(KERN_INFO DEVNAME ":"
+                       pr_info(DEVNAME ":"
                               " rc5 start bits invalid: %u\n", RC5_START(rc5));
 
                        /* right address? */
@@ -235,8 +237,7 @@ static void bttv_rc5_timer_end(unsigned long data)
 
                        /* Good code */
                        rc_keydown(ir->dev, instr, toggle);
-                       dprintk(KERN_INFO DEVNAME ":"
-                               " instruction %x, toggle %x\n",
+                       dprintk("instruction %x, toggle %x\n",
                                instr, toggle);
                }
        }
@@ -265,7 +266,7 @@ static int bttv_rc5_irq(struct bttv *btv)
                    tv.tv_usec - ir->base_time.tv_usec;
        }
 
-       dprintk(KERN_INFO DEVNAME ": RC5 IRQ: gap %d us for %s\n",
+       dprintk("RC5 IRQ: gap %d us for %s\n",
                gap, (gpio & 0x20) ? "mark" : "space");
 
        /* remote IRQ? */
@@ -340,14 +341,14 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 
        /* poll IR chip */
        if (1 != i2c_master_recv(ir->c, &b, 1)) {
-               dprintk(KERN_INFO DEVNAME ": read error\n");
+               dprintk("read error\n");
                return -EIO;
        }
 
        /* ignore 0xaa */
        if (b==0xaa)
                return 0;
-       dprintk(KERN_INFO DEVNAME ": key %02x\n", b);
+       dprintk("key %02x\n", b);
 
        /*
         * NOTE:
@@ -517,7 +518,7 @@ int bttv_input_init(struct bttv *btv)
                break;
        }
        if (NULL == ir_codes) {
-               dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type);
+               dprintk("Ooops: IR config error [card=%d]\n", btv->c.type);
                err = -ENODEV;
                goto err_out_free;
        }
index 9b57d09..82cc47d 100644 (file)
@@ -24,6 +24,8 @@
 
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -473,8 +475,7 @@ bttv_set_dma(struct bttv *btv, int override)
        capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00;  /* vbi data */
        capctl |= override;
 
-       d2printk(KERN_DEBUG
-                "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
+       d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n",
                 btv->c.nr,capctl,btv->loop_irq,
                 btv->cvbi         ? (unsigned long long)btv->cvbi->top.dma            : 0,
                 btv->curr.top     ? (unsigned long long)btv->curr.top->top.dma        : 0,
@@ -517,8 +518,8 @@ bttv_risc_init_main(struct bttv *btv)
 
        if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
                return rc;
-       dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
-               btv->c.nr,(unsigned long long)btv->main.dma);
+       dprintk("%d: risc main @ %08llx\n",
+               btv->c.nr, (unsigned long long)btv->main.dma);
 
        btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
                                       BT848_FIFO_STATUS_VRE);
@@ -557,12 +558,12 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
        unsigned long next = btv->main.dma + ((slot+2) << 2);
 
        if (NULL == risc) {
-               d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n",
-                        btv->c.nr,risc,slot);
+               d2printk("%d: risc=%p slot[%d]=NULL\n", btv->c.nr, risc, slot);
                btv->main.cpu[slot+1] = cpu_to_le32(next);
        } else {
-               d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
-                        btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags);
+               d2printk("%d: risc=%p slot[%d]=%08llx irq=%d\n",
+                        btv->c.nr, risc, slot,
+                        (unsigned long long)risc->dma, irqflags);
                cmd = BT848_RISC_JUMP;
                if (irqflags) {
                        cmd |= BT848_RISC_IRQ;
@@ -708,8 +709,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
        const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
        struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
-       dprintk(KERN_DEBUG
-               "bttv%d: buffer field: %s  format: %s  size: %dx%d\n",
+       dprintk("%d: buffer field: %s  format: %s  size: %dx%d\n",
                btv->c.nr, v4l2_field_names[buf->vb.field],
                buf->fmt->name, buf->vb.width, buf->vb.height);
 
@@ -870,10 +870,9 @@ bttv_overlay_risc(struct bttv *btv,
                  struct bttv_buffer *buf)
 {
        /* check interleave, bottom+top fields */
-       dprintk(KERN_DEBUG
-               "bttv%d: overlay fields: %s format: %s  size: %dx%d\n",
+       dprintk("%d: overlay fields: %s format: %s  size: %dx%d\n",
                btv->c.nr, v4l2_field_names[buf->vb.field],
-               fmt->name,ov->w.width,ov->w.height);
+               fmt->name, ov->w.width, ov->w.height);
 
        /* calculate geometry */
        bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
index e79a402..b433267 100644 (file)
@@ -23,6 +23,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -65,8 +67,11 @@ MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
 #ifdef dprintk
 # undef dprintk
 #endif
-#define dprintk(fmt, arg...)   if (vbi_debug) \
-       printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg)
+#define dprintk(fmt, ...)                                              \
+do {                                                                   \
+       if (vbi_debug)                                                  \
+               pr_debug("%d: " fmt, btv->c.nr, ##__VA_ARGS__);         \
+} while (0)
 
 #define IMAGE_SIZE(fmt) \
        (((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line)
index 318edf2..db943a8 100644 (file)
@@ -310,9 +310,21 @@ extern unsigned int bttv_gpio;
 extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
 extern int init_bttv_i2c(struct bttv *btv);
 
-#define bttv_printk if (bttv_verbose) printk
-#define dprintk  if (bttv_debug >= 1) printk
-#define d2printk if (bttv_debug >= 2) printk
+#define dprintk(fmt, ...)                      \
+do {                                           \
+       if (bttv_debug >= 1)                    \
+               pr_debug(fmt, ##__VA_ARGS__);   \
+} while (0)
+#define dprintk_cont(fmt, ...)                 \
+do {                                           \
+       if (bttv_debug >= 1)                    \
+               pr_cont(fmt, ##__VA_ARGS__);    \
+} while (0)
+#define d2printk(fmt, ...)                     \
+do {                                           \
+       if (bttv_debug >= 2)                    \
+               printk(fmt, ##__VA_ARGS__);     \
+} while (0)
 
 #define BTTV_MAX_FBUF   0x208000
 #define BTTV_TIMEOUT    msecs_to_jiffies(500)    /* 0.5 seconds */
index 2fadd9d..a86bab5 100644 (file)
@@ -8,6 +8,6 @@ cx18-alsa-objs := cx18-alsa-main.o cx18-alsa-pcm.o
 obj-$(CONFIG_VIDEO_CX18) += cx18.o
 obj-$(CONFIG_VIDEO_CX18_ALSA) += cx18-alsa.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/common/tuners
index 1834207..b9a94fc 100644 (file)
@@ -409,6 +409,7 @@ struct cx18_stream {
 
        /* Videobuf for YUV video */
        u32 pixelformat;
+       u32 vb_bytes_per_frame;
        struct list_head vb_capture;    /* video capture queue */
        spinlock_t vb_lock;
        struct timer_list vb_timeout;
@@ -430,10 +431,6 @@ struct cx18_open_id {
        u32 open_id;
        int type;
        struct cx18 *cx;
-
-       struct videobuf_queue vbuf_q;
-       spinlock_t s_lock; /* Protect vbuf_q */
-       enum v4l2_buf_type vb_type;
 };
 
 static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh)
index 07411f3..14cb961 100644 (file)
@@ -784,8 +784,6 @@ int cx18_v4l2_close(struct file *filp)
                cx18_release_stream(s);
        } else {
                cx18_stop_capture(id, 0);
-               if (id->type == CX18_ENC_STREAM_TYPE_YUV)
-                       videobuf_mmap_free(&id->vbuf_q);
        }
        kfree(id);
        mutex_unlock(&cx->serialize_lock);
index afe0a29..66b1c15 100644 (file)
@@ -160,12 +160,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
        pixfmt->priv = 0;
        if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
                pixfmt->pixelformat = s->pixelformat;
-               /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
-                  UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
-               if (s->pixelformat == V4L2_PIX_FMT_HM12)
-                       pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
-               else
-                       pixfmt->sizeimage = pixfmt->height * 720 * 2;
+               pixfmt->sizeimage = s->vb_bytes_per_frame;
                pixfmt->bytesperline = 720;
        } else {
                pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
@@ -296,6 +291,12 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
                return -EBUSY;
 
        s->pixelformat = fmt->fmt.pix.pixelformat;
+       /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+          UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
+       if (s->pixelformat == V4L2_PIX_FMT_HM12)
+               s->vb_bytes_per_frame = h * 720 * 3 / 2;
+       else
+               s->vb_bytes_per_frame = h * 720 * 2;
 
        mbus_fmt.width = cx->cxhdl.width = w;
        mbus_fmt.height = cx->cxhdl.height = h;
@@ -463,13 +464,16 @@ static int cx18_s_register(struct file *file, void *fh,
 static int cx18_querycap(struct file *file, void *fh,
                                struct v4l2_capability *vcap)
 {
-       struct cx18 *cx = fh2id(fh)->cx;
+       struct cx18_open_id *id = fh2id(fh);
+       struct cx18 *cx = id->cx;
 
        strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
        strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
        snprintf(vcap->bus_info, sizeof(vcap->bus_info),
                 "PCI:%s", pci_name(cx->pci_dev));
        vcap->capabilities = cx->v4l2_cap;          /* capabilities */
+       if (id->type == CX18_ENC_STREAM_TYPE_YUV)
+               vcap->capabilities |= V4L2_CAP_STREAMING;
        return 0;
 }
 
index c07191e..0c7796e 100644 (file)
@@ -196,7 +196,7 @@ static void cx18_mdl_send_to_videobuf(struct cx18_stream *s,
        }
 
        /* If we've filled the buffer as per the callers res then dispatch it */
-       if (vb_buf->bytes_used >= (vb_buf->vb.width * vb_buf->vb.height * 2)) {
+       if (vb_buf->bytes_used >= s->vb_bytes_per_frame) {
                dispatch = 1;
                vb_buf->bytes_used = 0;
        }
index 852f420..638cca1 100644 (file)
@@ -138,6 +138,12 @@ static int cx18_prepare_buffer(struct videobuf_queue *q,
                buf->tvnorm    = cx->std;
                s->pixelformat = pixelformat;
 
+               /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+                  UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
+               if (s->pixelformat == V4L2_PIX_FMT_HM12)
+                       s->vb_bytes_per_frame = height * 720 * 3 / 2;
+               else
+                       s->vb_bytes_per_frame = height * 720 * 2;
                cx18_dma_free(q, s, buf);
        }
 
@@ -154,6 +160,12 @@ static int cx18_prepare_buffer(struct videobuf_queue *q,
                buf->tvnorm    = cx->std;
                s->pixelformat = pixelformat;
 
+               /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+                  UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
+               if (s->pixelformat == V4L2_PIX_FMT_HM12)
+                       s->vb_bytes_per_frame = height * 720 * 3 / 2;
+               else
+                       s->vb_bytes_per_frame = height * 720 * 2;
                rc = videobuf_iolock(q, &buf->vb, NULL);
                if (rc != 0)
                        goto fail;
@@ -287,6 +299,7 @@ static void cx18_stream_init(struct cx18 *cx, int type)
 
                /* Assume the previous pixel default */
                s->pixelformat = V4L2_PIX_FMT_HM12;
+               s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2;
        }
 }
 
index 2c24843..b334897 100644 (file)
@@ -8,9 +8,9 @@ obj-$(CONFIG_VIDEO_CX231XX) += cx231xx.o
 obj-$(CONFIG_VIDEO_CX231XX_ALSA) += cx231xx-alsa.o
 obj-$(CONFIG_VIDEO_CX231XX_DVB) += cx231xx-dvb.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-usb
+ccflags-y += -Idrivers/media/video
+ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/dvb/dvb-usb
 
index caab1bf..b391e9b 100644 (file)
@@ -38,7 +38,7 @@ config VIDEO_CX23885
 config MEDIA_ALTERA_CI
        tristate "Altera FPGA based CI module"
        depends on VIDEO_CX23885 && DVB_CORE
-       select STAPL_ALTERA
+       select ALTERA_STAPL
        ---help---
          An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card.
 
index 23293c7..f81f279 100644 (file)
@@ -2,14 +2,14 @@ cx23885-objs  := cx23885-cards.o cx23885-video.o cx23885-vbi.o \
                    cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \
                    cx23885-ioctl.o cx23885-ir.o cx23885-av.o cx23885-input.o \
                    cx23888-ir.o netup-init.o cimax2.o netup-eeprom.o \
-                   cx23885-f300.o
+                   cx23885-f300.o cx23885-alsa.o
 
 obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
 obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/video
+ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
 
-EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx23885/cx23885-alsa.c b/drivers/media/video/cx23885/cx23885-alsa.c
new file mode 100644 (file)
index 0000000..7951692
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ *
+ *  Support for CX23885 analog audio capture
+ *
+ *    (c) 2008 Mijhail Moreyra <mijhail.moreyra@gmail.com>
+ *    Adapted from cx88-alsa.c
+ *    (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+
+#include <asm/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+#include <sound/tlv.h>
+
+
+#include "cx23885.h"
+#include "cx23885-reg.h"
+
+#define AUDIO_SRAM_CHANNEL     SRAM_CH07
+
+#define dprintk(level, fmt, arg...)    if (audio_debug >= level) \
+       printk(KERN_INFO "%s: " fmt, chip->dev->name , ## arg)
+
+#define dprintk_core(level, fmt, arg...)       if (audio_debug >= level) \
+       printk(KERN_DEBUG "%s: " fmt, chip->dev->name , ## arg)
+
+/****************************************************************************
+                       Module global static vars
+ ****************************************************************************/
+
+static unsigned int disable_analog_audio;
+module_param(disable_analog_audio, int, 0644);
+MODULE_PARM_DESC(disable_analog_audio, "disable analog audio ALSA driver");
+
+static unsigned int audio_debug;
+module_param(audio_debug, int, 0644);
+MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]");
+
+/****************************************************************************
+                       Board specific funtions
+ ****************************************************************************/
+
+/* Constants taken from cx88-reg.h */
+#define AUD_INT_DN_RISCI1       (1 <<  0)
+#define AUD_INT_UP_RISCI1       (1 <<  1)
+#define AUD_INT_RDS_DN_RISCI1   (1 <<  2)
+#define AUD_INT_DN_RISCI2       (1 <<  4) /* yes, 3 is skipped */
+#define AUD_INT_UP_RISCI2       (1 <<  5)
+#define AUD_INT_RDS_DN_RISCI2   (1 <<  6)
+#define AUD_INT_DN_SYNC         (1 << 12)
+#define AUD_INT_UP_SYNC         (1 << 13)
+#define AUD_INT_RDS_DN_SYNC     (1 << 14)
+#define AUD_INT_OPC_ERR         (1 << 16)
+#define AUD_INT_BER_IRQ         (1 << 20)
+#define AUD_INT_MCHG_IRQ        (1 << 21)
+#define GP_COUNT_CONTROL_RESET 0x3
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+static int cx23885_start_audio_dma(struct cx23885_audio_dev *chip)
+{
+       struct cx23885_audio_buffer *buf = chip->buf;
+       struct cx23885_dev *dev  = chip->dev;
+       struct sram_channel *audio_ch =
+               &dev->sram_channels[AUDIO_SRAM_CHANNEL];
+
+       dprintk(1, "%s()\n", __func__);
+
+       /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
+       cx_clear(AUD_INT_DMA_CTL, 0x11);
+
+       /* setup fifo + format - out channel */
+       cx23885_sram_channel_setup(chip->dev, audio_ch, buf->bpl,
+               buf->risc.dma);
+
+       /* sets bpl size */
+       cx_write(AUD_INT_A_LNGTH, buf->bpl);
+
+       /* This is required to get good audio (1 seems to be ok) */
+       cx_write(AUD_INT_A_MODE, 1);
+
+       /* reset counter */
+       cx_write(AUD_INT_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET);
+       atomic_set(&chip->count, 0);
+
+       dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d "
+               "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start+12)>>1,
+               chip->num_periods, buf->bpl * chip->num_periods);
+
+       /* Enables corresponding bits at AUD_INT_STAT */
+       cx_write(AUDIO_INT_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+                                   AUD_INT_DN_RISCI1);
+
+       /* Clean any pending interrupt bits already set */
+       cx_write(AUDIO_INT_INT_STAT, ~0);
+
+       /* enable audio irqs */
+       cx_set(PCI_INT_MSK, chip->dev->pci_irqmask | PCI_MSK_AUD_INT);
+
+       /* start dma */
+       cx_set(DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
+       cx_set(AUD_INT_DMA_CTL, 0x11); /* audio downstream FIFO and
+                                         RISC enable */
+       if (audio_debug)
+               cx23885_sram_channel_dump(chip->dev, audio_ch);
+
+       return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+static int cx23885_stop_audio_dma(struct cx23885_audio_dev *chip)
+{
+       struct cx23885_dev *dev = chip->dev;
+       dprintk(1, "Stopping audio DMA\n");
+
+       /* stop dma */
+       cx_clear(AUD_INT_DMA_CTL, 0x11);
+
+       /* disable irqs */
+       cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT);
+       cx_clear(AUDIO_INT_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+                                   AUD_INT_DN_RISCI1);
+
+       if (audio_debug)
+               cx23885_sram_channel_dump(chip->dev,
+                       &dev->sram_channels[AUDIO_SRAM_CHANNEL]);
+
+       return 0;
+}
+
+/*
+ * BOARD Specific: Handles audio IRQ
+ */
+int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask)
+{
+       struct cx23885_audio_dev *chip = dev->audio_dev;
+
+       if (0 == (status & mask))
+               return 0;
+
+       cx_write(AUDIO_INT_INT_STAT, status);
+
+       /* risc op code error */
+       if (status & AUD_INT_OPC_ERR) {
+               printk(KERN_WARNING "%s/1: Audio risc op code error\n",
+                       dev->name);
+               cx_clear(AUD_INT_DMA_CTL, 0x11);
+               cx23885_sram_channel_dump(dev,
+                       &dev->sram_channels[AUDIO_SRAM_CHANNEL]);
+       }
+       if (status & AUD_INT_DN_SYNC) {
+               dprintk(1, "Downstream sync error\n");
+               cx_write(AUD_INT_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET);
+               return 1;
+       }
+       /* risc1 downstream */
+       if (status & AUD_INT_DN_RISCI1) {
+               atomic_set(&chip->count, cx_read(AUD_INT_A_GPCNT));
+               snd_pcm_period_elapsed(chip->substream);
+       }
+       /* FIXME: Any other status should deserve a special handling? */
+
+       return 1;
+}
+
+static int dsp_buffer_free(struct cx23885_audio_dev *chip)
+{
+       BUG_ON(!chip->dma_size);
+
+       dprintk(2, "Freeing buffer\n");
+       videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
+       videobuf_dma_free(chip->dma_risc);
+       btcx_riscmem_free(chip->pci, &chip->buf->risc);
+       kfree(chip->buf);
+
+       chip->dma_risc = NULL;
+       chip->dma_size = 0;
+
+       return 0;
+}
+
+/****************************************************************************
+                               ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+#define DEFAULT_FIFO_SIZE      4096
+
+static struct snd_pcm_hardware snd_cx23885_digital_hw = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+       .rates =                SNDRV_PCM_RATE_48000,
+       .rate_min =             48000,
+       .rate_max =             48000,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* Analog audio output will be full of clicks and pops if there
+          are not exactly four lines in the SRAM FIFO buffer.  */
+       .period_bytes_min = DEFAULT_FIFO_SIZE/4,
+       .period_bytes_max = DEFAULT_FIFO_SIZE/4,
+       .periods_min = 1,
+       .periods_max = 1024,
+       .buffer_bytes_max = (1024*1024),
+};
+
+/*
+ * audio pcm capture open callback
+ */
+static int snd_cx23885_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int err;
+
+       if (!chip) {
+               printk(KERN_ERR "BUG: cx23885 can't find device struct."
+                               " Can't proceed with open\n");
+               return -ENODEV;
+       }
+
+       err = snd_pcm_hw_constraint_pow2(runtime, 0,
+               SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0)
+               goto _error;
+
+       chip->substream = substream;
+
+       runtime->hw = snd_cx23885_digital_hw;
+
+       if (chip->dev->sram_channels[AUDIO_SRAM_CHANNEL].fifo_size !=
+               DEFAULT_FIFO_SIZE) {
+               unsigned int bpl = chip->dev->
+                       sram_channels[AUDIO_SRAM_CHANNEL].fifo_size / 4;
+               bpl &= ~7; /* must be multiple of 8 */
+               runtime->hw.period_bytes_min = bpl;
+               runtime->hw.period_bytes_max = bpl;
+       }
+
+       return 0;
+_error:
+       dprintk(1, "Error opening PCM!\n");
+       return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_cx23885_close(struct snd_pcm_substream *substream)
+{
+       return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *hw_params)
+{
+       struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+       struct videobuf_dmabuf *dma;
+
+       struct cx23885_audio_buffer *buf;
+       int ret;
+
+       if (substream->runtime->dma_area) {
+               dsp_buffer_free(chip);
+               substream->runtime->dma_area = NULL;
+       }
+
+       chip->period_size = params_period_bytes(hw_params);
+       chip->num_periods = params_periods(hw_params);
+       chip->dma_size = chip->period_size * params_periods(hw_params);
+
+       BUG_ON(!chip->dma_size);
+       BUG_ON(chip->num_periods & (chip->num_periods-1));
+
+       buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+       if (NULL == buf)
+               return -ENOMEM;
+
+       buf->bpl = chip->period_size;
+
+       dma = &buf->dma;
+       videobuf_dma_init(dma);
+       ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
+                       (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
+       if (ret < 0)
+               goto error;
+
+       ret = videobuf_dma_map(&chip->pci->dev, dma);
+       if (ret < 0)
+               goto error;
+
+       ret = cx23885_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+                                  chip->period_size, chip->num_periods, 1);
+       if (ret < 0)
+               goto error;
+
+       /* Loop back to start of program */
+       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
+       buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+       buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+       chip->buf = buf;
+       chip->dma_risc = dma;
+
+       substream->runtime->dma_area = chip->dma_risc->vaddr;
+       substream->runtime->dma_bytes = chip->dma_size;
+       substream->runtime->dma_addr = 0;
+
+       return 0;
+
+error:
+       kfree(buf);
+       return ret;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_cx23885_hw_free(struct snd_pcm_substream *substream)
+{
+
+       struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+
+       if (substream->runtime->dma_area) {
+               dsp_buffer_free(chip);
+               substream->runtime->dma_area = NULL;
+       }
+
+       return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_cx23885_prepare(struct snd_pcm_substream *substream)
+{
+       return 0;
+}
+
+/*
+ * trigger callback
+ */
+static int snd_cx23885_card_trigger(struct snd_pcm_substream *substream,
+       int cmd)
+{
+       struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+       int err;
+
+       /* Local interrupts are already disabled by ALSA */
+       spin_lock(&chip->lock);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               err = cx23885_start_audio_dma(chip);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               err = cx23885_stop_audio_dma(chip);
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
+
+       spin_unlock(&chip->lock);
+
+       return err;
+}
+
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_cx23885_pointer(
+       struct snd_pcm_substream *substream)
+{
+       struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       u16 count;
+
+       count = atomic_read(&chip->count);
+
+       return runtime->period_size * (count & (runtime->periods-1));
+}
+
+/*
+ * page callback (needed for mmap)
+ */
+static struct page *snd_cx23885_page(struct snd_pcm_substream *substream,
+                               unsigned long offset)
+{
+       void *pageptr = substream->runtime->dma_area + offset;
+       return vmalloc_to_page(pageptr);
+}
+
+/*
+ * operators
+ */
+static struct snd_pcm_ops snd_cx23885_pcm_ops = {
+       .open = snd_cx23885_pcm_open,
+       .close = snd_cx23885_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_cx23885_hw_params,
+       .hw_free = snd_cx23885_hw_free,
+       .prepare = snd_cx23885_prepare,
+       .trigger = snd_cx23885_card_trigger,
+       .pointer = snd_cx23885_pointer,
+       .page = snd_cx23885_page,
+};
+
+/*
+ * create a PCM device
+ */
+static int snd_cx23885_pcm(struct cx23885_audio_dev *chip, int device,
+       char *name)
+{
+       int err;
+       struct snd_pcm *pcm;
+
+       err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
+       if (err < 0)
+               return err;
+       pcm->private_data = chip;
+       strcpy(pcm->name, name);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx23885_pcm_ops);
+
+       return 0;
+}
+
+/****************************************************************************
+                       Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * Alsa Constructor - Component probe
+ */
+
+struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev)
+{
+       struct snd_card *card;
+       struct cx23885_audio_dev *chip;
+       int err;
+
+       if (disable_analog_audio)
+               return NULL;
+
+       if (dev->sram_channels[AUDIO_SRAM_CHANNEL].cmds_start == 0) {
+               printk(KERN_WARNING "%s(): Missing SRAM channel configuration "
+                       "for analog TV Audio\n", __func__);
+               return NULL;
+       }
+
+       err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                       THIS_MODULE, sizeof(struct cx23885_audio_dev), &card);
+       if (err < 0)
+               goto error;
+
+       chip = (struct cx23885_audio_dev *) card->private_data;
+       chip->dev = dev;
+       chip->pci = dev->pci;
+       chip->card = card;
+       spin_lock_init(&chip->lock);
+
+       snd_card_set_dev(card, &dev->pci->dev);
+
+       err = snd_cx23885_pcm(chip, 0, "CX23885 Digital");
+       if (err < 0)
+               goto error;
+
+       strcpy(card->driver, "CX23885");
+       sprintf(card->shortname, "Conexant CX23885");
+       sprintf(card->longname, "%s at %s", card->shortname, dev->name);
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto error;
+
+       dprintk(0, "registered ALSA audio device\n");
+
+       return chip;
+
+error:
+       snd_card_free(card);
+       printk(KERN_ERR "%s(): Failed to register analog "
+                       "audio adapter\n", __func__);
+
+       return NULL;
+}
+
+/*
+ * ALSA destructor
+ */
+void cx23885_audio_unregister(struct cx23885_dev *dev)
+{
+       struct cx23885_audio_dev *chip = dev->audio_dev;
+
+       snd_card_free(chip->card);
+}
index 76b7563..c3cf089 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/delay.h>
 #include <media/cx25840.h>
 #include <linux/firmware.h>
+#include <misc/altera.h>
 
-#include "../../../staging/altera-stapl/altera.h"
 #include "cx23885.h"
 #include "tuner-xc2028.h"
 #include "netup-eeprom.h"
@@ -106,12 +106,14 @@ struct cx23885_board cx23885_boards[] = {
                        .vmux   =       CX25840_VIN7_CH3 |
                                        CX25840_VIN5_CH2 |
                                        CX25840_VIN2_CH1,
+                       .amux   = CX25840_AUDIO8,
                        .gpio0  = 0,
                }, {
                        .type   = CX23885_VMUX_COMPOSITE1,
                        .vmux   =       CX25840_VIN7_CH3 |
                                        CX25840_VIN4_CH2 |
                                        CX25840_VIN6_CH1,
+                       .amux   = CX25840_AUDIO7,
                        .gpio0  = 0,
                }, {
                        .type   = CX23885_VMUX_SVIDEO,
@@ -119,6 +121,7 @@ struct cx23885_board cx23885_boards[] = {
                                        CX25840_VIN4_CH2 |
                                        CX25840_VIN8_CH1 |
                                        CX25840_SVIDEO_ON,
+                       .amux   = CX25840_AUDIO7,
                        .gpio0  = 0,
                } },
        },
@@ -153,7 +156,30 @@ struct cx23885_board cx23885_boards[] = {
        },
        [CX23885_BOARD_HAUPPAUGE_HVR1500] = {
                .name           = "Hauppauge WinTV-HVR1500",
+               .porta          = CX23885_ANALOG_VIDEO,
                .portc          = CX23885_MPEG_DVB,
+               .tuner_type     = TUNER_XC2028,
+               .tuner_addr     = 0x61, /* 0xc2 >> 1 */
+               .input          = {{
+                       .type   = CX23885_VMUX_TELEVISION,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN5_CH2 |
+                                       CX25840_VIN2_CH1,
+                       .gpio0  = 0,
+               }, {
+                       .type   = CX23885_VMUX_COMPOSITE1,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN4_CH2 |
+                                       CX25840_VIN6_CH1,
+                       .gpio0  = 0,
+               }, {
+                       .type   = CX23885_VMUX_SVIDEO,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN4_CH2 |
+                                       CX25840_VIN8_CH1 |
+                                       CX25840_SVIDEO_ON,
+                       .gpio0  = 0,
+               } },
        },
        [CX23885_BOARD_HAUPPAUGE_HVR1200] = {
                .name           = "Hauppauge WinTV-HVR1200",
@@ -387,6 +413,31 @@ struct cx23885_board cx23885_boards[] = {
                                .vmux   = CX25840_COMPOSITE1,
                } },
        },
+       [CX23885_BOARD_MPX885] = {
+               .name           = "MPX-885",
+               .porta          = CX23885_ANALOG_VIDEO,
+               .input          = {{
+                       .type   = CX23885_VMUX_COMPOSITE1,
+                       .vmux   = CX25840_COMPOSITE1,
+                       .amux   = CX25840_AUDIO6,
+                       .gpio0  = 0,
+               }, {
+                       .type   = CX23885_VMUX_COMPOSITE2,
+                       .vmux   = CX25840_COMPOSITE2,
+                       .amux   = CX25840_AUDIO6,
+                       .gpio0  = 0,
+               }, {
+                       .type   = CX23885_VMUX_COMPOSITE3,
+                       .vmux   = CX25840_COMPOSITE3,
+                       .amux   = CX25840_AUDIO7,
+                       .gpio0  = 0,
+               }, {
+                       .type   = CX23885_VMUX_COMPOSITE4,
+                       .vmux   = CX25840_COMPOSITE4,
+                       .amux   = CX25840_AUDIO7,
+                       .gpio0  = 0,
+               } },
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -1415,6 +1466,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
        case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
        case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
+       case CX23885_BOARD_HAUPPAUGE_HVR1500:
+       case CX23885_BOARD_MPX885:
                dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
                                &dev->i2c_bus[2].i2c_adap,
                                "cx25840", 0x88 >> 1, NULL);
index ee41a88..40e68b2 100644 (file)
@@ -54,7 +54,7 @@ MODULE_PARM_DESC(card, "card type");
 
 #define dprintk(level, fmt, arg...)\
        do { if (debug >= level)\
-               printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+               printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\
        } while (0)
 
 static unsigned int cx23885_devcount;
@@ -155,12 +155,12 @@ static struct sram_channel cx23885_sram_channels[] = {
                .cnt2_reg       = DMA5_CNT2,
        },
        [SRAM_CH07] = {
-               .name           = "ch7",
-               .cmds_start     = 0x0,
-               .ctrl_start     = 0x0,
-               .cdt            = 0x0,
-               .fifo_start     = 0x0,
-               .fifo_size      = 0x0,
+               .name           = "TV Audio",
+               .cmds_start     = 0x10190,
+               .ctrl_start     = 0x10480,
+               .cdt            = 0x10a00,
+               .fifo_start     = 0x7000,
+               .fifo_size      = 0x1000,
                .ptr1_reg       = DMA6_PTR1,
                .ptr2_reg       = DMA6_PTR2,
                .cnt1_reg       = DMA6_CNT1,
@@ -1082,10 +1082,10 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev)
 static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
                               unsigned int offset, u32 sync_line,
                               unsigned int bpl, unsigned int padding,
-                              unsigned int lines)
+                              unsigned int lines,  unsigned int lpi)
 {
        struct scatterlist *sg;
-       unsigned int line, todo;
+       unsigned int line, todo, sol;
 
        /* sync instruction */
        if (sync_line != NO_SYNC_LINE)
@@ -1098,16 +1098,22 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
                        offset -= sg_dma_len(sg);
                        sg++;
                }
+
+               if (lpi && line > 0 && !(line % lpi))
+                       sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
+               else
+                       sol = RISC_SOL;
+
                if (bpl <= sg_dma_len(sg)-offset) {
                        /* fits into current chunk */
-                       *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+                       *(rp++) = cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl);
                        *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset);
                        *(rp++) = cpu_to_le32(0); /* bits 63-32 */
                        offset += bpl;
                } else {
                        /* scanline needs to be split */
                        todo = bpl;
-                       *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|
+                       *(rp++) = cpu_to_le32(RISC_WRITE|sol|
                                            (sg_dma_len(sg)-offset));
                        *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset);
                        *(rp++) = cpu_to_le32(0); /* bits 63-32 */
@@ -1164,10 +1170,10 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
        rp = risc->cpu;
        if (UNSET != top_offset)
                rp = cx23885_risc_field(rp, sglist, top_offset, 0,
-                                       bpl, padding, lines);
+                                       bpl, padding, lines, 0);
        if (UNSET != bottom_offset)
                rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
-                                       bpl, padding, lines);
+                                       bpl, padding, lines, 0);
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
@@ -1175,11 +1181,11 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
        return 0;
 }
 
-static int cx23885_risc_databuffer(struct pci_dev *pci,
+int cx23885_risc_databuffer(struct pci_dev *pci,
                                   struct btcx_riscmem *risc,
                                   struct scatterlist *sglist,
                                   unsigned int bpl,
-                                  unsigned int lines)
+                                  unsigned int lines, unsigned int lpi)
 {
        u32 instructions;
        __le32 *rp;
@@ -1199,7 +1205,55 @@ static int cx23885_risc_databuffer(struct pci_dev *pci,
 
        /* write risc instructions */
        rp = risc->cpu;
-       rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
+       rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE,
+                               bpl, 0, lines, lpi);
+
+       /* save pointer to jmp instruction address */
+       risc->jmp = rp;
+       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+       return 0;
+}
+
+int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+                       struct scatterlist *sglist, unsigned int top_offset,
+                       unsigned int bottom_offset, unsigned int bpl,
+                       unsigned int padding, unsigned int lines)
+{
+       u32 instructions, fields;
+       __le32 *rp;
+       int rc;
+
+       fields = 0;
+       if (UNSET != top_offset)
+               fields++;
+       if (UNSET != bottom_offset)
+               fields++;
+
+       /* estimate risc mem: worst case is one write per page border +
+          one write per scan line + syncs + jump (all 2 dwords).  Padding
+          can cause next bpl to start close to a page border.  First DMA
+          region may be smaller than PAGE_SIZE */
+       /* write and jump need and extra dword */
+       instructions  = fields * (1 + ((bpl + padding) * lines)
+               / PAGE_SIZE + lines);
+       instructions += 2;
+       rc = btcx_riscmem_alloc(pci, risc, instructions*12);
+       if (rc < 0)
+               return rc;
+       /* write risc instructions */
+       rp = risc->cpu;
+
+       /* Sync to line 6, so US CC line 21 will appear in line '12'
+        * in the userland vbi payload */
+       if (UNSET != top_offset)
+               rp = cx23885_risc_field(rp, sglist, top_offset, 6,
+                                       bpl, padding, lines, 0);
+
+       if (UNSET != bottom_offset)
+               rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207,
+                                       bpl, padding, lines, 0);
+
+
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
@@ -1207,6 +1261,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci,
        return 0;
 }
 
+
 int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
                                u32 reg, u32 mask, u32 value)
 {
@@ -1517,7 +1572,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
                        goto fail;
                cx23885_risc_databuffer(dev->pci, &buf->risc,
                                        videobuf_to_dma(&buf->vb)->sglist,
-                                       buf->vb.width, buf->vb.height);
+                                       buf->vb.width, buf->vb.height, 0);
        }
        buf->vb.state = VIDEOBUF_PREPARED;
        return 0;
@@ -1741,15 +1796,19 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
        struct cx23885_tsport *ts2 = &dev->ts2;
        u32 pci_status, pci_mask;
        u32 vida_status, vida_mask;
+       u32 audint_status, audint_mask;
        u32 ts1_status, ts1_mask;
        u32 ts2_status, ts2_mask;
        int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
+       int audint_count = 0;
        bool subdev_handled;
 
        pci_status = cx_read(PCI_INT_STAT);
        pci_mask = cx23885_irq_get_mask(dev);
        vida_status = cx_read(VID_A_INT_STAT);
        vida_mask = cx_read(VID_A_INT_MSK);
+       audint_status = cx_read(AUDIO_INT_INT_STAT);
+       audint_mask = cx_read(AUDIO_INT_INT_MSK);
        ts1_status = cx_read(VID_B_INT_STAT);
        ts1_mask = cx_read(VID_B_INT_MSK);
        ts2_status = cx_read(VID_C_INT_STAT);
@@ -1759,12 +1818,15 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
                goto out;
 
        vida_count = cx_read(VID_A_GPCNT);
+       audint_count = cx_read(AUD_INT_A_GPCNT);
        ts1_count = cx_read(ts1->reg_gpcnt);
        ts2_count = cx_read(ts2->reg_gpcnt);
        dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n",
                pci_status, pci_mask);
        dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n",
                vida_status, vida_mask, vida_count);
+       dprintk(7, "audint_status: 0x%08x audint_mask: 0x%08x count: 0x%x\n",
+               audint_status, audint_mask, audint_count);
        dprintk(7, "ts1_status: 0x%08x  ts1_mask: 0x%08x count: 0x%x\n",
                ts1_status, ts1_mask, ts1_count);
        dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n",
@@ -1861,6 +1923,9 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
        if (vida_status)
                handled += cx23885_video_irq(dev, vida_status);
 
+       if (audint_status)
+               handled += cx23885_audio_irq(dev, audint_status, audint_mask);
+
        if (pci_status & PCI_MSK_IR) {
                subdev_handled = false;
                v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine,
index aa83f07..bcb45be 100644 (file)
@@ -844,7 +844,7 @@ static int dvb_register(struct cx23885_tsport *port)
                        static struct xc2028_ctrl ctl = {
                                .fname   = XC3028L_DEFAULT_FIRMWARE,
                                .max_len = 64,
-                               .demod   = 5000,
+                               .demod   = XC3028_FE_DIBCOM52,
                                /* This is true for all demods with
                                        v36 firmware? */
                                .type    = XC2028_D2633,
index 307ff54..0ff7a9e 100644 (file)
@@ -287,6 +287,7 @@ static char *i2c_devs[128] = {
        [0x32 >> 1] = "cx24227",
        [0x88 >> 1] = "cx25837",
        [0x84 >> 1] = "tda8295",
+       [0x98 >> 1] = "flatiron",
        [0xa0 >> 1] = "eeprom",
        [0xc0 >> 1] = "tuner/mt2131/tda8275",
        [0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028",
index c87ac68..a99936e 100644 (file)
@@ -203,6 +203,7 @@ Channel manager Data Structure entry = 20 DWORD
 #define SD2_BIAS_CTRL  0x0000000A
 #define AMP_BIAS_CTRL  0x0000000C
 #define CH_PWR_CTRL1   0x0000000E
+#define FLD_CH_SEL      (1 << 3)
 #define CH_PWR_CTRL2   0x0000000F
 #define DSM_STATUS1    0x00000010
 #define DSM_STATUS2    0x00000011
@@ -271,7 +272,9 @@ Channel manager Data Structure entry = 20 DWORD
 #define VID_BC_MSK_OPC_ERR (1 << 16)
 #define VID_BC_MSK_SYNC    (1 << 12)
 #define VID_BC_MSK_OF      (1 <<  8)
+#define VID_BC_MSK_VBI_RISCI2 (1 <<  5)
 #define VID_BC_MSK_RISCI2  (1 <<  4)
+#define VID_BC_MSK_VBI_RISCI1 (1 <<  1)
 #define VID_BC_MSK_RISCI1   1
 
 #define VID_C_INT_MSK  0x00040040
index c0b6038..a1154f0 100644 (file)
@@ -41,6 +41,12 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
 
 /* ------------------------------------------------------------------ */
 
+#define VBI_LINE_LENGTH 1440
+#define NTSC_VBI_START_LINE 10        /* line 10 - 21 */
+#define NTSC_VBI_END_LINE   21
+#define NTSC_VBI_LINES      (NTSC_VBI_END_LINE - NTSC_VBI_START_LINE + 1)
+
+
 int cx23885_vbi_fmt(struct file *file, void *priv,
        struct v4l2_format *f)
 {
@@ -49,43 +55,86 @@ int cx23885_vbi_fmt(struct file *file, void *priv,
 
        if (dev->tvnorm & V4L2_STD_525_60) {
                /* ntsc */
-               f->fmt.vbi.sampling_rate = 28636363;
+               f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+               f->fmt.vbi.sampling_rate = 27000000;
+               f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+               f->fmt.vbi.offset = 0;
+               f->fmt.vbi.flags = 0;
                f->fmt.vbi.start[0] = 10;
-               f->fmt.vbi.start[1] = 273;
-
+               f->fmt.vbi.count[0] = 17;
+               f->fmt.vbi.start[1] = 263 + 10 + 1;
+               f->fmt.vbi.count[1] = 17;
        } else if (dev->tvnorm & V4L2_STD_625_50) {
                /* pal */
                f->fmt.vbi.sampling_rate = 35468950;
                f->fmt.vbi.start[0] = 7 - 1;
                f->fmt.vbi.start[1] = 319 - 1;
        }
+
        return 0;
 }
 
+/* We're given the Video Interrupt status register.
+ * The cx23885_video_irq() func has already validated
+ * the potential error bits, we just need to
+ * deal with vbi payload and return indication if
+ * we actually processed any payload.
+ */
+int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status)
+{
+       u32 count;
+       int handled = 0;
+
+       if (status & VID_BC_MSK_VBI_RISCI1) {
+               dprintk(1, "%s() VID_BC_MSK_VBI_RISCI1\n", __func__);
+               spin_lock(&dev->slock);
+               count = cx_read(VID_A_GPCNT);
+               cx23885_video_wakeup(dev, &dev->vbiq, count);
+               spin_unlock(&dev->slock);
+               handled++;
+       }
+
+       if (status & VID_BC_MSK_VBI_RISCI2) {
+               dprintk(1, "%s() VID_BC_MSK_VBI_RISCI2\n", __func__);
+               dprintk(2, "stopper vbi\n");
+               spin_lock(&dev->slock);
+               cx23885_restart_vbi_queue(dev, &dev->vbiq);
+               spin_unlock(&dev->slock);
+               handled++;
+       }
+
+       return handled;
+}
+
 static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
                         struct cx23885_dmaqueue *q,
                         struct cx23885_buffer   *buf)
 {
+       dprintk(1, "%s()\n", __func__);
+
        /* setup fifo + format */
        cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02],
                                buf->vb.width, buf->risc.dma);
 
        /* reset counter */
+       cx_write(VID_A_GPCNT_CTL, 3);
+       cx_write(VID_A_VBI_CTRL, 3);
+       cx_write(VBI_A_GPCNT_CTL, 3);
        q->count = 1;
 
-       /* enable irqs */
+       /* enable irq */
        cx23885_irq_add_enable(dev, 0x01);
        cx_set(VID_A_INT_MSK, 0x000022);
 
        /* start dma */
        cx_set(DEV_CNTRL2, (1<<5));
-       cx_set(VID_A_DMA_CTL, 0x00000022);
+       cx_set(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */
 
        return 0;
 }
 
 
-static int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
+int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
                             struct cx23885_dmaqueue *q)
 {
        struct cx23885_buffer *buf;
@@ -102,7 +151,7 @@ static int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
                buf = list_entry(item, struct cx23885_buffer, vb.queue);
                buf->count = q->count++;
        }
-       mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+       mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
        return 0;
 }
 
@@ -113,8 +162,7 @@ void cx23885_vbi_timeout(unsigned long data)
        struct cx23885_buffer *buf;
        unsigned long flags;
 
-       cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]);
-
+       /* Stop the VBI engine */
        cx_clear(VID_A_DMA_CTL, 0x22);
 
        spin_lock_irqsave(&dev->slock, flags);
@@ -132,7 +180,7 @@ void cx23885_vbi_timeout(unsigned long data)
 }
 
 /* ------------------------------------------------------------------ */
-#define VBI_LINE_LENGTH 2048
+#define VBI_LINE_LENGTH 1440
 #define VBI_LINE_COUNT 17
 
 static int
@@ -173,7 +221,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                rc = videobuf_iolock(q, &buf->vb, NULL);
                if (0 != rc)
                        goto fail;
-               cx23885_risc_buffer(dev->pci, &buf->risc,
+               cx23885_risc_vbibuffer(dev->pci, &buf->risc,
                                 dma->sglist,
                                 0, buf->vb.width * buf->vb.height,
                                 buf->vb.width, 0,
@@ -207,7 +255,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
                cx23885_start_vbi_dma(dev, q, buf);
                buf->vb.state = VIDEOBUF_ACTIVE;
                buf->count    = q->count++;
-               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+               mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
                dprintk(2, "[%p/%d] vbi_queue - first active\n",
                        buf, buf->vb.i);
 
index 896bb32..e730b92 100644 (file)
@@ -37,6 +37,8 @@
 #include "cx23885-ioctl.h"
 #include "tuner-xc2028.h"
 
+#include <media/cx25840.h>
+
 MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
@@ -69,14 +71,14 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
 
 #define dprintk(level, fmt, arg...)\
        do { if (video_debug >= level)\
-               printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+               printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\
        } while (0)
 
 /* ------------------------------------------------------------------- */
 /* static data                                                         */
 
 #define FORMAT_FLAGS_PACKED       0x01
-
+#if 0
 static struct cx23885_fmt formats[] = {
        {
                .name     = "8 bpp, gray",
@@ -130,6 +132,23 @@ static struct cx23885_fmt formats[] = {
                .flags    = FORMAT_FLAGS_PACKED,
        },
 };
+#else
+static struct cx23885_fmt formats[] = {
+       {
+#if 0
+               .name     = "4:2:2, packed, UYVY",
+               .fourcc   = V4L2_PIX_FMT_UYVY,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       }, {
+#endif
+               .name     = "4:2:2, packed, YUYV",
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       }
+};
+#endif
 
 static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
 {
@@ -139,7 +158,12 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
                if (formats[i].fourcc == fourcc)
                        return formats+i;
 
-       printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc);
+       printk(KERN_ERR "%s(%c%c%c%c) NOT FOUND\n", __func__,
+               (fourcc & 0xff),
+               ((fourcc >> 8) & 0xff),
+               ((fourcc >> 16) & 0xff),
+               ((fourcc >> 24) & 0xff)
+               );
        return NULL;
 }
 
@@ -171,7 +195,7 @@ static struct cx23885_ctrl cx23885_ctls[] = {
                        .id            = V4L2_CID_CONTRAST,
                        .name          = "Contrast",
                        .minimum       = 0,
-                       .maximum       = 0xff,
+                       .maximum       = 0x7f,
                        .step          = 1,
                        .default_value = 0x3f,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
@@ -184,10 +208,10 @@ static struct cx23885_ctrl cx23885_ctls[] = {
                .v = {
                        .id            = V4L2_CID_HUE,
                        .name          = "Hue",
-                       .minimum       = 0,
-                       .maximum       = 0xff,
+                       .minimum       = -127,
+                       .maximum       = 128,
                        .step          = 1,
-                       .default_value = 0x7f,
+                       .default_value = 0x0,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
                },
                .off                   = 128,
@@ -202,9 +226,9 @@ static struct cx23885_ctrl cx23885_ctls[] = {
                        .id            = V4L2_CID_SATURATION,
                        .name          = "Saturation",
                        .minimum       = 0,
-                       .maximum       = 0xff,
+                       .maximum       = 0x7f,
                        .step          = 1,
-                       .default_value = 0x7f,
+                       .default_value = 0x3f,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
                },
                .off                   = 0,
@@ -258,8 +282,8 @@ static const u32 *ctrl_classes[] = {
        NULL
 };
 
-static void cx23885_video_wakeup(struct cx23885_dev *dev,
-                struct cx23885_dmaqueue *q, u32 count)
+void cx23885_video_wakeup(struct cx23885_dev *dev,
+       struct cx23885_dmaqueue *q, u32 count)
 {
        struct cx23885_buffer *buf;
        int bc;
@@ -393,6 +417,71 @@ static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
        mutex_unlock(&dev->lock);
 }
 
+static int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data)
+{
+       /* 8 bit registers, 8 bit values */
+       u8 buf[] = { reg, data };
+
+       struct i2c_msg msg = { .addr = 0x98 >> 1,
+               .flags = 0, .buf = buf, .len = 2 };
+
+       return i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);
+}
+
+static u8 cx23885_flatiron_read(struct cx23885_dev *dev, u8 reg)
+{
+       /* 8 bit registers, 8 bit values */
+       int ret;
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+
+       struct i2c_msg msg[] = {
+               { .addr = 0x98 >> 1, .flags = 0, .buf = b0, .len = 1 },
+               { .addr = 0x98 >> 1, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+       };
+
+       ret = i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg[0], 2);
+       if (ret != 2)
+               printk(KERN_ERR "%s() error\n", __func__);
+
+       return b1[0];
+}
+
+static void cx23885_flatiron_dump(struct cx23885_dev *dev)
+{
+       int i;
+       dprintk(1, "Flatiron dump\n");
+       for (i = 0; i < 0x24; i++) {
+               dprintk(1, "FI[%02x] = %02x\n", i,
+                       cx23885_flatiron_read(dev, i));
+       }
+}
+
+static int cx23885_flatiron_mux(struct cx23885_dev *dev, int input)
+{
+       u8 val;
+       dprintk(1, "%s(input = %d)\n", __func__, input);
+
+       if (input == 1)
+               val = cx23885_flatiron_read(dev, CH_PWR_CTRL1) & ~FLD_CH_SEL;
+       else if (input == 2)
+               val = cx23885_flatiron_read(dev, CH_PWR_CTRL1) | FLD_CH_SEL;
+       else
+               return -EINVAL;
+
+       val |= 0x20; /* Enable clock to delta-sigma and dec filter */
+
+       cx23885_flatiron_write(dev, CH_PWR_CTRL1, val);
+
+       /* Wake up */
+       cx23885_flatiron_write(dev, CH_PWR_CTRL2, 0);
+
+       if (video_debug)
+               cx23885_flatiron_dump(dev);
+
+       return 0;
+}
+
 static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
 {
        dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
@@ -413,27 +502,59 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
        v4l2_subdev_call(dev->sd_cx25840, video, s_routing,
                        INPUT(input)->vmux, 0, 0);
 
+       if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) ||
+               (dev->board == CX23885_BOARD_MPX885)) {
+               /* Configure audio routing */
+               v4l2_subdev_call(dev->sd_cx25840, audio, s_routing,
+                       INPUT(input)->amux, 0, 0);
+
+               if (INPUT(input)->amux == CX25840_AUDIO7)
+                       cx23885_flatiron_mux(dev, 1);
+               else if (INPUT(input)->amux == CX25840_AUDIO6)
+                       cx23885_flatiron_mux(dev, 2);
+       }
+
        return 0;
 }
 
-/* ------------------------------------------------------------------ */
-static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
-       unsigned int height, enum v4l2_field field)
+static int cx23885_audio_mux(struct cx23885_dev *dev, unsigned int input)
 {
-       dprintk(1, "%s()\n", __func__);
+       dprintk(1, "%s(input=%d)\n", __func__, input);
+
+       /* The baseband video core of the cx23885 has two audio inputs.
+        * LR1 and LR2. In almost every single case so far only HVR1xxx
+        * cards we've only ever supported LR1. Time to support LR2,
+        * which is available via the optional white breakout header on
+        * the board.
+        * We'll use a could of existing enums in the card struct to allow
+        * devs to specify which baseband input they need, or just default
+        * to what we've always used.
+        */
+       if (INPUT(input)->amux == CX25840_AUDIO7)
+               cx23885_flatiron_mux(dev, 1);
+       else if (INPUT(input)->amux == CX25840_AUDIO6)
+               cx23885_flatiron_mux(dev, 2);
+       else {
+               /* Not specifically defined, assume the default. */
+               cx23885_flatiron_mux(dev, 1);
+       }
+
        return 0;
 }
 
+/* ------------------------------------------------------------------ */
 static int cx23885_start_video_dma(struct cx23885_dev *dev,
                           struct cx23885_dmaqueue *q,
                           struct cx23885_buffer *buf)
 {
        dprintk(1, "%s()\n", __func__);
 
+       /* Stop the dma/fifo before we tamper with it's risc programs */
+       cx_clear(VID_A_DMA_CTL, 0x11);
+
        /* setup fifo + format */
        cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
                                buf->bpl, buf->risc.dma);
-       cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field);
 
        /* reset counter */
        cx_write(VID_A_GPCNT_CTL, 3);
@@ -748,7 +869,7 @@ static int video_open(struct file *file)
        fh->type     = type;
        fh->width    = 320;
        fh->height   = 240;
-       fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+       fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_YUYV);
 
        videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops,
                            &dev->pci->dev, &dev->slock,
@@ -757,6 +878,14 @@ static int video_open(struct file *file)
                            sizeof(struct cx23885_buffer),
                            fh, NULL);
 
+       videobuf_queue_sg_init(&fh->vbiq, &cx23885_vbi_qops,
+               &dev->pci->dev, &dev->slock,
+               V4L2_BUF_TYPE_VBI_CAPTURE,
+               V4L2_FIELD_SEQ_TB,
+               sizeof(struct cx23885_buffer),
+               fh, NULL);
+
+
        dprintk(1, "post videobuf_queue_init()\n");
 
        return 0;
@@ -884,8 +1013,9 @@ static int cx23885_get_control(struct cx23885_dev *dev,
 static int cx23885_set_control(struct cx23885_dev *dev,
        struct v4l2_control *ctl)
 {
-       dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
-               " (disabled - no action)\n", __func__);
+       dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__);
+       call_all(dev, core, s_ctrl, ctl);
+
        return 0;
 }
 
@@ -1059,13 +1189,22 @@ static int vidioc_streamon(struct file *file, void *priv,
        struct cx23885_dev *dev = fh->dev;
        dprintk(1, "%s()\n", __func__);
 
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
+       if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+               (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
                return -EINVAL;
        if (unlikely(i != fh->type))
                return -EINVAL;
 
        if (unlikely(!res_get(dev, fh, get_resource(fh))))
                return -EBUSY;
+
+       /* Don't start VBI streaming unless vida streaming
+        * has already started.
+        */
+       if ((fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) &&
+               ((cx_read(VID_A_DMA_CTL) & 0x11) == 0))
+               return -EINVAL;
+
        return videobuf_streamon(get_queue(fh));
 }
 
@@ -1076,7 +1215,8 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
        int err, res;
        dprintk(1, "%s()\n", __func__);
 
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+               (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
                return -EINVAL;
        if (i != fh->type)
                return -EINVAL;
@@ -1119,7 +1259,7 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
        dprintk(1, "%s()\n", __func__);
 
        n = i->index;
-       if (n >= 4)
+       if (n >= MAX_CX23885_INPUT)
                return -EINVAL;
 
        if (0 == INPUT(n)->type)
@@ -1133,6 +1273,11 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
                i->type = V4L2_INPUT_TYPE_TUNER;
                i->std = CX23885_NORMS;
        }
+
+       /* Two selectable audio inputs for non-tv inputs */
+       if (INPUT(n)->type != CX23885_VMUX_TELEVISION)
+               i->audioset = 0x3;
+
        return 0;
 }
 
@@ -1159,13 +1304,20 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 
        dprintk(1, "%s(%d)\n", __func__, i);
 
-       if (i >= 4) {
+       if (i >= MAX_CX23885_INPUT) {
                dprintk(1, "%s() -EINVAL\n", __func__);
                return -EINVAL;
        }
 
+       if (INPUT(i)->type == 0)
+               return -EINVAL;
+
        mutex_lock(&dev->lock);
        cx23885_video_mux(dev, i);
+
+       /* By default establish the default audio input for the card also */
+       /* Caller is free to use VIDIOC_S_AUDIO to override afterwards */
+       cx23885_audio_mux(dev, i);
        mutex_unlock(&dev->lock);
        return 0;
 }
@@ -1185,6 +1337,64 @@ static int vidioc_log_status(struct file *file, void *priv)
        return 0;
 }
 
+static int cx23885_query_audinput(struct file *file, void *priv,
+       struct v4l2_audio *i)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       static const char *iname[] = {
+               [0] = "Baseband L/R 1",
+               [1] = "Baseband L/R 2",
+       };
+       unsigned int n;
+       dprintk(1, "%s()\n", __func__);
+
+       n = i->index;
+       if (n >= 2)
+               return -EINVAL;
+
+       memset(i, 0, sizeof(*i));
+       i->index = n;
+       strcpy(i->name, iname[n]);
+       i->capability  = V4L2_AUDCAP_STEREO;
+       i->mode  = V4L2_AUDMODE_AVL;
+       return 0;
+
+}
+
+static int vidioc_enum_audinput(struct file *file, void *priv,
+                               struct v4l2_audio *i)
+{
+       return cx23885_query_audinput(file, priv, i);
+}
+
+static int vidioc_g_audinput(struct file *file, void *priv,
+       struct v4l2_audio *i)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+       i->index = dev->audinput;
+       dprintk(1, "%s(input=%d)\n", __func__, i->index);
+
+       return cx23885_query_audinput(file, priv, i);
+}
+
+static int vidioc_s_audinput(struct file *file, void *priv,
+       struct v4l2_audio *i)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       if (i->index >= 2)
+               return -EINVAL;
+
+       dprintk(1, "%s(%d)\n", __func__, i->index);
+
+       dev->audinput = i->index;
+
+       /* Skip the audio defaults from the cards struct, caller wants
+        * directly touch the audio mux hardware. */
+       cx23885_flatiron_mux(dev, dev->audinput + 1);
+       return 0;
+}
+
 static int vidioc_queryctrl(struct file *file, void *priv,
                                struct v4l2_queryctrl *qctrl)
 {
@@ -1221,10 +1431,8 @@ static int vidioc_g_tuner(struct file *file, void *priv,
                return -EINVAL;
 
        strcpy(t->name, "Television");
-       t->type       = V4L2_TUNER_ANALOG_TV;
-       t->capability = V4L2_TUNER_CAP_NORM;
-       t->rangehigh  = 0xffffffffUL;
-       t->signal = 0xffff ; /* LOCKED */
+
+       call_all(dev, tuner, g_tuner, t);
        return 0;
 }
 
@@ -1237,6 +1445,9 @@ static int vidioc_s_tuner(struct file *file, void *priv,
                return -EINVAL;
        if (0 != t->index)
                return -EINVAL;
+       /* Update the A/V core */
+       call_all(dev, tuner, s_tuner, t);
+
        return 0;
 }
 
@@ -1302,10 +1513,6 @@ static void cx23885_vid_timeout(unsigned long data)
        struct cx23885_buffer *buf;
        unsigned long flags;
 
-       cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]);
-
-       cx_clear(VID_A_DMA_CTL, 0x11);
-
        spin_lock_irqsave(&dev->slock, flags);
        while (!list_empty(&q->active)) {
                buf = list_entry(q->active.next,
@@ -1313,7 +1520,7 @@ static void cx23885_vid_timeout(unsigned long data)
                list_del(&buf->vb.queue);
                buf->vb.state = VIDEOBUF_ERROR;
                wake_up(&buf->vb.done);
-               printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n",
+               printk(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n",
                        dev->name, buf, buf->vb.i,
                        (unsigned long)buf->risc.dma);
        }
@@ -1329,27 +1536,43 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
        mask   = cx_read(VID_A_INT_MSK);
        if (0 == (status & mask))
                return handled;
+
        cx_write(VID_A_INT_STAT, status);
 
-       dprintk(2, "%s() status = 0x%08x\n", __func__, status);
-       /* risc op code error */
-       if (status & (1 << 16)) {
-               printk(KERN_WARNING "%s/0: video risc op code error\n",
-                       dev->name);
-               cx_clear(VID_A_DMA_CTL, 0x11);
-               cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]);
+       /* risc op code error, fifo overflow or line sync detection error */
+       if ((status & VID_BC_MSK_OPC_ERR) ||
+               (status & VID_BC_MSK_SYNC) ||
+               (status & VID_BC_MSK_OF)) {
+
+               if (status & VID_BC_MSK_OPC_ERR) {
+                       dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n",
+                               VID_BC_MSK_OPC_ERR);
+                       printk(KERN_WARNING "%s: video risc op code error\n",
+                               dev->name);
+                       cx23885_sram_channel_dump(dev,
+                               &dev->sram_channels[SRAM_CH01]);
+               }
+
+               if (status & VID_BC_MSK_SYNC)
+                       dprintk(7, " (VID_BC_MSK_SYNC 0x%08x) "
+                               "video lines miss-match\n",
+                               VID_BC_MSK_SYNC);
+
+               if (status & VID_BC_MSK_OF)
+                       dprintk(7, " (VID_BC_MSK_OF 0x%08x) fifo overflow\n",
+                               VID_BC_MSK_OF);
+
        }
 
-       /* risc1 y */
-       if (status & 0x01) {
+       /* Video */
+       if (status & VID_BC_MSK_RISCI1) {
                spin_lock(&dev->slock);
                count = cx_read(VID_A_GPCNT);
                cx23885_video_wakeup(dev, &dev->vidq, count);
                spin_unlock(&dev->slock);
                handled++;
        }
-       /* risc2 y */
-       if (status & 0x10) {
+       if (status & VID_BC_MSK_RISCI2) {
                dprintk(2, "stopper video\n");
                spin_lock(&dev->slock);
                cx23885_restart_video_queue(dev, &dev->vidq);
@@ -1357,6 +1580,9 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
                handled++;
        }
 
+       /* Allow the VBI framework to process it's payload */
+       handled += cx23885_vbi_irq(dev, status);
+
        return handled;
 }
 
@@ -1405,6 +1631,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_g_register    = cx23885_g_register,
        .vidioc_s_register    = cx23885_s_register,
 #endif
+       .vidioc_enumaudio     = vidioc_enum_audinput,
+       .vidioc_g_audio       = vidioc_g_audinput,
+       .vidioc_s_audio       = vidioc_s_audinput,
 };
 
 static struct video_device cx23885_vbi_template;
@@ -1429,6 +1658,14 @@ void cx23885_video_unregister(struct cx23885_dev *dev)
        dprintk(1, "%s()\n", __func__);
        cx23885_irq_remove(dev, 0x01);
 
+       if (dev->vbi_dev) {
+               if (video_is_registered(dev->vbi_dev))
+                       video_unregister_device(dev->vbi_dev);
+               else
+                       video_device_release(dev->vbi_dev);
+               dev->vbi_dev = NULL;
+               btcx_riscmem_free(dev->pci, &dev->vbiq.stopper);
+       }
        if (dev->video_dev) {
                if (video_is_registered(dev->video_dev))
                        video_unregister_device(dev->video_dev);
@@ -1438,6 +1675,9 @@ void cx23885_video_unregister(struct cx23885_dev *dev)
 
                btcx_riscmem_free(dev->pci, &dev->vidq.stopper);
        }
+
+       if (dev->audio_dev)
+               cx23885_audio_unregister(dev);
 }
 
 int cx23885_video_register(struct cx23885_dev *dev)
@@ -1463,7 +1703,14 @@ int cx23885_video_register(struct cx23885_dev *dev)
        cx23885_risc_stopper(dev->pci, &dev->vidq.stopper,
                VID_A_DMA_CTL, 0x11, 0x00);
 
-       /* Don't enable VBI yet */
+       /* init vbi dma queues */
+       INIT_LIST_HEAD(&dev->vbiq.active);
+       INIT_LIST_HEAD(&dev->vbiq.queued);
+       dev->vbiq.timeout.function = cx23885_vbi_timeout;
+       dev->vbiq.timeout.data = (unsigned long)dev;
+       init_timer(&dev->vbiq.timeout);
+       cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper,
+               VID_A_DMA_CTL, 0x22, 0x00);
 
        cx23885_irq_add_enable(dev, 0x01);
 
@@ -1504,8 +1751,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
                }
        }
 
-
-       /* register v4l devices */
+       /* register Video device */
        dev->video_dev = cx23885_vdev_init(dev, dev->pci,
                &cx23885_video_template, "video");
        err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER,
@@ -1515,13 +1761,31 @@ int cx23885_video_register(struct cx23885_dev *dev)
                        dev->name);
                goto fail_unreg;
        }
-       printk(KERN_INFO "%s/0: registered device %s [v4l2]\n",
+       printk(KERN_INFO "%s: registered device %s [v4l2]\n",
               dev->name, video_device_node_name(dev->video_dev));
+
+       /* register VBI device */
+       dev->vbi_dev = cx23885_vdev_init(dev, dev->pci,
+               &cx23885_vbi_template, "vbi");
+       err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+                                   vbi_nr[dev->nr]);
+       if (err < 0) {
+               printk(KERN_INFO "%s: can't register vbi device\n",
+                       dev->name);
+               goto fail_unreg;
+       }
+       printk(KERN_INFO "%s: registered device %s\n",
+              dev->name, video_device_node_name(dev->vbi_dev));
+
+       /* Register ALSA audio device */
+       dev->audio_dev = cx23885_audio_register(dev);
+
        /* initial device configuration */
        mutex_lock(&dev->lock);
        cx23885_set_tvnorm(dev, dev->tvnorm);
        init_controls(dev);
        cx23885_video_mux(dev, 0);
+       cx23885_audio_mux(dev, 0);
        mutex_unlock(&dev->lock);
 
        return 0;
index d86bc0b..b49036f 100644 (file)
@@ -86,6 +86,7 @@
 #define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID     29
 #define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30
 #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31
+#define CX23885_BOARD_MPX885                   32
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
@@ -192,6 +193,7 @@ struct cx23885_buffer {
 struct cx23885_input {
        enum cx23885_itype type;
        unsigned int    vmux;
+       unsigned int    amux;
        u32             gpio0, gpio1, gpio2, gpio3;
 };
 
@@ -318,6 +320,34 @@ struct cx23885_kernel_ir {
        struct rc_dev           *rc;
 };
 
+struct cx23885_audio_buffer {
+       unsigned int            bpl;
+       struct btcx_riscmem     risc;
+       struct videobuf_dmabuf  dma;
+};
+
+struct cx23885_audio_dev {
+       struct cx23885_dev      *dev;
+
+       struct pci_dev          *pci;
+
+       struct snd_card         *card;
+
+       spinlock_t              lock;
+
+       atomic_t                count;
+
+       unsigned int            dma_size;
+       unsigned int            period_size;
+       unsigned int            num_periods;
+
+       struct videobuf_dmabuf  *dma_risc;
+
+       struct cx23885_audio_buffer   *buf;
+
+       struct snd_pcm_substream *substream;
+};
+
 struct cx23885_dev {
        atomic_t                   refcount;
        struct v4l2_device         v4l2_dev;
@@ -362,6 +392,7 @@ struct cx23885_dev {
        /* Analog video */
        u32                        resources;
        unsigned int               input;
+       unsigned int               audinput; /* Selectable audio input */
        u32                        tvaudio;
        v4l2_std_id                tvnorm;
        unsigned int               tuner_type;
@@ -400,6 +431,9 @@ struct cx23885_dev {
        atomic_t                   v4l_reader_count;
        struct cx23885_tvnorm      encodernorm;
 
+       /* Analog raw audio */
+       struct cx23885_audio_dev   *audio_dev;
+
 };
 
 static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev)
@@ -478,6 +512,11 @@ extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
        unsigned int top_offset, unsigned int bottom_offset,
        unsigned int bpl, unsigned int padding, unsigned int lines);
 
+extern int cx23885_risc_vbibuffer(struct pci_dev *pci,
+       struct btcx_riscmem *risc, struct scatterlist *sglist,
+       unsigned int top_offset, unsigned int bottom_offset,
+       unsigned int bpl, unsigned int padding, unsigned int lines);
+
 void cx23885_cancel_buffers(struct cx23885_tsport *port);
 
 extern int cx23885_restart_queue(struct cx23885_tsport *port,
@@ -533,6 +572,8 @@ extern void cx23885_free_buffer(struct videobuf_queue *q,
 extern int cx23885_video_register(struct cx23885_dev *dev);
 extern void cx23885_video_unregister(struct cx23885_dev *dev);
 extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status);
+extern void cx23885_video_wakeup(struct cx23885_dev *dev,
+       struct cx23885_dmaqueue *q, u32 count);
 
 /* ----------------------------------------------------------- */
 /* cx23885-vbi.c                                               */
@@ -540,6 +581,9 @@ extern int cx23885_vbi_fmt(struct file *file, void *priv,
        struct v4l2_format *f);
 extern void cx23885_vbi_timeout(unsigned long data);
 extern struct videobuf_queue_ops cx23885_vbi_qops;
+extern int cx23885_restart_vbi_queue(struct cx23885_dev *dev,
+       struct cx23885_dmaqueue *q);
+extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status);
 
 /* cx23885-i2c.c                                                */
 extern int cx23885_i2c_register(struct cx23885_i2c *bus);
@@ -563,6 +607,18 @@ extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask);
 extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask);
 extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput);
 
+/* ----------------------------------------------------------- */
+/* cx23885-alsa.c                                             */
+extern struct cx23885_audio_dev *cx23885_audio_register(
+                                       struct cx23885_dev *dev);
+extern void cx23885_audio_unregister(struct cx23885_dev *dev);
+extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask);
+extern int cx23885_risc_databuffer(struct pci_dev *pci,
+                                  struct btcx_riscmem *risc,
+                                  struct scatterlist *sglist,
+                                  unsigned int bpl,
+                                  unsigned int lines,
+                                  unsigned int lpi);
 
 /* ----------------------------------------------------------- */
 /* tv norms                                                    */
index e37be6f..bb1ce34 100644 (file)
@@ -673,7 +673,7 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
 
        unsigned int i, n;
        union cx23888_ir_fifo_rec *p;
-       unsigned u, v;
+       unsigned u, v, w;
 
        n = count / sizeof(union cx23888_ir_fifo_rec)
                * sizeof(union cx23888_ir_fifo_rec);
@@ -692,11 +692,12 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
                if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
                        /* Assume RTO was because of no IR light input */
                        u = 0;
-                       v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n");
+                       w = 1;
                } else {
                        u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
                        if (invert)
                                u = u ? 0 : 1;
+                       w = 0;
                }
 
                v = (unsigned) pulse_width_count_to_ns(
@@ -707,9 +708,12 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
                init_ir_raw_event(&p->ir_core_data);
                p->ir_core_data.pulse = u;
                p->ir_core_data.duration = v;
+               p->ir_core_data.timeout = w;
 
-               v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns  %s\n",
-                        v, u ? "mark" : "space");
+               v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns  %s  %s\n",
+                        v, u ? "mark" : "space", w ? "(timed out)" : "");
+               if (w)
+                       v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n");
        }
        return 0;
 }
index 2ee96d3..dc40dde 100644 (file)
@@ -3,4 +3,4 @@ cx25840-objs    := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
 
 obj-$(CONFIG_VIDEO_CX25840) += cx25840.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
+ccflags-y += -Idrivers/media/video
index 34b96c7..005f110 100644 (file)
@@ -480,6 +480,7 @@ void cx25840_audio_set_path(struct i2c_client *client)
 
 static void set_volume(struct i2c_client *client, int volume)
 {
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        int vol;
 
        /* Convert the volume to msp3400 values (0-127) */
@@ -495,7 +496,14 @@ static void set_volume(struct i2c_client *client, int volume)
        }
 
        /* PATH1_VOLUME */
-       cx25840_write(client, 0x8d4, 228 - (vol * 2));
+       if (is_cx2388x(state)) {
+               /* for cx23885 volume doesn't work,
+                * the calculation always results in
+                * e4 regardless.
+                */
+               cx25840_write(client, 0x8d4, volume);
+       } else
+               cx25840_write(client, 0x8d4, 228 - (vol * 2));
 }
 
 static void set_balance(struct i2c_client *client, int balance)
index b7ee2ae..cd99764 100644 (file)
@@ -702,6 +702,13 @@ static void cx231xx_initialize(struct i2c_client *client)
 
        /* start microcontroller */
        cx25840_and_or(client, 0x803, ~0x10, 0x10);
+
+       /* CC raw enable */
+       cx25840_write(client, 0x404, 0x0b);
+
+       /* CC on */
+       cx25840_write(client, 0x42f, 0x66);
+       cx25840_write4(client, 0x474, 0x1e1e601a);
 }
 
 /* ----------------------------------------------------------------------- */
@@ -1067,6 +1074,18 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
                cx25840_write(client, 0x919, 0x01);
        }
 
+       if (is_cx2388x(state) && ((aud_input == CX25840_AUDIO7) ||
+               (aud_input == CX25840_AUDIO6))) {
+               /* Configure audio from LR1 or LR2 input */
+               cx25840_write4(client, 0x910, 0);
+               cx25840_write4(client, 0x8d0, 0x63073);
+       } else
+       if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) {
+               /* Configure audio from tuner/sif input */
+               cx25840_write4(client, 0x910, 0x12b000c9);
+               cx25840_write4(client, 0x8d0, 0x1f063870);
+       }
+
        return 0;
 }
 
index 7eb79af..b718a3a 100644 (file)
@@ -668,7 +668,7 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
        u16 divider;
        unsigned int i, n;
        union cx25840_ir_fifo_rec *p;
-       unsigned u, v;
+       unsigned u, v, w;
 
        if (ir_state == NULL)
                return -ENODEV;
@@ -694,11 +694,12 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
                if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
                        /* Assume RTO was because of no IR light input */
                        u = 0;
-                       v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n");
+                       w = 1;
                } else {
                        u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
                        if (invert)
                                u = u ? 0 : 1;
+                       w = 0;
                }
 
                v = (unsigned) pulse_width_count_to_ns(
@@ -709,9 +710,12 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
                init_ir_raw_event(&p->ir_core_data);
                p->ir_core_data.pulse = u;
                p->ir_core_data.duration = v;
+               p->ir_core_data.timeout = w;
 
-               v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns  %s\n",
-                        v, u ? "mark" : "space");
+               v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns  %s  %s\n",
+                        v, u ? "mark" : "space", w ? "(timed out)" : "");
+               if (w)
+                       v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n");
        }
        return 0;
 }
index 5b7e267..c1a2785 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o
 obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
 obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/video
+ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
index fbcaa1c..fbfdd80 100644 (file)
@@ -636,9 +636,6 @@ int cx88_reset(struct cx88_core *core)
        cx_write(MO_PCI_INTSTAT,   0xFFFFFFFF); // Clear PCI int
        cx_write(MO_INT1_STAT,     0xFFFFFFFF); // Clear RISC int
 
-       /* set default notch filter */
-       cx_andor(MO_HTOTAL, 0x1800, (HLNotchFilter4xFsc << 11));
-
        /* Reset on-board parts */
        cx_write(MO_SRST_IO, 0);
        msleep(10);
index 60d28fd..921c56d 100644 (file)
@@ -266,7 +266,7 @@ static const struct cx88_ctrl cx8800_ctls[] = {
                        .id            = V4L2_CID_BAND_STOP_FILTER,
                        .name          = "Notch filter",
                        .minimum       = 0,
-                       .maximum       = 3,
+                       .maximum       = 1,
                        .step          = 1,
                        .default_value = 0x0,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
index 7f1d83a..8588a86 100644 (file)
@@ -43,7 +43,6 @@
 
 static int debug;
 
-#define VPBE_DISPLAY_SD_BUF_SIZE (720*576*2)
 #define VPBE_DEFAULT_NUM_BUFS 3
 
 module_param(debug, int, 0644);
index 5352884..ceccf43 100644 (file)
@@ -1162,7 +1162,7 @@ static int osd_probe(struct platform_device *pdev)
                goto free_mem;
        }
        osd->osd_base_phys = res->start;
-       osd->osd_size = res->end - res->start + 1;
+       osd->osd_size = resource_size(res);
        if (!request_mem_region(osd->osd_base_phys, osd->osd_size,
                                MODULE_NAME)) {
                dev_err(osd->dev, "Unable to reserve OSD MMIO region\n");
index 281ee42..f6f622e 100644 (file)
@@ -41,6 +41,8 @@ config VIDEO_EM28XX_DVB
        select DVB_CXD2820R if !DVB_FE_CUSTOMISE
        select DVB_DRXK if !DVB_FE_CUSTOMISE
        select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
+       select DVB_TDA10071 if !DVB_FE_CUSTOMISE
+       select DVB_A8293 if !DVB_FE_CUSTOMISE
        select VIDEOBUF_DVB
        ---help---
          This adds support for DVB cards based on the
index 38aaa00..2abdf76 100644 (file)
@@ -9,8 +9,8 @@ obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
 obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
 obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/video
+ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
 
index 3e3959f..4240f0b 100644 (file)
@@ -60,7 +60,7 @@ static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card,     "card type");
 
-/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
+/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */
 static unsigned long em28xx_devused;
 
 struct em28xx_hash_table {
@@ -317,6 +317,25 @@ static struct em28xx_reg_seq terratec_h5_digital[] = {
 };
 #endif
 
+/* 2013:024f PCTV DVB-S2 Stick 460e
+ * GPIO_0 - POWER_ON
+ * GPIO_1 - BOOST
+ * GPIO_2 - VUV_LNB (red LED)
+ * GPIO_3 - EXT_12V
+ * GPIO_4 - INT_DEM (DEMOD GPIO_0)
+ * GPIO_5 - INT_LNB
+ * GPIO_6 - RESET_DEM
+ * GPIO_7 - LED (green LED)
+ */
+static struct em28xx_reg_seq pctv_460e[] = {
+       {EM2874_R80_GPIO, 0x01, 0xff,  50},
+       {0x0d,            0xff, 0xff,  50},
+       {EM2874_R80_GPIO, 0x41, 0xff,  50}, /* GPIO_6=1 */
+       {0x0d,            0x42, 0xff,  50},
+       {EM2874_R80_GPIO, 0x61, 0xff,  50}, /* GPIO_5=1 */
+       {             -1,   -1,   -1,  -1},
+};
+
 /*
  *  Board definitions
  */
@@ -1810,6 +1829,17 @@ struct em28xx_board em28xx_boards[] = {
                .has_dvb       = 1,
                .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
        },
+       /* 2013:024f PCTV DVB-S2 Stick 460e
+        * Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293 */
+       [EM28174_BOARD_PCTV_460E] = {
+               .i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+                       EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+               .name          = "PCTV DVB-S2 Stick (460e)",
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = pctv_460e,
+               .has_dvb       = 1,
+               .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+       },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -1941,6 +1971,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2870_BOARD_KWORLD_A340 },
        { USB_DEVICE(0x2013, 0x024f),
                        .driver_info = EM28174_BOARD_PCTV_290E },
+       { USB_DEVICE(0x2013, 0x024c),
+                       .driver_info = EM28174_BOARD_PCTV_460E },
        { },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2768,9 +2800,9 @@ static void flush_request_modules(struct em28xx *dev)
 #endif /* CONFIG_MODULES */
 
 /*
- * em28xx_realease_resources()
+ * em28xx_release_resources()
  * unregisters the v4l2,i2c and usb devices
- * called when the device gets disconected or at module unload
+ * called when the device gets disconnected or at module unload
 */
 void em28xx_release_resources(struct em28xx *dev)
 {
@@ -2784,8 +2816,6 @@ void em28xx_release_resources(struct em28xx *dev)
 
        em28xx_release_analog_resources(dev);
 
-       em28xx_remove_from_devlist(dev);
-
        em28xx_i2c_unregister(dev);
 
        v4l2_device_unregister(&dev->v4l2_dev);
@@ -2793,7 +2823,7 @@ void em28xx_release_resources(struct em28xx *dev)
        usb_put_dev(dev->udev);
 
        /* Mark device as unused */
-       em28xx_devused &= ~(1 << dev->devno);
+       clear_bit(dev->devno, &em28xx_devused);
 };
 
 /*
@@ -2806,7 +2836,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
 {
        struct em28xx *dev = *devhandle;
        int retval;
-       int errCode;
 
        dev->udev = udev;
        mutex_init(&dev->ctrl_urb_lock);
@@ -2883,10 +2912,9 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        }
 
        if (dev->is_audio_only) {
-               errCode = em28xx_audio_setup(dev);
-               if (errCode)
+               retval = em28xx_audio_setup(dev);
+               if (retval)
                        return -ENODEV;
-               em28xx_add_into_devlist(dev);
                em28xx_init_extension(dev);
 
                return 0;
@@ -2903,7 +2931,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
                /* Resets I2C speed */
                em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
                if (retval < 0) {
-                       em28xx_errdev("%s: em28xx_write_regs_req failed!"
+                       em28xx_errdev("%s: em28xx_write_reg failed!"
                                      " retval [%d]\n",
                                      __func__, retval);
                        return retval;
@@ -2917,12 +2945,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        }
 
        /* register i2c bus */
-       errCode = em28xx_i2c_register(dev);
-       if (errCode < 0) {
-               v4l2_device_unregister(&dev->v4l2_dev);
-               em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n",
-                       __func__, errCode);
-               return errCode;
+       retval = em28xx_i2c_register(dev);
+       if (retval < 0) {
+               em28xx_errdev("%s: em28xx_i2c_register - error [%d]!\n",
+                       __func__, retval);
+               goto unregister_dev;
        }
 
        /*
@@ -2936,11 +2963,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        em28xx_card_setup(dev);
 
        /* Configure audio */
-       errCode = em28xx_audio_setup(dev);
-       if (errCode < 0) {
-               v4l2_device_unregister(&dev->v4l2_dev);
-               em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n",
-                       __func__, errCode);
+       retval = em28xx_audio_setup(dev);
+       if (retval < 0) {
+               em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
+                       __func__, retval);
+               goto fail;
        }
 
        /* wake i2c devices */
@@ -2954,41 +2981,41 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
 
        if (dev->board.has_msp34xx) {
                /* Send a reset to other chips via gpio */
-               errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
-               if (errCode < 0) {
-                       em28xx_errdev("%s: em28xx_write_regs_req - "
-                                     "msp34xx(1) failed! errCode [%d]\n",
-                                     __func__, errCode);
-                       return errCode;
+               retval = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
+               if (retval < 0) {
+                       em28xx_errdev("%s: em28xx_write_reg - "
+                                     "msp34xx(1) failed! error [%d]\n",
+                                     __func__, retval);
+                       goto fail;
                }
                msleep(3);
 
-               errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
-               if (errCode < 0) {
-                       em28xx_errdev("%s: em28xx_write_regs_req - "
-                                     "msp34xx(2) failed! errCode [%d]\n",
-                                     __func__, errCode);
-                       return errCode;
+               retval = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+               if (retval < 0) {
+                       em28xx_errdev("%s: em28xx_write_reg - "
+                                     "msp34xx(2) failed! error [%d]\n",
+                                     __func__, retval);
+                       goto fail;
                }
                msleep(3);
        }
 
-       em28xx_add_into_devlist(dev);
-
        retval = em28xx_register_analog_devices(dev);
        if (retval < 0) {
-               em28xx_release_resources(dev);
-               goto fail_reg_devices;
+               goto fail;
        }
 
-       em28xx_init_extension(dev);
-
        /* Save some power by putting tuner to sleep */
        v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
 
        return 0;
 
-fail_reg_devices:
+fail:
+       em28xx_i2c_unregister(dev);
+
+unregister_dev:
+       v4l2_device_unregister(&dev->v4l2_dev);
+
        return retval;
 }
 
@@ -3015,8 +3042,16 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        udev = usb_get_dev(interface_to_usbdev(interface));
 
        /* Check to see next free device and mark as used */
-       nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
-       em28xx_devused |= 1<<nr;
+       do {
+               nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
+               if (nr >= EM28XX_MAXBOARDS) {
+                       /* No free device slots */
+                       printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
+                                       EM28XX_MAXBOARDS);
+                       retval = -ENOMEM;
+                       goto err_no_slot;
+               }
+       } while (test_and_set_bit(nr, &em28xx_devused));
 
        /* Don't register audio interfaces */
        if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
@@ -3027,7 +3062,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                        ifnum,
                        interface->altsetting[0].desc.bInterfaceClass);
 
-               em28xx_devused &= ~(1<<nr);
                retval = -ENODEV;
                goto err;
        }
@@ -3076,7 +3110,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                                em28xx_err(DRIVER_NAME " This is an anciliary "
                                        "interface not used by the driver\n");
 
-                               em28xx_devused &= ~(1<<nr);
                                retval = -ENODEV;
                                goto err;
                        }
@@ -3132,29 +3165,19 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                printk(DRIVER_NAME ": Device initialization failed.\n");
                printk(DRIVER_NAME ": Device must be connected to a high-speed"
                       " USB 2.0 port.\n");
-               em28xx_devused &= ~(1<<nr);
                retval = -ENODEV;
                goto err;
        }
 
-       if (nr >= EM28XX_MAXBOARDS) {
-               printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
-                               EM28XX_MAXBOARDS);
-               em28xx_devused &= ~(1<<nr);
-               retval = -ENOMEM;
-               goto err;
-       }
-
        /* allocate memory for our device state and initialize it */
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
                em28xx_err(DRIVER_NAME ": out of memory!\n");
-               em28xx_devused &= ~(1<<nr);
                retval = -ENOMEM;
                goto err;
        }
 
-       snprintf(dev->name, 29, "em28xx #%d", nr);
+       snprintf(dev->name, sizeof(dev->name), "em28xx #%d", nr);
        dev->devno = nr;
        dev->model = id->driver_info;
        dev->alt   = -1;
@@ -3177,7 +3200,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 
        if (dev->alt_max_pkt_size == NULL) {
                em28xx_errdev("out of memory!\n");
-               em28xx_devused &= ~(1<<nr);
                kfree(dev);
                retval = -ENOMEM;
                goto err;
@@ -3204,8 +3226,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        mutex_lock(&dev->lock);
        retval = em28xx_init_dev(&dev, udev, interface, nr);
        if (retval) {
-               em28xx_devused &= ~(1<<dev->devno);
                mutex_unlock(&dev->lock);
+               kfree(dev->alt_max_pkt_size);
                kfree(dev);
                goto err;
        }
@@ -3217,15 +3239,26 @@ static int em28xx_usb_probe(struct usb_interface *interface,
         */
        mutex_unlock(&dev->lock);
 
+       /*
+        * These extensions can be modules. If the modules are already
+        * loaded then we can initialise the device now, otherwise we
+        * will initialise it when the modules load instead.
+        */
+       em28xx_init_extension(dev);
+
        return 0;
 
 err:
+       clear_bit(nr, &em28xx_devused);
+
+err_no_slot:
+       usb_put_dev(udev);
        return retval;
 }
 
 /*
  * em28xx_usb_disconnect()
- * called when the device gets diconencted
+ * called when the device gets disconnected
  * video device will be unregistered on v4l2_close in case it is still open
  */
 static void em28xx_usb_disconnect(struct usb_interface *interface)
@@ -3273,10 +3306,10 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
                em28xx_release_resources(dev);
        }
 
-       em28xx_close_extension(dev);
-
        mutex_unlock(&dev->lock);
 
+       em28xx_close_extension(dev);
+
        if (!dev->users) {
                kfree(dev->alt_max_pkt_size);
                kfree(dev);
index 57b1b5c..804a4ab 100644 (file)
@@ -1183,25 +1183,6 @@ void em28xx_wake_i2c(struct em28xx *dev)
 static LIST_HEAD(em28xx_devlist);
 static DEFINE_MUTEX(em28xx_devlist_mutex);
 
-/*
- * em28xx_realease_resources()
- * unregisters the v4l2,i2c and usb devices
- * called when the device gets disconected or at module unload
-*/
-void em28xx_remove_from_devlist(struct em28xx *dev)
-{
-       mutex_lock(&em28xx_devlist_mutex);
-       list_del(&dev->devlist);
-       mutex_unlock(&em28xx_devlist_mutex);
-};
-
-void em28xx_add_into_devlist(struct em28xx *dev)
-{
-       mutex_lock(&em28xx_devlist_mutex);
-       list_add_tail(&dev->devlist, &em28xx_devlist);
-       mutex_unlock(&em28xx_devlist_mutex);
-};
-
 /*
  * Extension interface
  */
@@ -1217,8 +1198,8 @@ int em28xx_register_extension(struct em28xx_ops *ops)
        list_for_each_entry(dev, &em28xx_devlist, devlist) {
                ops->init(dev);
        }
-       printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
        mutex_unlock(&em28xx_devlist_mutex);
+       printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
        return 0;
 }
 EXPORT_SYMBOL(em28xx_register_extension);
@@ -1231,36 +1212,34 @@ void em28xx_unregister_extension(struct em28xx_ops *ops)
        list_for_each_entry(dev, &em28xx_devlist, devlist) {
                ops->fini(dev);
        }
-       printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
        list_del(&ops->next);
        mutex_unlock(&em28xx_devlist_mutex);
+       printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
 }
 EXPORT_SYMBOL(em28xx_unregister_extension);
 
 void em28xx_init_extension(struct em28xx *dev)
 {
-       struct em28xx_ops *ops = NULL;
+       const struct em28xx_ops *ops = NULL;
 
        mutex_lock(&em28xx_devlist_mutex);
-       if (!list_empty(&em28xx_extension_devlist)) {
-               list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-                       if (ops->init)
-                               ops->init(dev);
-               }
+       list_add_tail(&dev->devlist, &em28xx_devlist);
+       list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+               if (ops->init)
+                       ops->init(dev);
        }
        mutex_unlock(&em28xx_devlist_mutex);
 }
 
 void em28xx_close_extension(struct em28xx *dev)
 {
-       struct em28xx_ops *ops = NULL;
+       const struct em28xx_ops *ops = NULL;
 
        mutex_lock(&em28xx_devlist_mutex);
-       if (!list_empty(&em28xx_extension_devlist)) {
-               list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-                       if (ops->fini)
-                               ops->fini(dev);
-               }
+       list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+               if (ops->fini)
+                       ops->fini(dev);
        }
+       list_del(&dev->devlist);
        mutex_unlock(&em28xx_devlist_mutex);
 }
index e5916de..cef7a2d 100644 (file)
@@ -42,6 +42,8 @@
 #include "cxd2820r.h"
 #include "tda18271c2dd.h"
 #include "drxk.h"
+#include "tda10071.h"
+#include "a8293.h"
 
 MODULE_DESCRIPTION("driver for em28xx based DVB cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -122,7 +124,7 @@ static inline void print_err_status(struct em28xx *dev,
        }
 }
 
-static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
+static inline int em28xx_dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
 {
        int i;
 
@@ -155,7 +157,7 @@ static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
        return 0;
 }
 
-static int start_streaming(struct em28xx_dvb *dvb)
+static int em28xx_start_streaming(struct em28xx_dvb *dvb)
 {
        int rc;
        struct em28xx *dev = dvb->adapter.priv;
@@ -175,10 +177,10 @@ static int start_streaming(struct em28xx_dvb *dvb)
 
        return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
                                EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
-                               dvb_isoc_copy);
+                               em28xx_dvb_isoc_copy);
 }
 
-static int stop_streaming(struct em28xx_dvb *dvb)
+static int em28xx_stop_streaming(struct em28xx_dvb *dvb)
 {
        struct em28xx *dev = dvb->adapter.priv;
 
@@ -189,7 +191,7 @@ static int stop_streaming(struct em28xx_dvb *dvb)
        return 0;
 }
 
-static int start_feed(struct dvb_demux_feed *feed)
+static int em28xx_start_feed(struct dvb_demux_feed *feed)
 {
        struct dvb_demux *demux  = feed->demux;
        struct em28xx_dvb *dvb = demux->priv;
@@ -203,7 +205,7 @@ static int start_feed(struct dvb_demux_feed *feed)
        rc = dvb->nfeeds;
 
        if (dvb->nfeeds == 1) {
-               ret = start_streaming(dvb);
+               ret = em28xx_start_streaming(dvb);
                if (ret < 0)
                        rc = ret;
        }
@@ -212,7 +214,7 @@ static int start_feed(struct dvb_demux_feed *feed)
        return rc;
 }
 
-static int stop_feed(struct dvb_demux_feed *feed)
+static int em28xx_stop_feed(struct dvb_demux_feed *feed)
 {
        struct dvb_demux *demux  = feed->demux;
        struct em28xx_dvb *dvb = demux->priv;
@@ -222,7 +224,7 @@ static int stop_feed(struct dvb_demux_feed *feed)
        dvb->nfeeds--;
 
        if (0 == dvb->nfeeds)
-               err = stop_streaming(dvb);
+               err = em28xx_stop_streaming(dvb);
 
        mutex_unlock(&dvb->lock);
        return err;
@@ -380,7 +382,7 @@ static void terratec_h5_init(struct em28xx *dev)
        em28xx_gpio_set(dev, terratec_h5_end);
 };
 
-static int mt352_terratec_xs_init(struct dvb_frontend *fe)
+static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe)
 {
        /* Values extracted from a USB trace of the Terratec Windows driver */
        static u8 clock_config[]   = { CLOCK_CTL,  0x38, 0x2c };
@@ -412,7 +414,7 @@ static struct mt352_config terratec_xs_mt352_cfg = {
        .demod_address = (0x1e >> 1),
        .no_tuner = 1,
        .if2 = 45600,
-       .demod_init = mt352_terratec_xs_init,
+       .demod_init = em28xx_mt352_terratec_xs_init,
 };
 
 static struct tda10023_config em28xx_tda10023_config = {
@@ -438,11 +440,25 @@ static struct cxd2820r_config em28xx_cxd2820r_config = {
 
 static struct tda18271_config em28xx_cxd2820r_tda18271_config = {
        .output_opt = TDA18271_OUTPUT_LT_OFF,
+       .gate = TDA18271_GATE_DIGITAL,
+};
+
+static const struct tda10071_config em28xx_tda10071_config = {
+       .i2c_address = 0x55, /* (0xaa >> 1) */
+       .i2c_wr_max = 64,
+       .ts_mode = TDA10071_TS_SERIAL,
+       .spec_inv = 0,
+       .xtal = 40444000, /* 40.444 MHz */
+       .pll_multiplier = 20,
+};
+
+static const struct a8293_config em28xx_a8293_config = {
+       .i2c_addr = 0x08, /* (0x10 >> 1) */
 };
 
 /* ------------------------------------------------------------------ */
 
-static int attach_xc3028(u8 addr, struct em28xx *dev)
+static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
 {
        struct dvb_frontend *fe;
        struct xc2028_config cfg;
@@ -472,10 +488,8 @@ static int attach_xc3028(u8 addr, struct em28xx *dev)
 
 /* ------------------------------------------------------------------ */
 
-static int register_dvb(struct em28xx_dvb *dvb,
-                struct module *module,
-                struct em28xx *dev,
-                struct device *device)
+static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module,
+                              struct em28xx *dev, struct device *device)
 {
        int result;
 
@@ -522,8 +536,8 @@ static int register_dvb(struct em28xx_dvb *dvb,
        dvb->demux.priv       = dvb;
        dvb->demux.filternum  = 256;
        dvb->demux.feednum    = 256;
-       dvb->demux.start_feed = start_feed;
-       dvb->demux.stop_feed  = stop_feed;
+       dvb->demux.start_feed = em28xx_start_feed;
+       dvb->demux.stop_feed  = em28xx_stop_feed;
 
        result = dvb_dmx_init(&dvb->demux);
        if (result < 0) {
@@ -591,7 +605,7 @@ fail_adapter:
        return result;
 }
 
-static void unregister_dvb(struct em28xx_dvb *dvb)
+static void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
 {
        dvb_net_release(&dvb->net);
        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
@@ -607,9 +621,9 @@ static void unregister_dvb(struct em28xx_dvb *dvb)
        dvb_unregister_adapter(&dvb->adapter);
 }
 
-static int dvb_init(struct em28xx *dev)
+static int em28xx_dvb_init(struct em28xx *dev)
 {
-       int result = 0;
+       int result = 0, mfe_shared = 0;
        struct em28xx_dvb *dvb;
 
        if (!dev->board.has_dvb) {
@@ -648,7 +662,7 @@ static int dvb_init(struct em28xx *dev)
                dvb->fe[0] = dvb_attach(lgdt330x_attach,
                                           &em2880_lgdt3303_dev,
                                           &dev->i2c_adap);
-               if (attach_xc3028(0x61, dev) < 0) {
+               if (em28xx_attach_xc3028(0x61, dev) < 0) {
                        result = -EINVAL;
                        goto out_free;
                }
@@ -657,7 +671,7 @@ static int dvb_init(struct em28xx *dev)
                dvb->fe[0] = dvb_attach(zl10353_attach,
                                           &em28xx_zl10353_with_xc3028,
                                           &dev->i2c_adap);
-               if (attach_xc3028(0x61, dev) < 0) {
+               if (em28xx_attach_xc3028(0x61, dev) < 0) {
                        result = -EINVAL;
                        goto out_free;
                }
@@ -668,7 +682,7 @@ static int dvb_init(struct em28xx *dev)
                dvb->fe[0] = dvb_attach(zl10353_attach,
                                           &em28xx_zl10353_xc3028_no_i2c_gate,
                                           &dev->i2c_adap);
-               if (attach_xc3028(0x61, dev) < 0) {
+               if (em28xx_attach_xc3028(0x61, dev) < 0) {
                        result = -EINVAL;
                        goto out_free;
                }
@@ -689,7 +703,7 @@ static int dvb_init(struct em28xx *dev)
                                                   &dev->i2c_adap);
                }
 
-               if (attach_xc3028(0x61, dev) < 0) {
+               if (em28xx_attach_xc3028(0x61, dev) < 0) {
                        result = -EINVAL;
                        goto out_free;
                }
@@ -699,7 +713,7 @@ static int dvb_init(struct em28xx *dev)
                dvb->fe[0] = dvb_attach(s5h1409_attach,
                                           &em28xx_s5h1409_with_xc3028,
                                           &dev->i2c_adap);
-               if (attach_xc3028(0x61, dev) < 0) {
+               if (em28xx_attach_xc3028(0x61, dev) < 0) {
                        result = -EINVAL;
                        goto out_free;
                }
@@ -720,7 +734,7 @@ static int dvb_init(struct em28xx *dev)
        case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
                dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL,
                                           &dev->i2c_adap, &dev->udev->dev);
-               if (attach_xc3028(0x61, dev) < 0) {
+               if (em28xx_attach_xc3028(0x61, dev) < 0) {
                        result = -EINVAL;
                        goto out_free;
                }
@@ -753,11 +767,9 @@ static int dvb_init(struct em28xx *dev)
                dvb->fe[0] = dvb_attach(cxd2820r_attach,
                        &em28xx_cxd2820r_config, &dev->i2c_adap, NULL);
                if (dvb->fe[0]) {
-                       struct i2c_adapter *i2c_tuner;
-                       i2c_tuner = cxd2820r_get_tuner_i2c_adapter(dvb->fe[0]);
                        /* FE 0 attach tuner */
                        if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
-                               i2c_tuner, &em28xx_cxd2820r_tda18271_config)) {
+                               &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) {
                                dvb_frontend_detach(dvb->fe[0]);
                                result = -EINVAL;
                                goto out_free;
@@ -768,10 +780,12 @@ static int dvb_init(struct em28xx *dev)
                        dvb->fe[1]->id = 1;
                        /* FE 1 attach tuner */
                        if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60,
-                               i2c_tuner, &em28xx_cxd2820r_tda18271_config)) {
+                               &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) {
                                dvb_frontend_detach(dvb->fe[1]);
                                /* leave FE 0 still active */
                        }
+
+                       mfe_shared = 1;
                }
                break;
        case EM2884_BOARD_TERRATEC_H5:
@@ -809,6 +823,16 @@ static int dvb_init(struct em28xx *dev)
                       sizeof(dvb->fe[0]->ops.tuner_ops));
 
                break;
+       case EM28174_BOARD_PCTV_460E:
+               /* attach demod */
+               dvb->fe[0] = dvb_attach(tda10071_attach,
+                       &em28xx_tda10071_config, &dev->i2c_adap);
+
+               /* attach SEC */
+               if (dvb->fe[0])
+                       dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap,
+                               &em28xx_a8293_config);
+               break;
        default:
                em28xx_errdev("/2: The frontend of your DVB/ATSC card"
                                " isn't supported yet\n");
@@ -823,11 +847,14 @@ static int dvb_init(struct em28xx *dev)
        dvb->fe[0]->callback = em28xx_tuner_callback;
 
        /* register everything */
-       result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
+       result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
 
        if (result < 0)
                goto out_free;
 
+       /* MFE lock */
+       dvb->adapter.mfe_shared = mfe_shared;
+
        em28xx_info("Successfully loaded em28xx-dvb\n");
 ret:
        em28xx_set_mode(dev, EM28XX_SUSPEND);
@@ -840,7 +867,14 @@ out_free:
        goto ret;
 }
 
-static int dvb_fini(struct em28xx *dev)
+static inline void prevent_sleep(struct dvb_frontend_ops *ops)
+{
+       ops->set_voltage = NULL;
+       ops->sleep = NULL;
+       ops->tuner_ops.sleep = NULL;
+}
+
+static int em28xx_dvb_fini(struct em28xx *dev)
 {
        if (!dev->board.has_dvb) {
                /* This device does not support the extension */
@@ -848,8 +882,19 @@ static int dvb_fini(struct em28xx *dev)
        }
 
        if (dev->dvb) {
-               unregister_dvb(dev->dvb);
-               kfree(dev->dvb);
+               struct em28xx_dvb *dvb = dev->dvb;
+
+               if (dev->state & DEV_DISCONNECTED) {
+                       /* We cannot tell the device to sleep
+                        * once it has been unplugged. */
+                       if (dvb->fe[0])
+                               prevent_sleep(&dvb->fe[0]->ops);
+                       if (dvb->fe[1])
+                               prevent_sleep(&dvb->fe[1]->ops);
+               }
+
+               em28xx_unregister_dvb(dvb);
+               kfree(dvb);
                dev->dvb = NULL;
        }
 
@@ -859,8 +904,8 @@ static int dvb_fini(struct em28xx *dev)
 static struct em28xx_ops dvb_ops = {
        .id   = EM28XX_DVB,
        .name = "Em28xx dvb Extension",
-       .init = dvb_init,
-       .fini = dvb_fini,
+       .init = em28xx_dvb_init,
+       .fini = em28xx_dvb_fini,
 };
 
 static int __init em28xx_dvb_register(void)
index 5d12b14..679da48 100644 (file)
@@ -463,11 +463,11 @@ int em28xx_ir_fini(struct em28xx *dev)
        if (!ir)
                return 0;
 
-       em28xx_ir_stop(ir->rc);
-       rc_unregister_device(ir->rc);
-       kfree(ir);
+       if (ir->rc)
+               rc_unregister_device(ir->rc);
 
        /* done */
+       kfree(ir);
        dev->ir = NULL;
        return 0;
 }
index d176dc0..9b4557a 100644 (file)
@@ -1156,6 +1156,21 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
        return 0;
 }
 
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
+{
+       struct em28xx_fh   *fh  = priv;
+       struct em28xx      *dev = fh->dev;
+       int                rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm);
+
+       return 0;
+}
+
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
 {
        struct em28xx_fh   *fh  = priv;
@@ -1787,6 +1802,45 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
        return 0;
 }
 
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+                                 struct v4l2_frmsizeenum *fsize)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       struct em28xx_fmt     *fmt;
+       unsigned int          maxw = norm_maxw(dev);
+       unsigned int          maxh = norm_maxh(dev);
+
+       fmt = format_by_fourcc(fsize->pixel_format);
+       if (!fmt) {
+               em28xx_videodbg("Fourcc format (%08x) invalid.\n",
+                               fsize->pixel_format);
+               return -EINVAL;
+       }
+
+       if (dev->board.is_em2800) {
+               if (fsize->index > 1)
+                       return -EINVAL;
+               fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+               fsize->discrete.width = maxw / (1 + fsize->index);
+               fsize->discrete.height = maxh / (1 + fsize->index);
+               return 0;
+       }
+
+       if (fsize->index != 0)
+               return -EINVAL;
+
+       /* Report a continuous range */
+       fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+       fsize->stepwise.min_width = 48;
+       fsize->stepwise.min_height = 32;
+       fsize->stepwise.max_width = maxw;
+       fsize->stepwise.max_height = maxh;
+       fsize->stepwise.step_width = 1;
+       fsize->stepwise.step_height = 1;
+       return 0;
+}
+
 /* Sliced VBI ioctls */
 static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
@@ -2200,6 +2254,7 @@ static int em28xx_v4l2_close(struct file *filp)
                   free the remaining resources */
                if (dev->state & DEV_DISCONNECTED) {
                        em28xx_release_resources(dev);
+                       kfree(dev->alt_max_pkt_size);
                        kfree(dev);
                        return 0;
                }
@@ -2340,10 +2395,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_s_fmt_vid_cap       = vidioc_s_fmt_vid_cap,
        .vidioc_g_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
        .vidioc_s_fmt_vbi_cap       = vidioc_s_fmt_vbi_cap,
+       .vidioc_enum_framesizes     = vidioc_enum_framesizes,
        .vidioc_g_audio             = vidioc_g_audio,
        .vidioc_s_audio             = vidioc_s_audio,
        .vidioc_cropcap             = vidioc_cropcap,
-
        .vidioc_g_fmt_sliced_vbi_cap   = vidioc_g_fmt_sliced_vbi_cap,
        .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
        .vidioc_s_fmt_sliced_vbi_cap   = vidioc_try_set_sliced_vbi_cap,
@@ -2353,6 +2408,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_qbuf                = vidioc_qbuf,
        .vidioc_dqbuf               = vidioc_dqbuf,
        .vidioc_g_std               = vidioc_g_std,
+       .vidioc_querystd            = vidioc_querystd,
        .vidioc_s_std               = vidioc_s_std,
        .vidioc_g_parm              = vidioc_g_parm,
        .vidioc_s_parm              = vidioc_s_parm,
index d80658b..2a2cb7e 100644 (file)
 #define EM2874_BOARD_LEADERSHIP_ISDBT            77
 #define EM28174_BOARD_PCTV_290E                   78
 #define EM2884_BOARD_TERRATEC_H5                 79
+#define EM28174_BOARD_PCTV_460E                   80
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -677,8 +678,6 @@ int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
 int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
 int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
 void em28xx_wake_i2c(struct em28xx *dev);
-void em28xx_remove_from_devlist(struct em28xx *dev);
-void em28xx_add_into_devlist(struct em28xx *dev);
 int em28xx_register_extension(struct em28xx_ops *dev);
 void em28xx_unregister_extension(struct em28xx_ops *dev);
 void em28xx_init_extension(struct em28xx *dev);
index 14bb907..337ded4 100644 (file)
@@ -165,45 +165,49 @@ et61x251_attach_sensor(struct et61x251_device* cam,
 #undef DBG
 #undef KDBG
 #ifdef ET61X251_DEBUG
-#      define DBG(level, fmt, args...)                                       \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1)                                             \
-                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
-               else if ((level) == 2)                                        \
-                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
-               else if ((level) >= 3)                                        \
-                       dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",   \
-                                __FILE__, __func__, __LINE__ , ## args); \
-       }                                                                     \
+#define DBG(level, fmt, ...)                                           \
+do {                                                                   \
+       if (debug >= (level)) {                                         \
+               if ((level) == 1)                                       \
+                       dev_err(&cam->usbdev->dev, fmt "\n",            \
+                               ##__VA_ARGS__);                         \
+               else if ((level) == 2)                                  \
+                       dev_info(&cam->usbdev->dev, fmt "\n",           \
+                                ##__VA_ARGS__);                        \
+               else if ((level) >= 3)                                  \
+                       dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
+                                __FILE__, __func__, __LINE__,          \
+                                ##__VA_ARGS__);                        \
+       }                                                               \
 } while (0)
-#      define KDBG(level, fmt, args...)                                      \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1 || (level) == 2)                             \
-                       pr_info("et61x251: " fmt "\n", ## args);              \
-               else if ((level) == 3)                                        \
-                       pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__,   \
-                                __func__, __LINE__ , ## args);           \
-       }                                                                     \
+#define KDBG(level, fmt, ...)                                          \
+do {                                                                   \
+       if (debug >= (level)) {                                         \
+               if ((level) == 1 || (level) == 2)                       \
+                       pr_info(fmt "\n", ##__VA_ARGS__);               \
+               else if ((level) == 3)                                  \
+                       pr_debug("[%s:%s:%d] " fmt "\n",                \
+                                __FILE__,  __func__, __LINE__,         \
+                                ##__VA_ARGS__);                        \
+       }                                                               \
 } while (0)
-#      define V4LDBG(level, name, cmd)                                       \
-do {                                                                          \
-       if (debug >= (level))                                                 \
-               v4l_print_ioctl(name, cmd);                                   \
+#define V4LDBG(level, name, cmd)                                       \
+do {                                                                   \
+       if (debug >= (level))                                           \
+               v4l_print_ioctl(name, cmd);                             \
 } while (0)
 #else
-#      define DBG(level, fmt, args...) do {;} while(0)
-#      define KDBG(level, fmt, args...) do {;} while(0)
-#      define V4LDBG(level, name, cmd) do {;} while(0)
+#define DBG(level, fmt, ...) do {;} while(0)
+#define KDBG(level, fmt, ...) do {;} while(0)
+#define V4LDBG(level, name, cmd) do {;} while(0)
 #endif
 
 #undef PDBG
-#define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__,   \
-        __LINE__ , ## args)
+#define PDBG(fmt, ...)                                                 \
+       dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",             \
+                __FILE__, __func__, __LINE__, ##__VA_ARGS__)
 
 #undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+#define PDBGG(fmt, args...) do {;} while (0) /* placeholder */
 
 #endif /* _ET61X251_H_ */
index 9a1e80a..d3777c8 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
  ***************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
index 04b7fbb..ced2e16 100644 (file)
@@ -19,6 +19,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
  ***************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "et61x251_sensor.h"
 
 
index 43d9a20..103af3f 100644 (file)
@@ -356,6 +356,16 @@ config USB_GSPCA_T613
          To compile this driver as a module, choose M here: the
          module will be called gspca_t613.
 
+config USB_GSPCA_TOPRO
+       tristate "TOPRO USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for cameras based on the
+         TP6800 and TP6810 Topro chips.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_topro.
+
 config USB_GSPCA_TV8532
        tristate "TV8532 USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
index d6364a8..f345f49 100644 (file)
@@ -35,6 +35,7 @@ obj-$(CONFIG_USB_GSPCA_SUNPLUS)  += gspca_sunplus.o
 obj-$(CONFIG_USB_GSPCA_STK014)   += gspca_stk014.o
 obj-$(CONFIG_USB_GSPCA_STV0680)  += gspca_stv0680.o
 obj-$(CONFIG_USB_GSPCA_T613)     += gspca_t613.o
+obj-$(CONFIG_USB_GSPCA_TOPRO)    += gspca_topro.o
 obj-$(CONFIG_USB_GSPCA_TV8532)   += gspca_tv8532.o
 obj-$(CONFIG_USB_GSPCA_VC032X)   += gspca_vc032x.o
 obj-$(CONFIG_USB_GSPCA_VICAM)    += gspca_vicam.o
@@ -78,6 +79,7 @@ gspca_stk014-objs   := stk014.o
 gspca_stv0680-objs  := stv0680.o
 gspca_sunplus-objs  := sunplus.o
 gspca_t613-objs     := t613.o
+gspca_topro-objs    := topro.o
 gspca_tv8532-objs   := tv8532.o
 gspca_vc032x-objs   := vc032x.o
 gspca_vicam-objs    := vicam.o
index a09c470..6ae2616 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "benq"
 
 #include "gspca.h"
@@ -62,7 +64,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        0,
                        500);
        if (ret < 0) {
-               err("reg_w err %d", ret);
+               pr_err("reg_w err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -84,20 +86,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static int sd_isoc_init(struct gspca_dev *gspca_dev)
-{
-       int ret;
-
-       ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface,
-               gspca_dev->nbalt - 1);
-       if (ret < 0) {
-               err("usb_set_interface failed");
-               return ret;
-       }
-/*     reg_w(gspca_dev, 0x0003, 0x0002); */
-       return 0;
-}
-
 /* -- start the camera -- */
 static int sd_start(struct gspca_dev *gspca_dev)
 {
@@ -113,7 +101,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        for (n = 0; n < 4; n++) {
                urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL);
                if (!urb) {
-                       err("usb_alloc_urb failed");
+                       pr_err("usb_alloc_urb failed\n");
                        return -ENOMEM;
                }
                gspca_dev->urb[n] = urb;
@@ -123,7 +111,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                                                &urb->transfer_dma);
 
                if (urb->transfer_buffer == NULL) {
-                       err("usb_alloc_coherent failed");
+                       pr_err("usb_alloc_coherent failed\n");
                        return -ENOMEM;
                }
                urb->dev = gspca_dev->dev;
@@ -181,7 +169,7 @@ static void sd_isoc_irq(struct urb *urb)
                if (gspca_dev->frozen)
                        return;
 #endif
-               err("urb status: %d", urb->status);
+               pr_err("urb status: %d\n", urb->status);
                return;
        }
 
@@ -209,7 +197,7 @@ static void sd_isoc_irq(struct urb *urb)
                if (st == 0)
                        st = urb->iso_frame_desc[i].status;
                if (st) {
-                       err("ISOC data error: [%d] status=%d",
+                       pr_err("ISOC data error: [%d] status=%d\n",
                                i, st);
                        gspca_dev->last_packet_type = DISCARD_PACKET;
                        continue;
@@ -256,10 +244,10 @@ static void sd_isoc_irq(struct urb *urb)
        /* resubmit the URBs */
        st = usb_submit_urb(urb0, GFP_ATOMIC);
        if (st < 0)
-               err("usb_submit_urb(0) ret %d", st);
+               pr_err("usb_submit_urb(0) ret %d\n", st);
        st = usb_submit_urb(urb, GFP_ATOMIC);
        if (st < 0)
-               err("usb_submit_urb() ret %d", st);
+               pr_err("usb_submit_urb() ret %d\n", st);
 }
 
 /* sub-driver description */
@@ -269,7 +257,6 @@ static const struct sd_desc sd_desc = {
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
        .init = sd_init,
-       .isoc_init = sd_isoc_init,
        .start = sd_start,
        .stopN = sd_stopN,
        .pkt_scan = sd_pkt_scan,
index 8b39849..4c56dbe 100644 (file)
@@ -19,6 +19,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "conex"
 
 #include "gspca.h"
@@ -129,7 +131,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
 
 #ifdef GSPCA_DEBUG
        if (len > USB_BUF_SZ) {
-               err("reg_r: buffer overflow");
+               pr_err("reg_r: buffer overflow\n");
                return;
        }
 #endif
@@ -169,7 +171,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
 
 #ifdef GSPCA_DEBUG
        if (len > USB_BUF_SZ) {
-               err("reg_w: buffer overflow");
+               pr_err("reg_w: buffer overflow\n");
                return;
        }
        PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
index f2a9451..f9b86b2 100644 (file)
@@ -26,6 +26,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "cpia1"
 
 #include <linux/input.h>
@@ -550,8 +552,7 @@ retry:
                              gspca_dev->usb_buf, databytes, 1000);
 
        if (ret < 0)
-               err("usb_control_msg %02x, error %d", command[1],
-                      ret);
+               pr_err("usb_control_msg %02x, error %d\n", command[1], ret);
 
        if (ret == -EPIPE && retries > 0) {
                retries--;
@@ -1279,7 +1280,7 @@ static void monitor_exposure(struct gspca_dev *gspca_dev)
        cmd[7] = 0;
        ret = cpia_usb_transferCmd(gspca_dev, cmd);
        if (ret) {
-               err("ReadVPRegs(30,4,9,8) - failed: %d", ret);
+               pr_err("ReadVPRegs(30,4,9,8) - failed: %d\n", ret);
                return;
        }
        exp_acc = gspca_dev->usb_buf[0];
index 4b2c483..0357d6d 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "etoms"
 
 #include "gspca.h"
@@ -236,7 +238,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
 
 #ifdef GSPCA_DEBUG
        if (len > USB_BUF_SZ) {
-               err("reg_r: buffer overflow");
+               pr_err("reg_r: buffer overflow\n");
                return;
        }
 #endif
@@ -274,7 +276,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
 
 #ifdef GSPCA_DEBUG
        if (len > USB_BUF_SZ) {
-               err("reg_w: buffer overflow");
+               pr_err("reg_w: buffer overflow\n");
                return;
        }
        PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
index 987b4b6..ea48200 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "finepix"
 
 #include "gspca.h"
@@ -182,7 +184,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        /* Init the device */
        ret = command(gspca_dev, 0);
        if (ret < 0) {
-               err("init failed %d", ret);
+               pr_err("init failed %d\n", ret);
                return ret;
        }
 
@@ -194,14 +196,14 @@ static int sd_start(struct gspca_dev *gspca_dev)
                        FPIX_MAX_TRANSFER, &len,
                        FPIX_TIMEOUT);
        if (ret < 0) {
-               err("usb_bulk_msg failed %d", ret);
+               pr_err("usb_bulk_msg failed %d\n", ret);
                return ret;
        }
 
        /* Request a frame, but don't read it */
        ret = command(gspca_dev, 1);
        if (ret < 0) {
-               err("frame request failed %d", ret);
+               pr_err("frame request failed %d\n", ret);
                return ret;
        }
 
index 13c9403..f511ecc 100644 (file)
@@ -6,5 +6,5 @@ gspca_gl860-objs := gl860.o \
                    gl860-ov9655.o \
                    gl860-mi2020.o
 
-EXTRA_CFLAGS += -Idrivers/media/video/gspca
+ccflags-y += -Idrivers/media/video/gspca
 
index e8e071a..2ced3b7 100644 (file)
@@ -18,6 +18,9 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "gspca.h"
 #include "gl860.h"
 
@@ -572,9 +575,8 @@ int gl860_RTx(struct gspca_dev *gspca_dev,
        }
 
        if (r < 0)
-               err("ctrl transfer failed %4d "
-                       "[p%02x r%d v%04x i%04x len%d]",
-                       r, pref, req, val, index, len);
+               pr_err("ctrl transfer failed %4d [p%02x r%d v%04x i%04x len%d]\n",
+                      r, pref, req, val, index, len);
        else if (len > 1 && r < len)
                PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len);
 
index 5da4879..881e04c 100644 (file)
@@ -21,7 +21,9 @@
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define MODULE_NAME "gspca"
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define GSPCA_VERSION  "2.14.0"
 
 #include <linux/init.h>
 #include <linux/fs.h>
 #error "DEF_NURBS too big"
 #endif
 
-#define DRIVER_VERSION_NUMBER  "2.13.0"
-
 MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION_NUMBER);
+MODULE_VERSION(GSPCA_VERSION);
 
 #ifdef GSPCA_DEBUG
 int gspca_debug = D_ERR | D_PROBE;
@@ -148,7 +148,7 @@ static void int_irq(struct urb *urb)
        if (ret == 0) {
                ret = usb_submit_urb(urb, GFP_ATOMIC);
                if (ret < 0)
-                       err("Resubmit URB failed with error %i", ret);
+                       pr_err("Resubmit URB failed with error %i\n", ret);
        }
 }
 
@@ -177,8 +177,8 @@ static int gspca_input_connect(struct gspca_dev *dev)
 
                err = input_register_device(input_dev);
                if (err) {
-                       err("Input device registration failed with error %i",
-                               err);
+                       pr_err("Input device registration failed with error %i\n",
+                              err);
                        input_dev->dev.parent = NULL;
                        input_free_device(input_dev);
                } else {
@@ -323,8 +323,8 @@ static void fill_frame(struct gspca_dev *gspca_dev,
                /* check the packet status and length */
                st = urb->iso_frame_desc[i].status;
                if (st) {
-                       err("ISOC data error: [%d] len=%d, status=%d",
-                               i, len, st);
+                       pr_err("ISOC data error: [%d] len=%d, status=%d\n",
+                              i, len, st);
                        gspca_dev->last_packet_type = DISCARD_PACKET;
                        continue;
                }
@@ -346,7 +346,7 @@ resubmit:
        /* resubmit the URB */
        st = usb_submit_urb(urb, GFP_ATOMIC);
        if (st < 0)
-               err("usb_submit_urb() ret %d", st);
+               pr_err("usb_submit_urb() ret %d\n", st);
 }
 
 /*
@@ -400,7 +400,7 @@ resubmit:
        if (gspca_dev->cam.bulk_nurbs != 0) {
                st = usb_submit_urb(urb, GFP_ATOMIC);
                if (st < 0)
-                       err("usb_submit_urb() ret %d", st);
+                       pr_err("usb_submit_urb() ret %d\n", st);
        }
 }
 
@@ -464,7 +464,7 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
                } else {
 /* !! image is NULL only when last pkt is LAST or DISCARD
                        if (gspca_dev->image == NULL) {
-                               err("gspca_frame_add() image == NULL");
+                               pr_err("gspca_frame_add() image == NULL\n");
                                return;
                        }
  */
@@ -497,19 +497,6 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
 }
 EXPORT_SYMBOL(gspca_frame_add);
 
-static int gspca_is_compressed(__u32 format)
-{
-       switch (format) {
-       case V4L2_PIX_FMT_MJPEG:
-       case V4L2_PIX_FMT_JPEG:
-       case V4L2_PIX_FMT_SPCA561:
-       case V4L2_PIX_FMT_PAC207:
-       case V4L2_PIX_FMT_MR97310A:
-               return 1;
-       }
-       return 0;
-}
-
 static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file,
                        enum v4l2_memory memory, unsigned int count)
 {
@@ -525,7 +512,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file,
                count = GSPCA_MAX_FRAMES - 1;
        gspca_dev->frbuf = vmalloc_32(frsz * count);
        if (!gspca_dev->frbuf) {
-               err("frame alloc failed");
+               pr_err("frame alloc failed\n");
                return -ENOMEM;
        }
        gspca_dev->capt_file = file;
@@ -597,7 +584,7 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
                return 0;
        ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
        if (ret < 0)
-               err("set alt 0 err %d", ret);
+               pr_err("set alt 0 err %d\n", ret);
        return ret;
 }
 
@@ -640,53 +627,104 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
        return NULL;
 }
 
+/* compute the minimum bandwidth for the current transfer */
+static u32 which_bandwidth(struct gspca_dev *gspca_dev)
+{
+       u32 bandwidth;
+       int i;
+
+       i = gspca_dev->curr_mode;
+       bandwidth = gspca_dev->cam.cam_mode[i].sizeimage;
+
+       /* if the image is compressed, estimate the mean image size */
+       if (bandwidth < gspca_dev->cam.cam_mode[i].width *
+                               gspca_dev->cam.cam_mode[i].height)
+               bandwidth /= 3;
+
+       /* estimate the frame rate */
+       if (gspca_dev->sd_desc->get_streamparm) {
+               struct v4l2_streamparm parm;
+
+               parm.parm.capture.timeperframe.denominator = 15;
+               gspca_dev->sd_desc->get_streamparm(gspca_dev, &parm);
+               bandwidth *= parm.parm.capture.timeperframe.denominator;
+       } else {
+               bandwidth *= 15;                /* 15 fps */
+       }
+
+       PDEBUG(D_STREAM, "min bandwidth: %d", bandwidth);
+       return bandwidth;
+}
+
+/* endpoint table */
+#define MAX_ALT 16
+struct ep_tb_s {
+       u32 alt;
+       u32 bandwidth;
+};
+
 /*
- * look for an input (isoc or bulk) endpoint
- *
- * The endpoint is defined by the subdriver.
- * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep).
- * This routine may be called many times when the bandwidth is too small
- * (the bandwidth is checked on urb submit).
+ * build the table of the endpoints
+ * and compute the minimum bandwidth for the image transfer
  */
-static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
+static int build_ep_tb(struct gspca_dev *gspca_dev,
+                       struct usb_interface *intf,
+                       int xfer,
+                       struct ep_tb_s *ep_tb)
 {
-       struct usb_interface *intf;
        struct usb_host_endpoint *ep;
-       int xfer, i, ret;
+       int i, j, nbalt, psize, found;
+       u32 bandwidth, last_bw;
 
-       intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
-       ep = NULL;
-       xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
-                                  : USB_ENDPOINT_XFER_ISOC;
-       i = gspca_dev->alt;                     /* previous alt setting */
-       if (gspca_dev->cam.reverse_alts) {
-               while (++i < gspca_dev->nbalt) {
-                       ep = alt_xfer(&intf->altsetting[i], xfer);
-                       if (ep)
-                               break;
-               }
-       } else {
-               while (--i >= 0) {
-                       ep = alt_xfer(&intf->altsetting[i], xfer);
-                       if (ep)
-                               break;
-               }
-       }
-       if (ep == NULL) {
-               err("no transfer endpoint found");
-               return NULL;
-       }
-       PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
-                       i, ep->desc.bEndpointAddress);
-       gspca_dev->alt = i;             /* memorize the current alt setting */
-       if (gspca_dev->nbalt > 1) {
-               ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
-               if (ret < 0) {
-                       err("set alt %d err %d", i, ret);
-                       ep = NULL;
+       nbalt = intf->num_altsetting;
+       if (nbalt > MAX_ALT)
+               nbalt = MAX_ALT;        /* fixme: should warn */
+
+       /* build the endpoint table */
+       i = 0;
+       last_bw = 0;
+       for (;;) {
+               ep_tb->bandwidth = 2000 * 2000 * 120;
+               found = 0;
+               for (j = 0; j < nbalt; j++) {
+                       ep = alt_xfer(&intf->altsetting[j], xfer);
+                       if (ep == NULL)
+                               continue;
+                       psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+                       if (!gspca_dev->cam.bulk)               /* isoc */
+                               psize = (psize & 0x07ff) *
+                                               (1 + ((psize >> 11) & 3));
+                       bandwidth = psize * ep->desc.bInterval * 1000;
+                       if (gspca_dev->dev->speed == USB_SPEED_HIGH
+                        || gspca_dev->dev->speed == USB_SPEED_SUPER)
+                               bandwidth *= 8;
+                       if (bandwidth <= last_bw)
+                               continue;
+                       if (bandwidth < ep_tb->bandwidth) {
+                               ep_tb->bandwidth = bandwidth;
+                               ep_tb->alt = j;
+                               found = 1;
+                       }
                }
+               if (!found)
+                       break;
+               PDEBUG(D_STREAM, "alt %d bandwidth %d",
+                               ep_tb->alt, ep_tb->bandwidth);
+               last_bw = ep_tb->bandwidth;
+               i++;
+               ep_tb++;
+       }
+
+       /* get the requested bandwidth and start at the highest atlsetting */
+       bandwidth = which_bandwidth(gspca_dev);
+       ep_tb--;
+       while (i > 1) {
+               ep_tb--;
+               if (ep_tb->bandwidth < bandwidth)
+                       break;
+               i--;
        }
-       return ep;
+       return i;
 }
 
 /*
@@ -731,7 +769,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
        for (n = 0; n < nurbs; n++) {
                urb = usb_alloc_urb(npkt, GFP_KERNEL);
                if (!urb) {
-                       err("usb_alloc_urb failed");
+                       pr_err("usb_alloc_urb failed\n");
                        return -ENOMEM;
                }
                gspca_dev->urb[n] = urb;
@@ -741,7 +779,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
                                                &urb->transfer_dma);
 
                if (urb->transfer_buffer == NULL) {
-                       err("usb_alloc_coherent failed");
+                       pr_err("usb_alloc_coherent failed\n");
                        return -ENOMEM;
                }
                urb->dev = gspca_dev->dev;
@@ -752,7 +790,10 @@ static int create_urbs(struct gspca_dev *gspca_dev,
                                                    ep->desc.bEndpointAddress);
                        urb->transfer_flags = URB_ISO_ASAP
                                        | URB_NO_TRANSFER_DMA_MAP;
-                       urb->interval = ep->desc.bInterval;
+                       if (gspca_dev->dev->speed == USB_SPEED_LOW)
+                               urb->interval = ep->desc.bInterval;
+                       else
+                               urb->interval = 1 << (ep->desc.bInterval - 1);
                        urb->complete = isoc_irq;
                        urb->number_of_packets = npkt;
                        for (i = 0; i < npkt; i++) {
@@ -774,9 +815,11 @@ static int create_urbs(struct gspca_dev *gspca_dev,
  */
 static int gspca_init_transfer(struct gspca_dev *gspca_dev)
 {
+       struct usb_interface *intf;
        struct usb_host_endpoint *ep;
        struct urb *urb;
-       int n, ret;
+       struct ep_tb_s ep_tb[MAX_ALT];
+       int n, ret, xfer, alt, alt_idx;
 
        if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                return -ERESTARTSYS;
@@ -794,30 +837,65 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
 
        gspca_dev->usb_err = 0;
 
-       /* set the higher alternate setting and
-        * loop until urb submit succeeds */
-       if (gspca_dev->cam.reverse_alts)
-               gspca_dev->alt = 0;
-       else
-               gspca_dev->alt = gspca_dev->nbalt;
-
+       /* do the specific subdriver stuff before endpoint selection */
+       gspca_dev->alt = 0;
        if (gspca_dev->sd_desc->isoc_init) {
                ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
                if (ret < 0)
                        goto unlock;
        }
+       intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+       xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
+                                  : USB_ENDPOINT_XFER_ISOC;
 
-       gspca_input_destroy_urb(gspca_dev);
-       ep = get_ep(gspca_dev);
-       if (ep == NULL) {
-               ret = -EIO;
-               goto out;
+       /* if the subdriver forced an altsetting, get the endpoint */
+       if (gspca_dev->alt != 0) {
+               gspca_dev->alt--;       /* (previous version compatibility) */
+               ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer);
+               if (ep == NULL) {
+                       pr_err("bad altsetting %d\n", gspca_dev->alt);
+                       ret = -EIO;
+                       goto out;
+               }
+               ep_tb[0].alt = gspca_dev->alt;
+               alt_idx = 1;
+       } else {
+
+       /* else, compute the minimum bandwidth
+        * and build the endpoint table */
+               alt_idx = build_ep_tb(gspca_dev, intf, xfer, ep_tb);
+               if (alt_idx <= 0) {
+                       pr_err("no transfer endpoint found\n");
+                       ret = -EIO;
+                       goto unlock;
+               }
        }
+
+       /* set the highest alternate setting and
+        * loop until urb submit succeeds */
+       gspca_input_destroy_urb(gspca_dev);
+
+       gspca_dev->alt = ep_tb[--alt_idx].alt;
+       alt = -1;
        for (;;) {
+               if (alt != gspca_dev->alt) {
+                       alt = gspca_dev->alt;
+                       if (gspca_dev->nbalt > 1) {
+                               ret = usb_set_interface(gspca_dev->dev,
+                                                       gspca_dev->iface,
+                                                       alt);
+                               if (ret < 0) {
+                                       if (ret == -ENOSPC)
+                                               goto retry; /*fixme: ugly*/
+                                       pr_err("set alt %d err %d\n", alt, ret);
+                                       goto out;
+                               }
+                       }
+               }
                if (!gspca_dev->cam.no_urb_create) {
-                       PDEBUG(D_STREAM, "init transfer alt %d",
-                               gspca_dev->alt);
-                       ret = create_urbs(gspca_dev, ep);
+                       PDEBUG(D_STREAM, "init transfer alt %d", alt);
+                       ret = create_urbs(gspca_dev,
+                               alt_xfer(&intf->altsetting[alt], xfer));
                        if (ret < 0) {
                                destroy_urbs(gspca_dev);
                                goto out;
@@ -851,29 +929,35 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                                break;
                }
                if (ret >= 0)
-                       break;
+                       break;                  /* transfer is started */
+
+               /* something when wrong
+                * stop the webcam and free the transfer resources */
                gspca_stream_off(gspca_dev);
                if (ret != -ENOSPC) {
-                       err("usb_submit_urb alt %d err %d",
-                               gspca_dev->alt, ret);
+                       pr_err("usb_submit_urb alt %d err %d\n",
+                              gspca_dev->alt, ret);
                        goto out;
                }
 
                /* the bandwidth is not wide enough
                 * negotiate or try a lower alternate setting */
+retry:
                PDEBUG(D_ERR|D_STREAM,
-                       "bandwidth not wide enough - trying again");
+                       "alt %d - bandwidth not wide enough - trying again",
+                       alt);
                msleep(20);     /* wait for kill complete */
                if (gspca_dev->sd_desc->isoc_nego) {
                        ret = gspca_dev->sd_desc->isoc_nego(gspca_dev);
                        if (ret < 0)
                                goto out;
                } else {
-                       ep = get_ep(gspca_dev);
-                       if (ep == NULL) {
+                       if (alt_idx <= 0) {
+                               pr_err("no transfer endpoint found\n");
                                ret = -EIO;
                                goto out;
                        }
+                       alt = ep_tb[--alt_idx].alt;
                }
        }
 out:
@@ -1044,7 +1128,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
                return -EINVAL;         /* no more format */
 
        fmtdesc->pixelformat = fmt_tb[index];
-       if (gspca_is_compressed(fmt_tb[index]))
+       if (gspca_dev->cam.cam_mode[i].sizeimage <
+                       gspca_dev->cam.cam_mode[i].width *
+                               gspca_dev->cam.cam_mode[i].height)
                fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
        fmtdesc->description[0] = fmtdesc->pixelformat & 0xff;
        fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff;
@@ -2195,19 +2281,20 @@ int gspca_dev_probe2(struct usb_interface *intf,
        struct usb_device *dev = interface_to_usbdev(intf);
        int ret;
 
-       PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);
+       pr_info("%s-" GSPCA_VERSION " probing %04x:%04x\n",
+               sd_desc->name, id->idVendor, id->idProduct);
 
        /* create the device */
        if (dev_size < sizeof *gspca_dev)
                dev_size = sizeof *gspca_dev;
        gspca_dev = kzalloc(dev_size, GFP_KERNEL);
        if (!gspca_dev) {
-               err("couldn't kzalloc gspca struct");
+               pr_err("couldn't kzalloc gspca struct\n");
                return -ENOMEM;
        }
        gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL);
        if (!gspca_dev->usb_buf) {
-               err("out of memory");
+               pr_err("out of memory\n");
                ret = -ENOMEM;
                goto out;
        }
@@ -2264,7 +2351,7 @@ int gspca_dev_probe2(struct usb_interface *intf,
                                  VFL_TYPE_GRABBER,
                                  -1);
        if (ret < 0) {
-               err("video_register_device err %d", ret);
+               pr_err("video_register_device err %d\n", ret);
                goto out;
        }
 
@@ -2296,8 +2383,8 @@ int gspca_dev_probe(struct usb_interface *intf,
 
        /* we don't handle multi-config cameras */
        if (dev->descriptor.bNumConfigurations != 1) {
-               err("%04x:%04x too many config",
-                               id->idVendor, id->idProduct);
+               pr_err("%04x:%04x too many config\n",
+                      id->idVendor, id->idProduct);
                return -ENODEV;
        }
 
@@ -2480,7 +2567,7 @@ EXPORT_SYMBOL(gspca_auto_gain_n_exposure);
 /* -- module insert / remove -- */
 static int __init gspca_init(void)
 {
-       info("v" DRIVER_VERSION_NUMBER " registered");
+       pr_info("v" GSPCA_VERSION " registered\n");
        return 0;
 }
 static void __exit gspca_exit(void)
index 49e2fcb..e444f16 100644 (file)
 #ifdef GSPCA_DEBUG
 /* GSPCA our debug messages */
 extern int gspca_debug;
-#define PDEBUG(level, fmt, args...) \
-       do {\
-               if (gspca_debug & (level)) \
-                       printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \
-       } while (0)
+#define PDEBUG(level, fmt, ...)                                        \
+do {                                                           \
+       if (gspca_debug & (level))                              \
+               pr_info(fmt, ##__VA_ARGS__);                    \
+} while (0)
+
 #define D_ERR  0x01
 #define D_PROBE 0x02
 #define D_CONF 0x04
@@ -29,17 +30,8 @@ extern int gspca_debug;
 #define D_USBO 0x00
 #define D_V4L2 0x0100
 #else
-#define PDEBUG(level, fmt, args...)
+#define PDEBUG(level, fmt, ...)
 #endif
-#undef err
-#define err(fmt, args...) \
-       printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args)
-#undef info
-#define info(fmt, args...) \
-       printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args)
-#undef warn
-#define warn(fmt, args...) \
-       printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args)
 
 #define GSPCA_MAX_FRAMES 16    /* maximum number of video frame buffers */
 /* image transfers */
index 1bd9c4b..8e3dabe 100644 (file)
@@ -24,6 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "jeilinj"
 
 #include <linux/slab.h>
@@ -113,8 +115,8 @@ static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
                        usb_sndbulkpipe(gspca_dev->dev, 3),
                        gspca_dev->usb_buf, 2, NULL, 500);
        if (retval < 0) {
-               err("command write [%02x] error %d",
-                               gspca_dev->usb_buf[0], retval);
+               pr_err("command write [%02x] error %d\n",
+                      gspca_dev->usb_buf[0], retval);
                gspca_dev->usb_err = retval;
        }
 }
@@ -131,8 +133,8 @@ static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
                                gspca_dev->usb_buf, 1, NULL, 500);
        response = gspca_dev->usb_buf[0];
        if (retval < 0) {
-               err("read command [%02x] error %d",
-                               gspca_dev->usb_buf[0], retval);
+               pr_err("read command [%02x] error %d\n",
+                      gspca_dev->usb_buf[0], retval);
                gspca_dev->usb_err = retval;
        }
 }
@@ -403,13 +405,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        dev->type = id->driver_info;
        gspca_dev->cam.ctrls = dev->ctrls;
        dev->quality = QUALITY_DEF;
-       dev->ctrls[LIGHTFREQ].def = V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
-       dev->ctrls[RED].def = RED_BALANCE_DEF;
-       dev->ctrls[GREEN].def = GREEN_BALANCE_DEF;
-       dev->ctrls[BLUE].def = BLUE_BALANCE_DEF;
-       PDEBUG(D_PROBE,
-               "JEILINJ camera detected"
-               " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+
        cam->cam_mode = jlj_mode;
        cam->nmodes = ARRAY_SIZE(jlj_mode);
        cam->bulk = 1;
@@ -422,7 +418,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 {
        int i;
        u8 *buf;
-       u8 stop_commands[][2] = {
+       static u8 stop_commands[][2] = {
                {0x71, 0x00},
                {0x70, 0x09},
                {0x71, 0x80},
index 26fc206..4fe51fd 100644 (file)
@@ -24,6 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "kinect"
 
 #include "gspca.h"
@@ -34,11 +36,6 @@ MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
 MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#ifdef GSPCA_DEBUG
-int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK |
-       D_USBI | D_USBO | D_V4L2;
-#endif
-
 struct pkt_hdr {
        uint8_t magic[2];
        uint8_t pad;
@@ -141,7 +138,7 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf,
        struct cam_hdr *rhdr = (void *)ibuf;
 
        if (cmd_len & 1 || cmd_len > (0x400 - sizeof(*chdr))) {
-               err("send_cmd: Invalid command length (0x%x)", cmd_len);
+               pr_err("send_cmd: Invalid command length (0x%x)\n", cmd_len);
                return -1;
        }
 
@@ -157,7 +154,7 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf,
        PDEBUG(D_USBO, "Control cmd=%04x tag=%04x len=%04x: %d", cmd,
                sd->cam_tag, cmd_len, res);
        if (res < 0) {
-               err("send_cmd: Output control transfer failed (%d)", res);
+               pr_err("send_cmd: Output control transfer failed (%d)\n", res);
                return res;
        }
 
@@ -166,33 +163,35 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf,
        } while (actual_len == 0);
        PDEBUG(D_USBO, "Control reply: %d", res);
        if (actual_len < sizeof(*rhdr)) {
-               err("send_cmd: Input control transfer failed (%d)", res);
+               pr_err("send_cmd: Input control transfer failed (%d)\n", res);
                return res;
        }
        actual_len -= sizeof(*rhdr);
 
        if (rhdr->magic[0] != 0x52 || rhdr->magic[1] != 0x42) {
-               err("send_cmd: Bad magic %02x %02x", rhdr->magic[0],
-                       rhdr->magic[1]);
+               pr_err("send_cmd: Bad magic %02x %02x\n",
+                      rhdr->magic[0], rhdr->magic[1]);
                return -1;
        }
        if (rhdr->cmd != chdr->cmd) {
-               err("send_cmd: Bad cmd %02x != %02x", rhdr->cmd, chdr->cmd);
+               pr_err("send_cmd: Bad cmd %02x != %02x\n",
+                      rhdr->cmd, chdr->cmd);
                return -1;
        }
        if (rhdr->tag != chdr->tag) {
-               err("send_cmd: Bad tag %04x != %04x", rhdr->tag, chdr->tag);
+               pr_err("send_cmd: Bad tag %04x != %04x\n",
+                      rhdr->tag, chdr->tag);
                return -1;
        }
        if (cpu_to_le16(rhdr->len) != (actual_len/2)) {
-               err("send_cmd: Bad len %04x != %04x",
-                               cpu_to_le16(rhdr->len), (int)(actual_len/2));
+               pr_err("send_cmd: Bad len %04x != %04x\n",
+                      cpu_to_le16(rhdr->len), (int)(actual_len/2));
                return -1;
        }
 
        if (actual_len > reply_len) {
-               warn("send_cmd: Data buffer is %d bytes long, but got %d bytes",
-                               reply_len, actual_len);
+               pr_warn("send_cmd: Data buffer is %d bytes long, but got %d bytes\n",
+                       reply_len, actual_len);
                memcpy(replybuf, ibuf+sizeof(*rhdr), reply_len);
        } else {
                memcpy(replybuf, ibuf+sizeof(*rhdr), actual_len);
@@ -218,8 +217,8 @@ static int write_register(struct gspca_dev *gspca_dev, uint16_t reg,
        if (res < 0)
                return res;
        if (res != 2) {
-               warn("send_cmd returned %d [%04x %04x], 0000 expected",
-                               res, reply[0], reply[1]);
+               pr_warn("send_cmd returned %d [%04x %04x], 0000 expected\n",
+                       res, reply[0], reply[1]);
        }
        return 0;
 }
@@ -353,8 +352,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len)
                return;
 
        if (hdr->magic[0] != 'R' || hdr->magic[1] != 'B') {
-               warn("[Stream %02x] Invalid magic %02x%02x", sd->stream_flag,
-                               hdr->magic[0], hdr->magic[1]);
+               pr_warn("[Stream %02x] Invalid magic %02x%02x\n",
+                       sd->stream_flag, hdr->magic[0], hdr->magic[1]);
                return;
        }
 
@@ -368,7 +367,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len)
                gspca_frame_add(gspca_dev, LAST_PACKET, data, datalen);
 
        else
-               warn("Packet type not recognized...");
+               pr_warn("Packet type not recognized...\n");
 }
 
 /* sub-driver description */
index 5964691..f3f7fe0 100644 (file)
@@ -28,6 +28,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "konica"
 
 #include <linux/input.h>
@@ -200,7 +202,7 @@ static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
                        0,
                        1000);
        if (ret < 0) {
-               err("reg_w err %d", ret);
+               pr_err("reg_w err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -221,7 +223,7 @@ static void reg_r(struct gspca_dev *gspca_dev, u16 value, u16 index)
                        2,
                        1000);
        if (ret < 0) {
-               err("reg_w err %d", ret);
+               pr_err("reg_w err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -284,7 +286,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
        alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
        if (!alt) {
-               err("Couldn't get altsetting");
+               pr_err("Couldn't get altsetting\n");
                return -EIO;
        }
 
@@ -315,7 +317,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                        le16_to_cpu(alt->endpoint[i].desc.wMaxPacketSize);
                urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL);
                if (!urb) {
-                       err("usb_alloc_urb failed");
+                       pr_err("usb_alloc_urb failed\n");
                        return -ENOMEM;
                }
                gspca_dev->urb[n] = urb;
@@ -324,7 +326,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                                                GFP_KERNEL,
                                                &urb->transfer_dma);
                if (urb->transfer_buffer == NULL) {
-                       err("usb_buffer_alloc failed");
+                       pr_err("usb_buffer_alloc failed\n");
                        return -ENOMEM;
                }
 
@@ -386,7 +388,7 @@ static void sd_isoc_irq(struct urb *urb)
                PDEBUG(D_ERR, "urb status: %d", urb->status);
                st = usb_submit_urb(urb, GFP_ATOMIC);
                if (st < 0)
-                       err("resubmit urb error %d", st);
+                       pr_err("resubmit urb error %d\n", st);
                return;
        }
 
@@ -477,7 +479,7 @@ resubmit:
        }
        st = usb_submit_urb(status_urb, GFP_ATOMIC);
        if (st < 0)
-               err("usb_submit_urb(status_urb) ret %d", st);
+               pr_err("usb_submit_urb(status_urb) ret %d\n", st);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
index bf7a19a..7f52961 100644 (file)
@@ -8,4 +8,4 @@ gspca_m5602-objs := m5602_core.o \
                    m5602_s5k83a.o \
                    m5602_s5k4aa.o
 
-EXTRA_CFLAGS += -Idrivers/media/video/gspca
+ccflags-y += -Idrivers/media/video/gspca
index a7722b1..67533e5 100644 (file)
@@ -16,6 +16,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "m5602_ov9650.h"
 #include "m5602_ov7660.h"
 #include "m5602_mt9m111.h"
@@ -192,10 +194,9 @@ static void m5602_dump_bridge(struct sd *sd)
        for (i = 0; i < 0x80; i++) {
                unsigned char val = 0;
                m5602_read_bridge(sd, i, &val);
-               info("ALi m5602 address 0x%x contains 0x%x", i, val);
+               pr_info("ALi m5602 address 0x%x contains 0x%x\n", i, val);
        }
-       info("Warning: The ALi m5602 webcam probably won't work "
-               "until it's power cycled");
+       pr_info("Warning: The ALi m5602 webcam probably won't work until it's power cycled\n");
 }
 
 static int m5602_probe_sensor(struct sd *sd)
@@ -231,7 +232,7 @@ static int m5602_probe_sensor(struct sd *sd)
                return 0;
 
        /* More sensor probe function goes here */
-       info("Failed to find a sensor");
+       pr_info("Failed to find a sensor\n");
        sd->sensor = NULL;
        return -ENODEV;
 }
index 0d605a5..6268aa2 100644 (file)
@@ -16,6 +16,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "m5602_mt9m111.h"
 
 static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
@@ -163,7 +165,7 @@ int mt9m111_probe(struct sd *sd)
 
        if (force_sensor) {
                if (force_sensor == MT9M111_SENSOR) {
-                       info("Forcing a %s sensor", mt9m111.name);
+                       pr_info("Forcing a %s sensor\n", mt9m111.name);
                        goto sensor_found;
                }
                /* If we want to force another sensor, don't try to probe this
@@ -191,7 +193,7 @@ int mt9m111_probe(struct sd *sd)
                return -ENODEV;
 
        if ((data[0] == 0x14) && (data[1] == 0x3a)) {
-               info("Detected a mt9m111 sensor");
+               pr_info("Detected a mt9m111 sensor\n");
                goto sensor_found;
        }
 
@@ -612,34 +614,34 @@ static void mt9m111_dump_registers(struct sd *sd)
 {
        u8 address, value[2] = {0x00, 0x00};
 
-       info("Dumping the mt9m111 register state");
+       pr_info("Dumping the mt9m111 register state\n");
 
-       info("Dumping the mt9m111 sensor core registers");
+       pr_info("Dumping the mt9m111 sensor core registers\n");
        value[1] = MT9M111_SENSOR_CORE;
        m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
        for (address = 0; address < 0xff; address++) {
                m5602_read_sensor(sd, address, value, 2);
-               info("register 0x%x contains 0x%x%x",
-                    address, value[0], value[1]);
+               pr_info("register 0x%x contains 0x%x%x\n",
+                       address, value[0], value[1]);
        }
 
-       info("Dumping the mt9m111 color pipeline registers");
+       pr_info("Dumping the mt9m111 color pipeline registers\n");
        value[1] = MT9M111_COLORPIPE;
        m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
        for (address = 0; address < 0xff; address++) {
                m5602_read_sensor(sd, address, value, 2);
-               info("register 0x%x contains 0x%x%x",
-                    address, value[0], value[1]);
+               pr_info("register 0x%x contains 0x%x%x\n",
+                       address, value[0], value[1]);
        }
 
-       info("Dumping the mt9m111 camera control registers");
+       pr_info("Dumping the mt9m111 camera control registers\n");
        value[1] = MT9M111_CAMERA_CONTROL;
        m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
        for (address = 0; address < 0xff; address++) {
                m5602_read_sensor(sd, address, value, 2);
-               info("register 0x%x contains 0x%x%x",
-                    address, value[0], value[1]);
+               pr_info("register 0x%x contains 0x%x%x\n",
+                       address, value[0], value[1]);
        }
 
-       info("mt9m111 register state dump complete");
+       pr_info("mt9m111 register state dump complete\n");
 }
index b12f604..9a14835 100644 (file)
@@ -16,6 +16,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "m5602_ov7660.h"
 
 static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
@@ -149,7 +151,7 @@ int ov7660_probe(struct sd *sd)
 
        if (force_sensor) {
                if (force_sensor == OV7660_SENSOR) {
-                       info("Forcing an %s sensor", ov7660.name);
+                       pr_info("Forcing an %s sensor\n", ov7660.name);
                        goto sensor_found;
                }
                /* If we want to force another sensor,
@@ -180,10 +182,10 @@ int ov7660_probe(struct sd *sd)
        if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
                return -ENODEV;
 
-       info("Sensor reported 0x%x%x", prod_id, ver_id);
+       pr_info("Sensor reported 0x%x%x\n", prod_id, ver_id);
 
        if ((prod_id == 0x76) && (ver_id == 0x60)) {
-               info("Detected a ov7660 sensor");
+               pr_info("Detected a ov7660 sensor\n");
                goto sensor_found;
        }
        return -ENODEV;
@@ -457,17 +459,16 @@ static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 static void ov7660_dump_registers(struct sd *sd)
 {
        int address;
-       info("Dumping the ov7660 register state");
+       pr_info("Dumping the ov7660 register state\n");
        for (address = 0; address < 0xa9; address++) {
                u8 value;
                m5602_read_sensor(sd, address, &value, 1);
-               info("register 0x%x contains 0x%x",
-                    address, value);
+               pr_info("register 0x%x contains 0x%x\n", address, value);
        }
 
-       info("ov7660 register state dump complete");
+       pr_info("ov7660 register state dump complete\n");
 
-       info("Probing for which registers that are read/write");
+       pr_info("Probing for which registers that are read/write\n");
        for (address = 0; address < 0xff; address++) {
                u8 old_value, ctrl_value;
                u8 test_value[2] = {0xff, 0xff};
@@ -477,9 +478,9 @@ static void ov7660_dump_registers(struct sd *sd)
                m5602_read_sensor(sd, address, &ctrl_value, 1);
 
                if (ctrl_value == test_value[0])
-                       info("register 0x%x is writeable", address);
+                       pr_info("register 0x%x is writeable\n", address);
                else
-                       info("register 0x%x is read only", address);
+                       pr_info("register 0x%x is read only\n", address);
 
                /* Restore original value */
                m5602_write_sensor(sd, address, &old_value, 1);
index 703d486..2114a8b 100644 (file)
@@ -16,6 +16,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "m5602_ov9650.h"
 
 static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
@@ -299,7 +301,7 @@ int ov9650_probe(struct sd *sd)
 
        if (force_sensor) {
                if (force_sensor == OV9650_SENSOR) {
-                       info("Forcing an %s sensor", ov9650.name);
+                       pr_info("Forcing an %s sensor\n", ov9650.name);
                        goto sensor_found;
                }
                /* If we want to force another sensor,
@@ -330,7 +332,7 @@ int ov9650_probe(struct sd *sd)
                return -ENODEV;
 
        if ((prod_id == 0x96) && (ver_id == 0x52)) {
-               info("Detected an ov9650 sensor");
+               pr_info("Detected an ov9650 sensor\n");
                goto sensor_found;
        }
        return -ENODEV;
@@ -850,17 +852,16 @@ static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
 static void ov9650_dump_registers(struct sd *sd)
 {
        int address;
-       info("Dumping the ov9650 register state");
+       pr_info("Dumping the ov9650 register state\n");
        for (address = 0; address < 0xa9; address++) {
                u8 value;
                m5602_read_sensor(sd, address, &value, 1);
-               info("register 0x%x contains 0x%x",
-                    address, value);
+               pr_info("register 0x%x contains 0x%x\n", address, value);
        }
 
-       info("ov9650 register state dump complete");
+       pr_info("ov9650 register state dump complete\n");
 
-       info("Probing for which registers that are read/write");
+       pr_info("Probing for which registers that are read/write\n");
        for (address = 0; address < 0xff; address++) {
                u8 old_value, ctrl_value;
                u8 test_value[2] = {0xff, 0xff};
@@ -870,9 +871,9 @@ static void ov9650_dump_registers(struct sd *sd)
                m5602_read_sensor(sd, address, &ctrl_value, 1);
 
                if (ctrl_value == test_value[0])
-                       info("register 0x%x is writeable", address);
+                       pr_info("register 0x%x is writeable\n", address);
                else
-                       info("register 0x%x is read only", address);
+                       pr_info("register 0x%x is read only\n", address);
 
                /* Restore original value */
                m5602_write_sensor(sd, address, &old_value, 1);
index 1febd34..b877169 100644 (file)
@@ -16,6 +16,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "m5602_po1030.h"
 
 static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
@@ -197,7 +199,7 @@ int po1030_probe(struct sd *sd)
 
        if (force_sensor) {
                if (force_sensor == PO1030_SENSOR) {
-                       info("Forcing a %s sensor", po1030.name);
+                       pr_info("Forcing a %s sensor\n", po1030.name);
                        goto sensor_found;
                }
                /* If we want to force another sensor, don't try to probe this
@@ -221,7 +223,7 @@ int po1030_probe(struct sd *sd)
                return -ENODEV;
 
        if (dev_id_h == 0x30) {
-               info("Detected a po1030 sensor");
+               pr_info("Detected a po1030 sensor\n");
                goto sensor_found;
        }
        return -ENODEV;
@@ -267,7 +269,7 @@ int po1030_init(struct sd *sd)
                        break;
 
                default:
-                       info("Invalid stream command, exiting init");
+                       pr_info("Invalid stream command, exiting init\n");
                        return -EINVAL;
                }
        }
@@ -733,16 +735,15 @@ static void po1030_dump_registers(struct sd *sd)
        int address;
        u8 value = 0;
 
-       info("Dumping the po1030 sensor core registers");
+       pr_info("Dumping the po1030 sensor core registers\n");
        for (address = 0; address < 0x7f; address++) {
                m5602_read_sensor(sd, address, &value, 1);
-               info("register 0x%x contains 0x%x",
-                    address, value);
+               pr_info("register 0x%x contains 0x%x\n", address, value);
        }
 
-       info("po1030 register state dump complete");
+       pr_info("po1030 register state dump complete\n");
 
-       info("Probing for which registers that are read/write");
+       pr_info("Probing for which registers that are read/write\n");
        for (address = 0; address < 0xff; address++) {
                u8 old_value, ctrl_value;
                u8 test_value[2] = {0xff, 0xff};
@@ -752,9 +753,9 @@ static void po1030_dump_registers(struct sd *sd)
                m5602_read_sensor(sd, address, &ctrl_value, 1);
 
                if (ctrl_value == test_value[0])
-                       info("register 0x%x is writeable", address);
+                       pr_info("register 0x%x is writeable\n", address);
                else
-                       info("register 0x%x is read only", address);
+                       pr_info("register 0x%x is read only\n", address);
 
                /* Restore original value */
                m5602_write_sensor(sd, address, &old_value, 1);
index d27280b..cc8ec3f 100644 (file)
@@ -16,6 +16,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "m5602_s5k4aa.h"
 
 static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
@@ -240,7 +242,7 @@ int s5k4aa_probe(struct sd *sd)
 
        if (force_sensor) {
                if (force_sensor == S5K4AA_SENSOR) {
-                       info("Forcing a %s sensor", s5k4aa.name);
+                       pr_info("Forcing a %s sensor\n", s5k4aa.name);
                        goto sensor_found;
                }
                /* If we want to force another sensor, don't try to probe this
@@ -276,7 +278,7 @@ int s5k4aa_probe(struct sd *sd)
                                                  data, 2);
                        break;
                default:
-                       info("Invalid stream command, exiting init");
+                       pr_info("Invalid stream command, exiting init\n");
                        return -EINVAL;
                }
        }
@@ -292,7 +294,7 @@ int s5k4aa_probe(struct sd *sd)
        if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
                return -ENODEV;
        else
-               info("Detected a s5k4aa sensor");
+               pr_info("Detected a s5k4aa sensor\n");
 
 sensor_found:
        sensor_settings = kmalloc(
@@ -347,7 +349,7 @@ int s5k4aa_start(struct sd *sd)
                        break;
 
                        default:
-                               err("Invalid stream command, exiting init");
+                               pr_err("Invalid stream command, exiting init\n");
                                return -EINVAL;
                        }
                }
@@ -383,7 +385,7 @@ int s5k4aa_start(struct sd *sd)
                        break;
 
                        default:
-                               err("Invalid stream command, exiting init");
+                               pr_err("Invalid stream command, exiting init\n");
                                return -EINVAL;
                        }
                }
@@ -447,7 +449,7 @@ int s5k4aa_init(struct sd *sd)
                                init_s5k4aa[i][1], data, 2);
                        break;
                default:
-                       info("Invalid stream command, exiting init");
+                       pr_info("Invalid stream command, exiting init\n");
                        return -EINVAL;
                }
        }
@@ -686,20 +688,21 @@ static void s5k4aa_dump_registers(struct sd *sd)
        m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
        for (page = 0; page < 16; page++) {
                m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
-               info("Dumping the s5k4aa register state for page 0x%x", page);
+               pr_info("Dumping the s5k4aa register state for page 0x%x\n",
+                       page);
                for (address = 0; address <= 0xff; address++) {
                        u8 value = 0;
                        m5602_read_sensor(sd, address, &value, 1);
-                       info("register 0x%x contains 0x%x",
-                            address, value);
+                       pr_info("register 0x%x contains 0x%x\n",
+                               address, value);
                }
        }
-       info("s5k4aa register state dump complete");
+       pr_info("s5k4aa register state dump complete\n");
 
        for (page = 0; page < 16; page++) {
                m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
-               info("Probing for which registers that are "
-                    "read/write for page 0x%x", page);
+               pr_info("Probing for which registers that are read/write for page 0x%x\n",
+                       page);
                for (address = 0; address <= 0xff; address++) {
                        u8 old_value, ctrl_value, test_value = 0xff;
 
@@ -708,14 +711,16 @@ static void s5k4aa_dump_registers(struct sd *sd)
                        m5602_read_sensor(sd, address, &ctrl_value, 1);
 
                        if (ctrl_value == test_value)
-                               info("register 0x%x is writeable", address);
+                               pr_info("register 0x%x is writeable\n",
+                                       address);
                        else
-                               info("register 0x%x is read only", address);
+                               pr_info("register 0x%x is read only\n",
+                                       address);
 
                        /* Restore original value */
                        m5602_write_sensor(sd, address, &old_value, 1);
                }
        }
-       info("Read/write register probing complete");
+       pr_info("Read/write register probing complete\n");
        m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
 }
index fbd9154..1de743a 100644 (file)
@@ -16,6 +16,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kthread.h>
 #include "m5602_s5k83a.h"
 
@@ -135,7 +137,7 @@ int s5k83a_probe(struct sd *sd)
 
        if (force_sensor) {
                if (force_sensor == S5K83A_SENSOR) {
-                       info("Forcing a %s sensor", s5k83a.name);
+                       pr_info("Forcing a %s sensor\n", s5k83a.name);
                        goto sensor_found;
                }
                /* If we want to force another sensor, don't try to probe this
@@ -168,7 +170,7 @@ int s5k83a_probe(struct sd *sd)
        if ((prod_id == 0xff) || (ver_id == 0xff))
                return -ENODEV;
        else
-               info("Detected a s5k83a sensor");
+               pr_info("Detected a s5k83a sensor\n");
 
 sensor_found:
        sens_priv = kmalloc(
@@ -227,7 +229,7 @@ int s5k83a_init(struct sd *sd)
                                init_s5k83a[i][1], data, 2);
                        break;
                default:
-                       info("Invalid stream command, exiting init");
+                       pr_info("Invalid stream command, exiting init\n");
                        return -EINVAL;
                }
        }
@@ -273,7 +275,7 @@ static int rotation_thread_function(void *data)
                s5k83a_get_rotation(sd, &reg);
                if (previous_rotation != reg) {
                        previous_rotation = reg;
-                       info("Camera was flipped");
+                       pr_info("Camera was flipped\n");
 
                        s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
                        s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
@@ -566,20 +568,20 @@ static void s5k83a_dump_registers(struct sd *sd)
 
        for (page = 0; page < 16; page++) {
                m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
-               info("Dumping the s5k83a register state for page 0x%x", page);
+               pr_info("Dumping the s5k83a register state for page 0x%x\n",
+                       page);
                for (address = 0; address <= 0xff; address++) {
                        u8 val = 0;
                        m5602_read_sensor(sd, address, &val, 1);
-                       info("register 0x%x contains 0x%x",
-                            address, val);
+                       pr_info("register 0x%x contains 0x%x\n", address, val);
                }
        }
-       info("s5k83a register state dump complete");
+       pr_info("s5k83a register state dump complete\n");
 
        for (page = 0; page < 16; page++) {
                m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
-               info("Probing for which registers that are read/write "
-                               "for page 0x%x", page);
+               pr_info("Probing for which registers that are read/write for page 0x%x\n",
+                       page);
                for (address = 0; address <= 0xff; address++) {
                        u8 old_val, ctrl_val, test_val = 0xff;
 
@@ -588,14 +590,16 @@ static void s5k83a_dump_registers(struct sd *sd)
                        m5602_read_sensor(sd, address, &ctrl_val, 1);
 
                        if (ctrl_val == test_val)
-                               info("register 0x%x is writeable", address);
+                               pr_info("register 0x%x is writeable\n",
+                                       address);
                        else
-                               info("register 0x%x is read only", address);
+                               pr_info("register 0x%x is read only\n",
+                                       address);
 
                        /* Restore original val */
                        m5602_write_sensor(sd, address, &old_val, 1);
                }
        }
-       info("Read/write register probing complete");
+       pr_info("Read/write register probing complete\n");
        m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
 }
index 0196209..ef45fa5 100644 (file)
@@ -19,6 +19,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "mars"
 
 #include "gspca.h"
@@ -178,8 +180,8 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        &alen,
                        500);   /* timeout in milliseconds */
        if (ret < 0) {
-               err("reg write [%02x] error %d",
-                       gspca_dev->usb_buf[0], ret);
+               pr_err("reg write [%02x] error %d\n",
+                      gspca_dev->usb_buf[0], ret);
                gspca_dev->usb_err = ret;
        }
 }
index 97e5079..473e813 100644 (file)
@@ -40,6 +40,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "mr97310a"
 
 #include "gspca.h"
@@ -267,7 +269,7 @@ static int mr_write(struct gspca_dev *gspca_dev, int len)
                          usb_sndbulkpipe(gspca_dev->dev, 4),
                          gspca_dev->usb_buf, len, NULL, 500);
        if (rc < 0)
-               err("reg write [%02x] error %d",
+               pr_err("reg write [%02x] error %d\n",
                       gspca_dev->usb_buf[0], rc);
        return rc;
 }
@@ -281,7 +283,7 @@ static int mr_read(struct gspca_dev *gspca_dev, int len)
                          usb_rcvbulkpipe(gspca_dev->dev, 3),
                          gspca_dev->usb_buf, len, NULL, 500);
        if (rc < 0)
-               err("reg read [%02x] error %d",
+               pr_err("reg read [%02x] error %d\n",
                       gspca_dev->usb_buf[0], rc);
        return rc;
 }
@@ -540,7 +542,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        sd->sensor_type = 1;
                        break;
                default:
-                       err("Unknown CIF Sensor id : %02x",
+                       pr_err("Unknown CIF Sensor id : %02x\n",
                               gspca_dev->usb_buf[1]);
                        return -ENODEV;
                }
@@ -575,10 +577,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        sd->sensor_type = 2;
                } else if ((gspca_dev->usb_buf[0] != 0x03) &&
                                        (gspca_dev->usb_buf[0] != 0x04)) {
-                       err("Unknown VGA Sensor id Byte 0: %02x",
-                                       gspca_dev->usb_buf[0]);
-                       err("Defaults assumed, may not work");
-                       err("Please report this");
+                       pr_err("Unknown VGA Sensor id Byte 0: %02x\n",
+                              gspca_dev->usb_buf[0]);
+                       pr_err("Defaults assumed, may not work\n");
+                       pr_err("Please report this\n");
                }
                /* Sakar Digital color needs to be adjusted. */
                if ((gspca_dev->usb_buf[0] == 0x03) &&
@@ -595,10 +597,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
                                /* Nothing to do here. */
                                break;
                        default:
-                               err("Unknown VGA Sensor id Byte 1: %02x",
-                                       gspca_dev->usb_buf[1]);
-                               err("Defaults assumed, may not work");
-                               err("Please report this");
+                               pr_err("Unknown VGA Sensor id Byte 1: %02x\n",
+                                      gspca_dev->usb_buf[1]);
+                               pr_err("Defaults assumed, may not work\n");
+                               pr_err("Please report this\n");
                        }
                }
                PDEBUG(D_PROBE, "MR97310A VGA camera detected, sensor: %d",
index 8e754fd..7681814 100644 (file)
@@ -20,6 +20,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "nw80x"
 
 #include "gspca.h"
@@ -1571,7 +1573,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        len,
                        500);
        if (ret < 0) {
-               err("reg_w err %d", ret);
+               pr_err("reg_w err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -1592,7 +1594,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
                        0x00, index,
                        gspca_dev->usb_buf, len, 500);
        if (ret < 0) {
-               err("reg_r err %d", ret);
+               pr_err("reg_r err %d\n", ret);
                gspca_dev->usb_err = ret;
                return;
        }
@@ -1802,7 +1804,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
                }
        }
        if (webcam_chip[sd->webcam] != sd->bridge) {
-               err("Bad webcam type %d for NW80%d", sd->webcam, sd->bridge);
+               pr_err("Bad webcam type %d for NW80%d\n",
+                      sd->webcam, sd->bridge);
                gspca_dev->usb_err = -ENODEV;
                return gspca_dev->usb_err;
        }
index 18305c8..6a01b35 100644 (file)
@@ -36,6 +36,9 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "ov519"
 
 #include <linux/input.h>
@@ -2171,7 +2174,7 @@ static void reg_w(struct sd *sd, u16 index, u16 value)
                        sd->gspca_dev.usb_buf, 1, 500);
 leave:
        if (ret < 0) {
-               err("reg_w %02x failed %d", index, ret);
+               pr_err("reg_w %02x failed %d\n", index, ret);
                sd->gspca_dev.usb_err = ret;
                return;
        }
@@ -2210,7 +2213,7 @@ static int reg_r(struct sd *sd, u16 index)
                PDEBUG(D_USBI, "GET %02x 0000 %04x %02x",
                        req, index, ret);
        } else {
-               err("reg_r %02x failed %d", index, ret);
+               pr_err("reg_r %02x failed %d\n", index, ret);
                sd->gspca_dev.usb_err = ret;
        }
 
@@ -2235,7 +2238,7 @@ static int reg_r8(struct sd *sd,
        if (ret >= 0) {
                ret = sd->gspca_dev.usb_buf[0];
        } else {
-               err("reg_r8 %02x failed %d", index, ret);
+               pr_err("reg_r8 %02x failed %d\n", index, ret);
                sd->gspca_dev.usb_err = ret;
        }
 
@@ -2288,7 +2291,7 @@ static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n)
                        0, index,
                        sd->gspca_dev.usb_buf, n, 500);
        if (ret < 0) {
-               err("reg_w32 %02x failed %d", index, ret);
+               pr_err("reg_w32 %02x failed %d\n", index, ret);
                sd->gspca_dev.usb_err = ret;
        }
 }
@@ -2457,7 +2460,7 @@ static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value)
                        (u16) value, (u16) reg, NULL, 0, 500);
 
        if (ret < 0) {
-               err("ovfx2_i2c_w %02x failed %d", reg, ret);
+               pr_err("ovfx2_i2c_w %02x failed %d\n", reg, ret);
                sd->gspca_dev.usb_err = ret;
        }
 
@@ -2481,7 +2484,7 @@ static int ovfx2_i2c_r(struct sd *sd, u8 reg)
                ret = sd->gspca_dev.usb_buf[0];
                PDEBUG(D_USBI, "ovfx2_i2c_r %02x %02x", reg, ret);
        } else {
-               err("ovfx2_i2c_r %02x failed %d", reg, ret);
+               pr_err("ovfx2_i2c_r %02x failed %d\n", reg, ret);
                sd->gspca_dev.usb_err = ret;
        }
 
@@ -2727,7 +2730,7 @@ static void ov_hires_configure(struct sd *sd)
        int high, low;
 
        if (sd->bridge != BRIDGE_OVFX2) {
-               err("error hires sensors only supported with ovfx2");
+               pr_err("error hires sensors only supported with ovfx2\n");
                return;
        }
 
@@ -2762,7 +2765,7 @@ static void ov_hires_configure(struct sd *sd)
                }
                break;
        }
-       err("Error unknown sensor type: %02x%02x", high, low);
+       pr_err("Error unknown sensor type: %02x%02x\n", high, low);
 }
 
 /* This initializes the OV8110, OV8610 sensor. The OV8110 uses
@@ -2783,7 +2786,7 @@ static void ov8xx0_configure(struct sd *sd)
        if ((rc & 3) == 1)
                sd->sensor = SEN_OV8610;
        else
-               err("Unknown image sensor version: %d", rc & 3);
+               pr_err("Unknown image sensor version: %d\n", rc & 3);
 }
 
 /* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
@@ -2840,8 +2843,8 @@ static void ov7xx0_configure(struct sd *sd)
                if (high == 0x76) {
                        switch (low) {
                        case 0x30:
-                               err("Sensor is an OV7630/OV7635");
-                               err("7630 is not supported by this driver");
+                               pr_err("Sensor is an OV7630/OV7635\n");
+                               pr_err("7630 is not supported by this driver\n");
                                return;
                        case 0x40:
                                PDEBUG(D_PROBE, "Sensor is an OV7645");
@@ -2868,7 +2871,7 @@ static void ov7xx0_configure(struct sd *sd)
                        sd->sensor = SEN_OV7620;
                }
        } else {
-               err("Unknown image sensor version: %d", rc & 3);
+               pr_err("Unknown image sensor version: %d\n", rc & 3);
        }
 }
 
@@ -2891,8 +2894,7 @@ static void ov6xx0_configure(struct sd *sd)
        switch (rc) {
        case 0x00:
                sd->sensor = SEN_OV6630;
-               warn("WARNING: Sensor is an OV66308. Your camera may have");
-               warn("been misdetected in previous driver versions.");
+               pr_warn("WARNING: Sensor is an OV66308. Your camera may have been misdetected in previous driver versions.\n");
                break;
        case 0x01:
                sd->sensor = SEN_OV6620;
@@ -2908,11 +2910,10 @@ static void ov6xx0_configure(struct sd *sd)
                break;
        case 0x90:
                sd->sensor = SEN_OV6630;
-               warn("WARNING: Sensor is an OV66307. Your camera may have");
-               warn("been misdetected in previous driver versions.");
+               pr_warn("WARNING: Sensor is an OV66307. Your camera may have been misdetected in previous driver versions.\n");
                break;
        default:
-               err("FATAL: Unknown sensor version: 0x%02x", rc);
+               pr_err("FATAL: Unknown sensor version: 0x%02x\n", rc);
                return;
        }
 
@@ -3405,7 +3406,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        } else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) {
                ov_hires_configure(sd);
        } else {
-               err("Can't determine sensor slave IDs");
+               pr_err("Can't determine sensor slave IDs\n");
                goto error;
        }
 
@@ -3590,7 +3591,7 @@ static void ov511_mode_init_regs(struct sd *sd)
        intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
        alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
        if (!alt) {
-               err("Couldn't get altsetting");
+               pr_err("Couldn't get altsetting\n");
                sd->gspca_dev.usb_err = -EIO;
                return;
        }
@@ -3713,7 +3714,7 @@ static void ov518_mode_init_regs(struct sd *sd)
        intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
        alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
        if (!alt) {
-               err("Couldn't get altsetting");
+               pr_err("Couldn't get altsetting\n");
                sd->gspca_dev.usb_err = -EIO;
                return;
        }
index 0c6369b..76907ec 100644 (file)
@@ -28,6 +28,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "ov534"
 
 #include "gspca.h"
@@ -775,7 +777,7 @@ static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
        if (ret < 0) {
-               err("write failed %d", ret);
+               pr_err("write failed %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -794,7 +796,7 @@ static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
                              0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
        PDEBUG(D_USBI, "GET 01 0000 %04x %02x", reg, gspca_dev->usb_buf[0]);
        if (ret < 0) {
-               err("read failed %d", ret);
+               pr_err("read failed %d\n", ret);
                gspca_dev->usb_err = ret;
        }
        return gspca_dev->usb_buf[0];
@@ -858,7 +860,7 @@ static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
        ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
 
        if (!sccb_check_status(gspca_dev)) {
-               err("sccb_reg_write failed");
+               pr_err("sccb_reg_write failed\n");
                gspca_dev->usb_err = -EIO;
        }
 }
@@ -868,11 +870,11 @@ static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
        ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
        ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
        if (!sccb_check_status(gspca_dev))
-               err("sccb_reg_read failed 1");
+               pr_err("sccb_reg_read failed 1\n");
 
        ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
        if (!sccb_check_status(gspca_dev))
-               err("sccb_reg_read failed 2");
+               pr_err("sccb_reg_read failed 2\n");
 
        return ov534_reg_read(gspca_dev, OV534_REG_READ);
 }
index aaf5428..b3b1ea6 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * ov534-ov965x gspca driver
+ * ov534-ov9xxx gspca driver
  *
- * Copyright (C) 2009-2010 Jean-Francois Moine http://moinejf.free.fr
+ * Copyright (C) 2009-2011 Jean-Francois Moine http://moinejf.free.fr
  * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it>
  * Copyright (C) 2008 Jim Paris <jim@jtan.com>
  *
@@ -24,6 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "ov534_9"
 
 #include "gspca.h"
@@ -45,39 +47,44 @@ MODULE_AUTHOR("Jean-Francois Moine <moinejf@free.fr>");
 MODULE_DESCRIPTION("GSPCA/OV534_9 USB Camera Driver");
 MODULE_LICENSE("GPL");
 
+/* controls */
+enum e_ctrl {
+       BRIGHTNESS,
+       CONTRAST,
+       AUTOGAIN,
+       EXPOSURE,
+       SHARPNESS,
+       SATUR,
+       LIGHTFREQ,
+       NCTRLS          /* number of controls */
+};
+
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
+       struct gspca_ctrl ctrls[NCTRLS];
        __u32 last_pts;
        u8 last_fid;
 
-       u8 brightness;
-       u8 contrast;
-       u8 autogain;
-       u8 exposure;
-       s8 sharpness;
-       u8 satur;
-       u8 freq;
+       u8 sensor;
+};
+enum sensors {
+       SENSOR_OV965x,          /* ov9657 */
+       SENSOR_OV971x,          /* ov9712 */
+       NSENSORS
 };
 
 /* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
-
-static const struct ctrl sd_ctrls[] = {
-    {                                                  /* 0 */
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setcontrast(struct gspca_dev *gspca_dev);
+static void setautogain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static void setsharpness(struct gspca_dev *gspca_dev);
+static void setsatur(struct gspca_dev *gspca_dev);
+static void setlightfreq(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
        {
                .id      = V4L2_CID_BRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -85,13 +92,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 15,
                .step    = 1,
-#define BRIGHTNESS_DEF 7
-               .default_value = BRIGHTNESS_DEF,
+               .default_value = 7
        },
-       .set = sd_setbrightness,
-       .get = sd_getbrightness,
+       .set_control = setbrightness
     },
-    {                                                  /* 1 */
+[CONTRAST] = {
        {
                .id      = V4L2_CID_CONTRAST,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -99,13 +104,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 15,
                .step    = 1,
-#define CONTRAST_DEF 3
-               .default_value = CONTRAST_DEF,
+               .default_value = 3
        },
-       .set = sd_setcontrast,
-       .get = sd_getcontrast,
+       .set_control = setcontrast
     },
-    {                                                  /* 2 */
+[AUTOGAIN] = {
        {
                .id      = V4L2_CID_AUTOGAIN,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -116,11 +119,9 @@ static const struct ctrl sd_ctrls[] = {
 #define AUTOGAIN_DEF 1
                .default_value = AUTOGAIN_DEF,
        },
-       .set = sd_setautogain,
-       .get = sd_getautogain,
+       .set_control = setautogain
     },
-#define EXPO_IDX 3
-    {                                                  /* 3 */
+[EXPOSURE] = {
        {
                .id      = V4L2_CID_EXPOSURE,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -128,13 +129,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 3,
                .step    = 1,
-#define EXPO_DEF 0
-               .default_value = EXPO_DEF,
+               .default_value = 0
        },
-       .set = sd_setexposure,
-       .get = sd_getexposure,
+       .set_control = setexposure
     },
-    {                                                  /* 4 */
+[SHARPNESS] = {
        {
                .id      = V4L2_CID_SHARPNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -142,13 +141,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = -1,          /* -1 = auto */
                .maximum = 4,
                .step    = 1,
-#define SHARPNESS_DEF -1
-               .default_value = SHARPNESS_DEF,
+               .default_value = -1
        },
-       .set = sd_setsharpness,
-       .get = sd_getsharpness,
+       .set_control = setsharpness
     },
-    {                                                  /* 5 */
+[SATUR] = {
        {
                .id      = V4L2_CID_SATURATION,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -156,13 +153,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 4,
                .step    = 1,
-#define SATUR_DEF 2
-               .default_value = SATUR_DEF,
+               .default_value = 2
        },
-       .set = sd_setsatur,
-       .get = sd_getsatur,
+       .set_control = setsatur
     },
-    {
+[LIGHTFREQ] = {
        {
                .id      = V4L2_CID_POWER_LINE_FREQUENCY,
                .type    = V4L2_CTRL_TYPE_MENU,
@@ -170,11 +165,9 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 2,   /* 0: 0, 1: 50Hz, 2:60Hz */
                .step    = 1,
-#define FREQ_DEF 0
-               .default_value = FREQ_DEF,
+               .default_value = 0
        },
-       .set = sd_setfreq,
-       .get = sd_getfreq,
+       .set_control = setlightfreq
     },
 };
 
@@ -206,6 +199,14 @@ static const struct v4l2_pix_format ov965x_mode[] = {
                .colorspace = V4L2_COLORSPACE_JPEG},
 };
 
+static const struct v4l2_pix_format ov971x_mode[] = {
+       {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480,
+               .colorspace = V4L2_COLORSPACE_SRGB
+       }
+};
+
 static const u8 bridge_init[][2] = {
        {0x88, 0xf8},
        {0x89, 0xff},
@@ -240,7 +241,7 @@ static const u8 bridge_init[][2] = {
        {0x94, 0x11},
 };
 
-static const u8 sensor_init[][2] = {
+static const u8 ov965x_init[][2] = {
        {0x12, 0x80},   /* com7 - SSCB reset */
        {0x00, 0x00},   /* gain */
        {0x01, 0x80},   /* blue */
@@ -450,7 +451,7 @@ static const u8 bridge_init_2[][2] = {
        {0x94, 0x11},
 };
 
-static const u8 sensor_init_2[][2] = {
+static const u8 ov965x_init_2[][2] = {
        {0x3b, 0xc4},
        {0x1e, 0x04},   /* mvfp */
        {0x13, 0xe0},   /* com8 */
@@ -492,7 +493,65 @@ static const u8 sensor_init_2[][2] = {
        {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
 };
 
-static const u8 sensor_start_1_vga[][2] = {    /* same for qvga */
+static const u8 ov971x_init[][2] = {
+       {0x12, 0x80},
+       {0x09, 0x10},
+       {0x1e, 0x07},
+       {0x5f, 0x18},
+       {0x69, 0x04},
+       {0x65, 0x2a},
+       {0x68, 0x0a},
+       {0x39, 0x28},
+       {0x4d, 0x90},
+       {0xc1, 0x80},
+       {0x0c, 0x30},
+       {0x6d, 0x02},
+       {0x96, 0xf1},
+       {0xbc, 0x68},
+       {0x12, 0x00},
+       {0x3b, 0x00},
+       {0x97, 0x80},
+       {0x17, 0x25},
+       {0x18, 0xa2},
+       {0x19, 0x01},
+       {0x1a, 0xca},
+       {0x03, 0x0a},
+       {0x32, 0x07},
+       {0x98, 0x40},   /*{0x98, 0x00},*/
+       {0x99, 0xA0},   /*{0x99, 0x00},*/
+       {0x9a, 0x01},   /*{0x9a, 0x00},*/
+       {0x57, 0x00},
+       {0x58, 0x78},   /*{0x58, 0xc8},*/
+       {0x59, 0x50},   /*{0x59, 0xa0},*/
+       {0x4c, 0x13},
+       {0x4b, 0x36},
+       {0x3d, 0x3c},
+       {0x3e, 0x03},
+       {0xbd, 0x50},   /*{0xbd, 0xa0},*/
+       {0xbe, 0x78},   /*{0xbe, 0xc8},*/
+       {0x4e, 0x55},
+       {0x4f, 0x55},
+       {0x50, 0x55},
+       {0x51, 0x55},
+       {0x24, 0x55},
+       {0x25, 0x40},
+       {0x26, 0xa1},
+       {0x5c, 0x59},
+       {0x5d, 0x00},
+       {0x11, 0x00},
+       {0x2a, 0x98},
+       {0x2b, 0x06},
+       {0x2d, 0x00},
+       {0x2e, 0x00},
+       {0x13, 0xa5},
+       {0x14, 0x40},
+       {0x4a, 0x00},
+       {0x49, 0xce},
+       {0x22, 0x03},
+       {0x09, 0x00}
+};
+
+static const u8 ov965x_start_1_vga[][2] = {    /* same for qvga */
        {0x12, 0x62},   /* com7 - 30fps VGA YUV */
        {0x36, 0xfa},   /* aref3 */
        {0x69, 0x0a},   /* hv */
@@ -515,7 +574,7 @@ static const u8 sensor_start_1_vga[][2] = { /* same for qvga */
        {0xc0, 0xaa},
 };
 
-static const u8 sensor_start_1_svga[][2] = {
+static const u8 ov965x_start_1_svga[][2] = {
        {0x12, 0x02},   /* com7 - YUYV - VGA 15 full resolution */
        {0x36, 0xf8},   /* aref3 */
        {0x69, 0x02},   /* hv */
@@ -537,7 +596,7 @@ static const u8 sensor_start_1_svga[][2] = {
        {0xc0, 0xe2},
 };
 
-static const u8 sensor_start_1_xga[][2] = {
+static const u8 ov965x_start_1_xga[][2] = {
        {0x12, 0x02},   /* com7 */
        {0x36, 0xf8},   /* aref3 */
        {0x69, 0x02},   /* hv */
@@ -560,7 +619,7 @@ static const u8 sensor_start_1_xga[][2] = {
        {0xc0, 0xe2},
 };
 
-static const u8 sensor_start_1_sxga[][2] = {
+static const u8 ov965x_start_1_sxga[][2] = {
        {0x12, 0x02},   /* com7 */
        {0x36, 0xf8},   /* aref3 */
        {0x69, 0x02},   /* hv */
@@ -709,7 +768,7 @@ static const u8 bridge_start_sxga[][2] = {
        {0x94, 0x11},
 };
 
-static const u8 sensor_start_2_qvga[][2] = {
+static const u8 ov965x_start_2_qvga[][2] = {
        {0x3b, 0xe4},   /* com11 - night mode 1/4 frame rate */
        {0x1e, 0x04},   /* mvfp */
        {0x13, 0xe0},   /* com8 */
@@ -727,7 +786,7 @@ static const u8 sensor_start_2_qvga[][2] = {
        {0x3a, 0x80},   /* tslb - yuyv */
 };
 
-static const u8 sensor_start_2_vga[][2] = {
+static const u8 ov965x_start_2_vga[][2] = {
        {0x3b, 0xc4},   /* com11 - night mode 1/4 frame rate */
        {0x1e, 0x04},   /* mvfp */
        {0x13, 0xe0},   /* com8 */
@@ -743,7 +802,7 @@ static const u8 sensor_start_2_vga[][2] = {
        {0x2d, 0x00},   /* advfl */
 };
 
-static const u8 sensor_start_2_svga[][2] = {   /* same for xga */
+static const u8 ov965x_start_2_svga[][2] = {   /* same for xga */
        {0x3b, 0xc4},   /* com11 - night mode 1/4 frame rate */
        {0x1e, 0x04},   /* mvfp */
        {0x13, 0xe0},   /* com8 */
@@ -757,7 +816,7 @@ static const u8 sensor_start_2_svga[][2] = {        /* same for xga */
        {0xa3, 0x41},   /* bd60 */
 };
 
-static const u8 sensor_start_2_sxga[][2] = {
+static const u8 ov965x_start_2_sxga[][2] = {
        {0x13, 0xe0},   /* com8 */
        {0x00, 0x00},
        {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
@@ -785,7 +844,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val)
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
        if (ret < 0) {
-               err("reg_w failed %d", ret);
+               pr_err("reg_w failed %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -810,7 +869,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev, u16 reg)
                              0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
        PDEBUG(D_USBI, "reg_r [%04x] -> %02x", reg, gspca_dev->usb_buf[0]);
        if (ret < 0) {
-               err("reg_r err %d", ret);
+               pr_err("reg_r err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
        return gspca_dev->usb_buf[0];
@@ -848,7 +907,7 @@ static void sccb_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
        reg_w_i(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
 
        if (!sccb_check_status(gspca_dev))
-               err("sccb_write failed");
+               pr_err("sccb_write failed\n");
 }
 
 static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg)
@@ -856,11 +915,11 @@ static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg)
        reg_w(gspca_dev, OV534_REG_SUBADDR, reg);
        reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
        if (!sccb_check_status(gspca_dev))
-               err("sccb_read failed 1");
+               pr_err("sccb_read failed 1\n");
 
        reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
        if (!sccb_check_status(gspca_dev))
-               err("sccb_read failed 2");
+               pr_err("sccb_read failed 2\n");
 
        return reg_r(gspca_dev, OV534_REG_READ);
 }
@@ -922,7 +981,9 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        u8 val;
 
-       val = sd->brightness;
+       if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS))
+               return;
+       val = sd->ctrls[BRIGHTNESS].val;
        if (val < 8)
                val = 15 - val;         /* f .. 8 */
        else
@@ -935,8 +996,10 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
+       if (gspca_dev->ctrl_dis & (1 << CONTRAST))
+               return;
        sccb_write(gspca_dev, 0x56,     /* cnst1 - contrast 1 ctrl coeff */
-                       sd->contrast << 4);
+                       sd->ctrls[CONTRAST].val << 4);
 }
 
 static void setautogain(struct gspca_dev *gspca_dev)
@@ -944,10 +1007,12 @@ static void setautogain(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        u8 val;
 
+       if (gspca_dev->ctrl_dis & (1 << AUTOGAIN))
+               return;
 /*fixme: should adjust agc/awb/aec by different controls */
        val = sccb_read(gspca_dev, 0x13);               /* com8 */
        sccb_write(gspca_dev, 0xff, 0x00);
-       if (sd->autogain)
+       if (sd->ctrls[AUTOGAIN].val)
                val |= 0x05;            /* agc & aec */
        else
                val &= 0xfa;
@@ -960,8 +1025,10 @@ static void setexposure(struct gspca_dev *gspca_dev)
        u8 val;
        static const u8 expo[4] = {0x00, 0x25, 0x38, 0x5e};
 
+       if (gspca_dev->ctrl_dis & (1 << EXPOSURE))
+               return;
        sccb_write(gspca_dev, 0x10,                     /* aec[9:2] */
-                       expo[sd->exposure]);
+                       expo[sd->ctrls[EXPOSURE].val]);
 
        val = sccb_read(gspca_dev, 0x13);               /* com8 */
        sccb_write(gspca_dev, 0xff, 0x00);
@@ -977,7 +1044,9 @@ static void setsharpness(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        s8 val;
 
-       val = sd->sharpness;
+       if (gspca_dev->ctrl_dis & (1 << SHARPNESS))
+               return;
+       val = sd->ctrls[SHARPNESS].val;
        if (val < 0) {                          /* auto */
                val = sccb_read(gspca_dev, 0x42);       /* com17 */
                sccb_write(gspca_dev, 0xff, 0x00);
@@ -1006,8 +1075,10 @@ static void setsatur(struct gspca_dev *gspca_dev)
                {0x48, 0x90}
        };
 
-       val1 = matrix[sd->satur][0];
-       val2 = matrix[sd->satur][1];
+       if (gspca_dev->ctrl_dis & (1 << SATUR))
+               return;
+       val1 = matrix[sd->ctrls[SATUR].val][0];
+       val2 = matrix[sd->ctrls[SATUR].val][1];
        val3 = val1 + val2;
        sccb_write(gspca_dev, 0x4f, val3);      /* matrix coeff */
        sccb_write(gspca_dev, 0x50, val3);
@@ -1022,14 +1093,16 @@ static void setsatur(struct gspca_dev *gspca_dev)
        sccb_write(gspca_dev, 0x41, val1);
 }
 
-static void setfreq(struct gspca_dev *gspca_dev)
+static void setlightfreq(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        u8 val;
 
+       if (gspca_dev->ctrl_dis & (1 << LIGHTFREQ))
+               return;
        val = sccb_read(gspca_dev, 0x13);               /* com8 */
        sccb_write(gspca_dev, 0xff, 0x00);
-       if (sd->freq == 0) {
+       if (sd->ctrls[LIGHTFREQ].val == 0) {
                sccb_write(gspca_dev, 0x13, val & 0xdf);
                return;
        }
@@ -1037,7 +1110,7 @@ static void setfreq(struct gspca_dev *gspca_dev)
 
        val = sccb_read(gspca_dev, 0x42);               /* com17 */
        sccb_write(gspca_dev, 0xff, 0x00);
-       if (sd->freq == 1)
+       if (sd->ctrls[LIGHTFREQ].val == 1)
                val |= 0x01;
        else
                val &= 0xfe;
@@ -1049,34 +1122,19 @@ static int sd_config(struct gspca_dev *gspca_dev,
                     const struct usb_device_id *id)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       struct cam *cam;
-
-       cam = &gspca_dev->cam;
 
-       cam->cam_mode = ov965x_mode;
-       cam->nmodes = ARRAY_SIZE(ov965x_mode);
+       gspca_dev->cam.ctrls = sd->ctrls;
 
-       sd->brightness = BRIGHTNESS_DEF;
-       sd->contrast = CONTRAST_DEF;
 #if AUTOGAIN_DEF != 0
-       sd->autogain = AUTOGAIN_DEF;
-       gspca_dev->ctrl_inac |= (1 << EXPO_IDX);
-#endif
-#if EXPO_DEF != 0
-       sd->exposure = EXPO_DEF;
-#endif
-#if SHARPNESS_DEF != 0
-       sd->sharpness = SHARPNESS_DEF;
+       gspca_dev->ctrl_inac |= (1 << EXPOSURE);
 #endif
-       sd->satur = SATUR_DEF;
-       sd->freq = FREQ_DEF;
-
        return 0;
 }
 
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        u16 sensor_id;
 
        /* reset bridge */
@@ -1099,68 +1157,117 @@ static int sd_init(struct gspca_dev *gspca_dev)
        PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id);
 
        /* initialize */
-       reg_w_array(gspca_dev, bridge_init,
-                       ARRAY_SIZE(bridge_init));
-       sccb_w_array(gspca_dev, sensor_init,
-                       ARRAY_SIZE(sensor_init));
-       reg_w_array(gspca_dev, bridge_init_2,
-                       ARRAY_SIZE(bridge_init_2));
-       sccb_w_array(gspca_dev, sensor_init_2,
-                       ARRAY_SIZE(sensor_init_2));
-       reg_w(gspca_dev, 0xe0, 0x00);
-       reg_w(gspca_dev, 0xe0, 0x01);
-       set_led(gspca_dev, 0);
-       reg_w(gspca_dev, 0xe0, 0x00);
+       if ((sensor_id & 0xfff0) == 0x9650) {
+               sd->sensor = SENSOR_OV965x;
+
+               gspca_dev->cam.cam_mode = ov965x_mode;
+               gspca_dev->cam.nmodes = ARRAY_SIZE(ov965x_mode);
+
+               reg_w_array(gspca_dev, bridge_init,
+                               ARRAY_SIZE(bridge_init));
+               sccb_w_array(gspca_dev, ov965x_init,
+                               ARRAY_SIZE(ov965x_init));
+               reg_w_array(gspca_dev, bridge_init_2,
+                               ARRAY_SIZE(bridge_init_2));
+               sccb_w_array(gspca_dev, ov965x_init_2,
+                               ARRAY_SIZE(ov965x_init_2));
+               reg_w(gspca_dev, 0xe0, 0x00);
+               reg_w(gspca_dev, 0xe0, 0x01);
+               set_led(gspca_dev, 0);
+               reg_w(gspca_dev, 0xe0, 0x00);
+       } else if ((sensor_id & 0xfff0) == 0x9710) {
+               const char *p;
+               int l;
+
+               sd->sensor = SENSOR_OV971x;
+
+               gspca_dev->cam.cam_mode = ov971x_mode;
+               gspca_dev->cam.nmodes = ARRAY_SIZE(ov971x_mode);
+
+               /* no control yet */
+               gspca_dev->ctrl_dis = (1 << NCTRLS) - 1;
+
+               gspca_dev->cam.bulk = 1;
+               gspca_dev->cam.bulk_size = 16384;
+               gspca_dev->cam.bulk_nurbs = 2;
+
+               sccb_w_array(gspca_dev, ov971x_init,
+                               ARRAY_SIZE(ov971x_init));
+
+               /* set video format on bridge processor */
+               /* access bridge processor's video format registers at: 0x00 */
+               reg_w(gspca_dev, 0x1c, 0x00);
+               /*set register: 0x00 is 'RAW8', 0x40 is 'YUV422' (YUYV?)*/
+               reg_w(gspca_dev, 0x1d, 0x00);
+
+               /* Will W. specific stuff
+                * set VSYNC to
+                *      output (0x1f) if first webcam
+                *      input (0x17) if 2nd or 3rd webcam */
+               p = video_device_node_name(&gspca_dev->vdev);
+               l = strlen(p) - 1;
+               if (p[l] == '0')
+                       reg_w(gspca_dev, 0x56, 0x1f);
+               else
+                       reg_w(gspca_dev, 0x56, 0x17);
+       } else {
+               err("Unknown sensor %04x", sensor_id);
+               return -EINVAL;
+       }
 
        return gspca_dev->usb_err;
 }
 
 static int sd_start(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->sensor == SENSOR_OV971x)
+               return gspca_dev->usb_err;
        switch (gspca_dev->curr_mode) {
        case QVGA_MODE:                 /* 320x240 */
-               sccb_w_array(gspca_dev, sensor_start_1_vga,
-                               ARRAY_SIZE(sensor_start_1_vga));
+               sccb_w_array(gspca_dev, ov965x_start_1_vga,
+                               ARRAY_SIZE(ov965x_start_1_vga));
                reg_w_array(gspca_dev, bridge_start_qvga,
                                ARRAY_SIZE(bridge_start_qvga));
-               sccb_w_array(gspca_dev, sensor_start_2_qvga,
-                               ARRAY_SIZE(sensor_start_2_qvga));
+               sccb_w_array(gspca_dev, ov965x_start_2_qvga,
+                               ARRAY_SIZE(ov965x_start_2_qvga));
                break;
        case VGA_MODE:                  /* 640x480 */
-               sccb_w_array(gspca_dev, sensor_start_1_vga,
-                               ARRAY_SIZE(sensor_start_1_vga));
+               sccb_w_array(gspca_dev, ov965x_start_1_vga,
+                               ARRAY_SIZE(ov965x_start_1_vga));
                reg_w_array(gspca_dev, bridge_start_vga,
                                ARRAY_SIZE(bridge_start_vga));
-               sccb_w_array(gspca_dev, sensor_start_2_vga,
-                               ARRAY_SIZE(sensor_start_2_vga));
+               sccb_w_array(gspca_dev, ov965x_start_2_vga,
+                               ARRAY_SIZE(ov965x_start_2_vga));
                break;
        case SVGA_MODE:                 /* 800x600 */
-               sccb_w_array(gspca_dev, sensor_start_1_svga,
-                               ARRAY_SIZE(sensor_start_1_svga));
+               sccb_w_array(gspca_dev, ov965x_start_1_svga,
+                               ARRAY_SIZE(ov965x_start_1_svga));
                reg_w_array(gspca_dev, bridge_start_svga,
                                ARRAY_SIZE(bridge_start_svga));
-               sccb_w_array(gspca_dev, sensor_start_2_svga,
-                               ARRAY_SIZE(sensor_start_2_svga));
+               sccb_w_array(gspca_dev, ov965x_start_2_svga,
+                               ARRAY_SIZE(ov965x_start_2_svga));
                break;
        case XGA_MODE:                  /* 1024x768 */
-               sccb_w_array(gspca_dev, sensor_start_1_xga,
-                               ARRAY_SIZE(sensor_start_1_xga));
+               sccb_w_array(gspca_dev, ov965x_start_1_xga,
+                               ARRAY_SIZE(ov965x_start_1_xga));
                reg_w_array(gspca_dev, bridge_start_xga,
                                ARRAY_SIZE(bridge_start_xga));
-               sccb_w_array(gspca_dev, sensor_start_2_svga,
-                               ARRAY_SIZE(sensor_start_2_svga));
+               sccb_w_array(gspca_dev, ov965x_start_2_svga,
+                               ARRAY_SIZE(ov965x_start_2_svga));
                break;
        default:
 /*     case SXGA_MODE:                  * 1280x1024 */
-               sccb_w_array(gspca_dev, sensor_start_1_sxga,
-                               ARRAY_SIZE(sensor_start_1_sxga));
+               sccb_w_array(gspca_dev, ov965x_start_1_sxga,
+                               ARRAY_SIZE(ov965x_start_1_sxga));
                reg_w_array(gspca_dev, bridge_start_sxga,
                                ARRAY_SIZE(bridge_start_sxga));
-               sccb_w_array(gspca_dev, sensor_start_2_sxga,
-                               ARRAY_SIZE(sensor_start_2_sxga));
+               sccb_w_array(gspca_dev, ov965x_start_2_sxga,
+                               ARRAY_SIZE(ov965x_start_2_sxga));
                break;
        }
-       setfreq(gspca_dev);
+       setlightfreq(gspca_dev);
        setautogain(gspca_dev);
        setbrightness(gspca_dev);
        setcontrast(gspca_dev);
@@ -1198,9 +1305,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        __u32 this_pts;
        u8 this_fid;
        int remaining_len = len;
+       int payload_len;
 
+       payload_len = gspca_dev->cam.bulk ? 2048 : 2040;
        do {
-               len = min(remaining_len, 2040);
+               len = min(remaining_len, payload_len);
 
                /* Payloads are prefixed with a UVC-style header.  We
                   consider a frame to start when the FID toggles, or the PTS
@@ -1262,138 +1371,6 @@ scan_next:
        } while (remaining_len > 0);
 }
 
-/* controls */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->brightness = val;
-       if (gspca_dev->streaming)
-               setbrightness(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->brightness;
-       return 0;
-}
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->contrast = val;
-       if (gspca_dev->streaming)
-               setcontrast(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->contrast;
-       return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->autogain = val;
-
-       if (gspca_dev->streaming) {
-               if (val)
-                       gspca_dev->ctrl_inac |= (1 << EXPO_IDX);
-               else
-                       gspca_dev->ctrl_inac &= ~(1 << EXPO_IDX);
-               setautogain(gspca_dev);
-       }
-       return gspca_dev->usb_err;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->autogain;
-       return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->exposure = val;
-       if (gspca_dev->streaming)
-               setexposure(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->exposure;
-       return 0;
-}
-
-static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->sharpness = val;
-       if (gspca_dev->streaming)
-               setsharpness(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->sharpness;
-       return 0;
-}
-
-static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->satur = val;
-       if (gspca_dev->streaming)
-               setsatur(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->satur;
-       return 0;
-}
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->freq = val;
-       if (gspca_dev->streaming)
-               setfreq(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->freq;
-       return 0;
-}
-
 static int sd_querymenu(struct gspca_dev *gspca_dev,
                        struct v4l2_querymenu *menu)
 {
@@ -1419,7 +1396,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
 static const struct sd_desc sd_desc = {
        .name     = MODULE_NAME,
        .ctrls    = sd_ctrls,
-       .nctrls   = ARRAY_SIZE(sd_ctrls),
+       .nctrls   = NCTRLS,
        .config   = sd_config,
        .init     = sd_init,
        .start    = sd_start,
@@ -1430,6 +1407,7 @@ static const struct sd_desc sd_desc = {
 
 /* -- module initialisation -- */
 static const struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x05a9, 0x8065)},
        {USB_DEVICE(0x06f8, 0x3003)},
        {}
 };
index 81739a2..1600df1 100644 (file)
@@ -23,6 +23,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "pac207"
 
 #include <linux/input.h>
@@ -178,8 +180,8 @@ static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
                        0x00, index,
                        gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
        if (err < 0)
-               err("Failed to write registers to index 0x%04X, error %d)",
-                       index, err);
+               pr_err("Failed to write registers to index 0x%04X, error %d\n",
+                      index, err);
 
        return err;
 }
@@ -194,8 +196,8 @@ static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
                        value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
        if (err)
-               err("Failed to write a register (index 0x%04X,"
-                       " value 0x%02X, error %d)", index, value, err);
+               pr_err("Failed to write a register (index 0x%04X, value 0x%02X, error %d)\n",
+                      index, value, err);
 
        return err;
 }
@@ -210,8 +212,8 @@ static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
                        0x00, index,
                        gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
        if (res < 0) {
-               err("Failed to read a register (index 0x%04X, error %d)",
-                       index, res);
+               pr_err("Failed to read a register (index 0x%04X, error %d)\n",
+                      index, res);
                return res;
        }
 
index 5615d7b..1c44f78 100644 (file)
@@ -61,6 +61,8 @@
     3   | 0x21       | sethvflip()
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "pac7302"
 
 #include <linux/input.h>
@@ -408,8 +410,8 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
                        index, gspca_dev->usb_buf, len,
                        500);
        if (ret < 0) {
-               err("reg_w_buf failed index 0x%02x, error %d",
-                       index, ret);
+               pr_err("reg_w_buf failed index 0x%02x, error %d\n",
+                      index, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -431,8 +433,8 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        0, index, gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               err("reg_w() failed index 0x%02x, value 0x%02x, error %d",
-                       index, value, ret);
+               pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
+                      index, value, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -466,9 +468,8 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
                                0, index, gspca_dev->usb_buf, 1,
                                500);
                if (ret < 0) {
-                       err("reg_w_page() failed index 0x%02x, "
-                       "value 0x%02x, error %d",
-                               index, page[index], ret);
+                       pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
+                              index, page[index], ret);
                        gspca_dev->usb_err = ret;
                        break;
                }
index f8801b5..7509d05 100644 (file)
@@ -49,6 +49,8 @@
                for max gain, 0x14 for minimal gain.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "pac7311"
 
 #include <linux/input.h>
@@ -276,8 +278,8 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
                        index, gspca_dev->usb_buf, len,
                        500);
        if (ret < 0) {
-               err("reg_w_buf() failed index 0x%02x, error %d",
-                       index, ret);
+               pr_err("reg_w_buf() failed index 0x%02x, error %d\n",
+                      index, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -299,8 +301,8 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        0, index, gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               err("reg_w() failed index 0x%02x, value 0x%02x, error %d",
-                       index, value, ret);
+               pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
+                      index, value, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -334,9 +336,8 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
                                0, index, gspca_dev->usb_buf, 1,
                                500);
                if (ret < 0) {
-                       err("reg_w_page() failed index 0x%02x, "
-                       "value 0x%02x, error %d",
-                               index, page[index], ret);
+                       pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
+                              index, page[index], ret);
                        gspca_dev->usb_err = ret;
                        break;
                }
index 4c283c2..3b71bbc 100644 (file)
@@ -23,6 +23,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "se401"
 
 #define BULK_SIZE 4096
@@ -144,8 +146,8 @@ static void se401_write_req(struct gspca_dev *gspca_dev, u16 req, u16 value,
                              value, 0, NULL, 0, 1000);
        if (err < 0) {
                if (!silent)
-                       err("write req failed req %#04x val %#04x error %d",
-                           req, value, err);
+                       pr_err("write req failed req %#04x val %#04x error %d\n",
+                              req, value, err);
                gspca_dev->usb_err = err;
        }
 }
@@ -158,7 +160,7 @@ static void se401_read_req(struct gspca_dev *gspca_dev, u16 req, int silent)
                return;
 
        if (USB_BUF_SZ < READ_REQ_SIZE) {
-               err("USB_BUF_SZ too small!!");
+               pr_err("USB_BUF_SZ too small!!\n");
                gspca_dev->usb_err = -ENOBUFS;
                return;
        }
@@ -169,7 +171,8 @@ static void se401_read_req(struct gspca_dev *gspca_dev, u16 req, int silent)
                              0, 0, gspca_dev->usb_buf, READ_REQ_SIZE, 1000);
        if (err < 0) {
                if (!silent)
-                       err("read req failed req %#04x error %d", req, err);
+                       pr_err("read req failed req %#04x error %d\n",
+                              req, err);
                gspca_dev->usb_err = err;
        }
 }
@@ -188,8 +191,8 @@ static void se401_set_feature(struct gspca_dev *gspca_dev,
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              param, selector, NULL, 0, 1000);
        if (err < 0) {
-               err("set feature failed sel %#04x param %#04x error %d",
-                   selector, param, err);
+               pr_err("set feature failed sel %#04x param %#04x error %d\n",
+                      selector, param, err);
                gspca_dev->usb_err = err;
        }
 }
@@ -202,7 +205,7 @@ static int se401_get_feature(struct gspca_dev *gspca_dev, u16 selector)
                return gspca_dev->usb_err;
 
        if (USB_BUF_SZ < 2) {
-               err("USB_BUF_SZ too small!!");
+               pr_err("USB_BUF_SZ too small!!\n");
                gspca_dev->usb_err = -ENOBUFS;
                return gspca_dev->usb_err;
        }
@@ -213,7 +216,8 @@ static int se401_get_feature(struct gspca_dev *gspca_dev, u16 selector)
                              USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              0, selector, gspca_dev->usb_buf, 2, 1000);
        if (err < 0) {
-               err("get feature failed sel %#04x error %d", selector, err);
+               pr_err("get feature failed sel %#04x error %d\n",
+                      selector, err);
                gspca_dev->usb_err = err;
                return err;
        }
@@ -300,21 +304,21 @@ static int sd_config(struct gspca_dev *gspca_dev,
                return gspca_dev->usb_err;
 
        if (cd[1] != 0x41) {
-               err("Wrong descriptor type");
+               pr_err("Wrong descriptor type\n");
                return -ENODEV;
        }
 
        if (!(cd[2] & SE401_FORMAT_BAYER)) {
-               err("Bayer format not supported!");
+               pr_err("Bayer format not supported!\n");
                return -ENODEV;
        }
 
        if (cd[3])
-               info("ExtraFeatures: %d", cd[3]);
+               pr_info("ExtraFeatures: %d\n", cd[3]);
 
        n = cd[4] | (cd[5] << 8);
        if (n > MAX_MODES) {
-               err("Too many frame sizes");
+               pr_err("Too many frame sizes\n");
                return -ENODEV;
        }
 
@@ -353,15 +357,16 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        sd->fmts[i].pixelformat = V4L2_PIX_FMT_SBGGR8;
                        sd->fmts[i].bytesperline = widths[i];
                        sd->fmts[i].sizeimage = widths[i] * heights[i];
-                       info("Frame size: %dx%d bayer", widths[i], heights[i]);
+                       pr_info("Frame size: %dx%d bayer\n",
+                               widths[i], heights[i]);
                } else {
                        /* Found a match use janggu compression */
                        sd->fmts[i].pixelformat = V4L2_PIX_FMT_SE401;
                        sd->fmts[i].bytesperline = 0;
                        sd->fmts[i].sizeimage = widths[i] * heights[i] * 3;
-                       info("Frame size: %dx%d 1/%dth janggu",
-                            widths[i], heights[i],
-                            sd->fmts[i].priv * sd->fmts[i].priv);
+                       pr_info("Frame size: %dx%d 1/%dth janggu\n",
+                               widths[i], heights[i],
+                               sd->fmts[i].priv * sd->fmts[i].priv);
                }
        }
 
@@ -571,11 +576,12 @@ static void sd_pkt_scan_janggu(struct gspca_dev *gspca_dev, u8 *data, int len)
                plen   = ((bits + 47) >> 4) << 1;
                /* Sanity checks */
                if (plen > 1024) {
-                       err("invalid packet len %d restarting stream", plen);
+                       pr_err("invalid packet len %d restarting stream\n",
+                              plen);
                        goto error;
                }
                if (info == 3) {
-                       err("unknown frame info value restarting stream");
+                       pr_err("unknown frame info value restarting stream\n");
                        goto error;
                }
 
@@ -599,8 +605,8 @@ static void sd_pkt_scan_janggu(struct gspca_dev *gspca_dev, u8 *data, int len)
                        break;
                case 1: /* EOF */
                        if (sd->pixels_read != imagesize) {
-                               err("frame size %d expected %d",
-                                   sd->pixels_read, imagesize);
+                               pr_err("frame size %d expected %d\n",
+                                      sd->pixels_read, imagesize);
                                goto error;
                        }
                        sd_complete_frame(gspca_dev, sd->packet, plen);
index 4271f86..48aae39 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "sn9c2028"
 
 #include "gspca.h"
@@ -75,8 +77,8 @@ static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command)
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
                        2, 0, gspca_dev->usb_buf, 6, 500);
        if (rc < 0) {
-               err("command write [%02x] error %d",
-                               gspca_dev->usb_buf[0], rc);
+               pr_err("command write [%02x] error %d\n",
+                      gspca_dev->usb_buf[0], rc);
                return rc;
        }
 
@@ -93,7 +95,7 @@ static int sn9c2028_read1(struct gspca_dev *gspca_dev)
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
                        1, 0, gspca_dev->usb_buf, 1, 500);
        if (rc != 1) {
-               err("read1 error %d", rc);
+               pr_err("read1 error %d\n", rc);
                return (rc < 0) ? rc : -EIO;
        }
        PDEBUG(D_USBI, "read1 response %02x", gspca_dev->usb_buf[0]);
@@ -109,7 +111,7 @@ static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading)
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
                        4, 0, gspca_dev->usb_buf, 4, 500);
        if (rc != 4) {
-               err("read4 error %d", rc);
+               pr_err("read4 error %d\n", rc);
                return (rc < 0) ? rc : -EIO;
        }
        memcpy(reading, gspca_dev->usb_buf, 4);
@@ -131,7 +133,7 @@ static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command)
        for (i = 0; i < 256 && status < 2; i++)
                status = sn9c2028_read1(gspca_dev);
        if (status != 2) {
-               err("long command status read error %d", status);
+               pr_err("long command status read error %d\n", status);
                return (status < 0) ? status : -EIO;
        }
 
@@ -638,7 +640,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                err_code = start_vivitar_cam(gspca_dev);
                break;
        default:
-               err("Starting unknown camera, please report this");
+               pr_err("Starting unknown camera, please report this\n");
                return -ENXIO;
        }
 
index c431900..86e07a1 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/input.h>
 
 #include "gspca.h"
@@ -1123,7 +1125,7 @@ static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
                        length,
                        500);
        if (unlikely(result < 0 || result != length)) {
-               err("Read register failed 0x%02X", reg);
+               pr_err("Read register failed 0x%02X\n", reg);
                return -EIO;
        }
        return 0;
@@ -1144,7 +1146,7 @@ static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
                        length,
                        500);
        if (unlikely(result < 0 || result != length)) {
-               err("Write register failed index 0x%02X", reg);
+               pr_err("Write register failed index 0x%02X\n", reg);
                return -EIO;
        }
        return 0;
@@ -1275,14 +1277,14 @@ static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
                return -EINVAL;
 
        if (id != 0x7fa2) {
-               err("sensor id for ov9650 doesn't match (0x%04x)", id);
+               pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id);
                return -ENODEV;
        }
 
        for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
                if (i2c_w1(gspca_dev, ov9650_init[i].reg,
                                ov9650_init[i].val) < 0) {
-                       err("OV9650 sensor initialization failed");
+                       pr_err("OV9650 sensor initialization failed\n");
                        return -ENODEV;
                }
        }
@@ -1299,7 +1301,7 @@ static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
        for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
                if (i2c_w1(gspca_dev, ov9655_init[i].reg,
                                ov9655_init[i].val) < 0) {
-                       err("OV9655 sensor initialization failed");
+                       pr_err("OV9655 sensor initialization failed\n");
                        return -ENODEV;
                }
        }
@@ -1318,7 +1320,7 @@ static int soi968_init_sensor(struct gspca_dev *gspca_dev)
        for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
                if (i2c_w1(gspca_dev, soi968_init[i].reg,
                                soi968_init[i].val) < 0) {
-                       err("SOI968 sensor initialization failed");
+                       pr_err("SOI968 sensor initialization failed\n");
                        return -ENODEV;
                }
        }
@@ -1338,7 +1340,7 @@ static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
        for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
                if (i2c_w1(gspca_dev, ov7660_init[i].reg,
                                ov7660_init[i].val) < 0) {
-                       err("OV7660 sensor initialization failed");
+                       pr_err("OV7660 sensor initialization failed\n");
                        return -ENODEV;
                }
        }
@@ -1355,7 +1357,7 @@ static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
        for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
                if (i2c_w1(gspca_dev, ov7670_init[i].reg,
                                ov7670_init[i].val) < 0) {
-                       err("OV7670 sensor initialization failed");
+                       pr_err("OV7670 sensor initialization failed\n");
                        return -ENODEV;
                }
        }
@@ -1379,14 +1381,14 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
                for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
                        if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
                                        mt9v011_init[i].val) < 0) {
-                               err("MT9V011 sensor initialization failed");
+                               pr_err("MT9V011 sensor initialization failed\n");
                                return -ENODEV;
                        }
                }
                sd->hstart = 2;
                sd->vstart = 2;
                sd->sensor = SENSOR_MT9V011;
-               info("MT9V011 sensor detected");
+               pr_info("MT9V011 sensor detected\n");
                return 0;
        }
 
@@ -1397,7 +1399,7 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
                for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
                        if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
                                        mt9v111_init[i].val) < 0) {
-                               err("MT9V111 sensor initialization failed");
+                               pr_err("MT9V111 sensor initialization failed\n");
                                return -ENODEV;
                        }
                }
@@ -1407,7 +1409,7 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
                sd->hstart = 2;
                sd->vstart = 2;
                sd->sensor = SENSOR_MT9V111;
-               info("MT9V111 sensor detected");
+               pr_info("MT9V111 sensor detected\n");
                return 0;
        }
 
@@ -1422,14 +1424,14 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
                for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
                        if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
                                        mt9v112_init[i].val) < 0) {
-                               err("MT9V112 sensor initialization failed");
+                               pr_err("MT9V112 sensor initialization failed\n");
                                return -ENODEV;
                        }
                }
                sd->hstart = 6;
                sd->vstart = 2;
                sd->sensor = SENSOR_MT9V112;
-               info("MT9V112 sensor detected");
+               pr_info("MT9V112 sensor detected\n");
                return 0;
        }
 
@@ -1443,7 +1445,7 @@ static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
        for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
                if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
                                mt9m112_init[i].val) < 0) {
-                       err("MT9M112 sensor initialization failed");
+                       pr_err("MT9M112 sensor initialization failed\n");
                        return -ENODEV;
                }
        }
@@ -1461,7 +1463,7 @@ static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
        for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
                if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
                                mt9m111_init[i].val) < 0) {
-                       err("MT9M111 sensor initialization failed");
+                       pr_err("MT9M111 sensor initialization failed\n");
                        return -ENODEV;
                }
        }
@@ -1485,20 +1487,20 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
        switch (id) {
        case 0x8411:
        case 0x8421:
-               info("MT9M001 color sensor detected");
+               pr_info("MT9M001 color sensor detected\n");
                break;
        case 0x8431:
-               info("MT9M001 mono sensor detected");
+               pr_info("MT9M001 mono sensor detected\n");
                break;
        default:
-               err("No MT9M001 chip detected, ID = %x\n", id);
+               pr_err("No MT9M001 chip detected, ID = %x\n\n", id);
                return -ENODEV;
        }
 
        for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
                if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
                                mt9m001_init[i].val) < 0) {
-                       err("MT9M001 sensor initialization failed");
+                       pr_err("MT9M001 sensor initialization failed\n");
                        return -ENODEV;
                }
        }
@@ -1517,7 +1519,7 @@ static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
        for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
                if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
                                hv7131r_init[i].val) < 0) {
-                       err("HV7131R Sensor initialization failed");
+                       pr_err("HV7131R Sensor initialization failed\n");
                        return -ENODEV;
                }
        }
@@ -2103,7 +2105,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
                value = bridge_init[i][1];
                if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
-                       err("Device initialization failed");
+                       pr_err("Device initialization failed\n");
                        return -ENODEV;
                }
        }
@@ -2114,7 +2116,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                reg_w1(gspca_dev, 0x1006, 0x20);
 
        if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
-               err("Device initialization failed");
+               pr_err("Device initialization failed\n");
                return -ENODEV;
        }
 
@@ -2122,27 +2124,27 @@ static int sd_init(struct gspca_dev *gspca_dev)
        case SENSOR_OV9650:
                if (ov9650_init_sensor(gspca_dev) < 0)
                        return -ENODEV;
-               info("OV9650 sensor detected");
+               pr_info("OV9650 sensor detected\n");
                break;
        case SENSOR_OV9655:
                if (ov9655_init_sensor(gspca_dev) < 0)
                        return -ENODEV;
-               info("OV9655 sensor detected");
+               pr_info("OV9655 sensor detected\n");
                break;
        case SENSOR_SOI968:
                if (soi968_init_sensor(gspca_dev) < 0)
                        return -ENODEV;
-               info("SOI968 sensor detected");
+               pr_info("SOI968 sensor detected\n");
                break;
        case SENSOR_OV7660:
                if (ov7660_init_sensor(gspca_dev) < 0)
                        return -ENODEV;
-               info("OV7660 sensor detected");
+               pr_info("OV7660 sensor detected\n");
                break;
        case SENSOR_OV7670:
                if (ov7670_init_sensor(gspca_dev) < 0)
                        return -ENODEV;
-               info("OV7670 sensor detected");
+               pr_info("OV7670 sensor detected\n");
                break;
        case SENSOR_MT9VPRB:
                if (mt9v_init_sensor(gspca_dev) < 0)
@@ -2151,12 +2153,12 @@ static int sd_init(struct gspca_dev *gspca_dev)
        case SENSOR_MT9M111:
                if (mt9m111_init_sensor(gspca_dev) < 0)
                        return -ENODEV;
-               info("MT9M111 sensor detected");
+               pr_info("MT9M111 sensor detected\n");
                break;
        case SENSOR_MT9M112:
                if (mt9m112_init_sensor(gspca_dev) < 0)
                        return -ENODEV;
-               info("MT9M112 sensor detected");
+               pr_info("MT9M112 sensor detected\n");
                break;
        case SENSOR_MT9M001:
                if (mt9m001_init_sensor(gspca_dev) < 0)
@@ -2165,10 +2167,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
        case SENSOR_HV7131R:
                if (hv7131r_init_sensor(gspca_dev) < 0)
                        return -ENODEV;
-               info("HV7131R sensor detected");
+               pr_info("HV7131R sensor detected\n");
                break;
        default:
-               info("Unsupported Sensor");
+               pr_info("Unsupported Sensor\n");
                return -ENODEV;
        }
 
@@ -2263,19 +2265,19 @@ static int sd_start(struct gspca_dev *gspca_dev)
        switch (mode & SCALE_MASK) {
        case SCALE_1280x1024:
                scale = 0xc0;
-               info("Set 1280x1024");
+               pr_info("Set 1280x1024\n");
                break;
        case SCALE_640x480:
                scale = 0x80;
-               info("Set 640x480");
+               pr_info("Set 640x480\n");
                break;
        case SCALE_320x240:
                scale = 0x90;
-               info("Set 320x240");
+               pr_info("Set 320x240\n");
                break;
        case SCALE_160x120:
                scale = 0xa0;
-               info("Set 160x120");
+               pr_info("Set 160x120\n");
                break;
        }
 
@@ -2513,7 +2515,7 @@ static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
        {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
        {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
-       {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)},
+       {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, LED_REVERSE)},
        {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, LED_REVERSE)},
        {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
        {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
index c477ad1..c746bf1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Sonix sn9c102p sn9c105 sn9c120 (jpeg) subdriver
  *
- * Copyright (C) 2009-2010 Jean-François Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009-2011 Jean-François Moine <http://moinejf.free.fr>
  * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
  *
  * This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "sonixj"
 
 #include <linux/input.h>
@@ -136,7 +138,7 @@ static void setillum(struct gspca_dev *gspca_dev);
 static void setfreq(struct gspca_dev *gspca_dev);
 
 static const struct ctrl sd_ctrls[NCTRLS] = {
-[BRIGHTNESS] =  {
+[BRIGHTNESS] = {
            {
                .id      = V4L2_CID_BRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -157,7 +159,7 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
 #define CONTRAST_MAX 127
                .maximum = CONTRAST_MAX,
                .step    = 1,
-               .default_value = 63,
+               .default_value = 20,
            },
            .set_control = setcontrast
        },
@@ -737,7 +739,7 @@ static const u8 mi0360_sensor_init[][8] = {
        {0xd1, 0x5d, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xd1, 0x5d, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xd1, 0x5d, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
-       {0xd1, 0x5d, 0x2f, 0xf7, 0xB0, 0x00, 0x04, 0x10},
+       {0xd1, 0x5d, 0x2f, 0xf7, 0xb0, 0x00, 0x04, 0x10},
        {0xd1, 0x5d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xd1, 0x5d, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
        {0xb1, 0x5d, 0x3d, 0x06, 0x8f, 0x00, 0x00, 0x10},
@@ -1277,7 +1279,7 @@ static const u8 soi768_sensor_param1[][8] = {
                        /* global gain ? : 07 - change with 0x15 at the end */
        {0xa1, 0x21, 0x10, 0x3f, 0x00, 0x00, 0x00, 0x10}, /* ???? : 063f */
        {0xa1, 0x21, 0x04, 0x06, 0x00, 0x00, 0x00, 0x10},
-       {0xb1, 0x21, 0x2d, 0x00, 0x02, 0x00, 0x00, 0x10},
+       {0xb1, 0x21, 0x2d, 0x63, 0x03, 0x00, 0x00, 0x10},
                        /* exposure ? : 0200 - change with 0x1e at the end */
        {}
 };
@@ -1395,7 +1397,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
                return;
 #ifdef GSPCA_DEBUG
        if (len > USB_BUF_SZ) {
-               err("reg_r: buffer overflow");
+               pr_err("reg_r: buffer overflow\n");
                return;
        }
 #endif
@@ -1408,7 +1410,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
                        500);
        PDEBUG(D_USBI, "reg_r [%02x] -> %02x", value, gspca_dev->usb_buf[0]);
        if (ret < 0) {
-               err("reg_r err %d", ret);
+               pr_err("reg_r err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -1432,7 +1434,7 @@ static void reg_w1(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               err("reg_w1 err %d", ret);
+               pr_err("reg_w1 err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -1449,7 +1451,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
                value, buffer[0], buffer[1]);
 #ifdef GSPCA_DEBUG
        if (len > USB_BUF_SZ) {
-               err("reg_w: buffer overflow");
+               pr_err("reg_w: buffer overflow\n");
                return;
        }
 #endif
@@ -1462,7 +1464,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf, len,
                        500);
        if (ret < 0) {
-               err("reg_w err %d", ret);
+               pr_err("reg_w err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -1502,7 +1504,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
                        gspca_dev->usb_buf, 8,
                        500);
        if (ret < 0) {
-               err("i2c_w1 err %d", ret);
+               pr_err("i2c_w1 err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -1527,7 +1529,7 @@ static void i2c_w8(struct gspca_dev *gspca_dev,
                        500);
        msleep(2);
        if (ret < 0) {
-               err("i2c_w8 err %d", ret);
+               pr_err("i2c_w8 err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -1591,7 +1593,7 @@ static void hv7131r_probe(struct gspca_dev *gspca_dev)
                PDEBUG(D_PROBE, "Sensor HV7131R found");
                return;
        }
-       warn("Erroneous HV7131R ID 0x%02x 0x%02x 0x%02x",
+       pr_warn("Erroneous HV7131R ID 0x%02x 0x%02x 0x%02x\n",
                gspca_dev->usb_buf[0], gspca_dev->usb_buf[1],
                gspca_dev->usb_buf[2]);
 }
@@ -1710,7 +1712,7 @@ static void ov7648_probe(struct gspca_dev *gspca_dev)
                sd->sensor = SENSOR_PO1030;
                return;
        }
-       err("Unknown sensor %04x", val);
+       pr_err("Unknown sensor %04x\n", val);
 }
 
 /* 0c45:6142 sensor may be po2030n, gc0305 or gc0307 */
@@ -1748,7 +1750,7 @@ static void po2030n_probe(struct gspca_dev *gspca_dev)
                PDEBUG(D_PROBE, "Sensor po2030n");
 /*             sd->sensor = SENSOR_PO2030N; */
        } else {
-               err("Unknown sensor ID %04x", val);
+               pr_err("Unknown sensor ID %04x\n", val);
        }
 }
 
@@ -2006,8 +2008,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        case SENSOR_OM6802:
                expo = brightness << 2;
                sd->exposure = setexposure(gspca_dev, expo);
-               k2 = brightness >> 3;
-               break;
+               return;                 /* Y offset already set */
        }
 
        reg_w1(gspca_dev, 0x96, k2);    /* color matrix Y offset */
@@ -2019,13 +2020,13 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        u8 k2;
        u8 contrast[6];
 
-       k2 = sd->ctrls[CONTRAST].val * 0x30 / (CONTRAST_MAX + 1)
-                               + 0x10;         /* 10..40 */
+       k2 = sd->ctrls[CONTRAST].val * 37 / (CONTRAST_MAX + 1)
+                               + 37;           /* 37..73 */
        contrast[0] = (k2 + 1) / 2;             /* red */
        contrast[1] = 0;
        contrast[2] = k2;                       /* green */
        contrast[3] = 0;
-       contrast[4] = (k2 + 1) / 5;             /* blue */
+       contrast[4] = k2 / 5;                   /* blue */
        contrast[5] = 0;
        reg_w(gspca_dev, 0x84, contrast, sizeof contrast);
 }
@@ -2507,9 +2508,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                break;
        case SENSOR_HV7131R:
        case SENSOR_MI0360:
-               if (mode)
-                       reg01 |= SYS_SEL_48M;   /* 320x240: clk 48Mhz */
-               else
+               if (!mode)
                        reg01 &= ~SYS_SEL_48M;  /* 640x480: clk 24Mhz */
                reg17 &= ~MCK_SIZE_MASK;
                reg17 |= 0x01;                  /* clock / 1 */
index 76c006b..6956731 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * spca1528 subdriver
  *
- * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
+ * Copyright (C) 2010-2011 Jean-Francois Moine (http://moinejf.free.fr)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -18,6 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "spca1528"
 
 #include "gspca.h"
@@ -171,7 +173,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
        PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index,
                         gspca_dev->usb_buf[0]);
        if (ret < 0) {
-               err("reg_r err %d", ret);
+               pr_err("reg_r err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -193,7 +195,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        value, index,
                        NULL, 0, 500);
        if (ret < 0) {
-               err("reg_w err %d", ret);
+               pr_err("reg_w err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -217,21 +219,23 @@ static void reg_wb(struct gspca_dev *gspca_dev,
                        value, index,
                        gspca_dev->usb_buf, 1, 500);
        if (ret < 0) {
-               err("reg_w err %d", ret);
+               pr_err("reg_w err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
 
 static void wait_status_0(struct gspca_dev *gspca_dev)
 {
-       int i;
+       int i, w;
 
-       i = 20;
+       i = 16;
+       w = 0;
        do {
                reg_r(gspca_dev, 0x21, 0x0000, 1);
                if (gspca_dev->usb_buf[0] == 0)
                        return;
-               msleep(30);
+               w += 15;
+               msleep(w);
        } while (--i > 0);
        PDEBUG(D_ERR, "wait_status_0 timeout");
        gspca_dev->usb_err = -ETIME;
@@ -307,8 +311,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->color = COLOR_DEF;
        sd->sharpness = SHARPNESS_DEF;
 
-       gspca_dev->nbalt = 4;           /* use alternate setting 3 */
-
        return 0;
 }
 
@@ -347,8 +349,12 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
        mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
        reg_wb(gspca_dev, 0x25, 0x0000, 0x0004, mode);
        reg_r(gspca_dev, 0x25, 0x0004, 1);
-       reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06);
+       reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06);  /* 420 */
        reg_r(gspca_dev, 0x27, 0x0000, 1);
+
+/* not useful..
+       gspca_dev->alt = 4;             * use alternate setting 3 */
+
        return gspca_dev->usb_err;
 }
 
@@ -361,8 +367,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x22);          /* JPEG 411 */
 
-       /* the JPEG quality seems to be 82% */
-       jpeg_set_qual(sd->jpeg_hdr, 82);
+       /* the JPEG quality shall be 85% */
+       jpeg_set_qual(sd->jpeg_hdr, 85);
 
        /* set the controls */
        setbrightness(gspca_dev);
@@ -377,7 +383,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        /* start the capture */
        wait_status_0(gspca_dev);
-       reg_w(gspca_dev, 0x31, 0x0000, 0x0004);
+       reg_w(gspca_dev, 0x31, 0x0000, 0x0004); /* start request */
        wait_status_1(gspca_dev);
        wait_status_0(gspca_dev);
        msleep(200);
@@ -390,7 +396,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 {
        /* stop the capture */
        wait_status_0(gspca_dev);
-       reg_w(gspca_dev, 0x31, 0x0000, 0x0000);
+       reg_w(gspca_dev, 0x31, 0x0000, 0x0000); /* stop request */
        wait_status_1(gspca_dev);
        wait_status_0(gspca_dev);
 }
index 3e76951..bb82c94 100644 (file)
@@ -19,6 +19,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "spca500"
 
 #include "gspca.h"
@@ -396,7 +398,7 @@ static int reg_w(struct gspca_dev *gspca_dev,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        value, index, NULL, 0, 500);
        if (ret < 0)
-               err("reg write: error %d", ret);
+               pr_err("reg write: error %d\n", ret);
        return ret;
 }
 
@@ -418,7 +420,7 @@ static int reg_r_12(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf, length,
                        500);           /* timeout */
        if (ret < 0) {
-               err("reg_r_12 err %d", ret);
+               pr_err("reg_r_12 err %d\n", ret);
                return ret;
        }
        return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
index f7ef282..7aaac72 100644 (file)
@@ -19,6 +19,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "spca501"
 
 #include "gspca.h"
@@ -1852,7 +1854,7 @@ static int reg_write(struct usb_device *dev,
        PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x",
                req, index, value);
        if (ret < 0)
-               err("reg write: error %d", ret);
+               pr_err("reg write: error %d\n", ret);
        return ret;
 }
 
index e5bf865..16722dc 100644 (file)
@@ -19,6 +19,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "spca505"
 
 #include "gspca.h"
@@ -578,7 +580,7 @@ static int reg_write(struct usb_device *dev,
        PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
                req, index, value, ret);
        if (ret < 0)
-               err("reg write: error %d", ret);
+               pr_err("reg write: error %d\n", ret);
        return ret;
 }
 
@@ -685,8 +687,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
                return ret;
        }
        if (ret != 0x0101) {
-               err("After vector read returns 0x%04x should be 0x0101",
-                       ret);
+               pr_err("After vector read returns 0x%04x should be 0x0101\n",
+                      ret);
        }
 
        ret = reg_write(gspca_dev->dev, 0x06, 0x16, 0x0a);
index 9d0b460..a44fe3d 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "spca508"
 
 #include "gspca.h"
@@ -1275,7 +1277,7 @@ static int reg_write(struct usb_device *dev,
        PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x",
                index, value);
        if (ret < 0)
-               err("reg write: error %d", ret);
+               pr_err("reg write: error %d\n", ret);
        return ret;
 }
 
@@ -1297,7 +1299,7 @@ static int reg_read(struct gspca_dev *gspca_dev,
        PDEBUG(D_USBI, "reg read i:%04x --> %02x",
                index, gspca_dev->usb_buf[0]);
        if (ret < 0) {
-               err("reg_read err %d", ret);
+               pr_err("reg_read err %d\n", ret);
                return ret;
        }
        return gspca_dev->usb_buf[0];
index e836e77..c82fd53 100644 (file)
@@ -20,6 +20,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "spca561"
 
 #include <linux/input.h>
@@ -315,7 +317,7 @@ static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
                              value, index, NULL, 0, 500);
        PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
        if (ret < 0)
-               err("reg write: error %d", ret);
+               pr_err("reg write: error %d\n", ret);
 }
 
 static void write_vector(struct gspca_dev *gspca_dev,
index 5ba96af..df805f7 100644 (file)
@@ -33,6 +33,8 @@
  * drivers.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "sq905"
 
 #include <linux/workqueue.h>
@@ -123,8 +125,7 @@ static int sq905_command(struct gspca_dev *gspca_dev, u16 index)
                              SQ905_COMMAND, index, gspca_dev->usb_buf, 1,
                              SQ905_CMD_TIMEOUT);
        if (ret < 0) {
-               err("%s: usb_control_msg failed (%d)",
-                       __func__, ret);
+               pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret);
                return ret;
        }
 
@@ -135,8 +136,7 @@ static int sq905_command(struct gspca_dev *gspca_dev, u16 index)
                              SQ905_PING, 0, gspca_dev->usb_buf, 1,
                              SQ905_CMD_TIMEOUT);
        if (ret < 0) {
-               err("%s: usb_control_msg failed 2 (%d)",
-                       __func__, ret);
+               pr_err("%s: usb_control_msg failed 2 (%d)\n", __func__, ret);
                return ret;
        }
 
@@ -158,7 +158,7 @@ static int sq905_ack_frame(struct gspca_dev *gspca_dev)
                              SQ905_READ_DONE, 0, gspca_dev->usb_buf, 1,
                              SQ905_CMD_TIMEOUT);
        if (ret < 0) {
-               err("%s: usb_control_msg failed (%d)", __func__, ret);
+               pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret);
                return ret;
        }
 
@@ -186,7 +186,7 @@ sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock)
        if (need_lock)
                mutex_unlock(&gspca_dev->usb_lock);
        if (ret < 0) {
-               err("%s: usb_control_msg failed (%d)", __func__, ret);
+               pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret);
                return ret;
        }
        ret = usb_bulk_msg(gspca_dev->dev,
@@ -195,8 +195,7 @@ sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock)
 
        /* successful, it returns 0, otherwise  negative */
        if (ret < 0 || act_len != size) {
-               err("bulk read fail (%d) len %d/%d",
-                       ret, act_len, size);
+               pr_err("bulk read fail (%d) len %d/%d\n", ret, act_len, size);
                return -EIO;
        }
        return 0;
@@ -226,7 +225,7 @@ static void sq905_dostream(struct work_struct *work)
 
        buffer = kmalloc(SQ905_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
        if (!buffer) {
-               err("Couldn't allocate USB buffer");
+               pr_err("Couldn't allocate USB buffer\n");
                goto quit_stream;
        }
 
index 457563b..c2c0560 100644 (file)
@@ -27,6 +27,8 @@
  * and may contain code fragments from it.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "sq905c"
 
 #include <linux/workqueue.h>
@@ -95,8 +97,7 @@ static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index)
                              command, index, NULL, 0,
                              SQ905C_CMD_TIMEOUT);
        if (ret < 0) {
-               err("%s: usb_control_msg failed (%d)",
-                       __func__, ret);
+               pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret);
                return ret;
        }
 
@@ -115,8 +116,7 @@ static int sq905c_read(struct gspca_dev *gspca_dev, u16 command, u16 index,
                              command, index, gspca_dev->usb_buf, size,
                              SQ905C_CMD_TIMEOUT);
        if (ret < 0) {
-               err("%s: usb_control_msg failed (%d)",
-                      __func__, ret);
+               pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret);
                return ret;
        }
 
@@ -146,7 +146,7 @@ static void sq905c_dostream(struct work_struct *work)
 
        buffer = kmalloc(SQ905C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
        if (!buffer) {
-               err("Couldn't allocate USB buffer");
+               pr_err("Couldn't allocate USB buffer\n");
                goto quit_stream;
        }
 
index 8215d5d..e4255b4 100644 (file)
@@ -20,6 +20,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "sq930x"
 
 #include "gspca.h"
@@ -468,7 +470,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
                        value, 0, gspca_dev->usb_buf, len,
                        500);
        if (ret < 0) {
-               err("reg_r %04x failed %d", value, ret);
+               pr_err("reg_r %04x failed %d\n", value, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -488,7 +490,7 @@ static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
                        500);
        msleep(30);
        if (ret < 0) {
-               err("reg_w %04x %04x failed %d", value, index, ret);
+               pr_err("reg_w %04x %04x failed %d\n", value, index, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -511,7 +513,7 @@ static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index,
                        1000);
        msleep(30);
        if (ret < 0) {
-               err("reg_wb %04x %04x failed %d", value, index, ret);
+               pr_err("reg_wb %04x %04x failed %d\n", value, index, ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -556,7 +558,7 @@ static void i2c_write(struct sd *sd,
                        gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
                        500);
        if (ret < 0) {
-               err("i2c_write failed %d", ret);
+               pr_err("i2c_write failed %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -575,7 +577,7 @@ static void ucbus_write(struct gspca_dev *gspca_dev,
 
 #ifdef GSPCA_DEBUG
        if ((batchsize - 1) * 3 > USB_BUF_SZ) {
-               err("Bug: usb_buf overflow");
+               pr_err("Bug: usb_buf overflow\n");
                gspca_dev->usb_err = -ENOMEM;
                return;
        }
@@ -612,7 +614,7 @@ static void ucbus_write(struct gspca_dev *gspca_dev,
                                gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
                                500);
                if (ret < 0) {
-                       err("ucbus_write failed %d", ret);
+                       pr_err("ucbus_write failed %d\n", ret);
                        gspca_dev->usb_err = ret;
                        return;
                }
@@ -688,7 +690,7 @@ static void cmos_probe(struct gspca_dev *gspca_dev)
                        break;
        }
        if (i >= ARRAY_SIZE(probe_order)) {
-               err("Unknown sensor");
+               pr_err("Unknown sensor\n");
                gspca_dev->usb_err = -EINVAL;
                return;
        }
@@ -696,7 +698,8 @@ static void cmos_probe(struct gspca_dev *gspca_dev)
        switch (sd->sensor) {
        case SENSOR_OV7660:
        case SENSOR_OV9630:
-               err("Sensor %s not yet treated", sensor_tb[sd->sensor].name);
+               pr_err("Sensor %s not yet treated\n",
+                      sensor_tb[sd->sensor].name);
                gspca_dev->usb_err = -EINVAL;
                break;
        }
@@ -1091,7 +1094,7 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev)
        gspca_dev->cam.bulk_nurbs = 1;
        ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC);
        if (ret < 0)
-               err("sd_dq_callback() err %d", ret);
+               pr_err("sd_dq_callback() err %d\n", ret);
 
        /* wait a little time, otherwise the webcam crashes */
        msleep(100);
index 7637477..42a7a28 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "stk014"
 
 #include "gspca.h"
@@ -137,7 +139,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               err("reg_r err %d", ret);
+               pr_err("reg_r err %d\n", ret);
                gspca_dev->usb_err = ret;
                return 0;
        }
@@ -162,7 +164,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        0,
                        500);
        if (ret < 0) {
-               err("reg_w err %d", ret);
+               pr_err("reg_w err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -192,7 +194,7 @@ static void rcv_val(struct gspca_dev *gspca_dev,
                        &alen,
                        500);           /* timeout in milliseconds */
        if (ret < 0) {
-               err("rcv_val err %d", ret);
+               pr_err("rcv_val err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -235,7 +237,7 @@ static void snd_val(struct gspca_dev *gspca_dev,
                        &alen,
                        500);   /* timeout in milliseconds */
        if (ret < 0) {
-               err("snd_val err %d", ret);
+               pr_err("snd_val err %d\n", ret);
                gspca_dev->usb_err = ret;
        } else {
                if (ads == 0x003f08) {
@@ -315,7 +317,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        ret = reg_r(gspca_dev, 0x0740);
        if (gspca_dev->usb_err >= 0) {
                if (ret != 0xff) {
-                       err("init reg: 0x%02x", ret);
+                       pr_err("init reg: 0x%02x\n", ret);
                        gspca_dev->usb_err = -EIO;
                }
        }
@@ -349,8 +351,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
                                        gspca_dev->iface,
                                        gspca_dev->alt);
        if (ret < 0) {
-               err("set intf %d %d failed",
-                       gspca_dev->iface, gspca_dev->alt);
+               pr_err("set intf %d %d failed\n",
+                      gspca_dev->iface, gspca_dev->alt);
                gspca_dev->usb_err = ret;
                goto out;
        }
index e2ef41c..4dcc7e3 100644 (file)
@@ -27,6 +27,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "stv0680"
 
 #include "gspca.h"
@@ -79,7 +81,7 @@ static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val,
                              val, 0, gspca_dev->usb_buf, size, 500);
 
        if ((ret < 0) && (req != 0x0a))
-               err("usb_control_msg error %i, request = 0x%x, error = %i",
+               pr_err("usb_control_msg error %i, request = 0x%x, error = %i\n",
                       set, req, ret);
 
        return ret;
@@ -236,7 +238,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0100, 0x12) != 0x12 ||
            gspca_dev->usb_buf[8] != 0x53 || gspca_dev->usb_buf[9] != 0x05) {
-               err("Could not get descriptor 0100.");
+               pr_err("Could not get descriptor 0100\n");
                return stv0680_handle_error(gspca_dev, -EIO);
        }
 
index 2f3c3a6..5b318fa 100644 (file)
@@ -6,5 +6,5 @@ gspca_stv06xx-objs := stv06xx.o \
                      stv06xx_pb0100.o \
                      stv06xx_st6422.o
 
-EXTRA_CFLAGS += -Idrivers/media/video/gspca
+ccflags-y += -Idrivers/media/video/gspca
 
index abf1658..b1fca7d 100644 (file)
@@ -27,6 +27,8 @@
  * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/input.h>
 #include "stv06xx_sensor.h"
 
@@ -189,7 +191,7 @@ int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value)
                              0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH,
                              STV06XX_URB_MSG_TIMEOUT);
        if (err < 0) {
-               err("I2C: Read error writing address: %d", err);
+               pr_err("I2C: Read error writing address: %d\n", err);
                return err;
        }
 
@@ -213,14 +215,14 @@ static void stv06xx_dump_bridge(struct sd *sd)
        int i;
        u8 data, buf;
 
-       info("Dumping all stv06xx bridge registers");
+       pr_info("Dumping all stv06xx bridge registers\n");
        for (i = 0x1400; i < 0x160f; i++) {
                stv06xx_read_bridge(sd, i, &data);
 
-               info("Read 0x%x from address 0x%x", data, i);
+               pr_info("Read 0x%x from address 0x%x\n", data, i);
        }
 
-       info("Testing stv06xx bridge registers for writability");
+       pr_info("Testing stv06xx bridge registers for writability\n");
        for (i = 0x1400; i < 0x160f; i++) {
                stv06xx_read_bridge(sd, i, &data);
                buf = data;
@@ -228,12 +230,12 @@ static void stv06xx_dump_bridge(struct sd *sd)
                stv06xx_write_bridge(sd, i, 0xff);
                stv06xx_read_bridge(sd, i, &data);
                if (data == 0xff)
-                       info("Register 0x%x is read/write", i);
+                       pr_info("Register 0x%x is read/write\n", i);
                else if (data != buf)
-                       info("Register 0x%x is read/write,"
-                            " but only partially", i);
+                       pr_info("Register 0x%x is read/write, but only partially\n",
+                               i);
                else
-                       info("Register 0x%x is read-only", i);
+                       pr_info("Register 0x%x is read-only\n", i);
 
                stv06xx_write_bridge(sd, i, buf);
        }
index e0f63c5..d270a59 100644 (file)
@@ -37,6 +37,8 @@
 
 #define STV_ISOC_ENDPOINT_ADDR         0x81
 
+#define STV_R                           0x0509
+
 #define STV_REG23                      0x0423
 
 /* Control registers of the STV0600 ASIC */
@@ -61,7 +63,9 @@
 
 /* Refers to the CIF 352x288 and QCIF 176x144 */
 /* 1: 288 lines, 2: 144 lines */
-#define STV_Y_CTRL                     0x15c3
+#define STV_Y_CTRL                     0x15c3
+
+#define STV_RESET                       0x1620
 
 /* 0xa: 352 columns, 0x6: 176 columns */
 #define STV_X_CTRL                     0x1680
index b815685..a8698b7 100644 (file)
@@ -28,6 +28,8 @@
  * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "stv06xx_hdcs.h"
 
 static const struct ctrl hdcs1x00_ctrl[] = {
@@ -428,7 +430,7 @@ static int hdcs_probe_1x00(struct sd *sd)
        if (ret < 0 || sensor != 0x08)
                return -ENODEV;
 
-       info("HDCS-1000/1100 sensor detected");
+       pr_info("HDCS-1000/1100 sensor detected\n");
 
        sd->gspca_dev.cam.cam_mode = hdcs1x00_mode;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode);
@@ -487,7 +489,7 @@ static int hdcs_probe_1020(struct sd *sd)
        if (ret < 0 || sensor != 0x10)
                return -ENODEV;
 
-       info("HDCS-1020 sensor detected");
+       pr_info("HDCS-1020 sensor detected\n");
 
        sd->gspca_dev.cam.cam_mode = hdcs1020_mode;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode);
@@ -601,11 +603,11 @@ static int hdcs_dump(struct sd *sd)
 {
        u16 reg, val;
 
-       info("Dumping sensor registers:");
+       pr_info("Dumping sensor registers:\n");
 
        for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) {
                stv06xx_read_sensor(sd, reg, &val);
-               info("reg 0x%02x = 0x%02x", reg, val);
+               pr_info("reg 0x%02x = 0x%02x\n", reg, val);
        }
        return 0;
 }
index 75a5b9c..26f14fc 100644 (file)
@@ -44,6 +44,8 @@
  * PB_CFILLIN       = R5  = 0x0E (14 dec)     : Sets the frame rate
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "stv06xx_pb0100.h"
 
 static const struct ctrl pb0100_ctrl[] = {
@@ -190,7 +192,7 @@ static int pb0100_probe(struct sd *sd)
                if (!sensor_settings)
                        return -ENOMEM;
 
-               info("Photobit pb0100 sensor detected");
+               pr_info("Photobit pb0100 sensor detected\n");
 
                sd->gspca_dev.cam.cam_mode = pb0100_mode;
                sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode);
index 8a456de..9940e03 100644 (file)
@@ -26,6 +26,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "stv06xx_st6422.h"
 
 /* controls */
@@ -136,7 +138,7 @@ static int st6422_probe(struct sd *sd)
        if (sd->bridge != BRIDGE_ST6422)
                return -ENODEV;
 
-       info("st6422 sensor detected");
+       pr_info("st6422 sensor detected\n");
 
        sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL);
        if (!sensor_settings)
index f839843..a5c69d9 100644 (file)
@@ -27,6 +27,8 @@
  * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "stv06xx_vv6410.h"
 
 static struct v4l2_pix_format vv6410_mode[] = {
@@ -112,7 +114,7 @@ static int vv6410_probe(struct sd *sd)
                return -ENODEV;
 
        if (data == 0x19) {
-               info("vv6410 sensor detected");
+               pr_info("vv6410 sensor detected\n");
 
                sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32),
                                          GFP_KERNEL);
@@ -138,18 +140,7 @@ static int vv6410_init(struct sd *sd)
        s32 *sensor_settings = sd->sensor_priv;
 
        for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) {
-               /* if NULL then len contains single value */
-               if (stv_bridge_init[i].data == NULL) {
-                       err = stv06xx_write_bridge(sd,
-                               stv_bridge_init[i].start,
-                               stv_bridge_init[i].len);
-               } else {
-                       int j;
-                       for (j = 0; j < stv_bridge_init[i].len; j++)
-                               err = stv06xx_write_bridge(sd,
-                                       stv_bridge_init[i].start + j,
-                                       stv_bridge_init[i].data[j]);
-               }
+               stv06xx_write_bridge(sd, stv_bridge_init[i].addr, stv_bridge_init[i].data);
        }
 
        if (err < 0)
@@ -183,15 +174,6 @@ static int vv6410_start(struct sd *sd)
        struct cam *cam = &sd->gspca_dev.cam;
        u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
 
-       if (priv & VV6410_CROP_TO_QVGA) {
-               PDEBUG(D_CONF, "Cropping to QVGA");
-               stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1);
-               stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1);
-       } else {
-               stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1);
-               stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1);
-       }
-
        if (priv & VV6410_SUBSAMPLE) {
                PDEBUG(D_CONF, "Enabling subsampling");
                stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02);
@@ -201,8 +183,8 @@ static int vv6410_start(struct sd *sd)
        } else {
                stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
                stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
+               stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x00);
 
-               stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
        }
 
        /* Turn on LED */
@@ -242,11 +224,11 @@ static int vv6410_dump(struct sd *sd)
        u8 i;
        int err = 0;
 
-       info("Dumping all vv6410 sensor registers");
+       pr_info("Dumping all vv6410 sensor registers\n");
        for (i = 0; i < 0xff && !err; i++) {
                u16 data;
                err = stv06xx_read_sensor(sd, i, &data);
-               info("Register 0x%x contained 0x%x", i, data);
+               pr_info("Register 0x%x contained 0x%x\n", i, data);
        }
        return (err < 0) ? err : 0;
 }
index 7fe3587..a25b887 100644 (file)
@@ -211,49 +211,49 @@ const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
 
 /* If NULL, only single value to write, stored in len */
 struct stv_init {
-       const u8 *data;
-       u16 start;
-       u8 len;
-};
-
-static const u8 x1500[] = {    /* 0x1500 - 0x150f */
-       0x0b, 0xa7, 0xb7, 0x00, 0x00
-};
-
-static const u8 x1536[] = {    /* 0x1536 - 0x153b */
-       0x02, 0x00, 0x60, 0x01, 0x20, 0x01
+       u16 addr;
+       u8 data;
 };
 
 static const struct stv_init stv_bridge_init[] = {
        /* This reg is written twice. Some kind of reset? */
-       {NULL,  0x1620, 0x80},
-       {NULL,  0x1620, 0x00},
-       {NULL,  0x1443, 0x00},
-       {NULL,  0x1423, 0x04},
-       {x1500, 0x1500, ARRAY_SIZE(x1500)},
-       {x1536, 0x1536, ARRAY_SIZE(x1536)},
+       {STV_RESET, 0x80},
+       {STV_RESET, 0x00},
+       {STV_SCAN_RATE, 0x00},
+       {STV_I2C_FLUSH, 0x04},
+       {STV_REG00, 0x0b},
+       {STV_REG01, 0xa7},
+       {STV_REG02, 0xb7},
+       {STV_REG03, 0x00},
+       {STV_REG04, 0x00},
+       {0x1536, 0x02},
+       {0x1537, 0x00},
+       {0x1538, 0x60},
+       {0x1539, 0x01},
+       {0x153a, 0x20},
+       {0x153b, 0x01},
 };
 
 static const u8 vv6410_sensor_init[][2] = {
        /* Setup registers */
-       {VV6410_SETUP0,         VV6410_SOFT_RESET},
-       {VV6410_SETUP0,         VV6410_LOW_POWER_MODE},
+       {VV6410_SETUP0, VV6410_SOFT_RESET},
+       {VV6410_SETUP0, VV6410_LOW_POWER_MODE},
        /* Use shuffled read-out mode */
-       {VV6410_SETUP1,         BIT(6)},
-       /* All modes to 1 */
-       {VV6410_FGMODES,        BIT(6) | BIT(4) | BIT(2) | BIT(0)},
-       {VV6410_PINMAPPING,     0x00},
+       {VV6410_SETUP1, BIT(6)},
+       /* All modes to 1, FST, Fast QCK, Free running QCK, Free running LST, FST will qualify visible pixels */
+       {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)},
+       {VV6410_PINMAPPING, 0x00},
        /* Pre-clock generator divide off */
-       {VV6410_DATAFORMAT,     BIT(7) | BIT(0)},
+       {VV6410_DATAFORMAT, BIT(7) | BIT(0)},
 
-       {VV6410_CLKDIV,         VV6410_CLK_DIV_2},
+       {VV6410_CLKDIV, VV6410_CLK_DIV_2},
 
        /* System registers */
        /* Enable voltage doubler */
-       {VV6410_AS0,            BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)},
-       {VV6410_AT0,            0x00},
+       {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)},
+       {VV6410_AT0, 0x00},
        /* Power up audio, differential */
-       {VV6410_AT1,            BIT(4)|BIT(0)},
+       {VV6410_AT1, BIT(4) | BIT(0)},
 };
 
 #endif
index 6ec2329..c890977 100644 (file)
@@ -19,6 +19,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "sunplus"
 
 #include "gspca.h"
@@ -325,7 +327,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
 
 #ifdef GSPCA_DEBUG
        if (len > USB_BUF_SZ) {
-               err("reg_r: buffer overflow");
+               pr_err("reg_r: buffer overflow\n");
                return;
        }
 #endif
@@ -340,7 +342,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
                        len ? gspca_dev->usb_buf : NULL, len,
                        500);
        if (ret < 0) {
-               err("reg_r err %d", ret);
+               pr_err("reg_r err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -365,7 +367,7 @@ static void reg_w_1(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               err("reg_w_1 err %d", ret);
+               pr_err("reg_w_1 err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -385,7 +387,7 @@ static void reg_w_riv(struct gspca_dev *gspca_dev,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        value, index, NULL, 0, 500);
        if (ret < 0) {
-               err("reg_w_riv err %d", ret);
+               pr_err("reg_w_riv err %d\n", ret);
                gspca_dev->usb_err = ret;
                return;
        }
index d1d733b..90f0877 100644 (file)
@@ -26,6 +26,8 @@
  *                     Costantino Leandro
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "t613"
 
 #include <linux/slab.h>
@@ -572,7 +574,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
 
                tmpbuf = kmemdup(buffer, len, GFP_KERNEL);
                if (!tmpbuf) {
-                       err("Out of memory");
+                       pr_err("Out of memory\n");
                        return;
                }
                usb_control_msg(gspca_dev->dev,
@@ -598,7 +600,7 @@ static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
        } else {
                p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
                if (!tmpbuf) {
-                       err("Out of memory");
+                       pr_err("Out of memory\n");
                        return;
                }
        }
@@ -652,7 +654,7 @@ static void om6802_sensor_init(struct gspca_dev *gspca_dev)
        }
        byte = reg_r(gspca_dev, 0x0063);
        if (byte != 0x17) {
-               err("Bad sensor reset %02x", byte);
+               pr_err("Bad sensor reset %02x\n", byte);
                /* continue? */
        }
 
@@ -890,7 +892,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                sd->sensor = SENSOR_OM6802;
                break;
        default:
-               err("unknown sensor %04x", sensor_id);
+               pr_err("unknown sensor %04x\n", sensor_id);
                return -EINVAL;
        }
 
@@ -905,7 +907,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                                break;          /* OK */
                }
                if (i < 0) {
-                       err("Bad sensor reset %02x", test_byte);
+                       pr_err("Bad sensor reset %02x\n", test_byte);
                        return -EIO;
                }
                reg_w_buf(gspca_dev, n2, sizeof n2);
diff --git a/drivers/media/video/gspca/topro.c b/drivers/media/video/gspca/topro.c
new file mode 100644 (file)
index 0000000..29596c5
--- /dev/null
@@ -0,0 +1,4989 @@
+/*
+ * Topro TP6800/6810 webcam driver.
+ *
+ * Copyright (C) 2011 Jean-François Moine (http://moinejf.free.fr)
+ * Copyright (C) 2009 Anders Blomdell (anders.blomdell@control.lth.se)
+ * Copyright (C) 2008 Thomas Champagne (lafeuil@gmail.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "gspca.h"
+
+MODULE_DESCRIPTION("Topro TP6800/6810 gspca webcam driver");
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
+               "Anders Blomdell <anders.blomdell@control.lth.se>");
+MODULE_LICENSE("GPL");
+
+static int force_sensor = -1;
+
+/* JPEG header */
+static const u8 jpeg_head[] = {
+       0xff, 0xd8,                     /* jpeg */
+
+/* quantization table quality 50% */
+       0xff, 0xdb, 0x00, 0x84,         /* DQT */
+0,
+#define JPEG_QT0_OFFSET 7
+       0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
+       0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
+       0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+       0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
+       0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
+       0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
+       0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
+       0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
+1,
+#define JPEG_QT1_OFFSET 72
+       0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
+       0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+
+       /* Define Huffman table (thanks to Thomas Kaiser) */
+       0xff, 0xc4, 0x01, 0x5e,
+       0x00, 0x00, 0x02, 0x03,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
+       0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
+       0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+       0x07, 0x05, 0x04, 0x06, 0x01, 0x00, 0x00, 0x57,
+       0x01, 0x02, 0x03, 0x00, 0x11, 0x04, 0x12, 0x21,
+       0x31, 0x13, 0x41, 0x51, 0x61, 0x05, 0x22, 0x32,
+       0x14, 0x71, 0x81, 0x91, 0x15, 0x23, 0x42, 0x52,
+       0x62, 0xa1, 0xb1, 0x06, 0x33, 0x72, 0xc1, 0xd1,
+       0x24, 0x43, 0x53, 0x82, 0x16, 0x34, 0x92, 0xa2,
+       0xe1, 0xf1, 0xf0, 0x07, 0x08, 0x17, 0x18, 0x25,
+       0x26, 0x27, 0x28, 0x35, 0x36, 0x37, 0x38, 0x44,
+       0x45, 0x46, 0x47, 0x48, 0x54, 0x55, 0x56, 0x57,
+       0x58, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x73,
+       0x74, 0x75, 0x76, 0x77, 0x78, 0x83, 0x84, 0x85,
+       0x86, 0x87, 0x88, 0x93, 0x94, 0x95, 0x96, 0x97,
+       0x98, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xb2,
+       0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xc2, 0xc3,
+       0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xd2, 0xd3, 0xd4,
+       0xd5, 0xd6, 0xd7, 0xd8, 0xe2, 0xe3, 0xe4, 0xe5,
+       0xe6, 0xe7, 0xe8, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
+       0xf7, 0xf8, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
+       0x05, 0x06, 0x07, 0x08, 0x09, 0x11, 0x00, 0x02,
+       0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05,
+       0x04, 0x06, 0x01, 0x00, 0x00, 0x57, 0x00, 0x01,
+       0x11, 0x02, 0x21, 0x03, 0x12, 0x31, 0x41, 0x13,
+       0x22, 0x51, 0x61, 0x04, 0x32, 0x71, 0x05, 0x14,
+       0x23, 0x42, 0x33, 0x52, 0x81, 0x91, 0xa1, 0xb1,
+       0xf0, 0x06, 0x15, 0xc1, 0xd1, 0xe1, 0x24, 0x43,
+       0x62, 0xf1, 0x16, 0x25, 0x34, 0x53, 0x72, 0x82,
+       0x92, 0x07, 0x08, 0x17, 0x18, 0x26, 0x27, 0x28,
+       0x35, 0x36, 0x37, 0x38, 0x44, 0x45, 0x46, 0x47,
+       0x48, 0x54, 0x55, 0x56, 0x57, 0x58, 0x63, 0x64,
+       0x65, 0x66, 0x67, 0x68, 0x73, 0x74, 0x75, 0x76,
+       0x77, 0x78, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
+       0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0xa2, 0xa3,
+       0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xb2, 0xb3, 0xb4,
+       0xb5, 0xb6, 0xb7, 0xb8, 0xc2, 0xc3, 0xc4, 0xc5,
+       0xc6, 0xc7, 0xc8, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+       0xd7, 0xd8, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+       0xe8, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+       0xff, 0xc0, 0x00, 0x11,         /* SOF0 (start of frame 0 */
+       0x08,                           /* data precision */
+#define JPEG_HEIGHT_OFFSET 493
+       0x01, 0xe0,                     /* height */
+       0x02, 0x80,                     /* width */
+       0x03,                           /* component number */
+               0x01,
+                       0x21,           /* samples Y = jpeg 422 */
+                       0x00,           /* quant Y */
+               0x02, 0x11, 0x01,       /* samples CbCr - quant CbCr */
+               0x03, 0x11, 0x01,
+
+       0xff, 0xda, 0x00, 0x0c,         /* SOS (start of scan) */
+       0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+#define JPEG_HDR_SZ 521
+};
+
+enum e_ctrl {
+       EXPOSURE,
+       QUALITY,
+       SHARPNESS,
+       RGAIN,
+       GAIN,
+       BGAIN,
+       GAMMA,
+       AUTOGAIN,
+       NCTRLS          /* number of controls */
+};
+
+#define AUTOGAIN_DEF 1
+
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       struct gspca_ctrl ctrls[NCTRLS];
+
+       u8 framerate;
+       u8 quality;             /* webcam current JPEG quality (0..16) */
+       s8 ag_cnt;              /* autogain / start counter for tp6810 */
+#define AG_CNT_START 13                /* check gain every N frames */
+
+       u8 bridge;
+       u8 sensor;
+
+       u8 jpeg_hdr[JPEG_HDR_SZ];
+};
+
+enum bridges {
+       BRIDGE_TP6800,
+       BRIDGE_TP6810,
+};
+
+enum sensors {
+       SENSOR_CX0342,
+       SENSOR_SOI763A,         /* ~= ov7630 / ov7648 */
+       NSENSORS
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+       {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 4 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG},
+       {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG}
+};
+
+/*
+ * JPEG quality
+ * index: webcam compression
+ * value: JPEG quality in %
+ */
+static const u8 jpeg_q[17] = {
+       88, 77, 67, 57, 55, 55, 45, 45, 36, 36, 30, 30, 26, 26, 22, 22, 94
+};
+
+#define BULK_OUT_SIZE          0x20
+#if BULK_OUT_SIZE > USB_BUF_SZ
+#error "USB buffer too small"
+#endif
+
+static const u8 rates[] = {30, 20, 15, 10, 7, 5};
+static const struct framerates framerates[] = {
+       {
+               .rates = rates,
+               .nrates = ARRAY_SIZE(rates)
+       },
+       {
+               .rates = rates,
+               .nrates = ARRAY_SIZE(rates)
+       }
+};
+static const u8 rates_6810[] = {30, 15, 10, 7, 5};
+static const struct framerates framerates_6810[] = {
+       {
+               .rates = rates_6810,
+               .nrates = ARRAY_SIZE(rates_6810)
+       },
+       {
+               .rates = rates_6810,
+               .nrates = ARRAY_SIZE(rates_6810)
+       }
+};
+
+/*
+ * webcam quality in %
+ * the last value is the ultra fine quality
+ */
+
+/* TP6800 register offsets */
+#define TP6800_R10_SIF_TYPE            0x10
+#define TP6800_R11_SIF_CONTROL         0x11
+#define TP6800_R12_SIF_ADDR_S          0x12
+#define TP6800_R13_SIF_TX_DATA         0x13
+#define TP6800_R14_SIF_RX_DATA         0x14
+#define TP6800_R15_GPIO_PU             0x15
+#define TP6800_R16_GPIO_PD             0x16
+#define TP6800_R17_GPIO_IO             0x17
+#define TP6800_R18_GPIO_DATA           0x18
+#define TP6800_R19_SIF_ADDR_S2         0x19
+#define TP6800_R1A_SIF_TX_DATA2                0x1a
+#define TP6800_R1B_SIF_RX_DATA2                0x1b
+#define TP6800_R21_ENDP_1_CTL          0x21
+#define TP6800_R2F_TIMING_CFG          0x2f
+#define TP6800_R30_SENSOR_CFG          0x30
+#define TP6800_R31_PIXEL_START         0x31
+#define TP6800_R32_PIXEL_END_L         0x32
+#define TP6800_R33_PIXEL_END_H         0x33
+#define TP6800_R34_LINE_START          0x34
+#define TP6800_R35_LINE_END_L          0x35
+#define TP6800_R36_LINE_END_H          0x36
+#define TP6800_R37_FRONT_DARK_ST       0x37
+#define TP6800_R38_FRONT_DARK_END      0x38
+#define TP6800_R39_REAR_DARK_ST_L      0x39
+#define TP6800_R3A_REAR_DARK_ST_H      0x3a
+#define TP6800_R3B_REAR_DARK_END_L     0x3b
+#define TP6800_R3C_REAR_DARK_END_H     0x3c
+#define TP6800_R3D_HORIZ_DARK_LINE_L   0x3d
+#define TP6800_R3E_HORIZ_DARK_LINE_H   0x3e
+#define TP6800_R3F_FRAME_RATE          0x3f
+#define TP6800_R50                     0x50
+#define TP6800_R51                     0x51
+#define TP6800_R52                     0x52
+#define TP6800_R53                     0x53
+#define TP6800_R54_DARK_CFG            0x54
+#define TP6800_R55_GAMMA_R             0x55
+#define TP6800_R56_GAMMA_G             0x56
+#define TP6800_R57_GAMMA_B             0x57
+#define TP6800_R5C_EDGE_THRLD          0x5c
+#define TP6800_R5D_DEMOSAIC_CFG                0x5d
+#define TP6800_R78_FORMAT              0x78
+#define TP6800_R79_QUALITY             0x79
+#define TP6800_R7A_BLK_THRLD           0x7a
+
+/* CX0342 register offsets */
+
+#define CX0342_SENSOR_ID               0x00
+#define CX0342_VERSION_NO              0x01
+#define CX0342_ORG_X_L                 0x02
+#define CX0342_ORG_X_H                 0x03
+#define CX0342_ORG_Y_L                 0x04
+#define CX0342_ORG_Y_H                 0x05
+#define CX0342_STOP_X_L                        0x06
+#define CX0342_STOP_X_H                        0x07
+#define CX0342_STOP_Y_L                        0x08
+#define CX0342_STOP_Y_H                        0x09
+#define CX0342_FRAME_WIDTH_L           0x0a
+#define CX0342_FRAME_WIDTH_H           0x0b
+#define CX0342_FRAME_HEIGH_L           0x0c
+#define CX0342_FRAME_HEIGH_H           0x0d
+#define CX0342_EXPO_LINE_L             0x10
+#define CX0342_EXPO_LINE_H             0x11
+#define CX0342_EXPO_CLK_L              0x12
+#define CX0342_EXPO_CLK_H              0x13
+#define CX0342_RAW_GRGAIN_L            0x14
+#define CX0342_RAW_GRGAIN_H            0x15
+#define CX0342_RAW_GBGAIN_L            0x16
+#define CX0342_RAW_GBGAIN_H            0x17
+#define CX0342_RAW_RGAIN_L             0x18
+#define CX0342_RAW_RGAIN_H             0x19
+#define CX0342_RAW_BGAIN_L             0x1a
+#define CX0342_RAW_BGAIN_H             0x1b
+#define CX0342_GLOBAL_GAIN             0x1c
+#define CX0342_SYS_CTRL_0              0x20
+#define CX0342_SYS_CTRL_1              0x21
+#define CX0342_SYS_CTRL_2              0x22
+#define CX0342_BYPASS_MODE             0x23
+#define CX0342_SYS_CTRL_3              0x24
+#define CX0342_TIMING_EN               0x25
+#define CX0342_OUTPUT_CTRL             0x26
+#define CX0342_AUTO_ADC_CALIB          0x27
+#define CX0342_SYS_CTRL_4              0x28
+#define CX0342_ADCGN                   0x30
+#define CX0342_SLPCR                   0x31
+#define CX0342_SLPFN_LO                        0x32
+#define CX0342_ADC_CTL                 0x33
+#define CX0342_LVRST_BLBIAS            0x34
+#define CX0342_VTHSEL                  0x35
+#define CX0342_RAMP_RIV                        0x36
+#define CX0342_LDOSEL                  0x37
+#define CX0342_CLOCK_GEN               0x40
+#define CX0342_SOFT_RESET              0x41
+#define CX0342_PLL                     0x42
+#define CX0342_DR_ENH_PULSE_OFFSET_L   0x43
+#define CX0342_DR_ENH_PULSE_OFFSET_H   0x44
+#define CX0342_DR_ENH_PULSE_POS_L      0x45
+#define CX0342_DR_ENH_PULSE_POS_H      0x46
+#define CX0342_DR_ENH_PULSE_WIDTH      0x47
+#define CX0342_AS_CURRENT_CNT_L                0x48
+#define CX0342_AS_CURRENT_CNT_H                0x49
+#define CX0342_AS_PREVIOUS_CNT_L       0x4a
+#define CX0342_AS_PREVIOUS_CNT_H       0x4b
+#define CX0342_SPV_VALUE_L             0x4c
+#define CX0342_SPV_VALUE_H             0x4d
+#define CX0342_GPXLTHD_L               0x50
+#define CX0342_GPXLTHD_H               0x51
+#define CX0342_RBPXLTHD_L              0x52
+#define CX0342_RBPXLTHD_H              0x53
+#define CX0342_PLANETHD_L              0x54
+#define CX0342_PLANETHD_H              0x55
+#define CX0342_ROWDARK_TH              0x56
+#define CX0342_ROWDARK_TOL             0x57
+#define CX0342_RB_GAP_L                        0x58
+#define CX0342_RB_GAP_H                        0x59
+#define CX0342_G_GAP_L                 0x5a
+#define CX0342_G_GAP_H                 0x5b
+#define CX0342_AUTO_ROW_DARK           0x60
+#define CX0342_MANUAL_DARK_VALUE       0x61
+#define CX0342_GB_DARK_OFFSET          0x62
+#define CX0342_GR_DARK_OFFSET          0x63
+#define CX0342_RED_DARK_OFFSET         0x64
+#define CX0342_BLUE_DARK_OFFSET                0x65
+#define CX0342_DATA_SCALING_MULTI      0x66
+#define CX0342_AUTOD_Q_FRAME           0x67
+#define CX0342_AUTOD_ALLOW_VARI                0x68
+#define CX0342_AUTO_DARK_VALUE_L       0x69
+#define CX0342_AUTO_DARK_VALUE_H       0x6a
+#define CX0342_IO_CTRL_0               0x70
+#define CX0342_IO_CTRL_1               0x71
+#define CX0342_IO_CTRL_2               0x72
+#define CX0342_IDLE_CTRL               0x73
+#define CX0342_TEST_MODE               0x74
+#define CX0342_FRAME_FIX_DATA_TEST     0x75
+#define CX0342_FRAME_CNT_TEST          0x76
+#define CX0342_RST_OVERFLOW_L          0x80
+#define CX0342_RST_OVERFLOW_H          0x81
+#define CX0342_RST_UNDERFLOW_L         0x82
+#define CX0342_RST_UNDERFLOW_H         0x83
+#define CX0342_DATA_OVERFLOW_L         0x84
+#define CX0342_DATA_OVERFLOW_H         0x85
+#define CX0342_DATA_UNDERFLOW_L                0x86
+#define CX0342_DATA_UNDERFLOW_H                0x87
+#define CX0342_CHANNEL_0_0_L_irst      0x90
+#define CX0342_CHANNEL_0_0_H_irst      0x91
+#define CX0342_CHANNEL_0_1_L_irst      0x92
+#define CX0342_CHANNEL_0_1_H_irst      0x93
+#define CX0342_CHANNEL_0_2_L_irst      0x94
+#define CX0342_CHANNEL_0_2_H_irst      0x95
+#define CX0342_CHANNEL_0_3_L_irst      0x96
+#define CX0342_CHANNEL_0_3_H_irst      0x97
+#define CX0342_CHANNEL_0_4_L_irst      0x98
+#define CX0342_CHANNEL_0_4_H_irst      0x99
+#define CX0342_CHANNEL_0_5_L_irst      0x9a
+#define CX0342_CHANNEL_0_5_H_irst      0x9b
+#define CX0342_CHANNEL_0_6_L_irst      0x9c
+#define CX0342_CHANNEL_0_6_H_irst      0x9d
+#define CX0342_CHANNEL_0_7_L_irst      0x9e
+#define CX0342_CHANNEL_0_7_H_irst      0x9f
+#define CX0342_CHANNEL_1_0_L_itx       0xa0
+#define CX0342_CHANNEL_1_0_H_itx       0xa1
+#define CX0342_CHANNEL_1_1_L_itx       0xa2
+#define CX0342_CHANNEL_1_1_H_itx       0xa3
+#define CX0342_CHANNEL_1_2_L_itx       0xa4
+#define CX0342_CHANNEL_1_2_H_itx       0xa5
+#define CX0342_CHANNEL_1_3_L_itx       0xa6
+#define CX0342_CHANNEL_1_3_H_itx       0xa7
+#define CX0342_CHANNEL_1_4_L_itx       0xa8
+#define CX0342_CHANNEL_1_4_H_itx       0xa9
+#define CX0342_CHANNEL_1_5_L_itx       0xaa
+#define CX0342_CHANNEL_1_5_H_itx       0xab
+#define CX0342_CHANNEL_1_6_L_itx       0xac
+#define CX0342_CHANNEL_1_6_H_itx       0xad
+#define CX0342_CHANNEL_1_7_L_itx       0xae
+#define CX0342_CHANNEL_1_7_H_itx       0xaf
+#define CX0342_CHANNEL_2_0_L_iwl       0xb0
+#define CX0342_CHANNEL_2_0_H_iwl       0xb1
+#define CX0342_CHANNEL_2_1_L_iwl       0xb2
+#define CX0342_CHANNEL_2_1_H_iwl       0xb3
+#define CX0342_CHANNEL_2_2_L_iwl       0xb4
+#define CX0342_CHANNEL_2_2_H_iwl       0xb5
+#define CX0342_CHANNEL_2_3_L_iwl       0xb6
+#define CX0342_CHANNEL_2_3_H_iwl       0xb7
+#define CX0342_CHANNEL_2_4_L_iwl       0xb8
+#define CX0342_CHANNEL_2_4_H_iwl       0xb9
+#define CX0342_CHANNEL_2_5_L_iwl       0xba
+#define CX0342_CHANNEL_2_5_H_iwl       0xbb
+#define CX0342_CHANNEL_2_6_L_iwl       0xbc
+#define CX0342_CHANNEL_2_6_H_iwl       0xbd
+#define CX0342_CHANNEL_2_7_L_iwl       0xbe
+#define CX0342_CHANNEL_2_7_H_iwl       0xbf
+#define CX0342_CHANNEL_3_0_L_ensp      0xc0
+#define CX0342_CHANNEL_3_0_H_ensp      0xc1
+#define CX0342_CHANNEL_3_1_L_ensp      0xc2
+#define CX0342_CHANNEL_3_1_H_ensp      0xc3
+#define CX0342_CHANNEL_3_2_L_ensp      0xc4
+#define CX0342_CHANNEL_3_2_H_ensp      0xc5
+#define CX0342_CHANNEL_3_3_L_ensp      0xc6
+#define CX0342_CHANNEL_3_3_H_ensp      0xc7
+#define CX0342_CHANNEL_3_4_L_ensp      0xc8
+#define CX0342_CHANNEL_3_4_H_ensp      0xc9
+#define CX0342_CHANNEL_3_5_L_ensp      0xca
+#define CX0342_CHANNEL_3_5_H_ensp      0xcb
+#define CX0342_CHANNEL_3_6_L_ensp      0xcc
+#define CX0342_CHANNEL_3_6_H_ensp      0xcd
+#define CX0342_CHANNEL_3_7_L_ensp      0xce
+#define CX0342_CHANNEL_3_7_H_ensp      0xcf
+#define CX0342_CHANNEL_4_0_L_sela      0xd0
+#define CX0342_CHANNEL_4_0_H_sela      0xd1
+#define CX0342_CHANNEL_4_1_L_sela      0xd2
+#define CX0342_CHANNEL_4_1_H_sela      0xd3
+#define CX0342_CHANNEL_5_0_L_intla     0xe0
+#define CX0342_CHANNEL_5_0_H_intla     0xe1
+#define CX0342_CHANNEL_5_1_L_intla     0xe2
+#define CX0342_CHANNEL_5_1_H_intla     0xe3
+#define CX0342_CHANNEL_5_2_L_intla     0xe4
+#define CX0342_CHANNEL_5_2_H_intla     0xe5
+#define CX0342_CHANNEL_5_3_L_intla     0xe6
+#define CX0342_CHANNEL_5_3_H_intla     0xe7
+#define CX0342_CHANNEL_6_0_L_xa_sel_pos 0xf0
+#define CX0342_CHANNEL_6_0_H_xa_sel_pos 0xf1
+#define CX0342_CHANNEL_7_1_L_cds_pos   0xf2
+#define CX0342_CHANNEL_7_1_H_cds_pos   0xf3
+#define CX0342_SENSOR_HEIGHT_L         0xfb
+#define CX0342_SENSOR_HEIGHT_H         0xfc
+#define CX0342_SENSOR_WIDTH_L          0xfd
+#define CX0342_SENSOR_WIDTH_H          0xfe
+#define CX0342_VSYNC_HSYNC_READ                0xff
+
+struct cmd {
+       u8 reg;
+       u8 val;
+};
+
+static const u8 DQT[17][130] = {
+       /* Define quantization table (thanks to Thomas Kaiser) */
+       {                       /* Quality 0 */
+        0x00,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x01,
+        0x04, 0x04, 0x04, 0x06, 0x05, 0x06, 0x0b, 0x06,
+        0x06, 0x0b, 0x18, 0x10, 0x0e, 0x10, 0x18, 0x18,
+        0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        },
+       {                       /* Quality 1 */
+        0x00,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09,
+        0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+        0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+        0x01,
+        0x08, 0x09, 0x09, 0x0c, 0x0a, 0x0c, 0x17, 0x0d,
+        0x0d, 0x17, 0x31, 0x21, 0x1c, 0x21, 0x31, 0x31,
+        0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
+        0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
+        0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
+        0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
+        0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
+        0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
+        },
+       {                       /* Quality 2 */
+        0x00,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x06, 0x06, 0x06, 0x04, 0x04, 0x04,
+        0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+        0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+        0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+        0x06, 0x06, 0x06, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+        0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+        0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+        0x01,
+        0x0c, 0x0d, 0x0d, 0x12, 0x0f, 0x12, 0x23, 0x13,
+        0x13, 0x23, 0x4a, 0x31, 0x2a, 0x31, 0x4a, 0x4a,
+        0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a,
+        0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a,
+        0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a,
+        0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a,
+        0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a,
+        0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a,
+        },
+       {                       /* Quality 3 */
+        0x00,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04,
+        0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+        0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+        0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+        0x08, 0x08, 0x08, 0x13, 0x13, 0x13, 0x13, 0x13,
+        0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+        0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+        0x01,
+        0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
+        0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+        },
+       {                       /* Quality 4 */
+        0x00,
+        0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+        0x05, 0x05, 0x0a, 0x0a, 0x0a, 0x05, 0x05, 0x05,
+        0x05, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+        0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+        0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+        0x0a, 0x0a, 0x0a, 0x17, 0x17, 0x17, 0x17, 0x17,
+        0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+        0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+        0x01,
+        0x11, 0x16, 0x16, 0x1e, 0x1a, 0x1e, 0x3a, 0x20,
+        0x20, 0x3a, 0x7b, 0x52, 0x46, 0x52, 0x7b, 0x7b,
+        0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
+        0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
+        0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
+        0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
+        0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
+        0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
+        },
+       {                       /* Quality 5 */
+        0x00,
+        0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+        0x06, 0x06, 0x0c, 0x0c, 0x0c, 0x06, 0x06, 0x06,
+        0x06, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+        0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+        0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+        0x0c, 0x0c, 0x0c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+        0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+        0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+        0x01,
+        0x11, 0x1b, 0x1b, 0x24, 0x1f, 0x24, 0x46, 0x27,
+        0x27, 0x46, 0x94, 0x63, 0x54, 0x63, 0x94, 0x94,
+        0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+        0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+        0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+        0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+        0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+        0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+        },
+       {                       /* Quality 6 */
+        0x00,
+        0x05, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+        0x07, 0x07, 0x0e, 0x0e, 0x0e, 0x07, 0x07, 0x07,
+        0x07, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+        0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+        0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+        0x0e, 0x0e, 0x0e, 0x21, 0x21, 0x21, 0x21, 0x21,
+        0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+        0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+        0x01,
+        0x15, 0x1f, 0x1f, 0x2a, 0x24, 0x2a, 0x52, 0x2d,
+        0x2d, 0x52, 0xad, 0x73, 0x62, 0x73, 0xad, 0xad,
+        0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+        0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+        0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+        0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+        0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+        0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+        },
+       {                       /* Quality 7 */
+        0x00,
+        0x05, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+        0x08, 0x08, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08,
+        0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+        0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+        0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+        0x10, 0x10, 0x10, 0x26, 0x26, 0x26, 0x26, 0x26,
+        0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,
+        0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,
+        0x01,
+        0x15, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34,
+        0x34, 0x5e, 0xc6, 0x84, 0x70, 0x84, 0xc6, 0xc6,
+        0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+        0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+        0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+        0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+        0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+        0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+        },
+       {                       /* Quality 8 */
+        0x00,
+        0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+        0x0a, 0x0a, 0x14, 0x14, 0x14, 0x0a, 0x0a, 0x0a,
+        0x0a, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+        0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+        0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+        0x14, 0x14, 0x14, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+        0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+        0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+        0x01,
+        0x19, 0x2d, 0x2d, 0x3c, 0x34, 0x3c, 0x75, 0x41,
+        0x41, 0x75, 0xf7, 0xa5, 0x8c, 0xa5, 0xf7, 0xf7,
+        0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
+        0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
+        0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
+        0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
+        0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
+        0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
+        },
+       {                       /* Quality 9 */
+        0x00,
+        0x06, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+        0x0c, 0x0c, 0x18, 0x18, 0x18, 0x0c, 0x0c, 0x0c,
+        0x0c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x18, 0x18, 0x18, 0x39, 0x39, 0x39, 0x39, 0x39,
+        0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39,
+        0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39,
+        0x01,
+        0x19, 0x36, 0x36, 0x48, 0x3f, 0x48, 0x8d, 0x4e,
+        0x4e, 0x8d, 0xff, 0xc6, 0xa8, 0xc6, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        },
+       {                       /* Quality 10 */
+        0x00,
+        0x07, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+        0x0e, 0x0e, 0x1c, 0x1c, 0x1c, 0x0e, 0x0e, 0x0e,
+        0x0e, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+        0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+        0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+        0x1c, 0x1c, 0x1c, 0x42, 0x42, 0x42, 0x42, 0x42,
+        0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+        0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+        0x01,
+        0x1d, 0x3f, 0x3f, 0x54, 0x49, 0x54, 0xa4, 0x5b,
+        0x5b, 0xa4, 0xff, 0xe7, 0xc4, 0xe7, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        },
+       {                       /* Quality 11 */
+        0x00,
+        0x07, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+        0x10, 0x10, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10,
+        0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
+        0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
+        0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
+        0x01,
+        0x1d, 0x48, 0x48, 0x60, 0x54, 0x60, 0xbc, 0x68,
+        0x68, 0xbc, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        },
+       {                       /* Quality 12 */
+        0x00,
+        0x08, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+        0x14, 0x14, 0x28, 0x28, 0x28, 0x14, 0x14, 0x14,
+        0x14, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+        0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+        0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+        0x28, 0x28, 0x28, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+        0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+        0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+        0x01,
+        0x22, 0x5a, 0x5a, 0x78, 0x69, 0x78, 0xeb, 0x82,
+        0x82, 0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        },
+       {                       /* Quality 13 */
+        0x00,
+        0x08, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x18, 0x18, 0x30, 0x30, 0x30, 0x18, 0x18, 0x18,
+        0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+        0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+        0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+        0x30, 0x30, 0x30, 0x72, 0x72, 0x72, 0x72, 0x72,
+        0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
+        0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
+        0x01,
+        0x22, 0x6c, 0x6c, 0x90, 0x7e, 0x90, 0xff, 0x9c,
+        0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        },
+       {                       /* Quality 14 */
+        0x00,
+        0x0a, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+        0x1c, 0x1c, 0x38, 0x38, 0x38, 0x1c, 0x1c, 0x1c,
+        0x1c, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
+        0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
+        0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
+        0x38, 0x38, 0x38, 0x85, 0x85, 0x85, 0x85, 0x85,
+        0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+        0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+        0x01,
+        0x2a, 0x7e, 0x7e, 0xa8, 0x93, 0xa8, 0xff, 0xb6,
+        0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        },
+       {                       /* Quality 15 */
+        0x00,
+        0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20,
+        0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+        0x40, 0x40, 0x40, 0x98, 0x98, 0x98, 0x98, 0x98,
+        0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+        0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+        0x01,
+        0x2a, 0x90, 0x90, 0xc0, 0xa8, 0xc0, 0xff, 0xd0,
+        0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        },
+       {                       /* Quality 16-31 */
+        0x00,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x01,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+        }
+};
+
+static const struct cmd tp6810_cx_init_common[] = {
+       {0x1c, 0x00},
+       {TP6800_R10_SIF_TYPE, 0x00},
+       {0x4e, 0x00},
+       {0x4f, 0x00},
+       {TP6800_R50, 0xff},
+       {TP6800_R51, 0x03},
+       {0x00, 0x07},
+       {TP6800_R79_QUALITY, 0x03},
+       {TP6800_R2F_TIMING_CFG, 0x37},
+       {TP6800_R30_SENSOR_CFG, 0x10},
+       {TP6800_R21_ENDP_1_CTL, 0x00},
+       {TP6800_R52, 0x40},
+       {TP6800_R53, 0x40},
+       {TP6800_R54_DARK_CFG, 0x40},
+       {TP6800_R30_SENSOR_CFG, 0x18},
+       {0x4b, 0x00},
+       {TP6800_R3F_FRAME_RATE, 0x83},
+       {TP6800_R79_QUALITY, 0x05},
+       {TP6800_R21_ENDP_1_CTL, 0x00},
+       {0x7c, 0x04},
+       {0x25, 0x14},
+       {0x26, 0x0f},
+       {0x7b, 0x10},
+};
+
+static const struct cmd tp6810_ov_init_common[] = {
+       {0x1c, 0x00},
+       {TP6800_R10_SIF_TYPE, 0x00},
+       {0x4e, 0x00},
+       {0x4f, 0x00},
+       {TP6800_R50, 0xff},
+       {TP6800_R51, 0x03},
+       {0x00, 0x07},
+       {TP6800_R52, 0x40},
+       {TP6800_R53, 0x40},
+       {TP6800_R54_DARK_CFG, 0x40},
+       {TP6800_R79_QUALITY, 0x03},
+       {TP6800_R2F_TIMING_CFG, 0x17},
+       {TP6800_R30_SENSOR_CFG, 0x18},
+       {TP6800_R21_ENDP_1_CTL, 0x00},
+       {TP6800_R3F_FRAME_RATE, 0x86},
+       {0x25, 0x18},
+       {0x26, 0x0f},
+       {0x7b, 0x90},
+};
+
+static const struct cmd tp6810_bridge_start[] = {
+       {0x59, 0x88},
+       {0x5a, 0x0f},
+       {0x5b, 0x4e},
+       {TP6800_R5C_EDGE_THRLD, 0x63},
+       {TP6800_R5D_DEMOSAIC_CFG, 0x00},
+       {0x03, 0x7f},
+       {0x04, 0x80},
+       {0x06, 0x00},
+       {0x00, 0x00},
+};
+
+static const struct cmd tp6810_late_start[] = {
+       {0x7d, 0x01},
+       {0xb0, 0x04},
+       {0xb1, 0x04},
+       {0xb2, 0x04},
+       {0xb3, 0x04},
+       {0xb4, 0x04},
+       {0xb5, 0x04},
+       {0xb6, 0x08},
+       {0xb7, 0x08},
+       {0xb8, 0x04},
+       {0xb9, 0x04},
+       {0xba, 0x04},
+       {0xbb, 0x04},
+       {0xbc, 0x04},
+       {0xbd, 0x08},
+       {0xbe, 0x08},
+       {0xbf, 0x08},
+       {0xc0, 0x04},
+       {0xc1, 0x04},
+       {0xc2, 0x08},
+       {0xc3, 0x08},
+       {0xc4, 0x08},
+       {0xc5, 0x08},
+       {0xc6, 0x08},
+       {0xc7, 0x13},
+       {0xc8, 0x04},
+       {0xc9, 0x08},
+       {0xca, 0x08},
+       {0xcb, 0x08},
+       {0xcc, 0x08},
+       {0xcd, 0x08},
+       {0xce, 0x13},
+       {0xcf, 0x13},
+       {0xd0, 0x08},
+       {0xd1, 0x08},
+       {0xd2, 0x08},
+       {0xd3, 0x08},
+       {0xd4, 0x08},
+       {0xd5, 0x13},
+       {0xd6, 0x13},
+       {0xd7, 0x13},
+       {0xd8, 0x08},
+       {0xd9, 0x08},
+       {0xda, 0x08},
+       {0xdb, 0x08},
+       {0xdc, 0x13},
+       {0xdd, 0x13},
+       {0xde, 0x13},
+       {0xdf, 0x13},
+       {0xe0, 0x08},
+       {0xe1, 0x08},
+       {0xe2, 0x08},
+       {0xe3, 0x13},
+       {0xe4, 0x13},
+       {0xe5, 0x13},
+       {0xe6, 0x13},
+       {0xe7, 0x13},
+       {0xe8, 0x08},
+       {0xe9, 0x08},
+       {0xea, 0x13},
+       {0xeb, 0x13},
+       {0xec, 0x13},
+       {0xed, 0x13},
+       {0xee, 0x13},
+       {0xef, 0x13},
+       {0x7d, 0x02},
+
+       /* later after isoc start */
+       {0x7d, 0x08},
+       {0x7d, 0x00},
+};
+
+static const struct cmd cx0342_timing_seq[] = {
+       {CX0342_CHANNEL_0_1_L_irst, 0x20},
+       {CX0342_CHANNEL_0_2_L_irst, 0x24},
+       {CX0342_CHANNEL_0_2_H_irst, 0x00},
+       {CX0342_CHANNEL_0_3_L_irst, 0x2f},
+       {CX0342_CHANNEL_0_3_H_irst, 0x00},
+       {CX0342_CHANNEL_1_0_L_itx, 0x02},
+       {CX0342_CHANNEL_1_0_H_itx, 0x00},
+       {CX0342_CHANNEL_1_1_L_itx, 0x20},
+       {CX0342_CHANNEL_1_1_H_itx, 0x00},
+       {CX0342_CHANNEL_1_2_L_itx, 0xe4},
+       {CX0342_CHANNEL_1_2_H_itx, 0x00},
+       {CX0342_CHANNEL_1_3_L_itx, 0xee},
+       {CX0342_CHANNEL_1_3_H_itx, 0x00},
+       {CX0342_CHANNEL_2_0_L_iwl, 0x30},
+       {CX0342_CHANNEL_2_0_H_iwl, 0x00},
+       {CX0342_CHANNEL_3_0_L_ensp, 0x34},
+       {CX0342_CHANNEL_3_1_L_ensp, 0xe2},
+       {CX0342_CHANNEL_3_1_H_ensp, 0x00},
+       {CX0342_CHANNEL_3_2_L_ensp, 0xf6},
+       {CX0342_CHANNEL_3_2_H_ensp, 0x00},
+       {CX0342_CHANNEL_3_3_L_ensp, 0xf4},
+       {CX0342_CHANNEL_3_3_H_ensp, 0x02},
+       {CX0342_CHANNEL_4_0_L_sela, 0x26},
+       {CX0342_CHANNEL_4_0_H_sela, 0x00},
+       {CX0342_CHANNEL_4_1_L_sela, 0xe2},
+       {CX0342_CHANNEL_4_1_H_sela, 0x00},
+       {CX0342_CHANNEL_5_0_L_intla, 0x26},
+       {CX0342_CHANNEL_5_1_L_intla, 0x29},
+       {CX0342_CHANNEL_5_2_L_intla, 0xf0},
+       {CX0342_CHANNEL_5_2_H_intla, 0x00},
+       {CX0342_CHANNEL_5_3_L_intla, 0xf3},
+       {CX0342_CHANNEL_5_3_H_intla, 0x00},
+       {CX0342_CHANNEL_6_0_L_xa_sel_pos, 0x24},
+       {CX0342_CHANNEL_7_1_L_cds_pos, 0x02},
+       {CX0342_TIMING_EN, 0x01},
+};
+
+/* define the JPEG header */
+static void jpeg_define(u8 *jpeg_hdr,
+                       int height,
+                       int width)
+{
+       memcpy(jpeg_hdr, jpeg_head, sizeof jpeg_head);
+       jpeg_hdr[JPEG_HEIGHT_OFFSET + 0] = height >> 8;
+       jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height;
+       jpeg_hdr[JPEG_HEIGHT_OFFSET + 2] = width >> 8;
+       jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width;
+}
+
+/* set the JPEG quality for sensor soi763a */
+static void jpeg_set_qual(u8 *jpeg_hdr,
+                         int quality)
+{
+       int i, sc;
+
+       if (quality < 50)
+               sc = 5000 / quality;
+       else
+               sc = 200 - quality * 2;
+       for (i = 0; i < 64; i++) {
+               jpeg_hdr[JPEG_QT0_OFFSET + i] =
+                       (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100;
+               jpeg_hdr[JPEG_QT1_OFFSET + i] =
+                       (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100;
+       }
+}
+
+static void reg_w(struct gspca_dev *gspca_dev, u8 index, u8 value)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                       0x0e,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, NULL, 0, 500);
+       if (ret < 0) {
+               pr_err("reg_w err %d\n", ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+
+/* the returned value is in gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev, u8 index)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                       0x0d,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0, index, gspca_dev->usb_buf, 1, 500);
+       if (ret < 0) {
+               pr_err("reg_r err %d\n", ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+
+static void reg_w_buf(struct gspca_dev *gspca_dev,
+                       const struct cmd *p, int l)
+{
+       do {
+               reg_w(gspca_dev, p->reg, p->val);
+               p++;
+       } while (--l > 0);
+}
+
+static int i2c_w(struct gspca_dev *gspca_dev, u8 index, u8 value)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_w(gspca_dev, TP6800_R11_SIF_CONTROL, 0x00);
+       reg_w(gspca_dev, TP6800_R19_SIF_ADDR_S2, index);
+       reg_w(gspca_dev, TP6800_R13_SIF_TX_DATA, value);
+       reg_w(gspca_dev, TP6800_R11_SIF_CONTROL, 0x01);
+       if (sd->bridge == BRIDGE_TP6800)
+               return 0;
+       msleep(5);
+       reg_r(gspca_dev, TP6800_R11_SIF_CONTROL);
+       if (gspca_dev->usb_buf[0] == 0)
+               return 0;
+       reg_w(gspca_dev, TP6800_R11_SIF_CONTROL, 0x00);
+       return -1;                              /* error */
+}
+
+static void i2c_w_buf(struct gspca_dev *gspca_dev,
+                       const struct cmd *p, int l)
+{
+       do {
+               i2c_w(gspca_dev, p->reg, p->val);
+               p++;
+       } while (--l > 0);
+}
+
+static int i2c_r(struct gspca_dev *gspca_dev, u8 index, int len)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int v;
+
+       reg_w(gspca_dev, TP6800_R19_SIF_ADDR_S2, index);
+       reg_w(gspca_dev, TP6800_R11_SIF_CONTROL, 0x02);
+       msleep(5);
+       reg_r(gspca_dev, TP6800_R14_SIF_RX_DATA);
+       v = gspca_dev->usb_buf[0];
+       if (sd->bridge == BRIDGE_TP6800)
+               return v;
+       if (len > 1) {
+               reg_r(gspca_dev, TP6800_R1B_SIF_RX_DATA2);
+               v |= (gspca_dev->usb_buf[0] << 8);
+       }
+       reg_r(gspca_dev, TP6800_R11_SIF_CONTROL);
+       if (gspca_dev->usb_buf[0] == 0)
+               return v;
+       reg_w(gspca_dev, TP6800_R11_SIF_CONTROL, 0x00);
+       return -1;
+}
+
+static void bulk_w(struct gspca_dev *gspca_dev,
+                 u8 tag,
+                 const u8 *data,
+                 int length)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int count, actual_count, ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       for (;;) {
+               count = length > BULK_OUT_SIZE - 1
+                               ? BULK_OUT_SIZE - 1 : length;
+               gspca_dev->usb_buf[0] = tag;
+               memcpy(&gspca_dev->usb_buf[1], data, count);
+               ret = usb_bulk_msg(dev,
+                                  usb_sndbulkpipe(dev, 3),
+                                  gspca_dev->usb_buf, count + 1,
+                                  &actual_count, 500);
+               if (ret < 0) {
+                       pr_err("bulk write error %d tag=%02x\n",
+                               ret, tag);
+                       gspca_dev->usb_err = ret;
+                       return;
+               }
+               length -= count;
+               if (length <= 0)
+                       break;
+               data += count;
+       }
+}
+
+static int probe_6810(struct gspca_dev *gspca_dev)
+{
+       u8 gpio;
+       int ret;
+
+       reg_r(gspca_dev, TP6800_R18_GPIO_DATA);
+       gpio = gspca_dev->usb_buf[0];
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio);
+       reg_w(gspca_dev, TP6800_R10_SIF_TYPE, 0x04);    /* i2c 16 bits */
+       reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x21);  /* ov??? */
+       reg_w(gspca_dev, TP6800_R1A_SIF_TX_DATA2, 0x00);
+       if (i2c_w(gspca_dev, 0x00, 0x00) >= 0)
+               return SENSOR_SOI763A;
+
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R10_SIF_TYPE, 0x00);    /* i2c 8 bits */
+       reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x7f);  /* (unknown i2c) */
+       if (i2c_w(gspca_dev, 0x00, 0x00) >= 0)
+               return -2;
+
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R10_SIF_TYPE, 0x00);    /* i2c 8 bits */
+       reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x11);  /* tas??? / hv??? */
+       ret = i2c_r(gspca_dev, 0x00, 1);
+       if (ret > 0)
+               return -3;
+
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x6e);  /* po??? */
+       ret = i2c_r(gspca_dev, 0x00, 1);
+       if (ret > 0)
+               return -4;
+
+       ret = i2c_r(gspca_dev, 0x01, 1);
+       if (ret > 0)
+               return -5;
+
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R10_SIF_TYPE, 0x04);    /* i2c 16 bits */
+       reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x5d);  /* mi/mt??? */
+       ret = i2c_r(gspca_dev, 0x00, 2);
+       if (ret > 0)
+               return -6;
+
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x5c);  /* mi/mt??? */
+       ret = i2c_r(gspca_dev, 0x36, 2);
+       if (ret > 0)
+               return -7;
+
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio);
+       reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x61);  /* (unknown i2c) */
+       reg_w(gspca_dev, TP6800_R1A_SIF_TX_DATA2, 0x10);
+       if (i2c_w(gspca_dev, 0xff, 0x00) >= 0)
+               return -8;
+
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio);
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20);
+       reg_w(gspca_dev, TP6800_R10_SIF_TYPE, 0x00);    /* i2c 8 bits */
+       reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x20);  /* cx0342 */
+       ret = i2c_r(gspca_dev, 0x00, 1);
+       if (ret > 0)
+               return SENSOR_CX0342;
+       return -9;
+}
+
+static void cx0342_6810_init(struct gspca_dev *gspca_dev)
+{
+       static const struct cmd reg_init_1[] = {
+               {TP6800_R2F_TIMING_CFG, 0x2f},
+               {0x25, 0x02},
+               {TP6800_R21_ENDP_1_CTL, 0x00},
+               {TP6800_R3F_FRAME_RATE, 0x80},
+               {TP6800_R2F_TIMING_CFG, 0x2f},
+               {TP6800_R18_GPIO_DATA, 0xe1},
+               {TP6800_R18_GPIO_DATA, 0xc1},
+               {TP6800_R18_GPIO_DATA, 0xe1},
+               {TP6800_R11_SIF_CONTROL, 0x00},
+       };
+       static const struct cmd reg_init_2[] = {
+               {TP6800_R78_FORMAT, 0x48},
+               {TP6800_R11_SIF_CONTROL, 0x00},
+       };
+       static const struct cmd sensor_init[] = {
+               {CX0342_OUTPUT_CTRL, 0x07},
+               {CX0342_BYPASS_MODE, 0x58},
+               {CX0342_GPXLTHD_L, 0x28},
+               {CX0342_RBPXLTHD_L, 0x28},
+               {CX0342_PLANETHD_L, 0x50},
+               {CX0342_PLANETHD_H, 0x03},
+               {CX0342_RB_GAP_L, 0xff},
+               {CX0342_RB_GAP_H, 0x07},
+               {CX0342_G_GAP_L, 0xff},
+               {CX0342_G_GAP_H, 0x07},
+               {CX0342_RST_OVERFLOW_L, 0x5c},
+               {CX0342_RST_OVERFLOW_H, 0x01},
+               {CX0342_DATA_OVERFLOW_L, 0xfc},
+               {CX0342_DATA_OVERFLOW_H, 0x03},
+               {CX0342_DATA_UNDERFLOW_L, 0x00},
+               {CX0342_DATA_UNDERFLOW_H, 0x00},
+               {CX0342_SYS_CTRL_0, 0x40},
+               {CX0342_GLOBAL_GAIN, 0x01},
+               {CX0342_CLOCK_GEN, 0x00},
+               {CX0342_SYS_CTRL_0, 0x02},
+               {CX0342_IDLE_CTRL, 0x05},
+               {CX0342_ADCGN, 0x00},
+               {CX0342_ADC_CTL, 0x00},
+               {CX0342_LVRST_BLBIAS, 0x01},
+               {CX0342_VTHSEL, 0x0b},
+               {CX0342_RAMP_RIV, 0x0b},
+               {CX0342_LDOSEL, 0x07},
+               {CX0342_SPV_VALUE_L, 0x40},
+               {CX0342_SPV_VALUE_H, 0x02},
+
+               {CX0342_AUTO_ADC_CALIB, 0x81},
+               {CX0342_TIMING_EN, 0x01},
+       };
+
+       reg_w_buf(gspca_dev, reg_init_1, ARRAY_SIZE(reg_init_1));
+       reg_w_buf(gspca_dev, tp6810_cx_init_common,
+                       ARRAY_SIZE(tp6810_cx_init_common));
+       reg_w_buf(gspca_dev, reg_init_2, ARRAY_SIZE(reg_init_2));
+
+       reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x20);  /* cx0342 I2C addr */
+       i2c_w_buf(gspca_dev, sensor_init, ARRAY_SIZE(sensor_init));
+       i2c_w_buf(gspca_dev, cx0342_timing_seq, ARRAY_SIZE(cx0342_timing_seq));
+}
+
+static void soi763a_6810_init(struct gspca_dev *gspca_dev)
+{
+       static const struct cmd reg_init_1[] = {
+               {TP6800_R2F_TIMING_CFG, 0x2f},
+               {TP6800_R18_GPIO_DATA, 0xe1},
+               {0x25, 0x02},
+               {TP6800_R21_ENDP_1_CTL, 0x00},
+               {TP6800_R3F_FRAME_RATE, 0x80},
+               {TP6800_R2F_TIMING_CFG, 0x2f},
+               {TP6800_R18_GPIO_DATA, 0xc1},
+       };
+       static const struct cmd reg_init_2[] = {
+               {TP6800_R78_FORMAT, 0x54},
+       };
+       static const struct cmd sensor_init[] = {
+               {0x00, 0x00},
+               {0x01, 0x80},
+               {0x02, 0x80},
+               {0x03, 0x90},
+               {0x04, 0x20},
+               {0x05, 0x20},
+               {0x06, 0x80},
+               {0x07, 0x00},
+               {0x08, 0xff},
+               {0x09, 0xff},
+               {0x0a, 0x76},           /* 7630 = soi673a */
+               {0x0b, 0x30},
+               {0x0c, 0x20},
+               {0x0d, 0x20},
+               {0x0e, 0xff},
+               {0x0f, 0xff},
+               {0x10, 0x41},
+               {0x15, 0x14},
+               {0x11, 0x40},
+               {0x12, 0x48},
+               {0x13, 0x80},
+               {0x14, 0x80},
+               {0x16, 0x03},
+               {0x28, 0xb0},
+               {0x71, 0x20},
+               {0x75, 0x8e},
+               {0x17, 0x1b},
+               {0x18, 0xbd},
+               {0x19, 0x05},
+               {0x1a, 0xf6},
+               {0x1b, 0x04},
+               {0x1c, 0x7f},           /* omnivision */
+               {0x1d, 0xa2},
+               {0x1e, 0x00},
+               {0x1f, 0x00},
+               {0x20, 0x45},
+               {0x21, 0x80},
+               {0x22, 0x80},
+               {0x23, 0xee},
+               {0x24, 0x50},
+               {0x25, 0x7a},
+               {0x26, 0xa0},
+               {0x27, 0x9a},
+               {0x29, 0x30},
+               {0x2a, 0x80},
+               {0x2b, 0x00},
+               {0x2c, 0xac},
+               {0x2d, 0x05},
+               {0x2e, 0x80},
+               {0x2f, 0x3c},
+               {0x30, 0x22},
+               {0x31, 0x00},
+               {0x32, 0x86},
+               {0x33, 0x08},
+               {0x34, 0xff},
+               {0x35, 0xff},
+               {0x36, 0xff},
+               {0x37, 0xff},
+               {0x38, 0xff},
+               {0x39, 0xff},
+               {0x3a, 0xfe},
+               {0x3b, 0xfe},
+               {0x3c, 0xfe},
+               {0x3d, 0xfe},
+               {0x3e, 0xfe},
+               {0x3f, 0x71},
+               {0x40, 0xff},
+               {0x41, 0xff},
+               {0x42, 0xff},
+               {0x43, 0xff},
+               {0x44, 0xff},
+               {0x45, 0xff},
+               {0x46, 0xff},
+               {0x47, 0xff},
+               {0x48, 0xff},
+               {0x49, 0xff},
+               {0x4a, 0xfe},
+               {0x4b, 0xff},
+               {0x4c, 0x00},
+               {0x4d, 0x00},
+               {0x4e, 0xff},
+               {0x4f, 0xff},
+               {0x50, 0xff},
+               {0x51, 0xff},
+               {0x52, 0xff},
+               {0x53, 0xff},
+               {0x54, 0xff},
+               {0x55, 0xff},
+               {0x56, 0xff},
+               {0x57, 0xff},
+               {0x58, 0xff},
+               {0x59, 0xff},
+               {0x5a, 0xff},
+               {0x5b, 0xfe},
+               {0x5c, 0xff},
+               {0x5d, 0x8f},
+               {0x5e, 0xff},
+               {0x5f, 0x8f},
+               {0x60, 0xa2},
+               {0x61, 0x4a},
+               {0x62, 0xf3},
+               {0x63, 0x75},
+               {0x64, 0xf0},
+               {0x65, 0x00},
+               {0x66, 0x55},
+               {0x67, 0x92},
+               {0x68, 0xa0},
+               {0x69, 0x4a},
+               {0x6a, 0x22},
+               {0x6b, 0x00},
+               {0x6c, 0x33},
+               {0x6d, 0x44},
+               {0x6e, 0x22},
+               {0x6f, 0x84},
+               {0x70, 0x0b},
+               {0x72, 0x10},
+               {0x73, 0x50},
+               {0x74, 0x21},
+               {0x76, 0x00},
+               {0x77, 0xa5},
+               {0x78, 0x80},
+               {0x79, 0x80},
+               {0x7a, 0x80},
+               {0x7b, 0xe2},
+               {0x7c, 0x00},
+               {0x7d, 0xf7},
+               {0x7e, 0x00},
+               {0x7f, 0x00},
+       };
+
+       reg_w_buf(gspca_dev, reg_init_1, ARRAY_SIZE(reg_init_1));
+       reg_w_buf(gspca_dev, tp6810_ov_init_common,
+                       ARRAY_SIZE(tp6810_ov_init_common));
+       reg_w_buf(gspca_dev, reg_init_2, ARRAY_SIZE(reg_init_2));
+
+       i2c_w(gspca_dev, 0x12, 0x80);           /* sensor reset */
+       msleep(10);
+       i2c_w_buf(gspca_dev, sensor_init, ARRAY_SIZE(sensor_init));
+}
+
+/* set the gain and exposure */
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->sensor == SENSOR_CX0342) {
+               int expo;
+
+               expo = (sd->ctrls[EXPOSURE].val << 2) - 1;
+               i2c_w(gspca_dev, CX0342_EXPO_LINE_L, expo);
+               i2c_w(gspca_dev, CX0342_EXPO_LINE_H, expo >> 8);
+               if (sd->bridge == BRIDGE_TP6800)
+                       i2c_w(gspca_dev, CX0342_RAW_GBGAIN_H,
+                                               sd->ctrls[GAIN].val >> 8);
+               i2c_w(gspca_dev, CX0342_RAW_GBGAIN_L, sd->ctrls[GAIN].val);
+               if (sd->bridge == BRIDGE_TP6800)
+                       i2c_w(gspca_dev, CX0342_RAW_GRGAIN_H,
+                                               sd->ctrls[GAIN].val >> 8);
+               i2c_w(gspca_dev, CX0342_RAW_GRGAIN_L, sd->ctrls[GAIN].val);
+               if (sd->bridge == BRIDGE_TP6800)
+                       i2c_w(gspca_dev, CX0342_RAW_BGAIN_H,
+                                               sd->ctrls[BGAIN].val >> 8);
+               i2c_w(gspca_dev, CX0342_RAW_BGAIN_L, sd->ctrls[BGAIN].val);
+               if (sd->bridge == BRIDGE_TP6800)
+                       i2c_w(gspca_dev, CX0342_RAW_RGAIN_H,
+                                               sd->ctrls[RGAIN].val >> 8);
+               i2c_w(gspca_dev, CX0342_RAW_RGAIN_L, sd->ctrls[RGAIN].val);
+               i2c_w(gspca_dev, CX0342_SYS_CTRL_0,
+                               sd->bridge == BRIDGE_TP6800 ? 0x80 : 0x81);
+               return;
+       }
+
+       /* soi763a */
+       i2c_w(gspca_dev, 0x10,          /* AEC_H (exposure time) */
+                        sd->ctrls[EXPOSURE].val);
+/*     i2c_w(gspca_dev, 0x76, 0x02);    * AEC_L ([1:0] */
+       i2c_w(gspca_dev, 0x00,          /* gain */
+                        sd->ctrls[GAIN].val);
+}
+
+/* set the JPEG quantization tables */
+static void set_dqt(struct gspca_dev *gspca_dev, u8 q)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* update the jpeg quantization tables */
+       PDEBUG(D_STREAM, "q %d -> %d", sd->quality, q);
+       sd->quality = q;
+       if (q > 16)
+               q = 16;
+       if (sd->sensor == SENSOR_SOI763A)
+               jpeg_set_qual(sd->jpeg_hdr, jpeg_q[q]);
+       else
+               memcpy(&sd->jpeg_hdr[JPEG_QT0_OFFSET - 1],
+                       DQT[q], sizeof DQT[0]);
+}
+
+/* set the JPEG compression quality factor */
+static void setquality(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u16 q;
+
+       q = sd->ctrls[QUALITY].val;
+       if (q != 16)
+               q = 15 - q;
+
+       reg_w(gspca_dev, TP6800_R7A_BLK_THRLD, 0x00);
+       reg_w(gspca_dev, TP6800_R79_QUALITY, 0x04);
+       reg_w(gspca_dev, TP6800_R79_QUALITY, q);
+
+       /* auto quality */
+       if (q == 15 && sd->bridge == BRIDGE_TP6810) {
+               msleep(4);
+               reg_w(gspca_dev, TP6800_R7A_BLK_THRLD, 0x19);
+       }
+}
+
+static const u8 color_null[18] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const u8 color_gain[NSENSORS][18] = {
+[SENSOR_CX0342] =
+       {0x4c, 0x00, 0xa9, 0x00, 0x31, 0x00,    /* Y R/G/B (LE values) */
+        0xb6, 0x03, 0x6c, 0x03, 0xe0, 0x00,    /* U R/G/B */
+        0xdf, 0x00, 0x46, 0x03, 0xdc, 0x03},   /* V R/G/B */
+[SENSOR_SOI763A] =
+       {0x4c, 0x00, 0x95, 0x00, 0x1d, 0x00,    /* Y R/G/B (LE values) */
+        0xb6, 0x03, 0x6c, 0x03, 0xd7, 0x00,    /* U R/G/B */
+        0xd5, 0x00, 0x46, 0x03, 0xdc, 0x03},   /* V R/G/B */
+};
+
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int gamma;
+#define NGAMMA 6
+       static const u8 gamma_tb[NGAMMA][3][1024] = {
+           {                           /* gamma 0 - from tp6800 + soi763a */
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02,
+                0x02, 0x03, 0x05, 0x07, 0x07, 0x08, 0x09, 0x09,
+                0x0a, 0x0c, 0x0c, 0x0d, 0x0e, 0x0e, 0x10, 0x11,
+                0x11, 0x12, 0x14, 0x14, 0x15, 0x16, 0x16, 0x17,
+                0x17, 0x18, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1e,
+                0x1e, 0x1f, 0x1f, 0x20, 0x20, 0x22, 0x23, 0x23,
+                0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28,
+                0x29, 0x29, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2f,
+                0x2f, 0x30, 0x30, 0x31, 0x31, 0x33, 0x33, 0x34,
+                0x34, 0x34, 0x35, 0x35, 0x37, 0x37, 0x38, 0x38,
+                0x39, 0x39, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c,
+                0x3c, 0x3d, 0x3d, 0x3f, 0x3f, 0x40, 0x40, 0x40,
+                0x42, 0x42, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45,
+                0x45, 0x47, 0x47, 0x47, 0x48, 0x48, 0x49, 0x49,
+                0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c,
+                0x4d, 0x4d, 0x4d, 0x4f, 0x4f, 0x50, 0x50, 0x50,
+                0x52, 0x52, 0x52, 0x53, 0x53, 0x54, 0x54, 0x54,
+                0x55, 0x55, 0x55, 0x56, 0x56, 0x58, 0x58, 0x58,
+                0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b,
+                0x5b, 0x5c, 0x5c, 0x5c, 0x5e, 0x5e, 0x5e, 0x5f,
+                0x5f, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61,
+                0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x65, 0x65,
+                0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68,
+                0x68, 0x68, 0x69, 0x69, 0x69, 0x69, 0x6a, 0x6a,
+                0x6a, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e,
+                0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70,
+                0x70, 0x71, 0x71, 0x71, 0x71, 0x73, 0x73, 0x73,
+                0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x77,
+                0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79,
+                0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b,
+                0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d,
+                0x7d, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80,
+                0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82,
+                0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x86,
+                0x86, 0x86, 0x86, 0x88, 0x88, 0x88, 0x88, 0x89,
+                0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b,
+                0x8b, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e,
+                0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x90,
+                0x90, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91,
+                0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93,
+                0x94, 0x94, 0x94, 0x94, 0x96, 0x96, 0x96, 0x96,
+                0x96, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98,
+                0x98, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a,
+                0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c,
+                0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e,
+                0x9e, 0x9e, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa0,
+                0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2,
+                0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4,
+                0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa6,
+                0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8,
+                0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab,
+                0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xac, 0xad,
+                0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xae, 0xae,
+                0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0,
+                0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2,
+                0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3,
+                0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6,
+                0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb8,
+                0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9,
+                0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbc, 0xbc,
+                0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+                0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf,
+                0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2,
+                0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3,
+                0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5,
+                0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+                0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc9, 0xc9, 0xc9,
+                0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xca, 0xca,
+                0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc,
+                0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xce,
+                0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf,
+                0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1,
+                0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3,
+                0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6,
+                0xd6, 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7,
+                0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9,
+                0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb,
+                0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd,
+                0xdd, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf,
+                0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0,
+                0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2,
+                0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3,
+                0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5,
+                0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7,
+                0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8,
+                0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb,
+                0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed,
+                0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee,
+                0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0,
+                0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3,
+                0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4,
+                0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6,
+                0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8,
+                0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb},
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02,
+                0x02, 0x03, 0x05, 0x07, 0x07, 0x08, 0x09, 0x09,
+                0x0a, 0x0c, 0x0c, 0x0d, 0x0e, 0x0e, 0x10, 0x11,
+                0x11, 0x12, 0x14, 0x14, 0x15, 0x16, 0x16, 0x17,
+                0x17, 0x18, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1e,
+                0x1e, 0x1f, 0x1f, 0x20, 0x20, 0x22, 0x23, 0x23,
+                0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28,
+                0x29, 0x29, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2f,
+                0x2f, 0x30, 0x30, 0x31, 0x31, 0x33, 0x33, 0x34,
+                0x34, 0x34, 0x35, 0x35, 0x37, 0x37, 0x38, 0x38,
+                0x39, 0x39, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c,
+                0x3c, 0x3d, 0x3d, 0x3f, 0x3f, 0x40, 0x40, 0x40,
+                0x42, 0x42, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45,
+                0x45, 0x47, 0x47, 0x47, 0x48, 0x48, 0x49, 0x49,
+                0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c,
+                0x4d, 0x4d, 0x4d, 0x4f, 0x4f, 0x50, 0x50, 0x50,
+                0x52, 0x52, 0x52, 0x53, 0x53, 0x54, 0x54, 0x54,
+                0x55, 0x55, 0x55, 0x56, 0x56, 0x58, 0x58, 0x58,
+                0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b,
+                0x5b, 0x5c, 0x5c, 0x5c, 0x5e, 0x5e, 0x5e, 0x5f,
+                0x5f, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61,
+                0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x65, 0x65,
+                0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68,
+                0x68, 0x68, 0x69, 0x69, 0x69, 0x69, 0x6a, 0x6a,
+                0x6a, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e,
+                0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70,
+                0x70, 0x71, 0x71, 0x71, 0x71, 0x73, 0x73, 0x73,
+                0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x77,
+                0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79,
+                0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b,
+                0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d,
+                0x7d, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80,
+                0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82,
+                0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x86,
+                0x86, 0x86, 0x86, 0x88, 0x88, 0x88, 0x88, 0x89,
+                0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b,
+                0x8b, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e,
+                0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x90,
+                0x90, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91,
+                0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93,
+                0x94, 0x94, 0x94, 0x94, 0x96, 0x96, 0x96, 0x96,
+                0x96, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98,
+                0x98, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a,
+                0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c,
+                0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e,
+                0x9e, 0x9e, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa0,
+                0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2,
+                0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4,
+                0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa6,
+                0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8,
+                0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab,
+                0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xac, 0xad,
+                0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xae, 0xae,
+                0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0,
+                0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2,
+                0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3,
+                0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6,
+                0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb8,
+                0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9,
+                0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbc, 0xbc,
+                0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+                0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf,
+                0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2,
+                0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3,
+                0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5,
+                0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+                0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc9, 0xc9, 0xc9,
+                0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xca, 0xca,
+                0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc,
+                0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xce,
+                0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf,
+                0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1,
+                0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3,
+                0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6,
+                0xd6, 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7,
+                0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9,
+                0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb,
+                0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd,
+                0xdd, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf,
+                0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0,
+                0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2,
+                0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3,
+                0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5,
+                0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7,
+                0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8,
+                0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb,
+                0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed,
+                0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee,
+                0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0,
+                0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3,
+                0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4,
+                0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6,
+                0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8,
+                0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb},
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02,
+                0x02, 0x03, 0x05, 0x07, 0x07, 0x08, 0x09, 0x09,
+                0x0a, 0x0c, 0x0c, 0x0d, 0x0e, 0x0e, 0x10, 0x11,
+                0x11, 0x12, 0x14, 0x14, 0x15, 0x16, 0x16, 0x17,
+                0x17, 0x18, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1e,
+                0x1e, 0x1f, 0x1f, 0x20, 0x20, 0x22, 0x23, 0x23,
+                0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28,
+                0x29, 0x29, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2f,
+                0x2f, 0x30, 0x30, 0x31, 0x31, 0x33, 0x33, 0x34,
+                0x34, 0x34, 0x35, 0x35, 0x37, 0x37, 0x38, 0x38,
+                0x39, 0x39, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c,
+                0x3c, 0x3d, 0x3d, 0x3f, 0x3f, 0x40, 0x40, 0x40,
+                0x42, 0x42, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45,
+                0x45, 0x47, 0x47, 0x47, 0x48, 0x48, 0x49, 0x49,
+                0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c,
+                0x4d, 0x4d, 0x4d, 0x4f, 0x4f, 0x50, 0x50, 0x50,
+                0x52, 0x52, 0x52, 0x53, 0x53, 0x54, 0x54, 0x54,
+                0x55, 0x55, 0x55, 0x56, 0x56, 0x58, 0x58, 0x58,
+                0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b,
+                0x5b, 0x5c, 0x5c, 0x5c, 0x5e, 0x5e, 0x5e, 0x5f,
+                0x5f, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61,
+                0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x65, 0x65,
+                0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68,
+                0x68, 0x68, 0x69, 0x69, 0x69, 0x69, 0x6a, 0x6a,
+                0x6a, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e,
+                0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70,
+                0x70, 0x71, 0x71, 0x71, 0x71, 0x73, 0x73, 0x73,
+                0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76,
+                0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79,
+                0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b,
+                0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d,
+                0x7d, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80,
+                0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82,
+                0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x86,
+                0x86, 0x86, 0x86, 0x88, 0x88, 0x88, 0x88, 0x89,
+                0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b,
+                0x8b, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e,
+                0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x90,
+                0x90, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91,
+                0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93,
+                0x94, 0x94, 0x94, 0x94, 0x96, 0x96, 0x96, 0x96,
+                0x96, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98,
+                0x98, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a,
+                0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c,
+                0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e,
+                0x9e, 0x9e, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa0,
+                0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2,
+                0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4,
+                0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa6,
+                0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8,
+                0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab,
+                0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xac, 0xad,
+                0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xae, 0xae,
+                0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0,
+                0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2,
+                0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3,
+                0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6,
+                0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb8,
+                0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9,
+                0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbc, 0xbc,
+                0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+                0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf,
+                0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2,
+                0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3,
+                0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5,
+                0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+                0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc9, 0xc9, 0xc9,
+                0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xca, 0xca,
+                0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc,
+                0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xce,
+                0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf,
+                0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1,
+                0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3,
+                0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6,
+                0xd6, 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7,
+                0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9,
+                0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb,
+                0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd,
+                0xdd, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf,
+                0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0,
+                0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2,
+                0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3,
+                0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5,
+                0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7,
+                0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8,
+                0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb,
+                0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed,
+                0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee,
+                0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0,
+                0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3,
+                0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4,
+                0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6,
+                0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8,
+                0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb}
+           },
+           {                           /* gamma 1 - from tp6810 + soi763a */
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x01, 0x02, 0x03, 0x05, 0x07, 0x08, 0x09, 0x0a,
+                0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15,
+                0x16, 0x17, 0x18, 0x1a, 0x1a, 0x1b, 0x1c, 0x1e,
+                0x1f, 0x20, 0x22, 0x22, 0x23, 0x25, 0x26, 0x27,
+                0x27, 0x28, 0x29, 0x2b, 0x2b, 0x2c, 0x2d, 0x2f,
+                0x2f, 0x30, 0x31, 0x33, 0x33, 0x34, 0x35, 0x35,
+                0x37, 0x38, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c,
+                0x3c, 0x3d, 0x3f, 0x3f, 0x40, 0x42, 0x42, 0x43,
+                0x43, 0x44, 0x45, 0x45, 0x47, 0x47, 0x48, 0x49,
+                0x49, 0x4a, 0x4a, 0x4b, 0x4b, 0x4c, 0x4d, 0x4d,
+                0x4f, 0x4f, 0x50, 0x50, 0x52, 0x52, 0x53, 0x53,
+                0x54, 0x54, 0x55, 0x56, 0x56, 0x58, 0x58, 0x59,
+                0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5e,
+                0x5e, 0x5e, 0x5f, 0x5f, 0x60, 0x60, 0x61, 0x61,
+                0x62, 0x62, 0x63, 0x63, 0x65, 0x65, 0x65, 0x66,
+                0x66, 0x67, 0x67, 0x68, 0x68, 0x69, 0x69, 0x69,
+                0x6a, 0x6a, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e,
+                0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71,
+                0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x75, 0x75,
+                0x77, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x79,
+                0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c,
+                0x7d, 0x7d, 0x7d, 0x7f, 0x7f, 0x80, 0x80, 0x80,
+                0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x84, 0x84,
+                0x84, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x88,
+                0x88, 0x88, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a,
+                0x8b, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e,
+                0x8e, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x91,
+                0x91, 0x91, 0x92, 0x92, 0x92, 0x92, 0x93, 0x93,
+                0x93, 0x94, 0x94, 0x94, 0x96, 0x96, 0x96, 0x97,
+                0x97, 0x97, 0x97, 0x98, 0x98, 0x98, 0x99, 0x99,
+                0x99, 0x9a, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b,
+                0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9e,
+                0x9e, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1,
+                0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa2, 0xa3, 0xa3,
+                0xa3, 0xa4, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5,
+                0xa5, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8,
+                0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab, 0xab,
+                0xac, 0xac, 0xac, 0xad, 0xad, 0xad, 0xad, 0xae,
+                0xae, 0xae, 0xae, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0,
+                0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2,
+                0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, 0xb4,
+                0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, 0xb6, 0xb7,
+                0xb7, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb8,
+                0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba,
+                0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd,
+                0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf,
+                0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0xc2,
+                0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4,
+                0xc4, 0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6,
+                0xc6, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7,
+                0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca,
+                0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc,
+                0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xcd, 0xce,
+                0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf,
+                0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1,
+                0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd4,
+                0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6,
+                0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8,
+                0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xda,
+                0xda, 0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdb,
+                0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde,
+                0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0,
+                0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1,
+                0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3,
+                0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4,
+                0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6,
+                0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8,
+                0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9,
+                0xe9, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec,
+                0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed,
+                0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef,
+                0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+                0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, 0xf3, 0xf3,
+                0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5,
+                0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6,
+                0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8,
+                0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9,
+                0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
+                0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe,
+                0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
+                0x05, 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0c, 0x0d,
+                0x0e, 0x10, 0x10, 0x11, 0x12, 0x14, 0x15, 0x15,
+                0x16, 0x17, 0x18, 0x1a, 0x1a, 0x1b, 0x1c, 0x1e,
+                0x1e, 0x1f, 0x20, 0x20, 0x22, 0x23, 0x25, 0x25,
+                0x26, 0x27, 0x27, 0x28, 0x29, 0x29, 0x2b, 0x2c,
+                0x2c, 0x2d, 0x2d, 0x2f, 0x30, 0x30, 0x31, 0x31,
+                0x33, 0x34, 0x34, 0x35, 0x35, 0x37, 0x38, 0x38,
+                0x39, 0x39, 0x3a, 0x3a, 0x3b, 0x3b, 0x3c, 0x3d,
+                0x3d, 0x3f, 0x3f, 0x40, 0x40, 0x42, 0x42, 0x43,
+                0x43, 0x44, 0x44, 0x45, 0x45, 0x47, 0x47, 0x48,
+                0x48, 0x49, 0x49, 0x4a, 0x4a, 0x4b, 0x4b, 0x4c,
+                0x4c, 0x4d, 0x4d, 0x4d, 0x4f, 0x4f, 0x50, 0x50,
+                0x52, 0x52, 0x53, 0x53, 0x53, 0x54, 0x54, 0x55,
+                0x55, 0x56, 0x56, 0x56, 0x58, 0x58, 0x59, 0x59,
+                0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c,
+                0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60,
+                0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63, 0x65,
+                0x65, 0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67,
+                0x68, 0x68, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a,
+                0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e,
+                0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71,
+                0x71, 0x71, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74,
+                0x75, 0x75, 0x75, 0x77, 0x77, 0x77, 0x78, 0x78,
+                0x78, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a,
+                0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d,
+                0x7d, 0x7d, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80,
+                0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82,
+                0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x86,
+                0x86, 0x86, 0x88, 0x88, 0x88, 0x88, 0x89, 0x89,
+                0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b,
+                0x8b, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e,
+                0x8e, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90,
+                0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92,
+                0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94,
+                0x96, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97,
+                0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x99,
+                0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b,
+                0x9b, 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d,
+                0x9d, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0xa0, 0xa0,
+                0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2,
+                0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4,
+                0xa4, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5,
+                0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8,
+                0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab,
+                0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xac, 0xad,
+                0xad, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xae,
+                0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0,
+                0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2,
+                0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3,
+                0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6,
+                0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb8,
+                0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9,
+                0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbc, 0xbc,
+                0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+                0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf,
+                0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+                0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3,
+                0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5,
+                0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6,
+                0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc9,
+                0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca,
+                0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc,
+                0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd,
+                0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcf,
+                0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0,
+                0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
+                0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4,
+                0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6,
+                0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8,
+                0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9,
+                0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb, 0xdb,
+                0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd,
+                0xdd, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf,
+                0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0,
+                0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2,
+                0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3,
+                0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4,
+                0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6,
+                0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
+                0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9,
+                0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb,
+                0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed,
+                0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee,
+                0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0,
+                0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1,
+                0xf1, 0xf1, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4,
+                0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5,
+                0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7,
+                0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8,
+                0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc,
+                0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
+                0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe,
+                0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x01, 0x02, 0x03, 0x05, 0x05, 0x07,
+                0x08, 0x09, 0x0a, 0x0a, 0x0c, 0x0d, 0x0e, 0x0e,
+                0x10, 0x11, 0x12, 0x12, 0x14, 0x15, 0x16, 0x16,
+                0x17, 0x18, 0x18, 0x1a, 0x1b, 0x1b, 0x1c, 0x1e,
+                0x1e, 0x1f, 0x1f, 0x20, 0x22, 0x22, 0x23, 0x23,
+                0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x29, 0x29,
+                0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2f, 0x30,
+                0x30, 0x31, 0x31, 0x33, 0x33, 0x34, 0x34, 0x35,
+                0x35, 0x37, 0x37, 0x38, 0x38, 0x39, 0x39, 0x3a,
+                0x3a, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d,
+                0x3f, 0x3f, 0x40, 0x40, 0x42, 0x42, 0x42, 0x43,
+                0x43, 0x44, 0x44, 0x45, 0x45, 0x47, 0x47, 0x47,
+                0x48, 0x48, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4b,
+                0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4f,
+                0x4f, 0x50, 0x50, 0x50, 0x52, 0x52, 0x52, 0x53,
+                0x53, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x56,
+                0x56, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x5a,
+                0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c,
+                0x5e, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x60, 0x60,
+                0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63,
+                0x63, 0x63, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66,
+                0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x69,
+                0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a, 0x6c, 0x6c,
+                0x6c, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e,
+                0x6f, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71,
+                0x71, 0x71, 0x71, 0x73, 0x73, 0x73, 0x74, 0x74,
+                0x74, 0x74, 0x75, 0x75, 0x75, 0x75, 0x77, 0x77,
+                0x77, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79,
+                0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b,
+                0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d,
+                0x7d, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80,
+                0x80, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82,
+                0x82, 0x84, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85,
+                0x85, 0x86, 0x86, 0x86, 0x86, 0x88, 0x88, 0x88,
+                0x88, 0x88, 0x89, 0x89, 0x89, 0x89, 0x8a, 0x8a,
+                0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8d,
+                0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+                0x8f, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90,
+                0x90, 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92,
+                0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x94, 0x94,
+                0x94, 0x94, 0x94, 0x96, 0x96, 0x96, 0x96, 0x96,
+                0x97, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98,
+                0x98, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a,
+                0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+                0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d,
+                0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0xa0,
+                0xa0, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1,
+                0xa1, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa3, 0xa3,
+                0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+                0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6,
+                0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+                0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab,
+                0xab, 0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xac,
+                0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xae, 0xae,
+                0xae, 0xae, 0xae, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+                0xaf, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1,
+                0xb1, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2, 0xb2,
+                0xb2, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb4,
+                0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, 0xb6,
+                0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
+                0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9,
+                0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba,
+                0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd,
+                0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe,
+                0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+                0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0xc2,
+                0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3,
+                0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5,
+                0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6,
+                0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7,
+                0xc7, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca,
+                0xca, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb,
+                0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+                0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce,
+                0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf,
+                0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
+                0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3,
+                0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4,
+                0xd4, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd7,
+                0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8,
+                0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9,
+                0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb,
+                0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd,
+                0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde,
+                0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0,
+                0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1,
+                0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3,
+                0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4,
+                0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
+                0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7,
+                0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8,
+                0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb,
+                0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec,
+                0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xee,
+                0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, 0xef,
+                0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1,
+                0xf1, 0xf1, 0xf1, 0xf1, 0xf3, 0xf3, 0xf3, 0xf3,
+                0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5,
+                0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6,
+                0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8,
+                0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc,
+                0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd,
+                0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+           },
+           {                                                   /* gamma 2 */
+               {0x00, 0x01, 0x02, 0x05, 0x07, 0x08, 0x0a, 0x0c,
+                0x0d, 0x0e, 0x10, 0x12, 0x14, 0x15, 0x16, 0x17,
+                0x18, 0x1a, 0x1b, 0x1c, 0x1e, 0x1f, 0x20, 0x22,
+                0x23, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2b, 0x2c,
+                0x2d, 0x2d, 0x2f, 0x30, 0x31, 0x33, 0x34, 0x34,
+                0x35, 0x37, 0x38, 0x38, 0x39, 0x3a, 0x3b, 0x3b,
+                0x3c, 0x3d, 0x3f, 0x3f, 0x40, 0x42, 0x42, 0x43,
+                0x44, 0x44, 0x45, 0x47, 0x47, 0x48, 0x49, 0x49,
+                0x4a, 0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4f, 0x4f,
+                0x50, 0x50, 0x52, 0x53, 0x53, 0x54, 0x54, 0x55,
+                0x55, 0x56, 0x56, 0x58, 0x58, 0x59, 0x5a, 0x5a,
+                0x5b, 0x5b, 0x5c, 0x5c, 0x5e, 0x5e, 0x5f, 0x5f,
+                0x60, 0x60, 0x61, 0x61, 0x62, 0x62, 0x63, 0x63,
+                0x65, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68,
+                0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6c, 0x6c,
+                0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x70,
+                0x70, 0x70, 0x71, 0x71, 0x73, 0x73, 0x73, 0x74,
+                0x74, 0x75, 0x75, 0x75, 0x77, 0x77, 0x78, 0x78,
+                0x78, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7b, 0x7b,
+                0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7f, 0x7f,
+                0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82,
+                0x82, 0x82, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85,
+                0x86, 0x86, 0x86, 0x88, 0x88, 0x88, 0x89, 0x89,
+                0x89, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8d,
+                0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f,
+                0x8f, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91,
+                0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x94,
+                0x94, 0x94, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97,
+                0x97, 0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99,
+                0x9a, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b,
+                0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e,
+                0x9e, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa0, 0xa1,
+                0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa2, 0xa3,
+                0xa3, 0xa3, 0xa4, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5,
+                0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa6, 0xa6, 0xa8,
+                0xa8, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xab,
+                0xab, 0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xad,
+                0xad, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xae,
+                0xaf, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb0,
+                0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2,
+                0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, 0xb4, 0xb4,
+                0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, 0xb6, 0xb7,
+                0xb7, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb8,
+                0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba,
+                0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd,
+                0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe,
+                0xbe, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xc0, 0xc0,
+                0xc0, 0xc0, 0xc0, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3,
+                0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4,
+                0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6,
+                0xc6, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7,
+                0xc7, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca,
+                0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb,
+                0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd,
+                0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce, 0xce,
+                0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0,
+                0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd1,
+                0xd1, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4,
+                0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6,
+                0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8,
+                0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9,
+                0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda,
+                0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd,
+                0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xde,
+                0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0,
+                0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1,
+                0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2,
+                0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4,
+                0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5,
+                0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
+                0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8,
+                0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9,
+                0xe9, 0xe9, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb,
+                0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed,
+                0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee,
+                0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0,
+                0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1,
+                0xf1, 0xf1, 0xf1, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3,
+                0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5,
+                0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6,
+                0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
+                0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9,
+                0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb},
+               {0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x05,
+                0x07, 0x08, 0x09, 0x0a, 0x0d, 0x0e, 0x10, 0x11,
+                0x12, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x1a,
+                0x1b, 0x1c, 0x1e, 0x1f, 0x20, 0x20, 0x22, 0x23,
+                0x25, 0x26, 0x26, 0x27, 0x28, 0x29, 0x29, 0x2b,
+                0x2c, 0x2d, 0x2d, 0x2f, 0x30, 0x30, 0x31, 0x33,
+                0x33, 0x34, 0x35, 0x35, 0x37, 0x38, 0x38, 0x39,
+                0x3a, 0x3a, 0x3b, 0x3b, 0x3c, 0x3d, 0x3d, 0x3f,
+                0x3f, 0x40, 0x42, 0x42, 0x43, 0x43, 0x44, 0x44,
+                0x45, 0x45, 0x47, 0x47, 0x48, 0x48, 0x49, 0x4a,
+                0x4a, 0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d,
+                0x4f, 0x4f, 0x50, 0x50, 0x52, 0x52, 0x53, 0x53,
+                0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x56, 0x58,
+                0x58, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b,
+                0x5c, 0x5c, 0x5c, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f,
+                0x60, 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x63,
+                0x63, 0x63, 0x65, 0x65, 0x65, 0x66, 0x66, 0x67,
+                0x67, 0x67, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69,
+                0x6a, 0x6a, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d,
+                0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70,
+                0x70, 0x71, 0x71, 0x71, 0x73, 0x73, 0x73, 0x73,
+                0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x77, 0x77,
+                0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79,
+                0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c,
+                0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7f, 0x7f,
+                0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81,
+                0x82, 0x82, 0x82, 0x82, 0x84, 0x84, 0x84, 0x84,
+                0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x88,
+                0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x89, 0x8a,
+                0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b, 0x8d,
+                0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8e, 0x8f,
+                0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90, 0x91,
+                0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92,
+                0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94,
+                0x94, 0x96, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97,
+                0x97, 0x98, 0x98, 0x98, 0x98, 0x98, 0x99, 0x99,
+                0x99, 0x99, 0x99, 0x9a, 0x9a, 0x9a, 0x9a, 0x9b,
+                0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9c,
+                0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e,
+                0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa1,
+                0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa2,
+                0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4,
+                0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+                0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8,
+                0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xab,
+                0xab, 0xab, 0xab, 0xab, 0xac, 0xac, 0xac, 0xac,
+                0xac, 0xac, 0xad, 0xad, 0xad, 0xad, 0xad, 0xae,
+                0xae, 0xae, 0xae, 0xae, 0xaf, 0xaf, 0xaf, 0xaf,
+                0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb1,
+                0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2,
+                0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
+                0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6,
+                0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
+                0xb7, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb9,
+                0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba,
+                0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
+                0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe,
+                0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf,
+                0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+                0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3,
+                0xc3, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4,
+                0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
+                0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7,
+                0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc9, 0xc9, 0xc9,
+                0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xca, 0xca,
+                0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc,
+                0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd,
+                0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce,
+                0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
+                0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1,
+                0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3,
+                0xd3, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4,
+                0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6,
+                0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8,
+                0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9,
+                0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda,
+                0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb,
+                0xdb, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+                0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf,
+                0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0,
+                0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1,
+                0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2,
+                0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4,
+                0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5,
+                0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6,
+                0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
+                0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9,
+                0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb,
+                0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec,
+                0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed,
+                0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xef,
+                0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0,
+                0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
+                0xf1, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4,
+                0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5,
+                0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6,
+                0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
+                0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9,
+                0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb},
+               {0x00, 0x00, 0x00, 0x01, 0x02, 0x05, 0x07, 0x08,
+                0x09, 0x0a, 0x0c, 0x0e, 0x10, 0x11, 0x12, 0x14,
+                0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1e,
+                0x1f, 0x20, 0x20, 0x22, 0x23, 0x25, 0x26, 0x27,
+                0x28, 0x28, 0x29, 0x2b, 0x2c, 0x2d, 0x2d, 0x2f,
+                0x30, 0x31, 0x31, 0x33, 0x34, 0x35, 0x35, 0x37,
+                0x38, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3c,
+                0x3d, 0x3f, 0x3f, 0x40, 0x40, 0x42, 0x43, 0x43,
+                0x44, 0x44, 0x45, 0x47, 0x47, 0x48, 0x48, 0x49,
+                0x4a, 0x4a, 0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4d,
+                0x4f, 0x4f, 0x50, 0x50, 0x52, 0x52, 0x53, 0x53,
+                0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x58, 0x58,
+                0x59, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c,
+                0x5c, 0x5e, 0x5e, 0x5f, 0x5f, 0x60, 0x60, 0x61,
+                0x61, 0x61, 0x62, 0x62, 0x63, 0x63, 0x65, 0x65,
+                0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, 0x68,
+                0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6c, 0x6c,
+                0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f,
+                0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x73, 0x73,
+                0x73, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x77,
+                0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x7a,
+                0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c,
+                0x7c, 0x7d, 0x7d, 0x7d, 0x7f, 0x7f, 0x7f, 0x80,
+                0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82,
+                0x82, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85,
+                0x86, 0x86, 0x86, 0x88, 0x88, 0x88, 0x88, 0x89,
+                0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b,
+                0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e,
+                0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90,
+                0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92,
+                0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94,
+                0x96, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97,
+                0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x99,
+                0x9a, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b,
+                0x9b, 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d,
+                0x9d, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0xa0, 0xa0,
+                0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2,
+                0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4,
+                0xa4, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5,
+                0xa5, 0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8,
+                0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xab,
+                0xab, 0xab, 0xab, 0xab, 0xac, 0xac, 0xac, 0xac,
+                0xad, 0xad, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae,
+                0xae, 0xae, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0,
+                0xb0, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1,
+                0xb1, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3,
+                0xb3, 0xb3, 0xb3, 0xb4, 0xb3, 0xb4, 0xb4, 0xb4,
+                0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7,
+                0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
+                0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba,
+                0xba, 0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
+                0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe,
+                0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+                0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0xc2,
+                0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3,
+                0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5,
+                0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6,
+                0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7,
+                0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca,
+                0xca, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb,
+                0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+                0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce,
+                0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf,
+                0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
+                0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3,
+                0xd3, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4,
+                0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6,
+                0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8,
+                0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9,
+                0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda,
+                0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdd,
+                0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde,
+                0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf,
+                0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0,
+                0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2,
+                0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3,
+                0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4,
+                0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6,
+                0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7,
+                0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8,
+                0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9,
+                0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec,
+                0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed,
+                0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee,
+                0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0,
+                0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1,
+                0xf1, 0xf1, 0xf1, 0xf1, 0xf3, 0xf3, 0xf3, 0xf3,
+                0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,
+                0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6,
+                0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7,
+                0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8,
+                0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb}
+           },
+           {                           /* gamma 3 - from tp6810 + cx0342 */
+               {0x08, 0x09, 0x0c, 0x0d, 0x10, 0x11, 0x14, 0x15,
+                0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x1f, 0x20, 0x23,
+                0x25, 0x26, 0x27, 0x28, 0x2b, 0x2c, 0x2d, 0x2f,
+                0x30, 0x31, 0x33, 0x34, 0x35, 0x37, 0x38, 0x39,
+                0x3a, 0x3b, 0x3c, 0x3d, 0x3f, 0x40, 0x42, 0x43,
+                0x44, 0x45, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
+                0x4c, 0x4d, 0x4d, 0x4f, 0x50, 0x52, 0x53, 0x53,
+                0x54, 0x55, 0x56, 0x56, 0x58, 0x59, 0x5a, 0x5a,
+                0x5b, 0x5c, 0x5c, 0x5e, 0x5f, 0x5f, 0x60, 0x61,
+                0x61, 0x62, 0x63, 0x63, 0x65, 0x66, 0x66, 0x67,
+                0x68, 0x68, 0x69, 0x69, 0x6a, 0x6c, 0x6c, 0x6d,
+                0x6d, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x73,
+                0x73, 0x74, 0x74, 0x75, 0x75, 0x77, 0x77, 0x78,
+                0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c,
+                0x7d, 0x7d, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81,
+                0x82, 0x82, 0x84, 0x84, 0x85, 0x85, 0x86, 0x86,
+                0x86, 0x88, 0x88, 0x89, 0x89, 0x8a, 0x8a, 0x8b,
+                0x8b, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8f, 0x8f,
+                0x90, 0x90, 0x91, 0x91, 0x91, 0x92, 0x92, 0x93,
+                0x93, 0x93, 0x94, 0x94, 0x96, 0x96, 0x97, 0x97,
+                0x97, 0x98, 0x98, 0x99, 0x99, 0x99, 0x9a, 0x9a,
+                0x9a, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d,
+                0x9e, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1,
+                0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4,
+                0xa4, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa8, 0xa8,
+                0xa8, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab, 0xac,
+                0xac, 0xac, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae,
+                0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1,
+                0xb1, 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3,
+                0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7,
+                0xb7, 0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9,
+                0xba, 0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd,
+                0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf,
+                0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0xc2, 0xc2,
+                0xc3, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc5,
+                0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7,
+                0xc7, 0xc7, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca,
+                0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc,
+                0xcc, 0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce,
+                0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0,
+                0xd0, 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3,
+                0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6,
+                0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8,
+                0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda,
+                0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd,
+                0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf,
+                0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1,
+                0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2,
+                0xe3, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4,
+                0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6,
+                0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8,
+                0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb,
+                0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec,
+                0xed, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee,
+                0xee, 0xee, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0,
+                0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
+                0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4,
+                0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6,
+                0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
+                0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9,
+                0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
+                0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd,
+                0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+               {0x03, 0x05, 0x07, 0x09, 0x0a, 0x0c, 0x0d, 0x10,
+                0x11, 0x12, 0x14, 0x15, 0x17, 0x18, 0x1a, 0x1b,
+                0x1c, 0x1e, 0x1f, 0x20, 0x22, 0x23, 0x25, 0x26,
+                0x27, 0x28, 0x29, 0x2b, 0x2c, 0x2c, 0x2d, 0x2f,
+                0x30, 0x31, 0x33, 0x33, 0x34, 0x35, 0x37, 0x38,
+                0x38, 0x39, 0x3a, 0x3b, 0x3b, 0x3c, 0x3d, 0x3f,
+                0x3f, 0x40, 0x42, 0x42, 0x43, 0x44, 0x45, 0x45,
+                0x47, 0x47, 0x48, 0x49, 0x49, 0x4a, 0x4b, 0x4b,
+                0x4c, 0x4d, 0x4d, 0x4f, 0x4f, 0x50, 0x52, 0x52,
+                0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x56, 0x58,
+                0x58, 0x59, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c,
+                0x5c, 0x5e, 0x5e, 0x5f, 0x5f, 0x60, 0x60, 0x61,
+                0x61, 0x62, 0x62, 0x63, 0x63, 0x65, 0x65, 0x66,
+                0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x69, 0x69,
+                0x6a, 0x6a, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6e,
+                0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71,
+                0x71, 0x73, 0x73, 0x74, 0x74, 0x74, 0x75, 0x75,
+                0x77, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x79,
+                0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c,
+                0x7d, 0x7d, 0x7d, 0x7f, 0x7f, 0x7f, 0x80, 0x80,
+                0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x84,
+                0x84, 0x84, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86,
+                0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x8a, 0x8a,
+                0x8a, 0x8b, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8e,
+                0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x90, 0x90,
+                0x90, 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92,
+                0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x96,
+                0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x98, 0x98,
+                0x98, 0x98, 0x99, 0x99, 0x99, 0x9a, 0x9a, 0x9a,
+                0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c,
+                0x9c, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9e,
+                0xa0, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1,
+                0xa2, 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3,
+                0xa4, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5,
+                0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8,
+                0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab,
+                0xab, 0xac, 0xac, 0xac, 0xac, 0xad, 0xad, 0xad,
+                0xad, 0xad, 0xae, 0xae, 0xae, 0xae, 0xaf, 0xaf,
+                0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb1,
+                0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
+                0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4,
+                0xb4, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7,
+                0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb8, 0xb9,
+                0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba,
+                0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd,
+                0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+                0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0,
+                0xc0, 0xc0, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3,
+                0xc3, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4,
+                0xc4, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6,
+                0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7,
+                0xc7, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca,
+                0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb,
+                0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd,
+                0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce,
+                0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0,
+                0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd1,
+                0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd4,
+                0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6,
+                0xd6, 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7,
+                0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9,
+                0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda,
+                0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdd,
+                0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde,
+                0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf,
+                0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1,
+                0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2,
+                0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3,
+                0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5,
+                0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6,
+                0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
+                0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9,
+                0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb,
+                0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec,
+                0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xee,
+                0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef,
+                0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+                0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3,
+                0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4,
+                0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5,
+                0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6,
+                0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8,
+                0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9,
+                0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc,
+                0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
+                0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe,
+                0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+               {0x07, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14,
+                0x16, 0x17, 0x18, 0x1b, 0x1c, 0x1e, 0x1f, 0x20,
+                0x23, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2b, 0x2d,
+                0x2f, 0x30, 0x31, 0x33, 0x34, 0x35, 0x37, 0x38,
+                0x39, 0x3a, 0x3b, 0x3b, 0x3c, 0x3d, 0x3f, 0x40,
+                0x42, 0x43, 0x44, 0x44, 0x45, 0x47, 0x48, 0x49,
+                0x4a, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4f, 0x50,
+                0x52, 0x52, 0x53, 0x54, 0x55, 0x55, 0x56, 0x58,
+                0x58, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5e, 0x5e,
+                0x5f, 0x5f, 0x60, 0x61, 0x61, 0x62, 0x63, 0x63,
+                0x65, 0x65, 0x66, 0x67, 0x67, 0x68, 0x68, 0x69,
+                0x6a, 0x6a, 0x6c, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e,
+                0x6f, 0x70, 0x70, 0x71, 0x71, 0x73, 0x73, 0x74,
+                0x74, 0x75, 0x75, 0x77, 0x77, 0x78, 0x78, 0x79,
+                0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7d,
+                0x7d, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81,
+                0x82, 0x82, 0x84, 0x84, 0x85, 0x85, 0x86, 0x86,
+                0x88, 0x88, 0x88, 0x89, 0x89, 0x8a, 0x8a, 0x8b,
+                0x8b, 0x8b, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8f,
+                0x8f, 0x90, 0x90, 0x90, 0x91, 0x91, 0x92, 0x92,
+                0x92, 0x93, 0x93, 0x94, 0x94, 0x94, 0x96, 0x96,
+                0x96, 0x97, 0x97, 0x98, 0x98, 0x98, 0x99, 0x99,
+                0x99, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c,
+                0x9c, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0xa0,
+                0xa0, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa3,
+                0xa3, 0xa3, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5,
+                0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8, 0xa9,
+                0xa9, 0xa9, 0xab, 0xab, 0xab, 0xac, 0xac, 0xac,
+                0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xaf, 0xaf,
+                0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1,
+                0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb4,
+                0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7,
+                0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9,
+                0xb9, 0xba, 0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbc,
+                0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbf,
+                0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2,
+                0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3, 0xc4,
+                0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6,
+                0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, 0xc9, 0xc9,
+                0xc9, 0xc9, 0xca, 0xca, 0xca, 0xca, 0xcb, 0xcb,
+                0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd,
+                0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce, 0xcf,
+                0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1,
+                0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3,
+                0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6,
+                0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8,
+                0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda,
+                0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdd,
+                0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xde,
+                0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0,
+                0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2,
+                0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4,
+                0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5,
+                0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7,
+                0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9,
+                0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb, 0xeb,
+                0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed,
+                0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee,
+                0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0,
+                0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3,
+                0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4,
+                0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6,
+                0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
+                0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9,
+                0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
+                0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd,
+                0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+           },
+           {                           /* gamma 4 - from tp6800 + soi763a */
+               {0x11, 0x14, 0x15, 0x17, 0x1a, 0x1b, 0x1e, 0x1f,
+                0x22, 0x23, 0x25, 0x27, 0x28, 0x2b, 0x2c, 0x2d,
+                0x2f, 0x31, 0x33, 0x34, 0x35, 0x38, 0x39, 0x3a,
+                0x3b, 0x3c, 0x3d, 0x40, 0x42, 0x43, 0x44, 0x45,
+                0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4f,
+                0x50, 0x52, 0x53, 0x53, 0x54, 0x55, 0x56, 0x58,
+                0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5e, 0x5f, 0x60,
+                0x61, 0x61, 0x62, 0x63, 0x65, 0x65, 0x66, 0x67,
+                0x68, 0x68, 0x69, 0x6a, 0x6c, 0x6c, 0x6d, 0x6e,
+                0x6f, 0x6f, 0x70, 0x71, 0x71, 0x73, 0x74, 0x74,
+                0x75, 0x77, 0x77, 0x78, 0x79, 0x79, 0x7a, 0x7a,
+                0x7b, 0x7c, 0x7c, 0x7d, 0x7f, 0x7f, 0x80, 0x80,
+                0x81, 0x81, 0x82, 0x84, 0x84, 0x85, 0x85, 0x86,
+                0x86, 0x88, 0x89, 0x89, 0x8a, 0x8a, 0x8b, 0x8b,
+                0x8d, 0x8d, 0x8e, 0x8e, 0x8f, 0x90, 0x90, 0x91,
+                0x91, 0x92, 0x92, 0x93, 0x93, 0x94, 0x94, 0x96,
+                0x96, 0x97, 0x97, 0x98, 0x98, 0x98, 0x99, 0x99,
+                0x9a, 0x9a, 0x9b, 0x9b, 0x9c, 0x9c, 0x9d, 0x9d,
+                0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2,
+                0xa2, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5,
+                0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa9, 0xa9, 0xab,
+                0xab, 0xab, 0xac, 0xac, 0xad, 0xad, 0xad, 0xae,
+                0xae, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1,
+                0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4,
+                0xb4, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8,
+                0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xbc,
+                0xbc, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbf,
+                0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc2, 0xc2, 0xc2,
+                0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5,
+                0xc5, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc9,
+                0xc9, 0xc9, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb,
+                0xcb, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xce,
+                0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0,
+                0xd0, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3,
+                0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd7, 0xd7,
+                0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9,
+                0xd9, 0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdb,
+                0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xdf,
+                0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1,
+                0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3,
+                0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5,
+                0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7,
+                0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9,
+                0xe9, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec,
+                0xec, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee,
+                0xee, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0,
+                0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, 0xf3, 0xf3,
+                0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5,
+                0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7,
+                0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9,
+                0xf9, 0xf9, 0xfa, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb},
+               {0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x11, 0x14, 0x15,
+                0x16, 0x17, 0x1a, 0x1b, 0x1c, 0x1e, 0x1f, 0x20,
+                0x23, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2b, 0x2c,
+                0x2d, 0x2f, 0x30, 0x31, 0x33, 0x34, 0x34, 0x35,
+                0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3c, 0x3d,
+                0x3f, 0x40, 0x42, 0x42, 0x43, 0x44, 0x45, 0x45,
+                0x47, 0x48, 0x49, 0x49, 0x4a, 0x4b, 0x4b, 0x4c,
+                0x4d, 0x4f, 0x4f, 0x50, 0x52, 0x52, 0x53, 0x54,
+                0x54, 0x55, 0x55, 0x56, 0x58, 0x58, 0x59, 0x5a,
+                0x5a, 0x5b, 0x5b, 0x5c, 0x5e, 0x5e, 0x5f, 0x5f,
+                0x60, 0x60, 0x61, 0x61, 0x62, 0x63, 0x63, 0x65,
+                0x65, 0x66, 0x66, 0x67, 0x67, 0x68, 0x68, 0x69,
+                0x69, 0x6a, 0x6a, 0x6c, 0x6c, 0x6d, 0x6d, 0x6e,
+                0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x73,
+                0x73, 0x74, 0x74, 0x74, 0x75, 0x75, 0x77, 0x77,
+                0x78, 0x78, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7b,
+                0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7f, 0x7f,
+                0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82,
+                0x84, 0x84, 0x84, 0x85, 0x85, 0x86, 0x86, 0x86,
+                0x88, 0x88, 0x88, 0x89, 0x89, 0x8a, 0x8a, 0x8a,
+                0x8b, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e,
+                0x8e, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x91, 0x91,
+                0x91, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x94,
+                0x94, 0x94, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97,
+                0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x9a,
+                0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c,
+                0x9c, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0xa0,
+                0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2,
+                0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa4,
+                0xa5, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa6, 0xa6,
+                0xa8, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xab,
+                0xaa, 0xab, 0xab, 0xac, 0xac, 0xac, 0xad, 0xad,
+                0xad, 0xad, 0xae, 0xae, 0xae, 0xae, 0xaf, 0xaf,
+                0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1,
+                0xb1, 0xb1, 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3,
+                0xb3, 0xb3, 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6,
+                0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8,
+                0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba,
+                0xba, 0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd,
+                0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+                0xbf, 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0,
+                0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3,
+                0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5,
+                0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7,
+                0xc7, 0xc7, 0xc7, 0xc7, 0xc9, 0xc9, 0xc9, 0xc9,
+                0xca, 0xca, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb,
+                0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd,
+                0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce,
+                0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0,
+                0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd3,
+                0xd3, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4,
+                0xd4, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd7, 0xd7,
+                0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8,
+                0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda,
+                0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb,
+                0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde,
+                0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf,
+                0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1,
+                0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2,
+                0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4,
+                0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
+                0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7,
+                0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8,
+                0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb,
+                0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec,
+                0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed,
+                0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef,
+                0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+                0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3,
+                0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4,
+                0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5,
+                0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7,
+                0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8,
+                0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb},
+               {0x0d, 0x10, 0x11, 0x14, 0x15, 0x17, 0x18, 0x1b,
+                0x1c, 0x1e, 0x20, 0x22, 0x23, 0x26, 0x27, 0x28,
+                0x29, 0x2b, 0x2d, 0x2f, 0x30, 0x31, 0x33, 0x34,
+                0x35, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
+                0x3f, 0x40, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48,
+                0x49, 0x4a, 0x4b, 0x4b, 0x4c, 0x4d, 0x4f, 0x50,
+                0x52, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58,
+                0x59, 0x5a, 0x5a, 0x5b, 0x5c, 0x5e, 0x5e, 0x5f,
+                0x60, 0x60, 0x61, 0x62, 0x62, 0x63, 0x65, 0x65,
+                0x66, 0x67, 0x67, 0x68, 0x69, 0x69, 0x6a, 0x6c,
+                0x6c, 0x6d, 0x6d, 0x6e, 0x6f, 0x6f, 0x70, 0x70,
+                0x71, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 0x77,
+                0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, 0x7b, 0x7b,
+                0x7c, 0x7c, 0x7d, 0x7d, 0x7f, 0x7f, 0x80, 0x80,
+                0x81, 0x81, 0x82, 0x82, 0x84, 0x84, 0x85, 0x85,
+                0x86, 0x86, 0x88, 0x88, 0x89, 0x89, 0x8a, 0x8a,
+                0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8f,
+                0x8f, 0x90, 0x90, 0x91, 0x91, 0x91, 0x92, 0x92,
+                0x93, 0x93, 0x94, 0x94, 0x94, 0x96, 0x96, 0x97,
+                0x97, 0x98, 0x98, 0x98, 0x99, 0x99, 0x9a, 0x9a,
+                0x9a, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d,
+                0x9d, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1,
+                0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4,
+                0xa4, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa8, 0xa8,
+                0xa8, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab, 0xac,
+                0xac, 0xac, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae,
+                0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1,
+                0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb4,
+                0xb4, 0xb4, 0xb6, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7,
+                0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba,
+                0xba, 0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd,
+                0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf,
+                0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0xc2, 0xc2, 0xc3,
+                0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5,
+                0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7,
+                0xc7, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca,
+                0xca, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcc,
+                0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce,
+                0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0,
+                0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3,
+                0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6,
+                0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd8,
+                0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda,
+                0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd,
+                0xdd, 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf,
+                0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1,
+                0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3,
+                0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5,
+                0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6,
+                0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8,
+                0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb,
+                0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed,
+                0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee,
+                0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0,
+                0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3,
+                0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,
+                0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6,
+                0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8,
+                0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9,
+                0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb}
+           },
+           {                                                   /* gamma 5 */
+               {0x16, 0x18, 0x19, 0x1b, 0x1d, 0x1e, 0x20, 0x21,
+                0x23, 0x24, 0x25, 0x27, 0x28, 0x2a, 0x2b, 0x2c,
+                0x2d, 0x2f, 0x30, 0x31, 0x32, 0x34, 0x35, 0x36,
+                0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+                0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+                0x48, 0x49, 0x4a, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
+                0x4f, 0x50, 0x51, 0x51, 0x52, 0x53, 0x54, 0x55,
+                0x56, 0x56, 0x57, 0x58, 0x59, 0x59, 0x5a, 0x5b,
+                0x5c, 0x5c, 0x5d, 0x5e, 0x5f, 0x5f, 0x60, 0x61,
+                0x62, 0x62, 0x63, 0x64, 0x64, 0x65, 0x66, 0x66,
+                0x67, 0x68, 0x68, 0x69, 0x6a, 0x6a, 0x6b, 0x6b,
+                0x6c, 0x6d, 0x6d, 0x6e, 0x6f, 0x6f, 0x70, 0x70,
+                0x71, 0x71, 0x72, 0x73, 0x73, 0x74, 0x74, 0x75,
+                0x75, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79,
+                0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7d, 0x7d, 0x7e,
+                0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x82,
+                0x82, 0x83, 0x83, 0x84, 0x84, 0x84, 0x85, 0x85,
+                0x86, 0x86, 0x87, 0x87, 0x88, 0x88, 0x89, 0x89,
+                0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8d,
+                0x8d, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x90, 0x90,
+                0x91, 0x91, 0x91, 0x92, 0x92, 0x93, 0x93, 0x94,
+                0x94, 0x94, 0x95, 0x95, 0x96, 0x96, 0x96, 0x97,
+                0x97, 0x98, 0x98, 0x98, 0x99, 0x99, 0x9a, 0x9a,
+                0x9a, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9d, 0x9d,
+                0x9d, 0x9e, 0x9e, 0x9e, 0x9f, 0x9f, 0xa0, 0xa0,
+                0xa0, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa3,
+                0xa3, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa6,
+                0xa6, 0xa6, 0xa7, 0xa7, 0xa7, 0xa8, 0xa8, 0xa8,
+                0xa9, 0xa9, 0xa9, 0xaa, 0xaa, 0xaa, 0xab, 0xab,
+                0xab, 0xac, 0xac, 0xac, 0xad, 0xad, 0xad, 0xae,
+                0xae, 0xae, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0,
+                0xb0, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3,
+                0xb3, 0xb3, 0xb4, 0xb4, 0xb4, 0xb4, 0xb5, 0xb5,
+                0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7,
+                0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba,
+                0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc,
+                0xbc, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe,
+                0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
+                0xc1, 0xc1, 0xc1, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3,
+                0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5,
+                0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7,
+                0xc7, 0xc8, 0xc8, 0xc8, 0xc8, 0xc9, 0xc9, 0xc9,
+                0xc9, 0xca, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb,
+                0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd,
+                0xcd, 0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf,
+                0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1,
+                0xd1, 0xd2, 0xd2, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3,
+                0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd5, 0xd5, 0xd5,
+                0xd5, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd7, 0xd7,
+                0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9,
+                0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb,
+                0xdb, 0xdb, 0xdb, 0xdc, 0xdc, 0xdc, 0xdc, 0xdd,
+                0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde,
+                0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0,
+                0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2,
+                0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4,
+                0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
+                0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7,
+                0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9,
+                0xe9, 0xe9, 0xea, 0xea, 0xea, 0xea, 0xea, 0xeb,
+                0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec,
+                0xed, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee,
+                0xee, 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0,
+                0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
+                0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3,
+                0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5,
+                0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6,
+                0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8,
+                0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd,
+                0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+               {0x0f, 0x11, 0x12, 0x14, 0x15, 0x16, 0x18, 0x19,
+                0x1a, 0x1b, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
+                0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+                0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x31, 0x32,
+                0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x38, 0x39,
+                0x3a, 0x3b, 0x3c, 0x3c, 0x3d, 0x3e, 0x3f, 0x3f,
+                0x40, 0x41, 0x42, 0x42, 0x43, 0x44, 0x44, 0x45,
+                0x46, 0x47, 0x47, 0x48, 0x49, 0x49, 0x4a, 0x4b,
+                0x4b, 0x4c, 0x4c, 0x4d, 0x4e, 0x4e, 0x4f, 0x50,
+                0x50, 0x51, 0x51, 0x52, 0x53, 0x53, 0x54, 0x54,
+                0x55, 0x55, 0x56, 0x56, 0x57, 0x58, 0x58, 0x59,
+                0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5d,
+                0x5d, 0x5e, 0x5e, 0x5f, 0x5f, 0x60, 0x60, 0x61,
+                0x61, 0x62, 0x62, 0x63, 0x63, 0x64, 0x64, 0x65,
+                0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x68, 0x68,
+                0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c,
+                0x6c, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f,
+                0x6f, 0x70, 0x70, 0x71, 0x71, 0x71, 0x72, 0x72,
+                0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 0x75,
+                0x76, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, 0x78,
+                0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b,
+                0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e,
+                0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81,
+                0x81, 0x81, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83,
+                0x84, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x86,
+                0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88,
+                0x88, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8b,
+                0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d,
+                0x8d, 0x8e, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f,
+                0x90, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91,
+                0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x94,
+                0x94, 0x94, 0x94, 0x95, 0x95, 0x95, 0x96, 0x96,
+                0x96, 0x96, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98,
+                0x98, 0x98, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a,
+                0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c,
+                0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e,
+                0x9e, 0x9e, 0x9f, 0x9f, 0x9f, 0x9f, 0xa0, 0xa0,
+                0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2,
+                0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4,
+                0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+                0xa6, 0xa6, 0xa6, 0xa6, 0xa7, 0xa7, 0xa7, 0xa7,
+                0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9,
+                0xa9, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xab,
+                0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xac, 0xad,
+                0xad, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xae,
+                0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0,
+                0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2,
+                0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3,
+                0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5,
+                0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb7,
+                0xb7, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb8,
+                0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba,
+                0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+                0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd,
+                0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+                0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0,
+                0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
+                0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3,
+                0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+                0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6,
+                0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7,
+                0xc7, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc9, 0xc9,
+                0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xca,
+                0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc,
+                0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xcd,
+                0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce,
+                0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0,
+                0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
+                0xd1, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd3,
+                0xd3, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4,
+                0xd4, 0xd4, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
+                0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd7, 0xd7,
+                0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8,
+                0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xda,
+                0xda, 0xda, 0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb,
+                0xdb, 0xdb, 0xdb, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc,
+                0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde,
+                0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf,
+                0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0,
+                0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2,
+                0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3,
+                0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5,
+                0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6,
+                0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
+                0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9,
+                0xe9, 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea, 0xea,
+                0xea, 0xea, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb,
+                0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed,
+                0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee,
+                0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0,
+                0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1,
+                0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+                0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4,
+                0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5,
+                0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7,
+                0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8,
+                0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd,
+                0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
+                0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+               {0x13, 0x15, 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1e,
+                0x1f, 0x20, 0x22, 0x23, 0x24, 0x26, 0x27, 0x28,
+                0x29, 0x2a, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31,
+                0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+                0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41,
+                0x42, 0x43, 0x44, 0x44, 0x45, 0x46, 0x47, 0x48,
+                0x49, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e,
+                0x4f, 0x50, 0x50, 0x51, 0x52, 0x53, 0x53, 0x54,
+                0x55, 0x55, 0x56, 0x57, 0x57, 0x58, 0x59, 0x59,
+                0x5a, 0x5b, 0x5b, 0x5c, 0x5d, 0x5d, 0x5e, 0x5f,
+                0x5f, 0x60, 0x60, 0x61, 0x62, 0x62, 0x63, 0x63,
+                0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68,
+                0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c,
+                0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70,
+                0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74,
+                0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78,
+                0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c,
+                0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f,
+                0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x83,
+                0x83, 0x84, 0x84, 0x84, 0x85, 0x85, 0x86, 0x86,
+                0x86, 0x87, 0x87, 0x88, 0x88, 0x88, 0x89, 0x89,
+                0x89, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c,
+                0x8c, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f,
+                0x8f, 0x90, 0x90, 0x90, 0x91, 0x91, 0x92, 0x92,
+                0x92, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x95,
+                0x95, 0x95, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97,
+                0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x9a, 0x9a,
+                0x9a, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9d,
+                0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9e, 0x9f, 0x9f,
+                0x9f, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa2,
+                0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4,
+                0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa6,
+                0xa7, 0xa7, 0xa7, 0xa7, 0xa8, 0xa8, 0xa8, 0xa9,
+                0xa9, 0xa9, 0xa9, 0xaa, 0xaa, 0xaa, 0xab, 0xab,
+                0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xad, 0xad,
+                0xad, 0xae, 0xae, 0xae, 0xae, 0xaf, 0xaf, 0xaf,
+                0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1,
+                0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3,
+                0xb4, 0xb4, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5,
+                0xb6, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7,
+                0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9,
+                0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb,
+                0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd,
+                0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf,
+                0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc1,
+                0xc1, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3,
+                0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5,
+                0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7,
+                0xc7, 0xc7, 0xc7, 0xc7, 0xc8, 0xc8, 0xc8, 0xc8,
+                0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca,
+                0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc,
+                0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xce,
+                0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf,
+                0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1,
+                0xd1, 0xd1, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd3,
+                0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4,
+                0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd6, 0xd6, 0xd6,
+                0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8,
+                0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9,
+                0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb, 0xdb,
+                0xdb, 0xdb, 0xdb, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc,
+                0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde,
+                0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0,
+                0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1,
+                0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3,
+                0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4,
+                0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6,
+                0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
+                0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9,
+                0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea, 0xea, 0xea,
+                0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec,
+                0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed,
+                0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef,
+                0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+                0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2,
+                0xf2, 0xf2, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3,
+                0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5,
+                0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6,
+                0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8,
+                0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9,
+                0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb,
+                0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
+                0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe,
+                0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+           },
+       };
+
+       reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x00);
+       if (sd->bridge == BRIDGE_TP6810)
+               reg_w(gspca_dev, 0x02, 0x28);
+/*     msleep(50); */
+       gamma = sd->ctrls[GAMMA].val;
+       bulk_w(gspca_dev, 0x00, gamma_tb[gamma][0], 1024);
+       bulk_w(gspca_dev, 0x01, gamma_tb[gamma][1], 1024);
+       bulk_w(gspca_dev, 0x02, gamma_tb[gamma][2], 1024);
+       if (sd->bridge == BRIDGE_TP6810) {
+               int i;
+
+               reg_w(gspca_dev, 0x02, 0x2b);
+               reg_w(gspca_dev, 0x02, 0x28);
+               for (i = 0; i < 6; i++)
+                       reg_w(gspca_dev, TP6800_R55_GAMMA_R,
+                               gamma_tb[gamma][0][i]);
+               reg_w(gspca_dev, 0x02, 0x2b);
+               reg_w(gspca_dev, 0x02, 0x28);
+               for (i = 0; i < 6; i++)
+                       reg_w(gspca_dev, TP6800_R56_GAMMA_G,
+                               gamma_tb[gamma][1][i]);
+               reg_w(gspca_dev, 0x02, 0x2b);
+               reg_w(gspca_dev, 0x02, 0x28);
+               for (i = 0; i < 6; i++)
+                       reg_w(gspca_dev, TP6800_R57_GAMMA_B,
+                               gamma_tb[gamma][2][i]);
+               reg_w(gspca_dev, 0x02, 0x28);
+       }
+       reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x03);
+/*     msleep(50); */
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 val;
+
+       if (sd->bridge == BRIDGE_TP6800) {
+               val = sd->ctrls[SHARPNESS].val
+                               | 0x08;         /* grid compensation enable */
+               if (gspca_dev->width == 640)
+                       reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00); /* vga */
+               else
+                       val |= 0x04;            /* scaling down enable */
+               reg_w(gspca_dev, TP6800_R5D_DEMOSAIC_CFG, val);
+       } else {
+               val = (sd->ctrls[SHARPNESS].val << 5) | 0x08;
+               reg_w(gspca_dev, 0x59, val);
+       }
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (gspca_dev->ctrl_dis & (1 << AUTOGAIN))
+               return;
+       if (sd->ctrls[AUTOGAIN].val) {
+               sd->ag_cnt = AG_CNT_START;
+               gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN);
+       } else {
+               sd->ag_cnt = -1;
+               gspca_dev->ctrl_inac &= ~((1 << EXPOSURE) | (1 << GAIN));
+       }
+}
+
+/* set the resolution for sensor cx0342 */
+static void set_resolution(struct gspca_dev *gspca_dev)
+{
+       reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x00);
+       if (gspca_dev->width == 320) {
+               reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x06);
+               msleep(100);
+               i2c_w(gspca_dev, CX0342_AUTO_ADC_CALIB, 0x01);
+               msleep(100);
+               reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x03);
+               reg_w(gspca_dev, TP6800_R78_FORMAT, 0x01);      /* qvga */
+               reg_w(gspca_dev, TP6800_R5D_DEMOSAIC_CFG, 0x0d);
+               i2c_w(gspca_dev, CX0342_EXPO_LINE_L, 0x37);
+               i2c_w(gspca_dev, CX0342_EXPO_LINE_H, 0x01);
+       } else {
+               reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x05);
+               msleep(100);
+               i2c_w(gspca_dev, CX0342_AUTO_ADC_CALIB, 0x01);
+               msleep(100);
+               reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x03);
+               reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00);      /* vga */
+               reg_w(gspca_dev, TP6800_R5D_DEMOSAIC_CFG, 0x09);
+               i2c_w(gspca_dev, CX0342_EXPO_LINE_L, 0xcf);
+               i2c_w(gspca_dev, CX0342_EXPO_LINE_H, 0x00);
+       }
+       i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x01);
+       bulk_w(gspca_dev, 0x03, color_gain[SENSOR_CX0342],
+                               ARRAY_SIZE(color_gain[0]));
+       setgamma(gspca_dev);
+       setquality(gspca_dev);
+}
+
+/* convert the frame rate to a tp68x0 value */
+static int get_fr_idx(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+
+       if (sd->bridge == BRIDGE_TP6800) {
+               for (i = 0; i < ARRAY_SIZE(rates) - 1; i++) {
+                       if (sd->framerate >= rates[i])
+                               break;
+               }
+               i = 6 - i;              /* 1 = 5fps .. 6 = 30fps */
+
+               /* 640x480 * 30 fps does not work */
+               if (i == 6                      /* if 30 fps */
+                && gspca_dev->width == 640)
+                       i = 0x86;               /* 15 fps */
+       } else {
+               for (i = 0; i < ARRAY_SIZE(rates_6810) - 1; i++) {
+                       if (sd->framerate >= rates_6810[i])
+                               break;
+               }
+               i = 7 - i;              /* 3 = 5fps .. 7 = 30fps */
+
+               /* 640x480 * 30 fps does not work */
+               if (i == 7                      /* if 30 fps */
+                && gspca_dev->width == 640)
+                       i = 6;                  /* 15 fps */
+               i |= 0x80;                      /* clock * 1 */
+       }
+       return i;
+}
+
+static void setframerate(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 fr_idx;
+
+       fr_idx = get_fr_idx(gspca_dev);
+
+       if (sd->bridge == BRIDGE_TP6810) {
+               reg_r(gspca_dev, 0x7b);
+               reg_w(gspca_dev, 0x7b,
+                       sd->sensor == SENSOR_CX0342 ? 0x10 : 0x90);
+               if (sd->ctrls[EXPOSURE].val >= 128)
+                       fr_idx = 0xf0;          /* lower frame rate */
+       }
+
+       reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, fr_idx);
+
+       if (sd->sensor == SENSOR_CX0342)
+               i2c_w(gspca_dev, CX0342_AUTO_ADC_CALIB, 0x01);
+}
+
+static void setrgain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int rgain;
+
+       rgain = sd->ctrls[RGAIN].val;
+       i2c_w(gspca_dev, CX0342_RAW_RGAIN_H, rgain >> 8);
+       i2c_w(gspca_dev, CX0342_RAW_RGAIN_L, rgain);
+       i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x80);
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->sensor == SENSOR_CX0342) {
+               sd->ctrls[BGAIN].val = sd->ctrls[BGAIN].val
+                                       * val / sd->ctrls[GAIN].val;
+               if (sd->ctrls[BGAIN].val > 4095)
+                       sd->ctrls[BGAIN].val = 4095;
+               sd->ctrls[RGAIN].val = sd->ctrls[RGAIN].val
+                                       * val / sd->ctrls[GAIN].val;
+               if (sd->ctrls[RGAIN].val > 4095)
+                       sd->ctrls[RGAIN].val = 4095;
+       }
+       sd->ctrls[GAIN].val = val;
+       if (gspca_dev->streaming)
+               setexposure(gspca_dev);
+       return gspca_dev->usb_err;
+}
+
+static void setbgain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int bgain;
+
+       bgain = sd->ctrls[BGAIN].val;
+       i2c_w(gspca_dev, CX0342_RAW_BGAIN_H, bgain >> 8);
+       i2c_w(gspca_dev, CX0342_RAW_BGAIN_L, bgain);
+       i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x80);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                    const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->bridge = id->driver_info;
+
+       gspca_dev->cam.cam_mode = vga_mode;
+       gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+       gspca_dev->cam.mode_framerates = sd->bridge == BRIDGE_TP6800 ?
+                       framerates : framerates_6810;
+
+       sd->framerate = 30;             /* default: 30 fps */
+       gspca_dev->cam.ctrls = sd->ctrls;
+       return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       static const struct cmd tp6800_preinit[] = {
+               {TP6800_R10_SIF_TYPE, 0x01},    /* sif */
+               {TP6800_R11_SIF_CONTROL, 0x01},
+               {TP6800_R15_GPIO_PU, 0x9f},
+               {TP6800_R16_GPIO_PD, 0x9f},
+               {TP6800_R17_GPIO_IO, 0x80},
+               {TP6800_R18_GPIO_DATA, 0x40},   /* LED off */
+       };
+       static const struct cmd tp6810_preinit[] = {
+               {TP6800_R2F_TIMING_CFG, 0x2f},
+               {TP6800_R15_GPIO_PU, 0x6f},
+               {TP6800_R16_GPIO_PD, 0x40},
+               {TP6800_R17_GPIO_IO, 0x9f},
+               {TP6800_R18_GPIO_DATA, 0xc1},   /* LED off */
+       };
+
+       if (sd->bridge == BRIDGE_TP6800)
+               reg_w_buf(gspca_dev, tp6800_preinit,
+                               ARRAY_SIZE(tp6800_preinit));
+       else
+               reg_w_buf(gspca_dev, tp6810_preinit,
+                               ARRAY_SIZE(tp6810_preinit));
+       msleep(15);
+       reg_r(gspca_dev, TP6800_R18_GPIO_DATA);
+       PDEBUG(D_PROBE, "gpio: %02x", gspca_dev->usb_buf[0]);
+/* values:
+ *     0x80: snapshot button
+ *     0x40: LED
+ *     0x20: (bridge / sensor) reset for tp6810 ?
+ *     0x07: sensor type ?
+ */
+
+       /* guess the sensor type */
+       if (force_sensor >= 0) {
+               sd->sensor = force_sensor;
+       } else {
+               if (sd->bridge == BRIDGE_TP6800) {
+/*fixme: not sure this is working*/
+                       switch (gspca_dev->usb_buf[0] & 0x07) {
+                       case 0:
+                               sd->sensor = SENSOR_SOI763A;
+                               break;
+                       case 1:
+                               sd->sensor = SENSOR_CX0342;
+                               break;
+                       }
+               } else {
+                       int sensor;
+
+                       sensor = probe_6810(gspca_dev);
+                       if (sensor < 0) {
+                               pr_warn("Unknown sensor %d - forced to soi763a\n",
+                                       -sensor);
+                               sensor = SENSOR_SOI763A;
+                       }
+                       sd->sensor = sensor;
+               }
+       }
+       if (sd->sensor == SENSOR_SOI763A) {
+               pr_info("Sensor soi763a\n");
+               sd->ctrls[GAMMA].def = sd->bridge == BRIDGE_TP6800 ? 0 : 1;
+               sd->ctrls[GAIN].max = 15;
+               sd->ctrls[GAIN].def = 3;
+               gspca_dev->ctrl_dis = (1 << RGAIN) | (1 << BGAIN);
+               if (sd->bridge == BRIDGE_TP6810) {
+                       soi763a_6810_init(gspca_dev);
+#if AUTOGAIN_DEF
+                       gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN);
+#endif
+               } else {
+                       gspca_dev->ctrl_dis |= (1 << AUTOGAIN);
+               }
+       } else {
+               pr_info("Sensor cx0342\n");
+               if (sd->bridge == BRIDGE_TP6810) {
+                       cx0342_6810_init(gspca_dev);
+#if AUTOGAIN_DEF
+                       gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN);
+#endif
+               } else {
+                       gspca_dev->ctrl_dis |= (1 << AUTOGAIN);
+               }
+       }
+
+       if (sd->bridge == BRIDGE_TP6810)
+               sd->ctrls[QUALITY].def = 0;     /* auto quality */
+       set_dqt(gspca_dev, 0);
+       return 0;
+}
+
+/* This function is called before choosing the alt setting */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       static const struct cmd cx_sensor_init[] = {
+               {CX0342_AUTO_ADC_CALIB, 0x81},
+               {CX0342_EXPO_LINE_L, 0x37},
+               {CX0342_EXPO_LINE_H, 0x01},
+               {CX0342_RAW_GRGAIN_L, 0x00},
+               {CX0342_RAW_GBGAIN_L, 0x00},
+               {CX0342_RAW_RGAIN_L, 0x00},
+               {CX0342_RAW_BGAIN_L, 0x00},
+               {CX0342_SYS_CTRL_0, 0x81},
+       };
+       static const struct cmd cx_bridge_init[] = {
+               {0x4d, 0x00},
+               {0x4c, 0xff},
+               {0x4e, 0xff},
+               {0x4f, 0x00},
+       };
+       static const struct cmd ov_sensor_init[] = {
+               {0x10, 0x75},           /* exposure */
+               {0x76, 0x03},
+               {0x00, 0x00},           /* gain */
+       };
+       static const struct cmd ov_bridge_init[] = {
+               {0x7b, 0x90},
+               {TP6800_R3F_FRAME_RATE, 0x87},
+       };
+
+       if (sd->bridge == BRIDGE_TP6800)
+               return 0;
+       if (sd->sensor == SENSOR_CX0342) {
+               reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x20);
+               reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x87);
+               i2c_w_buf(gspca_dev, cx_sensor_init,
+                               ARRAY_SIZE(cx_sensor_init));
+               reg_w_buf(gspca_dev, cx_bridge_init,
+                               ARRAY_SIZE(cx_bridge_init));
+               bulk_w(gspca_dev, 0x03, color_null, sizeof color_null);
+               reg_w(gspca_dev, 0x59, 0x40);
+       } else {
+               reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x21);
+               i2c_w_buf(gspca_dev, ov_sensor_init,
+                               ARRAY_SIZE(ov_sensor_init));
+               reg_r(gspca_dev, 0x7b);
+               reg_w_buf(gspca_dev, ov_bridge_init,
+                               ARRAY_SIZE(ov_bridge_init));
+       }
+       reg_w(gspca_dev, TP6800_R78_FORMAT,
+                       gspca_dev->curr_mode ? 0x00 : 0x01);
+       return gspca_dev->usb_err;
+}
+
+static void set_led(struct gspca_dev *gspca_dev, int on)
+{
+       u8 data;
+
+       reg_r(gspca_dev, TP6800_R18_GPIO_DATA);
+       data = gspca_dev->usb_buf[0];
+       if (on)
+               data &= ~0x40;
+       else
+               data |= 0x40;
+       reg_w(gspca_dev, TP6800_R18_GPIO_DATA, data);
+}
+
+static void cx0342_6800_start(struct gspca_dev *gspca_dev)
+{
+       static const struct cmd reg_init[] = {
+/*fixme: is this usefull?*/
+               {TP6800_R17_GPIO_IO, 0x9f},
+               {TP6800_R16_GPIO_PD, 0x40},
+               {TP6800_R10_SIF_TYPE, 0x00},    /* i2c 8 bits */
+               {TP6800_R50, 0x00},
+               {TP6800_R51, 0x00},
+               {TP6800_R52, 0xff},
+               {TP6800_R53, 0x03},
+               {TP6800_R54_DARK_CFG, 0x07},
+               {TP6800_R5C_EDGE_THRLD, 0x40},
+               {TP6800_R7A_BLK_THRLD, 0x40},
+               {TP6800_R2F_TIMING_CFG, 0x17},
+               {TP6800_R30_SENSOR_CFG, 0x18},  /* G1B..RG0 */
+               {TP6800_R37_FRONT_DARK_ST, 0x00},
+               {TP6800_R38_FRONT_DARK_END, 0x00},
+               {TP6800_R39_REAR_DARK_ST_L, 0x00},
+               {TP6800_R3A_REAR_DARK_ST_H, 0x00},
+               {TP6800_R3B_REAR_DARK_END_L, 0x00},
+               {TP6800_R3C_REAR_DARK_END_H, 0x00},
+               {TP6800_R3D_HORIZ_DARK_LINE_L, 0x00},
+               {TP6800_R3E_HORIZ_DARK_LINE_H, 0x00},
+               {TP6800_R21_ENDP_1_CTL, 0x03},
+
+               {TP6800_R31_PIXEL_START, 0x0b},
+               {TP6800_R32_PIXEL_END_L, 0x8a},
+               {TP6800_R33_PIXEL_END_H, 0x02},
+               {TP6800_R34_LINE_START, 0x0e},
+               {TP6800_R35_LINE_END_L, 0xf4},
+               {TP6800_R36_LINE_END_H, 0x01},
+               {TP6800_R78_FORMAT, 0x00},
+               {TP6800_R12_SIF_ADDR_S, 0x20},  /* cx0342 i2c addr */
+       };
+       static const struct cmd sensor_init[] = {
+               {CX0342_OUTPUT_CTRL, 0x07},
+               {CX0342_BYPASS_MODE, 0x58},
+               {CX0342_GPXLTHD_L, 0x16},
+               {CX0342_RBPXLTHD_L, 0x16},
+               {CX0342_PLANETHD_L, 0xc0},
+               {CX0342_PLANETHD_H, 0x03},
+               {CX0342_RB_GAP_L, 0xff},
+               {CX0342_RB_GAP_H, 0x07},
+               {CX0342_G_GAP_L, 0xff},
+               {CX0342_G_GAP_H, 0x07},
+               {CX0342_RST_OVERFLOW_L, 0x5c},
+               {CX0342_RST_OVERFLOW_H, 0x01},
+               {CX0342_DATA_OVERFLOW_L, 0xfc},
+               {CX0342_DATA_OVERFLOW_H, 0x03},
+               {CX0342_DATA_UNDERFLOW_L, 0x00},
+               {CX0342_DATA_UNDERFLOW_H, 0x00},
+               {CX0342_SYS_CTRL_0, 0x40},
+               {CX0342_GLOBAL_GAIN, 0x01},
+               {CX0342_CLOCK_GEN, 0x00},
+               {CX0342_SYS_CTRL_0, 0x02},
+               {CX0342_IDLE_CTRL, 0x05},
+               {CX0342_ADCGN, 0x00},
+               {CX0342_ADC_CTL, 0x00},
+               {CX0342_LVRST_BLBIAS, 0x01},
+               {CX0342_VTHSEL, 0x0b},
+               {CX0342_RAMP_RIV, 0x0b},
+               {CX0342_LDOSEL, 0x07},
+               {CX0342_SPV_VALUE_L, 0x40},
+               {CX0342_SPV_VALUE_H, 0x02},
+       };
+
+       reg_w_buf(gspca_dev, reg_init, ARRAY_SIZE(reg_init));
+       i2c_w_buf(gspca_dev, sensor_init, ARRAY_SIZE(sensor_init));
+       i2c_w_buf(gspca_dev, cx0342_timing_seq, ARRAY_SIZE(cx0342_timing_seq));
+       reg_w(gspca_dev, TP6800_R5C_EDGE_THRLD, 0x10);
+       reg_w(gspca_dev, TP6800_R54_DARK_CFG, 0x00);
+       i2c_w(gspca_dev, CX0342_EXPO_LINE_H, 0x00);
+       i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x01);
+       setexposure(gspca_dev);
+       set_led(gspca_dev, 1);
+       set_resolution(gspca_dev);
+}
+
+static void cx0342_6810_start(struct gspca_dev *gspca_dev)
+{
+       static const struct cmd sensor_init_2[] = {
+               {CX0342_EXPO_LINE_L, 0x6f},
+               {CX0342_EXPO_LINE_H, 0x02},
+               {CX0342_RAW_GRGAIN_L, 0x00},
+               {CX0342_RAW_GBGAIN_L, 0x00},
+               {CX0342_RAW_RGAIN_L, 0x00},
+               {CX0342_RAW_BGAIN_L, 0x00},
+               {CX0342_SYS_CTRL_0, 0x81},
+       };
+       static const struct cmd bridge_init_2[] = {
+               {0x4d, 0x00},
+               {0x4c, 0xff},
+               {0x4e, 0xff},
+               {0x4f, 0x00},
+               {TP6800_R7A_BLK_THRLD, 0x00},
+               {TP6800_R79_QUALITY, 0x04},
+               {TP6800_R79_QUALITY, 0x01},
+       };
+       static const struct cmd bridge_init_3[] = {
+               {TP6800_R31_PIXEL_START, 0x08},
+               {TP6800_R32_PIXEL_END_L, 0x87},
+               {TP6800_R33_PIXEL_END_H, 0x02},
+               {TP6800_R34_LINE_START, 0x0e},
+               {TP6800_R35_LINE_END_L, 0xf4},
+               {TP6800_R36_LINE_END_H, 0x01},
+       };
+       static const struct cmd sensor_init_3[] = {
+               {CX0342_AUTO_ADC_CALIB, 0x81},
+               {CX0342_EXPO_LINE_L, 0x6f},
+               {CX0342_EXPO_LINE_H, 0x02},
+               {CX0342_RAW_GRGAIN_L, 0x00},
+               {CX0342_RAW_GBGAIN_L, 0x00},
+               {CX0342_RAW_RGAIN_L, 0x00},
+               {CX0342_RAW_BGAIN_L, 0x00},
+               {CX0342_SYS_CTRL_0, 0x81},
+       };
+       static const struct cmd bridge_init_5[] = {
+               {0x4d, 0x00},
+               {0x4c, 0xff},
+               {0x4e, 0xff},
+               {0x4f, 0x00},
+       };
+       static const struct cmd sensor_init_4[] = {
+               {CX0342_EXPO_LINE_L, 0xd3},
+               {CX0342_EXPO_LINE_H, 0x01},
+/*fixme: gains, but 00..80 only*/
+               {CX0342_RAW_GRGAIN_L, 0x40},
+               {CX0342_RAW_GBGAIN_L, 0x40},
+               {CX0342_RAW_RGAIN_L, 0x40},
+               {CX0342_RAW_BGAIN_L, 0x40},
+               {CX0342_SYS_CTRL_0, 0x81},
+       };
+       static const struct cmd sensor_init_5[] = {
+               {CX0342_IDLE_CTRL, 0x05},
+               {CX0342_ADCGN, 0x00},
+               {CX0342_ADC_CTL, 0x00},
+               {CX0342_LVRST_BLBIAS, 0x01},
+               {CX0342_VTHSEL, 0x0b},
+               {CX0342_RAMP_RIV, 0x0b},
+               {CX0342_LDOSEL, 0x07},
+               {CX0342_SPV_VALUE_L, 0x40},
+               {CX0342_SPV_VALUE_H, 0x02},
+               {CX0342_AUTO_ADC_CALIB, 0x81},
+       };
+
+       reg_w(gspca_dev, 0x22, gspca_dev->alt);
+       i2c_w_buf(gspca_dev, sensor_init_2, ARRAY_SIZE(sensor_init_2));
+       reg_w_buf(gspca_dev, bridge_init_2, ARRAY_SIZE(bridge_init_2));
+       reg_w_buf(gspca_dev, tp6810_cx_init_common,
+                       ARRAY_SIZE(tp6810_cx_init_common));
+       reg_w_buf(gspca_dev, bridge_init_3, ARRAY_SIZE(bridge_init_3));
+       if (gspca_dev->curr_mode) {
+               reg_w(gspca_dev, 0x4a, 0x7f);
+               reg_w(gspca_dev, 0x07, 0x05);
+               reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00);      /* vga */
+       } else {
+               reg_w(gspca_dev, 0x4a, 0xff);
+               reg_w(gspca_dev, 0x07, 0x85);
+               reg_w(gspca_dev, TP6800_R78_FORMAT, 0x01);      /* qvga */
+       }
+       setgamma(gspca_dev);
+       reg_w_buf(gspca_dev, tp6810_bridge_start,
+                       ARRAY_SIZE(tp6810_bridge_start));
+       setsharpness(gspca_dev);
+       bulk_w(gspca_dev, 0x03, color_gain[SENSOR_CX0342],
+                               ARRAY_SIZE(color_gain[0]));
+       reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x87);
+       i2c_w_buf(gspca_dev, sensor_init_3, ARRAY_SIZE(sensor_init_3));
+       reg_w_buf(gspca_dev, bridge_init_5, ARRAY_SIZE(bridge_init_5));
+       i2c_w_buf(gspca_dev, sensor_init_4, ARRAY_SIZE(sensor_init_4));
+       reg_w_buf(gspca_dev, bridge_init_5, ARRAY_SIZE(bridge_init_5));
+       i2c_w_buf(gspca_dev, sensor_init_5, ARRAY_SIZE(sensor_init_5));
+
+       set_led(gspca_dev, 1);
+/*     setquality(gspca_dev); */
+}
+
+static void soi763a_6800_start(struct gspca_dev *gspca_dev)
+{
+       static const struct cmd reg_init[] = {
+               {TP6800_R79_QUALITY, 0x04},
+               {TP6800_R79_QUALITY, 0x01},
+               {TP6800_R10_SIF_TYPE, 0x00},    /* i2c 8 bits */
+
+               {TP6800_R50, 0x00},
+               {TP6800_R51, 0x00},
+               {TP6800_R52, 0xff},
+               {TP6800_R53, 0x03},
+               {TP6800_R54_DARK_CFG, 0x07},
+               {TP6800_R5C_EDGE_THRLD, 0x40},
+
+               {TP6800_R79_QUALITY, 0x03},
+               {TP6800_R7A_BLK_THRLD, 0x40},
+
+               {TP6800_R2F_TIMING_CFG, 0x46},
+               {TP6800_R30_SENSOR_CFG, 0x10},  /* BG1..G0R */
+               {TP6800_R37_FRONT_DARK_ST, 0x00},
+               {TP6800_R38_FRONT_DARK_END, 0x00},
+               {TP6800_R39_REAR_DARK_ST_L, 0x00},
+               {TP6800_R3A_REAR_DARK_ST_H, 0x00},
+               {TP6800_R3B_REAR_DARK_END_L, 0x00},
+               {TP6800_R3C_REAR_DARK_END_H, 0x00},
+               {TP6800_R3D_HORIZ_DARK_LINE_L, 0x00},
+               {TP6800_R3E_HORIZ_DARK_LINE_H, 0x00},
+               {TP6800_R21_ENDP_1_CTL, 0x03},
+
+               {TP6800_R3F_FRAME_RATE, 0x04},  /* 15 fps */
+               {TP6800_R5D_DEMOSAIC_CFG, 0x0e}, /* scale down - medium edge */
+
+               {TP6800_R31_PIXEL_START, 0x1b},
+               {TP6800_R32_PIXEL_END_L, 0x9a},
+               {TP6800_R33_PIXEL_END_H, 0x02},
+               {TP6800_R34_LINE_START, 0x0f},
+               {TP6800_R35_LINE_END_L, 0xf4},
+               {TP6800_R36_LINE_END_H, 0x01},
+               {TP6800_R78_FORMAT, 0x01},      /* qvga */
+               {TP6800_R12_SIF_ADDR_S, 0x21},  /* soi763a i2c addr */
+               {TP6800_R1A_SIF_TX_DATA2, 0x00},
+       };
+       static const struct cmd sensor_init[] = {
+               {0x12, 0x48},           /* mirror - RGB */
+               {0x13, 0xa0},           /* clock - no AGC nor AEC */
+               {0x03, 0xa4},           /* saturation */
+               {0x04, 0x30},           /* hue */
+               {0x05, 0x88},           /* contrast */
+               {0x06, 0x60},           /* brightness */
+               {0x10, 0x41},           /* AEC */
+               {0x11, 0x40},           /* clock rate */
+               {0x13, 0xa0},
+               {0x14, 0x00},           /* 640x480 */
+               {0x15, 0x14},
+               {0x1f, 0x41},
+               {0x20, 0x80},
+               {0x23, 0xee},
+               {0x24, 0x50},
+               {0x25, 0x7a},
+               {0x26, 0x00},
+               {0x27, 0xe2},
+               {0x28, 0xb0},
+               {0x2a, 0x00},
+               {0x2b, 0x00},
+               {0x2d, 0x81},
+               {0x2f, 0x9d},
+               {0x60, 0x80},
+               {0x61, 0x00},
+               {0x62, 0x88},
+               {0x63, 0x11},
+               {0x64, 0x89},
+               {0x65, 0x00},
+               {0x67, 0x94},
+               {0x68, 0x7a},
+               {0x69, 0x0f},
+               {0x6c, 0x80},
+               {0x6d, 0x80},
+               {0x6e, 0x80},
+               {0x6f, 0xff},
+               {0x71, 0x20},
+               {0x74, 0x20},
+               {0x75, 0x86},
+               {0x77, 0xb5},
+               {0x17, 0x18},           /* H href start */
+               {0x18, 0xbf},           /* H href end */
+               {0x19, 0x03},           /* V start */
+               {0x1a, 0xf8},           /* V end */
+               {0x01, 0x80},           /* blue gain */
+               {0x02, 0x80},           /* red gain */
+       };
+
+       reg_w_buf(gspca_dev, reg_init, ARRAY_SIZE(reg_init));
+
+       i2c_w(gspca_dev, 0x12, 0x80);           /* sensor reset */
+       msleep(10);
+
+       i2c_w_buf(gspca_dev, sensor_init, ARRAY_SIZE(sensor_init));
+
+       reg_w(gspca_dev, TP6800_R5C_EDGE_THRLD, 0x10);
+       reg_w(gspca_dev, TP6800_R54_DARK_CFG, 0x00);
+
+       setsharpness(gspca_dev);
+
+       bulk_w(gspca_dev, 0x03, color_gain[SENSOR_SOI763A],
+                               ARRAY_SIZE(color_gain[0]));
+
+       set_led(gspca_dev, 1);
+       setexposure(gspca_dev);
+       setquality(gspca_dev);
+       setgamma(gspca_dev);
+}
+
+static void soi763a_6810_start(struct gspca_dev *gspca_dev)
+{
+       static const struct cmd bridge_init_2[] = {
+               {TP6800_R7A_BLK_THRLD, 0x00},
+               {TP6800_R79_QUALITY, 0x04},
+               {TP6800_R79_QUALITY, 0x01},
+       };
+       static const struct cmd bridge_init_3[] = {
+               {TP6800_R31_PIXEL_START, 0x20},
+               {TP6800_R32_PIXEL_END_L, 0x9f},
+               {TP6800_R33_PIXEL_END_H, 0x02},
+               {TP6800_R34_LINE_START, 0x13},
+               {TP6800_R35_LINE_END_L, 0xf8},
+               {TP6800_R36_LINE_END_H, 0x01},
+       };
+       static const struct cmd bridge_init_6[] = {
+               {0x08, 0xff},
+               {0x09, 0xff},
+               {0x0a, 0x5f},
+               {0x0b, 0x80},
+       };
+
+       reg_w(gspca_dev, 0x22, gspca_dev->alt);
+       bulk_w(gspca_dev, 0x03, color_null, sizeof color_null);
+       reg_w(gspca_dev, 0x59, 0x40);
+       setexposure(gspca_dev);
+       reg_w_buf(gspca_dev, bridge_init_2, ARRAY_SIZE(bridge_init_2));
+       reg_w_buf(gspca_dev, tp6810_ov_init_common,
+                       ARRAY_SIZE(tp6810_ov_init_common));
+       reg_w_buf(gspca_dev, bridge_init_3, ARRAY_SIZE(bridge_init_3));
+       if (gspca_dev->curr_mode) {
+               reg_w(gspca_dev, 0x4a, 0x7f);
+               reg_w(gspca_dev, 0x07, 0x05);
+               reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00);      /* vga */
+       } else {
+               reg_w(gspca_dev, 0x4a, 0xff);
+               reg_w(gspca_dev, 0x07, 0x85);
+               reg_w(gspca_dev, TP6800_R78_FORMAT, 0x01);      /* qvga */
+       }
+       setgamma(gspca_dev);
+       reg_w_buf(gspca_dev, tp6810_bridge_start,
+                       ARRAY_SIZE(tp6810_bridge_start));
+
+       if (gspca_dev->curr_mode) {
+               reg_w(gspca_dev, 0x4f, 0x00);
+               reg_w(gspca_dev, 0x4e, 0x7c);
+       }
+
+       reg_w(gspca_dev, 0x00, 0x00);
+
+       setsharpness(gspca_dev);
+       bulk_w(gspca_dev, 0x03, color_gain[SENSOR_SOI763A],
+                               ARRAY_SIZE(color_gain[0]));
+       set_led(gspca_dev, 1);
+       reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0xf0);
+       setexposure(gspca_dev);
+       reg_w_buf(gspca_dev, bridge_init_6, ARRAY_SIZE(bridge_init_6));
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width);
+       set_dqt(gspca_dev, sd->quality);
+       if (sd->bridge == BRIDGE_TP6800) {
+               if (sd->sensor == SENSOR_CX0342)
+                       cx0342_6800_start(gspca_dev);
+               else
+                       soi763a_6800_start(gspca_dev);
+       } else {
+               if (sd->sensor == SENSOR_CX0342)
+                       cx0342_6810_start(gspca_dev);
+               else
+                       soi763a_6810_start(gspca_dev);
+               reg_w_buf(gspca_dev, tp6810_late_start,
+                               ARRAY_SIZE(tp6810_late_start));
+               reg_w(gspca_dev, 0x80, 0x03);
+               reg_w(gspca_dev, 0x82, gspca_dev->curr_mode ? 0x0a : 0x0e);
+
+               setexposure(gspca_dev);
+               setquality(gspca_dev);
+               setautogain(gspca_dev);
+       }
+
+       setframerate(gspca_dev);
+
+       return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->bridge == BRIDGE_TP6800)
+               reg_w(gspca_dev, TP6800_R2F_TIMING_CFG, 0x03);
+       set_led(gspca_dev, 0);
+       reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x00);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       u8 *data,
+                       int len)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* the start of frame contains:
+        *      ff d8
+        *      ff fe
+        *      width / 16
+        *      height / 8
+        *      quality
+        */
+       if (sd->bridge == BRIDGE_TP6810) {
+               if (*data != 0x5a) {
+/*fixme: don't discard the whole frame..*/
+                       if (*data == 0xaa || *data == 0x00)
+                               return;
+                       if (*data > 0xc0) {
+                               PDEBUG(D_FRAM, "bad frame");
+                               gspca_dev->last_packet_type = DISCARD_PACKET;
+                               return;
+                       }
+               }
+               data++;
+               len--;
+               if (*data == 0xff && data[1] == 0xd8) {
+/*fixme: there may be information in the 4 high bits*/
+                       if ((data[6] & 0x0f) != sd->quality)
+                               set_dqt(gspca_dev, data[6] & 0x0f);
+                       gspca_frame_add(gspca_dev, FIRST_PACKET,
+                                       sd->jpeg_hdr, JPEG_HDR_SZ);
+                       gspca_frame_add(gspca_dev, INTER_PACKET,
+                                       data + 7, len - 7);
+               } else if (data[len - 2] == 0xff && data[len - 1] == 0xd9) {
+                       gspca_frame_add(gspca_dev, LAST_PACKET,
+                                       data, len);
+               } else {
+                       gspca_frame_add(gspca_dev, INTER_PACKET,
+                                       data, len);
+               }
+               return;
+       }
+
+       switch (*data) {
+       case 0x55:
+               gspca_frame_add(gspca_dev, LAST_PACKET, data, 0);
+
+               if (len < 8
+                || data[1] != 0xff || data[2] != 0xd8
+                || data[3] != 0xff || data[4] != 0xfe) {
+
+                       /* Have only seen this with corrupt frames */
+                       gspca_dev->last_packet_type = DISCARD_PACKET;
+                       return;
+               }
+               if (data[7] != sd->quality)
+                       set_dqt(gspca_dev, data[7]);
+               gspca_frame_add(gspca_dev, FIRST_PACKET,
+                               sd->jpeg_hdr, JPEG_HDR_SZ);
+               gspca_frame_add(gspca_dev, INTER_PACKET,
+                               data + 8, len - 8);
+               break;
+       case 0xaa:
+               gspca_dev->last_packet_type = DISCARD_PACKET;
+               break;
+       case 0xcc:
+               if (data[1] != 0xff || data[2] != 0xd8)
+                       gspca_frame_add(gspca_dev, INTER_PACKET,
+                                       data + 1, len - 1);
+               else
+                       gspca_dev->last_packet_type = DISCARD_PACKET;
+               break;
+       }
+}
+
+/* -- do autogain -- */
+/* gain setting is done in setexposure() for tp6810 */
+static void setgain(struct gspca_dev *gspca_dev) {}
+/* !! coarse_grained_expo_autogain is not used !! */
+#define exp_too_low_cnt bridge
+#define exp_too_high_cnt sensor
+
+#include "autogain_functions.h"
+static void sd_dq_callback(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int ret, alen;
+       int luma, expo;
+
+       if (sd->ag_cnt < 0)
+               return;
+       if (--sd->ag_cnt > 5)
+               return;
+       switch (sd->ag_cnt) {
+/*     case 5: */
+       default:
+               reg_w(gspca_dev, 0x7d, 0x00);
+               break;
+       case 4:
+               reg_w(gspca_dev, 0x27, 0xb0);
+               break;
+       case 3:
+               reg_w(gspca_dev, 0x0c, 0x01);
+               break;
+       case 2:
+               ret = usb_bulk_msg(gspca_dev->dev,
+                               usb_rcvbulkpipe(gspca_dev->dev, 0x02),
+                               gspca_dev->usb_buf,
+                               32,
+                               &alen,
+                               500);
+               if (ret < 0) {
+                       pr_err("bulk err %d\n", ret);
+                       break;
+               }
+               /* values not used (unknown) */
+               break;
+       case 1:
+               reg_w(gspca_dev, 0x27, 0xd0);
+               break;
+       case 0:
+               ret = usb_bulk_msg(gspca_dev->dev,
+                               usb_rcvbulkpipe(gspca_dev->dev, 0x02),
+                               gspca_dev->usb_buf,
+                               32,
+                               &alen,
+                               500);
+               if (ret < 0) {
+                       pr_err("bulk err %d\n", ret);
+                       break;
+               }
+               luma = ((gspca_dev->usb_buf[8] << 8) + gspca_dev->usb_buf[7] +
+                       (gspca_dev->usb_buf[11] << 8) + gspca_dev->usb_buf[10] +
+                       (gspca_dev->usb_buf[14] << 8) + gspca_dev->usb_buf[13] +
+                       (gspca_dev->usb_buf[17] << 8) + gspca_dev->usb_buf[16] +
+                       (gspca_dev->usb_buf[20] << 8) + gspca_dev->usb_buf[19] +
+                       (gspca_dev->usb_buf[23] << 8) + gspca_dev->usb_buf[22] +
+                       (gspca_dev->usb_buf[26] << 8) + gspca_dev->usb_buf[25] +
+                       (gspca_dev->usb_buf[29] << 8) + gspca_dev->usb_buf[28])
+                               / 8;
+               if (gspca_dev->width == 640)
+                       luma /= 4;
+               reg_w(gspca_dev, 0x7d, 0x00);
+
+               expo = sd->ctrls[EXPOSURE].val;
+               ret = auto_gain_n_exposure(gspca_dev, luma,
+                               60,     /* desired luma */
+                               6,      /* dead zone */
+                               2,      /* gain knee */
+                               70);    /* expo knee */
+               sd->ag_cnt = AG_CNT_START;
+               if (sd->bridge == BRIDGE_TP6810) {
+                       if ((expo >= 128 && sd->ctrls[EXPOSURE].val < 128)
+                        || (expo < 128 && sd->ctrls[EXPOSURE].val >= 128))
+                               setframerate(gspca_dev);
+               }
+               break;
+       }
+}
+
+/* get stream parameters (framerate) */
+static void sd_get_streamparm(struct gspca_dev *gspca_dev,
+                            struct v4l2_streamparm *parm)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct v4l2_captureparm *cp = &parm->parm.capture;
+       struct v4l2_fract *tpf = &cp->timeperframe;
+       int fr, i;
+
+       cp->capability |= V4L2_CAP_TIMEPERFRAME;
+       tpf->numerator = 1;
+       i = get_fr_idx(gspca_dev);
+       if (i & 0x80) {
+               if (sd->bridge == BRIDGE_TP6800)
+                       fr = rates[6 - (i & 0x07)];
+               else
+                       fr = rates_6810[7 - (i & 0x07)];
+       } else {
+               fr = rates[6 - i];
+       }
+       tpf->denominator = fr;
+}
+
+/* set stream parameters (framerate) */
+static void sd_set_streamparm(struct gspca_dev *gspca_dev,
+                            struct v4l2_streamparm *parm)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct v4l2_captureparm *cp = &parm->parm.capture;
+       struct v4l2_fract *tpf = &cp->timeperframe;
+       int fr, i;
+
+       sd->framerate = tpf->denominator / tpf->numerator;
+       if (gspca_dev->streaming)
+               setframerate(gspca_dev);
+
+       /* Return the actual framerate */
+       i = get_fr_idx(gspca_dev);
+       if (i & 0x80)
+               fr = rates_6810[7 - (i & 0x07)];
+       else
+               fr = rates[6 - i];
+       tpf->numerator = 1;
+       tpf->denominator = fr;
+}
+
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->sensor == SENSOR_SOI763A)
+               jpeg_set_qual(sd->jpeg_hdr, jcomp->quality);
+/*     else
+               fixme: TODO
+*/
+       return gspca_dev->usb_err;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       memset(jcomp, 0, sizeof *jcomp);
+       jcomp->quality = jpeg_q[sd->quality];
+       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+                       | V4L2_JPEG_MARKER_DQT;
+       return 0;
+}
+
+static struct ctrl sd_ctrls[NCTRLS] = {
+[EXPOSURE] = {
+           {
+               .id = V4L2_CID_EXPOSURE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Exposure",
+               .minimum = 0x01,
+               .maximum = 0xdc,
+               .step = 1,
+               .default_value = 0x4e,
+           },
+           .set_control = setexposure
+       },
+[QUALITY] = {
+           {
+               .id = V4L2_CID_PRIVATE_BASE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Compression quality",
+               .minimum = 0,
+               .maximum = 15,
+               .step = 1,
+               .default_value = 13,
+           },
+           .set_control = setquality
+       },
+[RGAIN] = {
+           {
+               .id = V4L2_CID_RED_BALANCE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Red balance",
+               .minimum = 0,
+               .maximum = 4095,
+               .step = 1,
+               .default_value = 256,
+           },
+           .set_control = setrgain
+       },
+[GAIN] = {
+           {
+               .id = V4L2_CID_GAIN,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Gain",
+               .minimum = 0,
+               .maximum = 4095,
+               .step = 1,
+               .default_value = 256,
+           },
+           .set = sd_setgain
+       },
+[BGAIN] = {
+           {
+               .id = V4L2_CID_BLUE_BALANCE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Blue balance",
+               .minimum = 0,
+               .maximum = 4095,
+               .step = 1,
+               .default_value = 256,
+           },
+           .set_control = setbgain
+       },
+[SHARPNESS] = {
+           {
+               .id      = V4L2_CID_SHARPNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Sharpness",
+               .minimum = 0,
+               .maximum = 3,
+               .step    = 1,
+               .default_value = 2,
+           },
+           .set_control = setsharpness
+       },
+[GAMMA] = {
+           {
+               .id      = V4L2_CID_GAMMA,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gamma",
+               .minimum = 0,
+               .maximum = NGAMMA - 1,
+               .step    = 1,
+               .default_value = 1,
+           },
+           .set_control = setgamma
+       },
+[AUTOGAIN] = {
+           {
+               .id      = V4L2_CID_AUTOGAIN,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Auto Gain",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+               .default_value = AUTOGAIN_DEF
+           },
+           .set_control = setautogain
+       },
+};
+
+static const struct sd_desc sd_desc = {
+       .name = KBUILD_MODNAME,
+       .ctrls = sd_ctrls,
+       .nctrls = NCTRLS,
+       .config = sd_config,
+       .init = sd_init,
+       .isoc_init = sd_isoc_init,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .pkt_scan = sd_pkt_scan,
+       .dq_callback = sd_dq_callback,
+       .get_streamparm = sd_get_streamparm,
+       .set_streamparm = sd_set_streamparm,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
+};
+
+static const struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x06a2, 0x0003), .driver_info = BRIDGE_TP6800},
+       {USB_DEVICE(0x06a2, 0x6810), .driver_info = BRIDGE_TP6810},
+       {}                      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+static int sd_probe(struct usb_interface *interface,
+                   const struct usb_device_id *id)
+{
+       return gspca_dev_probe(interface, id, &sd_desc, sizeof(struct sd),
+                              THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+       .reset_resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       return usb_register(&sd_driver);
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param(force_sensor, int, 0644);
+MODULE_PARM_DESC(force_sensor,
+       "Force sensor. 0: cx0342, 1: soi763a");
index 6caed73..7ee2c82 100644 (file)
@@ -20,6 +20,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "vc032x"
 
 #include "gspca.h"
@@ -3169,7 +3171,7 @@ static void reg_r_i(struct gspca_dev *gspca_dev,
                        index, gspca_dev->usb_buf, len,
                        500);
        if (ret < 0) {
-               err("reg_r err %d", ret);
+               pr_err("reg_r err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -3210,7 +3212,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev,
                        value, index, NULL, 0,
                        500);
        if (ret < 0) {
-               err("reg_w err %d", ret);
+               pr_err("reg_w err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -3235,8 +3237,7 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
 
        reg_r(gspca_dev, 0xa1, 0xb33f, 1);
        if (!(gspca_dev->usb_buf[0] & 0x02)) {
-               err("I2c Bus Busy Wait %02x",
-                       gspca_dev->usb_buf[0]);
+               pr_err("I2c Bus Busy Wait %02x\n", gspca_dev->usb_buf[0]);
                return 0;
        }
        reg_w(gspca_dev, 0xa0, address, 0xb33a);
@@ -3349,7 +3350,7 @@ static void i2c_write(struct gspca_dev *gspca_dev,
                msleep(20);
        } while (--retry > 0);
        if (retry <= 0)
-               err("i2c_write timeout");
+               pr_err("i2c_write timeout\n");
 }
 
 static void put_tab_to_reg(struct gspca_dev *gspca_dev,
@@ -3446,7 +3447,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 
        switch (sensor) {
        case -1:
-               err("Unknown sensor...");
+               pr_err("Unknown sensor...\n");
                return -EINVAL;
        case SENSOR_HV7131R:
                PDEBUG(D_PROBE, "Find Sensor HV7131R");
index 84dfbab..81dd4c9 100644 (file)
@@ -26,6 +26,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "vicam"
 #define HEADER_SIZE 64
 
@@ -117,7 +119,7 @@ static int vicam_control_msg(struct gspca_dev *gspca_dev, u8 request,
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              value, index, data, len, 1000);
        if (ret < 0)
-               err("control msg req %02X error %d", request, ret);
+               pr_err("control msg req %02X error %d\n", request, ret);
 
        return ret;
 }
@@ -189,8 +191,8 @@ static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size)
                           data, size, &act_len, 10000);
        /* successful, it returns 0, otherwise  negative */
        if (ret < 0 || act_len != size) {
-               err("bulk read fail (%d) len %d/%d",
-                       ret, act_len, size);
+               pr_err("bulk read fail (%d) len %d/%d\n",
+                      ret, act_len, size);
                return -EIO;
        }
        return 0;
@@ -216,7 +218,7 @@ static void vicam_dostream(struct work_struct *work)
                   HEADER_SIZE;
        buffer = kmalloc(frame_sz, GFP_KERNEL | GFP_DMA);
        if (!buffer) {
-               err("Couldn't allocate USB buffer");
+               pr_err("Couldn't allocate USB buffer\n");
                goto exit;
        }
 
@@ -269,7 +271,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        ret = request_ihex_firmware(&fw, "vicam/firmware.fw",
                                    &gspca_dev->dev->dev);
        if (ret) {
-               err("Failed to load \"vicam/firmware.fw\": %d\n", ret);
+               pr_err("Failed to load \"vicam/firmware.fw\": %d\n", ret);
                return ret;
        }
 
index 4a9e622..27d2cef 100644 (file)
@@ -31,6 +31,8 @@
    the sensor drivers to v4l2 sub drivers, and properly split of this
    driver from ov519.c */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define W9968CF_I2C_BUS_DELAY    4 /* delay in us for I2C bit r/w operations */
 
 #define Y_QUANTABLE (&sd->jpeg_hdr[JPEG_QT0_OFFSET])
@@ -81,7 +83,7 @@ static void w9968cf_write_fsb(struct sd *sd, u16* data)
                              USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
                              value, 0x06, sd->gspca_dev.usb_buf, 6, 500);
        if (ret < 0) {
-               err("Write FSB registers failed (%d)", ret);
+               pr_err("Write FSB registers failed (%d)\n", ret);
                sd->gspca_dev.usb_err = ret;
        }
 }
@@ -108,7 +110,7 @@ static void w9968cf_write_sb(struct sd *sd, u16 value)
        udelay(W9968CF_I2C_BUS_DELAY);
 
        if (ret < 0) {
-               err("Write SB reg [01] %04x failed", value);
+               pr_err("Write SB reg [01] %04x failed\n", value);
                sd->gspca_dev.usb_err = ret;
        }
 }
@@ -135,7 +137,7 @@ static int w9968cf_read_sb(struct sd *sd)
                ret = sd->gspca_dev.usb_buf[0] |
                      (sd->gspca_dev.usb_buf[1] << 8);
        } else {
-               err("Read SB reg [01] failed");
+               pr_err("Read SB reg [01] failed\n");
                sd->gspca_dev.usb_err = ret;
        }
 
index c089a0f..3aed42a 100644 (file)
@@ -27,6 +27,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "xirlink-cit"
 
 #include <linux/input.h>
@@ -800,8 +802,8 @@ static int cit_write_reg(struct gspca_dev *gspca_dev, u16 value, u16 index)
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
                        value, index, NULL, 0, 1000);
        if (err < 0)
-               err("Failed to write a register (index 0x%04X,"
-                       " value 0x%02X, error %d)", index, value, err);
+               pr_err("Failed to write a register (index 0x%04X, value 0x%02X, error %d)\n",
+                      index, value, err);
 
        return 0;
 }
@@ -816,8 +818,8 @@ static int cit_read_reg(struct gspca_dev *gspca_dev, u16 index, int verbose)
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
                        0x00, index, buf, 8, 1000);
        if (res < 0) {
-               err("Failed to read a register (index 0x%04X, error %d)",
-                       index, res);
+               pr_err("Failed to read a register (index 0x%04X, error %d)\n",
+                      index, res);
                return res;
        }
 
@@ -1587,7 +1589,7 @@ static int cit_get_packet_size(struct gspca_dev *gspca_dev)
        intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
        alt = usb_altnum_to_altsetting(intf, gspca_dev->alt);
        if (!alt) {
-               err("Couldn't get altsetting");
+               pr_err("Couldn't get altsetting\n");
                return -EIO;
        }
 
@@ -2824,7 +2826,7 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev)
 
        ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
        if (ret < 0)
-               err("set alt 1 err %d", ret);
+               pr_err("set alt 1 err %d\n", ret);
 
        return ret;
 }
index 61cdd56..30ea1e4 100644 (file)
@@ -19,6 +19,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MODULE_NAME "zc3xx"
 
 #include <linux/input.h>
@@ -5666,7 +5668,7 @@ static u8 reg_r_i(struct gspca_dev *gspca_dev,
                        index, gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               err("reg_r_i err %d", ret);
+               pr_err("reg_r_i err %d\n", ret);
                gspca_dev->usb_err = ret;
                return 0;
        }
@@ -5698,7 +5700,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev,
                        value, index, NULL, 0,
                        500);
        if (ret < 0) {
-               err("reg_w_i err %d", ret);
+               pr_err("reg_w_i err %d\n", ret);
                gspca_dev->usb_err = ret;
        }
 }
@@ -5724,7 +5726,7 @@ static u16 i2c_read(struct gspca_dev *gspca_dev,
        msleep(20);
        retbyte = reg_r_i(gspca_dev, 0x0091);           /* read status */
        if (retbyte != 0x00)
-               err("i2c_r status error %02x", retbyte);
+               pr_err("i2c_r status error %02x\n", retbyte);
        retval = reg_r_i(gspca_dev, 0x0095);            /* read Lowbyte */
        retval |= reg_r_i(gspca_dev, 0x0096) << 8;      /* read Hightbyte */
        PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)",
@@ -5748,7 +5750,7 @@ static u8 i2c_write(struct gspca_dev *gspca_dev,
        msleep(1);
        retbyte = reg_r_i(gspca_dev, 0x0091);           /* read status */
        if (retbyte != 0x00)
-               err("i2c_w status error %02x", retbyte);
+               pr_err("i2c_w status error %02x\n", retbyte);
        PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)",
                        reg, valH, valL, retbyte);
        return retbyte;
@@ -6497,7 +6499,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                                PDEBUG(D_PROBE, "Sensor GC0303");
                                break;
                        default:
-                               warn("Unknown sensor - set to TAS5130C");
+                               pr_warn("Unknown sensor - set to TAS5130C\n");
                                sd->sensor = SENSOR_TAS5130C;
                        }
                        break;
@@ -6603,7 +6605,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        sd->sensor = SENSOR_OV7620;     /* same sensor (?) */
                        break;
                default:
-                       err("Unknown sensor %04x", sensor);
+                       pr_err("Unknown sensor %04x\n", sensor);
                        return -EINVAL;
                }
        }
@@ -6970,6 +6972,7 @@ static const struct sd_desc sd_desc = {
 };
 
 static const struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x03f0, 0x1b07)},
        {USB_DEVICE(0x041e, 0x041e)},
        {USB_DEVICE(0x041e, 0x4017)},
        {USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106},
index 3baa9f6..52f057f 100644 (file)
@@ -2,6 +2,6 @@ hdpvr-objs      := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o
 
 obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
+ccflags-y += -Idrivers/media/video
 
-EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
index cbc505a..9cb039e 100644 (file)
@@ -21,6 +21,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define DEBUG_VARIABLE debug
 
 #include <media/saa7146_vv.h>
@@ -175,13 +177,14 @@ static int hexium_init_done(struct saa7146_dev *dev)
        union i2c_smbus_data data;
        int i = 0;
 
-       DEB_D(("hexium_init_done called.\n"));
+       DEB_D("hexium_init_done called\n");
 
        /* initialize the helper ics to useful values */
        for (i = 0; i < sizeof(hexium_ks0127b); i++) {
                data.byte = hexium_ks0127b[i];
                if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
-                       printk("hexium_gemini: hexium_init_done() failed for address 0x%02x\n", i);
+                       pr_err("hexium_init_done() failed for address 0x%02x\n",
+                              i);
                }
        }
 
@@ -192,7 +195,7 @@ static int hexium_set_input(struct hexium *hexium, int input)
 {
        union i2c_smbus_data data;
 
-       DEB_D((".\n"));
+       DEB_D("\n");
 
        data.byte = hexium_input_select[input].byte;
        if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
@@ -207,12 +210,13 @@ static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
        union i2c_smbus_data data;
        int i = 0;
 
-       DEB_D((".\n"));
+       DEB_D("\n");
 
        while (vdec[i].adr != -1) {
                data.byte = vdec[i].byte;
                if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
-                       printk("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n", i);
+                       pr_err("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n",
+                              i);
                        return -1;
                }
                i++;
@@ -222,14 +226,14 @@ static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
 
 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
-       DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
+       DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
 
        if (i->index >= HEXIUM_INPUTS)
                return -EINVAL;
 
        memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
 
-       DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
+       DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
        return 0;
 }
 
@@ -240,7 +244,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
 
        *input = hexium->cur_input;
 
-       DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
+       DEB_D("VIDIOC_G_INPUT: %d\n", *input);
        return 0;
 }
 
@@ -249,7 +253,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 
-       DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
+       DEB_EE("VIDIOC_S_INPUT %d\n", input);
 
        if (input >= HEXIUM_INPUTS)
                return -EINVAL;
@@ -270,7 +274,7 @@ static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *
        for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
                if (hexium_controls[i].id == qc->id) {
                        *qc = hexium_controls[i];
-                       DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
+                       DEB_D("VIDIOC_QUERYCTRL %d\n", qc->id);
                        return 0;
                }
        }
@@ -293,7 +297,7 @@ static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
 
        if (vc->id == V4L2_CID_PRIVATE_BASE) {
                vc->value = hexium->cur_bw;
-               DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
+               DEB_D("VIDIOC_G_CTRL BW:%d\n", vc->value);
                return 0;
        }
        return -EINVAL;
@@ -316,7 +320,7 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
        if (vc->id == V4L2_CID_PRIVATE_BASE)
                hexium->cur_bw = vc->value;
 
-       DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
+       DEB_D("VIDIOC_S_CTRL BW:%d\n", hexium->cur_bw);
 
        if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
                hexium_set_standard(hexium, hexium_pal);
@@ -351,14 +355,14 @@ static struct saa7146_ext_vv vv_data;
 /* this function only gets called when the probing was successful */
 static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 {
-       struct hexium *hexium = (struct hexium *) dev->ext_priv;
+       struct hexium *hexium;
        int ret;
 
-       DEB_EE((".\n"));
+       DEB_EE("\n");
 
        hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
        if (NULL == hexium) {
-               printk("hexium_gemini: not enough kernel memory in hexium_attach().\n");
+               pr_err("not enough kernel memory in hexium_attach()\n");
                return -ENOMEM;
        }
        dev->ext_priv = hexium;
@@ -371,7 +375,7 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
        };
        saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
        if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
-               DEB_S(("cannot register i2c-device. skipping.\n"));
+               DEB_S("cannot register i2c-device. skipping.\n");
                kfree(hexium);
                return -EFAULT;
        }
@@ -402,11 +406,11 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
        vv_data.ops.vidioc_s_input = vidioc_s_input;
        ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
        if (ret < 0) {
-               printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
+               pr_err("cannot register capture v4l2 device. skipping.\n");
                return ret;
        }
 
-       printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num);
+       pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num);
        hexium_num++;
 
        return 0;
@@ -416,7 +420,7 @@ static int hexium_detach(struct saa7146_dev *dev)
 {
        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 
-       DEB_EE(("dev:%p\n", dev));
+       DEB_EE("dev:%p\n", dev);
 
        saa7146_unregister_device(&hexium->video_dev, dev);
        saa7146_vv_release(dev);
@@ -508,7 +512,7 @@ static struct saa7146_extension hexium_extension = {
 static int __init hexium_init_module(void)
 {
        if (0 != saa7146_register_extension(&hexium_extension)) {
-               DEB_S(("failed to register extension.\n"));
+               DEB_S("failed to register extension\n");
                return -ENODEV;
        }
 
index 6ad7e1c..74861a4 100644 (file)
@@ -21,6 +21,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define DEBUG_VARIABLE debug
 
 #include <media/saa7146_vv.h>
@@ -209,7 +211,7 @@ static int hexium_probe(struct saa7146_dev *dev)
        union i2c_smbus_data data;
        int err = 0;
 
-       DEB_EE((".\n"));
+       DEB_EE("\n");
 
        /* there are no hexium orion cards with revision 0 saa7146s */
        if (0 == dev->revision) {
@@ -218,7 +220,7 @@ static int hexium_probe(struct saa7146_dev *dev)
 
        hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
        if (NULL == hexium) {
-               printk("hexium_orion: hexium_probe: not enough kernel memory.\n");
+               pr_err("hexium_probe: not enough kernel memory\n");
                return -ENOMEM;
        }
 
@@ -234,7 +236,7 @@ static int hexium_probe(struct saa7146_dev *dev)
        };
        saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
        if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
-               DEB_S(("cannot register i2c-device. skipping.\n"));
+               DEB_S("cannot register i2c-device. skipping.\n");
                kfree(hexium);
                return -EFAULT;
        }
@@ -248,7 +250,7 @@ static int hexium_probe(struct saa7146_dev *dev)
 
        /* detect newer Hexium Orion cards by subsystem ids */
        if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {
-               printk("hexium_orion: device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs.\n");
+               pr_info("device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs\n");
                /* we store the pointer in our private data field */
                dev->ext_priv = hexium;
                hexium->type = HEXIUM_ORION_1SVHS_3BNC;
@@ -256,7 +258,7 @@ static int hexium_probe(struct saa7146_dev *dev)
        }
 
        if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {
-               printk("hexium_orion: device is a Hexium Orion w/ 4 BNC inputs.\n");
+               pr_info("device is a Hexium Orion w/ 4 BNC inputs\n");
                /* we store the pointer in our private data field */
                dev->ext_priv = hexium;
                hexium->type = HEXIUM_ORION_4BNC;
@@ -266,7 +268,7 @@ static int hexium_probe(struct saa7146_dev *dev)
        /* check if this is an old hexium Orion card by looking at
           a saa7110 at address 0x4e */
        if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
-               printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n");
+               pr_info("device is a Hexium HV-PCI6/Orion (old)\n");
                /* we store the pointer in our private data field */
                dev->ext_priv = hexium;
                hexium->type = HEXIUM_HV_PCI6_ORION;
@@ -288,13 +290,13 @@ static int hexium_init_done(struct saa7146_dev *dev)
        union i2c_smbus_data data;
        int i = 0;
 
-       DEB_D(("hexium_init_done called.\n"));
+       DEB_D("hexium_init_done called\n");
 
        /* initialize the helper ics to useful values */
        for (i = 0; i < sizeof(hexium_saa7110); i++) {
                data.byte = hexium_saa7110[i];
                if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
-                       printk("hexium_orion: failed for address 0x%02x\n", i);
+                       pr_err("failed for address 0x%02x\n", i);
                }
        }
 
@@ -306,7 +308,7 @@ static int hexium_set_input(struct hexium *hexium, int input)
        union i2c_smbus_data data;
        int i = 0;
 
-       DEB_D((".\n"));
+       DEB_D("\n");
 
        for (i = 0; i < 8; i++) {
                int adr = hexium_input_select[input].data[i].adr;
@@ -314,7 +316,7 @@ static int hexium_set_input(struct hexium *hexium, int input)
                if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {
                        return -1;
                }
-               printk("%d: 0x%02x => 0x%02x\n",input, adr,data.byte);
+               pr_debug("%d: 0x%02x => 0x%02x\n", input, adr, data.byte);
        }
 
        return 0;
@@ -322,14 +324,14 @@ static int hexium_set_input(struct hexium *hexium, int input)
 
 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
-       DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
+       DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
 
        if (i->index >= HEXIUM_INPUTS)
                return -EINVAL;
 
        memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
 
-       DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
+       DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
        return 0;
 }
 
@@ -340,7 +342,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
 
        *input = hexium->cur_input;
 
-       DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
+       DEB_D("VIDIOC_G_INPUT: %d\n", *input);
        return 0;
 }
 
@@ -365,18 +367,18 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
 {
        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 
-       DEB_EE((".\n"));
+       DEB_EE("\n");
 
        saa7146_vv_init(dev, &vv_data);
        vv_data.ops.vidioc_enum_input = vidioc_enum_input;
        vv_data.ops.vidioc_g_input = vidioc_g_input;
        vv_data.ops.vidioc_s_input = vidioc_s_input;
        if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
-               printk("hexium_orion: cannot register capture v4l2 device. skipping.\n");
+               pr_err("cannot register capture v4l2 device. skipping.\n");
                return -1;
        }
 
-       printk("hexium_orion: found 'hexium orion' frame grabber-%d.\n", hexium_num);
+       pr_err("found 'hexium orion' frame grabber-%d\n", hexium_num);
        hexium_num++;
 
        /* the rest */
@@ -390,7 +392,7 @@ static int hexium_detach(struct saa7146_dev *dev)
 {
        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 
-       DEB_EE(("dev:%p\n", dev));
+       DEB_EE("dev:%p\n", dev);
 
        saa7146_unregister_device(&hexium->video_dev, dev);
        saa7146_vv_release(dev);
@@ -479,7 +481,7 @@ static struct saa7146_extension extension = {
 static int __init hexium_init_module(void)
 {
        if (0 != saa7146_register_extension(&extension)) {
-               DEB_S(("failed to register extension.\n"));
+               DEB_S("failed to register extension\n");
                return -ENODEV;
        }
 
index 26ce0d6..71ab76a 100644 (file)
@@ -7,8 +7,8 @@ ivtv-objs       := ivtv-routing.o ivtv-cards.o ivtv-controls.o \
 obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
 obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/video
+ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
 
index 3e5c090..ecafa69 100644 (file)
@@ -1203,9 +1203,7 @@ static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced
                                        cap->service_lines[f][l] = set;
                        }
                }
-               return 0;
-       }
-       if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
+       } else if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
                if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
                        return -EINVAL;
                if (itv->is_60hz) {
@@ -1215,9 +1213,16 @@ static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced
                        cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
                        cap->service_lines[0][16] = V4L2_SLICED_VPS;
                }
-               return 0;
+       } else {
+               return -EINVAL;
        }
-       return -EINVAL;
+
+       set = 0;
+       for (f = 0; f < 2; f++)
+               for (l = 0; l < 24; l++)
+                       set |= cap->service_lines[f][l];
+       cap->service_set = set;
+       return 0;
 }
 
 static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx)
index fb8e4a7..5d21d05 100644 (file)
@@ -936,7 +936,7 @@ static int __devinit m5mols_probe(struct i2c_client *client,
                return -EINVAL;
        }
 
-       if (!pdata->irq) {
+       if (!client->irq) {
                dev_err(&client->dev, "Interrupt not assigned\n");
                return -EINVAL;
        }
@@ -973,7 +973,7 @@ static int __devinit m5mols_probe(struct i2c_client *client,
 
        init_waitqueue_head(&info->irq_waitq);
        INIT_WORK(&info->work_irq, m5mols_irq_work);
-       ret = request_irq(pdata->irq, m5mols_irq_handler,
+       ret = request_irq(client->irq, m5mols_irq_handler,
                          IRQF_TRIGGER_RISING, MODULE_NAME, sd);
        if (ret) {
                dev_err(&client->dev, "Interrupt request failed: %d\n", ret);
@@ -998,7 +998,7 @@ static int __devexit m5mols_remove(struct i2c_client *client)
        struct m5mols_info *info = to_m5mols(sd);
 
        v4l2_device_unregister_subdev(sd);
-       free_irq(info->pdata->irq, sd);
+       free_irq(client->irq, sd);
 
        regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
        gpio_free(info->pdata->gpio_reset);
index 83c1451..1141b97 100644 (file)
@@ -450,7 +450,7 @@ static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame)
                buf = cam->vb_bufs[frame ^ 0x1];
                cam->vb_bufs[frame] = buf;
                mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
-                               vb2_dma_contig_plane_paddr(&buf->vb_buf, 0));
+                               vb2_dma_contig_plane_dma_addr(&buf->vb_buf, 0));
                set_bit(CF_SINGLE_BUFFER, &cam->flags);
                singles++;
                return;
@@ -461,7 +461,7 @@ static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame)
        buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
        list_del_init(&buf->queue);
        mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
-                       vb2_dma_contig_plane_paddr(&buf->vb_buf, 0));
+                       vb2_dma_contig_plane_dma_addr(&buf->vb_buf, 0));
        cam->vb_bufs[frame] = buf;
        clear_bit(CF_SINGLE_BUFFER, &cam->flags);
 }
@@ -884,7 +884,7 @@ static int mcam_read_setup(struct mcam_camera *cam)
  */
 
 static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
-               unsigned int *num_planes, unsigned long sizes[],
+               unsigned int *num_planes, unsigned int sizes[],
                void *alloc_ctxs[])
 {
        struct mcam_camera *cam = vb2_get_drv_priv(vq);
@@ -940,12 +940,14 @@ static void mcam_vb_wait_finish(struct vb2_queue *vq)
 /*
  * These need to be called with the mutex held from vb2
  */
-static int mcam_vb_start_streaming(struct vb2_queue *vq)
+static int mcam_vb_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct mcam_camera *cam = vb2_get_drv_priv(vq);
 
-       if (cam->state != S_IDLE)
+       if (cam->state != S_IDLE) {
+               INIT_LIST_HEAD(&cam->buffers);
                return -EINVAL;
+       }
        cam->sequence = 0;
        /*
         * Videobuf2 sneakily hoards all the buffers and won't
index d6b7645..fb0b124 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "mcam-core.h"
 
+MODULE_ALIAS("platform:mmp-camera");
 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
 MODULE_LICENSE("GPL");
 
index 166bf93..9594b52 100644 (file)
@@ -739,7 +739,7 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = {
  */
 
 static int m2mtest_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
-                               unsigned int *nplanes, unsigned long sizes[],
+                               unsigned int *nplanes, unsigned int sizes[],
                                void *alloc_ctxs[])
 {
        struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq);
@@ -793,10 +793,24 @@ static void m2mtest_buf_queue(struct vb2_buffer *vb)
        v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
 }
 
+static void m2mtest_wait_prepare(struct vb2_queue *q)
+{
+       struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
+       m2mtest_unlock(ctx);
+}
+
+static void m2mtest_wait_finish(struct vb2_queue *q)
+{
+       struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
+       m2mtest_lock(ctx);
+}
+
 static struct vb2_ops m2mtest_qops = {
        .queue_setup     = m2mtest_queue_setup,
        .buf_prepare     = m2mtest_buf_prepare,
        .buf_queue       = m2mtest_buf_queue,
+       .wait_prepare    = m2mtest_wait_prepare,
+       .wait_finish     = m2mtest_wait_finish,
 };
 
 static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
index c43c81f..d0f5388 100644 (file)
@@ -426,6 +426,20 @@ static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
        return 0;
 }
 
+static int msp_querystd(struct v4l2_subdev *sd, v4l2_std_id *id)
+{
+       struct msp_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       *id &= state->detected_std;
+
+       v4l_dbg(2, msp_debug, client,
+               "detected standard: %s(0x%08Lx)\n",
+               msp_standard_std_name(state->std), state->detected_std);
+
+       return 0;
+}
+
 static int msp_s_std(struct v4l2_subdev *sd, v4l2_std_id id)
 {
        struct msp_state *state = to_state(sd);
@@ -616,6 +630,10 @@ static const struct v4l2_subdev_core_ops msp_core_ops = {
        .s_std = msp_s_std,
 };
 
+static const struct v4l2_subdev_video_ops msp_video_ops = {
+       .querystd = msp_querystd,
+};
+
 static const struct v4l2_subdev_tuner_ops msp_tuner_ops = {
        .s_frequency = msp_s_frequency,
        .g_tuner = msp_g_tuner,
@@ -630,6 +648,7 @@ static const struct v4l2_subdev_audio_ops msp_audio_ops = {
 
 static const struct v4l2_subdev_ops msp_ops = {
        .core = &msp_core_ops,
+       .video = &msp_video_ops,
        .tuner = &msp_tuner_ops,
        .audio = &msp_audio_ops,
 };
@@ -664,6 +683,7 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
        v4l2_i2c_subdev_init(sd, client, &msp_ops);
 
        state->v4l2_std = V4L2_STD_NTSC;
+       state->detected_std = V4L2_STD_ALL;
        state->audmode = V4L2_TUNER_MODE_STEREO;
        state->input = -1;
        state->i2s_mode = 0;
index 32a478e..831e8db 100644 (file)
@@ -75,7 +75,7 @@ struct msp_state {
        int opmode;
        int std;
        int mode;
-       v4l2_std_id v4l2_std;
+       v4l2_std_id v4l2_std, detected_std;
        int nicam_on;
        int acb;
        int in_scart;
index 80387e2..f8b5171 100644 (file)
@@ -37,29 +37,49 @@ static struct {
        int retval;
        int main, second;
        char *name;
+       v4l2_std_id std;
 } msp_stdlist[] = {
-       { 0x0000, 0, 0, "could not detect sound standard" },
-       { 0x0001, 0, 0, "autodetect start" },
-       { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72  M Dual FM-Stereo" },
-       { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74  B/G Dual FM-Stereo" },
-       { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25  D/K1 Dual FM-Stereo" },
-       { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74  D/K2 Dual FM-Stereo" },
-       { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  D/K FM-Mono (HDEV3)" },
-       { 0x0007, MSP_CARRIER(6.5), MSP_CARRIER(5.7421875), "6.5/5.74  D/K3 Dual FM-Stereo" },
-       { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85  B/G NICAM FM" },
-       { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  L NICAM AM" },
-       { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55  I NICAM FM" },
-       { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM" },
-       { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM (HDEV2)" },
-       { 0x000d, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM (HDEV3)" },
-       { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Stereo" },
-       { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Mono + SAP" },
-       { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M EIA-J Japan Stereo" },
-       { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7  FM-Stereo Radio" },
-       { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  SAT-Mono" },
-       { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20  SAT-Stereo" },
-       { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2  SAT ADR" },
-       {     -1, 0, 0, NULL }, /* EOF */
+       { 0x0000, 0, 0, "could not detect sound standard", V4L2_STD_ALL },
+       { 0x0001, 0, 0, "autodetect start", V4L2_STD_ALL },
+       { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72),
+         "4.5/4.72  M Dual FM-Stereo", V4L2_STD_MN },
+       { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875),
+         "5.5/5.74  B/G Dual FM-Stereo", V4L2_STD_BG },
+       { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125),
+         "6.5/6.25  D/K1 Dual FM-Stereo", V4L2_STD_DK },
+       { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875),
+         "6.5/6.74  D/K2 Dual FM-Stereo", V4L2_STD_DK },
+       { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+         "6.5  D/K FM-Mono (HDEV3)", V4L2_STD_DK },
+       { 0x0007, MSP_CARRIER(6.5), MSP_CARRIER(5.7421875),
+         "6.5/5.74  D/K3 Dual FM-Stereo", V4L2_STD_DK },
+       { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85),
+         "5.5/5.85  B/G NICAM FM", V4L2_STD_BG },
+       { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85),
+         "6.5/5.85  L NICAM AM", V4L2_STD_L },
+       { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55),
+         "6.0/6.55  I NICAM FM", V4L2_STD_PAL_I },
+       { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85),
+         "6.5/5.85  D/K NICAM FM", V4L2_STD_DK },
+       { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85),
+         "6.5/5.85  D/K NICAM FM (HDEV2)", V4L2_STD_DK },
+       { 0x000d, MSP_CARRIER(6.5), MSP_CARRIER(5.85),
+         "6.5/5.85  D/K NICAM FM (HDEV3)", V4L2_STD_DK },
+       { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5),
+         "4.5  M BTSC-Stereo", V4L2_STD_MTS },
+       { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5),
+         "4.5  M BTSC-Mono + SAP", V4L2_STD_MTS },
+       { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5),
+         "4.5  M EIA-J Japan Stereo", V4L2_STD_NTSC_M_JP },
+       { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7),
+         "10.7  FM-Stereo Radio", V4L2_STD_ALL },
+       { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+         "6.5  SAT-Mono", V4L2_STD_ALL },
+       { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20),
+         "7.02/7.20  SAT-Stereo", V4L2_STD_ALL },
+       { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2),
+         "7.2  SAT ADR", V4L2_STD_ALL },
+       {     -1, 0, 0, NULL, 0 }, /* EOF */
 };
 
 static struct msp3400c_init_data_dem {
@@ -156,6 +176,16 @@ const char *msp_standard_std_name(int std)
        return "unknown";
 }
 
+static v4l2_std_id msp_standard_std(int std)
+{
+       int i;
+
+       for (i = 0; msp_stdlist[i].name != NULL; i++)
+               if (msp_stdlist[i].retval == std)
+                       return msp_stdlist[i].std;
+       return V4L2_STD_ALL;
+}
+
 static void msp_set_source(struct i2c_client *client, u16 src)
 {
        struct msp_state *state = to_state(i2c_get_clientdata(client));
@@ -479,6 +509,7 @@ int msp3400c_thread(void *data)
        int count, max1, max2, val1, val2, val, i;
 
        v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
+       state->detected_std = V4L2_STD_ALL;
        set_freezable();
        for (;;) {
                v4l_dbg(2, msp_debug, client, "msp3400 thread: sleep\n");
@@ -579,6 +610,7 @@ restart:
                state->main = msp3400c_carrier_detect_main[max1].cdo;
                switch (max1) {
                case 1: /* 5.5 */
+                       state->detected_std = V4L2_STD_BG | V4L2_STD_PAL_H;
                        if (max2 == 0) {
                                /* B/G FM-stereo */
                                state->second = msp3400c_carrier_detect_55[max2].cdo;
@@ -596,6 +628,7 @@ restart:
                        break;
                case 2: /* 6.0 */
                        /* PAL I NICAM */
+                       state->detected_std = V4L2_STD_PAL_I;
                        state->second = MSP_CARRIER(6.552);
                        msp3400c_set_mode(client, MSP_MODE_FM_NICAM2);
                        state->nicam_on = 1;
@@ -607,22 +640,26 @@ restart:
                                state->second = msp3400c_carrier_detect_65[max2].cdo;
                                msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
                                state->watch_stereo = 1;
+                               state->detected_std = V4L2_STD_DK;
                        } else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) {
                                /* L NICAM or AM-mono */
                                state->second = msp3400c_carrier_detect_65[max2].cdo;
                                msp3400c_set_mode(client, MSP_MODE_AM_NICAM);
                                state->watch_stereo = 1;
+                               state->detected_std = V4L2_STD_L;
                        } else if (max2 == 0 && state->has_nicam) {
                                /* D/K NICAM */
                                state->second = msp3400c_carrier_detect_65[max2].cdo;
                                msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
                                state->nicam_on = 1;
                                state->watch_stereo = 1;
+                               state->detected_std = V4L2_STD_DK;
                        } else {
                                goto no_second;
                        }
                        break;
                case 0: /* 4.5 */
+                       state->detected_std = V4L2_STD_MN;
                default:
 no_second:
                        state->second = msp3400c_carrier_detect_main[max1].cdo;
@@ -662,6 +699,7 @@ int msp3410d_thread(void *data)
        int val, i, std, count;
 
        v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n");
+       state->detected_std = V4L2_STD_ALL;
        set_freezable();
        for (;;) {
                v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n");
@@ -743,6 +781,8 @@ restart:
                                        msp_stdlist[8].name : "unknown", val);
                        state->std = val = 0x0009;
                        msp_write_dem(client, 0x20, val);
+               } else {
+                       state->detected_std = msp_standard_std(state->std);
                }
 
                /* set stereo */
@@ -957,6 +997,7 @@ int msp34xxg_thread(void *data)
        int val, i;
 
        v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n");
+       state->detected_std = V4L2_STD_ALL;
        set_freezable();
        for (;;) {
                v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n");
@@ -1013,6 +1054,7 @@ unmute:
                v4l_dbg(1, msp_debug, client,
                        "detected standard: %s (0x%04x)\n",
                        msp_standard_std_name(state->std), state->std);
+               state->detected_std = msp_standard_std(state->std);
 
                if (state->std == 9) {
                        /* AM NICAM mode */
index a357aa8..07af26e 100644 (file)
@@ -184,6 +184,7 @@ struct mt9m111 {
        struct mutex power_lock; /* lock to protect power_count */
        int power_count;
        const struct mt9m111_datafmt *fmt;
+       int lastpage;   /* PageMap cache value */
        unsigned int gain;
        unsigned char autoexposure;
        unsigned char datawidth;
@@ -202,17 +203,17 @@ static int reg_page_map_set(struct i2c_client *client, const u16 reg)
 {
        int ret;
        u16 page;
-       static int lastpage = -1;       /* PageMap cache value */
+       struct mt9m111 *mt9m111 = to_mt9m111(client);
 
        page = (reg >> 8);
-       if (page == lastpage)
+       if (page == mt9m111->lastpage)
                return 0;
        if (page > 2)
                return -EINVAL;
 
        ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page));
        if (!ret)
-               lastpage = page;
+               mt9m111->lastpage = page;
        return ret;
 }
 
@@ -932,6 +933,8 @@ static int mt9m111_video_probe(struct soc_camera_device *icd,
        BUG_ON(!icd->parent ||
               to_soc_camera_host(icd->parent)->nr != icd->iface);
 
+       mt9m111->lastpage = -1;
+
        mt9m111->autoexposure = 1;
        mt9m111->autowhitebalance = 1;
 
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c
new file mode 100644 (file)
index 0000000..73c0689
--- /dev/null
@@ -0,0 +1,964 @@
+/*
+ * Driver for MT9P031 CMOS Image Sensor from Aptina
+ *
+ * Copyright (C) 2011, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Copyright (C) 2011, Javier Martin <javier.martin@vista-silicon.com>
+ * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * Based on the MT9V032 driver and Bastian Hecht's code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <media/v4l2-subdev.h>
+#include <linux/videodev2.h>
+
+#include <media/mt9p031.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#define MT9P031_PIXEL_ARRAY_WIDTH                      2752
+#define MT9P031_PIXEL_ARRAY_HEIGHT                     2004
+
+#define MT9P031_CHIP_VERSION                           0x00
+#define                MT9P031_CHIP_VERSION_VALUE              0x1801
+#define MT9P031_ROW_START                              0x01
+#define                MT9P031_ROW_START_MIN                   0
+#define                MT9P031_ROW_START_MAX                   2004
+#define                MT9P031_ROW_START_DEF                   54
+#define MT9P031_COLUMN_START                           0x02
+#define                MT9P031_COLUMN_START_MIN                0
+#define                MT9P031_COLUMN_START_MAX                2750
+#define                MT9P031_COLUMN_START_DEF                16
+#define MT9P031_WINDOW_HEIGHT                          0x03
+#define                MT9P031_WINDOW_HEIGHT_MIN               2
+#define                MT9P031_WINDOW_HEIGHT_MAX               2006
+#define                MT9P031_WINDOW_HEIGHT_DEF               1944
+#define MT9P031_WINDOW_WIDTH                           0x04
+#define                MT9P031_WINDOW_WIDTH_MIN                2
+#define                MT9P031_WINDOW_WIDTH_MAX                2752
+#define                MT9P031_WINDOW_WIDTH_DEF                2592
+#define MT9P031_HORIZONTAL_BLANK                       0x05
+#define                MT9P031_HORIZONTAL_BLANK_MIN            0
+#define                MT9P031_HORIZONTAL_BLANK_MAX            4095
+#define MT9P031_VERTICAL_BLANK                         0x06
+#define                MT9P031_VERTICAL_BLANK_MIN              0
+#define                MT9P031_VERTICAL_BLANK_MAX              4095
+#define                MT9P031_VERTICAL_BLANK_DEF              25
+#define MT9P031_OUTPUT_CONTROL                         0x07
+#define                MT9P031_OUTPUT_CONTROL_CEN              2
+#define                MT9P031_OUTPUT_CONTROL_SYN              1
+#define                MT9P031_OUTPUT_CONTROL_DEF              0x1f82
+#define MT9P031_SHUTTER_WIDTH_UPPER                    0x08
+#define MT9P031_SHUTTER_WIDTH_LOWER                    0x09
+#define                MT9P031_SHUTTER_WIDTH_MIN               1
+#define                MT9P031_SHUTTER_WIDTH_MAX               1048575
+#define                MT9P031_SHUTTER_WIDTH_DEF               1943
+#define        MT9P031_PLL_CONTROL                             0x10
+#define                MT9P031_PLL_CONTROL_PWROFF              0x0050
+#define                MT9P031_PLL_CONTROL_PWRON               0x0051
+#define                MT9P031_PLL_CONTROL_USEPLL              0x0052
+#define        MT9P031_PLL_CONFIG_1                            0x11
+#define        MT9P031_PLL_CONFIG_2                            0x12
+#define MT9P031_PIXEL_CLOCK_CONTROL                    0x0a
+#define MT9P031_FRAME_RESTART                          0x0b
+#define MT9P031_SHUTTER_DELAY                          0x0c
+#define MT9P031_RST                                    0x0d
+#define                MT9P031_RST_ENABLE                      1
+#define                MT9P031_RST_DISABLE                     0
+#define MT9P031_READ_MODE_1                            0x1e
+#define MT9P031_READ_MODE_2                            0x20
+#define                MT9P031_READ_MODE_2_ROW_MIR             (1 << 15)
+#define                MT9P031_READ_MODE_2_COL_MIR             (1 << 14)
+#define                MT9P031_READ_MODE_2_ROW_BLC             (1 << 6)
+#define MT9P031_ROW_ADDRESS_MODE                       0x22
+#define MT9P031_COLUMN_ADDRESS_MODE                    0x23
+#define MT9P031_GLOBAL_GAIN                            0x35
+#define                MT9P031_GLOBAL_GAIN_MIN                 8
+#define                MT9P031_GLOBAL_GAIN_MAX                 1024
+#define                MT9P031_GLOBAL_GAIN_DEF                 8
+#define                MT9P031_GLOBAL_GAIN_MULT                (1 << 6)
+#define MT9P031_ROW_BLACK_DEF_OFFSET                   0x4b
+#define MT9P031_TEST_PATTERN                           0xa0
+#define                MT9P031_TEST_PATTERN_SHIFT              3
+#define                MT9P031_TEST_PATTERN_ENABLE             (1 << 0)
+#define                MT9P031_TEST_PATTERN_DISABLE            (0 << 0)
+#define MT9P031_TEST_PATTERN_GREEN                     0xa1
+#define MT9P031_TEST_PATTERN_RED                       0xa2
+#define MT9P031_TEST_PATTERN_BLUE                      0xa3
+
+struct mt9p031_pll_divs {
+       u32 ext_freq;
+       u32 target_freq;
+       u8 m;
+       u8 n;
+       u8 p1;
+};
+
+struct mt9p031 {
+       struct v4l2_subdev subdev;
+       struct media_pad pad;
+       struct v4l2_rect crop;  /* Sensor window */
+       struct v4l2_mbus_framefmt format;
+       struct v4l2_ctrl_handler ctrls;
+       struct mt9p031_platform_data *pdata;
+       struct mutex power_lock; /* lock to protect power_count */
+       int power_count;
+       u16 xskip;
+       u16 yskip;
+
+       const struct mt9p031_pll_divs *pll;
+
+       /* Registers cache */
+       u16 output_control;
+       u16 mode2;
+};
+
+static struct mt9p031 *to_mt9p031(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct mt9p031, subdev);
+}
+
+static int mt9p031_read(struct i2c_client *client, u8 reg)
+{
+       s32 data = i2c_smbus_read_word_data(client, reg);
+       return data < 0 ? data : be16_to_cpu(data);
+}
+
+static int mt9p031_write(struct i2c_client *client, u8 reg, u16 data)
+{
+       return i2c_smbus_write_word_data(client, reg, cpu_to_be16(data));
+}
+
+static int mt9p031_set_output_control(struct mt9p031 *mt9p031, u16 clear,
+                                     u16 set)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+       u16 value = (mt9p031->output_control & ~clear) | set;
+       int ret;
+
+       ret = mt9p031_write(client, MT9P031_OUTPUT_CONTROL, value);
+       if (ret < 0)
+               return ret;
+
+       mt9p031->output_control = value;
+       return 0;
+}
+
+static int mt9p031_set_mode2(struct mt9p031 *mt9p031, u16 clear, u16 set)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+       u16 value = (mt9p031->mode2 & ~clear) | set;
+       int ret;
+
+       ret = mt9p031_write(client, MT9P031_READ_MODE_2, value);
+       if (ret < 0)
+               return ret;
+
+       mt9p031->mode2 = value;
+       return 0;
+}
+
+static int mt9p031_reset(struct mt9p031 *mt9p031)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+       int ret;
+
+       /* Disable chip output, synchronous option update */
+       ret = mt9p031_write(client, MT9P031_RST, MT9P031_RST_ENABLE);
+       if (ret < 0)
+               return ret;
+       ret = mt9p031_write(client, MT9P031_RST, MT9P031_RST_DISABLE);
+       if (ret < 0)
+               return ret;
+
+       return mt9p031_set_output_control(mt9p031, MT9P031_OUTPUT_CONTROL_CEN,
+                                         0);
+}
+
+/*
+ * This static table uses ext_freq and vdd_io values to select suitable
+ * PLL dividers m, n and p1 which have been calculated as specifiec in p36
+ * of Aptina's mt9p031 datasheet. New values should be added here.
+ */
+static const struct mt9p031_pll_divs mt9p031_divs[] = {
+       /* ext_freq     target_freq     m       n       p1 */
+       {21000000,      48000000,       26,     2,      6}
+};
+
+static int mt9p031_pll_get_divs(struct mt9p031 *mt9p031)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mt9p031_divs); i++) {
+               if (mt9p031_divs[i].ext_freq == mt9p031->pdata->ext_freq &&
+                 mt9p031_divs[i].target_freq == mt9p031->pdata->target_freq) {
+                       mt9p031->pll = &mt9p031_divs[i];
+                       return 0;
+               }
+       }
+
+       dev_err(&client->dev, "Couldn't find PLL dividers for ext_freq = %d, "
+               "target_freq = %d\n", mt9p031->pdata->ext_freq,
+               mt9p031->pdata->target_freq);
+       return -EINVAL;
+}
+
+static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+       int ret;
+
+       ret = mt9p031_write(client, MT9P031_PLL_CONTROL,
+                           MT9P031_PLL_CONTROL_PWRON);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9p031_write(client, MT9P031_PLL_CONFIG_1,
+                           (mt9p031->pll->m << 8) | (mt9p031->pll->n - 1));
+       if (ret < 0)
+               return ret;
+
+       ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll->p1 - 1);
+       if (ret < 0)
+               return ret;
+
+       usleep_range(1000, 2000);
+       ret = mt9p031_write(client, MT9P031_PLL_CONTROL,
+                           MT9P031_PLL_CONTROL_PWRON |
+                           MT9P031_PLL_CONTROL_USEPLL);
+       return ret;
+}
+
+static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+
+       return mt9p031_write(client, MT9P031_PLL_CONTROL,
+                            MT9P031_PLL_CONTROL_PWROFF);
+}
+
+static int mt9p031_power_on(struct mt9p031 *mt9p031)
+{
+       /* Ensure RESET_BAR is low */
+       if (mt9p031->pdata->reset) {
+               mt9p031->pdata->reset(&mt9p031->subdev, 1);
+               usleep_range(1000, 2000);
+       }
+
+       /* Emable clock */
+       if (mt9p031->pdata->set_xclk)
+               mt9p031->pdata->set_xclk(&mt9p031->subdev,
+                                        mt9p031->pdata->ext_freq);
+
+       /* Now RESET_BAR must be high */
+       if (mt9p031->pdata->reset) {
+               mt9p031->pdata->reset(&mt9p031->subdev, 0);
+               usleep_range(1000, 2000);
+       }
+
+       return 0;
+}
+
+static void mt9p031_power_off(struct mt9p031 *mt9p031)
+{
+       if (mt9p031->pdata->reset) {
+               mt9p031->pdata->reset(&mt9p031->subdev, 1);
+               usleep_range(1000, 2000);
+       }
+
+       if (mt9p031->pdata->set_xclk)
+               mt9p031->pdata->set_xclk(&mt9p031->subdev, 0);
+}
+
+static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+       int ret;
+
+       if (!on) {
+               mt9p031_power_off(mt9p031);
+               return 0;
+       }
+
+       ret = mt9p031_power_on(mt9p031);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9p031_reset(mt9p031);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to reset the camera\n");
+               return ret;
+       }
+
+       return v4l2_ctrl_handler_setup(&mt9p031->ctrls);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static int mt9p031_set_params(struct mt9p031 *mt9p031)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+       struct v4l2_mbus_framefmt *format = &mt9p031->format;
+       const struct v4l2_rect *crop = &mt9p031->crop;
+       unsigned int hblank;
+       unsigned int vblank;
+       unsigned int xskip;
+       unsigned int yskip;
+       unsigned int xbin;
+       unsigned int ybin;
+       int ret;
+
+       /* Windows position and size.
+        *
+        * TODO: Make sure the start coordinates and window size match the
+        * skipping, binning and mirroring (see description of registers 2 and 4
+        * in table 13, and Binning section on page 41).
+        */
+       ret = mt9p031_write(client, MT9P031_COLUMN_START, crop->left);
+       if (ret < 0)
+               return ret;
+       ret = mt9p031_write(client, MT9P031_ROW_START, crop->top);
+       if (ret < 0)
+               return ret;
+       ret = mt9p031_write(client, MT9P031_WINDOW_WIDTH, crop->width - 1);
+       if (ret < 0)
+               return ret;
+       ret = mt9p031_write(client, MT9P031_WINDOW_HEIGHT, crop->height - 1);
+       if (ret < 0)
+               return ret;
+
+       /* Row and column binning and skipping. Use the maximum binning value
+        * compatible with the skipping settings.
+        */
+       xskip = DIV_ROUND_CLOSEST(crop->width, format->width);
+       yskip = DIV_ROUND_CLOSEST(crop->height, format->height);
+       xbin = 1 << (ffs(xskip) - 1);
+       ybin = 1 << (ffs(yskip) - 1);
+
+       ret = mt9p031_write(client, MT9P031_COLUMN_ADDRESS_MODE,
+                           ((xbin - 1) << 4) | (xskip - 1));
+       if (ret < 0)
+               return ret;
+       ret = mt9p031_write(client, MT9P031_ROW_ADDRESS_MODE,
+                           ((ybin - 1) << 4) | (yskip - 1));
+       if (ret < 0)
+               return ret;
+
+       /* Blanking - use minimum value for horizontal blanking and default
+        * value for vertical blanking.
+        */
+       hblank = 346 * ybin + 64 + (80 >> max_t(unsigned int, xbin, 3));
+       vblank = MT9P031_VERTICAL_BLANK_DEF;
+
+       ret = mt9p031_write(client, MT9P031_HORIZONTAL_BLANK, hblank);
+       if (ret < 0)
+               return ret;
+       ret = mt9p031_write(client, MT9P031_VERTICAL_BLANK, vblank);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+       struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+       int ret;
+
+       if (!enable) {
+               /* Stop sensor readout */
+               ret = mt9p031_set_output_control(mt9p031,
+                                                MT9P031_OUTPUT_CONTROL_CEN, 0);
+               if (ret < 0)
+                       return ret;
+
+               return mt9p031_pll_disable(mt9p031);
+       }
+
+       ret = mt9p031_set_params(mt9p031);
+       if (ret < 0)
+               return ret;
+
+       /* Switch to master "normal" mode */
+       ret = mt9p031_set_output_control(mt9p031, 0,
+                                        MT9P031_OUTPUT_CONTROL_CEN);
+       if (ret < 0)
+               return ret;
+
+       return mt9p031_pll_enable(mt9p031);
+}
+
+static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev,
+                                 struct v4l2_subdev_fh *fh,
+                                 struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+
+       if (code->pad || code->index)
+               return -EINVAL;
+
+       code->code = mt9p031->format.code;
+       return 0;
+}
+
+static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev,
+                                  struct v4l2_subdev_fh *fh,
+                                  struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+
+       if (fse->index >= 8 || fse->code != mt9p031->format.code)
+               return -EINVAL;
+
+       fse->min_width = MT9P031_WINDOW_WIDTH_DEF
+                      / min_t(unsigned int, 7, fse->index + 1);
+       fse->max_width = fse->min_width;
+       fse->min_height = MT9P031_WINDOW_HEIGHT_DEF / (fse->index + 1);
+       fse->max_height = fse->min_height;
+
+       return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh,
+                        unsigned int pad, u32 which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_format(fh, pad);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &mt9p031->format;
+       default:
+               return NULL;
+       }
+}
+
+static struct v4l2_rect *
+__mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh,
+                    unsigned int pad, u32 which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_crop(fh, pad);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &mt9p031->crop;
+       default:
+               return NULL;
+       }
+}
+
+static int mt9p031_get_format(struct v4l2_subdev *subdev,
+                             struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *fmt)
+{
+       struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+
+       fmt->format = *__mt9p031_get_pad_format(mt9p031, fh, fmt->pad,
+                                               fmt->which);
+       return 0;
+}
+
+static int mt9p031_set_format(struct v4l2_subdev *subdev,
+                             struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *format)
+{
+       struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+       struct v4l2_mbus_framefmt *__format;
+       struct v4l2_rect *__crop;
+       unsigned int width;
+       unsigned int height;
+       unsigned int hratio;
+       unsigned int vratio;
+
+       __crop = __mt9p031_get_pad_crop(mt9p031, fh, format->pad,
+                                       format->which);
+
+       /* Clamp the width and height to avoid dividing by zero. */
+       width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
+                       max(__crop->width / 7, MT9P031_WINDOW_WIDTH_MIN),
+                       __crop->width);
+       height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
+                       max(__crop->height / 8, MT9P031_WINDOW_HEIGHT_MIN),
+                       __crop->height);
+
+       hratio = DIV_ROUND_CLOSEST(__crop->width, width);
+       vratio = DIV_ROUND_CLOSEST(__crop->height, height);
+
+       __format = __mt9p031_get_pad_format(mt9p031, fh, format->pad,
+                                           format->which);
+       __format->width = __crop->width / hratio;
+       __format->height = __crop->height / vratio;
+
+       format->format = *__format;
+
+       return 0;
+}
+
+static int mt9p031_get_crop(struct v4l2_subdev *subdev,
+                           struct v4l2_subdev_fh *fh,
+                           struct v4l2_subdev_crop *crop)
+{
+       struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+
+       crop->rect = *__mt9p031_get_pad_crop(mt9p031, fh, crop->pad,
+                                            crop->which);
+       return 0;
+}
+
+static int mt9p031_set_crop(struct v4l2_subdev *subdev,
+                           struct v4l2_subdev_fh *fh,
+                           struct v4l2_subdev_crop *crop)
+{
+       struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+       struct v4l2_mbus_framefmt *__format;
+       struct v4l2_rect *__crop;
+       struct v4l2_rect rect;
+
+       /* Clamp the crop rectangle boundaries and align them to a multiple of 2
+        * pixels to ensure a GRBG Bayer pattern.
+        */
+       rect.left = clamp(ALIGN(crop->rect.left, 2), MT9P031_COLUMN_START_MIN,
+                         MT9P031_COLUMN_START_MAX);
+       rect.top = clamp(ALIGN(crop->rect.top, 2), MT9P031_ROW_START_MIN,
+                        MT9P031_ROW_START_MAX);
+       rect.width = clamp(ALIGN(crop->rect.width, 2),
+                          MT9P031_WINDOW_WIDTH_MIN,
+                          MT9P031_WINDOW_WIDTH_MAX);
+       rect.height = clamp(ALIGN(crop->rect.height, 2),
+                           MT9P031_WINDOW_HEIGHT_MIN,
+                           MT9P031_WINDOW_HEIGHT_MAX);
+
+       rect.width = min(rect.width, MT9P031_PIXEL_ARRAY_WIDTH - rect.left);
+       rect.height = min(rect.height, MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
+
+       __crop = __mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which);
+
+       if (rect.width != __crop->width || rect.height != __crop->height) {
+               /* Reset the output image size if the crop rectangle size has
+                * been modified.
+                */
+               __format = __mt9p031_get_pad_format(mt9p031, fh, crop->pad,
+                                                   crop->which);
+               __format->width = rect.width;
+               __format->height = rect.height;
+       }
+
+       *__crop = rect;
+       crop->rect = rect;
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+#define V4L2_CID_TEST_PATTERN          (V4L2_CID_USER_BASE | 0x1001)
+
+static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct mt9p031 *mt9p031 =
+                       container_of(ctrl->handler, struct mt9p031, ctrls);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+       u16 data;
+       int ret;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               ret = mt9p031_write(client, MT9P031_SHUTTER_WIDTH_UPPER,
+                                   (ctrl->val >> 16) & 0xffff);
+               if (ret < 0)
+                       return ret;
+
+               return mt9p031_write(client, MT9P031_SHUTTER_WIDTH_LOWER,
+                                    ctrl->val & 0xffff);
+
+       case V4L2_CID_GAIN:
+               /* Gain is controlled by 2 analog stages and a digital stage.
+                * Valid values for the 3 stages are
+                *
+                * Stage                Min     Max     Step
+                * ------------------------------------------
+                * First analog stage   x1      x2      1
+                * Second analog stage  x1      x4      0.125
+                * Digital stage        x1      x16     0.125
+                *
+                * To minimize noise, the gain stages should be used in the
+                * second analog stage, first analog stage, digital stage order.
+                * Gain from a previous stage should be pushed to its maximum
+                * value before the next stage is used.
+                */
+               if (ctrl->val <= 32) {
+                       data = ctrl->val;
+               } else if (ctrl->val <= 64) {
+                       ctrl->val &= ~1;
+                       data = (1 << 6) | (ctrl->val >> 1);
+               } else {
+                       ctrl->val &= ~7;
+                       data = ((ctrl->val - 64) << 5) | (1 << 6) | 32;
+               }
+
+               return mt9p031_write(client, MT9P031_GLOBAL_GAIN, data);
+
+       case V4L2_CID_HFLIP:
+               if (ctrl->val)
+                       return mt9p031_set_mode2(mt9p031,
+                                       0, MT9P031_READ_MODE_2_COL_MIR);
+               else
+                       return mt9p031_set_mode2(mt9p031,
+                                       MT9P031_READ_MODE_2_COL_MIR, 0);
+
+       case V4L2_CID_VFLIP:
+               if (ctrl->val)
+                       return mt9p031_set_mode2(mt9p031,
+                                       0, MT9P031_READ_MODE_2_ROW_MIR);
+               else
+                       return mt9p031_set_mode2(mt9p031,
+                                       MT9P031_READ_MODE_2_ROW_MIR, 0);
+
+       case V4L2_CID_TEST_PATTERN:
+               if (!ctrl->val) {
+                       ret = mt9p031_set_mode2(mt9p031,
+                                       0, MT9P031_READ_MODE_2_ROW_BLC);
+                       if (ret < 0)
+                               return ret;
+
+                       return mt9p031_write(client, MT9P031_TEST_PATTERN,
+                                            MT9P031_TEST_PATTERN_DISABLE);
+               }
+
+               ret = mt9p031_write(client, MT9P031_TEST_PATTERN_GREEN, 0x05a0);
+               if (ret < 0)
+                       return ret;
+               ret = mt9p031_write(client, MT9P031_TEST_PATTERN_RED, 0x0a50);
+               if (ret < 0)
+                       return ret;
+               ret = mt9p031_write(client, MT9P031_TEST_PATTERN_BLUE, 0x0aa0);
+               if (ret < 0)
+                       return ret;
+
+               ret = mt9p031_set_mode2(mt9p031, MT9P031_READ_MODE_2_ROW_BLC,
+                                       0);
+               if (ret < 0)
+                       return ret;
+               ret = mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET, 0);
+               if (ret < 0)
+                       return ret;
+
+               return mt9p031_write(client, MT9P031_TEST_PATTERN,
+                               ((ctrl->val - 1) << MT9P031_TEST_PATTERN_SHIFT)
+                               | MT9P031_TEST_PATTERN_ENABLE);
+       }
+       return 0;
+}
+
+static struct v4l2_ctrl_ops mt9p031_ctrl_ops = {
+       .s_ctrl = mt9p031_s_ctrl,
+};
+
+static const char * const mt9p031_test_pattern_menu[] = {
+       "Disabled",
+       "Color Field",
+       "Horizontal Gradient",
+       "Vertical Gradient",
+       "Diagonal Gradient",
+       "Classic Test Pattern",
+       "Walking 1s",
+       "Monochrome Horizontal Bars",
+       "Monochrome Vertical Bars",
+       "Vertical Color Bars",
+};
+
+static const struct v4l2_ctrl_config mt9p031_ctrls[] = {
+       {
+               .ops            = &mt9p031_ctrl_ops,
+               .id             = V4L2_CID_TEST_PATTERN,
+               .type           = V4L2_CTRL_TYPE_MENU,
+               .name           = "Test Pattern",
+               .min            = 0,
+               .max            = ARRAY_SIZE(mt9p031_test_pattern_menu) - 1,
+               .step           = 0,
+               .def            = 0,
+               .flags          = 0,
+               .menu_skip_mask = 0,
+               .qmenu          = mt9p031_test_pattern_menu,
+       }
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int mt9p031_set_power(struct v4l2_subdev *subdev, int on)
+{
+       struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+       int ret = 0;
+
+       mutex_lock(&mt9p031->power_lock);
+
+       /* If the power count is modified from 0 to != 0 or from != 0 to 0,
+        * update the power state.
+        */
+       if (mt9p031->power_count == !on) {
+               ret = __mt9p031_set_power(mt9p031, !!on);
+               if (ret < 0)
+                       goto out;
+       }
+
+       /* Update the power count. */
+       mt9p031->power_count += on ? 1 : -1;
+       WARN_ON(mt9p031->power_count < 0);
+
+out:
+       mutex_unlock(&mt9p031->power_lock);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev internal operations
+ */
+
+static int mt9p031_registered(struct v4l2_subdev *subdev)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(subdev);
+       struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+       s32 data;
+       int ret;
+
+       ret = mt9p031_power_on(mt9p031);
+       if (ret < 0) {
+               dev_err(&client->dev, "MT9P031 power up failed\n");
+               return ret;
+       }
+
+       /* Read out the chip version register */
+       data = mt9p031_read(client, MT9P031_CHIP_VERSION);
+       if (data != MT9P031_CHIP_VERSION_VALUE) {
+               dev_err(&client->dev, "MT9P031 not detected, wrong version "
+                       "0x%04x\n", data);
+               return -ENODEV;
+       }
+
+       mt9p031_power_off(mt9p031);
+
+       dev_info(&client->dev, "MT9P031 detected at address 0x%02x\n",
+                client->addr);
+
+       return ret;
+}
+
+static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+       struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+       struct v4l2_mbus_framefmt *format;
+       struct v4l2_rect *crop;
+
+       crop = v4l2_subdev_get_try_crop(fh, 0);
+       crop->left = MT9P031_COLUMN_START_DEF;
+       crop->top = MT9P031_ROW_START_DEF;
+       crop->width = MT9P031_WINDOW_WIDTH_DEF;
+       crop->height = MT9P031_WINDOW_HEIGHT_DEF;
+
+       format = v4l2_subdev_get_try_format(fh, 0);
+
+       if (mt9p031->pdata->version == MT9P031_MONOCHROME_VERSION)
+               format->code = V4L2_MBUS_FMT_Y12_1X12;
+       else
+               format->code = V4L2_MBUS_FMT_SGRBG12_1X12;
+
+       format->width = MT9P031_WINDOW_WIDTH_DEF;
+       format->height = MT9P031_WINDOW_HEIGHT_DEF;
+       format->field = V4L2_FIELD_NONE;
+       format->colorspace = V4L2_COLORSPACE_SRGB;
+
+       mt9p031->xskip = 1;
+       mt9p031->yskip = 1;
+       return mt9p031_set_power(subdev, 1);
+}
+
+static int mt9p031_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+       return mt9p031_set_power(subdev, 0);
+}
+
+static struct v4l2_subdev_core_ops mt9p031_subdev_core_ops = {
+       .s_power        = mt9p031_set_power,
+};
+
+static struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = {
+       .s_stream       = mt9p031_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
+       .enum_mbus_code = mt9p031_enum_mbus_code,
+       .enum_frame_size = mt9p031_enum_frame_size,
+       .get_fmt = mt9p031_get_format,
+       .set_fmt = mt9p031_set_format,
+       .get_crop = mt9p031_get_crop,
+       .set_crop = mt9p031_set_crop,
+};
+
+static struct v4l2_subdev_ops mt9p031_subdev_ops = {
+       .core   = &mt9p031_subdev_core_ops,
+       .video  = &mt9p031_subdev_video_ops,
+       .pad    = &mt9p031_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = {
+       .registered = mt9p031_registered,
+       .open = mt9p031_open,
+       .close = mt9p031_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * Driver initialization and probing
+ */
+
+static int mt9p031_probe(struct i2c_client *client,
+                        const struct i2c_device_id *did)
+{
+       struct mt9p031_platform_data *pdata = client->dev.platform_data;
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct mt9p031 *mt9p031;
+       unsigned int i;
+       int ret;
+
+       if (pdata == NULL) {
+               dev_err(&client->dev, "No platform data\n");
+               return -EINVAL;
+       }
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_warn(&client->dev,
+                       "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+               return -EIO;
+       }
+
+       mt9p031 = kzalloc(sizeof(*mt9p031), GFP_KERNEL);
+       if (mt9p031 == NULL)
+               return -ENOMEM;
+
+       mt9p031->pdata = pdata;
+       mt9p031->output_control = MT9P031_OUTPUT_CONTROL_DEF;
+       mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC;
+
+       v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 4);
+
+       v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
+                         V4L2_CID_EXPOSURE, MT9P031_SHUTTER_WIDTH_MIN,
+                         MT9P031_SHUTTER_WIDTH_MAX, 1,
+                         MT9P031_SHUTTER_WIDTH_DEF);
+       v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
+                         V4L2_CID_GAIN, MT9P031_GLOBAL_GAIN_MIN,
+                         MT9P031_GLOBAL_GAIN_MAX, 1, MT9P031_GLOBAL_GAIN_DEF);
+       v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
+                         V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
+                         V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+       for (i = 0; i < ARRAY_SIZE(mt9p031_ctrls); ++i)
+               v4l2_ctrl_new_custom(&mt9p031->ctrls, &mt9p031_ctrls[i], NULL);
+
+       mt9p031->subdev.ctrl_handler = &mt9p031->ctrls;
+
+       if (mt9p031->ctrls.error)
+               printk(KERN_INFO "%s: control initialization error %d\n",
+                      __func__, mt9p031->ctrls.error);
+
+       mutex_init(&mt9p031->power_lock);
+       v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops);
+       mt9p031->subdev.internal_ops = &mt9p031_subdev_internal_ops;
+
+       mt9p031->pad.flags = MEDIA_PAD_FL_SOURCE;
+       ret = media_entity_init(&mt9p031->subdev.entity, 1, &mt9p031->pad, 0);
+       if (ret < 0)
+               goto done;
+
+       mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       mt9p031->crop.width = MT9P031_WINDOW_WIDTH_DEF;
+       mt9p031->crop.height = MT9P031_WINDOW_HEIGHT_DEF;
+       mt9p031->crop.left = MT9P031_COLUMN_START_DEF;
+       mt9p031->crop.top = MT9P031_ROW_START_DEF;
+
+       if (mt9p031->pdata->version == MT9P031_MONOCHROME_VERSION)
+               mt9p031->format.code = V4L2_MBUS_FMT_Y12_1X12;
+       else
+               mt9p031->format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
+
+       mt9p031->format.width = MT9P031_WINDOW_WIDTH_DEF;
+       mt9p031->format.height = MT9P031_WINDOW_HEIGHT_DEF;
+       mt9p031->format.field = V4L2_FIELD_NONE;
+       mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+       ret = mt9p031_pll_get_divs(mt9p031);
+
+done:
+       if (ret < 0) {
+               v4l2_ctrl_handler_free(&mt9p031->ctrls);
+               media_entity_cleanup(&mt9p031->subdev.entity);
+               kfree(mt9p031);
+       }
+
+       return ret;
+}
+
+static int mt9p031_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+
+       v4l2_ctrl_handler_free(&mt9p031->ctrls);
+       v4l2_device_unregister_subdev(subdev);
+       media_entity_cleanup(&subdev->entity);
+       kfree(mt9p031);
+
+       return 0;
+}
+
+static const struct i2c_device_id mt9p031_id[] = {
+       { "mt9p031", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9p031_id);
+
+static struct i2c_driver mt9p031_i2c_driver = {
+       .driver = {
+               .name = "mt9p031",
+       },
+       .probe          = mt9p031_probe,
+       .remove         = mt9p031_remove,
+       .id_table       = mt9p031_id,
+};
+
+static int __init mt9p031_mod_init(void)
+{
+       return i2c_add_driver(&mt9p031_i2c_driver);
+}
+
+static void __exit mt9p031_mod_exit(void)
+{
+       i2c_del_driver(&mt9p031_i2c_driver);
+}
+
+module_init(mt9p031_mod_init);
+module_exit(mt9p031_mod_exit);
+
+MODULE_DESCRIPTION("Aptina MT9P031 Camera driver");
+MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/mt9t001.c b/drivers/media/video/mt9t001.c
new file mode 100644 (file)
index 0000000..08074b8
--- /dev/null
@@ -0,0 +1,836 @@
+/*
+ * Driver for MT9T001 CMOS Image Sensor from Aptina (Micron)
+ *
+ * Copyright (C) 2010-2011, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on the MT9M001 driver,
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/log2.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/mt9t001.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#define MT9T001_PIXEL_ARRAY_HEIGHT                     1568
+#define MT9T001_PIXEL_ARRAY_WIDTH                      2112
+
+#define MT9T001_CHIP_VERSION                           0x00
+#define                MT9T001_CHIP_ID                         0x1621
+#define MT9T001_ROW_START                              0x01
+#define                MT9T001_ROW_START_MIN                   0
+#define                MT9T001_ROW_START_DEF                   20
+#define                MT9T001_ROW_START_MAX                   1534
+#define MT9T001_COLUMN_START                           0x02
+#define                MT9T001_COLUMN_START_MIN                0
+#define                MT9T001_COLUMN_START_DEF                32
+#define                MT9T001_COLUMN_START_MAX                2046
+#define MT9T001_WINDOW_HEIGHT                          0x03
+#define                MT9T001_WINDOW_HEIGHT_MIN               1
+#define                MT9T001_WINDOW_HEIGHT_DEF               1535
+#define                MT9T001_WINDOW_HEIGHT_MAX               1567
+#define MT9T001_WINDOW_WIDTH                           0x04
+#define                MT9T001_WINDOW_WIDTH_MIN                1
+#define                MT9T001_WINDOW_WIDTH_DEF                2047
+#define                MT9T001_WINDOW_WIDTH_MAX                2111
+#define MT9T001_HORIZONTAL_BLANKING                    0x05
+#define                MT9T001_HORIZONTAL_BLANKING_MIN         21
+#define                MT9T001_HORIZONTAL_BLANKING_MAX         1023
+#define MT9T001_VERTICAL_BLANKING                      0x06
+#define                MT9T001_VERTICAL_BLANKING_MIN           3
+#define                MT9T001_VERTICAL_BLANKING_MAX           1023
+#define MT9T001_OUTPUT_CONTROL                         0x07
+#define                MT9T001_OUTPUT_CONTROL_SYNC             (1 << 0)
+#define                MT9T001_OUTPUT_CONTROL_CHIP_ENABLE      (1 << 1)
+#define                MT9T001_OUTPUT_CONTROL_TEST_DATA        (1 << 6)
+#define MT9T001_SHUTTER_WIDTH_HIGH                     0x08
+#define MT9T001_SHUTTER_WIDTH_LOW                      0x09
+#define                MT9T001_SHUTTER_WIDTH_MIN               1
+#define                MT9T001_SHUTTER_WIDTH_DEF               1561
+#define                MT9T001_SHUTTER_WIDTH_MAX               (1024 * 1024)
+#define MT9T001_PIXEL_CLOCK                            0x0a
+#define                MT9T001_PIXEL_CLOCK_INVERT              (1 << 15)
+#define                MT9T001_PIXEL_CLOCK_SHIFT_MASK          (7 << 8)
+#define                MT9T001_PIXEL_CLOCK_SHIFT_SHIFT         8
+#define                MT9T001_PIXEL_CLOCK_DIVIDE_MASK         (0x7f << 0)
+#define MT9T001_FRAME_RESTART                          0x0b
+#define MT9T001_SHUTTER_DELAY                          0x0c
+#define                MT9T001_SHUTTER_DELAY_MAX               2047
+#define MT9T001_RESET                                  0x0d
+#define MT9T001_READ_MODE1                             0x1e
+#define                MT9T001_READ_MODE_SNAPSHOT              (1 << 8)
+#define                MT9T001_READ_MODE_STROBE_ENABLE         (1 << 9)
+#define                MT9T001_READ_MODE_STROBE_WIDTH          (1 << 10)
+#define                MT9T001_READ_MODE_STROBE_OVERRIDE       (1 << 11)
+#define MT9T001_READ_MODE2                             0x20
+#define                MT9T001_READ_MODE_BAD_FRAMES            (1 << 0)
+#define                MT9T001_READ_MODE_LINE_VALID_CONTINUOUS (1 << 9)
+#define                MT9T001_READ_MODE_LINE_VALID_FRAME      (1 << 10)
+#define MT9T001_READ_MODE3                             0x21
+#define                MT9T001_READ_MODE_GLOBAL_RESET          (1 << 0)
+#define                MT9T001_READ_MODE_GHST_CTL              (1 << 1)
+#define MT9T001_ROW_ADDRESS_MODE                       0x22
+#define                MT9T001_ROW_SKIP_MASK                   (7 << 0)
+#define                MT9T001_ROW_BIN_MASK                    (3 << 3)
+#define                MT9T001_ROW_BIN_SHIFT                   3
+#define MT9T001_COLUMN_ADDRESS_MODE                    0x23
+#define                MT9T001_COLUMN_SKIP_MASK                (7 << 0)
+#define                MT9T001_COLUMN_BIN_MASK                 (3 << 3)
+#define                MT9T001_COLUMN_BIN_SHIFT                3
+#define MT9T001_GREEN1_GAIN                            0x2b
+#define MT9T001_BLUE_GAIN                              0x2c
+#define MT9T001_RED_GAIN                               0x2d
+#define MT9T001_GREEN2_GAIN                            0x2e
+#define MT9T001_TEST_DATA                              0x32
+#define MT9T001_GLOBAL_GAIN                            0x35
+#define                MT9T001_GLOBAL_GAIN_MIN                 8
+#define                MT9T001_GLOBAL_GAIN_MAX                 1024
+#define MT9T001_BLACK_LEVEL                            0x49
+#define MT9T001_ROW_BLACK_DEFAULT_OFFSET               0x4b
+#define MT9T001_BLC_DELTA_THRESHOLDS                   0x5d
+#define MT9T001_CAL_THRESHOLDS                         0x5f
+#define MT9T001_GREEN1_OFFSET                          0x60
+#define MT9T001_GREEN2_OFFSET                          0x61
+#define MT9T001_BLACK_LEVEL_CALIBRATION                        0x62
+#define                MT9T001_BLACK_LEVEL_OVERRIDE            (1 << 0)
+#define                MT9T001_BLACK_LEVEL_DISABLE_OFFSET      (1 << 1)
+#define                MT9T001_BLACK_LEVEL_RECALCULATE         (1 << 12)
+#define                MT9T001_BLACK_LEVEL_LOCK_RED_BLUE       (1 << 13)
+#define                MT9T001_BLACK_LEVEL_LOCK_GREEN          (1 << 14)
+#define MT9T001_RED_OFFSET                             0x63
+#define MT9T001_BLUE_OFFSET                            0x64
+
+struct mt9t001 {
+       struct v4l2_subdev subdev;
+       struct media_pad pad;
+
+       struct v4l2_mbus_framefmt format;
+       struct v4l2_rect crop;
+
+       struct v4l2_ctrl_handler ctrls;
+       struct v4l2_ctrl *gains[4];
+
+       u16 output_control;
+       u16 black_level;
+};
+
+static inline struct mt9t001 *to_mt9t001(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct mt9t001, subdev);
+}
+
+static int mt9t001_read(struct i2c_client *client, u8 reg)
+{
+       s32 data = i2c_smbus_read_word_data(client, reg);
+       return data < 0 ? data : be16_to_cpu(data);
+}
+
+static int mt9t001_write(struct i2c_client *client, u8 reg, u16 data)
+{
+       return i2c_smbus_write_word_data(client, reg, cpu_to_be16(data));
+}
+
+static int mt9t001_set_output_control(struct mt9t001 *mt9t001, u16 clear,
+                                     u16 set)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev);
+       u16 value = (mt9t001->output_control & ~clear) | set;
+       int ret;
+
+       if (value == mt9t001->output_control)
+               return 0;
+
+       ret = mt9t001_write(client, MT9T001_OUTPUT_CONTROL, value);
+       if (ret < 0)
+               return ret;
+
+       mt9t001->output_control = value;
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh,
+                        unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_format(fh, pad);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &mt9t001->format;
+       default:
+               return NULL;
+       }
+}
+
+static struct v4l2_rect *
+__mt9t001_get_pad_crop(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh,
+                      unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_crop(fh, pad);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &mt9t001->crop;
+       default:
+               return NULL;
+       }
+}
+
+static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+       const u16 mode = MT9T001_OUTPUT_CONTROL_CHIP_ENABLE;
+       struct i2c_client *client = v4l2_get_subdevdata(subdev);
+       struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+       struct v4l2_mbus_framefmt *format = &mt9t001->format;
+       struct v4l2_rect *crop = &mt9t001->crop;
+       unsigned int hratio;
+       unsigned int vratio;
+       int ret;
+
+       if (!enable)
+               return mt9t001_set_output_control(mt9t001, mode, 0);
+
+       /* Configure the window size and row/column bin */
+       hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
+       vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
+
+       ret = mt9t001_write(client, MT9T001_ROW_ADDRESS_MODE, hratio - 1);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9t001_write(client, MT9T001_COLUMN_ADDRESS_MODE, vratio - 1);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9t001_write(client, MT9T001_COLUMN_START, crop->left);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9t001_write(client, MT9T001_ROW_START, crop->top);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9t001_write(client, MT9T001_WINDOW_WIDTH, crop->width - 1);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9t001_write(client, MT9T001_WINDOW_HEIGHT, crop->height - 1);
+       if (ret < 0)
+               return ret;
+
+       /* Switch to master "normal" mode */
+       return mt9t001_set_output_control(mt9t001, 0, mode);
+}
+
+static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev,
+                                 struct v4l2_subdev_fh *fh,
+                                 struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index > 0)
+               return -EINVAL;
+
+       code->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       return 0;
+}
+
+static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev,
+                                  struct v4l2_subdev_fh *fh,
+                                  struct v4l2_subdev_frame_size_enum *fse)
+{
+       if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
+               return -EINVAL;
+
+       fse->min_width = (MT9T001_WINDOW_WIDTH_DEF + 1) / fse->index;
+       fse->max_width = fse->min_width;
+       fse->min_height = (MT9T001_WINDOW_HEIGHT_DEF + 1) / fse->index;
+       fse->max_height = fse->min_height;
+
+       return 0;
+}
+
+static int mt9t001_get_format(struct v4l2_subdev *subdev,
+                             struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *format)
+{
+       struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+
+       format->format = *__mt9t001_get_pad_format(mt9t001, fh, format->pad,
+                                                  format->which);
+       return 0;
+}
+
+static int mt9t001_set_format(struct v4l2_subdev *subdev,
+                             struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *format)
+{
+       struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+       struct v4l2_mbus_framefmt *__format;
+       struct v4l2_rect *__crop;
+       unsigned int width;
+       unsigned int height;
+       unsigned int hratio;
+       unsigned int vratio;
+
+       __crop = __mt9t001_get_pad_crop(mt9t001, fh, format->pad,
+                                       format->which);
+
+       /* Clamp the width and height to avoid dividing by zero. */
+       width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
+                       max(__crop->width / 8, MT9T001_WINDOW_HEIGHT_MIN + 1),
+                       __crop->width);
+       height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
+                        max(__crop->height / 8, MT9T001_WINDOW_HEIGHT_MIN + 1),
+                        __crop->height);
+
+       hratio = DIV_ROUND_CLOSEST(__crop->width, width);
+       vratio = DIV_ROUND_CLOSEST(__crop->height, height);
+
+       __format = __mt9t001_get_pad_format(mt9t001, fh, format->pad,
+                                           format->which);
+       __format->width = __crop->width / hratio;
+       __format->height = __crop->height / vratio;
+
+       format->format = *__format;
+
+       return 0;
+}
+
+static int mt9t001_get_crop(struct v4l2_subdev *subdev,
+                           struct v4l2_subdev_fh *fh,
+                           struct v4l2_subdev_crop *crop)
+{
+       struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+
+       crop->rect = *__mt9t001_get_pad_crop(mt9t001, fh, crop->pad,
+                                            crop->which);
+       return 0;
+}
+
+static int mt9t001_set_crop(struct v4l2_subdev *subdev,
+                           struct v4l2_subdev_fh *fh,
+                           struct v4l2_subdev_crop *crop)
+{
+       struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+       struct v4l2_mbus_framefmt *__format;
+       struct v4l2_rect *__crop;
+       struct v4l2_rect rect;
+
+       /* Clamp the crop rectangle boundaries and align them to a multiple of 2
+        * pixels.
+        */
+       rect.left = clamp(ALIGN(crop->rect.left, 2),
+                         MT9T001_COLUMN_START_MIN,
+                         MT9T001_COLUMN_START_MAX);
+       rect.top = clamp(ALIGN(crop->rect.top, 2),
+                        MT9T001_ROW_START_MIN,
+                        MT9T001_ROW_START_MAX);
+       rect.width = clamp(ALIGN(crop->rect.width, 2),
+                          MT9T001_WINDOW_WIDTH_MIN + 1,
+                          MT9T001_WINDOW_WIDTH_MAX + 1);
+       rect.height = clamp(ALIGN(crop->rect.height, 2),
+                           MT9T001_WINDOW_HEIGHT_MIN + 1,
+                           MT9T001_WINDOW_HEIGHT_MAX + 1);
+
+       rect.width = min(rect.width, MT9T001_PIXEL_ARRAY_WIDTH - rect.left);
+       rect.height = min(rect.height, MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
+
+       __crop = __mt9t001_get_pad_crop(mt9t001, fh, crop->pad, crop->which);
+
+       if (rect.width != __crop->width || rect.height != __crop->height) {
+               /* Reset the output image size if the crop rectangle size has
+                * been modified.
+                */
+               __format = __mt9t001_get_pad_format(mt9t001, fh, crop->pad,
+                                                   crop->which);
+               __format->width = rect.width;
+               __format->height = rect.height;
+       }
+
+       *__crop = rect;
+       crop->rect = rect;
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+#define V4L2_CID_TEST_PATTERN          (V4L2_CID_USER_BASE | 0x1001)
+#define V4L2_CID_BLACK_LEVEL_AUTO      (V4L2_CID_USER_BASE | 0x1002)
+#define V4L2_CID_BLACK_LEVEL_OFFSET    (V4L2_CID_USER_BASE | 0x1003)
+#define V4L2_CID_BLACK_LEVEL_CALIBRATE (V4L2_CID_USER_BASE | 0x1004)
+
+#define V4L2_CID_GAIN_RED              (V4L2_CTRL_CLASS_CAMERA | 0x1001)
+#define V4L2_CID_GAIN_GREEN_RED                (V4L2_CTRL_CLASS_CAMERA | 0x1002)
+#define V4L2_CID_GAIN_GREEN_BLUE       (V4L2_CTRL_CLASS_CAMERA | 0x1003)
+#define V4L2_CID_GAIN_BLUE             (V4L2_CTRL_CLASS_CAMERA | 0x1004)
+
+static u16 mt9t001_gain_value(s32 *gain)
+{
+       /* Gain is controlled by 2 analog stages and a digital stage. Valid
+        * values for the 3 stages are
+        *
+        * Stage                Min     Max     Step
+        * ------------------------------------------
+        * First analog stage   x1      x2      1
+        * Second analog stage  x1      x4      0.125
+        * Digital stage        x1      x16     0.125
+        *
+        * To minimize noise, the gain stages should be used in the second
+        * analog stage, first analog stage, digital stage order. Gain from a
+        * previous stage should be pushed to its maximum value before the next
+        * stage is used.
+        */
+       if (*gain <= 32)
+               return *gain;
+
+       if (*gain <= 64) {
+               *gain &= ~1;
+               return (1 << 6) | (*gain >> 1);
+       }
+
+       *gain &= ~7;
+       return ((*gain - 64) << 5) | (1 << 6) | 32;
+}
+
+static int mt9t001_ctrl_freeze(struct mt9t001 *mt9t001, bool freeze)
+{
+       return mt9t001_set_output_control(mt9t001,
+               freeze ? 0 : MT9T001_OUTPUT_CONTROL_SYNC,
+               freeze ? MT9T001_OUTPUT_CONTROL_SYNC : 0);
+}
+
+static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       static const u8 gains[4] = {
+               MT9T001_RED_GAIN, MT9T001_GREEN1_GAIN,
+               MT9T001_GREEN2_GAIN, MT9T001_BLUE_GAIN
+       };
+
+       struct mt9t001 *mt9t001 =
+                       container_of(ctrl->handler, struct mt9t001, ctrls);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev);
+       unsigned int count;
+       unsigned int i;
+       u16 value;
+       int ret;
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN_RED:
+       case V4L2_CID_GAIN_GREEN_RED:
+       case V4L2_CID_GAIN_GREEN_BLUE:
+       case V4L2_CID_GAIN_BLUE:
+
+               /* Disable control updates if more than one control has changed
+                * in the cluster.
+                */
+               for (i = 0, count = 0; i < 4; ++i) {
+                       struct v4l2_ctrl *gain = mt9t001->gains[i];
+
+                       if (gain->val != gain->cur.val)
+                               count++;
+               }
+
+               if (count > 1) {
+                       ret = mt9t001_ctrl_freeze(mt9t001, true);
+                       if (ret < 0)
+                               return ret;
+               }
+
+               /* Update the gain controls. */
+               for (i = 0; i < 4; ++i) {
+                       struct v4l2_ctrl *gain = mt9t001->gains[i];
+
+                       if (gain->val == gain->cur.val)
+                               continue;
+
+                       value = mt9t001_gain_value(&gain->val);
+                       ret = mt9t001_write(client, gains[i], value);
+                       if (ret < 0) {
+                               mt9t001_ctrl_freeze(mt9t001, false);
+                               return ret;
+                       }
+               }
+
+               /* Enable control updates. */
+               if (count > 1) {
+                       ret = mt9t001_ctrl_freeze(mt9t001, false);
+                       if (ret < 0)
+                               return ret;
+               }
+
+               break;
+
+       case V4L2_CID_EXPOSURE:
+               ret = mt9t001_write(client, MT9T001_SHUTTER_WIDTH_LOW,
+                                   ctrl->val & 0xffff);
+               if (ret < 0)
+                       return ret;
+
+               return mt9t001_write(client, MT9T001_SHUTTER_WIDTH_HIGH,
+                                    ctrl->val >> 16);
+
+       case V4L2_CID_TEST_PATTERN:
+               ret = mt9t001_set_output_control(mt9t001,
+                       ctrl->val ? 0 : MT9T001_OUTPUT_CONTROL_TEST_DATA,
+                       ctrl->val ? MT9T001_OUTPUT_CONTROL_TEST_DATA : 0);
+               if (ret < 0)
+                       return ret;
+
+               return mt9t001_write(client, MT9T001_TEST_DATA, ctrl->val << 2);
+
+       case V4L2_CID_BLACK_LEVEL_AUTO:
+               value = ctrl->val ? 0 : MT9T001_BLACK_LEVEL_OVERRIDE;
+               ret = mt9t001_write(client, MT9T001_BLACK_LEVEL_CALIBRATION,
+                                   value);
+               if (ret < 0)
+                       return ret;
+
+               mt9t001->black_level = value;
+               break;
+
+       case V4L2_CID_BLACK_LEVEL_OFFSET:
+               ret = mt9t001_write(client, MT9T001_GREEN1_OFFSET, ctrl->val);
+               if (ret < 0)
+                       return ret;
+
+               ret = mt9t001_write(client, MT9T001_GREEN2_OFFSET, ctrl->val);
+               if (ret < 0)
+                       return ret;
+
+               ret = mt9t001_write(client, MT9T001_RED_OFFSET, ctrl->val);
+               if (ret < 0)
+                       return ret;
+
+               return mt9t001_write(client, MT9T001_BLUE_OFFSET, ctrl->val);
+
+       case V4L2_CID_BLACK_LEVEL_CALIBRATE:
+               return mt9t001_write(client, MT9T001_BLACK_LEVEL_CALIBRATION,
+                                    MT9T001_BLACK_LEVEL_RECALCULATE |
+                                    mt9t001->black_level);
+       }
+
+       return 0;
+}
+
+static struct v4l2_ctrl_ops mt9t001_ctrl_ops = {
+       .s_ctrl = mt9t001_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config mt9t001_ctrls[] = {
+       {
+               .ops            = &mt9t001_ctrl_ops,
+               .id             = V4L2_CID_TEST_PATTERN,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Test pattern",
+               .min            = 0,
+               .max            = 1023,
+               .step           = 1,
+               .def            = 0,
+               .flags          = 0,
+       }, {
+               .ops            = &mt9t001_ctrl_ops,
+               .id             = V4L2_CID_BLACK_LEVEL_AUTO,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Black Level, Auto",
+               .min            = 0,
+               .max            = 1,
+               .step           = 1,
+               .def            = 1,
+               .flags          = 0,
+       }, {
+               .ops            = &mt9t001_ctrl_ops,
+               .id             = V4L2_CID_BLACK_LEVEL_OFFSET,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Black Level, Offset",
+               .min            = -256,
+               .max            = 255,
+               .step           = 1,
+               .def            = 32,
+               .flags          = 0,
+       }, {
+               .ops            = &mt9t001_ctrl_ops,
+               .id             = V4L2_CID_BLACK_LEVEL_CALIBRATE,
+               .type           = V4L2_CTRL_TYPE_BUTTON,
+               .name           = "Black Level, Calibrate",
+               .min            = 0,
+               .max            = 0,
+               .step           = 0,
+               .def            = 0,
+               .flags          = V4L2_CTRL_FLAG_WRITE_ONLY,
+       },
+};
+
+static const struct v4l2_ctrl_config mt9t001_gains[] = {
+       {
+               .ops            = &mt9t001_ctrl_ops,
+               .id             = V4L2_CID_GAIN_RED,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Gain, Red",
+               .min            = MT9T001_GLOBAL_GAIN_MIN,
+               .max            = MT9T001_GLOBAL_GAIN_MAX,
+               .step           = 1,
+               .def            = MT9T001_GLOBAL_GAIN_MIN,
+               .flags          = 0,
+       }, {
+               .ops            = &mt9t001_ctrl_ops,
+               .id             = V4L2_CID_GAIN_GREEN_RED,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Gain, Green (R)",
+               .min            = MT9T001_GLOBAL_GAIN_MIN,
+               .max            = MT9T001_GLOBAL_GAIN_MAX,
+               .step           = 1,
+               .def            = MT9T001_GLOBAL_GAIN_MIN,
+               .flags          = 0,
+       }, {
+               .ops            = &mt9t001_ctrl_ops,
+               .id             = V4L2_CID_GAIN_GREEN_BLUE,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Gain, Green (B)",
+               .min            = MT9T001_GLOBAL_GAIN_MIN,
+               .max            = MT9T001_GLOBAL_GAIN_MAX,
+               .step           = 1,
+               .def            = MT9T001_GLOBAL_GAIN_MIN,
+               .flags          = 0,
+       }, {
+               .ops            = &mt9t001_ctrl_ops,
+               .id             = V4L2_CID_GAIN_BLUE,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Gain, Blue",
+               .min            = MT9T001_GLOBAL_GAIN_MIN,
+               .max            = MT9T001_GLOBAL_GAIN_MAX,
+               .step           = 1,
+               .def            = MT9T001_GLOBAL_GAIN_MIN,
+               .flags          = 0,
+       },
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev internal operations
+ */
+
+static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_mbus_framefmt *format;
+       struct v4l2_rect *crop;
+
+       crop = v4l2_subdev_get_try_crop(fh, 0);
+       crop->left = MT9T001_COLUMN_START_DEF;
+       crop->top = MT9T001_ROW_START_DEF;
+       crop->width = MT9T001_WINDOW_WIDTH_DEF + 1;
+       crop->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
+
+       format = v4l2_subdev_get_try_format(fh, 0);
+       format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       format->width = MT9T001_WINDOW_WIDTH_DEF + 1;
+       format->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
+       format->field = V4L2_FIELD_NONE;
+       format->colorspace = V4L2_COLORSPACE_SRGB;
+
+       return 0;
+}
+
+static struct v4l2_subdev_video_ops mt9t001_subdev_video_ops = {
+       .s_stream = mt9t001_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = {
+       .enum_mbus_code = mt9t001_enum_mbus_code,
+       .enum_frame_size = mt9t001_enum_frame_size,
+       .get_fmt = mt9t001_get_format,
+       .set_fmt = mt9t001_set_format,
+       .get_crop = mt9t001_get_crop,
+       .set_crop = mt9t001_set_crop,
+};
+
+static struct v4l2_subdev_ops mt9t001_subdev_ops = {
+       .video = &mt9t001_subdev_video_ops,
+       .pad = &mt9t001_subdev_pad_ops,
+};
+
+static struct v4l2_subdev_internal_ops mt9t001_subdev_internal_ops = {
+       .open = mt9t001_open,
+};
+
+static int mt9t001_video_probe(struct i2c_client *client)
+{
+       struct mt9t001_platform_data *pdata = client->dev.platform_data;
+       s32 data;
+       int ret;
+
+       dev_info(&client->dev, "Probing MT9T001 at address 0x%02x\n",
+                client->addr);
+
+       /* Reset the chip and stop data read out */
+       ret = mt9t001_write(client, MT9T001_RESET, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = mt9t001_write(client, MT9T001_RESET, 0);
+       if (ret < 0)
+               return ret;
+
+       ret  = mt9t001_write(client, MT9T001_OUTPUT_CONTROL, 0);
+       if (ret < 0)
+               return ret;
+
+       /* Configure the pixel clock polarity */
+       if (pdata && pdata->clk_pol) {
+               ret  = mt9t001_write(client, MT9T001_PIXEL_CLOCK,
+                                    MT9T001_PIXEL_CLOCK_INVERT);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* Read and check the sensor version */
+       data = mt9t001_read(client, MT9T001_CHIP_VERSION);
+       if (data != MT9T001_CHIP_ID) {
+               dev_err(&client->dev, "MT9T001 not detected, wrong version "
+                       "0x%04x\n", data);
+               return -ENODEV;
+       }
+
+       dev_info(&client->dev, "MT9T001 detected at address 0x%02x\n",
+                client->addr);
+
+       return ret;
+}
+
+static int mt9t001_probe(struct i2c_client *client,
+                        const struct i2c_device_id *did)
+{
+       struct mt9t001 *mt9t001;
+       unsigned int i;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_warn(&client->adapter->dev,
+                        "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+               return -EIO;
+       }
+
+       ret = mt9t001_video_probe(client);
+       if (ret < 0)
+               return ret;
+
+       mt9t001 = kzalloc(sizeof(*mt9t001), GFP_KERNEL);
+       if (!mt9t001)
+               return -ENOMEM;
+
+       v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) +
+                                               ARRAY_SIZE(mt9t001_gains) + 2);
+
+       v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
+                         V4L2_CID_EXPOSURE, MT9T001_SHUTTER_WIDTH_MIN,
+                         MT9T001_SHUTTER_WIDTH_MAX, 1,
+                         MT9T001_SHUTTER_WIDTH_DEF);
+       v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
+                         V4L2_CID_BLACK_LEVEL, 1, 1, 1, 1);
+
+       for (i = 0; i < ARRAY_SIZE(mt9t001_ctrls); ++i)
+               v4l2_ctrl_new_custom(&mt9t001->ctrls, &mt9t001_ctrls[i], NULL);
+
+       for (i = 0; i < ARRAY_SIZE(mt9t001_gains); ++i)
+               mt9t001->gains[i] = v4l2_ctrl_new_custom(&mt9t001->ctrls,
+                       &mt9t001_gains[i], NULL);
+
+       v4l2_ctrl_cluster(ARRAY_SIZE(mt9t001_gains), mt9t001->gains);
+
+       mt9t001->subdev.ctrl_handler = &mt9t001->ctrls;
+
+       if (mt9t001->ctrls.error) {
+               printk(KERN_INFO "%s: control initialization error %d\n",
+                      __func__, mt9t001->ctrls.error);
+               ret = -EINVAL;
+               goto done;
+       }
+
+       mt9t001->crop.left = MT9T001_COLUMN_START_DEF;
+       mt9t001->crop.top = MT9T001_ROW_START_DEF;
+       mt9t001->crop.width = MT9T001_WINDOW_WIDTH_DEF + 1;
+       mt9t001->crop.height = MT9T001_WINDOW_HEIGHT_DEF + 1;
+
+       mt9t001->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       mt9t001->format.width = MT9T001_WINDOW_WIDTH_DEF + 1;
+       mt9t001->format.height = MT9T001_WINDOW_HEIGHT_DEF + 1;
+       mt9t001->format.field = V4L2_FIELD_NONE;
+       mt9t001->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+       v4l2_i2c_subdev_init(&mt9t001->subdev, client, &mt9t001_subdev_ops);
+       mt9t001->subdev.internal_ops = &mt9t001_subdev_internal_ops;
+       mt9t001->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       mt9t001->pad.flags = MEDIA_PAD_FL_SOURCE;
+       ret = media_entity_init(&mt9t001->subdev.entity, 1, &mt9t001->pad, 0);
+
+done:
+       if (ret < 0) {
+               v4l2_ctrl_handler_free(&mt9t001->ctrls);
+               media_entity_cleanup(&mt9t001->subdev.entity);
+               kfree(mt9t001);
+       }
+
+       return ret;
+}
+
+static int mt9t001_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+
+       v4l2_ctrl_handler_free(&mt9t001->ctrls);
+       v4l2_device_unregister_subdev(subdev);
+       media_entity_cleanup(&subdev->entity);
+       kfree(mt9t001);
+       return 0;
+}
+
+static const struct i2c_device_id mt9t001_id[] = {
+       { "mt9t001", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9t001_id);
+
+static struct i2c_driver mt9t001_driver = {
+       .driver = {
+               .name = "mt9t001",
+       },
+       .probe          = mt9t001_probe,
+       .remove         = mt9t001_remove,
+       .id_table       = mt9t001_id,
+};
+
+static int __init mt9t001_init(void)
+{
+       return i2c_add_driver(&mt9t001_driver);
+}
+
+static void __exit mt9t001_exit(void)
+{
+       i2c_del_driver(&mt9t001_driver);
+}
+
+module_init(mt9t001_init);
+module_exit(mt9t001_exit);
+
+MODULE_DESCRIPTION("Aptina (Micron) MT9T001 Camera driver");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL");
index c045b47..c8e958a 100644 (file)
@@ -191,7 +191,7 @@ static void mx3_cam_dma_done(void *arg)
  */
 static int mx3_videobuf_setup(struct vb2_queue *vq,
                        unsigned int *count, unsigned int *num_planes,
-                       unsigned long sizes[], void *alloc_ctxs[])
+                       unsigned int sizes[], void *alloc_ctxs[])
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -247,7 +247,7 @@ static int mx3_videobuf_prepare(struct vb2_buffer *vb)
        }
 
        if (buf->state == CSI_BUF_NEEDS_INIT) {
-               sg_dma_address(sg)      = vb2_dma_contig_plane_paddr(vb, 0);
+               sg_dma_address(sg)      = vb2_dma_contig_plane_dma_addr(vb, 0);
                sg_dma_len(sg)          = new_size;
 
                buf->txd = ichan->dma_chan.device->device_prep_slave_sg(
index 0b38500..f0c3968 100644 (file)
@@ -21,6 +21,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define DEBUG_VARIABLE debug
 
 #include <media/saa7146_vv.h>
@@ -171,7 +173,7 @@ static int mxb_probe(struct saa7146_dev *dev)
 
        mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
        if (mxb == NULL) {
-               DEB_D(("not enough kernel memory.\n"));
+               DEB_D("not enough kernel memory\n");
                return -ENOMEM;
        }
 
@@ -179,7 +181,7 @@ static int mxb_probe(struct saa7146_dev *dev)
 
        saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
        if (i2c_add_adapter(&mxb->i2c_adapter) < 0) {
-               DEB_S(("cannot register i2c-device. skipping.\n"));
+               DEB_S("cannot register i2c-device. skipping.\n");
                kfree(mxb);
                return -EFAULT;
        }
@@ -200,7 +202,7 @@ static int mxb_probe(struct saa7146_dev *dev)
        /* check if all devices are present */
        if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
            !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) {
-               printk("mxb: did not find all i2c devices. aborting\n");
+               pr_err("did not find all i2c devices. aborting\n");
                i2c_del_adapter(&mxb->i2c_adapter);
                kfree(mxb);
                return -ENODEV;
@@ -346,11 +348,11 @@ static int mxb_init_done(struct saa7146_dev* dev)
                        msg.buf = &mxb_saa7740_init[i].data[0];
                        err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
                        if (err != 1) {
-                               DEB_D(("failed to initialize 'sound arena module'.\n"));
+                               DEB_D("failed to initialize 'sound arena module'\n");
                                goto err;
                        }
                }
-               INFO(("'sound arena module' detected.\n"));
+               pr_info("'sound arena module' detected\n");
        }
 err:
        /* the rest for saa7146: you should definitely set some basic values
@@ -390,7 +392,7 @@ static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *
        for (i = MAXCONTROLS - 1; i >= 0; i--) {
                if (mxb_controls[i].id == qc->id) {
                        *qc = mxb_controls[i];
-                       DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
+                       DEB_D("VIDIOC_QUERYCTRL %d\n", qc->id);
                        return 0;
                }
        }
@@ -413,11 +415,11 @@ static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
 
        if (vc->id == V4L2_CID_AUDIO_MUTE) {
                vc->value = mxb->cur_mute;
-               DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
+               DEB_D("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d\n", vc->value);
                return 0;
        }
 
-       DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
+       DEB_EE("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d\n", vc->value);
        return 0;
 }
 
@@ -440,14 +442,14 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
                /* switch the audio-source */
                tea6420_route_line(mxb, vc->value ? 6 :
                                video_audio_connect[mxb->cur_input]);
-               DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
+               DEB_EE("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d\n", vc->value);
        }
        return 0;
 }
 
 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
-       DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
+       DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
        if (i->index >= MXB_INPUTS)
                return -EINVAL;
        memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
@@ -460,7 +462,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
        struct mxb *mxb = (struct mxb *)dev->ext_priv;
        *i = mxb->cur_input;
 
-       DEB_EE(("VIDIOC_G_INPUT %d.\n", *i));
+       DEB_EE("VIDIOC_G_INPUT %d\n", *i);
        return 0;
 }
 
@@ -471,7 +473,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
        int err = 0;
        int i = 0;
 
-       DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
+       DEB_EE("VIDIOC_S_INPUT %d\n", input);
 
        if (input >= MXB_INPUTS)
                return -EINVAL;
@@ -514,7 +516,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
 
        /* switch video in saa7111a */
        if (saa7111a_call(mxb, video, s_routing, i, SAA7111_FMT_CCIR, 0))
-               printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a.\n");
+               pr_err("VIDIOC_S_INPUT: could not address saa7111a\n");
 
        /* switch the audio-source only if necessary */
        if (0 == mxb->cur_mute)
@@ -529,11 +531,12 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
        struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
        if (t->index) {
-               DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
+               DEB_D("VIDIOC_G_TUNER: channel %d does not have a tuner attached\n",
+                     t->index);
                return -EINVAL;
        }
 
-       DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
+       DEB_EE("VIDIOC_G_TUNER: %d\n", t->index);
 
        memset(t, 0, sizeof(*t));
        strlcpy(t->name, "TV Tuner", sizeof(t->name));
@@ -550,7 +553,8 @@ static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
        struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
        if (t->index) {
-               DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n", t->index));
+               DEB_D("VIDIOC_S_TUNER: channel %d does not have a tuner attached\n",
+                     t->index);
                return -EINVAL;
        }
 
@@ -564,14 +568,14 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency
        struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
        if (mxb->cur_input) {
-               DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
-                                       mxb->cur_input));
+               DEB_D("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
+                     mxb->cur_input);
                return -EINVAL;
        }
 
        *f = mxb->cur_freq;
 
-       DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
+       DEB_EE("VIDIOC_G_FREQ: freq:0x%08x\n", mxb->cur_freq.frequency);
        return 0;
 }
 
@@ -588,12 +592,13 @@ static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency
                return -EINVAL;
 
        if (mxb->cur_input) {
-               DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
+               DEB_D("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",
+                     mxb->cur_input);
                return -EINVAL;
        }
 
        mxb->cur_freq = *f;
-       DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
+       DEB_EE("VIDIOC_S_FREQUENCY: freq:0x%08x\n", mxb->cur_freq.frequency);
 
        /* tune in desired frequency */
        tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
@@ -612,18 +617,18 @@ static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
        struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
        if (a->index > MXB_INPUTS) {
-               DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
+               DEB_D("VIDIOC_G_AUDIO %d out of range\n", a->index);
                return -EINVAL;
        }
 
-       DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
+       DEB_EE("VIDIOC_G_AUDIO %d\n", a->index);
        memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
        return 0;
 }
 
 static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
 {
-       DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
+       DEB_D("VIDIOC_S_AUDIO %d\n", a->index);
        return 0;
 }
 
@@ -655,11 +660,11 @@ static long vidioc_default(struct file *file, void *fh, bool valid_prio,
                int i = *(int *)arg;
 
                if (i < 0 || i >= MXB_AUDIOS) {
-                       DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n", i));
+                       DEB_D("invalid argument to MXB_S_AUDIO_CD: i:%d\n", i);
                        return -EINVAL;
                }
 
-               DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i));
+               DEB_EE("MXB_S_AUDIO_CD: i:%d\n", i);
 
                tea6420_route_cd(mxb, i);
                return 0;
@@ -669,17 +674,18 @@ static long vidioc_default(struct file *file, void *fh, bool valid_prio,
                int i = *(int *)arg;
 
                if (i < 0 || i >= MXB_AUDIOS) {
-                       DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n", i));
+                       DEB_D("invalid argument to MXB_S_AUDIO_LINE: i:%d\n",
+                             i);
                        return -EINVAL;
                }
 
-               DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i));
+               DEB_EE("MXB_S_AUDIO_LINE: i:%d\n", i);
                tea6420_route_line(mxb, i);
                return 0;
        }
        default:
 /*
-               DEB2(printk("does not handle this ioctl.\n"));
+               DEB2(pr_err("does not handle this ioctl\n"));
 */
                return -ENOIOCTLCMD;
        }
@@ -693,7 +699,7 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data
 {
        struct mxb *mxb;
 
-       DEB_EE(("dev:%p\n", dev));
+       DEB_EE("dev:%p\n", dev);
 
        saa7146_vv_init(dev, &vv_data);
        if (mxb_probe(dev)) {
@@ -720,7 +726,7 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data
 #endif
        vv_data.ops.vidioc_default = vidioc_default;
        if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
-               ERR(("cannot register capture v4l2 device. skipping.\n"));
+               ERR("cannot register capture v4l2 device. skipping.\n");
                saa7146_vv_release(dev);
                return -1;
        }
@@ -728,11 +734,11 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data
        /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
        if (MXB_BOARD_CAN_DO_VBI(dev)) {
                if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
-                       ERR(("cannot register vbi v4l2 device. skipping.\n"));
+                       ERR("cannot register vbi v4l2 device. skipping.\n");
                }
        }
 
-       printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
+       pr_info("found Multimedia eXtension Board #%d\n", mxb_num);
 
        mxb_num++;
        mxb_init_done(dev);
@@ -743,7 +749,7 @@ static int mxb_detach(struct saa7146_dev *dev)
 {
        struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
-       DEB_EE(("dev:%p\n", dev));
+       DEB_EE("dev:%p\n", dev);
 
        saa7146_unregister_device(&mxb->video_dev,dev);
        if (MXB_BOARD_CAN_DO_VBI(dev))
@@ -765,7 +771,7 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
        if (V4L2_STD_PAL_I == standard->id) {
                v4l2_std_id std = V4L2_STD_PAL_I;
 
-               DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
+               DEB_D("VIDIOC_S_STD: setting mxb for PAL_I\n");
                /* set the 7146 gpio register -- I don't know what this does exactly */
                saa7146_write(dev, GPIO_CTRL, 0x00404050);
                /* unset the 7111 gpio register -- I don't know what this does exactly */
@@ -774,7 +780,7 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
        } else {
                v4l2_std_id std = V4L2_STD_PAL_BG;
 
-               DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
+               DEB_D("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM\n");
                /* set the 7146 gpio register -- I don't know what this does exactly */
                saa7146_write(dev, GPIO_CTRL, 0x00404050);
                /* set the 7111 gpio register -- I don't know what this does exactly */
@@ -852,7 +858,7 @@ static struct saa7146_extension extension = {
 static int __init mxb_init_module(void)
 {
        if (saa7146_register_extension(&extension)) {
-               DEB_S(("failed to register extension.\n"));
+               DEB_S("failed to register extension\n");
                return -ENODEV;
        }
 
index 35f722a..6cd21cf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for SiliconFile NOON010PC30 CIF (1/11") Image Sensor with ISP
  *
- * Copyright (C) 2010 Samsung Electronics
+ * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd.
  * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
  *
  * Initial register configuration based on a driver authored by
@@ -10,7 +10,7 @@
  * 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 vergsion.
+ * (at your option) any later version.
  */
 
 #include <linux/delay.h>
@@ -131,17 +131,23 @@ static const char * const noon010_supply_name[] = {
 
 struct noon010_info {
        struct v4l2_subdev sd;
+       struct media_pad pad;
        struct v4l2_ctrl_handler hdl;
-       const struct noon010pc30_platform_data *pdata;
+       struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES];
+       u32 gpio_nreset;
+       u32 gpio_nstby;
+
+       /* Protects the struct members below */
+       struct mutex lock;
+
        const struct noon010_format *curr_fmt;
        const struct noon010_frmsize *curr_win;
+       unsigned int apply_new_cfg:1;
+       unsigned int streaming:1;
        unsigned int hflip:1;
        unsigned int vflip:1;
        unsigned int power:1;
        u8 i2c_reg_page;
-       struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES];
-       u32 gpio_nreset;
-       u32 gpio_nstby;
 };
 
 struct i2c_regval {
@@ -292,8 +298,10 @@ static int noon010_power_ctrl(struct v4l2_subdev *sd, bool reset, bool sleep)
        u8 reg = sleep ? 0xF1 : 0xF0;
        int ret = 0;
 
-       if (reset)
+       if (reset) {
                ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02);
+               udelay(20);
+       }
        if (!ret) {
                ret = cam_i2c_write(sd, POWER_CTRL_REG, reg);
                if (reset && !ret)
@@ -313,6 +321,7 @@ static int noon010_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
        return ret;
 }
 
+/* Called with struct noon010_info.lock mutex held */
 static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip)
 {
        struct noon010_info *info = to_noon010(sd);
@@ -340,21 +349,18 @@ static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip)
 static int noon010_set_params(struct v4l2_subdev *sd)
 {
        struct noon010_info *info = to_noon010(sd);
-       int ret;
 
-       if (!info->curr_win)
-               return -EINVAL;
-
-       ret = cam_i2c_write(sd, VDO_CTL_REG(0), info->curr_win->vid_ctl1);
-
-       if (!ret && info->curr_fmt)
-               ret = cam_i2c_write(sd, ISP_CTL_REG(0),
-                               info->curr_fmt->ispctl1_reg);
-       return ret;
+       int ret = cam_i2c_write(sd, VDO_CTL_REG(0),
+                               info->curr_win->vid_ctl1);
+       if (ret)
+               return ret;
+       return cam_i2c_write(sd, ISP_CTL_REG(0),
+                            info->curr_fmt->ispctl1_reg);
 }
 
 /* Find nearest matching image pixel size. */
-static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf)
+static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf,
+                                 const struct noon010_frmsize **size)
 {
        unsigned int min_err = ~0;
        int i = ARRAY_SIZE(noon010_sizes);
@@ -374,11 +380,14 @@ static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf)
        if (match) {
                mf->width  = match->width;
                mf->height = match->height;
+               if (size)
+                       *size = match;
                return 0;
        }
        return -EINVAL;
 }
 
+/* Called with info.lock mutex held */
 static int power_enable(struct noon010_info *info)
 {
        int ret;
@@ -419,6 +428,7 @@ static int power_enable(struct noon010_info *info)
        return 0;
 }
 
+/* Called with info.lock mutex held */
 static int power_disable(struct noon010_info *info)
 {
        int ret;
@@ -448,147 +458,175 @@ static int power_disable(struct noon010_info *info)
 static int noon010_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct v4l2_subdev *sd = to_sd(ctrl);
+       struct noon010_info *info = to_noon010(sd);
+       int ret = 0;
 
        v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
                 __func__, ctrl->id, ctrl->val);
 
+       mutex_lock(&info->lock);
+       /*
+        * If the device is not powered up by the host driver do
+        * not apply any controls to H/W at this time. Instead
+        * the controls will be restored right after power-up.
+        */
+       if (!info->power)
+               goto unlock;
+
        switch (ctrl->id) {
        case V4L2_CID_AUTO_WHITE_BALANCE:
-               return noon010_enable_autowhitebalance(sd, ctrl->val);
+               ret = noon010_enable_autowhitebalance(sd, ctrl->val);
+               break;
        case V4L2_CID_BLUE_BALANCE:
-               return cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val);
+               ret = cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val);
+               break;
        case V4L2_CID_RED_BALANCE:
-               return cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val);
+               ret =  cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val);
+               break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
        }
+unlock:
+       mutex_unlock(&info->lock);
+       return ret;
 }
 
-static int noon010_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
-                           enum v4l2_mbus_pixelcode *code)
+static int noon010_enum_mbus_code(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_fh *fh,
+                                 struct v4l2_subdev_mbus_code_enum *code)
 {
-       if (!code || index >= ARRAY_SIZE(noon010_formats))
+       if (code->index >= ARRAY_SIZE(noon010_formats))
                return -EINVAL;
 
-       *code = noon010_formats[index].code;
+       code->code = noon010_formats[code->index].code;
        return 0;
 }
 
-static int noon010_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+static int noon010_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
 {
        struct noon010_info *info = to_noon010(sd);
-       int ret;
-
-       if (!mf)
-               return -EINVAL;
+       struct v4l2_mbus_framefmt *mf;
 
-       if (!info->curr_win || !info->curr_fmt) {
-               ret = noon010_set_params(sd);
-               if (ret)
-                       return ret;
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+               if (fh) {
+                       mf = v4l2_subdev_get_try_format(fh, 0);
+                       fmt->format = *mf;
+               }
+               return 0;
        }
+       mf = &fmt->format;
 
-       mf->width       = info->curr_win->width;
-       mf->height      = info->curr_win->height;
-       mf->code        = info->curr_fmt->code;
-       mf->colorspace  = info->curr_fmt->colorspace;
-       mf->field       = V4L2_FIELD_NONE;
+       mutex_lock(&info->lock);
+       mf->width = info->curr_win->width;
+       mf->height = info->curr_win->height;
+       mf->code = info->curr_fmt->code;
+       mf->colorspace = info->curr_fmt->colorspace;
+       mf->field = V4L2_FIELD_NONE;
 
+       mutex_unlock(&info->lock);
        return 0;
 }
 
 /* Return nearest media bus frame format. */
-static const struct noon010_format *try_fmt(struct v4l2_subdev *sd,
+static const struct noon010_format *noon010_try_fmt(struct v4l2_subdev *sd,
                                            struct v4l2_mbus_framefmt *mf)
 {
        int i = ARRAY_SIZE(noon010_formats);
 
-       noon010_try_frame_size(mf);
-
-       while (i--)
+       while (--i)
                if (mf->code == noon010_formats[i].code)
                        break;
-
        mf->code = noon010_formats[i].code;
 
        return &noon010_formats[i];
 }
 
-static int noon010_try_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_mbus_framefmt *mf)
-{
-       if (!sd || !mf)
-               return -EINVAL;
-
-       try_fmt(sd, mf);
-       return 0;
-}
-
-static int noon010_s_fmt(struct v4l2_subdev *sd,
-                        struct v4l2_mbus_framefmt *mf)
+static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
 {
        struct noon010_info *info = to_noon010(sd);
+       const struct noon010_frmsize *size = NULL;
+       const struct noon010_format *nf;
+       struct v4l2_mbus_framefmt *mf;
+       int ret = 0;
 
-       if (!sd || !mf)
-               return -EINVAL;
-
-       info->curr_fmt = try_fmt(sd, mf);
+       nf = noon010_try_fmt(sd, &fmt->format);
+       noon010_try_frame_size(&fmt->format, &size);
+       fmt->format.colorspace = V4L2_COLORSPACE_JPEG;
 
-       return noon010_set_params(sd);
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+               if (fh) {
+                       mf = v4l2_subdev_get_try_format(fh, 0);
+                       *mf = fmt->format;
+               }
+               return 0;
+       }
+       mutex_lock(&info->lock);
+       if (!info->streaming) {
+               info->apply_new_cfg = 1;
+               info->curr_fmt = nf;
+               info->curr_win = size;
+       } else {
+               ret = -EBUSY;
+       }
+       mutex_unlock(&info->lock);
+       return ret;
 }
 
+/* Called with struct noon010_info.lock mutex held */
 static int noon010_base_config(struct v4l2_subdev *sd)
 {
-       struct noon010_info *info = to_noon010(sd);
-       int ret;
-
-       ret = noon010_bulk_write_reg(sd, noon010_base_regs);
-       if (!ret) {
-               info->curr_fmt = &noon010_formats[0];
-               info->curr_win = &noon010_sizes[0];
+       int ret = noon010_bulk_write_reg(sd, noon010_base_regs);
+       if (!ret)
                ret = noon010_set_params(sd);
-       }
        if (!ret)
                ret = noon010_set_flip(sd, 1, 0);
-       if (!ret)
-               ret = noon010_power_ctrl(sd, false, false);
 
-       /* sync the handler and the registers state */
-       v4l2_ctrl_handler_setup(&to_noon010(sd)->hdl);
        return ret;
 }
 
 static int noon010_s_power(struct v4l2_subdev *sd, int on)
 {
        struct noon010_info *info = to_noon010(sd);
-       const struct noon010pc30_platform_data *pdata = info->pdata;
-       int ret = 0;
-
-       if (WARN(pdata == NULL, "No platform data!\n"))
-               return -ENOMEM;
+       int ret;
 
+       mutex_lock(&info->lock);
        if (on) {
                ret = power_enable(info);
-               if (ret)
-                       return ret;
-               ret = noon010_base_config(sd);
+               if (!ret)
+                       ret = noon010_base_config(sd);
        } else {
                noon010_power_ctrl(sd, false, true);
                ret = power_disable(info);
-               info->curr_win = NULL;
-               info->curr_fmt = NULL;
        }
+       mutex_unlock(&info->lock);
+
+       /* Restore the controls state */
+       if (!ret && on)
+               ret = v4l2_ctrl_handler_setup(&info->hdl);
 
        return ret;
 }
 
-static int noon010_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *chip)
+static int noon010_s_stream(struct v4l2_subdev *sd, int on)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct noon010_info *info = to_noon010(sd);
+       int ret = 0;
 
-       return v4l2_chip_ident_i2c_client(client, chip,
-                                         V4L2_IDENT_NOON010PC30, 0);
+       mutex_lock(&info->lock);
+       if (!info->streaming != !on) {
+               ret = noon010_power_ctrl(sd, false, !on);
+               if (!ret)
+                       info->streaming = on;
+       }
+       if (!ret && on && info->apply_new_cfg) {
+               ret = noon010_set_params(sd);
+               if (!ret)
+                       info->apply_new_cfg = 0;
+       }
+       mutex_unlock(&info->lock);
+       return ret;
 }
 
 static int noon010_log_status(struct v4l2_subdev *sd)
@@ -599,12 +637,27 @@ static int noon010_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
+static int noon010_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0);
+
+       mf->width = noon010_sizes[0].width;
+       mf->height = noon010_sizes[0].height;
+       mf->code = noon010_formats[0].code;
+       mf->colorspace = V4L2_COLORSPACE_JPEG;
+       mf->field = V4L2_FIELD_NONE;
+       return 0;
+}
+
+static const struct v4l2_subdev_internal_ops noon010_subdev_internal_ops = {
+       .open = noon010_open,
+};
+
 static const struct v4l2_ctrl_ops noon010_ctrl_ops = {
        .s_ctrl = noon010_s_ctrl,
 };
 
 static const struct v4l2_subdev_core_ops noon010_core_ops = {
-       .g_chip_ident   = noon010_g_chip_ident,
        .s_power        = noon010_s_power,
        .g_ctrl         = v4l2_subdev_g_ctrl,
        .s_ctrl         = v4l2_subdev_s_ctrl,
@@ -616,15 +669,19 @@ static const struct v4l2_subdev_core_ops noon010_core_ops = {
        .log_status     = noon010_log_status,
 };
 
-static const struct v4l2_subdev_video_ops noon010_video_ops = {
-       .g_mbus_fmt     = noon010_g_fmt,
-       .s_mbus_fmt     = noon010_s_fmt,
-       .try_mbus_fmt   = noon010_try_fmt,
-       .enum_mbus_fmt  = noon010_enum_fmt,
+static struct v4l2_subdev_pad_ops noon010_pad_ops = {
+       .enum_mbus_code = noon010_enum_mbus_code,
+       .get_fmt        = noon010_get_fmt,
+       .set_fmt        = noon010_set_fmt,
+};
+
+static struct v4l2_subdev_video_ops noon010_video_ops = {
+       .s_stream       = noon010_s_stream,
 };
 
 static const struct v4l2_subdev_ops noon010_ops = {
        .core   = &noon010_core_ops,
+       .pad    = &noon010_pad_ops,
        .video  = &noon010_video_ops,
 };
 
@@ -665,10 +722,14 @@ static int noon010_probe(struct i2c_client *client,
        if (!info)
                return -ENOMEM;
 
+       mutex_init(&info->lock);
        sd = &info->sd;
        strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
        v4l2_i2c_subdev_init(sd, client, &noon010_ops);
 
+       sd->internal_ops = &noon010_subdev_internal_ops;
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
        v4l2_ctrl_handler_init(&info->hdl, 3);
 
        v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
@@ -684,10 +745,11 @@ static int noon010_probe(struct i2c_client *client,
        if (ret)
                goto np_err;
 
-       info->pdata             = client->dev.platform_data;
        info->i2c_reg_page      = -1;
        info->gpio_nreset       = -EINVAL;
        info->gpio_nstby        = -EINVAL;
+       info->curr_fmt          = &noon010_formats[0];
+       info->curr_win          = &noon010_sizes[0];
 
        if (gpio_is_valid(pdata->gpio_nreset)) {
                ret = gpio_request(pdata->gpio_nreset, "NOON010PC30 NRST");
@@ -719,11 +781,17 @@ static int noon010_probe(struct i2c_client *client,
        if (ret)
                goto np_reg_err;
 
+       info->pad.flags = MEDIA_PAD_FL_SOURCE;
+       sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+       ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
+       if (ret < 0)
+               goto np_me_err;
+
        ret = noon010_detect(client, info);
        if (!ret)
                return 0;
 
-       /* the sensor detection failed */
+np_me_err:
        regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply);
 np_reg_err:
        if (gpio_is_valid(info->gpio_nstby))
@@ -754,6 +822,7 @@ static int noon010_remove(struct i2c_client *client)
        if (gpio_is_valid(info->gpio_nstby))
                gpio_free(info->gpio_nstby);
 
+       media_entity_cleanup(&sd->entity);
        kfree(info);
        return 0;
 }
index b3a5ecd..30d8896 100644 (file)
@@ -400,7 +400,6 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout,
 
        ovl->get_overlay_info(ovl, &info);
        info.paddr = addr;
-       info.vaddr = NULL;
        info.width = cropwidth;
        info.height = cropheight;
        info.color_mode = vout->dss_mode;
@@ -1165,12 +1164,17 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
 {
        int ret = 0;
        struct omap_vout_device *vout = fh;
+       struct omap_overlay *ovl;
+       struct omapvideo_info *ovid;
        struct v4l2_window *win = &f->fmt.win;
 
+       ovid = &vout->vid_info;
+       ovl = ovid->overlays[0];
+
        ret = omap_vout_try_window(&vout->fbuf, win);
 
        if (!ret) {
-               if (vout->vid == OMAP_VIDEO1)
+               if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
                        win->global_alpha = 255;
                else
                        win->global_alpha = f->fmt.win.global_alpha;
@@ -1194,8 +1198,8 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
 
        ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win);
        if (!ret) {
-               /* Video1 plane does not support global alpha */
-               if (ovl->id == OMAP_DSS_VIDEO1)
+               /* Video1 plane does not support global alpha on OMAP3 */
+               if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
                        vout->win.global_alpha = 255;
                else
                        vout->win.global_alpha = f->fmt.win.global_alpha;
@@ -1788,7 +1792,9 @@ static int vidioc_s_fbuf(struct file *file, void *fh,
        if (ovl->manager && ovl->manager->get_manager_info &&
                        ovl->manager->set_manager_info) {
                ovl->manager->get_manager_info(ovl->manager, &info);
-               info.alpha_enabled = enable;
+               /* enable this only if there is no zorder cap */
+               if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+                       info.partial_alpha_enabled = enable;
                if (ovl->manager->set_manager_info(ovl->manager, &info))
                        return -EINVAL;
        }
@@ -1820,7 +1826,7 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
        }
        if (ovl->manager && ovl->manager->get_manager_info) {
                ovl->manager->get_manager_info(ovl->manager, &info);
-               if (info.alpha_enabled)
+               if (info.partial_alpha_enabled)
                        a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
        }
 
index b1b3447..e8847e7 100644 (file)
@@ -1,8 +1,6 @@
 # Makefile for OMAP3 ISP driver
 
-ifdef CONFIG_VIDEO_OMAP3_DEBUG
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_VIDEO_OMAP3_DEBUG) += -DDEBUG
 
 omap3-isp-objs += \
        isp.o ispqueue.o ispvideo.o \
index 5cea2bb..678e125 100644 (file)
 #include "isph3a.h"
 #include "isphist.h"
 
+/*
+ * this is provided as an interim solution until omap3isp doesn't need
+ * any omap-specific iommu API
+ */
+#define to_iommu(dev)                                                  \
+       (struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))
+
 static unsigned int autoidle;
 module_param(autoidle, int, 0444);
 MODULE_PARM_DESC(autoidle, "Enable OMAP3ISP AUTOIDLE support");
@@ -732,7 +739,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
        struct media_pad *pad;
        struct v4l2_subdev *subdev;
        unsigned long flags;
-       int ret = 0;
+       int ret;
 
        spin_lock_irqsave(&pipe->lock, flags);
        pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT);
@@ -756,7 +763,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
 
                ret = v4l2_subdev_call(subdev, video, s_stream, mode);
                if (ret < 0 && ret != -ENOIOCTLCMD)
-                       break;
+                       return ret;
 
                if (subdev == &isp->isp_ccdc.subdev) {
                        v4l2_subdev_call(&isp->isp_aewb.subdev, video,
@@ -777,7 +784,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
        if (pipe->do_propagation && mode == ISP_PIPELINE_STREAM_SINGLESHOT)
                atomic_inc(&pipe->frame_number);
 
-       return ret;
+       return 0;
 }
 
 static int isp_pipeline_wait_resizer(struct isp_device *isp)
@@ -1108,7 +1115,7 @@ static void isp_save_ctx(struct isp_device *isp)
 {
        isp_save_context(isp, isp_reg_list);
        if (isp->iommu)
-               iommu_save_ctx(isp->iommu);
+               omap_iommu_save_ctx(isp->iommu);
 }
 
 /*
@@ -1122,7 +1129,7 @@ static void isp_restore_ctx(struct isp_device *isp)
 {
        isp_restore_context(isp, isp_reg_list);
        if (isp->iommu)
-               iommu_restore_ctx(isp->iommu);
+               omap_iommu_restore_ctx(isp->iommu);
        omap3isp_ccdc_restore_context(isp);
        omap3isp_preview_restore_context(isp);
 }
@@ -1975,7 +1982,8 @@ static int isp_remove(struct platform_device *pdev)
        isp_cleanup_modules(isp);
 
        omap3isp_get(isp);
-       iommu_put(isp->iommu);
+       iommu_detach_device(isp->domain, isp->iommu_dev);
+       iommu_domain_free(isp->domain);
        omap3isp_put(isp);
 
        free_irq(isp->irq_num, isp);
@@ -2123,25 +2131,41 @@ static int isp_probe(struct platform_device *pdev)
        }
 
        /* IOMMU */
-       isp->iommu = iommu_get("isp");
-       if (IS_ERR_OR_NULL(isp->iommu)) {
-               isp->iommu = NULL;
+       isp->iommu_dev = omap_find_iommu_device("isp");
+       if (!isp->iommu_dev) {
+               dev_err(isp->dev, "omap_find_iommu_device failed\n");
                ret = -ENODEV;
                goto error_isp;
        }
 
+       /* to be removed once iommu migration is complete */
+       isp->iommu = to_iommu(isp->iommu_dev);
+
+       isp->domain = iommu_domain_alloc(pdev->dev.bus);
+       if (!isp->domain) {
+               dev_err(isp->dev, "can't alloc iommu domain\n");
+               ret = -ENOMEM;
+               goto error_isp;
+       }
+
+       ret = iommu_attach_device(isp->domain, isp->iommu_dev);
+       if (ret) {
+               dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret);
+               goto free_domain;
+       }
+
        /* Interrupt */
        isp->irq_num = platform_get_irq(pdev, 0);
        if (isp->irq_num <= 0) {
                dev_err(isp->dev, "No IRQ resource\n");
                ret = -ENODEV;
-               goto error_isp;
+               goto detach_dev;
        }
 
        if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) {
                dev_err(isp->dev, "Unable to request IRQ\n");
                ret = -EINVAL;
-               goto error_isp;
+               goto detach_dev;
        }
 
        /* Entities */
@@ -2162,8 +2186,11 @@ error_modules:
        isp_cleanup_modules(isp);
 error_irq:
        free_irq(isp->irq_num, isp);
+detach_dev:
+       iommu_detach_device(isp->domain, isp->iommu_dev);
+free_domain:
+       iommu_domain_free(isp->domain);
 error_isp:
-       iommu_put(isp->iommu);
        omap3isp_put(isp);
 error:
        isp_put_clocks(isp);
index 529e582..705946e 100644 (file)
 #ifndef OMAP3_ISP_CORE_H
 #define OMAP3_ISP_CORE_H
 
+#include <media/omap3isp.h>
 #include <media/v4l2-device.h>
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/wait.h>
+#include <linux/iommu.h>
 #include <plat/iommu.h>
 #include <plat/iovmm.h>
 
@@ -94,14 +96,6 @@ enum isp_subclk_resource {
        OMAP3_ISP_SUBCLK_RESIZER        = (1 << 4),
 };
 
-enum isp_interface_type {
-       ISP_INTERFACE_PARALLEL,
-       ISP_INTERFACE_CSI2A_PHY2,
-       ISP_INTERFACE_CCP2B_PHY1,
-       ISP_INTERFACE_CCP2B_PHY2,
-       ISP_INTERFACE_CSI2C_PHY1,
-};
-
 /* ISP: OMAP 34xx ES 1.0 */
 #define ISP_REVISION_1_0               0x10
 /* ISP2: OMAP 34xx ES 2.0, 2.1 and 3.0 */
@@ -130,82 +124,6 @@ struct isp_reg {
        u32 val;
 };
 
-/**
- * struct isp_parallel_platform_data - Parallel interface platform data
- * @data_lane_shift: Data lane shifter
- *             0 - CAMEXT[13:0] -> CAM[13:0]
- *             1 - CAMEXT[13:2] -> CAM[11:0]
- *             2 - CAMEXT[13:4] -> CAM[9:0]
- *             3 - CAMEXT[13:6] -> CAM[7:0]
- * @clk_pol: Pixel clock polarity
- *             0 - Non Inverted, 1 - Inverted
- * @hs_pol: Horizontal synchronization polarity
- *             0 - Active high, 1 - Active low
- * @vs_pol: Vertical synchronization polarity
- *             0 - Active high, 1 - Active low
- * @bridge: CCDC Bridge input control
- *             ISPCTRL_PAR_BRIDGE_DISABLE - Disable
- *             ISPCTRL_PAR_BRIDGE_LENDIAN - Little endian
- *             ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian
- */
-struct isp_parallel_platform_data {
-       unsigned int data_lane_shift:2;
-       unsigned int clk_pol:1;
-       unsigned int hs_pol:1;
-       unsigned int vs_pol:1;
-       unsigned int bridge:4;
-};
-
-/**
- * struct isp_ccp2_platform_data - CCP2 interface platform data
- * @strobe_clk_pol: Strobe/clock polarity
- *             0 - Non Inverted, 1 - Inverted
- * @crc: Enable the cyclic redundancy check
- * @ccp2_mode: Enable CCP2 compatibility mode
- *             0 - MIPI-CSI1 mode, 1 - CCP2 mode
- * @phy_layer: Physical layer selection
- *             ISPCCP2_CTRL_PHY_SEL_CLOCK - Data/clock physical layer
- *             ISPCCP2_CTRL_PHY_SEL_STROBE - Data/strobe physical layer
- * @vpclk_div: Video port output clock control
- */
-struct isp_ccp2_platform_data {
-       unsigned int strobe_clk_pol:1;
-       unsigned int crc:1;
-       unsigned int ccp2_mode:1;
-       unsigned int phy_layer:1;
-       unsigned int vpclk_div:2;
-};
-
-/**
- * struct isp_csi2_platform_data - CSI2 interface platform data
- * @crc: Enable the cyclic redundancy check
- * @vpclk_div: Video port output clock control
- */
-struct isp_csi2_platform_data {
-       unsigned crc:1;
-       unsigned vpclk_div:2;
-};
-
-struct isp_subdev_i2c_board_info {
-       struct i2c_board_info *board_info;
-       int i2c_adapter_id;
-};
-
-struct isp_v4l2_subdevs_group {
-       struct isp_subdev_i2c_board_info *subdevs;
-       enum isp_interface_type interface;
-       union {
-               struct isp_parallel_platform_data parallel;
-               struct isp_ccp2_platform_data ccp2;
-               struct isp_csi2_platform_data csi2;
-       } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */
-};
-
-struct isp_platform_data {
-       struct isp_v4l2_subdevs_group *subdevs;
-       void (*set_constraints)(struct isp_device *isp, bool enable);
-};
-
 struct isp_platform_callback {
        u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
        int (*csiphy_config)(struct isp_csiphy *phy,
@@ -294,7 +212,9 @@ struct isp_device {
        unsigned int sbl_resources;
        unsigned int subclk_resources;
 
-       struct iommu *iommu;
+       struct omap_iommu *iommu;
+       struct iommu_domain *domain;
+       struct device *iommu_dev;
 
        struct isp_platform_callback platform_cb;
 };
index 80796eb..253fdcc 100644 (file)
@@ -366,7 +366,7 @@ static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc,
                dma_unmap_sg(isp->dev, req->iovm->sgt->sgl,
                             req->iovm->sgt->nents, DMA_TO_DEVICE);
        if (req->table)
-               iommu_vfree(isp->iommu, req->table);
+               omap_iommu_vfree(isp->domain, isp->iommu, req->table);
        kfree(req);
 }
 
@@ -438,15 +438,15 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc,
 
                req->enable = 1;
 
-               req->table = iommu_vmalloc(isp->iommu, 0, req->config.size,
-                                          IOMMU_FLAG);
+               req->table = omap_iommu_vmalloc(isp->domain, isp->iommu, 0,
+                                       req->config.size, IOMMU_FLAG);
                if (IS_ERR_VALUE(req->table)) {
                        req->table = 0;
                        ret = -ENOMEM;
                        goto done;
                }
 
-               req->iovm = find_iovm_area(isp->iommu, req->table);
+               req->iovm = omap_find_iovm_area(isp->iommu, req->table);
                if (req->iovm == NULL) {
                        ret = -ENOMEM;
                        goto done;
@@ -462,7 +462,7 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc,
                dma_sync_sg_for_cpu(isp->dev, req->iovm->sgt->sgl,
                                    req->iovm->sgt->nents, DMA_TO_DEVICE);
 
-               table = da_to_va(isp->iommu, req->table);
+               table = omap_da_to_va(isp->iommu, req->table);
                if (copy_from_user(table, config->lsc, req->config.size)) {
                        ret = -EFAULT;
                        goto done;
@@ -731,18 +731,19 @@ static int ccdc_config(struct isp_ccdc_device *ccdc,
 
                        /*
                         * table_new must be 64-bytes aligned, but it's
-                        * already done by iommu_vmalloc().
+                        * already done by omap_iommu_vmalloc().
                         */
                        size = ccdc->fpc.fpnum * 4;
-                       table_new = iommu_vmalloc(isp->iommu, 0, size,
-                                                 IOMMU_FLAG);
+                       table_new = omap_iommu_vmalloc(isp->domain, isp->iommu,
+                                                       0, size, IOMMU_FLAG);
                        if (IS_ERR_VALUE(table_new))
                                return -ENOMEM;
 
-                       if (copy_from_user(da_to_va(isp->iommu, table_new),
+                       if (copy_from_user(omap_da_to_va(isp->iommu, table_new),
                                           (__force void __user *)
                                           ccdc->fpc.fpcaddr, size)) {
-                               iommu_vfree(isp->iommu, table_new);
+                               omap_iommu_vfree(isp->domain, isp->iommu,
+                                                               table_new);
                                return -EFAULT;
                        }
 
@@ -752,7 +753,7 @@ static int ccdc_config(struct isp_ccdc_device *ccdc,
 
                ccdc_configure_fpc(ccdc);
                if (table_old != 0)
-                       iommu_vfree(isp->iommu, table_old);
+                       omap_iommu_vfree(isp->domain, isp->iommu, table_old);
        }
 
        return ccdc_lsc_config(ccdc, ccdc_struct);
@@ -1405,11 +1406,14 @@ static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
 
 static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc)
 {
+       struct isp_pipeline *pipe =
+               to_isp_pipeline(&ccdc->video_out.video.entity);
        struct video_device *vdev = &ccdc->subdev.devnode;
        struct v4l2_event event;
 
        memset(&event, 0, sizeof(event));
-       event.type = V4L2_EVENT_OMAP3ISP_HS_VS;
+       event.type = V4L2_EVENT_FRAME_SYNC;
+       event.u.frame_sync.frame_sequence = atomic_read(&pipe->frame_number);
 
        v4l2_event_queue(vdev, &event);
 }
@@ -1691,7 +1695,11 @@ static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
                                struct v4l2_event_subscription *sub)
 {
-       if (sub->type != V4L2_EVENT_OMAP3ISP_HS_VS)
+       if (sub->type != V4L2_EVENT_FRAME_SYNC)
+               return -EINVAL;
+
+       /* line number is zero at frame start */
+       if (sub->id != 0)
                return -EINVAL;
 
        return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS);
@@ -2287,5 +2295,5 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp)
        ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
 
        if (ccdc->fpc.fpcaddr != 0)
-               iommu_vfree(isp->iommu, ccdc->fpc.fpcaddr);
+               omap_iommu_vfree(isp->domain, isp->iommu, ccdc->fpc.fpcaddr);
 }
index ec9e395..fa1d09b 100644 (file)
@@ -243,9 +243,9 @@ static int ccp2_phyif_config(struct isp_ccp2_device *ccp2,
 
        val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
        if (!(val & ISPCCP2_CTRL_MODE)) {
-               if (pdata->ccp2_mode)
+               if (pdata->ccp2_mode == ISP_CCP2_MODE_CCP2)
                        dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n");
-               if (pdata->phy_layer == ISPCCP2_CTRL_PHY_SEL_STROBE)
+               if (pdata->phy_layer == ISP_CCP2_PHY_DATA_STROBE)
                        /* Strobe mode requires CCP2 */
                        return -EIO;
        }
index 9c31714..9bebb1e 100644 (file)
@@ -867,6 +867,10 @@ int omap3isp_video_queue_qbuf(struct isp_video_queue *queue,
        if (buf->state != ISP_BUF_STATE_IDLE)
                goto done;
 
+       if (vbuf->memory == V4L2_MEMORY_USERPTR &&
+           vbuf->length < buf->vbuf.length)
+               goto done;
+
        if (vbuf->memory == V4L2_MEMORY_USERPTR &&
            vbuf->m.userptr != buf->vbuf.m.userptr) {
                isp_video_buffer_cleanup(buf);
index 8080659..7329055 100644 (file)
@@ -366,7 +366,8 @@ static void isp_stat_bufs_free(struct ispstat *stat)
                                dma_unmap_sg(isp->dev, buf->iovm->sgt->sgl,
                                             buf->iovm->sgt->nents,
                                             DMA_FROM_DEVICE);
-                       iommu_vfree(isp->iommu, buf->iommu_addr);
+                       omap_iommu_vfree(isp->domain, isp->iommu,
+                                                       buf->iommu_addr);
                } else {
                        if (!buf->virt_addr)
                                continue;
@@ -399,8 +400,8 @@ static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size)
                struct iovm_struct *iovm;
 
                WARN_ON(buf->dma_addr);
-               buf->iommu_addr = iommu_vmalloc(isp->iommu, 0, size,
-                                               IOMMU_FLAG);
+               buf->iommu_addr = omap_iommu_vmalloc(isp->domain, isp->iommu, 0,
+                                                       size, IOMMU_FLAG);
                if (IS_ERR((void *)buf->iommu_addr)) {
                        dev_err(stat->isp->dev,
                                 "%s: Can't acquire memory for "
@@ -409,7 +410,7 @@ static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size)
                        return -ENOMEM;
                }
 
-               iovm = find_iovm_area(isp->iommu, buf->iommu_addr);
+               iovm = omap_find_iovm_area(isp->iommu, buf->iommu_addr);
                if (!iovm ||
                    !dma_map_sg(isp->dev, iovm->sgt->sgl, iovm->sgt->nents,
                                DMA_FROM_DEVICE)) {
@@ -418,7 +419,7 @@ static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size)
                }
                buf->iovm = iovm;
 
-               buf->virt_addr = da_to_va(stat->isp->iommu,
+               buf->virt_addr = omap_da_to_va(stat->isp->iommu,
                                          (u32)buf->iommu_addr);
                buf->empty = 1;
                dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated."
index fd965ad..0cb8a9f 100644 (file)
@@ -278,7 +278,8 @@ isp_video_far_end(struct isp_video *video)
  * limits reported by every block in the pipeline.
  *
  * Return 0 if all formats match, or -EPIPE if at least one link is found with
- * different formats on its two ends.
+ * different formats on its two ends or if the pipeline doesn't start with a
+ * video source (either a subdev with no input pad, or a non-subdev entity).
  */
 static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
 {
@@ -329,10 +330,15 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
                 * in the middle of it. */
                shifter_link = subdev == &isp->isp_ccdc.subdev;
 
-               /* Retrieve the source format */
+               /* Retrieve the source format. Return an error if no source
+                * entity can be found, and stop checking the pipeline if the
+                * source entity isn't a subdev.
+                */
                pad = media_entity_remote_source(pad);
-               if (pad == NULL ||
-                   media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+               if (pad == NULL)
+                       return -EPIPE;
+
+               if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
                        break;
 
                subdev = media_entity_to_v4l2_subdev(pad->entity);
@@ -446,7 +452,7 @@ ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen)
        sgt->nents = sglen;
        sgt->orig_nents = sglen;
 
-       da = iommu_vmap(isp->iommu, 0, sgt, IOMMU_FLAG);
+       da = omap_iommu_vmap(isp->domain, isp->iommu, 0, sgt, IOMMU_FLAG);
        if (IS_ERR_VALUE(da))
                kfree(sgt);
 
@@ -462,7 +468,7 @@ static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da)
 {
        struct sg_table *sgt;
 
-       sgt = iommu_vunmap(isp->iommu, (u32)da);
+       sgt = omap_iommu_vunmap(isp->domain, isp->iommu, (u32)da);
        kfree(sgt);
 }
 
@@ -1050,6 +1056,14 @@ error:
                if (video->isp->pdata->set_constraints)
                        video->isp->pdata->set_constraints(video->isp, false);
                media_entity_pipeline_stop(&video->video.entity);
+               /* The DMA queue must be emptied here, otherwise CCDC interrupts
+                * that will get triggered the next time the CCDC is powered up
+                * will try to access buffers that might have been freed but
+                * still present in the DMA queue. This can easily get triggered
+                * if the above omap3isp_pipeline_set_stream() call fails on a
+                * system with a free-running sensor.
+                */
+               INIT_LIST_HEAD(&video->dmaqueue);
                video->queue = NULL;
        }
 
index de2fc14..c17f37d 100644 (file)
@@ -16,7 +16,7 @@ pvrusb2-objs  := pvrusb2-i2c-core.o \
 
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/video
+ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
index e98d382..5a6f24d 100644 (file)
@@ -2993,6 +2993,13 @@ static void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id,
                pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \
        }
 
+int pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw, v4l2_std_id *std)
+{
+       v4l2_device_call_all(&hdw->v4l2_dev, 0,
+                            video, querystd, std);
+       return 0;
+}
+
 /* Execute whatever commands are required to update the state of all the
    sub-devices so that they match our current control values. */
 static void pvr2_subdev_update(struct pvr2_hdw *hdw)
index d7753ae..6654658 100644 (file)
@@ -214,6 +214,9 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *);
 int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std,
                               unsigned int idx);
 
+/* Get the detected video standard */
+int pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw, v4l2_std_id *std);
+
 /* Enable / disable retrieval of CPU firmware or prom contents.  This must
    be enabled before pvr2_hdw_cpufw_get() will function.  Note that doing
    this may prevent the device from running (and leaving this mode may
index e27f8ab..ce7ac45 100644 (file)
@@ -227,6 +227,14 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                break;
        }
 
+       case VIDIOC_QUERYSTD:
+       {
+               v4l2_std_id *std = arg;
+               *std = V4L2_STD_ALL;
+               ret = pvr2_hdw_get_detected_std(hdw, std);
+               break;
+       }
+
        case VIDIOC_G_STD:
        {
                int val = 0;
index 51ca358..360be22 100644 (file)
@@ -745,7 +745,7 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
 /* Videobuf2 operations */
 
 static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
-                               unsigned int *nplanes, unsigned long sizes[],
+                               unsigned int *nplanes, unsigned int sizes[],
                                void *alloc_ctxs[])
 {
        struct pwc_device *pdev = vb2_get_drv_priv(vq);
@@ -816,7 +816,7 @@ static void buffer_queue(struct vb2_buffer *vb)
        spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
 }
 
-static int start_streaming(struct vb2_queue *vq)
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct pwc_device *pdev = vb2_get_drv_priv(vq);
 
index 8c70e64..a10ff6b 100644 (file)
@@ -83,6 +83,7 @@ static const struct v4l2_ctrl_config pwc_contour_cfg = {
        .id     = PWC_CID_CUSTOM(contour),
        .type   = V4L2_CTRL_TYPE_INTEGER,
        .name   = "Contour",
+       .flags  = V4L2_CTRL_FLAG_SLIDER,
        .min    = 0,
        .max    = 63,
        .step   = 1,
@@ -206,8 +207,7 @@ int pwc_init_controls(struct pwc_device *pdev)
        pdev->blue_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
                                V4L2_CID_BLUE_BALANCE, 0, 255, 1, def);
 
-       v4l2_ctrl_auto_cluster(3, &pdev->auto_white_balance, awb_manual,
-                              pdev->auto_white_balance->cur.val == awb_auto);
+       v4l2_ctrl_auto_cluster(3, &pdev->auto_white_balance, awb_manual, true);
 
        /* autogain, gain */
        r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AGC_MODE_FORMATTER, &def);
@@ -331,12 +331,12 @@ int pwc_init_controls(struct pwc_device *pdev)
        pdev->restore_user = v4l2_ctrl_new_custom(hdl, &pwc_restore_user_cfg,
                                                  NULL);
        if (pdev->restore_user)
-               pdev->restore_user->flags = V4L2_CTRL_FLAG_UPDATE;
+               pdev->restore_user->flags |= V4L2_CTRL_FLAG_UPDATE;
        pdev->restore_factory = v4l2_ctrl_new_custom(hdl,
                                                     &pwc_restore_factory_cfg,
                                                     NULL);
        if (pdev->restore_factory)
-               pdev->restore_factory->flags = V4L2_CTRL_FLAG_UPDATE;
+               pdev->restore_factory->flags |= V4L2_CTRL_FLAG_UPDATE;
 
        if (!(pdev->features & FEATURE_MOTOR_PANTILT))
                return hdl->error;
@@ -563,8 +563,10 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 
        switch (ctrl->id) {
        case V4L2_CID_AUTO_WHITE_BALANCE:
-               if (pdev->color_bal_valid && time_before(jiffies,
-                               pdev->last_color_bal_update + HZ / 4)) {
+               if (pdev->color_bal_valid &&
+                       (pdev->auto_white_balance->val != awb_auto ||
+                        time_before(jiffies,
+                               pdev->last_color_bal_update + HZ / 4))) {
                        pdev->red_balance->val  = pdev->last_red_balance;
                        pdev->blue_balance->val = pdev->last_blue_balance;
                        break;
@@ -630,7 +632,7 @@ leave:
 
 static int pwc_set_awb(struct pwc_device *pdev)
 {
-       int ret = 0;
+       int ret;
 
        if (pdev->auto_white_balance->is_new) {
                ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
@@ -639,52 +641,34 @@ static int pwc_set_awb(struct pwc_device *pdev)
                if (ret)
                        return ret;
 
-               /* Update val when coming from auto or going to a preset */
-               if (pdev->red_balance->is_volatile ||
-                   pdev->auto_white_balance->val == awb_indoor ||
-                   pdev->auto_white_balance->val == awb_outdoor ||
-                   pdev->auto_white_balance->val == awb_fl) {
-                       if (!pdev->red_balance->is_new)
-                               pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
-                                       READ_RED_GAIN_FORMATTER,
-                                       &pdev->red_balance->val);
-                       if (!pdev->blue_balance->is_new)
-                               pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
-                                       READ_BLUE_GAIN_FORMATTER,
-                                       &pdev->blue_balance->val);
-               }
-               if (pdev->auto_white_balance->val == awb_auto) {
-                       pdev->red_balance->is_volatile = true;
-                       pdev->blue_balance->is_volatile = true;
+               if (pdev->auto_white_balance->val != awb_manual)
                        pdev->color_bal_valid = false; /* Force cache update */
-               } else {
-                       pdev->red_balance->is_volatile = false;
-                       pdev->blue_balance->is_volatile = false;
-               }
        }
+       if (pdev->auto_white_balance->val != awb_manual)
+               return 0;
 
-       if (ret == 0 && pdev->red_balance->is_new) {
-               if (pdev->auto_white_balance->val != awb_manual)
-                       return -EBUSY;
+       if (pdev->red_balance->is_new) {
                ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
                                      PRESET_MANUAL_RED_GAIN_FORMATTER,
                                      pdev->red_balance->val);
+               if (ret)
+                       return ret;
        }
 
-       if (ret == 0 && pdev->blue_balance->is_new) {
-               if (pdev->auto_white_balance->val != awb_manual)
-                       return -EBUSY;
+       if (pdev->blue_balance->is_new) {
                ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
                                      PRESET_MANUAL_BLUE_GAIN_FORMATTER,
                                      pdev->blue_balance->val);
+               if (ret)
+                       return ret;
        }
-       return ret;
+       return 0;
 }
 
 /* For CODEC2 models which have separate autogain and auto exposure */
 static int pwc_set_autogain(struct pwc_device *pdev)
 {
-       int ret = 0;
+       int ret;
 
        if (pdev->autogain->is_new) {
                ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
@@ -692,27 +676,28 @@ static int pwc_set_autogain(struct pwc_device *pdev)
                                      pdev->autogain->val ? 0 : 0xff);
                if (ret)
                        return ret;
+
                if (pdev->autogain->val)
                        pdev->gain_valid = false; /* Force cache update */
-               else if (!pdev->gain->is_new)
-                       pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
-                                       READ_AGC_FORMATTER,
-                                       &pdev->gain->val);
        }
-       if (ret == 0 && pdev->gain->is_new) {
-               if (pdev->autogain->val)
-                       return -EBUSY;
+
+       if (pdev->autogain->val)
+               return 0;
+
+       if (pdev->gain->is_new) {
                ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
                                      PRESET_AGC_FORMATTER,
                                      pdev->gain->val);
+               if (ret)
+                       return ret;
        }
-       return ret;
+       return 0;
 }
 
 /* For CODEC2 models which have separate autogain and auto exposure */
 static int pwc_set_exposure_auto(struct pwc_device *pdev)
 {
-       int ret = 0;
+       int ret;
        int is_auto = pdev->exposure_auto->val == V4L2_EXPOSURE_AUTO;
 
        if (pdev->exposure_auto->is_new) {
@@ -721,27 +706,28 @@ static int pwc_set_exposure_auto(struct pwc_device *pdev)
                                      is_auto ? 0 : 0xff);
                if (ret)
                        return ret;
+
                if (is_auto)
                        pdev->exposure_valid = false; /* Force cache update */
-               else if (!pdev->exposure->is_new)
-                       pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
-                                        READ_SHUTTER_FORMATTER,
-                                        &pdev->exposure->val);
        }
-       if (ret == 0 && pdev->exposure->is_new) {
-               if (is_auto)
-                       return -EBUSY;
+
+       if (is_auto)
+               return 0;
+
+       if (pdev->exposure->is_new) {
                ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL,
                                       PRESET_SHUTTER_FORMATTER,
                                       pdev->exposure->val);
+               if (ret)
+                       return ret;
        }
-       return ret;
+       return 0;
 }
 
 /* For CODEC3 models which have autogain controlling both gain and exposure */
 static int pwc_set_autogain_expo(struct pwc_device *pdev)
 {
-       int ret = 0;
+       int ret;
 
        if (pdev->autogain->is_new) {
                ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
@@ -749,35 +735,32 @@ static int pwc_set_autogain_expo(struct pwc_device *pdev)
                                      pdev->autogain->val ? 0 : 0xff);
                if (ret)
                        return ret;
+
                if (pdev->autogain->val) {
                        pdev->gain_valid     = false; /* Force cache update */
                        pdev->exposure_valid = false; /* Force cache update */
-               } else {
-                       if (!pdev->gain->is_new)
-                               pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
-                                               READ_AGC_FORMATTER,
-                                               &pdev->gain->val);
-                       if (!pdev->exposure->is_new)
-                               pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
-                                                READ_SHUTTER_FORMATTER,
-                                                &pdev->exposure->val);
                }
        }
-       if (ret == 0 && pdev->gain->is_new) {
-               if (pdev->autogain->val)
-                       return -EBUSY;
+
+       if (pdev->autogain->val)
+               return 0;
+
+       if (pdev->gain->is_new) {
                ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
                                      PRESET_AGC_FORMATTER,
                                      pdev->gain->val);
+               if (ret)
+                       return ret;
        }
-       if (ret == 0 && pdev->exposure->is_new) {
-               if (pdev->autogain->val)
-                       return -EBUSY;
+
+       if (pdev->exposure->is_new) {
                ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL,
                                       PRESET_SHUTTER_FORMATTER,
                                       pdev->exposure->val);
+               if (ret)
+                       return ret;
        }
-       return ret;
+       return 0;
 }
 
 static int pwc_set_motor(struct pwc_device *pdev)
@@ -878,10 +861,6 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
                                        pdev->autocontour->val ? 0 : 0xff);
                }
                if (ret == 0 && pdev->contour->is_new) {
-                       if (pdev->autocontour->val) {
-                               ret = -EBUSY;
-                               break;
-                       }
                        ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
                                              PRESET_CONTOUR_FORMATTER,
                                              pdev->contour->val);
@@ -1099,6 +1078,14 @@ static int pwc_enum_frameintervals(struct file *file, void *fh,
        return 0;
 }
 
+static int pwc_log_status(struct file *file, void *priv)
+{
+       struct pwc_device *pdev = video_drvdata(file);
+
+       v4l2_ctrl_handler_log_status(&pdev->ctrl_handler, PWC_NAME);
+       return 0;
+}
+
 static long pwc_default(struct file *file, void *fh, bool valid_prio,
                        int cmd, void *arg)
 {
@@ -1122,6 +1109,7 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = {
        .vidioc_dqbuf                       = pwc_dqbuf,
        .vidioc_streamon                    = pwc_streamon,
        .vidioc_streamoff                   = pwc_streamoff,
+       .vidioc_log_status                  = pwc_log_status,
        .vidioc_enum_framesizes             = pwc_enum_framesizes,
        .vidioc_enum_frameintervals         = pwc_enum_frameintervals,
        .vidioc_default             = pwc_default,
index df6954a..33dec7f 100644 (file)
@@ -1,4 +1,4 @@
-s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-capture.o
+s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-capture.o fimc-mdevice.o
 s5p-csis-objs := mipi-csis.o
 
 obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS)      += s5p-csis.o
index 0d730e5..931f469 100644 (file)
 #include <linux/bug.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
-#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/list.h>
 #include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/i2c.h>
 
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/videobuf2-core.h>
 #include <media/videobuf2-dma-contig.h>
 
+#include "fimc-mdevice.h"
 #include "fimc-core.h"
 
-static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
-                                           struct s5p_fimc_isp_info *isp_info)
+static int fimc_init_capture(struct fimc_dev *fimc)
 {
-       struct i2c_adapter *i2c_adap;
-       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
-       struct v4l2_subdev *sd = NULL;
-
-       i2c_adap = i2c_get_adapter(isp_info->i2c_bus_num);
-       if (!i2c_adap)
-               return ERR_PTR(-ENOMEM);
-
-       sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap,
-                                      isp_info->board_info, NULL);
-       if (!sd) {
-               v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n");
-               return NULL;
-       }
+       struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+       struct fimc_sensor_info *sensor;
+       unsigned long flags;
+       int ret = 0;
 
-       v4l2_info(&vid_cap->v4l2_dev, "subdevice %s registered successfuly\n",
-               isp_info->board_info->type);
+       if (fimc->pipeline.sensor == NULL || ctx == NULL)
+               return -ENXIO;
+       if (ctx->s_frame.fmt == NULL)
+               return -EINVAL;
 
-       return sd;
-}
+       sensor = v4l2_get_subdev_hostdata(fimc->pipeline.sensor);
 
-static void fimc_subdev_unregister(struct fimc_dev *fimc)
-{
-       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
-       struct i2c_client *client;
+       spin_lock_irqsave(&fimc->slock, flags);
+       fimc_prepare_dma_offset(ctx, &ctx->d_frame);
+       fimc_set_yuv_order(ctx);
 
-       if (vid_cap->input_index < 0)
-               return; /* Subdevice already released or not registered. */
+       fimc_hw_set_camera_polarity(fimc, sensor->pdata);
+       fimc_hw_set_camera_type(fimc, sensor->pdata);
+       fimc_hw_set_camera_source(fimc, sensor->pdata);
+       fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
 
-       if (vid_cap->sd) {
-               v4l2_device_unregister_subdev(vid_cap->sd);
-               client = v4l2_get_subdevdata(vid_cap->sd);
-               i2c_unregister_device(client);
-               i2c_put_adapter(client->adapter);
-               vid_cap->sd = NULL;
+       ret = fimc_set_scaler_info(ctx);
+       if (!ret) {
+               fimc_hw_set_input_path(ctx);
+               fimc_hw_set_prescaler(ctx);
+               fimc_hw_set_mainscaler(ctx);
+               fimc_hw_set_target_format(ctx);
+               fimc_hw_set_rotation(ctx);
+               fimc_hw_set_effect(ctx, false);
+               fimc_hw_set_output_path(ctx);
+               fimc_hw_set_out_dma(ctx);
+               clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
        }
-
-       vid_cap->input_index = -1;
+       spin_unlock_irqrestore(&fimc->slock, flags);
+       return ret;
 }
 
-/**
- * fimc_subdev_attach - attach v4l2_subdev to camera host interface
- *
- * @fimc: FIMC device information
- * @index: index to the array of available subdevices,
- *        -1 for full array search or non negative value
- *        to select specific subdevice
- */
-static int fimc_subdev_attach(struct fimc_dev *fimc, int index)
+static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend)
 {
-       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
-       struct s5p_platform_fimc *pdata = fimc->pdata;
-       struct s5p_fimc_isp_info *isp_info;
-       struct v4l2_subdev *sd;
-       int i;
-
-       for (i = 0; i < pdata->num_clients; ++i) {
-               isp_info = &pdata->isp_info[i];
+       struct fimc_vid_cap *cap = &fimc->vid_cap;
+       struct fimc_vid_buffer *buf;
+       unsigned long flags;
+       bool streaming;
 
-               if (index >= 0 && i != index)
-                       continue;
+       spin_lock_irqsave(&fimc->slock, flags);
+       streaming = fimc->state & (1 << ST_CAPT_ISP_STREAM);
 
-               sd = fimc_subdev_register(fimc, isp_info);
-               if (!IS_ERR_OR_NULL(sd)) {
-                       vid_cap->sd = sd;
-                       vid_cap->input_index = i;
+       fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_SHUT |
+                        1 << ST_CAPT_STREAM | 1 << ST_CAPT_ISP_STREAM);
+       if (!suspend)
+               fimc->state &= ~(1 << ST_CAPT_PEND | 1 << ST_CAPT_SUSPENDED);
 
-                       return 0;
-               }
+       /* Release unused buffers */
+       while (!suspend && !list_empty(&cap->pending_buf_q)) {
+               buf = fimc_pending_queue_pop(cap);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
        }
+       /* If suspending put unused buffers onto pending queue */
+       while (!list_empty(&cap->active_buf_q)) {
+               buf = fimc_active_queue_pop(cap);
+               if (suspend)
+                       fimc_pending_queue_add(cap, buf);
+               else
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+       set_bit(ST_CAPT_SUSPENDED, &fimc->state);
+       spin_unlock_irqrestore(&fimc->slock, flags);
 
-       vid_cap->input_index = -1;
-       vid_cap->sd = NULL;
-       v4l2_err(&vid_cap->v4l2_dev, "fimc%d: sensor attach failed\n",
-                fimc->id);
-       return -ENODEV;
-}
-
-static int fimc_isp_subdev_init(struct fimc_dev *fimc, unsigned int index)
-{
-       struct s5p_fimc_isp_info *isp_info;
-       struct s5p_platform_fimc *pdata = fimc->pdata;
-       int ret;
-
-       if (index >= pdata->num_clients)
-               return -EINVAL;
-
-       isp_info = &pdata->isp_info[index];
-
-       if (isp_info->clk_frequency)
-               clk_set_rate(fimc->clock[CLK_CAM], isp_info->clk_frequency);
-
-       ret = clk_enable(fimc->clock[CLK_CAM]);
-       if (ret)
-               return ret;
-
-       ret = fimc_subdev_attach(fimc, index);
-       if (ret)
-               return ret;
-
-       ret = fimc_hw_set_camera_polarity(fimc, isp_info);
-       if (ret)
-               return ret;
-
-       ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 1);
-       if (!ret)
-               return ret;
-
-       /* enabling power failed so unregister subdev */
-       fimc_subdev_unregister(fimc);
-
-       v4l2_err(&fimc->vid_cap.v4l2_dev, "ISP initialization failed: %d\n",
-                ret);
-
-       return ret;
+       if (streaming)
+               return fimc_pipeline_s_stream(fimc, 0);
+       else
+               return 0;
 }
 
-static int fimc_stop_capture(struct fimc_dev *fimc)
+static int fimc_stop_capture(struct fimc_dev *fimc, bool suspend)
 {
        unsigned long flags;
-       struct fimc_vid_cap *cap;
-       struct fimc_vid_buffer *buf;
-
-       cap = &fimc->vid_cap;
 
        if (!fimc_capture_active(fimc))
                return 0;
@@ -169,81 +120,73 @@ static int fimc_stop_capture(struct fimc_dev *fimc)
 
        wait_event_timeout(fimc->irq_queue,
                           !test_bit(ST_CAPT_SHUT, &fimc->state),
-                          FIMC_SHUTDOWN_TIMEOUT);
-
-       v4l2_subdev_call(cap->sd, video, s_stream, 0);
+                          (2*HZ/10)); /* 200 ms */
 
-       spin_lock_irqsave(&fimc->slock, flags);
-       fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND |
-                        1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM);
+       return fimc_capture_state_cleanup(fimc, suspend);
+}
 
-       fimc->vid_cap.active_buf_cnt = 0;
+/**
+ * fimc_capture_config_update - apply the camera interface configuration
+ *
+ * To be called from within the interrupt handler with fimc.slock
+ * spinlock held. It updates the camera pixel crop, rotation and
+ * image flip in H/W.
+ */
+int fimc_capture_config_update(struct fimc_ctx *ctx)
+{
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       int ret;
 
-       /* Release buffers that were enqueued in the driver by videobuf2. */
-       while (!list_empty(&cap->pending_buf_q)) {
-               buf = pending_queue_pop(cap);
-               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
-       }
+       if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state))
+               return 0;
 
-       while (!list_empty(&cap->active_buf_q)) {
-               buf = active_queue_pop(cap);
-               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       spin_lock(&ctx->slock);
+       fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
+       ret = fimc_set_scaler_info(ctx);
+       if (ret == 0) {
+               fimc_hw_set_prescaler(ctx);
+               fimc_hw_set_mainscaler(ctx);
+               fimc_hw_set_target_format(ctx);
+               fimc_hw_set_rotation(ctx);
+               fimc_prepare_dma_offset(ctx, &ctx->d_frame);
+               fimc_hw_set_out_dma(ctx);
+               set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
        }
-
-       spin_unlock_irqrestore(&fimc->slock, flags);
-
-       dbg("state: 0x%lx", fimc->state);
-       return 0;
+       spin_unlock(&ctx->slock);
+       return ret;
 }
 
-static int start_streaming(struct vb2_queue *q)
+static int start_streaming(struct vb2_queue *q, unsigned int count)
 {
        struct fimc_ctx *ctx = q->drv_priv;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       struct s5p_fimc_isp_info *isp_info;
+       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+       int min_bufs;
        int ret;
 
        fimc_hw_reset(fimc);
+       vid_cap->frame_count = 0;
 
-       ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1);
-       if (ret && ret != -ENOIOCTLCMD)
-               return ret;
-
-       ret = fimc_prepare_config(ctx, ctx->state);
+       ret = fimc_init_capture(fimc);
        if (ret)
-               return ret;
-
-       isp_info = &fimc->pdata->isp_info[fimc->vid_cap.input_index];
-       fimc_hw_set_camera_type(fimc, isp_info);
-       fimc_hw_set_camera_source(fimc, isp_info);
-       fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
+               goto error;
 
-       if (ctx->state & FIMC_PARAMS) {
-               ret = fimc_set_scaler_info(ctx);
-               if (ret) {
-                       err("Scaler setup error");
-                       return ret;
-               }
-               fimc_hw_set_input_path(ctx);
-               fimc_hw_set_prescaler(ctx);
-               fimc_hw_set_mainscaler(ctx);
-               fimc_hw_set_target_format(ctx);
-               fimc_hw_set_rotation(ctx);
-               fimc_hw_set_effect(ctx);
-       }
+       set_bit(ST_CAPT_PEND, &fimc->state);
 
-       fimc_hw_set_output_path(ctx);
-       fimc_hw_set_out_dma(ctx);
+       min_bufs = fimc->vid_cap.reqbufs_count > 1 ? 2 : 1;
 
-       INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q);
-       INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
-       fimc->vid_cap.active_buf_cnt = 0;
-       fimc->vid_cap.frame_count = 0;
-       fimc->vid_cap.buf_index = 0;
+       if (vid_cap->active_buf_cnt >= min_bufs &&
+           !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) {
+               fimc_activate_capture(ctx);
 
-       set_bit(ST_CAPT_PEND, &fimc->state);
+               if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
+                       fimc_pipeline_s_stream(fimc, 1);
+       }
 
        return 0;
+error:
+       fimc_capture_state_cleanup(fimc, false);
+       return ret;
 }
 
 static int stop_streaming(struct vb2_queue *q)
@@ -254,7 +197,46 @@ static int stop_streaming(struct vb2_queue *q)
        if (!fimc_capture_active(fimc))
                return -EINVAL;
 
-       return fimc_stop_capture(fimc);
+       return fimc_stop_capture(fimc, false);
+}
+
+int fimc_capture_suspend(struct fimc_dev *fimc)
+{
+       bool suspend = fimc_capture_busy(fimc);
+
+       int ret = fimc_stop_capture(fimc, suspend);
+       if (ret)
+               return ret;
+       return fimc_pipeline_shutdown(fimc);
+}
+
+static void buffer_queue(struct vb2_buffer *vb);
+
+int fimc_capture_resume(struct fimc_dev *fimc)
+{
+       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+       struct fimc_vid_buffer *buf;
+       int i;
+
+       if (!test_and_clear_bit(ST_CAPT_SUSPENDED, &fimc->state))
+               return 0;
+
+       INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
+       vid_cap->buf_index = 0;
+       fimc_pipeline_initialize(fimc, &fimc->vid_cap.vfd->entity,
+                                false);
+       fimc_init_capture(fimc);
+
+       clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
+
+       for (i = 0; i < vid_cap->reqbufs_count; i++) {
+               if (list_empty(&vid_cap->pending_buf_q))
+                       break;
+               buf = fimc_pending_queue_pop(vid_cap);
+               buffer_queue(&buf->vb);
+       }
+       return 0;
+
 }
 
 static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane)
@@ -265,7 +247,7 @@ static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane)
 }
 
 static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
-                      unsigned int *num_planes, unsigned long sizes[],
+                      unsigned int *num_planes, unsigned int sizes[],
                       void *allocators[])
 {
        struct fimc_ctx *ctx = vq->drv_priv;
@@ -289,21 +271,20 @@ static int buffer_prepare(struct vb2_buffer *vb)
 {
        struct vb2_queue *vq = vb->vb2_queue;
        struct fimc_ctx *ctx = vq->drv_priv;
-       struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev;
        int i;
 
-       if (!ctx->d_frame.fmt || vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+       if (ctx->d_frame.fmt == NULL)
                return -EINVAL;
 
        for (i = 0; i < ctx->d_frame.fmt->memplanes; i++) {
-               unsigned long size = get_plane_size(&ctx->d_frame, i);
+               unsigned long size = ctx->d_frame.payload[i];
 
                if (vb2_plane_size(vb, i) < size) {
-                       v4l2_err(v4l2_dev, "User buffer too small (%ld < %ld)\n",
+                       v4l2_err(ctx->fimc_dev->vid_cap.vfd,
+                                "User buffer too small (%ld < %ld)\n",
                                 vb2_plane_size(vb, i), size);
                        return -EINVAL;
                }
-
                vb2_set_plane_payload(vb, i, size);
        }
 
@@ -312,10 +293,10 @@ static int buffer_prepare(struct vb2_buffer *vb)
 
 static void buffer_queue(struct vb2_buffer *vb)
 {
-       struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       struct fimc_dev *fimc = ctx->fimc_dev;
        struct fimc_vid_buffer *buf
                = container_of(vb, struct fimc_vid_buffer, vb);
+       struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct fimc_dev *fimc = ctx->fimc_dev;
        struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
        unsigned long flags;
        int min_bufs;
@@ -323,15 +304,16 @@ static void buffer_queue(struct vb2_buffer *vb)
        spin_lock_irqsave(&fimc->slock, flags);
        fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr);
 
-       if (!test_bit(ST_CAPT_STREAM, &fimc->state)
-            && vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) {
+       if (!test_bit(ST_CAPT_SUSPENDED, &fimc->state) &&
+           !test_bit(ST_CAPT_STREAM, &fimc->state) &&
+           vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) {
                /* Setup the buffer directly for processing. */
                int buf_id = (vid_cap->reqbufs_count == 1) ? -1 :
                                vid_cap->buf_index;
 
                fimc_hw_set_output_addr(fimc, &buf->paddr, buf_id);
                buf->index = vid_cap->buf_index;
-               active_queue_add(vid_cap, buf);
+               fimc_active_queue_add(vid_cap, buf);
 
                if (++vid_cap->buf_index >= FIMC_MAX_OUT_BUFS)
                        vid_cap->buf_index = 0;
@@ -341,10 +323,17 @@ static void buffer_queue(struct vb2_buffer *vb)
 
        min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1;
 
-       if (vid_cap->active_buf_cnt >= min_bufs &&
-           !test_and_set_bit(ST_CAPT_STREAM, &fimc->state))
+
+       if (vb2_is_streaming(&vid_cap->vbq) &&
+           vid_cap->active_buf_cnt >= min_bufs &&
+           !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) {
                fimc_activate_capture(ctx);
+               spin_unlock_irqrestore(&fimc->slock, flags);
 
+               if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
+                       fimc_pipeline_s_stream(fimc, 1);
+               return;
+       }
        spin_unlock_irqrestore(&fimc->slock, flags);
 }
 
@@ -370,10 +359,40 @@ static struct vb2_ops fimc_capture_qops = {
        .stop_streaming         = stop_streaming,
 };
 
+/**
+ * fimc_capture_ctrls_create - initialize the control handler
+ * Initialize the capture video node control handler and fill it
+ * with the FIMC controls. Inherit any sensor's controls if the
+ * 'user_subdev_api' flag is false (default behaviour).
+ * This function need to be called with the graph mutex held.
+ */
+int fimc_capture_ctrls_create(struct fimc_dev *fimc)
+{
+       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+       int ret;
+
+       if (WARN_ON(vid_cap->ctx == NULL))
+               return -ENXIO;
+       if (vid_cap->ctx->ctrls_rdy)
+               return 0;
+
+       ret = fimc_ctrls_create(vid_cap->ctx);
+       if (ret || vid_cap->user_subdev_api)
+               return ret;
+
+       return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrl_handler,
+                                   fimc->pipeline.sensor->ctrl_handler);
+}
+
+static int fimc_capture_set_default_format(struct fimc_dev *fimc);
+
 static int fimc_capture_open(struct file *file)
 {
        struct fimc_dev *fimc = video_drvdata(file);
-       int ret = 0;
+       int ret = v4l2_fh_open(file);
+
+       if (ret)
+               return ret;
 
        dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
 
@@ -381,17 +400,27 @@ static int fimc_capture_open(struct file *file)
        if (fimc_m2m_active(fimc))
                return -EBUSY;
 
+       set_bit(ST_CAPT_BUSY, &fimc->state);
+       pm_runtime_get_sync(&fimc->pdev->dev);
+
        if (++fimc->vid_cap.refcnt == 1) {
-               ret = fimc_isp_subdev_init(fimc, 0);
-               if (ret) {
+               ret = fimc_pipeline_initialize(fimc,
+                              &fimc->vid_cap.vfd->entity, true);
+               if (ret < 0) {
+                       dev_err(&fimc->pdev->dev,
+                               "Video pipeline initialization failed\n");
+                       pm_runtime_put_sync(&fimc->pdev->dev);
                        fimc->vid_cap.refcnt--;
-                       return -EIO;
+                       v4l2_fh_release(file);
+                       clear_bit(ST_CAPT_BUSY, &fimc->state);
+                       return ret;
                }
-       }
-
-       file->private_data = fimc->vid_cap.ctx;
+               ret = fimc_capture_ctrls_create(fimc);
 
-       return 0;
+               if (!ret && !fimc->vid_cap.user_subdev_api)
+                       ret = fimc_capture_set_default_format(fimc);
+       }
+       return ret;
 }
 
 static int fimc_capture_close(struct file *file)
@@ -401,37 +430,36 @@ static int fimc_capture_close(struct file *file)
        dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
 
        if (--fimc->vid_cap.refcnt == 0) {
-               fimc_stop_capture(fimc);
-               vb2_queue_release(&fimc->vid_cap.vbq);
+               clear_bit(ST_CAPT_BUSY, &fimc->state);
+               fimc_stop_capture(fimc, false);
+               fimc_pipeline_shutdown(fimc);
+               clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
+       }
 
-               v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n");
+       pm_runtime_put(&fimc->pdev->dev);
 
-               v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
-               clk_disable(fimc->clock[CLK_CAM]);
-               fimc_subdev_unregister(fimc);
+       if (fimc->vid_cap.refcnt == 0) {
+               vb2_queue_release(&fimc->vid_cap.vbq);
+               fimc_ctrls_delete(fimc->vid_cap.ctx);
        }
-
-       return 0;
+       return v4l2_fh_release(file);
 }
 
 static unsigned int fimc_capture_poll(struct file *file,
                                      struct poll_table_struct *wait)
 {
-       struct fimc_ctx *ctx = file->private_data;
-       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_dev *fimc = video_drvdata(file);
 
        return vb2_poll(&fimc->vid_cap.vbq, file, wait);
 }
 
 static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct fimc_ctx *ctx = file->private_data;
-       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_dev *fimc = video_drvdata(file);
 
        return vb2_mmap(&fimc->vid_cap.vbq, vma);
 }
 
-/* video device file operations */
 static const struct v4l2_file_operations fimc_capture_fops = {
        .owner          = THIS_MODULE,
        .open           = fimc_capture_open,
@@ -441,263 +469,553 @@ static const struct v4l2_file_operations fimc_capture_fops = {
        .mmap           = fimc_capture_mmap,
 };
 
+/*
+ * Format and crop negotiation helpers
+ */
+
+static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx,
+                                               u32 *width, u32 *height,
+                                               u32 *code, u32 *fourcc, int pad)
+{
+       bool rotation = ctx->rotation == 90 || ctx->rotation == 270;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct samsung_fimc_variant *var = fimc->variant;
+       struct fimc_pix_limit *pl = var->pix_limit;
+       struct fimc_frame *dst = &ctx->d_frame;
+       u32 depth, min_w, max_w, min_h, align_h = 3;
+       u32 mask = FMT_FLAGS_CAM;
+       struct fimc_fmt *ffmt;
+
+       /* Color conversion from/to JPEG is not supported */
+       if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE &&
+           fimc_fmt_is_jpeg(ctx->s_frame.fmt->color))
+               *code = V4L2_MBUS_FMT_JPEG_1X8;
+
+       if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK)
+               mask |= FMT_FLAGS_M2M;
+
+       ffmt = fimc_find_format(fourcc, code, mask, 0);
+       if (WARN_ON(!ffmt))
+               return NULL;
+       if (code)
+               *code = ffmt->mbus_code;
+       if (fourcc)
+               *fourcc = ffmt->fourcc;
+
+       if (pad == FIMC_SD_PAD_SINK) {
+               max_w = fimc_fmt_is_jpeg(ffmt->color) ?
+                       pl->scaler_dis_w : pl->scaler_en_w;
+               /* Apply the camera input interface pixel constraints */
+               v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4,
+                                     height, max_t(u32, *height, 32),
+                                     FIMC_CAMIF_MAX_HEIGHT,
+                                     fimc_fmt_is_jpeg(ffmt->color) ? 3 : 1,
+                                     0);
+               return ffmt;
+       }
+       /* Can't scale or crop in transparent (JPEG) transfer mode */
+       if (fimc_fmt_is_jpeg(ffmt->color)) {
+               *width  = ctx->s_frame.f_width;
+               *height = ctx->s_frame.f_height;
+               return ffmt;
+       }
+       /* Apply the scaler and the output DMA constraints */
+       max_w = rotation ? pl->out_rot_en_w : pl->out_rot_dis_w;
+       min_w = ctx->state & FIMC_DST_CROP ? dst->width : var->min_out_pixsize;
+       min_h = ctx->state & FIMC_DST_CROP ? dst->height : var->min_out_pixsize;
+       if (fimc->id == 1 && var->pix_hoff)
+               align_h = fimc_fmt_is_rgb(ffmt->color) ? 0 : 1;
+
+       depth = fimc_get_format_depth(ffmt);
+       v4l_bound_align_image(width, min_w, max_w,
+                             ffs(var->min_out_pixsize) - 1,
+                             height, min_h, FIMC_CAMIF_MAX_HEIGHT,
+                             align_h,
+                             64/(ALIGN(depth, 8)));
+
+       dbg("pad%d: code: 0x%x, %dx%d. dst fmt: %dx%d",
+           pad, code ? *code : 0, *width, *height,
+           dst->f_width, dst->f_height);
+
+       return ffmt;
+}
+
+static void fimc_capture_try_crop(struct fimc_ctx *ctx, struct v4l2_rect *r,
+                                 int pad)
+{
+       bool rotate = ctx->rotation == 90 || ctx->rotation == 270;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct samsung_fimc_variant *var = fimc->variant;
+       struct fimc_pix_limit *pl = var->pix_limit;
+       struct fimc_frame *sink = &ctx->s_frame;
+       u32 max_w, max_h, min_w = 0, min_h = 0, min_sz;
+       u32 align_sz = 0, align_h = 4;
+       u32 max_sc_h, max_sc_v;
+
+       /* In JPEG transparent transfer mode cropping is not supported */
+       if (fimc_fmt_is_jpeg(ctx->d_frame.fmt->color)) {
+               r->width  = sink->f_width;
+               r->height = sink->f_height;
+               r->left   = r->top = 0;
+               return;
+       }
+       if (pad == FIMC_SD_PAD_SOURCE) {
+               if (ctx->rotation != 90 && ctx->rotation != 270)
+                       align_h = 1;
+               max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3));
+               max_sc_v = min(SCALER_MAX_VRATIO, 1 << (ffs(sink->height) - 1));
+               min_sz = var->min_out_pixsize;
+       } else {
+               u32 depth = fimc_get_format_depth(sink->fmt);
+               align_sz = 64/ALIGN(depth, 8);
+               min_sz = var->min_inp_pixsize;
+               min_w = min_h = min_sz;
+               max_sc_h = max_sc_v = 1;
+       }
+       /*
+        * For the crop rectangle at source pad the following constraints
+        * must be met:
+        * - it must fit in the sink pad format rectangle (f_width/f_height);
+        * - maximum downscaling ratio is 64;
+        * - maximum crop size depends if the rotator is used or not;
+        * - the sink pad format width/height must be 4 multiple of the
+        *   prescaler ratios determined by sink pad size and source pad crop,
+        *   the prescaler ratio is returned by fimc_get_scaler_factor().
+        */
+       max_w = min_t(u32,
+                     rotate ? pl->out_rot_en_w : pl->out_rot_dis_w,
+                     rotate ? sink->f_height : sink->f_width);
+       max_h = min_t(u32, FIMC_CAMIF_MAX_HEIGHT, sink->f_height);
+       if (pad == FIMC_SD_PAD_SOURCE) {
+               min_w = min_t(u32, max_w, sink->f_width / max_sc_h);
+               min_h = min_t(u32, max_h, sink->f_height / max_sc_v);
+               if (rotate) {
+                       swap(max_sc_h, max_sc_v);
+                       swap(min_w, min_h);
+               }
+       }
+       v4l_bound_align_image(&r->width, min_w, max_w, ffs(min_sz) - 1,
+                             &r->height, min_h, max_h, align_h,
+                             align_sz);
+       /* Adjust left/top if cropping rectangle is out of bounds */
+       r->left = clamp_t(u32, r->left, 0, sink->f_width - r->width);
+       r->top  = clamp_t(u32, r->top, 0, sink->f_height - r->height);
+       r->left = round_down(r->left, var->hor_offs_align);
+
+       dbg("pad%d: (%d,%d)/%dx%d, sink fmt: %dx%d",
+           pad, r->left, r->top, r->width, r->height,
+           sink->f_width, sink->f_height);
+}
+
+/*
+ * The video node ioctl operations
+ */
 static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
                                        struct v4l2_capability *cap)
 {
-       struct fimc_ctx *ctx = file->private_data;
-       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_dev *fimc = video_drvdata(file);
 
        strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
        strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
        cap->bus_info[0] = 0;
-       cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
-                           V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+       cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
 
        return 0;
 }
 
-/* Synchronize formats of the camera interface input and attached  sensor. */
-static int sync_capture_fmt(struct fimc_ctx *ctx)
+static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv,
+                                   struct v4l2_fmtdesc *f)
+{
+       struct fimc_fmt *fmt;
+
+       fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM | FMT_FLAGS_M2M,
+                              f->index);
+       if (!fmt)
+               return -EINVAL;
+       strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+       f->pixelformat = fmt->fourcc;
+       if (fmt->fourcc == V4L2_MBUS_FMT_JPEG_1X8)
+               f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+       return 0;
+}
+
+/**
+ * fimc_pipeline_try_format - negotiate and/or set formats at pipeline
+ *                            elements
+ * @ctx: FIMC capture context
+ * @tfmt: media bus format to try/set on subdevs
+ * @fmt_id: fimc pixel format id corresponding to returned @tfmt (output)
+ * @set: true to set format on subdevs, false to try only
+ */
+static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
+                                   struct v4l2_mbus_framefmt *tfmt,
+                                   struct fimc_fmt **fmt_id,
+                                   bool set)
 {
-       struct fimc_frame *frame = &ctx->s_frame;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       struct v4l2_mbus_framefmt *fmt = &fimc->vid_cap.fmt;
-       int ret;
+       struct v4l2_subdev *sd = fimc->pipeline.sensor;
+       struct v4l2_subdev *csis = fimc->pipeline.csis;
+       struct v4l2_subdev_format sfmt;
+       struct v4l2_mbus_framefmt *mf = &sfmt.format;
+       struct fimc_fmt *ffmt = NULL;
+       int ret, i = 0;
+
+       if (WARN_ON(!sd || !tfmt))
+               return -EINVAL;
 
-       fmt->width  = ctx->d_frame.o_width;
-       fmt->height = ctx->d_frame.o_height;
+       memset(&sfmt, 0, sizeof(sfmt));
+       sfmt.format = *tfmt;
+
+       sfmt.which = set ? V4L2_SUBDEV_FORMAT_ACTIVE : V4L2_SUBDEV_FORMAT_TRY;
+       while (1) {
+               ffmt = fimc_find_format(NULL, mf->code != 0 ? &mf->code : NULL,
+                                       FMT_FLAGS_CAM, i++);
+               if (ffmt == NULL) {
+                       /*
+                        * Notify user-space if common pixel code for
+                        * host and sensor does not exist.
+                        */
+                       return -EINVAL;
+               }
+               mf->code = tfmt->code = ffmt->mbus_code;
 
-       ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_mbus_fmt, fmt);
-       if (ret == -ENOIOCTLCMD) {
-               err("s_mbus_fmt failed");
-               return ret;
-       }
-       dbg("w: %d, h: %d, code= %d", fmt->width, fmt->height, fmt->code);
+               ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sfmt);
+               if (ret)
+                       return ret;
+               if (mf->code != tfmt->code) {
+                       mf->code = 0;
+                       continue;
+               }
+               if (mf->width != tfmt->width || mf->width != tfmt->width) {
+                       u32 fcc = ffmt->fourcc;
+                       tfmt->width  = mf->width;
+                       tfmt->height = mf->height;
+                       ffmt = fimc_capture_try_format(ctx,
+                                              &tfmt->width, &tfmt->height,
+                                              NULL, &fcc, FIMC_SD_PAD_SOURCE);
+                       if (ffmt && ffmt->mbus_code)
+                               mf->code = ffmt->mbus_code;
+                       if (mf->width != tfmt->width || mf->width != tfmt->width)
+                               continue;
+                       tfmt->code = mf->code;
+               }
+               if (csis)
+                       ret = v4l2_subdev_call(csis, pad, set_fmt, NULL, &sfmt);
 
-       frame->fmt = find_mbus_format(fmt, FMT_FLAGS_CAM);
-       if (!frame->fmt) {
-               err("fimc source format not found\n");
-               return -EINVAL;
+               if (mf->code == tfmt->code &&
+                   mf->width == tfmt->width && mf->width == tfmt->width)
+                       break;
        }
 
-       frame->f_width  = fmt->width;
-       frame->f_height = fmt->height;
-       frame->width    = fmt->width;
-       frame->height   = fmt->height;
-       frame->o_width  = fmt->width;
-       frame->o_height = fmt->height;
-       frame->offs_h   = 0;
-       frame->offs_v   = 0;
+       if (fmt_id && ffmt)
+               *fmt_id = ffmt;
+       *tfmt = *mf;
 
+       dbg("code: 0x%x, %dx%d, %p", mf->code, mf->width, mf->height, ffmt);
        return 0;
 }
 
-static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
+static int fimc_cap_g_fmt_mplane(struct file *file, void *fh,
                                 struct v4l2_format *f)
 {
-       struct fimc_ctx *ctx = priv;
-       struct fimc_dev *fimc = ctx->fimc_dev;
-       struct fimc_frame *frame;
-       struct v4l2_pix_format_mplane *pix;
-       int ret;
-       int i;
+       struct fimc_dev *fimc = video_drvdata(file);
+       struct fimc_ctx *ctx = fimc->vid_cap.ctx;
 
        if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
                return -EINVAL;
 
-       ret = fimc_vidioc_try_fmt_mplane(file, priv, f);
-       if (ret)
-               return ret;
-
-       if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc))
-               return -EBUSY;
+       return fimc_fill_format(&ctx->d_frame, f);
+}
 
-       frame = &ctx->d_frame;
+static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
+                                  struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+       struct fimc_dev *fimc = video_drvdata(file);
+       struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+       struct v4l2_mbus_framefmt mf;
+       struct fimc_fmt *ffmt = NULL;
 
-       pix = &f->fmt.pix_mp;
-       frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM);
-       if (!frame->fmt) {
-               err("fimc target format not found\n");
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
                return -EINVAL;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+               fimc_capture_try_format(ctx, &pix->width, &pix->height,
+                                       NULL, &pix->pixelformat,
+                                       FIMC_SD_PAD_SINK);
+               ctx->s_frame.f_width  = pix->width;
+               ctx->s_frame.f_height = pix->height;
        }
+       ffmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
+                                      NULL, &pix->pixelformat,
+                                      FIMC_SD_PAD_SOURCE);
+       if (!ffmt)
+               return -EINVAL;
 
-       for (i = 0; i < frame->fmt->colplanes; i++) {
-               frame->payload[i] =
-                       (pix->width * pix->height * frame->fmt->depth[i]) >> 3;
+       if (!fimc->vid_cap.user_subdev_api) {
+               mf.width  = pix->width;
+               mf.height = pix->height;
+               mf.code   = ffmt->mbus_code;
+               fimc_md_graph_lock(fimc);
+               fimc_pipeline_try_format(ctx, &mf, &ffmt, false);
+               fimc_md_graph_unlock(fimc);
+
+               pix->width       = mf.width;
+               pix->height      = mf.height;
+               if (ffmt)
+                       pix->pixelformat = ffmt->fourcc;
        }
 
-       /* Output DMA frame pixel size and offsets. */
-       frame->f_width = pix->plane_fmt[0].bytesperline * 8
-                       / frame->fmt->depth[0];
-       frame->f_height = pix->height;
-       frame->width    = pix->width;
-       frame->height   = pix->height;
-       frame->o_width  = pix->width;
-       frame->o_height = pix->height;
-       frame->offs_h   = 0;
-       frame->offs_v   = 0;
+       fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix);
+       return 0;
+}
 
-       ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT);
+static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, bool jpeg)
+{
+       ctx->scaler.enabled = !jpeg;
+       fimc_ctrls_activate(ctx, !jpeg);
 
-       ret = sync_capture_fmt(ctx);
-       return ret;
+       if (jpeg)
+               set_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state);
+       else
+               clear_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state);
 }
 
-static int fimc_cap_enum_input(struct file *file, void *priv,
-                                    struct v4l2_input *i)
+static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
 {
-       struct fimc_ctx *ctx = priv;
-       struct s5p_platform_fimc *pldata = ctx->fimc_dev->pdata;
-       struct s5p_fimc_isp_info *isp_info;
+       struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+       struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+       struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.mf;
+       struct fimc_frame *ff = &ctx->d_frame;
+       struct fimc_fmt *s_fmt = NULL;
+       int ret, i;
 
-       if (i->index >= pldata->num_clients)
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
                return -EINVAL;
+       if (vb2_is_busy(&fimc->vid_cap.vbq))
+               return -EBUSY;
 
-       isp_info = &pldata->isp_info[i->index];
+       /* Pre-configure format at camera interface input, for JPEG only */
+       if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+               fimc_capture_try_format(ctx, &pix->width, &pix->height,
+                                       NULL, &pix->pixelformat,
+                                       FIMC_SD_PAD_SINK);
+               ctx->s_frame.f_width  = pix->width;
+               ctx->s_frame.f_height = pix->height;
+       }
+       /* Try the format at the scaler and the DMA output */
+       ff->fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
+                                         NULL, &pix->pixelformat,
+                                         FIMC_SD_PAD_SOURCE);
+       if (!ff->fmt)
+               return -EINVAL;
+       /* Try to match format at the host and the sensor */
+       if (!fimc->vid_cap.user_subdev_api) {
+               mf->code   = ff->fmt->mbus_code;
+               mf->width  = pix->width;
+               mf->height = pix->height;
+
+               fimc_md_graph_lock(fimc);
+               ret = fimc_pipeline_try_format(ctx, mf, &s_fmt, true);
+               fimc_md_graph_unlock(fimc);
+               if (ret)
+                       return ret;
+               pix->width  = mf->width;
+               pix->height = mf->height;
+       }
+       fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix);
+       for (i = 0; i < ff->fmt->colplanes; i++)
+               ff->payload[i] =
+                       (pix->width * pix->height * ff->fmt->depth[i]) / 8;
+
+       set_frame_bounds(ff, pix->width, pix->height);
+       /* Reset the composition rectangle if not yet configured */
+       if (!(ctx->state & FIMC_DST_CROP))
+               set_frame_crop(ff, 0, 0, pix->width, pix->height);
+
+       fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ff->fmt->color));
+
+       /* Reset cropping and set format at the camera interface input */
+       if (!fimc->vid_cap.user_subdev_api) {
+               ctx->s_frame.fmt = s_fmt;
+               set_frame_bounds(&ctx->s_frame, pix->width, pix->height);
+               set_frame_crop(&ctx->s_frame, 0, 0, pix->width, pix->height);
+       }
 
-       i->type = V4L2_INPUT_TYPE_CAMERA;
-       strncpy(i->name, isp_info->board_info->type, 32);
-       return 0;
+       return ret;
 }
 
-static int fimc_cap_s_input(struct file *file, void *priv,
-                                 unsigned int i)
+static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
+                                struct v4l2_format *f)
 {
-       struct fimc_ctx *ctx = priv;
-       struct fimc_dev *fimc = ctx->fimc_dev;
-       struct s5p_platform_fimc *pdata = fimc->pdata;
-
-       if (fimc_capture_active(ctx->fimc_dev))
-               return -EBUSY;
+       struct fimc_dev *fimc = video_drvdata(file);
 
-       if (i >= pdata->num_clients)
-               return -EINVAL;
+       return fimc_capture_set_format(fimc, f);
+}
 
+static int fimc_cap_enum_input(struct file *file, void *priv,
+                              struct v4l2_input *i)
+{
+       struct fimc_dev *fimc = video_drvdata(file);
+       struct v4l2_subdev *sd = fimc->pipeline.sensor;
 
-       if (fimc->vid_cap.sd) {
-               int ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
-               if (ret)
-                       err("s_power failed: %d", ret);
+       if (i->index != 0)
+               return -EINVAL;
 
-               clk_disable(fimc->clock[CLK_CAM]);
-       }
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+       if (sd)
+               strlcpy(i->name, sd->name, sizeof(i->name));
+       return 0;
+}
 
-       /* Release the attached sensor subdevice. */
-       fimc_subdev_unregister(fimc);
+static int fimc_cap_s_input(struct file *file, void *priv, unsigned int i)
+{
+       return i == 0 ? i : -EINVAL;
+}
 
-       return fimc_isp_subdev_init(fimc, i);
+static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
 }
 
-static int fimc_cap_g_input(struct file *file, void *priv,
-                                      unsigned int *i)
+/**
+ * fimc_pipeline_validate - check for formats inconsistencies
+ *                          between source and sink pad of each link
+ *
+ * Return 0 if all formats match or -EPIPE otherwise.
+ */
+static int fimc_pipeline_validate(struct fimc_dev *fimc)
 {
-       struct fimc_ctx *ctx = priv;
-       struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+       struct v4l2_subdev_format sink_fmt, src_fmt;
+       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+       struct v4l2_subdev *sd;
+       struct media_pad *pad;
+       int ret;
 
-       *i = cap->input_index;
+       /* Start with the video capture node pad */
+       pad = media_entity_remote_source(&vid_cap->vd_pad);
+       if (pad == NULL)
+               return -EPIPE;
+       /* FIMC.{N} subdevice */
+       sd = media_entity_to_v4l2_subdev(pad->entity);
+
+       while (1) {
+               /* Retrieve format at the sink pad */
+               pad = &sd->entity.pads[0];
+               if (!(pad->flags & MEDIA_PAD_FL_SINK))
+                       break;
+               /* Don't call FIMC subdev operation to avoid nested locking */
+               if (sd == fimc->vid_cap.subdev) {
+                       struct fimc_frame *ff = &vid_cap->ctx->s_frame;
+                       sink_fmt.format.width = ff->f_width;
+                       sink_fmt.format.height = ff->f_height;
+                       sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0;
+               } else {
+                       sink_fmt.pad = pad->index;
+                       sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+                       ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt);
+                       if (ret < 0 && ret != -ENOIOCTLCMD)
+                               return -EPIPE;
+               }
+               /* Retrieve format at the source pad */
+               pad = media_entity_remote_source(pad);
+               if (pad == NULL ||
+                   media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+                       break;
+
+               sd = media_entity_to_v4l2_subdev(pad->entity);
+               src_fmt.pad = pad->index;
+               src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+               ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
+               if (ret < 0 && ret != -ENOIOCTLCMD)
+                       return -EPIPE;
+
+               if (src_fmt.format.width != sink_fmt.format.width ||
+                   src_fmt.format.height != sink_fmt.format.height ||
+                   src_fmt.format.code != sink_fmt.format.code)
+                       return -EPIPE;
+       }
        return 0;
 }
 
 static int fimc_cap_streamon(struct file *file, void *priv,
                             enum v4l2_buf_type type)
 {
-       struct fimc_ctx *ctx = priv;
-       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_dev *fimc = video_drvdata(file);
+       struct fimc_pipeline *p = &fimc->pipeline;
+       int ret;
 
-       if (fimc_capture_active(fimc) || !fimc->vid_cap.sd)
+       if (fimc_capture_active(fimc))
                return -EBUSY;
 
-       if (!(ctx->state & FIMC_DST_FMT)) {
-               v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n");
-               return -EINVAL;
-       }
+       media_entity_pipeline_start(&p->sensor->entity, p->pipe);
 
+       if (fimc->vid_cap.user_subdev_api) {
+               ret = fimc_pipeline_validate(fimc);
+               if (ret)
+                       return ret;
+       }
        return vb2_streamon(&fimc->vid_cap.vbq, type);
 }
 
 static int fimc_cap_streamoff(struct file *file, void *priv,
                            enum v4l2_buf_type type)
 {
-       struct fimc_ctx *ctx = priv;
-       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_dev *fimc = video_drvdata(file);
+       struct v4l2_subdev *sd = fimc->pipeline.sensor;
+       int ret;
 
-       return vb2_streamoff(&fimc->vid_cap.vbq, type);
+       ret = vb2_streamoff(&fimc->vid_cap.vbq, type);
+       if (ret == 0)
+               media_entity_pipeline_stop(&sd->entity);
+       return ret;
 }
 
 static int fimc_cap_reqbufs(struct file *file, void *priv,
                            struct v4l2_requestbuffers *reqbufs)
 {
-       struct fimc_ctx *ctx = priv;
-       struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
-       int ret;
-
+       struct fimc_dev *fimc = video_drvdata(file);
+       int ret = vb2_reqbufs(&fimc->vid_cap.vbq, reqbufs);
 
-       ret = vb2_reqbufs(&cap->vbq, reqbufs);
        if (!ret)
-               cap->reqbufs_count = reqbufs->count;
-
+               fimc->vid_cap.reqbufs_count = reqbufs->count;
        return ret;
 }
 
 static int fimc_cap_querybuf(struct file *file, void *priv,
                           struct v4l2_buffer *buf)
 {
-       struct fimc_ctx *ctx = priv;
-       struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+       struct fimc_dev *fimc = video_drvdata(file);
 
-       return vb2_querybuf(&cap->vbq, buf);
+       return vb2_querybuf(&fimc->vid_cap.vbq, buf);
 }
 
 static int fimc_cap_qbuf(struct file *file, void *priv,
                          struct v4l2_buffer *buf)
 {
-       struct fimc_ctx *ctx = priv;
-       struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
-       return vb2_qbuf(&cap->vbq, buf);
+       struct fimc_dev *fimc = video_drvdata(file);
+
+       return vb2_qbuf(&fimc->vid_cap.vbq, buf);
 }
 
 static int fimc_cap_dqbuf(struct file *file, void *priv,
                           struct v4l2_buffer *buf)
 {
-       struct fimc_ctx *ctx = priv;
-       return vb2_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf,
-               file->f_flags & O_NONBLOCK);
-}
-
-static int fimc_cap_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctrl)
-{
-       struct fimc_ctx *ctx = priv;
-       int ret = -EINVAL;
+       struct fimc_dev *fimc = video_drvdata(file);
 
-       /* Allow any controls but 90/270 rotation while streaming */
-       if (!fimc_capture_active(ctx->fimc_dev) ||
-           ctrl->id != V4L2_CID_ROTATE ||
-           (ctrl->value != 90 && ctrl->value != 270)) {
-               ret = check_ctrl_val(ctx, ctrl);
-               if (!ret) {
-                       ret = fimc_s_ctrl(ctx, ctrl);
-                       if (!ret)
-                               ctx->state |= FIMC_PARAMS;
-               }
-       }
-       if (ret == -EINVAL)
-               ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
-                                      core, s_ctrl, ctrl);
-       return ret;
+       return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK);
 }
 
 static int fimc_cap_cropcap(struct file *file, void *fh,
                            struct v4l2_cropcap *cr)
 {
-       struct fimc_frame *f;
-       struct fimc_ctx *ctx = fh;
+       struct fimc_dev *fimc = video_drvdata(file);
+       struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
 
        if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
                return -EINVAL;
 
-       f = &ctx->s_frame;
-
        cr->bounds.left         = 0;
        cr->bounds.top          = 0;
        cr->bounds.width        = f->o_width;
@@ -709,10 +1027,8 @@ static int fimc_cap_cropcap(struct file *file, void *fh,
 
 static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
 {
-       struct fimc_frame *f;
-       struct fimc_ctx *ctx = file->private_data;
-
-       f = &ctx->s_frame;
+       struct fimc_dev *fimc = video_drvdata(file);
+       struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
 
        cr->c.left      = f->offs_h;
        cr->c.top       = f->offs_v;
@@ -722,53 +1038,31 @@ static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
        return 0;
 }
 
-static int fimc_cap_s_crop(struct file *file, void *fh,
-                              struct v4l2_crop *cr)
+static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
 {
-       struct fimc_frame *f;
-       struct fimc_ctx *ctx = file->private_data;
-       struct fimc_dev *fimc = ctx->fimc_dev;
-       int ret = -EINVAL;
-
-       if (fimc_capture_active(fimc))
-               return -EBUSY;
-
-       ret = fimc_try_crop(ctx, cr);
-       if (ret)
-               return ret;
-
-       if (!(ctx->state & FIMC_DST_FMT)) {
-               v4l2_err(&fimc->vid_cap.v4l2_dev,
-                        "Capture color format not set\n");
-               return -EINVAL; /* TODO: make sure this is the right value */
-       }
+       struct fimc_dev *fimc = video_drvdata(file);
+       struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+       struct fimc_frame *ff;
+       unsigned long flags;
 
-       f = &ctx->s_frame;
-       /* Check for the pixel scaling ratio when cropping input image. */
-       ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height,
-                                     ctx->d_frame.width, ctx->d_frame.height,
-                                     ctx->rotation);
-       if (ret) {
-               v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range\n");
-               return ret;
-       }
+       fimc_capture_try_crop(ctx, &cr->c, FIMC_SD_PAD_SINK);
+       ff = &ctx->s_frame;
 
-       f->offs_h = cr->c.left;
-       f->offs_v = cr->c.top;
-       f->width  = cr->c.width;
-       f->height = cr->c.height;
+       spin_lock_irqsave(&fimc->slock, flags);
+       set_frame_crop(ff, cr->c.left, cr->c.top, cr->c.width, cr->c.height);
+       set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+       spin_unlock_irqrestore(&fimc->slock, flags);
 
        return 0;
 }
 
-
 static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
        .vidioc_querycap                = fimc_vidioc_querycap_capture,
 
-       .vidioc_enum_fmt_vid_cap_mplane = fimc_vidioc_enum_fmt_mplane,
-       .vidioc_try_fmt_vid_cap_mplane  = fimc_vidioc_try_fmt_mplane,
+       .vidioc_enum_fmt_vid_cap_mplane = fimc_cap_enum_fmt_mplane,
+       .vidioc_try_fmt_vid_cap_mplane  = fimc_cap_try_fmt_mplane,
        .vidioc_s_fmt_vid_cap_mplane    = fimc_cap_s_fmt_mplane,
-       .vidioc_g_fmt_vid_cap_mplane    = fimc_vidioc_g_fmt_mplane,
+       .vidioc_g_fmt_vid_cap_mplane    = fimc_cap_g_fmt_mplane,
 
        .vidioc_reqbufs                 = fimc_cap_reqbufs,
        .vidioc_querybuf                = fimc_cap_querybuf,
@@ -779,10 +1073,6 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
        .vidioc_streamon                = fimc_cap_streamon,
        .vidioc_streamoff               = fimc_cap_streamoff,
 
-       .vidioc_queryctrl               = fimc_vidioc_queryctrl,
-       .vidioc_g_ctrl                  = fimc_vidioc_g_ctrl,
-       .vidioc_s_ctrl                  = fimc_cap_s_ctrl,
-
        .vidioc_g_crop                  = fimc_cap_g_crop,
        .vidioc_s_crop                  = fimc_cap_s_crop,
        .vidioc_cropcap                 = fimc_cap_cropcap,
@@ -792,17 +1082,328 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
        .vidioc_g_input                 = fimc_cap_g_input,
 };
 
+/* Capture subdev media entity operations */
+static int fimc_link_setup(struct media_entity *entity,
+                          const struct media_pad *local,
+                          const struct media_pad *remote, u32 flags)
+{
+       struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+       struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+
+       if (media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+               return -EINVAL;
+
+       if (WARN_ON(fimc == NULL))
+               return 0;
+
+       dbg("%s --> %s, flags: 0x%x. input: 0x%x",
+           local->entity->name, remote->entity->name, flags,
+           fimc->vid_cap.input);
+
+       if (flags & MEDIA_LNK_FL_ENABLED) {
+               if (fimc->vid_cap.input != 0)
+                       return -EBUSY;
+               fimc->vid_cap.input = sd->grp_id;
+               return 0;
+       }
+
+       fimc->vid_cap.input = 0;
+       return 0;
+}
+
+static const struct media_entity_operations fimc_sd_media_ops = {
+       .link_setup = fimc_link_setup,
+};
+
+/**
+ * fimc_sensor_notify - v4l2_device notification from a sensor subdev
+ * @sd: pointer to a subdev generating the notification
+ * @notification: the notification type, must be S5P_FIMC_TX_END_NOTIFY
+ * @arg: pointer to an u32 type integer that stores the frame payload value
+ *
+ * The End Of Frame notification sent by sensor subdev in its still capture
+ * mode. If there is only a single VSYNC generated by the sensor at the
+ * beginning of a frame transmission, FIMC does not issue the LastIrq
+ * (end of frame) interrupt. And this notification is used to complete the
+ * frame capture and returning a buffer to user-space. Subdev drivers should
+ * call this notification from their last 'End of frame capture' interrupt.
+ */
+void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
+                       void *arg)
+{
+       struct fimc_sensor_info *sensor;
+       struct fimc_vid_buffer *buf;
+       struct fimc_md *fmd;
+       struct fimc_dev *fimc;
+       unsigned long flags;
+
+       if (sd == NULL)
+               return;
+
+       sensor = v4l2_get_subdev_hostdata(sd);
+       fmd = entity_to_fimc_mdev(&sd->entity);
+
+       spin_lock_irqsave(&fmd->slock, flags);
+       fimc = sensor ? sensor->host : NULL;
+
+       if (fimc && arg && notification == S5P_FIMC_TX_END_NOTIFY &&
+           test_bit(ST_CAPT_PEND, &fimc->state)) {
+               unsigned long irq_flags;
+               spin_lock_irqsave(&fimc->slock, irq_flags);
+               if (!list_empty(&fimc->vid_cap.active_buf_q)) {
+                       buf = list_entry(fimc->vid_cap.active_buf_q.next,
+                                        struct fimc_vid_buffer, list);
+                       vb2_set_plane_payload(&buf->vb, 0, *((u32 *)arg));
+               }
+               fimc_capture_irq_handler(fimc, true);
+               fimc_deactivate_capture(fimc);
+               spin_unlock_irqrestore(&fimc->slock, irq_flags);
+       }
+       spin_unlock_irqrestore(&fmd->slock, flags);
+}
+
+static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+                                     struct v4l2_subdev_fh *fh,
+                                     struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct fimc_fmt *fmt;
+
+       fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, code->index);
+       if (!fmt)
+               return -EINVAL;
+       code->code = fmt->mbus_code;
+       return 0;
+}
+
+static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
+                              struct v4l2_subdev_fh *fh,
+                              struct v4l2_subdev_format *fmt)
+{
+       struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+       struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+       struct v4l2_mbus_framefmt *mf;
+       struct fimc_frame *ff;
+
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+               mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+               fmt->format = *mf;
+               return 0;
+       }
+       mf = &fmt->format;
+       mf->colorspace = V4L2_COLORSPACE_JPEG;
+       ff = fmt->pad == FIMC_SD_PAD_SINK ? &ctx->s_frame : &ctx->d_frame;
+
+       mutex_lock(&fimc->lock);
+       /* The pixel code is same on both input and output pad */
+       if (!WARN_ON(ctx->s_frame.fmt == NULL))
+               mf->code = ctx->s_frame.fmt->mbus_code;
+       mf->width  = ff->f_width;
+       mf->height = ff->f_height;
+       mutex_unlock(&fimc->lock);
+
+       return 0;
+}
+
+static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
+                              struct v4l2_subdev_fh *fh,
+                              struct v4l2_subdev_format *fmt)
+{
+       struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *mf = &fmt->format;
+       struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+       struct fimc_frame *ff;
+       struct fimc_fmt *ffmt;
+
+       dbg("pad%d: code: 0x%x, %dx%d",
+           fmt->pad, mf->code, mf->width, mf->height);
+
+       if (fmt->pad == FIMC_SD_PAD_SOURCE &&
+           vb2_is_busy(&fimc->vid_cap.vbq))
+               return -EBUSY;
+
+       mutex_lock(&fimc->lock);
+       ffmt = fimc_capture_try_format(ctx, &mf->width, &mf->height,
+                                      &mf->code, NULL, fmt->pad);
+       mutex_unlock(&fimc->lock);
+       mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+               mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+               *mf = fmt->format;
+               return 0;
+       }
+       fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color));
+
+       ff = fmt->pad == FIMC_SD_PAD_SINK ?
+               &ctx->s_frame : &ctx->d_frame;
+
+       mutex_lock(&fimc->lock);
+       set_frame_bounds(ff, mf->width, mf->height);
+       ff->fmt = ffmt;
+
+       /* Reset the crop rectangle if required. */
+       if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_DST_CROP)))
+               set_frame_crop(ff, 0, 0, mf->width, mf->height);
+
+       if (fmt->pad == FIMC_SD_PAD_SINK)
+               ctx->state &= ~FIMC_DST_CROP;
+       mutex_unlock(&fimc->lock);
+       return 0;
+}
+
+static int fimc_subdev_get_crop(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_fh *fh,
+                               struct v4l2_subdev_crop *crop)
+{
+       struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+       struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+       struct v4l2_rect *r = &crop->rect;
+       struct fimc_frame *ff;
+
+       if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
+               crop->rect = *v4l2_subdev_get_try_crop(fh, crop->pad);
+               return 0;
+       }
+       ff = crop->pad == FIMC_SD_PAD_SINK ?
+               &ctx->s_frame : &ctx->d_frame;
+
+       mutex_lock(&fimc->lock);
+       r->left   = ff->offs_h;
+       r->top    = ff->offs_v;
+       r->width  = ff->width;
+       r->height = ff->height;
+       mutex_unlock(&fimc->lock);
+
+       dbg("ff:%p, pad%d: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d",
+           ff, crop->pad, r->left, r->top, r->width, r->height,
+           ff->f_width, ff->f_height);
+
+       return 0;
+}
+
+static int fimc_subdev_set_crop(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_fh *fh,
+                               struct v4l2_subdev_crop *crop)
+{
+       struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+       struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+       struct v4l2_rect *r = &crop->rect;
+       struct fimc_frame *ff;
+       unsigned long flags;
+
+       dbg("(%d,%d)/%dx%d", r->left, r->top, r->width, r->height);
+
+       ff = crop->pad == FIMC_SD_PAD_SOURCE ?
+               &ctx->d_frame : &ctx->s_frame;
+
+       mutex_lock(&fimc->lock);
+       fimc_capture_try_crop(ctx, r, crop->pad);
+
+       if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
+               mutex_lock(&fimc->lock);
+               *v4l2_subdev_get_try_crop(fh, crop->pad) = *r;
+               return 0;
+       }
+       spin_lock_irqsave(&fimc->slock, flags);
+       set_frame_crop(ff, r->left, r->top, r->width, r->height);
+       if (crop->pad == FIMC_SD_PAD_SOURCE)
+               ctx->state |= FIMC_DST_CROP;
+
+       set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+       spin_unlock_irqrestore(&fimc->slock, flags);
+
+       dbg("pad%d: (%d,%d)/%dx%d", crop->pad, r->left, r->top,
+           r->width, r->height);
+
+       mutex_unlock(&fimc->lock);
+       return 0;
+}
+
+static struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = {
+       .enum_mbus_code = fimc_subdev_enum_mbus_code,
+       .get_fmt = fimc_subdev_get_fmt,
+       .set_fmt = fimc_subdev_set_fmt,
+       .get_crop = fimc_subdev_get_crop,
+       .set_crop = fimc_subdev_set_crop,
+};
+
+static struct v4l2_subdev_ops fimc_subdev_ops = {
+       .pad = &fimc_subdev_pad_ops,
+};
+
+static int fimc_create_capture_subdev(struct fimc_dev *fimc,
+                                     struct v4l2_device *v4l2_dev)
+{
+       struct v4l2_subdev *sd;
+       int ret;
+
+       sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+       if (!sd)
+               return -ENOMEM;
+
+       v4l2_subdev_init(sd, &fimc_subdev_ops);
+       sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+       snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->pdev->id);
+
+       fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+       ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
+                               fimc->vid_cap.sd_pads, 0);
+       if (ret)
+               goto me_err;
+       ret = v4l2_device_register_subdev(v4l2_dev, sd);
+       if (ret)
+               goto sd_err;
+
+       fimc->vid_cap.subdev = sd;
+       v4l2_set_subdevdata(sd, fimc);
+       sd->entity.ops = &fimc_sd_media_ops;
+       return 0;
+sd_err:
+       media_entity_cleanup(&sd->entity);
+me_err:
+       kfree(sd);
+       return ret;
+}
+
+static void fimc_destroy_capture_subdev(struct fimc_dev *fimc)
+{
+       struct v4l2_subdev *sd = fimc->vid_cap.subdev;
+
+       if (!sd)
+               return;
+       media_entity_cleanup(&sd->entity);
+       v4l2_device_unregister_subdev(sd);
+       kfree(sd);
+       sd = NULL;
+}
+
+/* Set default format at the sensor and host interface */
+static int fimc_capture_set_default_format(struct fimc_dev *fimc)
+{
+       struct v4l2_format fmt = {
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+               .fmt.pix_mp = {
+                       .width          = 640,
+                       .height         = 480,
+                       .pixelformat    = V4L2_PIX_FMT_YUYV,
+                       .field          = V4L2_FIELD_NONE,
+                       .colorspace     = V4L2_COLORSPACE_JPEG,
+               },
+       };
+
+       return fimc_capture_set_format(fimc, &fmt);
+}
+
 /* fimc->lock must be already initialized */
-int fimc_register_capture_device(struct fimc_dev *fimc)
+int fimc_register_capture_device(struct fimc_dev *fimc,
+                                struct v4l2_device *v4l2_dev)
 {
-       struct v4l2_device *v4l2_dev = &fimc->vid_cap.v4l2_dev;
        struct video_device *vfd;
        struct fimc_vid_cap *vid_cap;
        struct fimc_ctx *ctx;
-       struct v4l2_format f;
-       struct fimc_frame *fr;
        struct vb2_queue *q;
-       int ret;
+       int ret = -ENOMEM;
 
        ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
        if (!ctx)
@@ -812,33 +1413,21 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
        ctx->in_path     = FIMC_CAMERA;
        ctx->out_path    = FIMC_DMA;
        ctx->state       = FIMC_CTX_CAP;
-
-       /* Default format of the output frames */
-       f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
-       fr = &ctx->d_frame;
-       fr->fmt = find_format(&f, FMT_FLAGS_M2M);
-       fr->width = fr->f_width = fr->o_width = 640;
-       fr->height = fr->f_height = fr->o_height = 480;
-
-       if (!v4l2_dev->name[0])
-               snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
-                        "%s.capture", dev_name(&fimc->pdev->dev));
-
-       ret = v4l2_device_register(NULL, v4l2_dev);
-       if (ret)
-               goto err_info;
+       ctx->s_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);
+       ctx->d_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);
 
        vfd = video_device_alloc();
        if (!vfd) {
                v4l2_err(v4l2_dev, "Failed to allocate video device\n");
-               goto err_v4l2_reg;
+               goto err_vd_alloc;
        }
 
-       snprintf(vfd->name, sizeof(vfd->name), "%s:cap",
+       snprintf(vfd->name, sizeof(vfd->name), "%s.capture",
                 dev_name(&fimc->pdev->dev));
 
        vfd->fops       = &fimc_capture_fops;
        vfd->ioctl_ops  = &fimc_capture_ioctl_ops;
+       vfd->v4l2_dev   = v4l2_dev;
        vfd->minor      = -1;
        vfd->release    = video_device_release;
        vfd->lock       = &fimc->lock;
@@ -849,8 +1438,6 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
        vid_cap->active_buf_cnt = 0;
        vid_cap->reqbufs_count  = 0;
        vid_cap->refcnt = 0;
-       /* Default color format for image sensor */
-       vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
 
        INIT_LIST_HEAD(&vid_cap->pending_buf_q);
        INIT_LIST_HEAD(&vid_cap->active_buf_q);
@@ -868,34 +1455,37 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
 
        vb2_queue_init(q);
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
-       if (ret) {
-               v4l2_err(v4l2_dev, "Failed to register video device\n");
-               goto err_vd_reg;
-       }
-
-       v4l2_info(v4l2_dev,
-                 "FIMC capture driver registered as /dev/video%d\n",
-                 vfd->num);
+       fimc->vid_cap.vd_pad.flags = MEDIA_PAD_FL_SINK;
+       ret = media_entity_init(&vfd->entity, 1, &fimc->vid_cap.vd_pad, 0);
+       if (ret)
+               goto err_ent;
+       ret = fimc_create_capture_subdev(fimc, v4l2_dev);
+       if (ret)
+               goto err_sd_reg;
 
+       vfd->ctrl_handler = &ctx->ctrl_handler;
        return 0;
 
-err_vd_reg:
+err_sd_reg:
+       media_entity_cleanup(&vfd->entity);
+err_ent:
        video_device_release(vfd);
-err_v4l2_reg:
-       v4l2_device_unregister(v4l2_dev);
-err_info:
+err_vd_alloc:
        kfree(ctx);
-       dev_err(&fimc->pdev->dev, "failed to install\n");
        return ret;
 }
 
 void fimc_unregister_capture_device(struct fimc_dev *fimc)
 {
-       struct fimc_vid_cap *capture = &fimc->vid_cap;
-
-       if (capture->vfd)
-               video_unregister_device(capture->vfd);
+       struct video_device *vfd = fimc->vid_cap.vfd;
 
-       kfree(capture->ctx);
+       if (vfd) {
+               media_entity_cleanup(&vfd->entity);
+               /* Can also be called if video device was
+                  not registered */
+               video_unregister_device(vfd);
+       }
+       fimc_destroy_capture_subdev(fimc);
+       kfree(fimc->vid_cap.ctx);
+       fimc->vid_cap.ctx = NULL;
 }
index aa55066..6c1c9cb 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/list.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <media/videobuf2-dma-contig.h>
 
 #include "fimc-core.h"
+#include "fimc-mdevice.h"
 
 static char *fimc_clocks[MAX_FIMC_CLOCKS] = {
-       "sclk_fimc", "fimc", "sclk_cam"
+       "sclk_fimc", "fimc"
 };
 
 static struct fimc_fmt fimc_formats[] = {
@@ -157,59 +159,28 @@ static struct fimc_fmt fimc_formats[] = {
                .memplanes      = 2,
                .colplanes      = 2,
                .flags          = FMT_FLAGS_M2M,
-       },
-};
-
-static struct v4l2_queryctrl fimc_ctrls[] = {
-       {
-               .id             = V4L2_CID_HFLIP,
-               .type           = V4L2_CTRL_TYPE_BOOLEAN,
-               .name           = "Horizontal flip",
-               .minimum        = 0,
-               .maximum        = 1,
-               .default_value  = 0,
        }, {
-               .id             = V4L2_CID_VFLIP,
-               .type           = V4L2_CTRL_TYPE_BOOLEAN,
-               .name           = "Vertical flip",
-               .minimum        = 0,
-               .maximum        = 1,
-               .default_value  = 0,
-       }, {
-               .id             = V4L2_CID_ROTATE,
-               .type           = V4L2_CTRL_TYPE_INTEGER,
-               .name           = "Rotation (CCW)",
-               .minimum        = 0,
-               .maximum        = 270,
-               .step           = 90,
-               .default_value  = 0,
+               .name           = "JPEG encoded data",
+               .fourcc         = V4L2_PIX_FMT_JPEG,
+               .color          = S5P_FIMC_JPEG,
+               .depth          = { 8 },
+               .memplanes      = 1,
+               .colplanes      = 1,
+               .mbus_code      = V4L2_MBUS_FMT_JPEG_1X8,
+               .flags          = FMT_FLAGS_CAM,
        },
 };
 
-
-static struct v4l2_queryctrl *get_ctrl(int id)
+int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
+                           int dw, int dh, int rotation)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(fimc_ctrls); ++i)
-               if (id == fimc_ctrls[i].id)
-                       return &fimc_ctrls[i];
-       return NULL;
-}
+       if (rotation == 90 || rotation == 270)
+               swap(dw, dh);
 
-int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot)
-{
-       int tx, ty;
-
-       if (rot == 90 || rot == 270) {
-               ty = dw;
-               tx = dh;
-       } else {
-               tx = dw;
-               ty = dh;
-       }
+       if (!ctx->scaler.enabled)
+               return (sw == dw && sh == dh) ? 0 : -EINVAL;
 
-       if ((sw >= SCALER_MAX_HRATIO * tx) || (sh >= SCALER_MAX_VRATIO * ty))
+       if ((sw >= SCALER_MAX_HRATIO * dw) || (sh >= SCALER_MAX_VRATIO * dh))
                return -EINVAL;
 
        return 0;
@@ -235,10 +206,11 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
 
 int fimc_set_scaler_info(struct fimc_ctx *ctx)
 {
+       struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+       struct device *dev = &ctx->fimc_dev->pdev->dev;
        struct fimc_scaler *sc = &ctx->scaler;
        struct fimc_frame *s_frame = &ctx->s_frame;
        struct fimc_frame *d_frame = &ctx->d_frame;
-       struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
        int tx, ty, sx, sy;
        int ret;
 
@@ -250,15 +222,14 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx)
                ty = d_frame->height;
        }
        if (tx <= 0 || ty <= 0) {
-               v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
-                       "invalid target size: %d x %d", tx, ty);
+               dev_err(dev, "Invalid target size: %dx%d", tx, ty);
                return -EINVAL;
        }
 
        sx = s_frame->width;
        sy = s_frame->height;
        if (sx <= 0 || sy <= 0) {
-               err("invalid source size: %d x %d", sx, sy);
+               dev_err(dev, "Invalid source size: %dx%d", sx, sy);
                return -EINVAL;
        }
        sc->real_width = sx;
@@ -301,7 +272,6 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx)
 static void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
 {
        struct vb2_buffer *src_vb, *dst_vb;
-       struct fimc_dev *fimc = ctx->fimc_dev;
 
        if (!ctx || !ctx->m2m_ctx)
                return;
@@ -312,54 +282,68 @@ static void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
        if (src_vb && dst_vb) {
                v4l2_m2m_buf_done(src_vb, vb_state);
                v4l2_m2m_buf_done(dst_vb, vb_state);
-               v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx);
+               v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev,
+                                   ctx->m2m_ctx);
        }
 }
 
 /* Complete the transaction which has been scheduled for execution. */
-static void fimc_m2m_shutdown(struct fimc_ctx *ctx)
+static int fimc_m2m_shutdown(struct fimc_ctx *ctx)
 {
        struct fimc_dev *fimc = ctx->fimc_dev;
        int ret;
 
        if (!fimc_m2m_pending(fimc))
-               return;
+               return 0;
 
        fimc_ctx_state_lock_set(FIMC_CTX_SHUT, ctx);
 
        ret = wait_event_timeout(fimc->irq_queue,
                           !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx),
                           FIMC_SHUTDOWN_TIMEOUT);
-       /*
-        * In case of a timeout the buffers are not released in the interrupt
-        * handler so return them here with the error flag set, if there are
-        * any on the queue.
-        */
-       if (ret == 0)
-               fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+
+       return ret == 0 ? -ETIMEDOUT : ret;
+}
+
+static int start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct fimc_ctx *ctx = q->drv_priv;
+       int ret;
+
+       ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev);
+       return ret > 0 ? 0 : ret;
 }
 
 static int stop_streaming(struct vb2_queue *q)
 {
        struct fimc_ctx *ctx = q->drv_priv;
+       int ret;
 
-       fimc_m2m_shutdown(ctx);
+       ret = fimc_m2m_shutdown(ctx);
+       if (ret == -ETIMEDOUT)
+               fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
 
+       pm_runtime_put(&ctx->fimc_dev->pdev->dev);
        return 0;
 }
 
-static void fimc_capture_irq_handler(struct fimc_dev *fimc)
+void fimc_capture_irq_handler(struct fimc_dev *fimc, bool final)
 {
        struct fimc_vid_cap *cap = &fimc->vid_cap;
        struct fimc_vid_buffer *v_buf;
        struct timeval *tv;
        struct timespec ts;
 
+       if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
+               wake_up(&fimc->irq_queue);
+               return;
+       }
+
        if (!list_empty(&cap->active_buf_q) &&
-           test_bit(ST_CAPT_RUN, &fimc->state)) {
+           test_bit(ST_CAPT_RUN, &fimc->state) && final) {
                ktime_get_real_ts(&ts);
 
-               v_buf = active_queue_pop(cap);
+               v_buf = fimc_active_queue_pop(cap);
 
                tv = &v_buf->vb.v4l2_buf.timestamp;
                tv->tv_sec = ts.tv_sec;
@@ -369,19 +353,14 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc)
                vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE);
        }
 
-       if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
-               wake_up(&fimc->irq_queue);
-               return;
-       }
-
        if (!list_empty(&cap->pending_buf_q)) {
 
-               v_buf = pending_queue_pop(cap);
+               v_buf = fimc_pending_queue_pop(cap);
                fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
                v_buf->index = cap->buf_index;
 
                /* Move the buffer to the capture active queue */
-               active_queue_add(cap, v_buf);
+               fimc_active_queue_add(cap, v_buf);
 
                dbg("next frame: %d, done frame: %d",
                    fimc_hw_get_frame_index(fimc), v_buf->index);
@@ -391,7 +370,8 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc)
        }
 
        if (cap->active_buf_cnt == 0) {
-               clear_bit(ST_CAPT_RUN, &fimc->state);
+               if (final)
+                       clear_bit(ST_CAPT_RUN, &fimc->state);
 
                if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
                        cap->buf_index = 0;
@@ -399,11 +379,13 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc)
                set_bit(ST_CAPT_RUN, &fimc->state);
        }
 
+       fimc_capture_config_update(cap->ctx);
+
        dbg("frame: %d, active_buf_cnt: %d",
            fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
 }
 
-static irqreturn_t fimc_isr(int irq, void *priv)
+static irqreturn_t fimc_irq_handler(int irq, void *priv)
 {
        struct fimc_dev *fimc = priv;
        struct fimc_vid_cap *cap = &fimc->vid_cap;
@@ -411,9 +393,17 @@ static irqreturn_t fimc_isr(int irq, void *priv)
 
        fimc_hw_clear_irq(fimc);
 
+       spin_lock(&fimc->slock);
+
        if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) {
+               if (test_and_clear_bit(ST_M2M_SUSPENDING, &fimc->state)) {
+                       set_bit(ST_M2M_SUSPENDED, &fimc->state);
+                       wake_up(&fimc->irq_queue);
+                       goto out;
+               }
                ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev);
                if (ctx != NULL) {
+                       spin_unlock(&fimc->slock);
                        fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
 
                        spin_lock(&ctx->slock);
@@ -423,21 +413,16 @@ static irqreturn_t fimc_isr(int irq, void *priv)
                        }
                        spin_unlock(&ctx->slock);
                }
-
                return IRQ_HANDLED;
-       }
-
-       spin_lock(&fimc->slock);
-
-       if (test_bit(ST_CAPT_PEND, &fimc->state)) {
-               fimc_capture_irq_handler(fimc);
-
+       } else if (test_bit(ST_CAPT_PEND, &fimc->state)) {
+               fimc_capture_irq_handler(fimc,
+                                !test_bit(ST_CAPT_JPEG, &fimc->state));
                if (cap->active_buf_cnt == 1) {
                        fimc_deactivate_capture(fimc);
                        clear_bit(ST_CAPT_STREAM, &fimc->state);
                }
        }
-
+out:
        spin_unlock(&fimc->slock);
        return IRQ_HANDLED;
 }
@@ -457,7 +442,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
        dbg("memplanes= %d, colplanes= %d, pix_size= %d",
                frame->fmt->memplanes, frame->fmt->colplanes, pix_size);
 
-       paddr->y = vb2_dma_contig_plane_paddr(vb, 0);
+       paddr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
 
        if (frame->fmt->memplanes == 1) {
                switch (frame->fmt->colplanes) {
@@ -485,10 +470,10 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
                }
        } else {
                if (frame->fmt->memplanes >= 2)
-                       paddr->cb = vb2_dma_contig_plane_paddr(vb, 1);
+                       paddr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
 
                if (frame->fmt->memplanes == 3)
-                       paddr->cr = vb2_dma_contig_plane_paddr(vb, 2);
+                       paddr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
        }
 
        dbg("PHYS_ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
@@ -498,7 +483,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
 }
 
 /* Set order for 1 and 2 plane YCBCR 4:2:2 formats. */
-static void fimc_set_yuv_order(struct fimc_ctx *ctx)
+void fimc_set_yuv_order(struct fimc_ctx *ctx)
 {
        /* The one only mode supported in SoC. */
        ctx->in_order_2p = S5P_FIMC_LSB_CRCB;
@@ -540,7 +525,7 @@ static void fimc_set_yuv_order(struct fimc_ctx *ctx)
        dbg("ctx->out_order_1p= %d", ctx->out_order_1p);
 }
 
-static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
+void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
 {
        struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
        u32 i, depth = 0;
@@ -606,9 +591,6 @@ int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
                fimc_set_yuv_order(ctx);
        }
 
-       /* Input DMA mode is not allowed when the scaler is disabled. */
-       ctx->scaler.enabled = 1;
-
        if (flags & FIMC_SRC_ADDR) {
                vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
                ret = fimc_prepare_addr(ctx, vb, s_frame, &s_frame->paddr);
@@ -635,10 +617,10 @@ static void fimc_dma_run(void *priv)
                return;
 
        fimc = ctx->fimc_dev;
-
-       spin_lock_irqsave(&ctx->slock, flags);
+       spin_lock_irqsave(&fimc->slock, flags);
        set_bit(ST_M2M_PEND, &fimc->state);
 
+       spin_lock(&ctx->slock);
        ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR);
        ret = fimc_prepare_config(ctx, ctx->state);
        if (ret)
@@ -649,8 +631,6 @@ static void fimc_dma_run(void *priv)
                ctx->state |= FIMC_PARAMS;
                fimc->m2m.ctx = ctx;
        }
-
-       spin_lock(&fimc->slock);
        fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr);
 
        if (ctx->state & FIMC_PARAMS) {
@@ -665,7 +645,7 @@ static void fimc_dma_run(void *priv)
                fimc_hw_set_mainscaler(ctx);
                fimc_hw_set_target_format(ctx);
                fimc_hw_set_rotation(ctx);
-               fimc_hw_set_effect(ctx);
+               fimc_hw_set_effect(ctx, false);
        }
 
        fimc_hw_set_output_path(ctx);
@@ -680,10 +660,9 @@ static void fimc_dma_run(void *priv)
        ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP |
                       FIMC_SRC_FMT | FIMC_DST_FMT);
        fimc_hw_activate_input_dma(fimc, true);
-       spin_unlock(&fimc->slock);
-
 dma_unlock:
-       spin_unlock_irqrestore(&ctx->slock, flags);
+       spin_unlock(&ctx->slock);
+       spin_unlock_irqrestore(&fimc->slock, flags);
 }
 
 static void fimc_job_abort(void *priv)
@@ -692,7 +671,7 @@ static void fimc_job_abort(void *priv)
 }
 
 static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
-                           unsigned int *num_planes, unsigned long sizes[],
+                           unsigned int *num_planes, unsigned int sizes[],
                            void *allocators[])
 {
        struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
@@ -762,146 +741,296 @@ static struct vb2_ops fimc_qops = {
        .wait_prepare    = fimc_unlock,
        .wait_finish     = fimc_lock,
        .stop_streaming  = stop_streaming,
+       .start_streaming = start_streaming,
 };
 
-static int fimc_m2m_querycap(struct file *file, void *priv,
-                          struct v4l2_capability *cap)
+/*
+ * V4L2 controls handling
+ */
+#define ctrl_to_ctx(__ctrl) \
+       container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler)
+
+static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct fimc_ctx *ctx = file->private_data;
+       struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct samsung_fimc_variant *variant = fimc->variant;
+       unsigned long flags;
+       int ret = 0;
+
+       if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_HFLIP:
+               spin_lock_irqsave(&ctx->slock, flags);
+               ctx->hflip = ctrl->val;
+               break;
+
+       case V4L2_CID_VFLIP:
+               spin_lock_irqsave(&ctx->slock, flags);
+               ctx->vflip = ctrl->val;
+               break;
+
+       case V4L2_CID_ROTATE:
+               if (fimc_capture_pending(fimc) ||
+                   fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
+                       ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
+                                       ctx->s_frame.height, ctx->d_frame.width,
+                                       ctx->d_frame.height, ctrl->val);
+               }
+               if (ret) {
+                       v4l2_err(fimc->m2m.vfd, "Out of scaler range\n");
+                       return -EINVAL;
+               }
+               if ((ctrl->val == 90 || ctrl->val == 270) &&
+                   !variant->has_out_rot)
+                       return -EINVAL;
+               spin_lock_irqsave(&ctx->slock, flags);
+               ctx->rotation = ctrl->val;
+               break;
+
+       default:
+               v4l2_err(fimc->v4l2_dev, "Invalid control: 0x%X\n", ctrl->id);
+               return -EINVAL;
+       }
+       ctx->state |= FIMC_PARAMS;
+       set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+       spin_unlock_irqrestore(&ctx->slock, flags);
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
+       .s_ctrl = fimc_s_ctrl,
+};
+
+int fimc_ctrls_create(struct fimc_ctx *ctx)
+{
+       if (ctx->ctrls_rdy)
+               return 0;
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+
+       ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
+                                    V4L2_CID_HFLIP, 0, 1, 1, 0);
+       ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
+                                   V4L2_CID_VFLIP, 0, 1, 1, 0);
+       ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
+                                   V4L2_CID_ROTATE, 0, 270, 90, 0);
+       ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
+
+       return ctx->ctrl_handler.error;
+}
+
+void fimc_ctrls_delete(struct fimc_ctx *ctx)
+{
+       if (ctx->ctrls_rdy) {
+               v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+               ctx->ctrls_rdy = false;
+       }
+}
+
+void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
+{
+       if (!ctx->ctrls_rdy)
+               return;
+
+       mutex_lock(&ctx->ctrl_handler.lock);
+       v4l2_ctrl_activate(ctx->ctrl_rotate, active);
+       v4l2_ctrl_activate(ctx->ctrl_hflip, active);
+       v4l2_ctrl_activate(ctx->ctrl_vflip, active);
+
+       if (active) {
+               ctx->rotation = ctx->ctrl_rotate->val;
+               ctx->hflip    = ctx->ctrl_hflip->val;
+               ctx->vflip    = ctx->ctrl_vflip->val;
+       } else {
+               ctx->rotation = 0;
+               ctx->hflip    = 0;
+               ctx->vflip    = 0;
+       }
+       mutex_unlock(&ctx->ctrl_handler.lock);
+}
+
+/*
+ * V4L2 ioctl handlers
+ */
+static int fimc_m2m_querycap(struct file *file, void *fh,
+                            struct v4l2_capability *cap)
+{
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
        struct fimc_dev *fimc = ctx->fimc_dev;
 
        strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
        strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
        cap->bus_info[0] = 0;
        cap->capabilities = V4L2_CAP_STREAMING |
-               V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
                V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
 
        return 0;
 }
 
-int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
-                               struct v4l2_fmtdesc *f)
+static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
+                                   struct v4l2_fmtdesc *f)
 {
        struct fimc_fmt *fmt;
 
-       if (f->index >= ARRAY_SIZE(fimc_formats))
+       fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_M2M, f->index);
+       if (!fmt)
                return -EINVAL;
 
-       fmt = &fimc_formats[f->index];
        strncpy(f->description, fmt->name, sizeof(f->description) - 1);
        f->pixelformat = fmt->fourcc;
-
        return 0;
 }
 
-int fimc_vidioc_g_fmt_mplane(struct file *file, void *priv,
-                            struct v4l2_format *f)
+int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f)
 {
-       struct fimc_ctx *ctx = priv;
-       struct fimc_frame *frame;
-       struct v4l2_pix_format_mplane *pixm;
+       struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
        int i;
 
-       frame = ctx_get_frame(ctx, f->type);
-       if (IS_ERR(frame))
-               return PTR_ERR(frame);
-
-       pixm = &f->fmt.pix_mp;
-
-       pixm->width             = frame->width;
-       pixm->height            = frame->height;
-       pixm->field             = V4L2_FIELD_NONE;
-       pixm->pixelformat       = frame->fmt->fourcc;
-       pixm->colorspace        = V4L2_COLORSPACE_JPEG;
-       pixm->num_planes        = frame->fmt->memplanes;
+       pixm->width = frame->o_width;
+       pixm->height = frame->o_height;
+       pixm->field = V4L2_FIELD_NONE;
+       pixm->pixelformat = frame->fmt->fourcc;
+       pixm->colorspace = V4L2_COLORSPACE_JPEG;
+       pixm->num_planes = frame->fmt->memplanes;
 
        for (i = 0; i < pixm->num_planes; ++i) {
-               int bpl = frame->o_width;
-
+               int bpl = frame->f_width;
                if (frame->fmt->colplanes == 1) /* packed formats */
                        bpl = (bpl * frame->fmt->depth[0]) / 8;
-
                pixm->plane_fmt[i].bytesperline = bpl;
-
                pixm->plane_fmt[i].sizeimage = (frame->o_width *
                        frame->o_height * frame->fmt->depth[i]) / 8;
        }
-
        return 0;
 }
 
-struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask)
+void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f)
 {
-       struct fimc_fmt *fmt;
-       unsigned int i;
+       struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+
+       frame->f_width  = pixm->plane_fmt[0].bytesperline;
+       if (frame->fmt->colplanes == 1)
+               frame->f_width = (frame->f_width * 8) / frame->fmt->depth[0];
+       frame->f_height = pixm->height;
+       frame->width    = pixm->width;
+       frame->height   = pixm->height;
+       frame->o_width  = pixm->width;
+       frame->o_height = pixm->height;
+       frame->offs_h   = 0;
+       frame->offs_v   = 0;
+}
 
-       for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
-               fmt = &fimc_formats[i];
-               if (fmt->fourcc == f->fmt.pix_mp.pixelformat &&
-                  (fmt->flags & mask))
-                       break;
+/**
+ * fimc_adjust_mplane_format - adjust bytesperline/sizeimage for each plane
+ * @fmt: fimc pixel format description (input)
+ * @width: requested pixel width
+ * @height: requested pixel height
+ * @pix: multi-plane format to adjust
+ */
+void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
+                              struct v4l2_pix_format_mplane *pix)
+{
+       u32 bytesperline = 0;
+       int i;
+
+       pix->colorspace = V4L2_COLORSPACE_JPEG;
+       pix->field = V4L2_FIELD_NONE;
+       pix->num_planes = fmt->memplanes;
+       pix->height = height;
+       pix->width = width;
+
+       for (i = 0; i < pix->num_planes; ++i) {
+               u32 bpl = pix->plane_fmt[i].bytesperline;
+               u32 *sizeimage = &pix->plane_fmt[i].sizeimage;
+
+               if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width))
+                       bpl = pix->width; /* Planar */
+
+               if (fmt->colplanes == 1 && /* Packed */
+                   (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width))
+                       bpl = (pix->width * fmt->depth[0]) / 8;
+
+               if (i == 0) /* Same bytesperline for each plane. */
+                       bytesperline = bpl;
+
+               pix->plane_fmt[i].bytesperline = bytesperline;
+               *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8;
        }
+}
 
-       return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt;
+static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh,
+                                struct v4l2_format *f)
+{
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
+       struct fimc_frame *frame = ctx_get_frame(ctx, f->type);
+
+       if (IS_ERR(frame))
+               return PTR_ERR(frame);
+
+       return fimc_fill_format(frame, f);
 }
 
-struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
-                                 unsigned int mask)
+/**
+ * fimc_find_format - lookup fimc color format by fourcc or media bus format
+ * @pixelformat: fourcc to match, ignored if null
+ * @mbus_code: media bus code to match, ignored if null
+ * @mask: the color flags to match
+ * @index: offset in the fimc_formats array, ignored if negative
+ */
+struct fimc_fmt *fimc_find_format(u32 *pixelformat, u32 *mbus_code,
+                                 unsigned int mask, int index)
 {
-       struct fimc_fmt *fmt;
+       struct fimc_fmt *fmt, *def_fmt = NULL;
        unsigned int i;
+       int id = 0;
+
+       if (index >= ARRAY_SIZE(fimc_formats))
+               return NULL;
 
        for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
                fmt = &fimc_formats[i];
-               if (fmt->mbus_code == f->code && (fmt->flags & mask))
-                       break;
+               if (!(fmt->flags & mask))
+                       continue;
+               if (pixelformat && fmt->fourcc == *pixelformat)
+                       return fmt;
+               if (mbus_code && fmt->mbus_code == *mbus_code)
+                       return fmt;
+               if (index == id)
+                       def_fmt = fmt;
+               id++;
        }
-
-       return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt;
+       return def_fmt;
 }
 
-
-int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv,
-                              struct v4l2_format *f)
+static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
 {
-       struct fimc_ctx *ctx = priv;
        struct fimc_dev *fimc = ctx->fimc_dev;
        struct samsung_fimc_variant *variant = fimc->variant;
        struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
        struct fimc_fmt *fmt;
-       u32 max_width, mod_x, mod_y, mask;
-       int i, is_output = 0;
-
+       u32 max_w, mod_x, mod_y;
 
-       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx))
-                       return -EINVAL;
-               is_output = 1;
-       } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+       if (!IS_M2M(f->type))
                return -EINVAL;
-       }
 
        dbg("w: %d, h: %d", pix->width, pix->height);
 
-       mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM;
-       fmt = find_format(f, mask);
-       if (!fmt) {
-               v4l2_err(&fimc->m2m.v4l2_dev, "Fourcc format (0x%X) invalid.\n",
-                        pix->pixelformat);
+       fmt = fimc_find_format(&pix->pixelformat, NULL, FMT_FLAGS_M2M, 0);
+       if (WARN(fmt == NULL, "Pixel format lookup failed"))
                return -EINVAL;
-       }
 
        if (pix->field == V4L2_FIELD_ANY)
                pix->field = V4L2_FIELD_NONE;
-       else if (V4L2_FIELD_NONE != pix->field)
+       else if (pix->field != V4L2_FIELD_NONE)
                return -EINVAL;
 
-       if (is_output) {
-               max_width = variant->pix_limit->scaler_dis_w;
+       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               max_w = variant->pix_limit->scaler_dis_w;
                mod_x = ffs(variant->min_inp_pixsize) - 1;
        } else {
-               max_width = variant->pix_limit->out_rot_dis_w;
+               max_w = variant->pix_limit->out_rot_dis_w;
                mod_x = ffs(variant->min_out_pixsize) - 1;
        }
 
@@ -914,70 +1043,52 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv,
                else
                        mod_y = mod_x;
        }
+       dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_w);
 
-       dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_width);
-
-       v4l_bound_align_image(&pix->width, 16, max_width, mod_x,
+       v4l_bound_align_image(&pix->width, 16, max_w, mod_x,
                &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
 
-       pix->num_planes = fmt->memplanes;
-       pix->colorspace = V4L2_COLORSPACE_JPEG;
-
-
-       for (i = 0; i < pix->num_planes; ++i) {
-               u32 bpl = pix->plane_fmt[i].bytesperline;
-               u32 *sizeimage = &pix->plane_fmt[i].sizeimage;
-
-               if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width))
-                       bpl = pix->width; /* Planar */
-
-               if (fmt->colplanes == 1 && /* Packed */
-                   (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width))
-                       bpl = (pix->width * fmt->depth[0]) / 8;
-
-               if (i == 0) /* Same bytesperline for each plane. */
-                       mod_x = bpl;
+       fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp);
+       return 0;
+}
 
-               pix->plane_fmt[i].bytesperline = mod_x;
-               *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8;
-       }
+static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh,
+                                  struct v4l2_format *f)
+{
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
 
-       return 0;
+       return fimc_try_fmt_mplane(ctx, f);
 }
 
-static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv,
+static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
                                 struct v4l2_format *f)
 {
-       struct fimc_ctx *ctx = priv;
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
        struct fimc_dev *fimc = ctx->fimc_dev;
        struct vb2_queue *vq;
        struct fimc_frame *frame;
        struct v4l2_pix_format_mplane *pix;
        int i, ret = 0;
 
-       ret = fimc_vidioc_try_fmt_mplane(file, priv, f);
+       ret = fimc_try_fmt_mplane(ctx, f);
        if (ret)
                return ret;
 
        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
 
        if (vb2_is_busy(vq)) {
-               v4l2_err(&fimc->m2m.v4l2_dev, "queue (%d) busy\n", f->type);
+               v4l2_err(fimc->m2m.vfd, "queue (%d) busy\n", f->type);
                return -EBUSY;
        }
 
-       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
                frame = &ctx->s_frame;
-       } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+       else
                frame = &ctx->d_frame;
-       } else {
-               v4l2_err(&fimc->m2m.v4l2_dev,
-                        "Wrong buffer/video queue type (%d)\n", f->type);
-               return -EINVAL;
-       }
 
        pix = &f->fmt.pix_mp;
-       frame->fmt = find_format(f, FMT_FLAGS_M2M);
+       frame->fmt = fimc_find_format(&pix->pixelformat, NULL,
+                                     FMT_FLAGS_M2M, 0);
        if (!frame->fmt)
                return -EINVAL;
 
@@ -986,15 +1097,9 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv,
                        (pix->width * pix->height * frame->fmt->depth[i]) / 8;
        }
 
-       frame->f_width  = pix->plane_fmt[0].bytesperline * 8 /
-               frame->fmt->depth[0];
-       frame->f_height = pix->height;
-       frame->width    = pix->width;
-       frame->height   = pix->height;
-       frame->o_width  = pix->width;
-       frame->o_height = pix->height;
-       frame->offs_h   = 0;
-       frame->offs_v   = 0;
+       fimc_fill_frame(frame, f);
+
+       ctx->scaler.enabled = 1;
 
        if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
                fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_DST_FMT, ctx);
@@ -1006,39 +1111,42 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv,
        return 0;
 }
 
-static int fimc_m2m_reqbufs(struct file *file, void *priv,
-                         struct v4l2_requestbuffers *reqbufs)
+static int fimc_m2m_reqbufs(struct file *file, void *fh,
+                           struct v4l2_requestbuffers *reqbufs)
 {
-       struct fimc_ctx *ctx = priv;
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
+
        return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
 }
 
-static int fimc_m2m_querybuf(struct file *file, void *priv,
-                          struct v4l2_buffer *buf)
+static int fimc_m2m_querybuf(struct file *file, void *fh,
+                            struct v4l2_buffer *buf)
 {
-       struct fimc_ctx *ctx = priv;
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
+
        return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
 }
 
-static int fimc_m2m_qbuf(struct file *file, void *priv,
-                         struct v4l2_buffer *buf)
+static int fimc_m2m_qbuf(struct file *file, void *fh,
+                        struct v4l2_buffer *buf)
 {
-       struct fimc_ctx *ctx = priv;
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
 
        return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
 }
 
-static int fimc_m2m_dqbuf(struct file *file, void *priv,
-                          struct v4l2_buffer *buf)
+static int fimc_m2m_dqbuf(struct file *file, void *fh,
+                         struct v4l2_buffer *buf)
 {
-       struct fimc_ctx *ctx = priv;
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
+
        return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
 }
 
-static int fimc_m2m_streamon(struct file *file, void *priv,
-                          enum v4l2_buf_type type)
+static int fimc_m2m_streamon(struct file *file, void *fh,
+                            enum v4l2_buf_type type)
 {
-       struct fimc_ctx *ctx = priv;
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
 
        /* The source and target color format need to be set */
        if (V4L2_TYPE_IS_OUTPUT(type)) {
@@ -1051,149 +1159,19 @@ static int fimc_m2m_streamon(struct file *file, void *priv,
        return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
 }
 
-static int fimc_m2m_streamoff(struct file *file, void *priv,
+static int fimc_m2m_streamoff(struct file *file, void *fh,
                            enum v4l2_buf_type type)
 {
-       struct fimc_ctx *ctx = priv;
-       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
-}
-
-int fimc_vidioc_queryctrl(struct file *file, void *priv,
-                           struct v4l2_queryctrl *qc)
-{
-       struct fimc_ctx *ctx = priv;
-       struct v4l2_queryctrl *c;
-       int ret = -EINVAL;
-
-       c = get_ctrl(qc->id);
-       if (c) {
-               *qc = *c;
-               return 0;
-       }
-
-       if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) {
-               return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
-                                       core, queryctrl, qc);
-       }
-       return ret;
-}
-
-int fimc_vidioc_g_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctrl)
-{
-       struct fimc_ctx *ctx = priv;
-       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
 
-       switch (ctrl->id) {
-       case V4L2_CID_HFLIP:
-               ctrl->value = (FLIP_X_AXIS & ctx->flip) ? 1 : 0;
-               break;
-       case V4L2_CID_VFLIP:
-               ctrl->value = (FLIP_Y_AXIS & ctx->flip) ? 1 : 0;
-               break;
-       case V4L2_CID_ROTATE:
-               ctrl->value = ctx->rotation;
-               break;
-       default:
-               if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) {
-                       return v4l2_subdev_call(fimc->vid_cap.sd, core,
-                                               g_ctrl, ctrl);
-               } else {
-                       v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n");
-                       return -EINVAL;
-               }
-       }
-       dbg("ctrl->value= %d", ctrl->value);
-
-       return 0;
-}
-
-int check_ctrl_val(struct fimc_ctx *ctx,  struct v4l2_control *ctrl)
-{
-       struct v4l2_queryctrl *c;
-       c = get_ctrl(ctrl->id);
-       if (!c)
-               return -EINVAL;
-
-       if (ctrl->value < c->minimum || ctrl->value > c->maximum
-               || (c->step != 0 && ctrl->value % c->step != 0)) {
-               v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
-               "Invalid control value\n");
-               return -ERANGE;
-       }
-
-       return 0;
-}
-
-int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
-{
-       struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
-       struct fimc_dev *fimc = ctx->fimc_dev;
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_HFLIP:
-               if (ctrl->value)
-                       ctx->flip |= FLIP_X_AXIS;
-               else
-                       ctx->flip &= ~FLIP_X_AXIS;
-               break;
-
-       case V4L2_CID_VFLIP:
-               if (ctrl->value)
-                       ctx->flip |= FLIP_Y_AXIS;
-               else
-                       ctx->flip &= ~FLIP_Y_AXIS;
-               break;
-
-       case V4L2_CID_ROTATE:
-               if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
-                       ret = fimc_check_scaler_ratio(ctx->s_frame.width,
-                                       ctx->s_frame.height, ctx->d_frame.width,
-                                       ctx->d_frame.height, ctrl->value);
-               }
-
-               if (ret) {
-                       v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n");
-                       return -EINVAL;
-               }
-
-               /* Check for the output rotator availability */
-               if ((ctrl->value == 90 || ctrl->value == 270) &&
-                   (ctx->in_path == FIMC_DMA && !variant->has_out_rot))
-                       return -EINVAL;
-               ctx->rotation = ctrl->value;
-               break;
-
-       default:
-               v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n");
-               return -EINVAL;
-       }
-
-       fimc_ctx_state_lock_set(FIMC_PARAMS, ctx);
-
-       return 0;
-}
-
-static int fimc_m2m_s_ctrl(struct file *file, void *priv,
-                          struct v4l2_control *ctrl)
-{
-       struct fimc_ctx *ctx = priv;
-       int ret = 0;
-
-       ret = check_ctrl_val(ctx, ctrl);
-       if (ret)
-               return ret;
-
-       ret = fimc_s_ctrl(ctx, ctrl);
-       return 0;
+       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
 }
 
 static int fimc_m2m_cropcap(struct file *file, void *fh,
-                       struct v4l2_cropcap *cr)
+                           struct v4l2_cropcap *cr)
 {
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
        struct fimc_frame *frame;
-       struct fimc_ctx *ctx = fh;
 
        frame = ctx_get_frame(ctx, cr->type);
        if (IS_ERR(frame))
@@ -1201,8 +1179,8 @@ static int fimc_m2m_cropcap(struct file *file, void *fh,
 
        cr->bounds.left         = 0;
        cr->bounds.top          = 0;
-       cr->bounds.width        = frame->f_width;
-       cr->bounds.height       = frame->f_height;
+       cr->bounds.width        = frame->o_width;
+       cr->bounds.height       = frame->o_height;
        cr->defrect             = cr->bounds;
 
        return 0;
@@ -1210,8 +1188,8 @@ static int fimc_m2m_cropcap(struct file *file, void *fh,
 
 static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
 {
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
        struct fimc_frame *frame;
-       struct fimc_ctx *ctx = file->private_data;
 
        frame = ctx_get_frame(ctx, cr->type);
        if (IS_ERR(frame))
@@ -1225,26 +1203,21 @@ static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
        return 0;
 }
 
-int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
+static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
 {
        struct fimc_dev *fimc = ctx->fimc_dev;
        struct fimc_frame *f;
        u32 min_size, halign, depth = 0;
-       bool is_capture_ctx;
        int i;
 
        if (cr->c.top < 0 || cr->c.left < 0) {
-               v4l2_err(&fimc->m2m.v4l2_dev,
+               v4l2_err(fimc->m2m.vfd,
                        "doesn't support negative values for top & left\n");
                return -EINVAL;
        }
-
-       is_capture_ctx = fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx);
-
        if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-               f = is_capture_ctx ? &ctx->s_frame : &ctx->d_frame;
-       else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
-                !is_capture_ctx)
+               f = &ctx->d_frame;
+       else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
                f = &ctx->s_frame;
        else
                return -EINVAL;
@@ -1253,15 +1226,10 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
                fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
 
        /* Get pixel alignment constraints. */
-       if (is_capture_ctx) {
-               min_size = 16;
-               halign = 4;
-       } else {
-               if (fimc->id == 1 && fimc->variant->pix_hoff)
-                       halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
-               else
-                       halign = ffs(min_size) - 1;
-       }
+       if (fimc->id == 1 && fimc->variant->pix_hoff)
+               halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
+       else
+               halign = ffs(min_size) - 1;
 
        for (i = 0; i < f->fmt->colplanes; i++)
                depth += f->fmt->depth[i];
@@ -1278,7 +1246,7 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
                cr->c.top = f->o_height - cr->c.height;
 
        cr->c.left = round_down(cr->c.left, min_size);
-       cr->c.top  = round_down(cr->c.top, is_capture_ctx ? 16 : 8);
+       cr->c.top  = round_down(cr->c.top, fimc->variant->hor_offs_align);
 
        dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
            cr->c.left, cr->c.top, cr->c.width, cr->c.height,
@@ -1289,12 +1257,12 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
 
 static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
 {
-       struct fimc_ctx *ctx = file->private_data;
+       struct fimc_ctx *ctx = fh_to_ctx(fh);
        struct fimc_dev *fimc = ctx->fimc_dev;
        struct fimc_frame *f;
        int ret;
 
-       ret = fimc_try_crop(ctx, cr);
+       ret = fimc_m2m_try_crop(ctx, cr);
        if (ret)
                return ret;
 
@@ -1304,18 +1272,16 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
        /* Check to see if scaling ratio is within supported range */
        if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
                if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-                       ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height,
-                                                     ctx->d_frame.width,
-                                                     ctx->d_frame.height,
-                                                     ctx->rotation);
+                       ret = fimc_check_scaler_ratio(ctx, cr->c.width,
+                                       cr->c.height, ctx->d_frame.width,
+                                       ctx->d_frame.height, ctx->rotation);
                } else {
-                       ret = fimc_check_scaler_ratio(ctx->s_frame.width,
-                                                     ctx->s_frame.height,
-                                                     cr->c.width, cr->c.height,
-                                                     ctx->rotation);
+                       ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
+                                       ctx->s_frame.height, cr->c.width,
+                                       cr->c.height, ctx->rotation);
                }
                if (ret) {
-                       v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n");
+                       v4l2_err(fimc->m2m.vfd, "Out of scaler range\n");
                        return -EINVAL;
                }
        }
@@ -1333,14 +1299,14 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
 static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
        .vidioc_querycap                = fimc_m2m_querycap,
 
-       .vidioc_enum_fmt_vid_cap_mplane = fimc_vidioc_enum_fmt_mplane,
-       .vidioc_enum_fmt_vid_out_mplane = fimc_vidioc_enum_fmt_mplane,
+       .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane,
+       .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane,
 
-       .vidioc_g_fmt_vid_cap_mplane    = fimc_vidioc_g_fmt_mplane,
-       .vidioc_g_fmt_vid_out_mplane    = fimc_vidioc_g_fmt_mplane,
+       .vidioc_g_fmt_vid_cap_mplane    = fimc_m2m_g_fmt_mplane,
+       .vidioc_g_fmt_vid_out_mplane    = fimc_m2m_g_fmt_mplane,
 
-       .vidioc_try_fmt_vid_cap_mplane  = fimc_vidioc_try_fmt_mplane,
-       .vidioc_try_fmt_vid_out_mplane  = fimc_vidioc_try_fmt_mplane,
+       .vidioc_try_fmt_vid_cap_mplane  = fimc_m2m_try_fmt_mplane,
+       .vidioc_try_fmt_vid_out_mplane  = fimc_m2m_try_fmt_mplane,
 
        .vidioc_s_fmt_vid_cap_mplane    = fimc_m2m_s_fmt_mplane,
        .vidioc_s_fmt_vid_out_mplane    = fimc_m2m_s_fmt_mplane,
@@ -1354,10 +1320,6 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
        .vidioc_streamon                = fimc_m2m_streamon,
        .vidioc_streamoff               = fimc_m2m_streamoff,
 
-       .vidioc_queryctrl               = fimc_vidioc_queryctrl,
-       .vidioc_g_ctrl                  = fimc_vidioc_g_ctrl,
-       .vidioc_s_ctrl                  = fimc_m2m_s_ctrl,
-
        .vidioc_g_crop                  = fimc_m2m_g_crop,
        .vidioc_s_crop                  = fimc_m2m_s_crop,
        .vidioc_cropcap                 = fimc_m2m_cropcap
@@ -1396,7 +1358,8 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 static int fimc_m2m_open(struct file *file)
 {
        struct fimc_dev *fimc = video_drvdata(file);
-       struct fimc_ctx *ctx = NULL;
+       struct fimc_ctx *ctx;
+       int ret;
 
        dbg("pid: %d, state: 0x%lx, refcnt: %d",
                task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
@@ -1408,19 +1371,24 @@ static int fimc_m2m_open(struct file *file)
        if (fimc->vid_cap.refcnt > 0)
                return -EBUSY;
 
-       fimc->m2m.refcnt++;
-       set_bit(ST_OUTDMA_RUN, &fimc->state);
-
        ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
+       v4l2_fh_init(&ctx->fh, fimc->m2m.vfd);
+       ret = fimc_ctrls_create(ctx);
+       if (ret)
+               goto error_fh;
+
+       /* Use separate control handler per file handle */
+       ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+       file->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
 
-       file->private_data = ctx;
        ctx->fimc_dev = fimc;
        /* Default color format */
        ctx->s_frame.fmt = &fimc_formats[0];
        ctx->d_frame.fmt = &fimc_formats[0];
-       /* Setup the device context for mem2mem mode. */
+       /* Setup the device context for memory-to-memory mode */
        ctx->state = FIMC_CTX_M2M;
        ctx->flags = 0;
        ctx->in_path = FIMC_DMA;
@@ -1429,34 +1397,46 @@ static int fimc_m2m_open(struct file *file)
 
        ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
        if (IS_ERR(ctx->m2m_ctx)) {
-               int err = PTR_ERR(ctx->m2m_ctx);
-               kfree(ctx);
-               return err;
+               ret = PTR_ERR(ctx->m2m_ctx);
+               goto error_c;
        }
 
+       if (fimc->m2m.refcnt++ == 0)
+               set_bit(ST_M2M_RUN, &fimc->state);
        return 0;
+
+error_c:
+       fimc_ctrls_delete(ctx);
+error_fh:
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+       return ret;
 }
 
 static int fimc_m2m_release(struct file *file)
 {
-       struct fimc_ctx *ctx = file->private_data;
+       struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
        struct fimc_dev *fimc = ctx->fimc_dev;
 
        dbg("pid: %d, state: 0x%lx, refcnt= %d",
                task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
 
        v4l2_m2m_ctx_release(ctx->m2m_ctx);
-       kfree(ctx);
-       if (--fimc->m2m.refcnt <= 0)
-               clear_bit(ST_OUTDMA_RUN, &fimc->state);
+       fimc_ctrls_delete(ctx);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
 
+       if (--fimc->m2m.refcnt <= 0)
+               clear_bit(ST_M2M_RUN, &fimc->state);
+       kfree(ctx);
        return 0;
 }
 
 static unsigned int fimc_m2m_poll(struct file *file,
-                                    struct poll_table_struct *wait)
+                                 struct poll_table_struct *wait)
 {
-       struct fimc_ctx *ctx = file->private_data;
+       struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
 
        return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
 }
@@ -1464,7 +1444,7 @@ static unsigned int fimc_m2m_poll(struct file *file,
 
 static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct fimc_ctx *ctx = file->private_data;
+       struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
 
        return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
 }
@@ -1483,92 +1463,73 @@ static struct v4l2_m2m_ops m2m_ops = {
        .job_abort      = fimc_job_abort,
 };
 
-static int fimc_register_m2m_device(struct fimc_dev *fimc)
+int fimc_register_m2m_device(struct fimc_dev *fimc,
+                            struct v4l2_device *v4l2_dev)
 {
        struct video_device *vfd;
        struct platform_device *pdev;
-       struct v4l2_device *v4l2_dev;
        int ret = 0;
 
        if (!fimc)
                return -ENODEV;
 
        pdev = fimc->pdev;
-       v4l2_dev = &fimc->m2m.v4l2_dev;
-
-       /* set name if it is empty */
-       if (!v4l2_dev->name[0])
-               snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
-                        "%s.m2m", dev_name(&pdev->dev));
-
-       ret = v4l2_device_register(&pdev->dev, v4l2_dev);
-       if (ret)
-               goto err_m2m_r1;
+       fimc->v4l2_dev = v4l2_dev;
 
        vfd = video_device_alloc();
        if (!vfd) {
                v4l2_err(v4l2_dev, "Failed to allocate video device\n");
-               goto err_m2m_r1;
+               return -ENOMEM;
        }
 
        vfd->fops       = &fimc_m2m_fops;
        vfd->ioctl_ops  = &fimc_m2m_ioctl_ops;
+       vfd->v4l2_dev   = v4l2_dev;
        vfd->minor      = -1;
        vfd->release    = video_device_release;
        vfd->lock       = &fimc->lock;
 
-       snprintf(vfd->name, sizeof(vfd->name), "%s:m2m", dev_name(&pdev->dev));
-
+       snprintf(vfd->name, sizeof(vfd->name), "%s.m2m", dev_name(&pdev->dev));
        video_set_drvdata(vfd, fimc);
-       platform_set_drvdata(pdev, fimc);
 
        fimc->m2m.vfd = vfd;
        fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops);
        if (IS_ERR(fimc->m2m.m2m_dev)) {
                v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n");
                ret = PTR_ERR(fimc->m2m.m2m_dev);
-               goto err_m2m_r2;
-       }
-
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
-       if (ret) {
-               v4l2_err(v4l2_dev,
-                        "%s(): failed to register video device\n", __func__);
-               goto err_m2m_r3;
+               goto err_init;
        }
-       v4l2_info(v4l2_dev,
-                 "FIMC m2m driver registered as /dev/video%d\n", vfd->num);
 
-       return 0;
+       ret = media_entity_init(&vfd->entity, 0, NULL, 0);
+       if (!ret)
+               return 0;
 
-err_m2m_r3:
        v4l2_m2m_release(fimc->m2m.m2m_dev);
-err_m2m_r2:
+err_init:
        video_device_release(fimc->m2m.vfd);
-err_m2m_r1:
-       v4l2_device_unregister(v4l2_dev);
-
        return ret;
 }
 
-static void fimc_unregister_m2m_device(struct fimc_dev *fimc)
+void fimc_unregister_m2m_device(struct fimc_dev *fimc)
 {
-       if (fimc) {
+       if (!fimc)
+               return;
+
+       if (fimc->m2m.m2m_dev)
                v4l2_m2m_release(fimc->m2m.m2m_dev);
+       if (fimc->m2m.vfd) {
+               media_entity_cleanup(&fimc->m2m.vfd->entity);
+               /* Can also be called if video device wasn't registered */
                video_unregister_device(fimc->m2m.vfd);
-
-               v4l2_device_unregister(&fimc->m2m.v4l2_dev);
        }
 }
 
-static void fimc_clk_release(struct fimc_dev *fimc)
+static void fimc_clk_put(struct fimc_dev *fimc)
 {
        int i;
        for (i = 0; i < fimc->num_clocks; i++) {
-               if (fimc->clock[i]) {
-                       clk_disable(fimc->clock[i]);
+               if (fimc->clock[i])
                        clk_put(fimc->clock[i]);
-               }
        }
 }
 
@@ -1577,15 +1538,50 @@ static int fimc_clk_get(struct fimc_dev *fimc)
        int i;
        for (i = 0; i < fimc->num_clocks; i++) {
                fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
-
-               if (!IS_ERR_OR_NULL(fimc->clock[i])) {
-                       clk_enable(fimc->clock[i]);
+               if (!IS_ERR_OR_NULL(fimc->clock[i]))
                        continue;
-               }
                dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n",
                        fimc_clocks[i]);
                return -ENXIO;
        }
+
+       return 0;
+}
+
+static int fimc_m2m_suspend(struct fimc_dev *fimc)
+{
+       unsigned long flags;
+       int timeout;
+
+       spin_lock_irqsave(&fimc->slock, flags);
+       if (!fimc_m2m_pending(fimc)) {
+               spin_unlock_irqrestore(&fimc->slock, flags);
+               return 0;
+       }
+       clear_bit(ST_M2M_SUSPENDED, &fimc->state);
+       set_bit(ST_M2M_SUSPENDING, &fimc->state);
+       spin_unlock_irqrestore(&fimc->slock, flags);
+
+       timeout = wait_event_timeout(fimc->irq_queue,
+                            test_bit(ST_M2M_SUSPENDED, &fimc->state),
+                            FIMC_SHUTDOWN_TIMEOUT);
+
+       clear_bit(ST_M2M_SUSPENDING, &fimc->state);
+       return timeout == 0 ? -EAGAIN : 0;
+}
+
+static int fimc_m2m_resume(struct fimc_dev *fimc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&fimc->slock, flags);
+       /* Clear for full H/W setup in first run after resume */
+       fimc->m2m.ctx = NULL;
+       spin_unlock_irqrestore(&fimc->slock, flags);
+
+       if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state))
+               fimc_m2m_job_finish(fimc->m2m.ctx,
+                                   VB2_BUF_STATE_ERROR);
        return 0;
 }
 
@@ -1596,7 +1592,6 @@ static int fimc_probe(struct platform_device *pdev)
        struct samsung_fimc_driverdata *drv_data;
        struct s5p_platform_fimc *pdata;
        int ret = 0;
-       int cap_input_index = -1;
 
        dev_dbg(&pdev->dev, "%s():\n", __func__);
 
@@ -1614,15 +1609,16 @@ static int fimc_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        fimc->id = pdev->id;
+
        fimc->variant = drv_data->variant[fimc->id];
        fimc->pdev = pdev;
        pdata = pdev->dev.platform_data;
        fimc->pdata = pdata;
-       fimc->state = ST_IDLE;
+
+       set_bit(ST_LPM, &fimc->state);
 
        init_waitqueue_head(&fimc->irq_queue);
        spin_lock_init(&fimc->slock);
-
        mutex_init(&fimc->lock);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1647,71 +1643,51 @@ static int fimc_probe(struct platform_device *pdev)
                goto err_req_region;
        }
 
-       fimc->num_clocks = MAX_FIMC_CLOCKS - 1;
-
-       /* Check if a video capture node needs to be registered. */
-       if (pdata && pdata->num_clients > 0) {
-               cap_input_index = 0;
-               fimc->num_clocks++;
-       }
-
-       ret = fimc_clk_get(fimc);
-       if (ret)
-               goto err_regs_unmap;
-       clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
-
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
                dev_err(&pdev->dev, "failed to get IRQ resource\n");
                ret = -ENXIO;
-               goto err_clk;
+               goto err_regs_unmap;
        }
        fimc->irq = res->start;
 
-       fimc_hw_reset(fimc);
+       fimc->num_clocks = MAX_FIMC_CLOCKS;
+       ret = fimc_clk_get(fimc);
+       if (ret)
+               goto err_regs_unmap;
+       clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
+       clk_enable(fimc->clock[CLK_BUS]);
 
-       ret = request_irq(fimc->irq, fimc_isr, 0, pdev->name, fimc);
+       platform_set_drvdata(pdev, fimc);
+
+       ret = request_irq(fimc->irq, fimc_irq_handler, 0, pdev->name, fimc);
        if (ret) {
                dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
                goto err_clk;
        }
 
+       pm_runtime_enable(&pdev->dev);
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (ret < 0)
+               goto err_irq;
        /* Initialize contiguous memory allocator */
-       fimc->alloc_ctx = vb2_dma_contig_init_ctx(&fimc->pdev->dev);
+       fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
        if (IS_ERR(fimc->alloc_ctx)) {
                ret = PTR_ERR(fimc->alloc_ctx);
-               goto err_irq;
+               goto err_pm;
        }
 
-       ret = fimc_register_m2m_device(fimc);
-       if (ret)
-               goto err_irq;
-
-       /* At least one camera sensor is required to register capture node */
-       if (cap_input_index >= 0) {
-               ret = fimc_register_capture_device(fimc);
-               if (ret)
-                       goto err_m2m;
-               clk_disable(fimc->clock[CLK_CAM]);
-       }
-       /*
-        * Exclude the additional output DMA address registers by masking
-        * them out on HW revisions that provide extended capabilites.
-        */
-       if (fimc->variant->out_buf_count > 4)
-               fimc_hw_set_dma_seq(fimc, 0xF);
-
-       dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n",
-               __func__, fimc->id);
+       dev_dbg(&pdev->dev, "FIMC.%d registered successfully\n", fimc->id);
 
+       pm_runtime_put(&pdev->dev);
        return 0;
 
-err_m2m:
-       fimc_unregister_m2m_device(fimc);
+err_pm:
+       pm_runtime_put(&pdev->dev);
 err_irq:
        free_irq(fimc->irq, fimc);
 err_clk:
-       fimc_clk_release(fimc);
+       fimc_clk_put(fimc);
 err_regs_unmap:
        iounmap(fimc->regs);
 err_req_region:
@@ -1719,31 +1695,105 @@ err_req_region:
        kfree(fimc->regs_res);
 err_info:
        kfree(fimc);
+       return ret;
+}
 
+static int fimc_runtime_resume(struct device *dev)
+{
+       struct fimc_dev *fimc = dev_get_drvdata(dev);
+
+       dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
+
+       /* Enable clocks and perform basic initalization */
+       clk_enable(fimc->clock[CLK_GATE]);
+       fimc_hw_reset(fimc);
+       if (fimc->variant->out_buf_count > 4)
+               fimc_hw_set_dma_seq(fimc, 0xF);
+
+       /* Resume the capture or mem-to-mem device */
+       if (fimc_capture_busy(fimc))
+               return fimc_capture_resume(fimc);
+       else if (fimc_m2m_pending(fimc))
+               return fimc_m2m_resume(fimc);
+       return 0;
+}
+
+static int fimc_runtime_suspend(struct device *dev)
+{
+       struct fimc_dev *fimc = dev_get_drvdata(dev);
+       int ret = 0;
+
+       if (fimc_capture_busy(fimc))
+               ret = fimc_capture_suspend(fimc);
+       else
+               ret = fimc_m2m_suspend(fimc);
+       if (!ret)
+               clk_disable(fimc->clock[CLK_GATE]);
+
+       dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
        return ret;
 }
 
-static int __devexit fimc_remove(struct platform_device *pdev)
+#ifdef CONFIG_PM_SLEEP
+static int fimc_resume(struct device *dev)
 {
-       struct fimc_dev *fimc =
-               (struct fimc_dev *)platform_get_drvdata(pdev);
+       struct fimc_dev *fimc = dev_get_drvdata(dev);
+       unsigned long flags;
 
-       free_irq(fimc->irq, fimc);
+       dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
+
+       /* Do not resume if the device was idle before system suspend */
+       spin_lock_irqsave(&fimc->slock, flags);
+       if (!test_and_clear_bit(ST_LPM, &fimc->state) ||
+           (!fimc_m2m_active(fimc) && !fimc_capture_busy(fimc))) {
+               spin_unlock_irqrestore(&fimc->slock, flags);
+               return 0;
+       }
        fimc_hw_reset(fimc);
+       if (fimc->variant->out_buf_count > 4)
+               fimc_hw_set_dma_seq(fimc, 0xF);
+       spin_unlock_irqrestore(&fimc->slock, flags);
+
+       if (fimc_capture_busy(fimc))
+               return fimc_capture_resume(fimc);
 
-       fimc_unregister_m2m_device(fimc);
-       fimc_unregister_capture_device(fimc);
+       return fimc_m2m_resume(fimc);
+}
+
+static int fimc_suspend(struct device *dev)
+{
+       struct fimc_dev *fimc = dev_get_drvdata(dev);
+
+       dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
 
-       fimc_clk_release(fimc);
+       if (test_and_set_bit(ST_LPM, &fimc->state))
+               return 0;
+       if (fimc_capture_busy(fimc))
+               return fimc_capture_suspend(fimc);
+
+       return fimc_m2m_suspend(fimc);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int __devexit fimc_remove(struct platform_device *pdev)
+{
+       struct fimc_dev *fimc = platform_get_drvdata(pdev);
+
+       pm_runtime_disable(&pdev->dev);
+       fimc_runtime_suspend(&pdev->dev);
+       pm_runtime_set_suspended(&pdev->dev);
 
        vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
 
+       clk_disable(fimc->clock[CLK_BUS]);
+       fimc_clk_put(fimc);
+       free_irq(fimc->irq, fimc);
        iounmap(fimc->regs);
        release_resource(fimc->regs_res);
        kfree(fimc->regs_res);
        kfree(fimc);
 
-       dev_info(&pdev->dev, "%s driver unloaded\n", pdev->name);
+       dev_info(&pdev->dev, "driver unloaded\n");
        return 0;
 }
 
@@ -1786,6 +1836,7 @@ static struct fimc_pix_limit s5p_pix_limit[4] = {
 static struct samsung_fimc_variant fimc0_variant_s5p = {
        .has_inp_rot     = 1,
        .has_out_rot     = 1,
+       .has_cam_if      = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
        .hor_offs_align  = 8,
@@ -1794,6 +1845,7 @@ static struct samsung_fimc_variant fimc0_variant_s5p = {
 };
 
 static struct samsung_fimc_variant fimc2_variant_s5p = {
+       .has_cam_if      = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
        .hor_offs_align  = 8,
@@ -1805,6 +1857,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv210 = {
        .pix_hoff        = 1,
        .has_inp_rot     = 1,
        .has_out_rot     = 1,
+       .has_cam_if      = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
        .hor_offs_align  = 8,
@@ -1816,6 +1869,7 @@ static struct samsung_fimc_variant fimc1_variant_s5pv210 = {
        .pix_hoff        = 1,
        .has_inp_rot     = 1,
        .has_out_rot     = 1,
+       .has_cam_if      = 1,
        .has_mainscaler_ext = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
@@ -1825,6 +1879,7 @@ static struct samsung_fimc_variant fimc1_variant_s5pv210 = {
 };
 
 static struct samsung_fimc_variant fimc2_variant_s5pv210 = {
+       .has_cam_if      = 1,
        .pix_hoff        = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
@@ -1837,22 +1892,24 @@ static struct samsung_fimc_variant fimc0_variant_exynos4 = {
        .pix_hoff        = 1,
        .has_inp_rot     = 1,
        .has_out_rot     = 1,
+       .has_cam_if      = 1,
        .has_cistatus2   = 1,
        .has_mainscaler_ext = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
-       .hor_offs_align  = 1,
+       .hor_offs_align  = 2,
        .out_buf_count   = 32,
        .pix_limit       = &s5p_pix_limit[1],
 };
 
-static struct samsung_fimc_variant fimc2_variant_exynos4 = {
+static struct samsung_fimc_variant fimc3_variant_exynos4 = {
        .pix_hoff        = 1,
+       .has_cam_if      = 1,
        .has_cistatus2   = 1,
        .has_mainscaler_ext = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
-       .hor_offs_align  = 1,
+       .hor_offs_align  = 2,
        .out_buf_count   = 32,
        .pix_limit       = &s5p_pix_limit[3],
 };
@@ -1885,7 +1942,7 @@ static struct samsung_fimc_driverdata fimc_drvdata_exynos4 = {
                [0] = &fimc0_variant_exynos4,
                [1] = &fimc0_variant_exynos4,
                [2] = &fimc0_variant_exynos4,
-               [3] = &fimc2_variant_exynos4,
+               [3] = &fimc3_variant_exynos4,
        },
        .num_entities = 4,
        .lclk_frequency = 166000000UL,
@@ -1906,33 +1963,28 @@ static struct platform_device_id fimc_driver_ids[] = {
 };
 MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
 
+static const struct dev_pm_ops fimc_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume)
+       SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL)
+};
+
 static struct platform_driver fimc_driver = {
        .probe          = fimc_probe,
-       .remove = __devexit_p(fimc_remove),
+       .remove         = __devexit_p(fimc_remove),
        .id_table       = fimc_driver_ids,
        .driver = {
-               .name   = MODULE_NAME,
+               .name   = FIMC_MODULE_NAME,
                .owner  = THIS_MODULE,
+               .pm     = &fimc_pm_ops,
        }
 };
 
-static int __init fimc_init(void)
+int __init fimc_register_driver(void)
 {
-       int ret = platform_driver_register(&fimc_driver);
-       if (ret)
-               err("platform_driver_register failed: %d\n", ret);
-       return ret;
+       return platform_driver_probe(&fimc_driver, fimc_probe);
 }
 
-static void __exit fimc_exit(void)
+void __exit fimc_unregister_driver(void)
 {
        platform_driver_unregister(&fimc_driver);
 }
-
-module_init(fimc_init);
-module_exit(fimc_exit);
-
-MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
-MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("1.0.1");
index 1f70772..a6936da 100644 (file)
 
 /*#define DEBUG*/
 
+#include <linux/platform_device.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/videodev2.h>
 #include <linux/io.h>
+
+#include <media/media-entity.h>
 #include <media/videobuf2-core.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/v4l2-mediabus.h>
 
 /* Time to wait for next frame VSYNC interrupt while stopping operation. */
 #define FIMC_SHUTDOWN_TIMEOUT  ((100*HZ)/1000)
-#define MAX_FIMC_CLOCKS                3
-#define MODULE_NAME            "s5p-fimc"
+#define MAX_FIMC_CLOCKS                2
+#define FIMC_MODULE_NAME       "s5p-fimc"
 #define FIMC_MAX_DEVS          4
 #define FIMC_MAX_OUT_BUFS      4
 #define SCALER_MAX_HRATIO      64
 #define SCALER_MAX_VRATIO      64
 #define DMA_MIN_SIZE           8
+#define FIMC_CAMIF_MAX_HEIGHT  0x2000
 
 /* indices to the clocks array */
 enum {
        CLK_BUS,
        CLK_GATE,
-       CLK_CAM,
 };
 
 enum fimc_dev_flags {
-       /* for m2m node */
-       ST_IDLE,
-       ST_OUTDMA_RUN,
+       ST_LPM,
+       /* m2m node */
+       ST_M2M_RUN,
        ST_M2M_PEND,
-       /* for capture node */
+       ST_M2M_SUSPENDING,
+       ST_M2M_SUSPENDED,
+       /* capture node */
        ST_CAPT_PEND,
        ST_CAPT_RUN,
        ST_CAPT_STREAM,
+       ST_CAPT_ISP_STREAM,
+       ST_CAPT_SUSPENDED,
        ST_CAPT_SHUT,
+       ST_CAPT_BUSY,
+       ST_CAPT_APPLY_CFG,
+       ST_CAPT_JPEG,
 };
 
-#define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state)
+#define fimc_m2m_active(dev) test_bit(ST_M2M_RUN, &(dev)->state)
 #define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state)
 
 #define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state)
 #define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state)
+#define fimc_capture_busy(dev) test_bit(ST_CAPT_BUSY, &(dev)->state)
 
 enum fimc_datapath {
        FIMC_CAMERA,
@@ -83,9 +95,14 @@ enum fimc_color_fmt {
        S5P_FIMC_CBYCRY422,
        S5P_FIMC_CRYCBY422,
        S5P_FIMC_YCBCR444_LOCAL,
+       S5P_FIMC_JPEG = 0x40,
 };
 
-#define fimc_fmt_is_rgb(x) ((x) & 0x10)
+#define fimc_fmt_is_rgb(x) (!!((x) & 0x10))
+#define fimc_fmt_is_jpeg(x) (!!((x) & 0x40))
+
+#define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \
+                       __strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
 
 /* Cb/Cr chrominance components order for 2 plane Y/CbCr 4:2:2 formats. */
 #define        S5P_FIMC_LSB_CRCB       S5P_CIOCTRL_ORDER422_2P_LSB_CRCB
@@ -104,9 +121,10 @@ enum fimc_color_fmt {
 #define        FIMC_DST_ADDR           (1 << 2)
 #define        FIMC_SRC_FMT            (1 << 3)
 #define        FIMC_DST_FMT            (1 << 4)
-#define        FIMC_CTX_M2M            (1 << 5)
-#define        FIMC_CTX_CAP            (1 << 6)
-#define        FIMC_CTX_SHUT           (1 << 7)
+#define        FIMC_DST_CROP           (1 << 5)
+#define        FIMC_CTX_M2M            (1 << 16)
+#define        FIMC_CTX_CAP            (1 << 17)
+#define        FIMC_CTX_SHUT           (1 << 18)
 
 /* Image conversion flags */
 #define        FIMC_IN_DMA_ACCESS_TILED        (1 << 0)
@@ -122,11 +140,6 @@ enum fimc_color_fmt {
 /* Y (16 ~ 235), Cb/Cr (16 ~ 240) */
 #define        FIMC_COLOR_RANGE_NARROW         (1 << 3)
 
-#define        FLIP_NONE                       0
-#define        FLIP_X_AXIS                     1
-#define        FLIP_Y_AXIS                     2
-#define        FLIP_XY_AXIS                    (FLIP_X_AXIS | FLIP_Y_AXIS)
-
 /**
  * struct fimc_fmt - the driver's internal color format data
  * @mbus_code: Media Bus pixel code, -1 if not applicable
@@ -275,26 +288,29 @@ struct fimc_frame {
 /**
  * struct fimc_m2m_device - v4l2 memory-to-memory device data
  * @vfd: the video device node for v4l2 m2m mode
- * @v4l2_dev: v4l2 device for m2m mode
  * @m2m_dev: v4l2 memory-to-memory device data
  * @ctx: hardware context data
  * @refcnt: the reference counter
  */
 struct fimc_m2m_device {
        struct video_device     *vfd;
-       struct v4l2_device      v4l2_dev;
        struct v4l2_m2m_dev     *m2m_dev;
        struct fimc_ctx         *ctx;
        int                     refcnt;
 };
 
+#define FIMC_SD_PAD_SINK       0
+#define FIMC_SD_PAD_SOURCE     1
+#define FIMC_SD_PADS_NUM       2
+
 /**
  * struct fimc_vid_cap - camera capture device information
  * @ctx: hardware context data
  * @vfd: video device node for camera capture mode
- * @v4l2_dev: v4l2_device struct to manage subdevs
- * @sd: pointer to camera sensor subdevice currently in use
- * @fmt: Media Bus format configured at selected image sensor
+ * @subdev: subdev exposing the FIMC processing block
+ * @vd_pad: fimc video capture node pad
+ * @sd_pads: fimc video processing block pads
+ * @mf: media bus format at the FIMC camera input (and the scaler output) pad
  * @pending_buf_q: the pending buffer queue head
  * @active_buf_q: the queue head of buffers scheduled in hardware
  * @vbq: the capture am video buffer queue
@@ -304,14 +320,17 @@ struct fimc_m2m_device {
  * @reqbufs_count: the number of buffers requested in REQBUFS ioctl
  * @input_index: input (camera sensor) index
  * @refcnt: driver's private reference counter
+ * @input: capture input type, grp_id of the attached subdev
+ * @user_subdev_api: true if subdevs are not configured by the host driver
  */
 struct fimc_vid_cap {
        struct fimc_ctx                 *ctx;
        struct vb2_alloc_ctx            *alloc_ctx;
        struct video_device             *vfd;
-       struct v4l2_device              v4l2_dev;
-       struct v4l2_subdev              *sd;;
-       struct v4l2_mbus_framefmt       fmt;
+       struct v4l2_subdev              *subdev;
+       struct media_pad                vd_pad;
+       struct v4l2_mbus_framefmt       mf;
+       struct media_pad                sd_pads[FIMC_SD_PADS_NUM];
        struct list_head                pending_buf_q;
        struct list_head                active_buf_q;
        struct vb2_queue                vbq;
@@ -321,6 +340,8 @@ struct fimc_vid_cap {
        unsigned int                    reqbufs_count;
        int                             input_index;
        int                             refcnt;
+       u32                             input;
+       bool                            user_subdev_api;
 };
 
 /**
@@ -351,6 +372,7 @@ struct fimc_pix_limit {
  * @has_cistatus2: 1 if CISTATUS2 register is present in this IP revision
  * @has_mainscaler_ext: 1 if extended mainscaler ratios in CIEXTEN register
  *                      are present in this IP revision
+ * @has_cam_if: set if this instance has a camera input interface
  * @pix_limit: pixel size constraints for the scaler
  * @min_inp_pixsize: minimum input pixel size
  * @min_out_pixsize: minimum output pixel size
@@ -363,6 +385,7 @@ struct samsung_fimc_variant {
        unsigned int    has_out_rot:1;
        unsigned int    has_cistatus2:1;
        unsigned int    has_mainscaler_ext:1;
+       unsigned int    has_cam_if:1;
        struct fimc_pix_limit *pix_limit;
        u16             min_inp_pixsize;
        u16             min_out_pixsize;
@@ -383,6 +406,12 @@ struct samsung_fimc_driverdata {
        int             num_entities;
 };
 
+struct fimc_pipeline {
+       struct media_pipeline *pipe;
+       struct v4l2_subdev *sensor;
+       struct v4l2_subdev *csis;
+};
+
 struct fimc_ctx;
 
 /**
@@ -399,10 +428,12 @@ struct fimc_ctx;
  * @regs_res:  the resource claimed for IO registers
  * @irq:       FIMC interrupt number
  * @irq_queue: interrupt handler waitqueue
+ * @v4l2_dev:  root v4l2_device
  * @m2m:       memory-to-memory V4L2 device information
  * @vid_cap:   camera capture device information
  * @state:     flags used to synchronize m2m and capture mode operation
  * @alloc_ctx: videobuf2 memory allocator context
+ * @pipeline:  fimc video capture pipeline data structure
  */
 struct fimc_dev {
        spinlock_t                      slock;
@@ -417,10 +448,12 @@ struct fimc_dev {
        struct resource                 *regs_res;
        int                             irq;
        wait_queue_head_t               irq_queue;
+       struct v4l2_device              *v4l2_dev;
        struct fimc_m2m_device          m2m;
        struct fimc_vid_cap             vid_cap;
        unsigned long                   state;
        struct vb2_alloc_ctx            *alloc_ctx;
+       struct fimc_pipeline            pipeline;
 };
 
 /**
@@ -437,11 +470,18 @@ struct fimc_dev {
  * @scaler:            image scaler properties
  * @effect:            image effect
  * @rotation:          image clockwise rotation in degrees
- * @flip:              image flip mode
+ * @hflip:             indicates image horizontal flip if set
+ * @vflip:             indicates image vertical flip if set
  * @flags:             additional flags for image conversion
  * @state:             flags to keep track of user configuration
  * @fimc_dev:          the FIMC device this context applies to
  * @m2m_ctx:           memory-to-memory device context
+ * @fh:                        v4l2 file handle
+ * @ctrl_handler:      v4l2 controls handler
+ * @ctrl_rotate                image rotation control
+ * @ctrl_hflip         horizontal flip control
+ * @ctrl_vflip         vartical flip control
+ * @ctrls_rdy:         true if the control handler is initialized
  */
 struct fimc_ctx {
        spinlock_t              slock;
@@ -456,13 +496,49 @@ struct fimc_ctx {
        struct fimc_scaler      scaler;
        struct fimc_effect      effect;
        int                     rotation;
-       u32                     flip;
+       unsigned int            hflip:1;
+       unsigned int            vflip:1;
        u32                     flags;
        u32                     state;
        struct fimc_dev         *fimc_dev;
        struct v4l2_m2m_ctx     *m2m_ctx;
+       struct v4l2_fh          fh;
+       struct v4l2_ctrl_handler ctrl_handler;
+       struct v4l2_ctrl        *ctrl_rotate;
+       struct v4l2_ctrl        *ctrl_hflip;
+       struct v4l2_ctrl        *ctrl_vflip;
+       bool                    ctrls_rdy;
 };
 
+#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh)
+
+static inline void set_frame_bounds(struct fimc_frame *f, u32 width, u32 height)
+{
+       f->o_width  = width;
+       f->o_height = height;
+       f->f_width  = width;
+       f->f_height = height;
+}
+
+static inline void set_frame_crop(struct fimc_frame *f,
+                                 u32 left, u32 top, u32 width, u32 height)
+{
+       f->offs_h = left;
+       f->offs_v = top;
+       f->width  = width;
+       f->height = height;
+}
+
+static inline u32 fimc_get_format_depth(struct fimc_fmt *ff)
+{
+       u32 i, depth = 0;
+
+       if (ff != NULL)
+               for (i = 0; i < ff->colplanes; i++)
+                       depth += ff->depth[i];
+       return depth;
+}
+
 static inline bool fimc_capture_active(struct fimc_dev *fimc)
 {
        unsigned long flags;
@@ -561,7 +637,7 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
        } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
                frame = &ctx->d_frame;
        } else {
-               v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
+               v4l2_err(ctx->fimc_dev->v4l2_dev,
                        "Wrong buffer/video queue type (%d)\n", type);
                return ERR_PTR(-EINVAL);
        }
@@ -595,7 +671,7 @@ void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
 void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
 void fimc_hw_set_mainscaler(struct fimc_ctx *ctx);
 void fimc_hw_en_capture(struct fimc_ctx *ctx);
-void fimc_hw_set_effect(struct fimc_ctx *ctx);
+void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active);
 void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
 void fimc_hw_set_input_path(struct fimc_ctx *ctx);
 void fimc_hw_set_output_path(struct fimc_ctx *ctx);
@@ -614,36 +690,45 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
 /* fimc-core.c */
 int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
                                struct v4l2_fmtdesc *f);
-int fimc_vidioc_g_fmt_mplane(struct file *file, void *priv,
-                            struct v4l2_format *f);
-int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv,
-                              struct v4l2_format *f);
-int fimc_vidioc_queryctrl(struct file *file, void *priv,
-                         struct v4l2_queryctrl *qc);
-int fimc_vidioc_g_ctrl(struct file *file, void *priv,
-                      struct v4l2_control *ctrl);
-
-int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr);
-int check_ctrl_val(struct fimc_ctx *ctx,  struct v4l2_control *ctrl);
-int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl);
-
-struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask);
-struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
-                                 unsigned int mask);
-
-int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot);
+int fimc_ctrls_create(struct fimc_ctx *ctx);
+void fimc_ctrls_delete(struct fimc_ctx *ctx);
+void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
+int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f);
+void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
+                              struct v4l2_pix_format_mplane *pix);
+struct fimc_fmt *fimc_find_format(u32 *pixelformat, u32 *mbus_code,
+                                 unsigned int mask, int index);
+
+int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
+                           int dw, int dh, int rotation);
 int fimc_set_scaler_info(struct fimc_ctx *ctx);
 int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags);
 int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
                      struct fimc_frame *frame, struct fimc_addr *paddr);
+void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f);
+void fimc_set_yuv_order(struct fimc_ctx *ctx);
+void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f);
+void fimc_capture_irq_handler(struct fimc_dev *fimc, bool done);
+
+int fimc_register_m2m_device(struct fimc_dev *fimc,
+                            struct v4l2_device *v4l2_dev);
+void fimc_unregister_m2m_device(struct fimc_dev *fimc);
+int fimc_register_driver(void);
+void fimc_unregister_driver(void);
 
 /* -----------------------------------------------------*/
 /* fimc-capture.c                                      */
-int fimc_register_capture_device(struct fimc_dev *fimc);
+int fimc_register_capture_device(struct fimc_dev *fimc,
+                                struct v4l2_device *v4l2_dev);
 void fimc_unregister_capture_device(struct fimc_dev *fimc);
-int fimc_sensor_sd_init(struct fimc_dev *fimc, int index);
+int fimc_capture_ctrls_create(struct fimc_dev *fimc);
 int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
                             struct fimc_vid_buffer *fimc_vb);
+void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
+                       void *arg);
+int fimc_capture_suspend(struct fimc_dev *fimc);
+int fimc_capture_resume(struct fimc_dev *fimc);
+int fimc_capture_config_update(struct fimc_ctx *ctx);
 
 /* Locking: the caller holds fimc->slock */
 static inline void fimc_activate_capture(struct fimc_ctx *ctx)
@@ -661,22 +746,27 @@ static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
 }
 
 /*
- * Add buf to the capture active buffers queue.
- * Locking: Need to be called with fimc_dev::slock held.
+ * Buffer list manipulation functions. Must be called with fimc.slock held.
  */
-static inline void active_queue_add(struct fimc_vid_cap *vid_cap,
-                                   struct fimc_vid_buffer *buf)
+
+/**
+ * fimc_active_queue_add - add buffer to the capture active buffers queue
+ * @buf: buffer to add to the active buffers list
+ */
+static inline void fimc_active_queue_add(struct fimc_vid_cap *vid_cap,
+                                        struct fimc_vid_buffer *buf)
 {
        list_add_tail(&buf->list, &vid_cap->active_buf_q);
        vid_cap->active_buf_cnt++;
 }
 
-/*
- * Pop a video buffer from the capture active buffers queue
- * Locking: Need to be called with fimc_dev::slock held.
+/**
+ * fimc_active_queue_pop - pop buffer from the capture active buffers queue
+ *
+ * The caller must assure the active_buf_q list is not empty.
  */
-static inline struct fimc_vid_buffer *
-active_queue_pop(struct fimc_vid_cap *vid_cap)
+static inline struct fimc_vid_buffer *fimc_active_queue_pop(
+                                   struct fimc_vid_cap *vid_cap)
 {
        struct fimc_vid_buffer *buf;
        buf = list_entry(vid_cap->active_buf_q.next,
@@ -686,16 +776,23 @@ active_queue_pop(struct fimc_vid_cap *vid_cap)
        return buf;
 }
 
-/* Add video buffer to the capture pending buffers queue */
+/**
+ * fimc_pending_queue_add - add buffer to the capture pending buffers queue
+ * @buf: buffer to add to the pending buffers list
+ */
 static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap,
                                          struct fimc_vid_buffer *buf)
 {
        list_add_tail(&buf->list, &vid_cap->pending_buf_q);
 }
 
-/* Add video buffer to the capture pending buffers queue */
-static inline struct fimc_vid_buffer *
-pending_queue_pop(struct fimc_vid_cap *vid_cap)
+/**
+ * fimc_pending_queue_pop - pop buffer from the capture pending buffers queue
+ *
+ * The caller must assure the pending_buf_q list is not empty.
+ */
+static inline struct fimc_vid_buffer *fimc_pending_queue_pop(
+                                    struct fimc_vid_cap *vid_cap)
 {
        struct fimc_vid_buffer *buf;
        buf = list_entry(vid_cap->pending_buf_q.next,
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c
new file mode 100644 (file)
index 0000000..cc337b1
--- /dev/null
@@ -0,0 +1,858 @@
+/*
+ * S5P/EXYNOS4 SoC series camera host interface media device driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <media/v4l2-ctrls.h>
+#include <media/media-device.h>
+
+#include "fimc-core.h"
+#include "fimc-mdevice.h"
+#include "mipi-csis.h"
+
+static int __fimc_md_set_camclk(struct fimc_md *fmd,
+                               struct fimc_sensor_info *s_info,
+                               bool on);
+/**
+ * fimc_pipeline_prepare - update pipeline information with subdevice pointers
+ * @fimc: fimc device terminating the pipeline
+ *
+ * Caller holds the graph mutex.
+ */
+void fimc_pipeline_prepare(struct fimc_dev *fimc, struct media_entity *me)
+{
+       struct media_entity_graph graph;
+       struct v4l2_subdev *sd;
+
+       media_entity_graph_walk_start(&graph, me);
+
+       while ((me = media_entity_graph_walk_next(&graph))) {
+               if (media_entity_type(me) != MEDIA_ENT_T_V4L2_SUBDEV)
+                       continue;
+               sd = media_entity_to_v4l2_subdev(me);
+
+               if (sd->grp_id == SENSOR_GROUP_ID)
+                       fimc->pipeline.sensor = sd;
+               else if (sd->grp_id == CSIS_GROUP_ID)
+                       fimc->pipeline.csis = sd;
+       }
+}
+
+/**
+ * __subdev_set_power - change power state of a single subdev
+ * @sd: subdevice to change power state for
+ * @on: 1 to enable power or 0 to disable
+ *
+ * Return result of s_power subdev operation or -ENXIO if sd argument
+ * is NULL. Return 0 if the subdevice does not implement s_power.
+ */
+static int __subdev_set_power(struct v4l2_subdev *sd, int on)
+{
+       int *use_count;
+       int ret;
+
+       if (sd == NULL)
+               return -ENXIO;
+
+       use_count = &sd->entity.use_count;
+       if (on && (*use_count)++ > 0)
+               return 0;
+       else if (!on && (*use_count == 0 || --(*use_count) > 0))
+               return 0;
+       ret = v4l2_subdev_call(sd, core, s_power, on);
+
+       return ret != -ENOIOCTLCMD ? ret : 0;
+}
+
+/**
+ * fimc_pipeline_s_power - change power state of all pipeline subdevs
+ * @fimc: fimc device terminating the pipeline
+ * @state: 1 to enable power or 0 for power down
+ *
+ * Need to be called with the graph mutex held.
+ */
+int fimc_pipeline_s_power(struct fimc_dev *fimc, int state)
+{
+       int ret = 0;
+
+       if (fimc->pipeline.sensor == NULL)
+               return -ENXIO;
+
+       if (state) {
+               ret = __subdev_set_power(fimc->pipeline.csis, 1);
+               if (ret && ret != -ENXIO)
+                       return ret;
+               return __subdev_set_power(fimc->pipeline.sensor, 1);
+       }
+
+       ret = __subdev_set_power(fimc->pipeline.sensor, 0);
+       if (ret)
+               return ret;
+       ret = __subdev_set_power(fimc->pipeline.csis, 0);
+
+       return ret == -ENXIO ? 0 : ret;
+}
+
+/**
+ * __fimc_pipeline_initialize - update the pipeline information, enable power
+ *                              of all pipeline subdevs and the sensor clock
+ * @me: media entity to start graph walk with
+ * @prep: true to acquire sensor (and csis) subdevs
+ *
+ * This function must be called with the graph mutex held.
+ */
+static int __fimc_pipeline_initialize(struct fimc_dev *fimc,
+                                     struct media_entity *me, bool prep)
+{
+       int ret;
+
+       if (prep)
+               fimc_pipeline_prepare(fimc, me);
+       if (fimc->pipeline.sensor == NULL)
+               return -EINVAL;
+       ret = fimc_md_set_camclk(fimc->pipeline.sensor, true);
+       if (ret)
+               return ret;
+       return fimc_pipeline_s_power(fimc, 1);
+}
+
+int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me,
+                            bool prep)
+{
+       int ret;
+
+       mutex_lock(&me->parent->graph_mutex);
+       ret =  __fimc_pipeline_initialize(fimc, me, prep);
+       mutex_unlock(&me->parent->graph_mutex);
+
+       return ret;
+}
+
+/**
+ * __fimc_pipeline_shutdown - disable the sensor clock and pipeline power
+ * @fimc: fimc device terminating the pipeline
+ *
+ * Disable power of all subdevs in the pipeline and turn off the external
+ * sensor clock.
+ * Called with the graph mutex held.
+ */
+int __fimc_pipeline_shutdown(struct fimc_dev *fimc)
+{
+       int ret = 0;
+
+       if (fimc->pipeline.sensor) {
+               ret = fimc_pipeline_s_power(fimc, 0);
+               fimc_md_set_camclk(fimc->pipeline.sensor, false);
+       }
+       return ret == -ENXIO ? 0 : ret;
+}
+
+int fimc_pipeline_shutdown(struct fimc_dev *fimc)
+{
+       struct media_entity *me = &fimc->vid_cap.vfd->entity;
+       int ret;
+
+       mutex_lock(&me->parent->graph_mutex);
+       ret = __fimc_pipeline_shutdown(fimc);
+       mutex_unlock(&me->parent->graph_mutex);
+
+       return ret;
+}
+
+/**
+ * fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs
+ * @fimc: fimc device terminating the pipeline
+ * @on: passed as the s_stream call argument
+ */
+int fimc_pipeline_s_stream(struct fimc_dev *fimc, int on)
+{
+       struct fimc_pipeline *p = &fimc->pipeline;
+       int ret = 0;
+
+       if (p->sensor == NULL)
+               return -ENODEV;
+
+       if ((on && p->csis) || !on)
+               ret = v4l2_subdev_call(on ? p->csis : p->sensor,
+                                      video, s_stream, on);
+       if (ret < 0 && ret != -ENOIOCTLCMD)
+               return ret;
+       if ((!on && p->csis) || on)
+               ret = v4l2_subdev_call(on ? p->sensor : p->csis,
+                                      video, s_stream, on);
+       return ret == -ENOIOCTLCMD ? 0 : ret;
+}
+
+/*
+ * Sensor subdevice helper functions
+ */
+static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd,
+                                  struct fimc_sensor_info *s_info)
+{
+       struct i2c_adapter *adapter;
+       struct v4l2_subdev *sd = NULL;
+
+       if (!s_info || !fmd)
+               return NULL;
+
+       adapter = i2c_get_adapter(s_info->pdata->i2c_bus_num);
+       if (!adapter)
+               return NULL;
+       sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter,
+                                      s_info->pdata->board_info, NULL);
+       if (IS_ERR_OR_NULL(sd)) {
+               v4l2_err(&fmd->v4l2_dev, "Failed to acquire subdev\n");
+               return NULL;
+       }
+       v4l2_set_subdev_hostdata(sd, s_info);
+       sd->grp_id = SENSOR_GROUP_ID;
+
+       v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice %s\n",
+                 s_info->pdata->board_info->type);
+       return sd;
+}
+
+static void fimc_md_unregister_sensor(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!client)
+               return;
+       v4l2_device_unregister_subdev(sd);
+       i2c_unregister_device(client);
+       i2c_put_adapter(client->adapter);
+}
+
+static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
+{
+       struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data;
+       struct fimc_dev *fd = NULL;
+       int num_clients, ret, i;
+
+       /*
+        * Runtime resume one of the FIMC entities to make sure
+        * the sclk_cam clocks are not globally disabled.
+        */
+       for (i = 0; !fd && i < ARRAY_SIZE(fmd->fimc); i++)
+               if (fmd->fimc[i])
+                       fd = fmd->fimc[i];
+       if (!fd)
+               return -ENXIO;
+       ret = pm_runtime_get_sync(&fd->pdev->dev);
+       if (ret < 0)
+               return ret;
+
+       WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor));
+       num_clients = min_t(u32, pdata->num_clients, ARRAY_SIZE(fmd->sensor));
+
+       fmd->num_sensors = num_clients;
+       for (i = 0; i < num_clients; i++) {
+               fmd->sensor[i].pdata = &pdata->isp_info[i];
+               ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true);
+               if (ret)
+                       break;
+               fmd->sensor[i].subdev =
+                       fimc_md_register_sensor(fmd, &fmd->sensor[i]);
+               ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false);
+               if (ret)
+                       break;
+       }
+       pm_runtime_put(&fd->pdev->dev);
+       return ret;
+}
+
+/*
+ * MIPI CSIS and FIMC platform devices registration.
+ */
+static int fimc_register_callback(struct device *dev, void *p)
+{
+       struct fimc_dev *fimc = dev_get_drvdata(dev);
+       struct fimc_md *fmd = p;
+       int ret;
+
+       if (!fimc || !fimc->pdev)
+               return 0;
+       if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS)
+               return 0;
+
+       fmd->fimc[fimc->pdev->id] = fimc;
+       ret = fimc_register_m2m_device(fimc, &fmd->v4l2_dev);
+       if (ret)
+               return ret;
+       ret = fimc_register_capture_device(fimc, &fmd->v4l2_dev);
+       if (!ret)
+               fimc->vid_cap.user_subdev_api = fmd->user_subdev_api;
+       return ret;
+}
+
+static int csis_register_callback(struct device *dev, void *p)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct platform_device *pdev;
+       struct fimc_md *fmd = p;
+       int id, ret;
+
+       if (!sd)
+               return 0;
+       pdev = v4l2_get_subdevdata(sd);
+       if (!pdev || pdev->id < 0 || pdev->id >= CSIS_MAX_ENTITIES)
+               return 0;
+       v4l2_info(sd, "csis%d sd: %s\n", pdev->id, sd->name);
+
+       id = pdev->id < 0 ? 0 : pdev->id;
+       fmd->csis[id].sd = sd;
+       sd->grp_id = CSIS_GROUP_ID;
+       ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+       if (ret)
+               v4l2_err(&fmd->v4l2_dev,
+                        "Failed to register CSIS subdevice: %d\n", ret);
+       return ret;
+}
+
+/**
+ * fimc_md_register_platform_entities - register FIMC and CSIS media entities
+ */
+static int fimc_md_register_platform_entities(struct fimc_md *fmd)
+{
+       struct device_driver *driver;
+       int ret;
+
+       driver = driver_find(FIMC_MODULE_NAME, &platform_bus_type);
+       if (!driver)
+               return -ENODEV;
+       ret = driver_for_each_device(driver, NULL, fmd,
+                                    fimc_register_callback);
+       put_driver(driver);
+       if (ret)
+               return ret;
+
+       driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type);
+       if (driver) {
+               ret = driver_for_each_device(driver, NULL, fmd,
+                                            csis_register_callback);
+               put_driver(driver);
+       }
+       return ret;
+}
+
+static void fimc_md_unregister_entities(struct fimc_md *fmd)
+{
+       int i;
+
+       for (i = 0; i < FIMC_MAX_DEVS; i++) {
+               if (fmd->fimc[i] == NULL)
+                       continue;
+               fimc_unregister_m2m_device(fmd->fimc[i]);
+               fimc_unregister_capture_device(fmd->fimc[i]);
+               fmd->fimc[i] = NULL;
+       }
+       for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
+               if (fmd->csis[i].sd == NULL)
+                       continue;
+               v4l2_device_unregister_subdev(fmd->csis[i].sd);
+               fmd->csis[i].sd = NULL;
+       }
+       for (i = 0; i < fmd->num_sensors; i++) {
+               if (fmd->sensor[i].subdev == NULL)
+                       continue;
+               fimc_md_unregister_sensor(fmd->sensor[i].subdev);
+               fmd->sensor[i].subdev = NULL;
+       }
+}
+
+static int fimc_md_register_video_nodes(struct fimc_md *fmd)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < FIMC_MAX_DEVS && !ret; i++) {
+               if (!fmd->fimc[i])
+                       continue;
+
+               if (fmd->fimc[i]->m2m.vfd)
+                       ret = video_register_device(fmd->fimc[i]->m2m.vfd,
+                                                   VFL_TYPE_GRABBER, -1);
+               if (ret)
+                       break;
+               if (fmd->fimc[i]->vid_cap.vfd)
+                       ret = video_register_device(fmd->fimc[i]->vid_cap.vfd,
+                                                   VFL_TYPE_GRABBER, -1);
+       }
+
+       return ret;
+}
+
+/**
+ * __fimc_md_create_fimc_links - create links to all FIMC entities
+ * @fmd: fimc media device
+ * @source: the source entity to create links to all fimc entities from
+ * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null
+ * @pad: the source entity pad index
+ * @fimc_id: index of the fimc device for which link should be enabled
+ */
+static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
+                                      struct media_entity *source,
+                                      struct v4l2_subdev *sensor,
+                                      int pad, int fimc_id)
+{
+       struct fimc_sensor_info *s_info;
+       struct media_entity *sink;
+       unsigned int flags;
+       int ret, i;
+
+       for (i = 0; i < FIMC_MAX_DEVS; i++) {
+               if (!fmd->fimc[i])
+                       break;
+               /*
+                * Some FIMC variants are not fitted with camera capture
+                * interface. Skip creating a link from sensor for those.
+                */
+               if (sensor->grp_id == SENSOR_GROUP_ID &&
+                   !fmd->fimc[i]->variant->has_cam_if)
+                       continue;
+
+               flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
+               sink = &fmd->fimc[i]->vid_cap.subdev->entity;
+               ret = media_entity_create_link(source, pad, sink,
+                                             FIMC_SD_PAD_SINK, flags);
+               if (ret)
+                       return ret;
+
+               /* Notify FIMC capture subdev entity */
+               ret = media_entity_call(sink, link_setup, &sink->pads[0],
+                                       &source->pads[pad], flags);
+               if (ret)
+                       break;
+
+               v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
+                         source->name, flags ? '=' : '-', sink->name);
+
+               if (flags == 0)
+                       continue;
+               s_info = v4l2_get_subdev_hostdata(sensor);
+               if (!WARN_ON(s_info == NULL)) {
+                       unsigned long irq_flags;
+                       spin_lock_irqsave(&fmd->slock, irq_flags);
+                       s_info->host = fmd->fimc[i];
+                       spin_unlock_irqrestore(&fmd->slock, irq_flags);
+               }
+       }
+       return 0;
+}
+
+/**
+ * fimc_md_create_links - create default links between registered entities
+ *
+ * Parallel interface sensor entities are connected directly to FIMC capture
+ * entities. The sensors using MIPI CSIS bus are connected through immutable
+ * link with CSI receiver entity specified by mux_id. Any registered CSIS
+ * entity has a link to each registered FIMC capture entity. Enabled links
+ * are created by default between each subsequent registered sensor and
+ * subsequent FIMC capture entity. The number of default active links is
+ * determined by the number of available sensors or FIMC entities,
+ * whichever is less.
+ */
+static int fimc_md_create_links(struct fimc_md *fmd)
+{
+       struct v4l2_subdev *sensor, *csis;
+       struct s5p_fimc_isp_info *pdata;
+       struct fimc_sensor_info *s_info;
+       struct media_entity *source, *sink;
+       int i, pad, fimc_id = 0;
+       int ret = 0;
+       u32 flags;
+
+       for (i = 0; i < fmd->num_sensors; i++) {
+               if (fmd->sensor[i].subdev == NULL)
+                       continue;
+
+               sensor = fmd->sensor[i].subdev;
+               s_info = v4l2_get_subdev_hostdata(sensor);
+               if (!s_info || !s_info->pdata)
+                       continue;
+
+               source = NULL;
+               pdata = s_info->pdata;
+
+               switch (pdata->bus_type) {
+               case FIMC_MIPI_CSI2:
+                       if (WARN(pdata->mux_id >= CSIS_MAX_ENTITIES,
+                               "Wrong CSI channel id: %d\n", pdata->mux_id))
+                               return -EINVAL;
+
+                       csis = fmd->csis[pdata->mux_id].sd;
+                       if (WARN(csis == NULL,
+                                "MIPI-CSI interface specified "
+                                "but s5p-csis module is not loaded!\n"))
+                               continue;
+
+                       ret = media_entity_create_link(&sensor->entity, 0,
+                                             &csis->entity, CSIS_PAD_SINK,
+                                             MEDIA_LNK_FL_IMMUTABLE |
+                                             MEDIA_LNK_FL_ENABLED);
+                       if (ret)
+                               return ret;
+
+                       v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]",
+                                 sensor->entity.name, csis->entity.name);
+
+                       source = &csis->entity;
+                       pad = CSIS_PAD_SOURCE;
+                       break;
+
+               case FIMC_ITU_601...FIMC_ITU_656:
+                       source = &sensor->entity;
+                       pad = 0;
+                       break;
+
+               default:
+                       v4l2_err(&fmd->v4l2_dev, "Wrong bus_type: %x\n",
+                                pdata->bus_type);
+                       return -EINVAL;
+               }
+               if (source == NULL)
+                       continue;
+
+               ret = __fimc_md_create_fimc_links(fmd, source, sensor, pad,
+                                                 fimc_id++);
+       }
+       /* Create immutable links between each FIMC's subdev and video node */
+       flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
+       for (i = 0; i < FIMC_MAX_DEVS; i++) {
+               if (!fmd->fimc[i])
+                       continue;
+               source = &fmd->fimc[i]->vid_cap.subdev->entity;
+               sink = &fmd->fimc[i]->vid_cap.vfd->entity;
+               ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
+                                             sink, 0, flags);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+/*
+ * The peripheral sensor clock management.
+ */
+static int fimc_md_get_clocks(struct fimc_md *fmd)
+{
+       char clk_name[32];
+       struct clk *clock;
+       int i;
+
+       for (i = 0; i < FIMC_MAX_CAMCLKS; i++) {
+               snprintf(clk_name, sizeof(clk_name), "sclk_cam%u", i);
+               clock = clk_get(NULL, clk_name);
+               if (IS_ERR_OR_NULL(clock)) {
+                       v4l2_err(&fmd->v4l2_dev, "Failed to get clock: %s",
+                                 clk_name);
+                       return -ENXIO;
+               }
+               fmd->camclk[i].clock = clock;
+       }
+       return 0;
+}
+
+static void fimc_md_put_clocks(struct fimc_md *fmd)
+{
+       int i = FIMC_MAX_CAMCLKS;
+
+       while (--i >= 0) {
+               if (IS_ERR_OR_NULL(fmd->camclk[i].clock))
+                       continue;
+               clk_put(fmd->camclk[i].clock);
+               fmd->camclk[i].clock = NULL;
+       }
+}
+
+static int __fimc_md_set_camclk(struct fimc_md *fmd,
+                                        struct fimc_sensor_info *s_info,
+                                        bool on)
+{
+       struct s5p_fimc_isp_info *pdata = s_info->pdata;
+       struct fimc_camclk_info *camclk;
+       int ret = 0;
+
+       if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || fmd == NULL)
+               return -EINVAL;
+
+       if (s_info->clk_on == on)
+               return 0;
+       camclk = &fmd->camclk[pdata->clk_id];
+
+       dbg("camclk %d, f: %lu, clk: %p, on: %d",
+           pdata->clk_id, pdata->clk_frequency, camclk, on);
+
+       if (on) {
+               if (camclk->use_count > 0 &&
+                   camclk->frequency != pdata->clk_frequency)
+                       return -EINVAL;
+
+               if (camclk->use_count++ == 0) {
+                       clk_set_rate(camclk->clock, pdata->clk_frequency);
+                       camclk->frequency = pdata->clk_frequency;
+                       ret = clk_enable(camclk->clock);
+               }
+               s_info->clk_on = 1;
+               dbg("Enabled camclk %d: f: %lu", pdata->clk_id,
+                   clk_get_rate(camclk->clock));
+
+               return ret;
+       }
+
+       if (WARN_ON(camclk->use_count == 0))
+               return 0;
+
+       if (--camclk->use_count == 0) {
+               clk_disable(camclk->clock);
+               s_info->clk_on = 0;
+               dbg("Disabled camclk %d", pdata->clk_id);
+       }
+       return ret;
+}
+
+/**
+ * fimc_md_set_camclk - peripheral sensor clock setup
+ * @sd: sensor subdev to configure sclk_cam clock for
+ * @on: 1 to enable or 0 to disable the clock
+ *
+ * There are 2 separate clock outputs available in the SoC for external
+ * image processors. These clocks are shared between all registered FIMC
+ * devices to which sensors can be attached, either directly or through
+ * the MIPI CSI receiver. The clock is allowed here to be used by
+ * multiple sensors concurrently if they use same frequency.
+ * The per sensor subdev clk_on attribute helps to synchronize accesses
+ * to the sclk_cam clocks from the video and media device nodes.
+ * This function should only be called when the graph mutex is held.
+ */
+int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
+{
+       struct fimc_sensor_info *s_info = v4l2_get_subdev_hostdata(sd);
+       struct fimc_md *fmd = entity_to_fimc_mdev(&sd->entity);
+
+       return __fimc_md_set_camclk(fmd, s_info, on);
+}
+
+static int fimc_md_link_notify(struct media_pad *source,
+                              struct media_pad *sink, u32 flags)
+{
+       struct v4l2_subdev *sd;
+       struct fimc_dev *fimc;
+       int ret = 0;
+
+       if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+               return 0;
+
+       sd = media_entity_to_v4l2_subdev(sink->entity);
+       fimc = v4l2_get_subdevdata(sd);
+
+       if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+               ret = __fimc_pipeline_shutdown(fimc);
+               fimc->pipeline.sensor = NULL;
+               fimc->pipeline.csis = NULL;
+
+               mutex_lock(&fimc->lock);
+               fimc_ctrls_delete(fimc->vid_cap.ctx);
+               mutex_unlock(&fimc->lock);
+               return ret;
+       }
+       /*
+        * Link activation. Enable power of pipeline elements only if the
+        * pipeline is already in use, i.e. its video node is opened.
+        * Recreate the controls destroyed during the link deactivation.
+        */
+       mutex_lock(&fimc->lock);
+       if (fimc->vid_cap.refcnt > 0) {
+               ret = __fimc_pipeline_initialize(fimc, source->entity, true);
+               if (!ret)
+                       ret = fimc_capture_ctrls_create(fimc);
+       }
+       mutex_unlock(&fimc->lock);
+
+       return ret ? -EPIPE : ret;
+}
+
+static ssize_t fimc_md_sysfs_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct fimc_md *fmd = platform_get_drvdata(pdev);
+
+       if (fmd->user_subdev_api)
+               return strlcpy(buf, "Sub-device API (sub-dev)\n", PAGE_SIZE);
+
+       return strlcpy(buf, "V4L2 video node only API (vid-dev)\n", PAGE_SIZE);
+}
+
+static ssize_t fimc_md_sysfs_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct fimc_md *fmd = platform_get_drvdata(pdev);
+       bool subdev_api;
+       int i;
+
+       if (!strcmp(buf, "vid-dev\n"))
+               subdev_api = false;
+       else if (!strcmp(buf, "sub-dev\n"))
+               subdev_api = true;
+       else
+               return count;
+
+       fmd->user_subdev_api = subdev_api;
+       for (i = 0; i < FIMC_MAX_DEVS; i++)
+               if (fmd->fimc[i])
+                       fmd->fimc[i]->vid_cap.user_subdev_api = subdev_api;
+       return count;
+}
+/*
+ * This device attribute is to select video pipeline configuration method.
+ * There are following valid values:
+ *  vid-dev - for V4L2 video node API only, subdevice will be configured
+ *  by the host driver.
+ *  sub-dev - for media controller API, subdevs must be configured in user
+ *  space before starting streaming.
+ */
+static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO,
+                  fimc_md_sysfs_show, fimc_md_sysfs_store);
+
+static int __devinit fimc_md_probe(struct platform_device *pdev)
+{
+       struct v4l2_device *v4l2_dev;
+       struct fimc_md *fmd;
+       int ret;
+
+       if (WARN(!pdev->dev.platform_data, "Platform data not specified!\n"))
+               return -EINVAL;
+
+       fmd = kzalloc(sizeof(struct fimc_md), GFP_KERNEL);
+       if (!fmd)
+               return -ENOMEM;
+
+       spin_lock_init(&fmd->slock);
+       fmd->pdev = pdev;
+
+       strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC",
+               sizeof(fmd->media_dev.model));
+       fmd->media_dev.link_notify = fimc_md_link_notify;
+       fmd->media_dev.dev = &pdev->dev;
+
+       v4l2_dev = &fmd->v4l2_dev;
+       v4l2_dev->mdev = &fmd->media_dev;
+       v4l2_dev->notify = fimc_sensor_notify;
+       snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s",
+                dev_name(&pdev->dev));
+
+       ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev);
+       if (ret < 0) {
+               v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
+               goto err1;
+       }
+       ret = media_device_register(&fmd->media_dev);
+       if (ret < 0) {
+               v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret);
+               goto err2;
+       }
+       ret = fimc_md_get_clocks(fmd);
+       if (ret)
+               goto err3;
+
+       fmd->user_subdev_api = false;
+       ret = fimc_md_register_platform_entities(fmd);
+       if (ret)
+               goto err3;
+
+       ret = fimc_md_register_sensor_entities(fmd);
+       if (ret)
+               goto err3;
+       ret = fimc_md_create_links(fmd);
+       if (ret)
+               goto err3;
+       ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev);
+       if (ret)
+               goto err3;
+       ret = fimc_md_register_video_nodes(fmd);
+       if (ret)
+               goto err3;
+
+       ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode);
+       if (!ret) {
+               platform_set_drvdata(pdev, fmd);
+               return 0;
+       }
+err3:
+       media_device_unregister(&fmd->media_dev);
+       fimc_md_put_clocks(fmd);
+       fimc_md_unregister_entities(fmd);
+err2:
+       v4l2_device_unregister(&fmd->v4l2_dev);
+err1:
+       kfree(fmd);
+       return ret;
+}
+
+static int __devexit fimc_md_remove(struct platform_device *pdev)
+{
+       struct fimc_md *fmd = platform_get_drvdata(pdev);
+
+       if (!fmd)
+               return 0;
+       device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
+       fimc_md_unregister_entities(fmd);
+       media_device_unregister(&fmd->media_dev);
+       fimc_md_put_clocks(fmd);
+       kfree(fmd);
+       return 0;
+}
+
+static struct platform_driver fimc_md_driver = {
+       .probe          = fimc_md_probe,
+       .remove         = __devexit_p(fimc_md_remove),
+       .driver = {
+               .name   = "s5p-fimc-md",
+               .owner  = THIS_MODULE,
+       }
+};
+
+int __init fimc_md_init(void)
+{
+       int ret;
+       request_module("s5p-csis");
+       ret = fimc_register_driver();
+       if (ret)
+               return ret;
+       return platform_driver_register(&fimc_md_driver);
+}
+void __exit fimc_md_exit(void)
+{
+       platform_driver_unregister(&fimc_md_driver);
+       fimc_unregister_driver();
+}
+
+module_init(fimc_md_init);
+module_exit(fimc_md_exit);
+
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("2.0.1");
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.h b/drivers/media/video/s5p-fimc/fimc-mdevice.h
new file mode 100644 (file)
index 0000000..da37808
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_MDEVICE_H_
+#define FIMC_MDEVICE_H_
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <media/media-device.h>
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "fimc-core.h"
+#include "mipi-csis.h"
+
+/* Group IDs of sensor, MIPI CSIS and the writeback subdevs. */
+#define SENSOR_GROUP_ID                (1 << 8)
+#define CSIS_GROUP_ID          (1 << 9)
+#define WRITEBACK_GROUP_ID     (1 << 10)
+
+#define FIMC_MAX_SENSORS       8
+#define FIMC_MAX_CAMCLKS       2
+
+struct fimc_csis_info {
+       struct v4l2_subdev *sd;
+       int id;
+};
+
+struct fimc_camclk_info {
+       struct clk *clock;
+       int use_count;
+       unsigned long frequency;
+};
+
+/**
+ * struct fimc_sensor_info - image data source subdev information
+ * @pdata: sensor's atrributes passed as media device's platform data
+ * @subdev: image sensor v4l2 subdev
+ * @host: fimc device the sensor is currently linked to
+ * @clk_on: sclk_cam clock's state associated with this subdev
+ *
+ * This data structure applies to image sensor and the writeback subdevs.
+ */
+struct fimc_sensor_info {
+       struct s5p_fimc_isp_info *pdata;
+       struct v4l2_subdev *subdev;
+       struct fimc_dev *host;
+       bool clk_on;
+};
+
+/**
+ * struct fimc_md - fimc media device information
+ * @csis: MIPI CSIS subdevs data
+ * @sensor: array of registered sensor subdevs
+ * @num_sensors: actual number of registered sensors
+ * @camclk: external sensor clock information
+ * @fimc: array of registered fimc devices
+ * @media_dev: top level media device
+ * @v4l2_dev: top level v4l2_device holding up the subdevs
+ * @pdev: platform device this media device is hooked up into
+ * @user_subdev_api: true if subdevs are not configured by the host driver
+ * @slock: spinlock protecting @sensor array
+ */
+struct fimc_md {
+       struct fimc_csis_info csis[CSIS_MAX_ENTITIES];
+       struct fimc_sensor_info sensor[FIMC_MAX_SENSORS];
+       int num_sensors;
+       struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS];
+       struct fimc_dev *fimc[FIMC_MAX_DEVS];
+       struct media_device media_dev;
+       struct v4l2_device v4l2_dev;
+       struct platform_device *pdev;
+       bool user_subdev_api;
+       spinlock_t slock;
+};
+
+#define is_subdev_pad(pad) (pad == NULL || \
+       media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV)
+
+#define me_subtype(me) \
+       ((me->type) & (MEDIA_ENT_TYPE_MASK | MEDIA_ENT_SUBTYPE_MASK))
+
+#define subdev_has_devnode(__sd) (__sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)
+
+static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me)
+{
+       return me->parent == NULL ? NULL :
+               container_of(me->parent, struct fimc_md, media_dev);
+}
+
+static inline void fimc_md_graph_lock(struct fimc_dev *fimc)
+{
+       BUG_ON(fimc->vid_cap.vfd == NULL);
+       mutex_lock(&fimc->vid_cap.vfd->entity.parent->graph_mutex);
+}
+
+static inline void fimc_md_graph_unlock(struct fimc_dev *fimc)
+{
+       BUG_ON(fimc->vid_cap.vfd == NULL);
+       mutex_unlock(&fimc->vid_cap.vfd->entity.parent->graph_mutex);
+}
+
+int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on);
+void fimc_pipeline_prepare(struct fimc_dev *fimc, struct media_entity *me);
+int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me,
+                            bool resume);
+int fimc_pipeline_shutdown(struct fimc_dev *fimc);
+int fimc_pipeline_s_power(struct fimc_dev *fimc, int state);
+int fimc_pipeline_s_stream(struct fimc_dev *fimc, int state);
+
+#endif
index 4893b2d..20e664e 100644 (file)
@@ -30,7 +30,7 @@ void fimc_hw_reset(struct fimc_dev *dev)
        cfg = readl(dev->regs + S5P_CIGCTRL);
        cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL);
        writel(cfg, dev->regs + S5P_CIGCTRL);
-       udelay(1000);
+       udelay(10);
 
        cfg = readl(dev->regs + S5P_CIGCTRL);
        cfg &= ~S5P_CIGCTRL_SWRST;
@@ -41,19 +41,11 @@ static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx)
 {
        u32 flip = S5P_MSCTRL_FLIP_NORMAL;
 
-       switch (ctx->flip) {
-       case FLIP_X_AXIS:
+       if (ctx->hflip)
                flip = S5P_MSCTRL_FLIP_X_MIRROR;
-               break;
-       case FLIP_Y_AXIS:
+       if (ctx->vflip)
                flip = S5P_MSCTRL_FLIP_Y_MIRROR;
-               break;
-       case FLIP_XY_AXIS:
-               flip = S5P_MSCTRL_FLIP_180;
-               break;
-       default:
-               break;
-       }
+
        if (ctx->rotation <= 90)
                return flip;
 
@@ -64,19 +56,11 @@ static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx)
 {
        u32 flip = S5P_CITRGFMT_FLIP_NORMAL;
 
-       switch (ctx->flip) {
-       case FLIP_X_AXIS:
-               flip = S5P_CITRGFMT_FLIP_X_MIRROR;
-               break;
-       case FLIP_Y_AXIS:
-               flip = S5P_CITRGFMT_FLIP_Y_MIRROR;
-               break;
-       case FLIP_XY_AXIS:
-               flip = S5P_CITRGFMT_FLIP_180;
-               break;
-       default:
-               break;
-       }
+       if (ctx->hflip)
+               flip |= S5P_CITRGFMT_FLIP_X_MIRROR;
+       if (ctx->vflip)
+               flip |= S5P_CITRGFMT_FLIP_Y_MIRROR;
+
        if (ctx->rotation <= 90)
                return flip;
 
@@ -368,17 +352,19 @@ void fimc_hw_en_capture(struct fimc_ctx *ctx)
        writel(cfg | S5P_CIIMGCPT_IMGCPTEN, dev->regs + S5P_CIIMGCPT);
 }
 
-void fimc_hw_set_effect(struct fimc_ctx *ctx)
+void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active)
 {
        struct fimc_dev *dev = ctx->fimc_dev;
        struct fimc_effect *effect = &ctx->effect;
-       u32 cfg = (S5P_CIIMGEFF_IE_ENABLE | S5P_CIIMGEFF_IE_SC_AFTER);
-
-       cfg |= effect->type;
+       u32 cfg = 0;
 
-       if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) {
-               cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb);
-               cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr);
+       if (active) {
+               cfg |= S5P_CIIMGEFF_IE_SC_AFTER | S5P_CIIMGEFF_IE_ENABLE;
+               cfg |= effect->type;
+               if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) {
+                       cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb);
+                       cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr);
+               }
        }
 
        writel(cfg, dev->regs + S5P_CIIMGEFF);
@@ -547,20 +533,24 @@ int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
        u32 cfg = readl(fimc->regs + S5P_CIGCTRL);
 
        cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC |
-                S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC);
+                S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC |
+                S5P_CIGCTRL_INVPOLFIELD);
 
-       if (cam->flags & FIMC_CLK_INV_PCLK)
+       if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
                cfg |= S5P_CIGCTRL_INVPOLPCLK;
 
-       if (cam->flags & FIMC_CLK_INV_VSYNC)
+       if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
                cfg |= S5P_CIGCTRL_INVPOLVSYNC;
 
-       if (cam->flags & FIMC_CLK_INV_HREF)
+       if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
                cfg |= S5P_CIGCTRL_INVPOLHREF;
 
-       if (cam->flags & FIMC_CLK_INV_HSYNC)
+       if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
                cfg |= S5P_CIGCTRL_INVPOLHSYNC;
 
+       if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW)
+               cfg |= S5P_CIGCTRL_INVPOLFIELD;
+
        writel(cfg, fimc->regs + S5P_CIGCTRL);
 
        return 0;
@@ -588,7 +578,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
 
        if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
                for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
-                       if (fimc->vid_cap.fmt.code == pix_desc[i].pixelcode) {
+                       if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) {
                                cfg = pix_desc[i].cisrcfmt;
                                bus_width = pix_desc[i].bus_width;
                                break;
@@ -596,9 +586,9 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
                }
 
                if (i == ARRAY_SIZE(pix_desc)) {
-                       v4l2_err(&fimc->vid_cap.v4l2_dev,
+                       v4l2_err(fimc->vid_cap.vfd,
                                 "Camera color format not supported: %d\n",
-                                fimc->vid_cap.fmt.code);
+                                fimc->vid_cap.mf.code);
                        return -EINVAL;
                }
 
@@ -608,6 +598,9 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
                        else if (bus_width == 16)
                                cfg |= S5P_CISRCFMT_ITU601_16BIT;
                } /* else defaults to ITU-R BT.656 8-bit */
+       } else if (cam->bus_type == FIMC_MIPI_CSI2) {
+               if (fimc_fmt_is_jpeg(f->fmt->color))
+                       cfg |= S5P_CISRCFMT_ITU601_8BIT;
        }
 
        cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height);
@@ -649,7 +642,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
        /* Select ITU B interface, disable Writeback path and test pattern. */
        cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A |
                S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB |
-               S5P_CIGCTRL_SELCAM_MIPI_A);
+               S5P_CIGCTRL_SELCAM_MIPI_A | S5P_CIGCTRL_CAM_JPEG);
 
        if (cam->bus_type == FIMC_MIPI_CSI2) {
                cfg |= S5P_CIGCTRL_SELCAM_MIPI;
@@ -658,11 +651,18 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
                        cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
 
                /* TODO: add remaining supported formats. */
-               if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) {
+               switch (vid_cap->mf.code) {
+               case V4L2_MBUS_FMT_VYUY8_2X8:
                        tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
-               } else {
-                       err("camera image format not supported: %d",
-                           vid_cap->fmt.code);
+                       break;
+               case V4L2_MBUS_FMT_JPEG_1X8:
+                       tmp = S5P_CSIIMGFMT_USER(1);
+                       cfg |= S5P_CIGCTRL_CAM_JPEG;
+                       break;
+               default:
+                       v4l2_err(fimc->vid_cap.vfd,
+                                "Not supported camera pixel format: %d",
+                                vid_cap->mf.code);
                        return -EINVAL;
                }
                tmp |= (cam->csi_data_align == 32) << 8;
index ef056d6..59d79bc 100644 (file)
@@ -81,6 +81,12 @@ static char *csi_clock_name[] = {
 };
 #define NUM_CSIS_CLOCKS        ARRAY_SIZE(csi_clock_name)
 
+static const char * const csis_supply_name[] = {
+       "vdd11", /* 1.1V or 1.2V (s5pc100) MIPI CSI suppply */
+       "vdd18", /* VDD 1.8V and MIPI CSI PLL supply */
+};
+#define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name)
+
 enum {
        ST_POWERED      = 1,
        ST_STREAMING    = 2,
@@ -109,9 +115,9 @@ struct csis_state {
        struct platform_device *pdev;
        struct resource *regs_res;
        void __iomem *regs;
+       struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES];
        struct clk *clock[NUM_CSIS_CLOCKS];
        int irq;
-       struct regulator *supply;
        u32 flags;
        const struct csis_pix_format *csis_fmt;
        struct v4l2_mbus_framefmt format;
@@ -460,6 +466,7 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
        struct resource *regs_res;
        struct csis_state *state;
        int ret = -ENOMEM;
+       int i;
 
        state = kzalloc(sizeof(*state), GFP_KERNEL);
        if (!state)
@@ -519,14 +526,13 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
                goto e_clkput;
        }
 
-       if (!pdata->fixed_phy_vdd) {
-               state->supply = regulator_get(&pdev->dev, "vdd");
-               if (IS_ERR(state->supply)) {
-                       ret = PTR_ERR(state->supply);
-                       state->supply = NULL;
-                       goto e_clkput;
-               }
-       }
+       for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
+               state->supplies[i].supply = csis_supply_name[i];
+
+       ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES,
+                                state->supplies);
+       if (ret)
+               goto e_clkput;
 
        ret = request_irq(state->irq, s5pcsis_irq_handler, 0,
                          dev_name(&pdev->dev), state);
@@ -553,7 +559,6 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
        /* .. and a pointer to the subdev. */
        platform_set_drvdata(pdev, &state->sd);
 
-       state->flags = ST_SUSPENDED;
        pm_runtime_enable(&pdev->dev);
 
        return 0;
@@ -561,8 +566,7 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
 e_irqfree:
        free_irq(state->irq, state);
 e_regput:
-       if (state->supply)
-               regulator_put(state->supply);
+       regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
 e_clkput:
        clk_disable(state->clock[CSIS_CLK_MUX]);
        s5pcsis_clk_put(state);
@@ -575,7 +579,7 @@ e_free:
        return ret;
 }
 
-static int s5pcsis_suspend(struct device *dev)
+static int s5pcsis_pm_suspend(struct device *dev, bool runtime)
 {
        struct s5p_platform_mipi_csis *pdata = dev->platform_data;
        struct platform_device *pdev = to_platform_device(dev);
@@ -592,21 +596,21 @@ static int s5pcsis_suspend(struct device *dev)
                ret = pdata->phy_enable(state->pdev, false);
                if (ret)
                        goto unlock;
-               if (state->supply) {
-                       ret = regulator_disable(state->supply);
-                       if (ret)
-                               goto unlock;
-               }
+               ret = regulator_bulk_disable(CSIS_NUM_SUPPLIES,
+                                            state->supplies);
+               if (ret)
+                       goto unlock;
                clk_disable(state->clock[CSIS_CLK_GATE]);
                state->flags &= ~ST_POWERED;
+               if (!runtime)
+                       state->flags |= ST_SUSPENDED;
        }
-       state->flags |= ST_SUSPENDED;
  unlock:
        mutex_unlock(&state->lock);
        return ret ? -EAGAIN : 0;
 }
 
-static int s5pcsis_resume(struct device *dev)
+static int s5pcsis_pm_resume(struct device *dev, bool runtime)
 {
        struct s5p_platform_mipi_csis *pdata = dev->platform_data;
        struct platform_device *pdev = to_platform_device(dev);
@@ -618,20 +622,20 @@ static int s5pcsis_resume(struct device *dev)
                 __func__, state->flags);
 
        mutex_lock(&state->lock);
-       if (!(state->flags & ST_SUSPENDED))
+       if (!runtime && !(state->flags & ST_SUSPENDED))
                goto unlock;
 
        if (!(state->flags & ST_POWERED)) {
-               if (state->supply)
-                       ret = regulator_enable(state->supply);
+               ret = regulator_bulk_enable(CSIS_NUM_SUPPLIES,
+                                           state->supplies);
                if (ret)
                        goto unlock;
-
                ret = pdata->phy_enable(state->pdev, true);
                if (!ret) {
                        state->flags |= ST_POWERED;
-               } else if (state->supply) {
-                       regulator_disable(state->supply);
+               } else {
+                       regulator_bulk_disable(CSIS_NUM_SUPPLIES,
+                                              state->supplies);
                        goto unlock;
                }
                clk_enable(state->clock[CSIS_CLK_GATE]);
@@ -646,24 +650,26 @@ static int s5pcsis_resume(struct device *dev)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int s5pcsis_pm_suspend(struct device *dev)
+static int s5pcsis_suspend(struct device *dev)
 {
-       return s5pcsis_suspend(dev);
+       return s5pcsis_pm_suspend(dev, false);
 }
 
-static int s5pcsis_pm_resume(struct device *dev)
+static int s5pcsis_resume(struct device *dev)
 {
-       int ret;
-
-       ret = s5pcsis_resume(dev);
+       return s5pcsis_pm_resume(dev, false);
+}
+#endif
 
-       if (!ret) {
-               pm_runtime_disable(dev);
-               ret = pm_runtime_set_active(dev);
-               pm_runtime_enable(dev);
-       }
+#ifdef CONFIG_PM_RUNTIME
+static int s5pcsis_runtime_suspend(struct device *dev)
+{
+       return s5pcsis_pm_suspend(dev, true);
+}
 
-       return ret;
+static int s5pcsis_runtime_resume(struct device *dev)
+{
+       return s5pcsis_pm_resume(dev, true);
 }
 #endif
 
@@ -679,8 +685,7 @@ static int __devexit s5pcsis_remove(struct platform_device *pdev)
        pm_runtime_set_suspended(&pdev->dev);
 
        s5pcsis_clk_put(state);
-       if (state->supply)
-               regulator_put(state->supply);
+       regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
 
        media_entity_cleanup(&state->sd.entity);
        free_irq(state->irq, state);
@@ -692,8 +697,9 @@ static int __devexit s5pcsis_remove(struct platform_device *pdev)
 }
 
 static const struct dev_pm_ops s5pcsis_pm_ops = {
-       SET_RUNTIME_PM_OPS(s5pcsis_suspend, s5pcsis_resume, NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_pm_suspend, s5pcsis_pm_resume)
+       SET_RUNTIME_PM_OPS(s5pcsis_runtime_suspend, s5pcsis_runtime_resume,
+                          NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume)
 };
 
 static struct platform_driver s5pcsis_driver = {
index 0fea3e6..c8e3b94 100644 (file)
 #define S5P_CIGCTRL_IRQ_CLR            (1 << 19)
 #define S5P_CIGCTRL_IRQ_ENABLE         (1 << 16)
 #define S5P_CIGCTRL_SHDW_DISABLE       (1 << 12)
+#define S5P_CIGCTRL_CAM_JPEG           (1 << 8)
 #define S5P_CIGCTRL_SELCAM_MIPI_A      (1 << 7)
 #define S5P_CIGCTRL_CAMIF_SELWB                (1 << 6)
 /* 0 - ITU601; 1 - ITU709 */
 #define S5P_CIGCTRL_CSC_ITU601_709     (1 << 5)
 #define S5P_CIGCTRL_INVPOLHSYNC                (1 << 4)
 #define S5P_CIGCTRL_SELCAM_MIPI                (1 << 3)
+#define S5P_CIGCTRL_INVPOLFIELD                (1 << 1)
 #define S5P_CIGCTRL_INTERLACE          (1 << 0)
 
 /* Window offset 2 */
 
 /* Image effect */
 #define S5P_CIIMGEFF                   0xd0
-#define S5P_CIIMGEFF_IE_DISABLE                (0 << 30)
 #define S5P_CIIMGEFF_IE_ENABLE         (1 << 30)
 #define S5P_CIIMGEFF_IE_SC_BEFORE      (0 << 29)
 #define S5P_CIIMGEFF_IE_SC_AFTER       (1 << 29)
 #define S5P_CSIIMGFMT_RAW8             0x2a
 #define S5P_CSIIMGFMT_RAW10            0x2b
 #define S5P_CSIIMGFMT_RAW12            0x2c
-#define S5P_CSIIMGFMT_USER1            0x30
-#define S5P_CSIIMGFMT_USER2            0x31
-#define S5P_CSIIMGFMT_USER3            0x32
-#define S5P_CSIIMGFMT_USER4            0x33
+/* User defined formats. x = 0...16. */
+#define S5P_CSIIMGFMT_USER(x)          (0x30 + x - 1)
 
 /* Output frame buffer sequence mask */
 #define S5P_CIFCNTSEQ                  0x1FC
index 7dc7eab..8be8b54 100644 (file)
@@ -202,7 +202,7 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
           appropraite flags */
        src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
        list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
-               if (vb2_dma_contig_plane_paddr(dst_buf->b, 0) == dec_y_addr) {
+               if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dec_y_addr) {
                        memcpy(&dst_buf->b->v4l2_buf.timecode,
                                &src_buf->b->v4l2_buf.timecode,
                                sizeof(struct v4l2_timecode));
@@ -248,7 +248,7 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
         * check which videobuf does it correspond to */
        list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
                /* Check if this is the buffer we're looking for */
-               if (vb2_dma_contig_plane_paddr(dst_buf->b, 0) == dspl_y_addr) {
+               if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dspl_y_addr) {
                        list_del(&dst_buf->list);
                        ctx->dst_queue_cnt--;
                        dst_buf->b->v4l2_buf.sequence = ctx->sequence;
@@ -940,9 +940,8 @@ static int match_child(struct device *dev, void *data)
        return !strcmp(dev_name(dev), (char *)data);
 }
 
-
 /* MFC probe function */
-static int __devinit s5p_mfc_probe(struct platform_device *pdev)
+static int s5p_mfc_probe(struct platform_device *pdev)
 {
        struct s5p_mfc_dev *dev;
        struct video_device *vfd;
@@ -1236,7 +1235,7 @@ static const struct dev_pm_ops s5p_mfc_pm_ops = {
                           NULL)
 };
 
-static struct platform_driver s5p_mfc_pdrv = {
+static struct platform_driver s5p_mfc_driver = {
        .probe  = s5p_mfc_probe,
        .remove = __devexit_p(s5p_mfc_remove),
        .driver = {
@@ -1254,15 +1253,15 @@ static int __init s5p_mfc_init(void)
        int ret;
 
        pr_info("%s", banner);
-       ret = platform_driver_register(&s5p_mfc_pdrv);
+       ret = platform_driver_register(&s5p_mfc_driver);
        if (ret)
                pr_err("Platform device registration failed.\n");
        return ret;
 }
 
-static void __devexit s5p_mfc_exit(void)
+static void __exit s5p_mfc_exit(void)
 {
-       platform_driver_unregister(&s5p_mfc_pdrv);
+       platform_driver_unregister(&s5p_mfc_driver);
 }
 
 module_init(s5p_mfc_init);
index b2c5052..bfbe084 100644 (file)
@@ -165,7 +165,7 @@ static struct mfc_control controls[] = {
                .maximum = 32,
                .step = 1,
                .default_value = 1,
-               .is_volatile = 1,
+               .flags = V4L2_CTRL_FLAG_VOLATILE,
        },
 };
 
@@ -745,7 +745,7 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
 };
 
 static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count,
-                              unsigned int *plane_count, unsigned long psize[],
+                              unsigned int *plane_count, unsigned int psize[],
                               void *allocators[])
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
@@ -824,7 +824,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
                        return 0;
                for (i = 0; i <= ctx->src_fmt->num_planes ; i++) {
                        if (IS_ERR_OR_NULL(ERR_PTR(
-                                       vb2_dma_contig_plane_paddr(vb, i)))) {
+                                       vb2_dma_contig_plane_dma_addr(vb, i)))) {
                                mfc_err("Plane mem not allocated\n");
                                return -EINVAL;
                        }
@@ -837,13 +837,13 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
                i = vb->v4l2_buf.index;
                ctx->dst_bufs[i].b = vb;
                ctx->dst_bufs[i].cookie.raw.luma =
-                                       vb2_dma_contig_plane_paddr(vb, 0);
+                                       vb2_dma_contig_plane_dma_addr(vb, 0);
                ctx->dst_bufs[i].cookie.raw.chroma =
-                                       vb2_dma_contig_plane_paddr(vb, 1);
+                                       vb2_dma_contig_plane_dma_addr(vb, 1);
                ctx->dst_bufs_cnt++;
        } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
                if (IS_ERR_OR_NULL(ERR_PTR(
-                                       vb2_dma_contig_plane_paddr(vb, 0)))) {
+                                       vb2_dma_contig_plane_dma_addr(vb, 0)))) {
                        mfc_err("Plane memory not allocated\n");
                        return -EINVAL;
                }
@@ -855,7 +855,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
                i = vb->v4l2_buf.index;
                ctx->src_bufs[i].b = vb;
                ctx->src_bufs[i].cookie.stream =
-                                       vb2_dma_contig_plane_paddr(vb, 0);
+                                       vb2_dma_contig_plane_dma_addr(vb, 0);
                ctx->src_bufs_cnt++;
        } else {
                mfc_err("s5p_mfc_buf_init: unknown queue type\n");
@@ -864,7 +864,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
        return 0;
 }
 
-static int s5p_mfc_start_streaming(struct vb2_queue *q)
+static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
        struct s5p_mfc_dev *dev = ctx->dev;
@@ -1020,7 +1020,7 @@ int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx)
                        return ctx->ctrl_handler.error;
                }
                if (controls[i].is_volatile && ctx->ctrls[i])
-                       ctx->ctrls[i]->is_volatile = 1;
+                       ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
        }
        return 0;
 }
index fee094a..4c90e53 100644 (file)
@@ -599,8 +599,8 @@ static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx)
        while (!list_empty(&ctx->ref_queue)) {
                mb_entry = list_entry((&ctx->ref_queue)->next,
                                                struct s5p_mfc_buf, list);
-               mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0);
-               mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1);
+               mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
+               mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
                list_del(&mb_entry->list);
                ctx->ref_queue_cnt--;
                list_add_tail(&mb_entry->list, &ctx->src_queue);
@@ -622,7 +622,7 @@ static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx)
 
        spin_lock_irqsave(&dev->irqlock, flags);
        dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
-       dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0);
+       dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
        dst_size = vb2_plane_size(dst_mb->b, 0);
        s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
        spin_unlock_irqrestore(&dev->irqlock, flags);
@@ -668,14 +668,14 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
 
        spin_lock_irqsave(&dev->irqlock, flags);
        src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
-       src_y_addr = vb2_dma_contig_plane_paddr(src_mb->b, 0);
-       src_c_addr = vb2_dma_contig_plane_paddr(src_mb->b, 1);
+       src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0);
+       src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1);
        s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
        spin_unlock_irqrestore(&dev->irqlock, flags);
 
        spin_lock_irqsave(&dev->irqlock, flags);
        dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
-       dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0);
+       dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
        dst_size = vb2_plane_size(dst_mb->b, 0);
        s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
        spin_unlock_irqrestore(&dev->irqlock, flags);
@@ -703,8 +703,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
        if (slice_type >= 0) {
                s5p_mfc_get_enc_frame_buffer(ctx, &enc_y_addr, &enc_c_addr);
                list_for_each_entry(mb_entry, &ctx->src_queue, list) {
-                       mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0);
-                       mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1);
+                       mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
+                       mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
                        if ((enc_y_addr == mb_y_addr) &&
                                                (enc_c_addr == mb_c_addr)) {
                                list_del(&mb_entry->list);
@@ -715,8 +715,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
                        }
                }
                list_for_each_entry(mb_entry, &ctx->ref_queue, list) {
-                       mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0);
-                       mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1);
+                       mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
+                       mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
                        if ((enc_y_addr == mb_y_addr) &&
                                                (enc_c_addr == mb_c_addr)) {
                                list_del(&mb_entry->list);
@@ -1501,20 +1501,20 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
                return -EINVAL;
        }
        for (i = 0; i < fmt->num_planes; i++) {
-               if (!vb2_dma_contig_plane_paddr(vb, i)) {
+               if (!vb2_dma_contig_plane_dma_addr(vb, i)) {
                        mfc_err("failed to get plane cookie\n");
                        return -EINVAL;
                }
                mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx",
                                vb->v4l2_buf.index, i,
-                               vb2_dma_contig_plane_paddr(vb, i));
+                               vb2_dma_contig_plane_dma_addr(vb, i));
        }
        return 0;
 }
 
 static int s5p_mfc_queue_setup(struct vb2_queue *vq,
                       unsigned int *buf_count, unsigned int *plane_count,
-                      unsigned long psize[], void *allocators[])
+                      unsigned int psize[], void *allocators[])
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
 
@@ -1584,7 +1584,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
                i = vb->v4l2_buf.index;
                ctx->dst_bufs[i].b = vb;
                ctx->dst_bufs[i].cookie.stream =
-                                       vb2_dma_contig_plane_paddr(vb, 0);
+                                       vb2_dma_contig_plane_dma_addr(vb, 0);
                ctx->dst_bufs_cnt++;
        } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
                ret = check_vb_with_fmt(ctx->src_fmt, vb);
@@ -1593,9 +1593,9 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
                i = vb->v4l2_buf.index;
                ctx->src_bufs[i].b = vb;
                ctx->src_bufs[i].cookie.raw.luma =
-                                       vb2_dma_contig_plane_paddr(vb, 0);
+                                       vb2_dma_contig_plane_dma_addr(vb, 0);
                ctx->src_bufs[i].cookie.raw.chroma =
-                                       vb2_dma_contig_plane_paddr(vb, 1);
+                                       vb2_dma_contig_plane_dma_addr(vb, 1);
                ctx->src_bufs_cnt++;
        } else {
                mfc_err("inavlid queue type: %d\n", vq->type);
@@ -1640,7 +1640,7 @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
        return 0;
 }
 
-static int s5p_mfc_start_streaming(struct vb2_queue *q)
+static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
        struct s5p_mfc_dev *dev = ctx->dev;
@@ -1814,7 +1814,7 @@ int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx)
                        return ctx->ctrl_handler.error;
                }
                if (controls[i].is_volatile && ctx->ctrls[i])
-                       ctx->ctrls[i]->is_volatile = 1;
+                       ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
        }
        return 0;
 }
index 7b23916..e08b21c 100644 (file)
@@ -1135,7 +1135,7 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
        temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
        temp_vb->used = 1;
        s5p_mfc_set_dec_stream_buffer(ctx,
-               vb2_dma_contig_plane_paddr(temp_vb->b, 0), ctx->consumed_stream,
+               vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream,
                                        temp_vb->b->v4l2_planes[0].bytesused);
        spin_unlock_irqrestore(&dev->irqlock, flags);
        index = temp_vb->b->v4l2_buf.index;
@@ -1172,12 +1172,12 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
        }
        src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
        src_mb->used = 1;
-       src_y_addr = vb2_dma_contig_plane_paddr(src_mb->b, 0);
-       src_c_addr = vb2_dma_contig_plane_paddr(src_mb->b, 1);
+       src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0);
+       src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1);
        s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
        dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
        dst_mb->used = 1;
-       dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0);
+       dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
        dst_size = vb2_plane_size(dst_mb->b, 0);
        s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
        spin_unlock_irqrestore(&dev->irqlock, flags);
@@ -1200,7 +1200,7 @@ static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
        s5p_mfc_set_dec_desc_buffer(ctx);
        mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused);
        s5p_mfc_set_dec_stream_buffer(ctx,
-                               vb2_dma_contig_plane_paddr(temp_vb->b, 0),
+                               vb2_dma_contig_plane_dma_addr(temp_vb->b, 0),
                                0, temp_vb->b->v4l2_planes[0].bytesused);
        spin_unlock_irqrestore(&dev->irqlock, flags);
        dev->curr_ctx = ctx->num;
@@ -1219,7 +1219,7 @@ static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
        s5p_mfc_set_enc_ref_buffer(ctx);
        spin_lock_irqsave(&dev->irqlock, flags);
        dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
-       dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0);
+       dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
        dst_size = vb2_plane_size(dst_mb->b, 0);
        s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
        spin_unlock_irqrestore(&dev->irqlock, flags);
@@ -1255,7 +1255,7 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
        temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
        mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused);
        s5p_mfc_set_dec_stream_buffer(ctx,
-                               vb2_dma_contig_plane_paddr(temp_vb->b, 0),
+                               vb2_dma_contig_plane_dma_addr(temp_vb->b, 0),
                                0, temp_vb->b->v4l2_planes[0].bytesused);
        spin_unlock_irqrestore(&dev->irqlock, flags);
        dev->curr_ctx = ctx->num;
index 9c37dee..f2a0977 100644 (file)
@@ -8,7 +8,7 @@
 
 config VIDEO_SAMSUNG_S5P_TV
        bool "Samsung TV driver for S5P platform (experimental)"
-       depends on PLAT_S5P
+       depends on PLAT_S5P && PM_RUNTIME
        depends on EXPERIMENTAL
        default n
        ---help---
index 06d6663..0279e6e 100644 (file)
@@ -210,20 +210,17 @@ static void hdmi_reg_init(struct hdmi_device *hdev)
        /* enable HPD interrupts */
        hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
                HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
-       /* choose HDMI mode */
+       /* choose DVI mode */
        hdmi_write_mask(hdev, HDMI_MODE_SEL,
-               HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
+               HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
+       hdmi_write_mask(hdev, HDMI_CON_2, ~0,
+               HDMI_DVI_PERAMBLE_EN | HDMI_DVI_BAND_EN);
        /* disable bluescreen */
        hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
        /* choose bluescreen (fecal) color */
        hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12);
        hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34);
        hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56);
-       /* enable AVI packet every vsync, fixes purple line problem */
-       hdmi_writeb(hdev, HDMI_AVI_CON, 0x02);
-       /* force YUV444, look to CEA-861-D, table 7 for more detail */
-       hdmi_writeb(hdev, HDMI_AVI_BYTE(0), 2 << 5);
-       hdmi_write_mask(hdev, HDMI_CON_1, 2, 3 << 5);
 }
 
 static void hdmi_timing_apply(struct hdmi_device *hdev,
@@ -443,6 +440,7 @@ static const struct hdmi_preset_conf hdmi_conf_480p = {
                .height = 480,
                .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
                .field = V4L2_FIELD_NONE,
+               .colorspace = V4L2_COLORSPACE_SRGB,
        },
 };
 
@@ -475,6 +473,7 @@ static const struct hdmi_preset_conf hdmi_conf_720p60 = {
                .height = 720,
                .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
                .field = V4L2_FIELD_NONE,
+               .colorspace = V4L2_COLORSPACE_SRGB,
        },
 };
 
@@ -507,6 +506,7 @@ static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
                .height = 1080,
                .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
                .field = V4L2_FIELD_NONE,
+               .colorspace = V4L2_COLORSPACE_SRGB,
        },
 };
 
@@ -539,6 +539,7 @@ static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
                .height = 1080,
                .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
                .field = V4L2_FIELD_NONE,
+               .colorspace = V4L2_COLORSPACE_SRGB,
        },
 };
 
index e224224..51ad59b 100644 (file)
@@ -111,8 +111,6 @@ struct mxr_buffer {
 enum mxr_layer_state {
        /** layers is not shown */
        MXR_LAYER_IDLE = 0,
-       /** state between STREAMON and hardware start */
-       MXR_LAYER_STREAMING_START,
        /** layer is shown */
        MXR_LAYER_STREAMING,
        /** state before STREAMOFF is finished */
index 58f0ba4..de8270c 100644 (file)
@@ -86,7 +86,7 @@ static void mxr_graph_buffer_set(struct mxr_layer *layer,
        dma_addr_t addr = 0;
 
        if (buf)
-               addr = vb2_dma_contig_plane_paddr(&buf->vb, 0);
+               addr = vb2_dma_contig_plane_dma_addr(&buf->vb, 0);
        mxr_reg_graph_buffer(layer->mdev, layer->idx, addr);
 }
 
index 38dac67..4800a3c 100644 (file)
@@ -90,7 +90,7 @@ void mxr_reg_reset(struct mxr_device *mdev)
        mxr_vsync_set_update(mdev, MXR_DISABLE);
 
        /* set output in RGB888 mode */
-       mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_YUV444);
+       mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_RGB888);
 
        /* 16 beat burst in DMA */
        mxr_write_mask(mdev, MXR_STATUS, MXR_STATUS_16_BURST,
@@ -376,6 +376,12 @@ void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
        spin_lock_irqsave(&mdev->reg_slock, flags);
        mxr_vsync_set_update(mdev, MXR_DISABLE);
 
+       /* selecting colorspace accepted by output */
+       if (fmt->colorspace == V4L2_COLORSPACE_JPEG)
+               val |= MXR_CFG_OUT_YUV444;
+       else
+               val |= MXR_CFG_OUT_RGB888;
+
        /* choosing between interlace and progressive mode */
        if (fmt->field == V4L2_FIELD_INTERLACED)
                val |= MXR_CFG_SCAN_INTERLACE;
@@ -394,7 +400,8 @@ void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
        else
                WARN(1, "unrecognized mbus height %u!\n", fmt->height);
 
-       mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK);
+       mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK |
+               MXR_CFG_OUT_MASK);
 
        val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0;
        vp_write_mask(mdev, VP_MODE, val,
index 43ac22f..4917e2c 100644 (file)
@@ -728,7 +728,7 @@ static const struct v4l2_file_operations mxr_fops = {
 };
 
 static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
-       unsigned int *nplanes, unsigned long sizes[],
+       unsigned int *nplanes, unsigned int sizes[],
        void *alloc_ctxs[])
 {
        struct mxr_layer *layer = vb2_get_drv_priv(vq);
@@ -764,19 +764,10 @@ static void buf_queue(struct vb2_buffer *vb)
        struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
        struct mxr_device *mdev = layer->mdev;
        unsigned long flags;
-       int must_start = 0;
 
        spin_lock_irqsave(&layer->enq_slock, flags);
-       if (layer->state == MXR_LAYER_STREAMING_START) {
-               layer->state = MXR_LAYER_STREAMING;
-               must_start = 1;
-       }
        list_add_tail(&buffer->list, &layer->enq_list);
        spin_unlock_irqrestore(&layer->enq_slock, flags);
-       if (must_start) {
-               layer->ops.stream_set(layer, MXR_ENABLE);
-               mxr_streamer_get(mdev);
-       }
 
        mxr_dbg(mdev, "queuing buffer\n");
 }
@@ -797,13 +788,19 @@ static void wait_unlock(struct vb2_queue *vq)
        mutex_unlock(&layer->mutex);
 }
 
-static int start_streaming(struct vb2_queue *vq)
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct mxr_layer *layer = vb2_get_drv_priv(vq);
        struct mxr_device *mdev = layer->mdev;
        unsigned long flags;
 
        mxr_dbg(mdev, "%s\n", __func__);
+
+       if (count == 0) {
+               mxr_dbg(mdev, "no output buffers queued\n");
+               return -EINVAL;
+       }
+
        /* block any changes in output configuration */
        mxr_output_get(mdev);
 
@@ -814,9 +811,12 @@ static int start_streaming(struct vb2_queue *vq)
        layer->ops.format_set(layer);
        /* enabling layer in hardware */
        spin_lock_irqsave(&layer->enq_slock, flags);
-       layer->state = MXR_LAYER_STREAMING_START;
+       layer->state = MXR_LAYER_STREAMING;
        spin_unlock_irqrestore(&layer->enq_slock, flags);
 
+       layer->ops.stream_set(layer, MXR_ENABLE);
+       mxr_streamer_get(mdev);
+
        return 0;
 }
 
index 6950ed8..f3bb2e3 100644 (file)
@@ -97,9 +97,9 @@ static void mxr_vp_buffer_set(struct mxr_layer *layer,
                mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
                return;
        }
-       luma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 0);
+       luma_addr[0] = vb2_dma_contig_plane_dma_addr(&buf->vb, 0);
        if (layer->fmt->num_subframes == 2) {
-               chroma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 1);
+               chroma_addr[0] = vb2_dma_contig_plane_dma_addr(&buf->vb, 1);
        } else {
                /* FIXME: mxr_get_plane_size compute integer division,
                 * which is slow and should not be performed in interrupt */
index ac93ad6..33247d1 100644 (file)
 #define HDMI_BLUE_SCR_EN               (1 << 5)
 #define HDMI_EN                                (1 << 0)
 
+/* HDMI_CON_2 */
+#define HDMI_DVI_PERAMBLE_EN           (1 << 5)
+#define HDMI_DVI_BAND_EN               (1 << 1)
+
 /* HDMI_PHY_STATUS */
 #define HDMI_PHY_STATUS_READY          (1 << 0)
 
index 3c84426..158abb4 100644 (file)
@@ -67,6 +67,7 @@
 /* bits for MXR_CFG */
 #define MXR_CFG_OUT_YUV444             (0 << 8)
 #define MXR_CFG_OUT_RGB888             (1 << 8)
+#define MXR_CFG_OUT_MASK               (1 << 8)
 #define MXR_CFG_DST_SDO                        (0 << 7)
 #define MXR_CFG_DST_HDMI               (1 << 7)
 #define MXR_CFG_DST_MASK               (1 << 7)
index 4dddd6b..8cec67e 100644 (file)
@@ -170,6 +170,7 @@ static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
        fmt->height = sdev->fmt->height;
        fmt->code = V4L2_MBUS_FMT_FIXED;
        fmt->field = V4L2_FIELD_INTERLACED;
+       fmt->colorspace = V4L2_COLORSPACE_JPEG;
        return 0;
 }
 
index f2ae405..5cfdbc7 100644 (file)
@@ -793,7 +793,6 @@ static int saa711x_s_ctrl(struct v4l2_ctrl *ctrl)
                        saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val);
                else
                        saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val | 0x80);
-               v4l2_ctrl_activate(state->gain, !state->agc->val);
                break;
 
        default:
@@ -1345,35 +1344,57 @@ static int saa711x_g_vbi_data(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_dat
 static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
 {
        struct saa711x_state *state = to_state(sd);
-       int reg1e;
+       int reg1f, reg1e;
 
-       *std = V4L2_STD_ALL;
-       if (state->ident != V4L2_IDENT_SAA7115) {
-               int reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+       /*
+        * The V4L2 core already initializes std with all supported
+        * Standards. All driver needs to do is to mask it, to remove
+        * standards that don't apply from the mask
+        */
 
-               if (reg1f & 0x20)
-                       *std = V4L2_STD_525_60;
-               else
-                       *std = V4L2_STD_625_50;
+       reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+       v4l2_dbg(1, debug, sd, "Status byte 2 (0x1f)=0x%02x\n", reg1f);
 
-               return 0;
-       }
+       /* horizontal/vertical not locked */
+       if (reg1f & 0x40)
+               goto ret;
+
+       if (reg1f & 0x20)
+               *std &= V4L2_STD_525_60;
+       else
+               *std &= V4L2_STD_625_50;
+
+       if (state->ident != V4L2_IDENT_SAA7115)
+               goto ret;
 
        reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
 
        switch (reg1e & 0x03) {
        case 1:
-               *std = V4L2_STD_NTSC;
+               *std &= V4L2_STD_NTSC;
                break;
        case 2:
-               *std = V4L2_STD_PAL;
+               /*
+                * V4L2_STD_PAL just cover the european PAL standards.
+                * This is wrong, as the device could also be using an
+                * other PAL standard.
+                */
+               *std &= V4L2_STD_PAL   | V4L2_STD_PAL_N  | V4L2_STD_PAL_Nc |
+                       V4L2_STD_PAL_M | V4L2_STD_PAL_60;
                break;
        case 3:
-               *std = V4L2_STD_SECAM;
+               *std &= V4L2_STD_SECAM;
                break;
        default:
+               /* Can't detect anything */
                break;
        }
+
+       v4l2_dbg(1, debug, sd, "Status byte 1 (0x1e)=0x%02x\n", reg1e);
+
+ret:
+       v4l2_dbg(1, debug, sd, "detected std mask = %08Lx\n", *std);
+
        return 0;
 }
 
@@ -1601,7 +1622,6 @@ static int saa711x_probe(struct i2c_client *client,
                        V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);
        state->gain = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
                        V4L2_CID_CHROMA_GAIN, 0, 127, 1, 40);
-       state->gain->is_volatile = 1;
        sd->ctrl_handler = hdl;
        if (hdl->error) {
                int err = hdl->error;
@@ -1610,8 +1630,7 @@ static int saa711x_probe(struct i2c_client *client,
                kfree(state);
                return err;
        }
-       state->agc->flags |= V4L2_CTRL_FLAG_UPDATE;
-       v4l2_ctrl_cluster(2, &state->agc);
+       v4l2_ctrl_auto_cluster(2, &state->agc, 0, true);
 
        state->input = -1;
        state->output = SAA7115_IPORT_ON;
index 8a5ff4d..a646ccf 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
 
 obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/video
+ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
index 6303a8e..ecd5811 100644 (file)
@@ -4,9 +4,9 @@ saa7164-objs    := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \
 
 obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/video
+ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
 
-EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
index 69822a4..971591d 100644 (file)
@@ -203,6 +203,66 @@ struct saa7164_board saa7164_boards[] = {
                        .i2c_reg_len    = REGLEN_8bit,
                } },
        },
+       [SAA7164_BOARD_HAUPPAUGE_HVR2200_4] = {
+               .name           = "Hauppauge WinTV-HVR2200",
+               .porta          = SAA7164_MPEG_DVB,
+               .portb          = SAA7164_MPEG_DVB,
+               .portc          = SAA7164_MPEG_ENCODER,
+               .portd          = SAA7164_MPEG_ENCODER,
+               .porte          = SAA7164_MPEG_VBI,
+               .portf          = SAA7164_MPEG_VBI,
+               .chiprev        = SAA7164_CHIP_REV3,
+               .unit           = {{
+                       .id             = 0x1d,
+                       .type           = SAA7164_UNIT_EEPROM,
+                       .name           = "4K EEPROM",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_0,
+                       .i2c_bus_addr   = 0xa0 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               }, {
+                       .id             = 0x04,
+                       .type           = SAA7164_UNIT_TUNER,
+                       .name           = "TDA18271-1",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_1,
+                       .i2c_bus_addr   = 0xc0 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               }, {
+                       .id             = 0x05,
+                       .type           = SAA7164_UNIT_ANALOG_DEMODULATOR,
+                       .name           = "TDA8290-1",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_1,
+                       .i2c_bus_addr   = 0x84 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               }, {
+                       .id             = 0x1b,
+                       .type           = SAA7164_UNIT_TUNER,
+                       .name           = "TDA18271-2",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_2,
+                       .i2c_bus_addr   = 0xc0 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               }, {
+                       .id             = 0x1c,
+                       .type           = SAA7164_UNIT_ANALOG_DEMODULATOR,
+                       .name           = "TDA8290-2",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_2,
+                       .i2c_bus_addr   = 0x84 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               }, {
+                       .id             = 0x1e,
+                       .type           = SAA7164_UNIT_DIGITAL_DEMODULATOR,
+                       .name           = "TDA10048-1",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_1,
+                       .i2c_bus_addr   = 0x10 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               }, {
+                       .id             = 0x1f,
+                       .type           = SAA7164_UNIT_DIGITAL_DEMODULATOR,
+                       .name           = "TDA10048-2",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_2,
+                       .i2c_bus_addr   = 0x12 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               } },
+       },
        [SAA7164_BOARD_HAUPPAUGE_HVR2250] = {
                .name           = "Hauppauge WinTV-HVR2250",
                .porta          = SAA7164_MPEG_DVB,
@@ -387,6 +447,62 @@ struct saa7164_board saa7164_boards[] = {
                        .i2c_reg_len    = REGLEN_8bit,
                } },
        },
+       [SAA7164_BOARD_HAUPPAUGE_HVR2200_5] = {
+               .name           = "Hauppauge WinTV-HVR2200",
+               .porta          = SAA7164_MPEG_DVB,
+               .portb          = SAA7164_MPEG_DVB,
+               .chiprev        = SAA7164_CHIP_REV3,
+               .unit           = {{
+                       .id             = 0x23,
+                       .type           = SAA7164_UNIT_EEPROM,
+                       .name           = "4K EEPROM",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_0,
+                       .i2c_bus_addr   = 0xa0 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               }, {
+                       .id             = 0x04,
+                       .type           = SAA7164_UNIT_TUNER,
+                       .name           = "TDA18271-1",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_1,
+                       .i2c_bus_addr   = 0xc0 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               }, {
+                       .id             = 0x05,
+                       .type           = SAA7164_UNIT_ANALOG_DEMODULATOR,
+                       .name           = "TDA8290-1",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_1,
+                       .i2c_bus_addr   = 0x84 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               }, {
+                       .id             = 0x21,
+                       .type           = SAA7164_UNIT_TUNER,
+                       .name           = "TDA18271-2",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_2,
+                       .i2c_bus_addr   = 0xc0 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               }, {
+                       .id             = 0x22,
+                       .type           = SAA7164_UNIT_ANALOG_DEMODULATOR,
+                       .name           = "TDA8290-2",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_2,
+                       .i2c_bus_addr   = 0x84 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               }, {
+                       .id             = 0x24,
+                       .type           = SAA7164_UNIT_DIGITAL_DEMODULATOR,
+                       .name           = "TDA10048-1",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_1,
+                       .i2c_bus_addr   = 0x10 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               }, {
+                       .id             = 0x25,
+                       .type           = SAA7164_UNIT_DIGITAL_DEMODULATOR,
+                       .name           = "TDA10048-2",
+                       .i2c_bus_nr     = SAA7164_I2C_BUS_2,
+                       .i2c_bus_addr   = 0x12 >> 1,
+                       .i2c_reg_len    = REGLEN_8bit,
+               } },
+       },
 };
 const unsigned int saa7164_bcount = ARRAY_SIZE(saa7164_boards);
 
@@ -426,6 +542,14 @@ struct saa7164_subid saa7164_subids[] = {
                .subvendor = 0x0070,
                .subdevice = 0x8851,
                .card      = SAA7164_BOARD_HAUPPAUGE_HVR2250_2,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x8940,
+               .card      = SAA7164_BOARD_HAUPPAUGE_HVR2200_4,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x8953,
+               .card      = SAA7164_BOARD_HAUPPAUGE_HVR2200_5,
        },
 };
 const unsigned int saa7164_idcount = ARRAY_SIZE(saa7164_subids);
@@ -469,6 +593,8 @@ void saa7164_gpio_setup(struct saa7164_dev *dev)
        case SAA7164_BOARD_HAUPPAUGE_HVR2200:
        case SAA7164_BOARD_HAUPPAUGE_HVR2200_2:
        case SAA7164_BOARD_HAUPPAUGE_HVR2200_3:
+       case SAA7164_BOARD_HAUPPAUGE_HVR2200_4:
+       case SAA7164_BOARD_HAUPPAUGE_HVR2200_5:
        case SAA7164_BOARD_HAUPPAUGE_HVR2250:
        case SAA7164_BOARD_HAUPPAUGE_HVR2250_2:
        case SAA7164_BOARD_HAUPPAUGE_HVR2250_3:
@@ -549,6 +675,8 @@ void saa7164_card_setup(struct saa7164_dev *dev)
        case SAA7164_BOARD_HAUPPAUGE_HVR2200:
        case SAA7164_BOARD_HAUPPAUGE_HVR2200_2:
        case SAA7164_BOARD_HAUPPAUGE_HVR2200_3:
+       case SAA7164_BOARD_HAUPPAUGE_HVR2200_4:
+       case SAA7164_BOARD_HAUPPAUGE_HVR2200_5:
        case SAA7164_BOARD_HAUPPAUGE_HVR2250:
        case SAA7164_BOARD_HAUPPAUGE_HVR2250_2:
        case SAA7164_BOARD_HAUPPAUGE_HVR2250_3:
index f65eab6..5c5cc3e 100644 (file)
@@ -475,6 +475,8 @@ int saa7164_dvb_register(struct saa7164_port *port)
        case SAA7164_BOARD_HAUPPAUGE_HVR2200:
        case SAA7164_BOARD_HAUPPAUGE_HVR2200_2:
        case SAA7164_BOARD_HAUPPAUGE_HVR2200_3:
+       case SAA7164_BOARD_HAUPPAUGE_HVR2200_4:
+       case SAA7164_BOARD_HAUPPAUGE_HVR2200_5:
                i2c_bus = &dev->i2c_bus[port->nr + 1];
                switch (port->nr) {
                case 0:
index 6678bf1..742b341 100644 (file)
@@ -82,6 +82,8 @@
 #define SAA7164_BOARD_HAUPPAUGE_HVR2200_3      6
 #define SAA7164_BOARD_HAUPPAUGE_HVR2250_2      7
 #define SAA7164_BOARD_HAUPPAUGE_HVR2250_3      8
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200_4      9
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200_5      10
 
 #define SAA7164_MAX_UNITS              8
 #define SAA7164_TS_NUMBER_OF_LINES     312
index e540898..8615fb8 100644 (file)
@@ -218,7 +218,7 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
  */
 static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
                        unsigned int *count, unsigned int *num_planes,
-                       unsigned long sizes[], void *alloc_ctxs[])
+                       unsigned int sizes[], void *alloc_ctxs[])
 {
        struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -243,7 +243,7 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
                        *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]);
        }
 
-       dev_dbg(icd->parent, "count=%d, size=%lu\n", *count, sizes[0]);
+       dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]);
 
        return 0;
 }
@@ -312,7 +312,7 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
                bottom2 = CDBCR;
        }
 
-       phys_addr_top = vb2_dma_contig_plane_paddr(pcdev->active, 0);
+       phys_addr_top = vb2_dma_contig_plane_dma_addr(pcdev->active, 0);
 
        ceu_write(pcdev, top1, phys_addr_top);
        if (V4L2_FIELD_NONE != pcdev->field) {
index 8afb0e8..10aff3f 100644 (file)
@@ -714,11 +714,6 @@ static int sr030pc30_base_config(struct v4l2_subdev *sd)
        return ret;
 }
 
-static int sr030pc30_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       return 0;
-}
-
 static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -764,7 +759,6 @@ static const struct v4l2_subdev_core_ops sr030pc30_core_ops = {
 };
 
 static const struct v4l2_subdev_video_ops sr030pc30_video_ops = {
-       .s_stream       = sr030pc30_s_stream,
        .g_mbus_fmt     = sr030pc30_g_fmt,
        .s_mbus_fmt     = sr030pc30_s_fmt,
        .try_mbus_fmt   = sr030pc30_try_fmt,
index d1a2cef..cbc105f 100644 (file)
@@ -55,6 +55,8 @@ MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay@gmail.com> and Nicolas VIVIEN");
 MODULE_DESCRIPTION("Syntek DC1125 webcam driver");
 
 
+/* bool for webcam LED management */
+int first_init = 1;
 
 /* Some cameras have audio interfaces, we aren't interested in those */
 static struct usb_device_id stkwebcam_table[] = {
@@ -518,7 +520,7 @@ static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs)
                        return -ENOMEM;
                for (i = 0; i < n_sbufs; i++) {
                        if (stk_setup_siobuf(dev, i))
-                               return (dev->n_sbufs > 1)? 0 : -ENOMEM;
+                               return (dev->n_sbufs > 1 ? 0 : -ENOMEM);
                        dev->n_sbufs = i+1;
                }
        }
@@ -558,9 +560,14 @@ static int v4l_stk_open(struct file *fp)
        vdev = video_devdata(fp);
        dev = vdev_to_camera(vdev);
 
-       if (dev == NULL || !is_present(dev)) {
+       if (dev == NULL || !is_present(dev))
                return -ENXIO;
-       }
+
+       if (!first_init)
+               stk_camera_write_reg(dev, 0x0, 0x24);
+       else
+               first_init = 0;
+
        fp->private_data = dev;
        usb_autopm_get_interface(dev->interface);
 
@@ -574,10 +581,12 @@ static int v4l_stk_release(struct file *fp)
        if (dev->owner == fp) {
                stk_stop_stream(dev);
                stk_free_buffers(dev);
+               stk_camera_write_reg(dev, 0x0, 0x49); /* turn off the LED */
+               unset_initialised(dev);
                dev->owner = NULL;
        }
 
-       if(is_present(dev))
+       if (is_present(dev))
                usb_autopm_put_interface(dev->interface);
 
        return 0;
@@ -654,7 +663,7 @@ static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
                return POLLERR;
 
        if (!list_empty(&dev->sio_full))
-               return (POLLIN | POLLRDNORM);
+               return POLLIN | POLLRDNORM;
 
        return 0;
 }
@@ -891,9 +900,9 @@ static int stk_vidioc_g_fmt_vid_cap(struct file *filp,
        struct stk_camera *dev = priv;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(stk_sizes)
-                       && stk_sizes[i].m != dev->vsettings.mode;
-               i++);
+       for (i = 0; i < ARRAY_SIZE(stk_sizes) &&
+                       stk_sizes[i].m != dev->vsettings.mode; i++)
+               ;
        if (i == ARRAY_SIZE(stk_sizes)) {
                STK_ERROR("ERROR: mode invalid\n");
                return -EINVAL;
@@ -1305,9 +1314,8 @@ static int stk_camera_probe(struct usb_interface *interface,
        usb_set_intfdata(interface, dev);
 
        err = stk_register_video_device(dev);
-       if (err) {
+       if (err)
                goto error;
-       }
 
        return 0;
 
@@ -1350,6 +1358,7 @@ static int stk_camera_resume(struct usb_interface *intf)
                return 0;
        unset_initialised(dev);
        stk_initialise(dev);
+       stk_camera_write_reg(dev, 0x0, 0x49);
        stk_setup_format(dev);
        if (is_streaming(dev))
                stk_start_stream(dev);
index 81bb7fd..ea09b9a 100644 (file)
@@ -2,8 +2,8 @@ poseidon-objs := pd-video.o pd-alsa.o pd-dvb.o pd-radio.o pd-main.o
 
 obj-$(CONFIG_VIDEO_TLG2300) += poseidon.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/video
+ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
 
diff --git a/drivers/media/video/tm6000/Kconfig b/drivers/media/video/tm6000/Kconfig
new file mode 100644 (file)
index 0000000..114eec8
--- /dev/null
@@ -0,0 +1,33 @@
+config VIDEO_TM6000
+       tristate "TV Master TM5600/6000/6010 driver"
+       depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB && EXPERIMENTAL
+       select VIDEO_TUNER
+       select MEDIA_TUNER_XC2028
+       select MEDIA_TUNER_XC5000
+       select VIDEOBUF_VMALLOC
+       help
+         Support for TM5600/TM6000/TM6010 USB Device
+
+         Since these cards have no MPEG decoder onboard, they transmit
+         only compressed MPEG data over the usb bus, so you need
+         an external software decoder to watch TV on your computer.
+
+         Say Y if you own such a device and want to use it.
+
+config VIDEO_TM6000_ALSA
+       tristate "TV Master TM5600/6000/6010 audio support"
+       depends on VIDEO_TM6000 && SND && EXPERIMENTAL
+       select SND_PCM
+       ---help---
+         This is a video4linux driver for direct (DMA) audio for
+         TM5600/TM6000/TM6010 USB Devices.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tm6000-alsa.
+
+config VIDEO_TM6000_DVB
+       tristate "DVB Support for tm6000 based TV cards"
+       depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL
+       select DVB_ZL10353
+       ---help---
+         This adds support for DVB cards based on the tm5600/tm6000 chip.
diff --git a/drivers/media/video/tm6000/Makefile b/drivers/media/video/tm6000/Makefile
new file mode 100644 (file)
index 0000000..395515b
--- /dev/null
@@ -0,0 +1,15 @@
+tm6000-y := tm6000-cards.o \
+                  tm6000-core.o  \
+                  tm6000-i2c.o   \
+                  tm6000-video.o \
+                  tm6000-stds.o \
+                  tm6000-input.o
+
+obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
+obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o
+obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o
+
+ccflags-y := -Idrivers/media/video
+ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/tm6000/tm6000-alsa.c b/drivers/media/video/tm6000/tm6000-alsa.c
new file mode 100644 (file)
index 0000000..7d675c7
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ *
+ *  Support for audio capture for tm5600/6000/6010
+ *    (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ *  Based on cx88-alsa.c
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+#undef dprintk
+
+#define dprintk(level, fmt, arg...) do {                                  \
+       if (debug >= level)                                                \
+               printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
+       } while (0)
+
+/****************************************************************************
+                       Module global static vars
+ ****************************************************************************/
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
+
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled.");
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
+
+
+/****************************************************************************
+                               Module macros
+ ****************************************************************************/
+
+MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
+                       "{{Trident,tm6000},"
+                       "{{Trident,tm6010}");
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+/****************************************************************************
+                       Module specific funtions
+ ****************************************************************************/
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
+{
+       struct tm6000_core *core = chip->core;
+
+       dprintk(1, "Starting audio DMA\n");
+
+       /* Enables audio */
+       tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x40, 0x40);
+
+       tm6000_set_audio_bitrate(core, 48000);
+
+       return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
+{
+       struct tm6000_core *core = chip->core;
+
+       dprintk(1, "Stopping audio DMA\n");
+
+       /* Disables audio */
+       tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x00, 0x40);
+
+       return 0;
+}
+
+static void dsp_buffer_free(struct snd_pcm_substream *substream)
+{
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+       dprintk(2, "Freeing buffer\n");
+
+       vfree(substream->runtime->dma_area);
+       substream->runtime->dma_area = NULL;
+       substream->runtime->dma_bytes = 0;
+}
+
+static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
+{
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+       dprintk(2, "Allocating buffer\n");
+
+       if (substream->runtime->dma_area) {
+               if (substream->runtime->dma_bytes > size)
+                       return 0;
+
+               dsp_buffer_free(substream);
+       }
+
+       substream->runtime->dma_area = vmalloc(size);
+       if (!substream->runtime->dma_area)
+               return -ENOMEM;
+
+       substream->runtime->dma_bytes = size;
+
+       return 0;
+}
+
+
+/****************************************************************************
+                               ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+#define DEFAULT_FIFO_SIZE      4096
+
+static struct snd_pcm_hardware snd_tm6000_digital_hw = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+       .rate_min = 48000,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .period_bytes_min = 64,
+       .period_bytes_max = 12544,
+       .periods_min = 1,
+       .periods_max = 98,
+       .buffer_bytes_max = 62720 * 8,
+};
+
+/*
+ * audio pcm capture open callback
+ */
+static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int err;
+
+       err = snd_pcm_hw_constraint_pow2(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0)
+               goto _error;
+
+       chip->substream = substream;
+
+       runtime->hw = snd_tm6000_digital_hw;
+
+       return 0;
+_error:
+       dprintk(1, "Error opening PCM!\n");
+       return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_tm6000_close(struct snd_pcm_substream *substream)
+{
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+       struct tm6000_core *core = chip->core;
+
+       if (atomic_read(&core->stream_started) > 0) {
+               atomic_set(&core->stream_started, 0);
+               schedule_work(&core->wq_trigger);
+       }
+
+       return 0;
+}
+
+static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
+{
+       struct snd_tm6000_card *chip = core->adev;
+       struct snd_pcm_substream *substream = chip->substream;
+       struct snd_pcm_runtime *runtime;
+       int period_elapsed = 0;
+       unsigned int stride, buf_pos;
+       int length;
+
+       if (atomic_read(&core->stream_started) == 0)
+               return 0;
+
+       if (!size || !substream) {
+               dprintk(1, "substream was NULL\n");
+               return -EINVAL;
+       }
+
+       runtime = substream->runtime;
+       if (!runtime || !runtime->dma_area) {
+               dprintk(1, "runtime was NULL\n");
+               return -EINVAL;
+       }
+
+       buf_pos = chip->buf_pos;
+       stride = runtime->frame_bits >> 3;
+
+       if (stride == 0) {
+               dprintk(1, "stride is zero\n");
+               return -EINVAL;
+       }
+
+       length = size / stride;
+       if (length == 0) {
+               dprintk(1, "%s: length was zero\n", __func__);
+               return -EINVAL;
+       }
+
+       dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
+               runtime->dma_area, buf_pos,
+               (unsigned int)runtime->buffer_size, stride);
+
+       if (buf_pos + length >= runtime->buffer_size) {
+               unsigned int cnt = runtime->buffer_size - buf_pos;
+               memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride);
+               memcpy(runtime->dma_area, buf + cnt * stride,
+                       length * stride - cnt * stride);
+       } else
+               memcpy(runtime->dma_area + buf_pos * stride, buf,
+                       length * stride);
+
+       snd_pcm_stream_lock(substream);
+
+       chip->buf_pos += length;
+       if (chip->buf_pos >= runtime->buffer_size)
+               chip->buf_pos -= runtime->buffer_size;
+
+       chip->period_pos += length;
+       if (chip->period_pos >= runtime->period_size) {
+               chip->period_pos -= runtime->period_size;
+               period_elapsed = 1;
+       }
+
+       snd_pcm_stream_unlock(substream);
+
+       if (period_elapsed)
+               snd_pcm_period_elapsed(substream);
+
+       return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *hw_params)
+{
+       int size, rc;
+
+       size = params_period_bytes(hw_params) * params_periods(hw_params);
+
+       rc = dsp_buffer_alloc(substream, size);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+       struct tm6000_core *core = chip->core;
+
+       if (atomic_read(&core->stream_started) > 0) {
+               atomic_set(&core->stream_started, 0);
+               schedule_work(&core->wq_trigger);
+       }
+
+       dsp_buffer_free(substream);
+       return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+       chip->buf_pos = 0;
+       chip->period_pos = 0;
+
+       return 0;
+}
+
+
+/*
+ * trigger callback
+ */
+static void audio_trigger(struct work_struct *work)
+{
+       struct tm6000_core *core = container_of(work, struct tm6000_core,
+                                               wq_trigger);
+       struct snd_tm6000_card *chip = core->adev;
+
+       if (atomic_read(&core->stream_started)) {
+               dprintk(1, "starting capture");
+               _tm6000_start_audio_dma(chip);
+       } else {
+               dprintk(1, "stopping capture");
+               _tm6000_stop_audio_dma(chip);
+       }
+}
+
+static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+       struct tm6000_core *core = chip->core;
+       int err = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               atomic_set(&core->stream_started, 1);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               atomic_set(&core->stream_started, 0);
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
+       schedule_work(&core->wq_trigger);
+
+       return err;
+}
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+       return chip->buf_pos;
+}
+
+/*
+ * operators
+ */
+static struct snd_pcm_ops snd_tm6000_pcm_ops = {
+       .open = snd_tm6000_pcm_open,
+       .close = snd_tm6000_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_tm6000_hw_params,
+       .hw_free = snd_tm6000_hw_free,
+       .prepare = snd_tm6000_prepare,
+       .trigger = snd_tm6000_card_trigger,
+       .pointer = snd_tm6000_pointer,
+};
+
+/*
+ * create a PCM device
+ */
+
+/* FIXME: Control interface - How to control volume/mute? */
+
+/****************************************************************************
+                       Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * Alsa Constructor - Component probe
+ */
+static int tm6000_audio_init(struct tm6000_core *dev)
+{
+       struct snd_card         *card;
+       struct snd_tm6000_card  *chip;
+       int                     rc;
+       static int              devnr;
+       char                    component[14];
+       struct snd_pcm          *pcm;
+
+       if (!dev)
+               return 0;
+
+       if (devnr >= SNDRV_CARDS)
+               return -ENODEV;
+
+       if (!enable[devnr])
+               return -ENOENT;
+
+       rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
+       if (rc < 0) {
+               snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
+               return rc;
+       }
+       strcpy(card->driver, "tm6000-alsa");
+       strcpy(card->shortname, "TM5600/60x0");
+       sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
+               dev->udev->bus->busnum, dev->udev->devnum);
+
+       sprintf(component, "USB%04x:%04x",
+               le16_to_cpu(dev->udev->descriptor.idVendor),
+               le16_to_cpu(dev->udev->descriptor.idProduct));
+       snd_component_add(card, component);
+       snd_card_set_dev(card, &dev->udev->dev);
+
+       chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
+       if (!chip) {
+               rc = -ENOMEM;
+               goto error;
+       }
+
+       chip->core = dev;
+       chip->card = card;
+       dev->adev = chip;
+       spin_lock_init(&chip->reg_lock);
+
+       rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
+       if (rc < 0)
+               goto error_chip;
+
+       pcm->info_flags = 0;
+       pcm->private_data = chip;
+       strcpy(pcm->name, "Trident TM5600/60x0");
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
+
+       INIT_WORK(&dev->wq_trigger, audio_trigger);
+       rc = snd_card_register(card);
+       if (rc < 0)
+               goto error_chip;
+
+       dprintk(1, "Registered audio driver for %s\n", card->longname);
+
+       return 0;
+
+error_chip:
+       kfree(chip);
+       dev->adev = NULL;
+error:
+       snd_card_free(card);
+       return rc;
+}
+
+static int tm6000_audio_fini(struct tm6000_core *dev)
+{
+       struct snd_tm6000_card  *chip = dev->adev;
+
+       if (!dev)
+               return 0;
+
+       if (!chip)
+               return 0;
+
+       if (!chip->card)
+               return 0;
+
+       snd_card_free(chip->card);
+       chip->card = NULL;
+       kfree(chip);
+       dev->adev = NULL;
+
+       return 0;
+}
+
+static struct tm6000_ops audio_ops = {
+       .type   = TM6000_AUDIO,
+       .name   = "TM6000 Audio Extension",
+       .init   = tm6000_audio_init,
+       .fini   = tm6000_audio_fini,
+       .fillbuf = tm6000_fillbuf,
+};
+
+static int __init tm6000_alsa_register(void)
+{
+       return tm6000_register_extension(&audio_ops);
+}
+
+static void __exit tm6000_alsa_unregister(void)
+{
+       tm6000_unregister_extension(&audio_ops);
+}
+
+module_init(tm6000_alsa_register);
+module_exit(tm6000_alsa_unregister);
diff --git a/drivers/media/video/tm6000/tm6000-cards.c b/drivers/media/video/tm6000/tm6000-cards.c
new file mode 100644 (file)
index 0000000..ec2578a
--- /dev/null
@@ -0,0 +1,1402 @@
+/*
+ *  tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.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 version 2
+ *
+ *  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/pci.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <media/tvaudio.h>
+#include <media/i2c-addr.h>
+#include <media/rc-map.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+#include "tuner-xc2028.h"
+#include "xc5000.h"
+
+#define TM6000_BOARD_UNKNOWN                   0
+#define TM5600_BOARD_GENERIC                   1
+#define TM6000_BOARD_GENERIC                   2
+#define TM6010_BOARD_GENERIC                   3
+#define TM5600_BOARD_10MOONS_UT821             4
+#define TM5600_BOARD_10MOONS_UT330             5
+#define TM6000_BOARD_ADSTECH_DUAL_TV           6
+#define TM6000_BOARD_FREECOM_AND_SIMILAR       7
+#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV      8
+#define TM6010_BOARD_HAUPPAUGE_900H            9
+#define TM6010_BOARD_BEHOLD_WANDER             10
+#define TM6010_BOARD_BEHOLD_VOYAGER            11
+#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE        12
+#define TM6010_BOARD_TWINHAN_TU501             13
+#define TM6010_BOARD_BEHOLD_WANDER_LITE                14
+#define TM6010_BOARD_BEHOLD_VOYAGER_LITE       15
+#define TM5600_BOARD_TERRATEC_GRABSTER         16
+
+#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
+                          (model == TM5600_BOARD_GENERIC) || \
+                          (model == TM6000_BOARD_GENERIC) || \
+                          (model == TM6010_BOARD_GENERIC))
+
+#define TM6000_MAXBOARDS        16
+static unsigned int card[]     = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(card,  int, NULL, 0444);
+
+static unsigned long tm6000_devused;
+
+
+struct tm6000_board {
+       char            *name;
+       char            eename[16];             /* EEPROM name */
+       unsigned        eename_size;            /* size of EEPROM name */
+       unsigned        eename_pos;             /* Position where it appears at ROM */
+
+       struct tm6000_capabilities caps;
+
+       enum            tm6000_devtype type;    /* variant of the chipset */
+       int             tuner_type;     /* type of the tuner */
+       int             tuner_addr;     /* tuner address */
+       int             demod_addr;     /* demodulator address */
+
+       struct tm6000_gpio gpio;
+
+       struct tm6000_input     vinput[3];
+       struct tm6000_input     rinput;
+
+       char            *ir_codes;
+};
+
+static struct tm6000_board tm6000_boards[] = {
+       [TM6000_BOARD_UNKNOWN] = {
+               .name         = "Unknown tm6000 video grabber",
+               .caps = {
+                       .has_tuner      = 1,
+                       .has_eeprom     = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6000_GPIO_1,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+       },
+       [TM5600_BOARD_GENERIC] = {
+               .name         = "Generic tm5600 board",
+               .type         = TM5600,
+               .tuner_type   = TUNER_XC2028,
+               .tuner_addr   = 0xc2 >> 1,
+               .caps = {
+                       .has_tuner      = 1,
+                       .has_eeprom     = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6000_GPIO_1,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+       },
+       [TM6000_BOARD_GENERIC] = {
+               .name         = "Generic tm6000 board",
+               .tuner_type   = TUNER_XC2028,
+               .tuner_addr   = 0xc2 >> 1,
+               .caps = {
+                       .has_tuner      = 1,
+                       .has_eeprom     = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6000_GPIO_1,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+       },
+       [TM6010_BOARD_GENERIC] = {
+               .name         = "Generic tm6010 board",
+               .type         = TM6010,
+               .tuner_type   = TUNER_XC2028,
+               .tuner_addr   = 0xc2 >> 1,
+               .demod_addr   = 0x1e >> 1,
+               .caps = {
+                       .has_tuner      = 1,
+                       .has_dvb        = 1,
+                       .has_zl10353    = 1,
+                       .has_eeprom     = 1,
+                       .has_remote     = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6010_GPIO_2,
+                       .tuner_on       = TM6010_GPIO_3,
+                       .demod_reset    = TM6010_GPIO_1,
+                       .demod_on       = TM6010_GPIO_4,
+                       .power_led      = TM6010_GPIO_7,
+                       .dvb_led        = TM6010_GPIO_5,
+                       .ir             = TM6010_GPIO_0,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+       },
+       [TM5600_BOARD_10MOONS_UT821] = {
+               .name         = "10Moons UT 821",
+               .tuner_type   = TUNER_XC2028,
+               .eename       = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
+               .eename_size  = 14,
+               .eename_pos   = 0x14,
+               .type         = TM5600,
+               .tuner_addr   = 0xc2 >> 1,
+               .caps = {
+                       .has_tuner    = 1,
+                       .has_eeprom   = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6000_GPIO_1,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+       },
+       [TM5600_BOARD_10MOONS_UT330] = {
+               .name         = "10Moons UT 330",
+               .tuner_type   = TUNER_PHILIPS_FQ1216AME_MK4,
+               .tuner_addr   = 0xc8 >> 1,
+               .caps = {
+                       .has_tuner    = 1,
+                       .has_dvb      = 0,
+                       .has_zl10353  = 0,
+                       .has_eeprom   = 1,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+       },
+       [TM6000_BOARD_ADSTECH_DUAL_TV] = {
+               .name         = "ADSTECH Dual TV USB",
+               .tuner_type   = TUNER_XC2028,
+               .tuner_addr   = 0xc8 >> 1,
+               .caps = {
+                       .has_tuner    = 1,
+                       .has_tda9874  = 1,
+                       .has_dvb      = 1,
+                       .has_zl10353  = 1,
+                       .has_eeprom   = 1,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+       },
+       [TM6000_BOARD_FREECOM_AND_SIMILAR] = {
+               .name         = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
+               .tuner_type   = TUNER_XC2028, /* has a XC3028 */
+               .tuner_addr   = 0xc2 >> 1,
+               .demod_addr   = 0x1e >> 1,
+               .caps = {
+                       .has_tuner    = 1,
+                       .has_dvb      = 1,
+                       .has_zl10353  = 1,
+                       .has_eeprom   = 0,
+                       .has_remote   = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6000_GPIO_4,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+       },
+       [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
+               .name         = "ADSTECH Mini Dual TV USB",
+               .tuner_type   = TUNER_XC2028, /* has a XC3028 */
+               .tuner_addr   = 0xc8 >> 1,
+               .demod_addr   = 0x1e >> 1,
+               .caps = {
+                       .has_tuner    = 1,
+                       .has_dvb      = 1,
+                       .has_zl10353  = 1,
+                       .has_eeprom   = 0,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6000_GPIO_4,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+       },
+       [TM6010_BOARD_HAUPPAUGE_900H] = {
+               .name         = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
+               .eename       = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
+               .eename_size  = 14,
+               .eename_pos   = 0x42,
+               .tuner_type   = TUNER_XC2028, /* has a XC3028 */
+               .tuner_addr   = 0xc2 >> 1,
+               .demod_addr   = 0x1e >> 1,
+               .type         = TM6010,
+               .caps = {
+                       .has_tuner    = 1,
+                       .has_dvb      = 1,
+                       .has_zl10353  = 1,
+                       .has_eeprom   = 1,
+                       .has_remote   = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6010_GPIO_2,
+                       .tuner_on       = TM6010_GPIO_3,
+                       .demod_reset    = TM6010_GPIO_1,
+                       .demod_on       = TM6010_GPIO_4,
+                       .power_led      = TM6010_GPIO_7,
+                       .dvb_led        = TM6010_GPIO_5,
+                       .ir             = TM6010_GPIO_0,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+       },
+       [TM6010_BOARD_BEHOLD_WANDER] = {
+               .name         = "Beholder Wander DVB-T/TV/FM USB2.0",
+               .tuner_type   = TUNER_XC5000,
+               .tuner_addr   = 0xc2 >> 1,
+               .demod_addr   = 0x1e >> 1,
+               .type         = TM6010,
+               .caps = {
+                       .has_tuner      = 1,
+                       .has_dvb        = 1,
+                       .has_zl10353    = 1,
+                       .has_eeprom     = 1,
+                       .has_remote     = 1,
+                       .has_radio      = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6010_GPIO_0,
+                       .demod_reset    = TM6010_GPIO_1,
+                       .power_led      = TM6010_GPIO_6,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+               .rinput = {
+                       .type   = TM6000_INPUT_RADIO,
+                       .amux   = TM6000_AMUX_ADC1,
+               },
+       },
+       [TM6010_BOARD_BEHOLD_VOYAGER] = {
+               .name         = "Beholder Voyager TV/FM USB2.0",
+               .tuner_type   = TUNER_XC5000,
+               .tuner_addr   = 0xc2 >> 1,
+               .type         = TM6010,
+               .caps = {
+                       .has_tuner      = 1,
+                       .has_dvb        = 0,
+                       .has_zl10353    = 0,
+                       .has_eeprom     = 1,
+                       .has_remote     = 1,
+                       .has_radio      = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6010_GPIO_0,
+                       .power_led      = TM6010_GPIO_6,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+               .rinput = {
+                       .type   = TM6000_INPUT_RADIO,
+                       .amux   = TM6000_AMUX_ADC1,
+               },
+       },
+       [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
+               .name         = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
+               .tuner_type   = TUNER_XC2028, /* has a XC3028 */
+               .tuner_addr   = 0xc2 >> 1,
+               .demod_addr   = 0x1e >> 1,
+               .type         = TM6010,
+               .caps = {
+                       .has_tuner    = 1,
+                       .has_dvb      = 1,
+                       .has_zl10353  = 1,
+                       .has_eeprom   = 1,
+                       .has_remote   = 1,
+                       .has_radio    = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6010_GPIO_2,
+                       .tuner_on       = TM6010_GPIO_3,
+                       .demod_reset    = TM6010_GPIO_1,
+                       .demod_on       = TM6010_GPIO_4,
+                       .power_led      = TM6010_GPIO_7,
+                       .dvb_led        = TM6010_GPIO_5,
+                       .ir             = TM6010_GPIO_0,
+               },
+               .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+               .rinput = {
+                       .type = TM6000_INPUT_RADIO,
+                       .amux = TM6000_AMUX_SIF1,
+               },
+       },
+       [TM5600_BOARD_TERRATEC_GRABSTER] = {
+               .name         = "Terratec Grabster AV 150/250 MX",
+               .type         = TM5600,
+               .tuner_type   = TUNER_ABSENT,
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_ADC1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+       },
+       [TM6010_BOARD_TWINHAN_TU501] = {
+               .name         = "Twinhan TU501(704D1)",
+               .tuner_type   = TUNER_XC2028, /* has a XC3028 */
+               .tuner_addr   = 0xc2 >> 1,
+               .demod_addr   = 0x1e >> 1,
+               .type         = TM6010,
+               .caps = {
+                       .has_tuner    = 1,
+                       .has_dvb      = 1,
+                       .has_zl10353  = 1,
+                       .has_eeprom   = 1,
+                       .has_remote   = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6010_GPIO_2,
+                       .tuner_on       = TM6010_GPIO_3,
+                       .demod_reset    = TM6010_GPIO_1,
+                       .demod_on       = TM6010_GPIO_4,
+                       .power_led      = TM6010_GPIO_7,
+                       .dvb_led        = TM6010_GPIO_5,
+                       .ir             = TM6010_GPIO_0,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       }, {
+                       .type   = TM6000_INPUT_COMPOSITE1,
+                       .vmux   = TM6000_VMUX_VIDEO_A,
+                       .amux   = TM6000_AMUX_ADC2,
+                       }, {
+                       .type   = TM6000_INPUT_SVIDEO,
+                       .vmux   = TM6000_VMUX_VIDEO_AB,
+                       .amux   = TM6000_AMUX_ADC2,
+                       },
+               },
+       },
+       [TM6010_BOARD_BEHOLD_WANDER_LITE] = {
+               .name         = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
+               .tuner_type   = TUNER_XC5000,
+               .tuner_addr   = 0xc2 >> 1,
+               .demod_addr   = 0x1e >> 1,
+               .type         = TM6010,
+               .caps = {
+                       .has_tuner      = 1,
+                       .has_dvb        = 1,
+                       .has_zl10353    = 1,
+                       .has_eeprom     = 1,
+                       .has_remote     = 0,
+                       .has_radio      = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6010_GPIO_0,
+                       .demod_reset    = TM6010_GPIO_1,
+                       .power_led      = TM6010_GPIO_6,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       },
+               },
+               .rinput = {
+                       .type   = TM6000_INPUT_RADIO,
+                       .amux   = TM6000_AMUX_ADC1,
+               },
+       },
+       [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
+               .name         = "Beholder Voyager Lite TV/FM USB2.0",
+               .tuner_type   = TUNER_XC5000,
+               .tuner_addr   = 0xc2 >> 1,
+               .type         = TM6010,
+               .caps = {
+                       .has_tuner      = 1,
+                       .has_dvb        = 0,
+                       .has_zl10353    = 0,
+                       .has_eeprom     = 1,
+                       .has_remote     = 0,
+                       .has_radio      = 1,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6010_GPIO_0,
+                       .power_led      = TM6010_GPIO_6,
+               },
+               .vinput = { {
+                       .type   = TM6000_INPUT_TV,
+                       .vmux   = TM6000_VMUX_VIDEO_B,
+                       .amux   = TM6000_AMUX_SIF1,
+                       },
+               },
+               .rinput = {
+                       .type   = TM6000_INPUT_RADIO,
+                       .amux   = TM6000_AMUX_ADC1,
+               },
+       },
+};
+
+/* table of devices that work with this driver */
+static struct usb_device_id tm6000_id_table[] = {
+       { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
+       { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
+       { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
+       { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
+       { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
+       { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
+       { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
+       { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
+       { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
+       { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
+       { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
+       { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
+       { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
+       { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
+       { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
+       { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
+       { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
+       { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
+       { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
+       { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
+       { }
+};
+
+/* Control power led for show some activity */
+void tm6000_flash_led(struct tm6000_core *dev, u8 state)
+{
+       /* Power LED unconfigured */
+       if (!dev->gpio.power_led)
+               return;
+
+       /* ON Power LED */
+       if (state) {
+               switch (dev->model) {
+               case TM6010_BOARD_HAUPPAUGE_900H:
+               case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+               case TM6010_BOARD_TWINHAN_TU501:
+                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                               dev->gpio.power_led, 0x00);
+                       break;
+               case TM6010_BOARD_BEHOLD_WANDER:
+               case TM6010_BOARD_BEHOLD_VOYAGER:
+               case TM6010_BOARD_BEHOLD_WANDER_LITE:
+               case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
+                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                               dev->gpio.power_led, 0x01);
+                       break;
+               }
+       }
+       /* OFF Power LED */
+       else {
+               switch (dev->model) {
+               case TM6010_BOARD_HAUPPAUGE_900H:
+               case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+               case TM6010_BOARD_TWINHAN_TU501:
+                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                               dev->gpio.power_led, 0x01);
+                       break;
+               case TM6010_BOARD_BEHOLD_WANDER:
+               case TM6010_BOARD_BEHOLD_VOYAGER:
+               case TM6010_BOARD_BEHOLD_WANDER_LITE:
+               case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
+                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                               dev->gpio.power_led, 0x00);
+                       break;
+               }
+       }
+}
+
+/* Tuner callback to provide the proper gpio changes needed for xc5000 */
+int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
+{
+       int rc = 0;
+       struct tm6000_core *dev = ptr;
+
+       if (dev->tuner_type != TUNER_XC5000)
+               return 0;
+
+       switch (command) {
+       case XC5000_TUNER_RESET:
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                              dev->gpio.tuner_reset, 0x01);
+               msleep(15);
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                              dev->gpio.tuner_reset, 0x00);
+               msleep(15);
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                              dev->gpio.tuner_reset, 0x01);
+               break;
+       }
+       return rc;
+}
+EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
+
+/* Tuner callback to provide the proper gpio changes needed for xc2028 */
+
+int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
+{
+       int rc = 0;
+       struct tm6000_core *dev = ptr;
+
+       if (dev->tuner_type != TUNER_XC2028)
+               return 0;
+
+       switch (command) {
+       case XC2028_RESET_CLK:
+               tm6000_ir_wait(dev, 0);
+
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
+                                       0x02, arg);
+               msleep(10);
+               rc = tm6000_i2c_reset(dev, 10);
+               break;
+       case XC2028_TUNER_RESET:
+               /* Reset codes during load firmware */
+               switch (arg) {
+               case 0:
+                       /* newer tuner can faster reset */
+                       switch (dev->model) {
+                       case TM5600_BOARD_10MOONS_UT821:
+                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                              dev->gpio.tuner_reset, 0x01);
+                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                              0x300, 0x01);
+                               msleep(10);
+                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                              dev->gpio.tuner_reset, 0x00);
+                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                              0x300, 0x00);
+                               msleep(10);
+                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                              dev->gpio.tuner_reset, 0x01);
+                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                              0x300, 0x01);
+                               break;
+                       case TM6010_BOARD_HAUPPAUGE_900H:
+                       case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+                       case TM6010_BOARD_TWINHAN_TU501:
+                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                              dev->gpio.tuner_reset, 0x01);
+                               msleep(60);
+                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                              dev->gpio.tuner_reset, 0x00);
+                               msleep(75);
+                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                              dev->gpio.tuner_reset, 0x01);
+                               msleep(60);
+                               break;
+                       default:
+                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                              dev->gpio.tuner_reset, 0x00);
+                               msleep(130);
+                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                              dev->gpio.tuner_reset, 0x01);
+                               msleep(130);
+                               break;
+                       }
+
+                       tm6000_ir_wait(dev, 1);
+                       break;
+               case 1:
+                       tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
+                                               0x02, 0x01);
+                       msleep(10);
+                       break;
+               case 2:
+                       rc = tm6000_i2c_reset(dev, 100);
+                       break;
+               }
+               break;
+       case XC2028_I2C_FLUSH:
+               tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
+               tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
+               break;
+       }
+       return rc;
+}
+EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
+
+int tm6000_cards_setup(struct tm6000_core *dev)
+{
+       /*
+        * Board-specific initialization sequence. Handles all GPIO
+        * initialization sequences that are board-specific.
+        * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
+        * Probably, they're all based on some reference device. Due to that,
+        * there's a common routine at the end to handle those GPIO's. Devices
+        * that use different pinups or init sequences can just return at
+        * the board-specific session.
+        */
+       switch (dev->model) {
+       case TM6010_BOARD_HAUPPAUGE_900H:
+       case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+       case TM6010_BOARD_TWINHAN_TU501:
+       case TM6010_BOARD_GENERIC:
+               /* Turn xceive 3028 on */
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
+               msleep(15);
+               /* Turn zarlink zl10353 on */
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
+               msleep(15);
+               /* Reset zarlink zl10353 */
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
+               msleep(50);
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
+               msleep(15);
+               /* Turn zarlink zl10353 off */
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
+               msleep(15);
+               /* ir ? */
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
+               msleep(15);
+               /* Power led on (blue) */
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
+               msleep(15);
+               /* DVB led off (orange) */
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
+               msleep(15);
+               /* Turn zarlink zl10353 on */
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
+               msleep(15);
+               break;
+       case TM6010_BOARD_BEHOLD_WANDER:
+       case TM6010_BOARD_BEHOLD_WANDER_LITE:
+               /* Power led on (blue) */
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
+               msleep(15);
+               /* Reset zarlink zl10353 */
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
+               msleep(50);
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
+               msleep(15);
+               break;
+       case TM6010_BOARD_BEHOLD_VOYAGER:
+       case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
+               /* Power led on (blue) */
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
+               msleep(15);
+               break;
+       default:
+               break;
+       }
+
+       /*
+        * Default initialization. Most of the devices seem to use GPIO1
+        * and GPIO4.on the same way, so, this handles the common sequence
+        * used by most devices.
+        * If a device uses a different sequence or different GPIO pins for
+        * reset, just add the code at the board-specific part
+        */
+
+       if (dev->gpio.tuner_reset) {
+               int rc;
+               int i;
+
+               for (i = 0; i < 2; i++) {
+                       rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                               dev->gpio.tuner_reset, 0x00);
+                       if (rc < 0) {
+                               printk(KERN_ERR "Error %i doing tuner reset\n", rc);
+                               return rc;
+                       }
+
+                       msleep(10); /* Just to be conservative */
+                       rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                                               dev->gpio.tuner_reset, 0x01);
+                       if (rc < 0) {
+                               printk(KERN_ERR "Error %i doing tuner reset\n", rc);
+                               return rc;
+                       }
+               }
+       } else {
+               printk(KERN_ERR "Tuner reset is not configured\n");
+               return -1;
+       }
+
+       msleep(50);
+
+       return 0;
+};
+
+static void tm6000_config_tuner(struct tm6000_core *dev)
+{
+       struct tuner_setup tun_setup;
+
+       /* Load tuner module */
+       v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+               "tuner", dev->tuner_addr, NULL);
+
+       memset(&tun_setup, 0, sizeof(tun_setup));
+       tun_setup.type = dev->tuner_type;
+       tun_setup.addr = dev->tuner_addr;
+
+       tun_setup.mode_mask = 0;
+       if (dev->caps.has_tuner)
+               tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
+
+       switch (dev->tuner_type) {
+       case TUNER_XC2028:
+               tun_setup.tuner_callback = tm6000_tuner_callback;
+               break;
+       case TUNER_XC5000:
+               tun_setup.tuner_callback = tm6000_xc5000_callback;
+               break;
+       }
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+
+       switch (dev->tuner_type) {
+       case TUNER_XC2028: {
+               struct v4l2_priv_tun_config xc2028_cfg;
+               struct xc2028_ctrl ctl;
+
+               memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+               memset(&ctl, 0, sizeof(ctl));
+
+               ctl.demod = XC3028_FE_ZARLINK456;
+
+               xc2028_cfg.tuner = TUNER_XC2028;
+               xc2028_cfg.priv  = &ctl;
+
+               switch (dev->model) {
+               case TM6010_BOARD_HAUPPAUGE_900H:
+               case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+               case TM6010_BOARD_TWINHAN_TU501:
+                       ctl.fname = "xc3028L-v36.fw";
+                       break;
+               default:
+                       if (dev->dev_type == TM6010)
+                               ctl.fname = "xc3028-v27.fw";
+                       else
+                               ctl.fname = "xc3028-v24.fw";
+               }
+
+               printk(KERN_INFO "Setting firmware parameters for xc2028\n");
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
+                                    &xc2028_cfg);
+
+               }
+               break;
+       case TUNER_XC5000:
+               {
+               struct v4l2_priv_tun_config  xc5000_cfg;
+               struct xc5000_config ctl = {
+                       .i2c_address = dev->tuner_addr,
+                       .if_khz      = 4570,
+                       .radio_input = XC5000_RADIO_FM1_MONO,
+                       };
+
+               xc5000_cfg.tuner = TUNER_XC5000;
+               xc5000_cfg.priv  = &ctl;
+
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
+                                    &xc5000_cfg);
+               }
+               break;
+       default:
+               printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
+               break;
+       }
+}
+
+static int fill_board_specific_data(struct tm6000_core *dev)
+{
+       int rc;
+
+       dev->dev_type   = tm6000_boards[dev->model].type;
+       dev->tuner_type = tm6000_boards[dev->model].tuner_type;
+       dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
+
+       dev->gpio = tm6000_boards[dev->model].gpio;
+
+       dev->ir_codes = tm6000_boards[dev->model].ir_codes;
+
+       dev->demod_addr = tm6000_boards[dev->model].demod_addr;
+
+       dev->caps = tm6000_boards[dev->model].caps;
+
+       dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
+       dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
+       dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
+       dev->rinput = tm6000_boards[dev->model].rinput;
+
+       /* setup per-model quirks */
+       switch (dev->model) {
+       case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+               dev->quirks |= TM6000_QUIRK_NO_USB_DELAY;
+               break;
+
+       default:
+               break;
+       }
+
+       /* initialize hardware */
+       rc = tm6000_init(dev);
+       if (rc < 0)
+               return rc;
+
+       return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
+}
+
+
+static void use_alternative_detection_method(struct tm6000_core *dev)
+{
+       int i, model = -1;
+
+       if (!dev->eedata_size)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
+               if (!tm6000_boards[i].eename_size)
+                       continue;
+               if (dev->eedata_size < tm6000_boards[i].eename_pos +
+                                      tm6000_boards[i].eename_size)
+                       continue;
+
+               if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
+                           tm6000_boards[i].eename,
+                           tm6000_boards[i].eename_size)) {
+                       model = i;
+                       break;
+               }
+       }
+       if (model < 0) {
+               printk(KERN_INFO "Device has eeprom but is currently unknown\n");
+               return;
+       }
+
+       dev->model = model;
+
+       printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
+              tm6000_boards[model].name, model);
+}
+
+static int tm6000_init_dev(struct tm6000_core *dev)
+{
+       struct v4l2_frequency f;
+       int rc = 0;
+
+       mutex_init(&dev->lock);
+       mutex_lock(&dev->lock);
+
+       if (!is_generic(dev->model)) {
+               rc = fill_board_specific_data(dev);
+               if (rc < 0)
+                       goto err;
+
+               /* register i2c bus */
+               rc = tm6000_i2c_register(dev);
+               if (rc < 0)
+                       goto err;
+       } else {
+               /* register i2c bus */
+               rc = tm6000_i2c_register(dev);
+               if (rc < 0)
+                       goto err;
+
+               use_alternative_detection_method(dev);
+
+               rc = fill_board_specific_data(dev);
+               if (rc < 0)
+                       goto err;
+       }
+
+       /* Default values for STD and resolutions */
+       dev->width = 720;
+       dev->height = 480;
+       dev->norm = V4L2_STD_PAL_M;
+
+       /* Configure tuner */
+       tm6000_config_tuner(dev);
+
+       /* Set video standard */
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+
+       /* Set tuner frequency - also loads firmware on xc2028/xc3028 */
+       f.tuner = 0;
+       f.type = V4L2_TUNER_ANALOG_TV;
+       f.frequency = 3092;     /* 193.25 MHz */
+       dev->freq = f.frequency;
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+
+       if (dev->caps.has_tda9874)
+               v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+                       "tvaudio", I2C_ADDR_TDA9874, NULL);
+
+       /* register and initialize V4L2 */
+       rc = tm6000_v4l2_register(dev);
+       if (rc < 0)
+               goto err;
+
+       tm6000_add_into_devlist(dev);
+       tm6000_init_extension(dev);
+
+       tm6000_ir_init(dev);
+
+       mutex_unlock(&dev->lock);
+       return 0;
+
+err:
+       mutex_unlock(&dev->lock);
+       return rc;
+}
+
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+
+static void get_max_endpoint(struct usb_device *udev,
+                            struct usb_host_interface *alt,
+                            char *msgtype,
+                            struct usb_host_endpoint *curr_e,
+                            struct tm6000_endpoint *tm_ep)
+{
+       u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
+       unsigned int size = tmp & 0x7ff;
+
+       if (udev->speed == USB_SPEED_HIGH)
+               size = size * hb_mult(tmp);
+
+       if (size > tm_ep->maxsize) {
+               tm_ep->endp = curr_e;
+               tm_ep->maxsize = size;
+               tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
+               tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
+
+               printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
+                                       msgtype, curr_e->desc.bEndpointAddress,
+                                       size);
+       }
+}
+
+/*
+ * tm6000_usb_probe()
+ * checks for supported devices
+ */
+static int tm6000_usb_probe(struct usb_interface *interface,
+                           const struct usb_device_id *id)
+{
+       struct usb_device *usbdev;
+       struct tm6000_core *dev = NULL;
+       int i, rc = 0;
+       int nr = 0;
+       char *speed;
+
+       usbdev = usb_get_dev(interface_to_usbdev(interface));
+
+       /* Selects the proper interface */
+       rc = usb_set_interface(usbdev, 0, 1);
+       if (rc < 0)
+               goto err;
+
+       /* Check to see next free device and mark as used */
+       nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
+       if (nr >= TM6000_MAXBOARDS) {
+               printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
+               usb_put_dev(usbdev);
+               return -ENOMEM;
+       }
+
+       /* Create and initialize dev struct */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               printk(KERN_ERR "tm6000" ": out of memory!\n");
+               usb_put_dev(usbdev);
+               return -ENOMEM;
+       }
+       spin_lock_init(&dev->slock);
+       mutex_init(&dev->usb_lock);
+
+       /* Increment usage count */
+       set_bit(nr, &tm6000_devused);
+       snprintf(dev->name, 29, "tm6000 #%d", nr);
+
+       dev->model = id->driver_info;
+       if (card[nr] < ARRAY_SIZE(tm6000_boards))
+               dev->model = card[nr];
+
+       dev->udev = usbdev;
+       dev->devno = nr;
+
+       switch (usbdev->speed) {
+       case USB_SPEED_LOW:
+               speed = "1.5";
+               break;
+       case USB_SPEED_UNKNOWN:
+       case USB_SPEED_FULL:
+               speed = "12";
+               break;
+       case USB_SPEED_HIGH:
+               speed = "480";
+               break;
+       default:
+               speed = "unknown";
+       }
+
+       /* Get endpoints */
+       for (i = 0; i < interface->num_altsetting; i++) {
+               int ep;
+
+               for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
+                       struct usb_host_endpoint        *e;
+                       int dir_out;
+
+                       e = &interface->altsetting[i].endpoint[ep];
+
+                       dir_out = ((e->desc.bEndpointAddress &
+                                       USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
+
+                       printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
+                              i,
+                              interface->altsetting[i].desc.bInterfaceNumber,
+                              interface->altsetting[i].desc.bInterfaceClass);
+
+                       switch (e->desc.bmAttributes) {
+                       case USB_ENDPOINT_XFER_BULK:
+                               if (!dir_out) {
+                                       get_max_endpoint(usbdev,
+                                                        &interface->altsetting[i],
+                                                        "Bulk IN", e,
+                                                        &dev->bulk_in);
+                               } else {
+                                       get_max_endpoint(usbdev,
+                                                        &interface->altsetting[i],
+                                                        "Bulk OUT", e,
+                                                        &dev->bulk_out);
+                               }
+                               break;
+                       case USB_ENDPOINT_XFER_ISOC:
+                               if (!dir_out) {
+                                       get_max_endpoint(usbdev,
+                                                        &interface->altsetting[i],
+                                                        "ISOC IN", e,
+                                                        &dev->isoc_in);
+                               } else {
+                                       get_max_endpoint(usbdev,
+                                                        &interface->altsetting[i],
+                                                        "ISOC OUT", e,
+                                                        &dev->isoc_out);
+                               }
+                               break;
+                       case USB_ENDPOINT_XFER_INT:
+                               if (!dir_out) {
+                                       get_max_endpoint(usbdev,
+                                                       &interface->altsetting[i],
+                                                       "INT IN", e,
+                                                       &dev->int_in);
+                               } else {
+                                       get_max_endpoint(usbdev,
+                                                       &interface->altsetting[i],
+                                                       "INT OUT", e,
+                                                       &dev->int_out);
+                               }
+                               break;
+                       }
+               }
+       }
+
+
+       printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
+               speed,
+               le16_to_cpu(dev->udev->descriptor.idVendor),
+               le16_to_cpu(dev->udev->descriptor.idProduct),
+               interface->altsetting->desc.bInterfaceNumber);
+
+/* check if the the device has the iso in endpoint at the correct place */
+       if (!dev->isoc_in.endp) {
+               printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
+               rc = -ENODEV;
+
+               goto err;
+       }
+
+       /* save our data pointer in this interface device */
+       usb_set_intfdata(interface, dev);
+
+       printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
+
+       rc = tm6000_init_dev(dev);
+       if (rc < 0)
+               goto err;
+
+       return 0;
+
+err:
+       printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
+
+       clear_bit(nr, &tm6000_devused);
+       usb_put_dev(usbdev);
+
+       kfree(dev);
+       return rc;
+}
+
+/*
+ * tm6000_usb_disconnect()
+ * called when the device gets diconencted
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void tm6000_usb_disconnect(struct usb_interface *interface)
+{
+       struct tm6000_core *dev = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       if (!dev)
+               return;
+
+       printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
+
+       tm6000_ir_fini(dev);
+
+       if (dev->gpio.power_led) {
+               switch (dev->model) {
+               case TM6010_BOARD_HAUPPAUGE_900H:
+               case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+               case TM6010_BOARD_TWINHAN_TU501:
+                       /* Power led off */
+                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                               dev->gpio.power_led, 0x01);
+                       msleep(15);
+                       break;
+               case TM6010_BOARD_BEHOLD_WANDER:
+               case TM6010_BOARD_BEHOLD_VOYAGER:
+               case TM6010_BOARD_BEHOLD_WANDER_LITE:
+               case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
+                       /* Power led off */
+                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                               dev->gpio.power_led, 0x00);
+                       msleep(15);
+                       break;
+               }
+       }
+       tm6000_v4l2_unregister(dev);
+
+       tm6000_i2c_unregister(dev);
+
+       v4l2_device_unregister(&dev->v4l2_dev);
+
+       dev->state |= DEV_DISCONNECTED;
+
+       usb_put_dev(dev->udev);
+
+       tm6000_close_extension(dev);
+       tm6000_remove_from_devlist(dev);
+
+       clear_bit(dev->devno, &tm6000_devused);
+       kfree(dev);
+}
+
+static struct usb_driver tm6000_usb_driver = {
+               .name = "tm6000",
+               .probe = tm6000_usb_probe,
+               .disconnect = tm6000_usb_disconnect,
+               .id_table = tm6000_id_table,
+};
+
+static int __init tm6000_module_init(void)
+{
+       int result;
+
+       printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n",
+              (TM6000_VERSION  >> 16) & 0xff,
+              (TM6000_VERSION  >> 8) & 0xff, TM6000_VERSION  & 0xff);
+
+       /* register this driver with the USB subsystem */
+       result = usb_register(&tm6000_usb_driver);
+       if (result)
+               printk(KERN_ERR "tm6000"
+                          " usb_register failed. Error number %d.\n", result);
+
+       return result;
+}
+
+static void __exit tm6000_module_exit(void)
+{
+       /* deregister at USB subsystem */
+       usb_deregister(&tm6000_usb_driver);
+}
+
+module_init(tm6000_module_init);
+module_exit(tm6000_module_exit);
+
+MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tm6000/tm6000-core.c b/drivers/media/video/tm6000/tm6000-core.c
new file mode 100644 (file)
index 0000000..9783616
--- /dev/null
@@ -0,0 +1,965 @@
+/*
+ *  tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ *      - DVB-T support
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation version 2
+ *
+ *  This program is distributed 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/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include "tm6000.h"
+#include "tm6000-regs.h"
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+
+#define USB_TIMEOUT    (5 * HZ) /* ms */
+
+int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
+                         u16 value, u16 index, u8 *buf, u16 len)
+{
+       int          ret, i;
+       unsigned int pipe;
+       u8           *data = NULL;
+
+       mutex_lock(&dev->usb_lock);
+
+       if (len)
+               data = kzalloc(len, GFP_KERNEL);
+
+       if (req_type & USB_DIR_IN)
+               pipe = usb_rcvctrlpipe(dev->udev, 0);
+       else {
+               pipe = usb_sndctrlpipe(dev->udev, 0);
+               memcpy(data, buf, len);
+       }
+
+       if (tm6000_debug & V4L2_DEBUG_I2C) {
+               printk(KERN_DEBUG "(dev %p, pipe %08x): ", dev->udev, pipe);
+
+               printk(KERN_CONT "%s: %02x %02x %02x %02x %02x %02x %02x %02x ",
+                       (req_type & USB_DIR_IN) ? " IN" : "OUT",
+                       req_type, req, value&0xff, value>>8, index&0xff,
+                       index>>8, len&0xff, len>>8);
+
+               if (!(req_type & USB_DIR_IN)) {
+                       printk(KERN_CONT ">>> ");
+                       for (i = 0; i < len; i++)
+                               printk(KERN_CONT " %02x", buf[i]);
+                       printk(KERN_CONT "\n");
+               }
+       }
+
+       ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index,
+                             data, len, USB_TIMEOUT);
+
+       if (req_type &  USB_DIR_IN)
+               memcpy(buf, data, len);
+
+       if (tm6000_debug & V4L2_DEBUG_I2C) {
+               if (ret < 0) {
+                       if (req_type &  USB_DIR_IN)
+                               printk(KERN_DEBUG "<<< (len=%d)\n", len);
+
+                       printk(KERN_CONT "%s: Error #%d\n", __func__, ret);
+               } else if (req_type &  USB_DIR_IN) {
+                       printk(KERN_CONT "<<< ");
+                       for (i = 0; i < len; i++)
+                               printk(KERN_CONT " %02x", buf[i]);
+                       printk(KERN_CONT "\n");
+               }
+       }
+
+       kfree(data);
+       msleep(5);
+
+       mutex_unlock(&dev->usb_lock);
+       return ret;
+}
+
+int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
+{
+       return
+               tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+                                     req, value, index, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(tm6000_set_reg);
+
+int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
+{
+       int rc;
+       u8 buf[1];
+
+       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+                                       value, index, buf, 1);
+
+       if (rc < 0)
+               return rc;
+
+       return *buf;
+}
+EXPORT_SYMBOL_GPL(tm6000_get_reg);
+
+int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
+                                               u16 index, u16 mask)
+{
+       int rc;
+       u8 buf[1];
+       u8 new_index;
+
+       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+                                       value, index, buf, 1);
+
+       if (rc < 0)
+               return rc;
+
+       new_index = (buf[0] & ~mask) | (index & mask);
+
+       if (new_index == index)
+               return 0;
+
+       return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+                                     req, value, new_index, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(tm6000_set_reg_mask);
+
+int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index)
+{
+       int rc;
+       u8 buf[2];
+
+       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+                                       value, index, buf, 2);
+
+       if (rc < 0)
+               return rc;
+
+       return buf[1]|buf[0]<<8;
+}
+
+int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index)
+{
+       int rc;
+       u8 buf[4];
+
+       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+                                       value, index, buf, 4);
+
+       if (rc < 0)
+               return rc;
+
+       return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24;
+}
+
+int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep)
+{
+       int rc;
+
+       rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0);
+       if (rc < 0)
+               return rc;
+
+       msleep(tsleep);
+
+       rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1);
+       msleep(tsleep);
+
+       return rc;
+}
+
+void tm6000_set_fourcc_format(struct tm6000_core *dev)
+{
+       if (dev->dev_type == TM6010) {
+               int val;
+
+               val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, 0) & 0xfc;
+               if (dev->fourcc == V4L2_PIX_FMT_UYVY)
+                       tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val);
+               else
+                       tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val | 1);
+       } else {
+               if (dev->fourcc == V4L2_PIX_FMT_UYVY)
+                       tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
+               else
+                       tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0x90);
+       }
+}
+
+static void tm6000_set_vbi(struct tm6000_core *dev)
+{
+       /*
+        * FIXME:
+        * VBI lines and start/end are different between 60Hz and 50Hz
+        * So, it is very likely that we need to change the config to
+        * something that takes it into account, doing something different
+        * if (dev->norm & V4L2_STD_525_60)
+        */
+
+       if (dev->dev_type == TM6010) {
+               tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
+               tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27);
+               tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55);
+               tm6000_set_reg(dev, TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7, 0x66);
+               tm6000_set_reg(dev, TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8, 0x66);
+               tm6000_set_reg(dev, TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22, 0x66);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23, 0x00);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES, 0x00);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN, 0x00);
+               tm6000_set_reg(dev,
+                       TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02);
+               tm6000_set_reg(dev, TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35);
+               tm6000_set_reg(dev, TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0);
+               tm6000_set_reg(dev, TM6010_REQ07_R5A_VBI_TELETEXT_DTO1, 0x11);
+               tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c);
+               tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01);
+               tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
+       }
+}
+
+int tm6000_init_analog_mode(struct tm6000_core *dev)
+{
+       struct v4l2_frequency f;
+
+       if (dev->dev_type == TM6010) {
+               u8 active = TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE;
+
+               if (!dev->radio)
+                       active |= TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE;
+
+               /* Enable video and audio */
+               tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF,
+                                                       active, 0x60);
+               /* Disable TS input */
+               tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
+                                                       0x00, 0x40);
+       } else {
+               /* Enables soft reset */
+               tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
+
+               if (dev->scaler)
+                       /* Disable Hfilter and Enable TS Drop err */
+                       tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20);
+               else    /* Enable Hfilter and disable TS Drop err */
+                       tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80);
+
+               tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88);
+               tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x23);
+               tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0);
+               tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8);
+               tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06);
+               tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f);
+
+               /* AP Software reset */
+               tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
+               tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
+
+               tm6000_set_fourcc_format(dev);
+
+               /* Disables soft reset */
+               tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
+       }
+       msleep(20);
+
+       /* Tuner firmware can now be loaded */
+
+       /*
+        * FIXME: This is a hack! xc3028 "sleeps" when no channel is detected
+        * for more than a few seconds. Not sure why, as this behavior does
+        * not happen on other devices with xc3028. So, I suspect that it
+        * is yet another bug at tm6000. After start sleeping, decoding
+        * doesn't start automatically. Instead, it requires some
+        * I2C commands to wake it up. As we want to have image at the
+        * beginning, we needed to add this hack. The better would be to
+        * discover some way to make tm6000 to wake up without this hack.
+        */
+       f.frequency = dev->freq;
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+
+       msleep(100);
+       tm6000_set_standard(dev);
+       tm6000_set_vbi(dev);
+       tm6000_set_audio_bitrate(dev, 48000);
+
+       /* switch dvb led off */
+       if (dev->gpio.dvb_led) {
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                       dev->gpio.dvb_led, 0x01);
+       }
+
+       return 0;
+}
+
+int tm6000_init_digital_mode(struct tm6000_core *dev)
+{
+       if (dev->dev_type == TM6010) {
+               /* Disable video and audio */
+               tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF,
+                               0x00, 0x60);
+               /* Enable TS input */
+               tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
+                               0x40, 0x40);
+               /* all power down, but not the digital data port */
+               tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28);
+               tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc);
+               tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff);
+       } else  {
+               tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
+               tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
+               tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
+               tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x08);
+               tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c);
+               tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff);
+               tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0xd8);
+               tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40);
+               tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
+               tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09);
+               tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x37);
+               tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8);
+               tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0);
+               tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60);
+
+               tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c);
+               tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff);
+               tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x08);
+               msleep(50);
+
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+               msleep(50);
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
+               msleep(50);
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+               msleep(100);
+       }
+
+       /* switch dvb led on */
+       if (dev->gpio.dvb_led) {
+               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                       dev->gpio.dvb_led, 0x00);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(tm6000_init_digital_mode);
+
+struct reg_init {
+       u8 req;
+       u8 reg;
+       u8 val;
+};
+
+/* The meaning of those initializations are unknown */
+static struct reg_init tm6000_init_tab[] = {
+       /* REG  VALUE */
+       { TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f },
+       { TM6010_REQ07_RFF_SOFT_RESET, 0x08 },
+       { TM6010_REQ07_RFF_SOFT_RESET, 0x00 },
+       { TM6010_REQ07_RD5_POWERSAVE, 0x4f },
+       { TM6000_REQ07_RDA_CLK_SEL, 0x23 },
+       { TM6000_REQ07_RDB_OUT_SEL, 0x08 },
+       { TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x00 },
+       { TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10 },
+       { TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00 },
+       { TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00 },
+       { TM6000_REQ07_REB_VADC_AADC_MODE, 0x64 },      /* 48000 bits/sample, external input */
+       { TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL, 0xc2 },
+
+       { TM6010_REQ07_R3F_RESET, 0x01 },               /* Start of soft reset */
+       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
+       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
+       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
+       { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 },
+       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 },
+       { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 },
+       { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 },
+       { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 },
+       { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a },
+       { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 },
+       { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 },
+       { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b },
+       { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 },
+       { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f },
+       { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd },
+       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
+       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
+       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
+       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
+       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+       { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c },
+       { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c },
+       { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 },
+       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
+       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
+       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
+       { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 },
+       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
+       { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 },
+       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
+       { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a },
+       { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 },
+       { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 },
+       { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a },
+       { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 },
+       { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 },
+       { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 },
+       { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 },
+       { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 },
+       { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 },
+       { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 },
+       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
+       { TM6010_REQ07_RC1_TRESHOLD, 0xd0 },
+       { TM6010_REQ07_RC3_HSTART1, 0x88 },
+       { TM6010_REQ07_R3F_RESET, 0x00 },               /* End of the soft reset */
+       { TM6010_REQ05_R18_IMASK7, 0x00 },
+};
+
+static struct reg_init tm6010_init_tab[] = {
+       { TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00 },
+       { TM6010_REQ07_RC4_HSTART0, 0xa0 },
+       { TM6010_REQ07_RC6_HEND0, 0x40 },
+       { TM6010_REQ07_RCA_VEND0, 0x31 },
+       { TM6010_REQ07_RCC_ACTIVE_IF, 0xe1 },
+       { TM6010_REQ07_RE0_DVIDEO_SOURCE, 0x03 },
+       { TM6010_REQ07_RFE_POWER_DOWN, 0x7f },
+
+       { TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0 },
+       { TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4 },
+       { TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8 },
+       { TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00 },
+       { TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2 },
+       { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 },
+       { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 },
+       { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 },
+       { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc },
+
+       { TM6010_REQ07_R3F_RESET, 0x01 },
+       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
+       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
+       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
+       { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 },
+       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 },
+       { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 },
+       { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 },
+       { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 },
+       { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a },
+       { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 },
+       { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 },
+       { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b },
+       { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 },
+       { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f },
+       { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd },
+       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
+       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
+       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
+       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
+       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+       { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c },
+       { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c },
+       { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 },
+       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
+       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
+       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
+       { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 },
+       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
+       { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 },
+       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
+       { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a },
+       { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 },
+       { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 },
+       { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a },
+       { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 },
+       { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 },
+       { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 },
+       { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 },
+       { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 },
+       { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 },
+       { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 },
+       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
+       { TM6010_REQ07_RC1_TRESHOLD, 0xd0 },
+       { TM6010_REQ07_RC3_HSTART1, 0x88 },
+       { TM6010_REQ07_R3F_RESET, 0x00 },
+
+       { TM6010_REQ05_R18_IMASK7, 0x00 },
+
+       { TM6010_REQ07_RD8_IR_LEADER1, 0xaa },
+       { TM6010_REQ07_RD8_IR_LEADER0, 0x30 },
+       { TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 },
+       { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 },
+       { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 },
+       { TM6010_REQ07_RD8_IR, 0x2f },
+
+       /* set remote wakeup key:any key wakeup */
+       { TM6010_REQ07_RE5_REMOTE_WAKEUP,  0xfe },
+       { TM6010_REQ07_RD8_IR_WAKEUP_SEL,  0xff },
+};
+
+int tm6000_init(struct tm6000_core *dev)
+{
+       int board, rc = 0, i, size;
+       struct reg_init *tab;
+
+       /* Check board revision */
+       board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0);
+       if (board >= 0) {
+               switch (board & 0xff) {
+               case 0xf3:
+                       printk(KERN_INFO "Found tm6000\n");
+                       if (dev->dev_type != TM6000)
+                               dev->dev_type = TM6000;
+                       break;
+               case 0xf4:
+                       printk(KERN_INFO "Found tm6010\n");
+                       if (dev->dev_type != TM6010)
+                               dev->dev_type = TM6010;
+                       break;
+               default:
+                       printk(KERN_INFO "Unknown board version = 0x%08x\n", board);
+               }
+       } else
+               printk(KERN_ERR "Error %i while retrieving board version\n", board);
+
+       if (dev->dev_type == TM6010) {
+               tab = tm6010_init_tab;
+               size = ARRAY_SIZE(tm6010_init_tab);
+       } else {
+               tab = tm6000_init_tab;
+               size = ARRAY_SIZE(tm6000_init_tab);
+       }
+
+       /* Load board's initialization table */
+       for (i = 0; i < size; i++) {
+               rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val);
+               if (rc < 0) {
+                       printk(KERN_ERR "Error %i while setting req %d, "
+                                       "reg %d to value %d\n", rc,
+                                       tab[i].req, tab[i].reg, tab[i].val);
+                       return rc;
+               }
+       }
+
+       msleep(5); /* Just to be conservative */
+
+       rc = tm6000_cards_setup(dev);
+
+       return rc;
+}
+
+int tm6000_reset(struct tm6000_core *dev)
+{
+       int pipe;
+       int err;
+
+       msleep(500);
+
+       err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 0);
+       if (err < 0) {
+               tm6000_err("failed to select interface %d, alt. setting 0\n",
+                               dev->isoc_in.bInterfaceNumber);
+               return err;
+       }
+
+       err = usb_reset_configuration(dev->udev);
+       if (err < 0) {
+               tm6000_err("failed to reset configuration\n");
+               return err;
+       }
+
+       if ((dev->quirks & TM6000_QUIRK_NO_USB_DELAY) == 0)
+               msleep(5);
+
+       /*
+        * Not all devices have int_in defined
+        */
+       if (!dev->int_in.endp)
+               return 0;
+
+       err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 2);
+       if (err < 0) {
+               tm6000_err("failed to select interface %d, alt. setting 2\n",
+                               dev->isoc_in.bInterfaceNumber);
+               return err;
+       }
+
+       msleep(5);
+
+       pipe = usb_rcvintpipe(dev->udev,
+                       dev->int_in.endp->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+
+       err = usb_clear_halt(dev->udev, pipe);
+       if (err < 0) {
+               tm6000_err("usb_clear_halt failed: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
+{
+       int val = 0;
+       u8 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
+       u8 areg_0a = 0x91; /* SIF 48KHz */
+
+       switch (bitrate) {
+       case 48000:
+               areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
+               areg_0a = 0x91; /* SIF 48KHz */
+               dev->audio_bitrate = bitrate;
+               break;
+       case 32000:
+               areg_f0 = 0x00; /* ADC MCLK = 375 Fs */
+               areg_0a = 0x90; /* SIF 32KHz */
+               dev->audio_bitrate = bitrate;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+
+       /* enable I2S, if we use sif or external I2S device */
+       if (dev->dev_type == TM6010) {
+               val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a);
+               if (val < 0)
+                       return val;
+
+               val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                                                       areg_f0, 0xf0);
+               if (val < 0)
+                       return val;
+       } else {
+               val = tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
+                                                       areg_f0, 0xf0);
+               if (val < 0)
+                       return val;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
+
+int tm6000_set_audio_rinput(struct tm6000_core *dev)
+{
+       if (dev->dev_type == TM6010) {
+               /* Audio crossbar setting, default SIF1 */
+               u8 areg_f0;
+
+               switch (dev->rinput.amux) {
+               case TM6000_AMUX_SIF1:
+               case TM6000_AMUX_SIF2:
+                       areg_f0 = 0x03;
+                       break;
+               case TM6000_AMUX_ADC1:
+                       areg_f0 = 0x00;
+                       break;
+               case TM6000_AMUX_ADC2:
+                       areg_f0 = 0x08;
+                       break;
+               case TM6000_AMUX_I2S:
+                       areg_f0 = 0x04;
+                       break;
+               default:
+                       printk(KERN_INFO "%s: audio input dosn't support\n",
+                               dev->name);
+                       return 0;
+                       break;
+               }
+               /* Set audio input crossbar */
+               tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                                                       areg_f0, 0x0f);
+       } else {
+               u8 areg_eb;
+               /* Audio setting, default LINE1 */
+               switch (dev->rinput.amux) {
+               case TM6000_AMUX_ADC1:
+                       areg_eb = 0x00;
+                       break;
+               case TM6000_AMUX_ADC2:
+                       areg_eb = 0x04;
+                       break;
+               default:
+                       printk(KERN_INFO "%s: audio input dosn't support\n",
+                               dev->name);
+                       return 0;
+                       break;
+               }
+               /* Set audio input */
+               tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
+                                                       areg_eb, 0x0f);
+       }
+       return 0;
+}
+
+static void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute)
+{
+       u8 mute_reg = 0;
+
+       if (mute)
+               mute_reg = 0x08;
+
+       tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08);
+}
+
+static void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute)
+{
+       u8 mute_reg = 0;
+
+       if (mute)
+               mute_reg = 0x20;
+
+       if (dev->dev_type == TM6010) {
+               tm6000_set_reg_mask(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL,
+                                                       mute_reg, 0x20);
+               tm6000_set_reg_mask(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL,
+                                                       mute_reg, 0x20);
+       } else {
+               tm6000_set_reg_mask(dev, TM6000_REQ07_REC_VADC_AADC_LVOL,
+                                                       mute_reg, 0x20);
+               tm6000_set_reg_mask(dev, TM6000_REQ07_RED_VADC_AADC_RVOL,
+                                                       mute_reg, 0x20);
+       }
+}
+
+int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute)
+{
+       enum tm6000_mux mux;
+
+       if (dev->radio)
+               mux = dev->rinput.amux;
+       else
+               mux = dev->vinput[dev->input].amux;
+
+       switch (mux) {
+       case TM6000_AMUX_SIF1:
+       case TM6000_AMUX_SIF2:
+               if (dev->dev_type == TM6010)
+                       tm6010_set_mute_sif(dev, mute);
+               else {
+                       printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has"
+                                       " SIF audio inputs. Please check the %s"
+                                       " configuration.\n", dev->name);
+                       return -EINVAL;
+               }
+               break;
+       case TM6000_AMUX_ADC1:
+       case TM6000_AMUX_ADC2:
+               tm6010_set_mute_adc(dev, mute);
+               break;
+       default:
+               return -EINVAL;
+               break;
+       }
+       return 0;
+}
+
+static void tm6010_set_volume_sif(struct tm6000_core *dev, int vol)
+{
+       u8 vol_reg;
+
+       vol_reg = vol & 0x0F;
+
+       if (vol < 0)
+               vol_reg |= 0x40;
+
+       tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, vol_reg);
+       tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg);
+}
+
+static void tm6010_set_volume_adc(struct tm6000_core *dev, int vol)
+{
+       u8 vol_reg;
+
+       vol_reg = (vol + 0x10) & 0x1f;
+
+       if (dev->dev_type == TM6010) {
+               tm6000_set_reg(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, vol_reg);
+               tm6000_set_reg(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, vol_reg);
+       } else {
+               tm6000_set_reg(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, vol_reg);
+               tm6000_set_reg(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, vol_reg);
+       }
+}
+
+void tm6000_set_volume(struct tm6000_core *dev, int vol)
+{
+       enum tm6000_mux mux;
+
+       if (dev->radio) {
+               mux = dev->rinput.amux;
+               vol += 8; /* Offset to 0 dB */
+       } else
+               mux = dev->vinput[dev->input].amux;
+
+       switch (mux) {
+       case TM6000_AMUX_SIF1:
+       case TM6000_AMUX_SIF2:
+               if (dev->dev_type == TM6010)
+                       tm6010_set_volume_sif(dev, vol);
+               else
+                       printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has"
+                                       " SIF audio inputs. Please check the %s"
+                                       " configuration.\n", dev->name);
+               break;
+       case TM6000_AMUX_ADC1:
+       case TM6000_AMUX_ADC2:
+               tm6010_set_volume_adc(dev, vol);
+               break;
+       default:
+               break;
+       }
+}
+
+static LIST_HEAD(tm6000_devlist);
+static DEFINE_MUTEX(tm6000_devlist_mutex);
+
+/*
+ * tm6000_realease_resource()
+ */
+
+void tm6000_remove_from_devlist(struct tm6000_core *dev)
+{
+       mutex_lock(&tm6000_devlist_mutex);
+       list_del(&dev->devlist);
+       mutex_unlock(&tm6000_devlist_mutex);
+};
+
+void tm6000_add_into_devlist(struct tm6000_core *dev)
+{
+       mutex_lock(&tm6000_devlist_mutex);
+       list_add_tail(&dev->devlist, &tm6000_devlist);
+       mutex_unlock(&tm6000_devlist_mutex);
+};
+
+/*
+ * Extension interface
+ */
+
+static LIST_HEAD(tm6000_extension_devlist);
+
+int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
+                       char *buf, int size)
+{
+       struct tm6000_ops *ops = NULL;
+
+       /* FIXME: tm6000_extension_devlist_lock should be a spinlock */
+
+       if (!list_empty(&tm6000_extension_devlist)) {
+               list_for_each_entry(ops, &tm6000_extension_devlist, next) {
+                       if (ops->fillbuf && ops->type == type)
+                               ops->fillbuf(dev, buf, size);
+               }
+       }
+
+       return 0;
+}
+
+int tm6000_register_extension(struct tm6000_ops *ops)
+{
+       struct tm6000_core *dev = NULL;
+
+       mutex_lock(&tm6000_devlist_mutex);
+       list_add_tail(&ops->next, &tm6000_extension_devlist);
+       list_for_each_entry(dev, &tm6000_devlist, devlist) {
+               ops->init(dev);
+               printk(KERN_INFO "%s: Initialized (%s) extension\n",
+                      dev->name, ops->name);
+       }
+       mutex_unlock(&tm6000_devlist_mutex);
+       return 0;
+}
+EXPORT_SYMBOL(tm6000_register_extension);
+
+void tm6000_unregister_extension(struct tm6000_ops *ops)
+{
+       struct tm6000_core *dev = NULL;
+
+       mutex_lock(&tm6000_devlist_mutex);
+       list_for_each_entry(dev, &tm6000_devlist, devlist)
+               ops->fini(dev);
+
+       printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name);
+       list_del(&ops->next);
+       mutex_unlock(&tm6000_devlist_mutex);
+}
+EXPORT_SYMBOL(tm6000_unregister_extension);
+
+void tm6000_init_extension(struct tm6000_core *dev)
+{
+       struct tm6000_ops *ops = NULL;
+
+       mutex_lock(&tm6000_devlist_mutex);
+       if (!list_empty(&tm6000_extension_devlist)) {
+               list_for_each_entry(ops, &tm6000_extension_devlist, next) {
+                       if (ops->init)
+                               ops->init(dev);
+               }
+       }
+       mutex_unlock(&tm6000_devlist_mutex);
+}
+
+void tm6000_close_extension(struct tm6000_core *dev)
+{
+       struct tm6000_ops *ops = NULL;
+
+       mutex_lock(&tm6000_devlist_mutex);
+       if (!list_empty(&tm6000_extension_devlist)) {
+               list_for_each_entry(ops, &tm6000_extension_devlist, next) {
+                       if (ops->fini)
+                               ops->fini(dev);
+               }
+       }
+       mutex_unlock(&tm6000_devlist_mutex);
+}
diff --git a/drivers/media/video/tm6000/tm6000-dvb.c b/drivers/media/video/tm6000/tm6000-dvb.c
new file mode 100644 (file)
index 0000000..5e6c129
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ *  tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation version 2
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+#include "zl10353.h"
+
+#include <media/tuner.h>
+
+#include "tuner-xc2028.h"
+#include "xc5000.h"
+
+MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_SUPPORTED_DEVICE("{{Trident, tm5600},"
+                       "{{Trident, tm6000},"
+                       "{{Trident, tm6010}");
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug message");
+
+static inline void print_err_status(struct tm6000_core *dev,
+                                   int packet, int status)
+{
+       char *errmsg = "Unknown";
+
+       switch (status) {
+       case -ENOENT:
+               errmsg = "unlinked synchronuously";
+               break;
+       case -ECONNRESET:
+               errmsg = "unlinked asynchronuously";
+               break;
+       case -ENOSR:
+               errmsg = "Buffer error (overrun)";
+               break;
+       case -EPIPE:
+               errmsg = "Stalled (device not responding)";
+               break;
+       case -EOVERFLOW:
+               errmsg = "Babble (bad cable?)";
+               break;
+       case -EPROTO:
+               errmsg = "Bit-stuff error (bad cable?)";
+               break;
+       case -EILSEQ:
+               errmsg = "CRC/Timeout (could be anything)";
+               break;
+       case -ETIME:
+               errmsg = "Device does not respond";
+               break;
+       }
+       if (packet < 0) {
+               dprintk(dev, 1, "URB status %d [%s].\n",
+                       status, errmsg);
+       } else {
+               dprintk(dev, 1, "URB packet %d, status %d [%s].\n",
+                       packet, status, errmsg);
+       }
+}
+
+static void tm6000_urb_received(struct urb *urb)
+{
+       int ret;
+       struct tm6000_core *dev = urb->context;
+
+       if (urb->status != 0)
+               print_err_status(dev, 0, urb->status);
+       else if (urb->actual_length > 0)
+               dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
+                                                  urb->actual_length);
+
+       if (dev->dvb->streams > 0) {
+               ret = usb_submit_urb(urb, GFP_ATOMIC);
+               if (ret < 0) {
+                       printk(KERN_ERR "tm6000:  error %s\n", __func__);
+                       kfree(urb->transfer_buffer);
+                       usb_free_urb(urb);
+               }
+       }
+}
+
+static int tm6000_start_stream(struct tm6000_core *dev)
+{
+       int ret;
+       unsigned int pipe, size;
+       struct tm6000_dvb *dvb = dev->dvb;
+
+       printk(KERN_INFO "tm6000: got start stream request %s\n", __func__);
+
+       if (dev->mode != TM6000_MODE_DIGITAL) {
+               tm6000_init_digital_mode(dev);
+               dev->mode = TM6000_MODE_DIGITAL;
+       }
+
+       dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (dvb->bulk_urb == NULL) {
+               printk(KERN_ERR "tm6000: couldn't allocate urb\n");
+               return -ENOMEM;
+       }
+
+       pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress
+                                                         & USB_ENDPOINT_NUMBER_MASK);
+
+       size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+       size = size * 15; /* 512 x 8 or 12 or 15 */
+
+       dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
+       if (dvb->bulk_urb->transfer_buffer == NULL) {
+               usb_free_urb(dvb->bulk_urb);
+               printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
+               return -ENOMEM;
+       }
+
+       usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
+                                                dvb->bulk_urb->transfer_buffer,
+                                                size,
+                                                tm6000_urb_received, dev);
+
+       ret = usb_clear_halt(dev->udev, pipe);
+       if (ret < 0) {
+               printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",
+                                                       ret, __func__);
+               return ret;
+       } else
+               printk(KERN_ERR "tm6000: pipe resetted\n");
+
+/*     mutex_lock(&tm6000_driver.open_close_mutex); */
+       ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
+
+/*     mutex_unlock(&tm6000_driver.open_close_mutex); */
+       if (ret) {
+               printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",
+                                                                       ret);
+
+               kfree(dvb->bulk_urb->transfer_buffer);
+               usb_free_urb(dvb->bulk_urb);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void tm6000_stop_stream(struct tm6000_core *dev)
+{
+       struct tm6000_dvb *dvb = dev->dvb;
+
+       if (dvb->bulk_urb) {
+               printk(KERN_INFO "urb killing\n");
+               usb_kill_urb(dvb->bulk_urb);
+               printk(KERN_INFO "urb buffer free\n");
+               kfree(dvb->bulk_urb->transfer_buffer);
+               usb_free_urb(dvb->bulk_urb);
+               dvb->bulk_urb = NULL;
+       }
+}
+
+static int tm6000_start_feed(struct dvb_demux_feed *feed)
+{
+       struct dvb_demux *demux = feed->demux;
+       struct tm6000_core *dev = demux->priv;
+       struct tm6000_dvb *dvb = dev->dvb;
+       printk(KERN_INFO "tm6000: got start feed request %s\n", __func__);
+
+       mutex_lock(&dvb->mutex);
+       if (dvb->streams == 0) {
+               dvb->streams = 1;
+/*             mutex_init(&tm6000_dev->streming_mutex); */
+               tm6000_start_stream(dev);
+       } else
+               ++(dvb->streams);
+       mutex_unlock(&dvb->mutex);
+
+       return 0;
+}
+
+static int tm6000_stop_feed(struct dvb_demux_feed *feed)
+{
+       struct dvb_demux *demux = feed->demux;
+       struct tm6000_core *dev = demux->priv;
+       struct tm6000_dvb *dvb = dev->dvb;
+
+       printk(KERN_INFO "tm6000: got stop feed request %s\n", __func__);
+
+       mutex_lock(&dvb->mutex);
+
+       printk(KERN_INFO "stream %#x\n", dvb->streams);
+       --(dvb->streams);
+       if (dvb->streams == 0) {
+               printk(KERN_INFO "stop stream\n");
+               tm6000_stop_stream(dev);
+/*             mutex_destroy(&tm6000_dev->streaming_mutex); */
+       }
+       mutex_unlock(&dvb->mutex);
+/*     mutex_destroy(&tm6000_dev->streaming_mutex); */
+
+       return 0;
+}
+
+static int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
+{
+       struct tm6000_dvb *dvb = dev->dvb;
+
+       if (dev->caps.has_zl10353) {
+               struct zl10353_config config = {
+                                    .demod_address = dev->demod_addr,
+                                    .no_tuner = 1,
+                                    .parallel_ts = 1,
+                                    .if2 = 45700,
+                                    .disable_i2c_gate_ctrl = 1,
+                                   };
+
+               dvb->frontend = dvb_attach(zl10353_attach, &config,
+                                                          &dev->i2c_adap);
+       } else {
+               printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
+               return -1;
+       }
+
+       return (!dvb->frontend) ? -1 : 0;
+}
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int register_dvb(struct tm6000_core *dev)
+{
+       int ret = -1;
+       struct tm6000_dvb *dvb = dev->dvb;
+
+       mutex_init(&dvb->mutex);
+
+       dvb->streams = 0;
+
+       /* attach the frontend */
+       ret = tm6000_dvb_attach_frontend(dev);
+       if (ret < 0) {
+               printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
+               goto err;
+       }
+
+       ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
+                                       THIS_MODULE, &dev->udev->dev, adapter_nr);
+       dvb->adapter.priv = dev;
+
+       if (dvb->frontend) {
+               switch (dev->tuner_type) {
+               case TUNER_XC2028: {
+                       struct xc2028_config cfg = {
+                               .i2c_adap = &dev->i2c_adap,
+                               .i2c_addr = dev->tuner_addr,
+                       };
+
+                       dvb->frontend->callback = tm6000_tuner_callback;
+                       ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+                       if (ret < 0) {
+                               printk(KERN_ERR
+                                       "tm6000: couldn't register frontend\n");
+                               goto adapter_err;
+                       }
+
+                       if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) {
+                               printk(KERN_ERR "tm6000: couldn't register "
+                                               "frontend (xc3028)\n");
+                               ret = -EINVAL;
+                               goto frontend_err;
+                       }
+                       printk(KERN_INFO "tm6000: XC2028/3028 asked to be "
+                                        "attached to frontend!\n");
+                       break;
+                       }
+               case TUNER_XC5000: {
+                       struct xc5000_config cfg = {
+                               .i2c_address = dev->tuner_addr,
+                       };
+
+                       dvb->frontend->callback = tm6000_xc5000_callback;
+                       ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+                       if (ret < 0) {
+                               printk(KERN_ERR
+                                       "tm6000: couldn't register frontend\n");
+                               goto adapter_err;
+                       }
+
+                       if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) {
+                               printk(KERN_ERR "tm6000: couldn't register "
+                                               "frontend (xc5000)\n");
+                               ret = -EINVAL;
+                               goto frontend_err;
+                       }
+                       printk(KERN_INFO "tm6000: XC5000 asked to be "
+                                        "attached to frontend!\n");
+                       break;
+                       }
+               }
+       } else
+               printk(KERN_ERR "tm6000: no frontend found\n");
+
+       dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
+                                                           | DMX_MEMORY_BASED_FILTERING;
+       dvb->demux.priv = dev;
+       dvb->demux.filternum = 8;
+       dvb->demux.feednum = 8;
+       dvb->demux.start_feed = tm6000_start_feed;
+       dvb->demux.stop_feed = tm6000_stop_feed;
+       dvb->demux.write_to_decoder = NULL;
+       ret = dvb_dmx_init(&dvb->demux);
+       if (ret < 0) {
+               printk(KERN_ERR "tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
+               goto frontend_err;
+       }
+
+       dvb->dmxdev.filternum = dev->dvb->demux.filternum;
+       dvb->dmxdev.demux = &dev->dvb->demux.dmx;
+       dvb->dmxdev.capabilities = 0;
+
+       ret =  dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+       if (ret < 0) {
+               printk(KERN_ERR "tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
+               goto dvb_dmx_err;
+       }
+
+       return 0;
+
+dvb_dmx_err:
+       dvb_dmx_release(&dvb->demux);
+frontend_err:
+       if (dvb->frontend) {
+               dvb_frontend_detach(dvb->frontend);
+               dvb_unregister_frontend(dvb->frontend);
+       }
+adapter_err:
+       dvb_unregister_adapter(&dvb->adapter);
+err:
+       return ret;
+}
+
+static void unregister_dvb(struct tm6000_core *dev)
+{
+       struct tm6000_dvb *dvb = dev->dvb;
+
+       if (dvb->bulk_urb != NULL) {
+               struct urb *bulk_urb = dvb->bulk_urb;
+
+               kfree(bulk_urb->transfer_buffer);
+               bulk_urb->transfer_buffer = NULL;
+               usb_unlink_urb(bulk_urb);
+               usb_free_urb(bulk_urb);
+       }
+
+/*     mutex_lock(&tm6000_driver.open_close_mutex); */
+       if (dvb->frontend) {
+               dvb_frontend_detach(dvb->frontend);
+               dvb_unregister_frontend(dvb->frontend);
+       }
+
+       dvb_dmxdev_release(&dvb->dmxdev);
+       dvb_dmx_release(&dvb->demux);
+       dvb_unregister_adapter(&dvb->adapter);
+       mutex_destroy(&dvb->mutex);
+/*     mutex_unlock(&tm6000_driver.open_close_mutex); */
+}
+
+static int dvb_init(struct tm6000_core *dev)
+{
+       struct tm6000_dvb *dvb;
+       int rc;
+
+       if (!dev)
+               return 0;
+
+       if (!dev->caps.has_dvb)
+               return 0;
+
+       dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL);
+       if (!dvb) {
+               printk(KERN_INFO "Cannot allocate memory\n");
+               return -ENOMEM;
+       }
+
+       dev->dvb = dvb;
+
+       rc = register_dvb(dev);
+       if (rc < 0) {
+               kfree(dvb);
+               dev->dvb = NULL;
+               return 0;
+       }
+
+       return 0;
+}
+
+static int dvb_fini(struct tm6000_core *dev)
+{
+       if (!dev)
+               return 0;
+
+       if (!dev->caps.has_dvb)
+               return 0;
+
+       if (dev->dvb) {
+               unregister_dvb(dev);
+               kfree(dev->dvb);
+               dev->dvb = NULL;
+       }
+
+       return 0;
+}
+
+static struct tm6000_ops dvb_ops = {
+       .type   = TM6000_DVB,
+       .name   = "TM6000 dvb Extension",
+       .init   = dvb_init,
+       .fini   = dvb_fini,
+};
+
+static int __init tm6000_dvb_register(void)
+{
+       return tm6000_register_extension(&dvb_ops);
+}
+
+static void __exit tm6000_dvb_unregister(void)
+{
+       tm6000_unregister_extension(&dvb_ops);
+}
+
+module_init(tm6000_dvb_register);
+module_exit(tm6000_dvb_unregister);
diff --git a/drivers/media/video/tm6000/tm6000-i2c.c b/drivers/media/video/tm6000/tm6000-i2c.c
new file mode 100644 (file)
index 0000000..0290bbf
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ *  tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ *     - Fix SMBus Read Byte command
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation version 2
+ *
+ *  This program is distributed 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/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include "tuner-xc2028.h"
+
+
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_debug;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \
+                       printk(KERN_DEBUG "%s at %s: " fmt, \
+                       dev->name, __func__, ##args); } while (0)
+
+static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr,
+                               __u8 reg, char *buf, int len)
+{
+       int rc;
+       unsigned int tsleep;
+       unsigned int i2c_packet_limit = 16;
+
+       if (dev->dev_type == TM6010)
+               i2c_packet_limit = 64;
+
+       if (!buf)
+               return -1;
+
+       if (len < 1 || len > i2c_packet_limit) {
+               printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
+                       len, i2c_packet_limit);
+               return -1;
+       }
+
+       /* capture mutex */
+       rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+               USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
+               addr | reg << 8, 0, buf, len);
+
+       if (rc < 0) {
+               /* release mutex */
+               return rc;
+       }
+
+       /* Calculate delay time, 14000us for 64 bytes */
+       tsleep = ((len * 200) + 200 + 1000) / 1000;
+       msleep(tsleep);
+
+       /* release mutex */
+       return rc;
+}
+
+/* Generic read - doesn't work fine with 16bit registers */
+static int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr,
+                               __u8 reg, char *buf, int len)
+{
+       int rc;
+       u8 b[2];
+       unsigned int i2c_packet_limit = 16;
+
+       if (dev->dev_type == TM6010)
+               i2c_packet_limit = 64;
+
+       if (!buf)
+               return -1;
+
+       if (len < 1 || len > i2c_packet_limit) {
+               printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
+                       len, i2c_packet_limit);
+               return -1;
+       }
+
+       /* capture mutex */
+       if ((dev->caps.has_zl10353) && (dev->demod_addr << 1 == addr) && (reg % 2 == 0)) {
+               /*
+                * Workaround an I2C bug when reading from zl10353
+                */
+               reg -= 1;
+               len += 1;
+
+               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, b, len);
+
+               *buf = b[1];
+       } else {
+               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, buf, len);
+       }
+
+       /* release mutex */
+       return rc;
+}
+
+/*
+ * read from a 16bit register
+ * for example xc2028, xc3028 or xc3028L
+ */
+static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr,
+                                 __u16 reg, char *buf, int len)
+{
+       int rc;
+       unsigned char ureg;
+
+       if (!buf || len != 2)
+               return -1;
+
+       /* capture mutex */
+       if (dev->dev_type == TM6010) {
+               ureg = reg & 0xFF;
+               rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+                       USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
+                       addr | (reg & 0xFF00), 0, &ureg, 1);
+
+               if (rc < 0) {
+                       /* release mutex */
+                       return rc;
+               }
+
+               msleep(1400 / 1000);
+               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
+                       USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ,
+                       reg, 0, buf, len);
+       } else {
+               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
+                       USB_RECIP_DEVICE, REQ_14_SET_GET_I2C_WR2_RDN,
+                       addr, reg, buf, len);
+       }
+
+       /* release mutex */
+       return rc;
+}
+
+static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
+                          struct i2c_msg msgs[], int num)
+{
+       struct tm6000_core *dev = i2c_adap->algo_data;
+       int addr, rc, i, byte;
+
+       if (num <= 0)
+               return 0;
+       for (i = 0; i < num; i++) {
+               addr = (msgs[i].addr << 1) & 0xff;
+               i2c_dprintk(2, "%s %s addr=0x%x len=%d:",
+                        (msgs[i].flags & I2C_M_RD) ? "read" : "write",
+                        i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
+               if (msgs[i].flags & I2C_M_RD) {
+                       /* read request without preceding register selection */
+                       /*
+                        * The TM6000 only supports a read transaction
+                        * immediately after a 1 or 2 byte write to select
+                        * a register.  We cannot fulfil this request.
+                        */
+                       i2c_dprintk(2, " read without preceding write not"
+                                      " supported");
+                       rc = -EOPNOTSUPP;
+                       goto err;
+               } else if (i + 1 < num && msgs[i].len <= 2 &&
+                          (msgs[i + 1].flags & I2C_M_RD) &&
+                          msgs[i].addr == msgs[i + 1].addr) {
+                       /* 1 or 2 byte write followed by a read */
+                       if (i2c_debug >= 2)
+                               for (byte = 0; byte < msgs[i].len; byte++)
+                                       printk(KERN_CONT " %02x", msgs[i].buf[byte]);
+                       i2c_dprintk(2, "; joined to read %s len=%d:",
+                                   i == num - 2 ? "stop" : "nonstop",
+                                   msgs[i + 1].len);
+
+                       if (msgs[i].len == 2) {
+                               rc = tm6000_i2c_recv_regs16(dev, addr,
+                                       msgs[i].buf[0] << 8 | msgs[i].buf[1],
+                                       msgs[i + 1].buf, msgs[i + 1].len);
+                       } else {
+                               rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0],
+                                       msgs[i + 1].buf, msgs[i + 1].len);
+                       }
+
+                       i++;
+
+                       if (addr == dev->tuner_addr << 1) {
+                               tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
+                               tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
+                       }
+                       if (i2c_debug >= 2)
+                               for (byte = 0; byte < msgs[i].len; byte++)
+                                       printk(KERN_CONT " %02x", msgs[i].buf[byte]);
+               } else {
+                       /* write bytes */
+                       if (i2c_debug >= 2)
+                               for (byte = 0; byte < msgs[i].len; byte++)
+                                       printk(KERN_CONT " %02x", msgs[i].buf[byte]);
+                       rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0],
+                               msgs[i].buf + 1, msgs[i].len - 1);
+               }
+               if (i2c_debug >= 2)
+                       printk(KERN_CONT "\n");
+               if (rc < 0)
+                       goto err;
+       }
+
+       return num;
+err:
+       i2c_dprintk(2, " ERROR: %i\n", rc);
+       return rc;
+}
+
+static int tm6000_i2c_eeprom(struct tm6000_core *dev)
+{
+       int i, rc;
+       unsigned char *p = dev->eedata;
+       unsigned char bytes[17];
+
+       dev->i2c_client.addr = 0xa0 >> 1;
+       dev->eedata_size = 0;
+
+       bytes[16] = '\0';
+       for (i = 0; i < sizeof(dev->eedata); ) {
+               *p = i;
+               rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1);
+               if (rc < 1) {
+                       if (p == dev->eedata)
+                               goto noeeprom;
+                       else {
+                               printk(KERN_WARNING
+                               "%s: i2c eeprom read error (err=%d)\n",
+                               dev->name, rc);
+                       }
+                       return -EINVAL;
+               }
+               dev->eedata_size++;
+               p++;
+               if (0 == (i % 16))
+                       printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
+               printk(KERN_CONT " %02x", dev->eedata[i]);
+               if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z'))
+                       bytes[i%16] = dev->eedata[i];
+               else
+                       bytes[i%16] = '.';
+
+               i++;
+
+               if (0 == (i % 16)) {
+                       bytes[16] = '\0';
+                       printk(KERN_CONT "  %s\n", bytes);
+               }
+       }
+       if (0 != (i%16)) {
+               bytes[i%16] = '\0';
+               for (i %= 16; i < 16; i++)
+                       printk(KERN_CONT "   ");
+               printk(KERN_CONT "  %s\n", bytes);
+       }
+
+       return 0;
+
+noeeprom:
+       printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
+              dev->name, rc);
+       return -EINVAL;
+}
+
+/* ----------------------------------------------------------- */
+
+/*
+ * functionality()
+ */
+static u32 functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm tm6000_algo = {
+       .master_xfer   = tm6000_i2c_xfer,
+       .functionality = functionality,
+};
+
+/* ----------------------------------------------------------- */
+
+/*
+ * tm6000_i2c_register()
+ * register i2c bus
+ */
+int tm6000_i2c_register(struct tm6000_core *dev)
+{
+       int rc;
+
+       dev->i2c_adap.owner = THIS_MODULE;
+       dev->i2c_adap.algo = &tm6000_algo;
+       dev->i2c_adap.dev.parent = &dev->udev->dev;
+       strlcpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name));
+       dev->i2c_adap.algo_data = dev;
+       i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+       rc = i2c_add_adapter(&dev->i2c_adap);
+       if (rc)
+               return rc;
+
+       dev->i2c_client.adapter = &dev->i2c_adap;
+       strlcpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE);
+       tm6000_i2c_eeprom(dev);
+
+       return 0;
+}
+
+/*
+ * tm6000_i2c_unregister()
+ * unregister i2c_bus
+ */
+int tm6000_i2c_unregister(struct tm6000_core *dev)
+{
+       i2c_del_adapter(&dev->i2c_adap);
+       return 0;
+}
diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c
new file mode 100644 (file)
index 0000000..405d127
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ *  tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ *  Copyright (C) 2010 Stefan Ringel <stefan.ringel@arcor.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation version 2
+ *
+ *  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/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include <media/rc-core.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+static unsigned int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debug message [IR]");
+
+static unsigned int enable_ir = 1;
+module_param(enable_ir, int, 0644);
+MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
+
+/* number of 50ms for ON-OFF-ON power led */
+/* show IR activity */
+#define PWLED_OFF 2
+
+#undef dprintk
+
+#define dprintk(fmt, arg...) \
+       if (ir_debug) { \
+               printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
+       }
+
+struct tm6000_ir_poll_result {
+       u16 rc_data;
+};
+
+struct tm6000_IR {
+       struct tm6000_core      *dev;
+       struct rc_dev           *rc;
+       char                    name[32];
+       char                    phys[32];
+
+       /* poll expernal decoder */
+       int                     polling;
+       struct delayed_work     work;
+       u8                      wait:1;
+       u8                      key:1;
+       u8                      pwled:1;
+       u8                      pwledcnt;
+       u16                     key_addr;
+       struct urb              *int_urb;
+       u8                      *urb_data;
+
+       int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *);
+
+       /* IR device properties */
+       u64                     rc_type;
+};
+
+
+void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
+{
+       struct tm6000_IR *ir = dev->ir;
+
+       if (!dev->ir)
+               return;
+
+       if (state)
+               ir->wait = 1;
+       else
+               ir->wait = 0;
+}
+
+
+static int tm6000_ir_config(struct tm6000_IR *ir)
+{
+       struct tm6000_core *dev = ir->dev;
+       u8 buf[10];
+       int rc;
+
+       switch (ir->rc_type) {
+       case RC_TYPE_NEC:
+               /* Setup IR decoder for NEC standard 12MHz system clock */
+               /* IR_LEADER_CNT = 0.9ms             */
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa);
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30);
+               /* IR_PULSE_CNT = 0.7ms              */
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20);
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0);
+               /* Remote WAKEUP = enable */
+               tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe);
+               /* IR_WKUP_SEL = Low byte in decoded IR data */
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff);
+               /* IR_WKU_ADD code */
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff);
+               tm6000_flash_led(dev, 0);
+               msleep(100);
+               tm6000_flash_led(dev, 1);
+               break;
+       default:
+               /* hack */
+               buf[0] = 0xff;
+               buf[1] = 0xff;
+               buf[2] = 0xf2;
+               buf[3] = 0x2b;
+               buf[4] = 0x20;
+               buf[5] = 0x35;
+               buf[6] = 0x60;
+               buf[7] = 0x04;
+               buf[8] = 0xc0;
+               buf[9] = 0x08;
+
+               rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+                       USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
+               msleep(100);
+
+               if (rc < 0) {
+                       printk(KERN_INFO "IR configuration failed");
+                       return rc;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static void tm6000_ir_urb_received(struct urb *urb)
+{
+       struct tm6000_core *dev = urb->context;
+       struct tm6000_IR *ir = dev->ir;
+       int rc;
+
+       if (urb->status != 0)
+               printk(KERN_INFO "not ready\n");
+       else if (urb->actual_length > 0) {
+               memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length);
+
+               dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0],
+                       ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]);
+
+               ir->key = 1;
+       }
+
+       rc = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int default_polling_getkey(struct tm6000_IR *ir,
+                               struct tm6000_ir_poll_result *poll_result)
+{
+       struct tm6000_core *dev = ir->dev;
+       int rc;
+       u8 buf[2];
+
+       if (ir->wait && !&dev->int_in)
+               return 0;
+
+       if (&dev->int_in) {
+               switch (ir->rc_type) {
+               case RC_TYPE_RC5:
+                       poll_result->rc_data = ir->urb_data[0];
+                       break;
+               case RC_TYPE_NEC:
+                       if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) {
+                               poll_result->rc_data = ir->urb_data[0]
+                                                       | ir->urb_data[1] << 8;
+                       }
+                       break;
+               default:
+                       poll_result->rc_data = ir->urb_data[0]
+                                       | ir->urb_data[1] << 8;
+                       break;
+               }
+       } else {
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
+               msleep(10);
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
+               msleep(10);
+
+               if (ir->rc_type == RC_TYPE_RC5) {
+                       rc = tm6000_read_write_usb(dev, USB_DIR_IN |
+                               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               REQ_02_GET_IR_CODE, 0, 0, buf, 1);
+
+                       msleep(10);
+
+                       dprintk("read data=%02x\n", buf[0]);
+                       if (rc < 0)
+                               return rc;
+
+                       poll_result->rc_data = buf[0];
+               } else {
+                       rc = tm6000_read_write_usb(dev, USB_DIR_IN |
+                               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               REQ_02_GET_IR_CODE, 0, 0, buf, 2);
+
+                       msleep(10);
+
+                       dprintk("read data=%04x\n", buf[0] | buf[1] << 8);
+                       if (rc < 0)
+                               return rc;
+
+                       poll_result->rc_data = buf[0] | buf[1] << 8;
+               }
+               if ((poll_result->rc_data & 0x00ff) != 0xff)
+                       ir->key = 1;
+       }
+       return 0;
+}
+
+static void tm6000_ir_handle_key(struct tm6000_IR *ir)
+{
+       struct tm6000_core *dev = ir->dev;
+       int result;
+       struct tm6000_ir_poll_result poll_result;
+
+       /* read the registers containing the IR status */
+       result = ir->get_key(ir, &poll_result);
+       if (result < 0) {
+               printk(KERN_INFO "ir->get_key() failed %d\n", result);
+               return;
+       }
+
+       dprintk("ir->get_key result data=%04x\n", poll_result.rc_data);
+
+       if (ir->pwled) {
+               if (ir->pwledcnt >= PWLED_OFF) {
+                       ir->pwled = 0;
+                       ir->pwledcnt = 0;
+                       tm6000_flash_led(dev, 1);
+               } else
+                       ir->pwledcnt += 1;
+       }
+
+       if (ir->key) {
+               rc_keydown(ir->rc, poll_result.rc_data, 0);
+               ir->key = 0;
+               ir->pwled = 1;
+               ir->pwledcnt = 0;
+               tm6000_flash_led(dev, 0);
+       }
+       return;
+}
+
+static void tm6000_ir_work(struct work_struct *work)
+{
+       struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
+
+       tm6000_ir_handle_key(ir);
+       schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+}
+
+static int tm6000_ir_start(struct rc_dev *rc)
+{
+       struct tm6000_IR *ir = rc->priv;
+
+       INIT_DELAYED_WORK(&ir->work, tm6000_ir_work);
+       schedule_delayed_work(&ir->work, 0);
+
+       return 0;
+}
+
+static void tm6000_ir_stop(struct rc_dev *rc)
+{
+       struct tm6000_IR *ir = rc->priv;
+
+       cancel_delayed_work_sync(&ir->work);
+}
+
+static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
+{
+       struct tm6000_IR *ir = rc->priv;
+
+       if (!ir)
+               return 0;
+
+       if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC))
+               ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff);
+
+       ir->get_key = default_polling_getkey;
+       ir->rc_type = rc_type;
+
+       tm6000_ir_config(ir);
+       /* TODO */
+       return 0;
+}
+
+int tm6000_ir_int_start(struct tm6000_core *dev)
+{
+       struct tm6000_IR *ir = dev->ir;
+       int pipe, size;
+       int err = -ENOMEM;
+
+
+       if (!ir)
+               return -ENODEV;
+
+       ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!ir->int_urb)
+               return -ENOMEM;
+
+       pipe = usb_rcvintpipe(dev->udev,
+               dev->int_in.endp->desc.bEndpointAddress
+               & USB_ENDPOINT_NUMBER_MASK);
+
+       size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+       dprintk("IR max size: %d\n", size);
+
+       ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
+       if (ir->int_urb->transfer_buffer == NULL) {
+               usb_free_urb(ir->int_urb);
+               return err;
+       }
+       dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
+       usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
+               ir->int_urb->transfer_buffer, size,
+               tm6000_ir_urb_received, dev,
+               dev->int_in.endp->desc.bInterval);
+       err = usb_submit_urb(ir->int_urb, GFP_KERNEL);
+       if (err) {
+               kfree(ir->int_urb->transfer_buffer);
+               usb_free_urb(ir->int_urb);
+               return err;
+       }
+       ir->urb_data = kzalloc(size, GFP_KERNEL);
+
+       return 0;
+}
+
+void tm6000_ir_int_stop(struct tm6000_core *dev)
+{
+       struct tm6000_IR *ir = dev->ir;
+
+       if (!ir)
+               return;
+
+       usb_kill_urb(ir->int_urb);
+       kfree(ir->int_urb->transfer_buffer);
+       usb_free_urb(ir->int_urb);
+       ir->int_urb = NULL;
+       kfree(ir->urb_data);
+       ir->urb_data = NULL;
+}
+
+int tm6000_ir_init(struct tm6000_core *dev)
+{
+       struct tm6000_IR *ir;
+       struct rc_dev *rc;
+       int err = -ENOMEM;
+
+       if (!enable_ir)
+               return -ENODEV;
+
+       if (!dev->caps.has_remote)
+               return 0;
+
+       if (!dev->ir_codes)
+               return 0;
+
+       ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+       rc = rc_allocate_device();
+       if (!ir || !rc)
+               goto out;
+
+       /* record handles to ourself */
+       ir->dev = dev;
+       dev->ir = ir;
+       ir->rc = rc;
+
+       /* input einrichten */
+       rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC;
+       rc->priv = ir;
+       rc->change_protocol = tm6000_ir_change_protocol;
+       rc->open = tm6000_ir_start;
+       rc->close = tm6000_ir_stop;
+       rc->driver_type = RC_DRIVER_SCANCODE;
+
+       ir->polling = 50;
+       ir->pwled = 0;
+       ir->pwledcnt = 0;
+
+
+       snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
+                                               dev->name);
+
+       usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
+       strlcat(ir->phys, "/input0", sizeof(ir->phys));
+
+       tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN);
+
+       rc->input_name = ir->name;
+       rc->input_phys = ir->phys;
+       rc->input_id.bustype = BUS_USB;
+       rc->input_id.version = 1;
+       rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+       rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+       rc->map_name = dev->ir_codes;
+       rc->driver_name = "tm6000";
+       rc->dev.parent = &dev->udev->dev;
+
+       if (&dev->int_in) {
+               dprintk("IR over int\n");
+
+               err = tm6000_ir_int_start(dev);
+
+               if (err)
+                       goto out;
+       }
+
+       /* ir register */
+       err = rc_register_device(rc);
+       if (err)
+               goto out;
+
+       return 0;
+
+out:
+       dev->ir = NULL;
+       rc_free_device(rc);
+       kfree(ir);
+       return err;
+}
+
+int tm6000_ir_fini(struct tm6000_core *dev)
+{
+       struct tm6000_IR *ir = dev->ir;
+
+       /* skip detach on non attached board */
+
+       if (!ir)
+               return 0;
+
+       rc_unregister_device(ir->rc);
+
+       if (ir->int_urb)
+               tm6000_ir_int_stop(dev);
+
+       kfree(ir);
+       dev->ir = NULL;
+
+       return 0;
+}
diff --git a/drivers/media/video/tm6000/tm6000-regs.h b/drivers/media/video/tm6000/tm6000-regs.h
new file mode 100644 (file)
index 0000000..7f491b6
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ *  tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.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 version 2
+ *
+ *  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.
+ */
+
+/*
+ * Define TV Master TM5600/TM6000/TM6010 Request codes
+ */
+#define REQ_00_SET_IR_VALUE            0
+#define REQ_01_SET_WAKEUP_IRCODE       1
+#define REQ_02_GET_IR_CODE             2
+#define REQ_03_SET_GET_MCU_PIN         3
+#define REQ_04_EN_DISABLE_MCU_INT      4
+#define REQ_05_SET_GET_USBREG          5
+       /* Write: RegNum, Value, 0 */
+       /* Read : RegNum, Value, 1, RegStatus */
+#define REQ_06_SET_GET_USBREG_BIT      6
+#define REQ_07_SET_GET_AVREG           7
+       /* Write: RegNum, Value, 0 */
+       /* Read : RegNum, Value, 1, RegStatus */
+#define REQ_08_SET_GET_AVREG_BIT       8
+#define REQ_09_SET_GET_TUNER_FQ                9
+#define REQ_10_SET_TUNER_SYSTEM                10
+#define REQ_11_SET_EEPROM_ADDR         11
+#define REQ_12_SET_GET_EEPROMBYTE      12
+#define REQ_13_GET_EEPROM_SEQREAD      13
+#define REQ_14_SET_GET_I2C_WR2_RDN     14
+#define REQ_15_SET_GET_I2CBYTE         15
+       /* Write: Subaddr, Slave Addr, value, 0 */
+       /* Read : Subaddr, Slave Addr, value, 1 */
+#define REQ_16_SET_GET_I2C_WR1_RDN     16
+       /* Subaddr, Slave Addr, 0, length */
+#define REQ_17_SET_GET_I2CFP           17
+       /* Write: Slave Addr, register, value */
+       /* Read : Slave Addr, register, 2, data */
+#define REQ_20_DATA_TRANSFER           20
+#define REQ_30_I2C_WRITE               30
+#define REQ_31_I2C_READ                        31
+#define REQ_35_AFTEK_TUNER_READ                35
+#define REQ_40_GET_VERSION             40
+#define REQ_50_SET_START               50
+#define REQ_51_SET_STOP                        51
+#define REQ_52_TRANSMIT_DATA           52
+#define REQ_53_SPI_INITIAL             53
+#define REQ_54_SPI_SETSTART            54
+#define REQ_55_SPI_INOUTDATA           55
+#define REQ_56_SPI_SETSTOP             56
+
+/*
+ * Define TV Master TM5600/TM6000/TM6010 GPIO lines
+ */
+
+#define TM6000_GPIO_CLK                0x101
+#define TM6000_GPIO_DATA       0x100
+
+#define TM6000_GPIO_1          0x102
+#define TM6000_GPIO_2          0x103
+#define TM6000_GPIO_3          0x104
+#define TM6000_GPIO_4          0x300
+#define TM6000_GPIO_5          0x301
+#define TM6000_GPIO_6          0x304
+#define TM6000_GPIO_7          0x305
+
+/* tm6010 defines GPIO with different values */
+#define TM6010_GPIO_0      0x0102
+#define TM6010_GPIO_1      0x0103
+#define TM6010_GPIO_2      0x0104
+#define TM6010_GPIO_3      0x0105
+#define TM6010_GPIO_4      0x0106
+#define TM6010_GPIO_5      0x0107
+#define TM6010_GPIO_6      0x0300
+#define TM6010_GPIO_7      0x0301
+#define TM6010_GPIO_9      0x0305
+/*
+ * Define TV Master TM5600/TM6000/TM6010 URB message codes and length
+ */
+
+enum {
+       TM6000_URB_MSG_VIDEO = 1,
+       TM6000_URB_MSG_AUDIO,
+       TM6000_URB_MSG_VBI,
+       TM6000_URB_MSG_PTS,
+       TM6000_URB_MSG_ERR,
+};
+
+/* Define specific TM6000 Video decoder registers */
+#define TM6000_REQ07_RD8_TEST_SEL                      0x07, 0xd8
+#define TM6000_REQ07_RD9_A_SIM_SEL                     0x07, 0xd9
+#define TM6000_REQ07_RDA_CLK_SEL                       0x07, 0xda
+#define TM6000_REQ07_RDB_OUT_SEL                       0x07, 0xdb
+#define TM6000_REQ07_RDC_NSEL_I2S                      0x07, 0xdc
+#define TM6000_REQ07_RDD_GPIO2_MDRV                    0x07, 0xdd
+#define TM6000_REQ07_RDE_GPIO1_MDRV                    0x07, 0xde
+#define TM6000_REQ07_RDF_PWDOWN_ACLK                   0x07, 0xdf
+#define TM6000_REQ07_RE0_VADC_REF_CTL                  0x07, 0xe0
+#define TM6000_REQ07_RE1_VADC_DACLIMP                  0x07, 0xe1
+#define TM6000_REQ07_RE2_VADC_STATUS_CTL               0x07, 0xe2
+#define TM6000_REQ07_RE3_VADC_INP_LPF_SEL1             0x07, 0xe3
+#define TM6000_REQ07_RE4_VADC_TARGET1                  0x07, 0xe4
+#define TM6000_REQ07_RE5_VADC_INP_LPF_SEL2             0x07, 0xe5
+#define TM6000_REQ07_RE6_VADC_TARGET2                  0x07, 0xe6
+#define TM6000_REQ07_RE7_VADC_AGAIN_CTL                        0x07, 0xe7
+#define TM6000_REQ07_RE8_VADC_PWDOWN_CTL               0x07, 0xe8
+#define TM6000_REQ07_RE9_VADC_INPUT_CTL1               0x07, 0xe9
+#define TM6000_REQ07_REA_VADC_INPUT_CTL2               0x07, 0xea
+#define TM6000_REQ07_REB_VADC_AADC_MODE                        0x07, 0xeb
+#define TM6000_REQ07_REC_VADC_AADC_LVOL                        0x07, 0xec
+#define TM6000_REQ07_RED_VADC_AADC_RVOL                        0x07, 0xed
+#define TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL         0x07, 0xee
+#define TM6000_REQ07_REF_VADC_GAIN_MAP_CTL             0x07, 0xef
+#define TM6000_REQ07_RFD_BIST_ERR_VST_LOW              0x07, 0xfd
+#define TM6000_REQ07_RFE_BIST_ERR_VST_HIGH             0x07, 0xfe
+
+/* Define TM6000/TM6010 Video decoder registers */
+#define TM6010_REQ07_R00_VIDEO_CONTROL0                        0x07, 0x00
+#define TM6010_REQ07_R01_VIDEO_CONTROL1                        0x07, 0x01
+#define TM6010_REQ07_R02_VIDEO_CONTROL2                        0x07, 0x02
+#define TM6010_REQ07_R03_YC_SEP_CONTROL                        0x07, 0x03
+#define TM6010_REQ07_R04_LUMA_HAGC_CONTROL             0x07, 0x04
+#define TM6010_REQ07_R05_NOISE_THRESHOLD               0x07, 0x05
+#define TM6010_REQ07_R06_AGC_GATE_THRESHOLD            0x07, 0x06
+#define TM6010_REQ07_R07_OUTPUT_CONTROL                        0x07, 0x07
+#define TM6010_REQ07_R08_LUMA_CONTRAST_ADJ             0x07, 0x08
+#define TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ           0x07, 0x09
+#define TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ         0x07, 0x0a
+#define TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ          0x07, 0x0b
+#define TM6010_REQ07_R0C_CHROMA_AGC_CONTROL            0x07, 0x0c
+#define TM6010_REQ07_R0D_CHROMA_KILL_LEVEL             0x07, 0x0d
+#define TM6010_REQ07_R0F_CHROMA_AUTO_POSITION          0x07, 0x0f
+#define TM6010_REQ07_R10_AGC_PEAK_NOMINAL              0x07, 0x10
+#define TM6010_REQ07_R11_AGC_PEAK_CONTROL              0x07, 0x11
+#define TM6010_REQ07_R12_AGC_GATE_STARTH               0x07, 0x12
+#define TM6010_REQ07_R13_AGC_GATE_STARTL               0x07, 0x13
+#define TM6010_REQ07_R14_AGC_GATE_WIDTH                        0x07, 0x14
+#define TM6010_REQ07_R15_AGC_BP_DELAY                  0x07, 0x15
+#define TM6010_REQ07_R16_LOCK_COUNT                    0x07, 0x16
+#define TM6010_REQ07_R17_HLOOP_MAXSTATE                        0x07, 0x17
+#define TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3         0x07, 0x18
+#define TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2         0x07, 0x19
+#define TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1         0x07, 0x1a
+#define TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0         0x07, 0x1b
+#define TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3          0x07, 0x1c
+#define TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2          0x07, 0x1d
+#define TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1          0x07, 0x1e
+#define TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0          0x07, 0x1f
+#define TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME                0x07, 0x20
+#define TM6010_REQ07_R21_HSYNC_PHASE_OFFSET            0x07, 0x21
+#define TM6010_REQ07_R22_HSYNC_PLL_START_TIME          0x07, 0x22
+#define TM6010_REQ07_R23_HSYNC_PLL_END_TIME            0x07, 0x23
+#define TM6010_REQ07_R24_HSYNC_TIP_START_TIME          0x07, 0x24
+#define TM6010_REQ07_R25_HSYNC_TIP_END_TIME            0x07, 0x25
+#define TM6010_REQ07_R26_HSYNC_RISING_EDGE_START       0x07, 0x26
+#define TM6010_REQ07_R27_HSYNC_RISING_EDGE_END         0x07, 0x27
+#define TM6010_REQ07_R28_BACKPORCH_START               0x07, 0x28
+#define TM6010_REQ07_R29_BACKPORCH_END                 0x07, 0x29
+#define TM6010_REQ07_R2A_HSYNC_FILTER_START            0x07, 0x2a
+#define TM6010_REQ07_R2B_HSYNC_FILTER_END              0x07, 0x2b
+#define TM6010_REQ07_R2C_CHROMA_BURST_START            0x07, 0x2c
+#define TM6010_REQ07_R2D_CHROMA_BURST_END              0x07, 0x2d
+#define TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART           0x07, 0x2e
+#define TM6010_REQ07_R2F_ACTIVE_VIDEO_HWIDTH           0x07, 0x2f
+#define TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART           0x07, 0x30
+#define TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT           0x07, 0x31
+#define TM6010_REQ07_R32_VSYNC_HLOCK_MIN               0x07, 0x32
+#define TM6010_REQ07_R33_VSYNC_HLOCK_MAX               0x07, 0x33
+#define TM6010_REQ07_R34_VSYNC_AGC_MIN                 0x07, 0x34
+#define TM6010_REQ07_R35_VSYNC_AGC_MAX                 0x07, 0x35
+#define TM6010_REQ07_R36_VSYNC_VBI_MIN                 0x07, 0x36
+#define TM6010_REQ07_R37_VSYNC_VBI_MAX                 0x07, 0x37
+#define TM6010_REQ07_R38_VSYNC_THRESHOLD               0x07, 0x38
+#define TM6010_REQ07_R39_VSYNC_TIME_CONSTANT           0x07, 0x39
+#define TM6010_REQ07_R3A_STATUS1                       0x07, 0x3a
+#define TM6010_REQ07_R3B_STATUS2                       0x07, 0x3b
+#define TM6010_REQ07_R3C_STATUS3                       0x07, 0x3c
+#define TM6010_REQ07_R3F_RESET                         0x07, 0x3f
+#define TM6010_REQ07_R40_TELETEXT_VBI_CODE0            0x07, 0x40
+#define TM6010_REQ07_R41_TELETEXT_VBI_CODE1            0x07, 0x41
+#define TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL           0x07, 0x42
+#define TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7           0x07, 0x43
+#define TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8           0x07, 0x44
+#define TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9           0x07, 0x45
+#define TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10          0x07, 0x46
+#define TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11          0x07, 0x47
+#define TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12          0x07, 0x48
+#define TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13          0x07, 0x49
+#define TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14          0x07, 0x4a
+#define TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15          0x07, 0x4b
+#define TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16          0x07, 0x4c
+#define TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17          0x07, 0x4d
+#define TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18          0x07, 0x4e
+#define TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19          0x07, 0x4f
+#define TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20          0x07, 0x50
+#define TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21          0x07, 0x51
+#define TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22          0x07, 0x52
+#define TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23          0x07, 0x53
+#define TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES          0x07, 0x54
+#define TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN          0x07, 0x55
+#define TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN                0x07, 0x56
+#define TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN                0x07, 0x57
+#define TM6010_REQ07_R58_VBI_CAPTION_DTO1              0x07, 0x58
+#define TM6010_REQ07_R59_VBI_CAPTION_DTO0              0x07, 0x59
+#define TM6010_REQ07_R5A_VBI_TELETEXT_DTO1             0x07, 0x5a
+#define TM6010_REQ07_R5B_VBI_TELETEXT_DTO0             0x07, 0x5b
+#define TM6010_REQ07_R5C_VBI_WSS625_DTO1               0x07, 0x5c
+#define TM6010_REQ07_R5D_VBI_WSS625_DTO0               0x07, 0x5d
+#define TM6010_REQ07_R5E_VBI_CAPTION_FRAME_START       0x07, 0x5e
+#define TM6010_REQ07_R5F_VBI_WSS625_FRAME_START                0x07, 0x5f
+#define TM6010_REQ07_R60_TELETEXT_FRAME_START          0x07, 0x60
+#define TM6010_REQ07_R61_VBI_CCDATA1                   0x07, 0x61
+#define TM6010_REQ07_R62_VBI_CCDATA2                   0x07, 0x62
+#define TM6010_REQ07_R63_VBI_WSS625_DATA1              0x07, 0x63
+#define TM6010_REQ07_R64_VBI_WSS625_DATA2              0x07, 0x64
+#define TM6010_REQ07_R65_VBI_DATA_STATUS               0x07, 0x65
+#define TM6010_REQ07_R66_VBI_CAPTION_START             0x07, 0x66
+#define TM6010_REQ07_R67_VBI_WSS625_START              0x07, 0x67
+#define TM6010_REQ07_R68_VBI_TELETEXT_START            0x07, 0x68
+#define TM6010_REQ07_R70_HSYNC_DTO_INC_STATUS3         0x07, 0x70
+#define TM6010_REQ07_R71_HSYNC_DTO_INC_STATUS2         0x07, 0x71
+#define TM6010_REQ07_R72_HSYNC_DTO_INC_STATUS1         0x07, 0x72
+#define TM6010_REQ07_R73_HSYNC_DTO_INC_STATUS0         0x07, 0x73
+#define TM6010_REQ07_R74_CHROMA_DTO_INC_STATUS3                0x07, 0x74
+#define TM6010_REQ07_R75_CHROMA_DTO_INC_STATUS2                0x07, 0x75
+#define TM6010_REQ07_R76_CHROMA_DTO_INC_STATUS1                0x07, 0x76
+#define TM6010_REQ07_R77_CHROMA_DTO_INC_STATUS0                0x07, 0x77
+#define TM6010_REQ07_R78_AGC_AGAIN_STATUS              0x07, 0x78
+#define TM6010_REQ07_R79_AGC_DGAIN_STATUS              0x07, 0x79
+#define TM6010_REQ07_R7A_CHROMA_MAG_STATUS             0x07, 0x7a
+#define TM6010_REQ07_R7B_CHROMA_GAIN_STATUS1           0x07, 0x7b
+#define TM6010_REQ07_R7C_CHROMA_GAIN_STATUS0           0x07, 0x7c
+#define TM6010_REQ07_R7D_CORDIC_FREQ_STATUS            0x07, 0x7d
+#define TM6010_REQ07_R7F_STATUS_NOISE                  0x07, 0x7f
+#define TM6010_REQ07_R80_COMB_FILTER_TRESHOLD          0x07, 0x80
+#define TM6010_REQ07_R82_COMB_FILTER_CONFIG            0x07, 0x82
+#define TM6010_REQ07_R83_CHROMA_LOCK_CONFIG            0x07, 0x83
+#define TM6010_REQ07_R84_NOISE_NTSC_C                  0x07, 0x84
+#define TM6010_REQ07_R85_NOISE_PAL_C                   0x07, 0x85
+#define TM6010_REQ07_R86_NOISE_PHASE_C                 0x07, 0x86
+#define TM6010_REQ07_R87_NOISE_PHASE_Y                 0x07, 0x87
+#define TM6010_REQ07_R8A_CHROMA_LOOPFILTER_STATE       0x07, 0x8a
+#define TM6010_REQ07_R8B_CHROMA_HRESAMPLER             0x07, 0x8b
+#define TM6010_REQ07_R8D_CPUMP_DELAY_ADJ               0x07, 0x8d
+#define TM6010_REQ07_R8E_CPUMP_ADJ                     0x07, 0x8e
+#define TM6010_REQ07_R8F_CPUMP_DELAY                   0x07, 0x8f
+
+/* Define TM6000/TM6010 Miscellaneous registers */
+#define TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE           0x07, 0xc0
+#define TM6010_REQ07_RC1_TRESHOLD                      0x07, 0xc1
+#define TM6010_REQ07_RC2_HSYNC_WIDTH                   0x07, 0xc2
+#define TM6010_REQ07_RC3_HSTART1                       0x07, 0xc3
+#define TM6010_REQ07_RC4_HSTART0                       0x07, 0xc4
+#define TM6010_REQ07_RC5_HEND1                         0x07, 0xc5
+#define TM6010_REQ07_RC6_HEND0                         0x07, 0xc6
+#define TM6010_REQ07_RC7_VSTART1                       0x07, 0xc7
+#define TM6010_REQ07_RC8_VSTART0                       0x07, 0xc8
+#define TM6010_REQ07_RC9_VEND1                         0x07, 0xc9
+#define TM6010_REQ07_RCA_VEND0                         0x07, 0xca
+#define TM6010_REQ07_RCB_DELAY                         0x07, 0xcb
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RCC_ACTIVE_IF                     0x07, 0xcc
+#define TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE (1 << 5)
+#define TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE (1 << 6)
+#define TM6010_REQ07_RD0_USB_PERIPHERY_CONTROL         0x07, 0xd0
+#define TM6010_REQ07_RD1_ADDR_FOR_REQ1                 0x07, 0xd1
+#define TM6010_REQ07_RD2_ADDR_FOR_REQ2                 0x07, 0xd2
+#define TM6010_REQ07_RD3_ADDR_FOR_REQ3                 0x07, 0xd3
+#define TM6010_REQ07_RD4_ADDR_FOR_REQ4                 0x07, 0xd4
+#define TM6010_REQ07_RD5_POWERSAVE                     0x07, 0xd5
+#define TM6010_REQ07_RD6_ENDP_REQ1_REQ2                        0x07, 0xd6
+#define TM6010_REQ07_RD7_ENDP_REQ3_REQ4                        0x07, 0xd7
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RD8_IR                            0x07, 0xd8
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RD8_IR_BSIZE                      0x07, 0xd9
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RD8_IR_WAKEUP_SEL                 0x07, 0xda
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RD8_IR_WAKEUP_ADD                 0x07, 0xdb
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RD8_IR_LEADER1                    0x07, 0xdc
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RD8_IR_LEADER0                    0x07, 0xdd
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RD8_IR_PULSE_CNT1                 0x07, 0xde
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RD8_IR_PULSE_CNT0                 0x07, 0xdf
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RE0_DVIDEO_SOURCE                 0x07, 0xe0
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RE0_DVIDEO_SOURCE_IF              0x07, 0xe1
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RE2_OUT_SEL2                      0x07, 0xe2
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RE3_OUT_SEL1                      0x07, 0xe3
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RE4_OUT_SEL0                      0x07, 0xe4
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RE5_REMOTE_WAKEUP                 0x07, 0xe5
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RE7_PUB_GPIO                      0x07, 0xe7
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RE8_TYPESEL_MOS_I2S               0x07, 0xe8
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RE9_TYPESEL_MOS_TS                        0x07, 0xe9
+/* ONLY for TM6010 */
+#define TM6010_REQ07_REA_TYPESEL_MOS_CCIR              0x07, 0xea
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RF0_BIST_CRC_RESULT0              0x07, 0xf0
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RF1_BIST_CRC_RESULT1              0x07, 0xf1
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RF2_BIST_CRC_RESULT2              0x07, 0xf2
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RF3_BIST_CRC_RESULT3              0x07, 0xf3
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RF4_BIST_ERR_VST2                 0x07, 0xf4
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RF5_BIST_ERR_VST1                 0x07, 0xf5
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RF6_BIST_ERR_VST0                 0x07, 0xf6
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RF7_BIST                          0x07, 0xf7
+/* ONLY for TM6010 */
+#define TM6010_REQ07_RFE_POWER_DOWN                    0x07, 0xfe
+#define TM6010_REQ07_RFF_SOFT_RESET                    0x07, 0xff
+
+/* Define TM6000/TM6010 USB registers */
+#define TM6010_REQ05_R00_MAIN_CTRL             0x05, 0x00
+#define TM6010_REQ05_R01_DEVADDR               0x05, 0x01
+#define TM6010_REQ05_R02_TEST                  0x05, 0x02
+#define TM6010_REQ05_R04_SOFN0                 0x05, 0x04
+#define TM6010_REQ05_R05_SOFN1                 0x05, 0x05
+#define TM6010_REQ05_R06_SOFTM0                        0x05, 0x06
+#define TM6010_REQ05_R07_SOFTM1                        0x05, 0x07
+#define TM6010_REQ05_R08_PHY_TEST              0x05, 0x08
+#define TM6010_REQ05_R09_VCTL                  0x05, 0x09
+#define TM6010_REQ05_R0A_VSTA                  0x05, 0x0a
+#define TM6010_REQ05_R0B_CX_CFG                        0x05, 0x0b
+#define TM6010_REQ05_R0C_ENDP0_REG0            0x05, 0x0c
+#define TM6010_REQ05_R10_GMASK                 0x05, 0x10
+#define TM6010_REQ05_R11_IMASK0                        0x05, 0x11
+#define TM6010_REQ05_R12_IMASK1                        0x05, 0x12
+#define TM6010_REQ05_R13_IMASK2                        0x05, 0x13
+#define TM6010_REQ05_R14_IMASK3                        0x05, 0x14
+#define TM6010_REQ05_R15_IMASK4                        0x05, 0x15
+#define TM6010_REQ05_R16_IMASK5                        0x05, 0x16
+#define TM6010_REQ05_R17_IMASK6                        0x05, 0x17
+#define TM6010_REQ05_R18_IMASK7                        0x05, 0x18
+#define TM6010_REQ05_R19_ZEROP0                        0x05, 0x19
+#define TM6010_REQ05_R1A_ZEROP1                        0x05, 0x1a
+#define TM6010_REQ05_R1C_FIFO_EMP0             0x05, 0x1c
+#define TM6010_REQ05_R1D_FIFO_EMP1             0x05, 0x1d
+#define TM6010_REQ05_R20_IRQ_GROUP             0x05, 0x20
+#define TM6010_REQ05_R21_IRQ_SOURCE0           0x05, 0x21
+#define TM6010_REQ05_R22_IRQ_SOURCE1           0x05, 0x22
+#define TM6010_REQ05_R23_IRQ_SOURCE2           0x05, 0x23
+#define TM6010_REQ05_R24_IRQ_SOURCE3           0x05, 0x24
+#define TM6010_REQ05_R25_IRQ_SOURCE4           0x05, 0x25
+#define TM6010_REQ05_R26_IRQ_SOURCE5           0x05, 0x26
+#define TM6010_REQ05_R27_IRQ_SOURCE6           0x05, 0x27
+#define TM6010_REQ05_R28_IRQ_SOURCE7           0x05, 0x28
+#define TM6010_REQ05_R29_SEQ_ERR0              0x05, 0x29
+#define TM6010_REQ05_R2A_SEQ_ERR1              0x05, 0x2a
+#define TM6010_REQ05_R2B_SEQ_ABORT0            0x05, 0x2b
+#define TM6010_REQ05_R2C_SEQ_ABORT1            0x05, 0x2c
+#define TM6010_REQ05_R2D_TX_ZERO0              0x05, 0x2d
+#define TM6010_REQ05_R2E_TX_ZERO1              0x05, 0x2e
+#define TM6010_REQ05_R2F_IDLE_CNT              0x05, 0x2f
+#define TM6010_REQ05_R30_FNO_P1                        0x05, 0x30
+#define TM6010_REQ05_R31_FNO_P2                        0x05, 0x31
+#define TM6010_REQ05_R32_FNO_P3                        0x05, 0x32
+#define TM6010_REQ05_R33_FNO_P4                        0x05, 0x33
+#define TM6010_REQ05_R34_FNO_P5                        0x05, 0x34
+#define TM6010_REQ05_R35_FNO_P6                        0x05, 0x35
+#define TM6010_REQ05_R36_FNO_P7                        0x05, 0x36
+#define TM6010_REQ05_R37_FNO_P8                        0x05, 0x37
+#define TM6010_REQ05_R38_FNO_P9                        0x05, 0x38
+#define TM6010_REQ05_R30_FNO_P10               0x05, 0x39
+#define TM6010_REQ05_R30_FNO_P11               0x05, 0x3a
+#define TM6010_REQ05_R30_FNO_P12               0x05, 0x3b
+#define TM6010_REQ05_R30_FNO_P13               0x05, 0x3c
+#define TM6010_REQ05_R30_FNO_P14               0x05, 0x3d
+#define TM6010_REQ05_R30_FNO_P15               0x05, 0x3e
+#define TM6010_REQ05_R40_IN_MAXPS_LOW1         0x05, 0x40
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH1                0x05, 0x41
+#define TM6010_REQ05_R42_IN_MAXPS_LOW2         0x05, 0x42
+#define TM6010_REQ05_R43_IN_MAXPS_HIGH2                0x05, 0x43
+#define TM6010_REQ05_R44_IN_MAXPS_LOW3         0x05, 0x44
+#define TM6010_REQ05_R45_IN_MAXPS_HIGH3                0x05, 0x45
+#define TM6010_REQ05_R46_IN_MAXPS_LOW4         0x05, 0x46
+#define TM6010_REQ05_R47_IN_MAXPS_HIGH4                0x05, 0x47
+#define TM6010_REQ05_R48_IN_MAXPS_LOW5         0x05, 0x48
+#define TM6010_REQ05_R49_IN_MAXPS_HIGH5                0x05, 0x49
+#define TM6010_REQ05_R4A_IN_MAXPS_LOW6         0x05, 0x4a
+#define TM6010_REQ05_R4B_IN_MAXPS_HIGH6                0x05, 0x4b
+#define TM6010_REQ05_R4C_IN_MAXPS_LOW7         0x05, 0x4c
+#define TM6010_REQ05_R4D_IN_MAXPS_HIGH7                0x05, 0x4d
+#define TM6010_REQ05_R4E_IN_MAXPS_LOW8         0x05, 0x4e
+#define TM6010_REQ05_R4F_IN_MAXPS_HIGH8                0x05, 0x4f
+#define TM6010_REQ05_R50_IN_MAXPS_LOW9         0x05, 0x50
+#define TM6010_REQ05_R51_IN_MAXPS_HIGH9                0x05, 0x51
+#define TM6010_REQ05_R40_IN_MAXPS_LOW10                0x05, 0x52
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH10       0x05, 0x53
+#define TM6010_REQ05_R40_IN_MAXPS_LOW11                0x05, 0x54
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH11       0x05, 0x55
+#define TM6010_REQ05_R40_IN_MAXPS_LOW12                0x05, 0x56
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH12       0x05, 0x57
+#define TM6010_REQ05_R40_IN_MAXPS_LOW13                0x05, 0x58
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH13       0x05, 0x59
+#define TM6010_REQ05_R40_IN_MAXPS_LOW14                0x05, 0x5a
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH14       0x05, 0x5b
+#define TM6010_REQ05_R40_IN_MAXPS_LOW15                0x05, 0x5c
+#define TM6010_REQ05_R41_IN_MAXPS_HIGH15       0x05, 0x5d
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW1                0x05, 0x60
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH1       0x05, 0x61
+#define TM6010_REQ05_R62_OUT_MAXPS_LOW2                0x05, 0x62
+#define TM6010_REQ05_R63_OUT_MAXPS_HIGH2       0x05, 0x63
+#define TM6010_REQ05_R64_OUT_MAXPS_LOW3                0x05, 0x64
+#define TM6010_REQ05_R65_OUT_MAXPS_HIGH3       0x05, 0x65
+#define TM6010_REQ05_R66_OUT_MAXPS_LOW4                0x05, 0x66
+#define TM6010_REQ05_R67_OUT_MAXPS_HIGH4       0x05, 0x67
+#define TM6010_REQ05_R68_OUT_MAXPS_LOW5                0x05, 0x68
+#define TM6010_REQ05_R69_OUT_MAXPS_HIGH5       0x05, 0x69
+#define TM6010_REQ05_R6A_OUT_MAXPS_LOW6                0x05, 0x6a
+#define TM6010_REQ05_R6B_OUT_MAXPS_HIGH6       0x05, 0x6b
+#define TM6010_REQ05_R6C_OUT_MAXPS_LOW7                0x05, 0x6c
+#define TM6010_REQ05_R6D_OUT_MAXPS_HIGH7       0x05, 0x6d
+#define TM6010_REQ05_R6E_OUT_MAXPS_LOW8                0x05, 0x6e
+#define TM6010_REQ05_R6F_OUT_MAXPS_HIGH8       0x05, 0x6f
+#define TM6010_REQ05_R70_OUT_MAXPS_LOW9                0x05, 0x70
+#define TM6010_REQ05_R71_OUT_MAXPS_HIGH9       0x05, 0x71
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW10       0x05, 0x72
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH10      0x05, 0x73
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW11       0x05, 0x74
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH11      0x05, 0x75
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW12       0x05, 0x76
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH12      0x05, 0x77
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW13       0x05, 0x78
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH13      0x05, 0x79
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW14       0x05, 0x7a
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH14      0x05, 0x7b
+#define TM6010_REQ05_R60_OUT_MAXPS_LOW15       0x05, 0x7c
+#define TM6010_REQ05_R61_OUT_MAXPS_HIGH15      0x05, 0x7d
+#define TM6010_REQ05_R80_FIFO0                 0x05, 0x80
+#define TM6010_REQ05_R81_FIFO1                 0x05, 0x81
+#define TM6010_REQ05_R82_FIFO2                 0x05, 0x82
+#define TM6010_REQ05_R83_FIFO3                 0x05, 0x83
+#define TM6010_REQ05_R84_FIFO4                 0x05, 0x84
+#define TM6010_REQ05_R85_FIFO5                 0x05, 0x85
+#define TM6010_REQ05_R86_FIFO6                 0x05, 0x86
+#define TM6010_REQ05_R87_FIFO7                 0x05, 0x87
+#define TM6010_REQ05_R88_FIFO8                 0x05, 0x88
+#define TM6010_REQ05_R89_FIFO9                 0x05, 0x89
+#define TM6010_REQ05_R81_FIFO10                        0x05, 0x8a
+#define TM6010_REQ05_R81_FIFO11                        0x05, 0x8b
+#define TM6010_REQ05_R81_FIFO12                        0x05, 0x8c
+#define TM6010_REQ05_R81_FIFO13                        0x05, 0x8d
+#define TM6010_REQ05_R81_FIFO14                        0x05, 0x8e
+#define TM6010_REQ05_R81_FIFO15                        0x05, 0x8f
+#define TM6010_REQ05_R90_CFG_FIFO0             0x05, 0x90
+#define TM6010_REQ05_R91_CFG_FIFO1             0x05, 0x91
+#define TM6010_REQ05_R92_CFG_FIFO2             0x05, 0x92
+#define TM6010_REQ05_R93_CFG_FIFO3             0x05, 0x93
+#define TM6010_REQ05_R94_CFG_FIFO4             0x05, 0x94
+#define TM6010_REQ05_R95_CFG_FIFO5             0x05, 0x95
+#define TM6010_REQ05_R96_CFG_FIFO6             0x05, 0x96
+#define TM6010_REQ05_R97_CFG_FIFO7             0x05, 0x97
+#define TM6010_REQ05_R98_CFG_FIFO8             0x05, 0x98
+#define TM6010_REQ05_R99_CFG_FIFO9             0x05, 0x99
+#define TM6010_REQ05_R91_CFG_FIFO10            0x05, 0x9a
+#define TM6010_REQ05_R91_CFG_FIFO11            0x05, 0x9b
+#define TM6010_REQ05_R91_CFG_FIFO12            0x05, 0x9c
+#define TM6010_REQ05_R91_CFG_FIFO13            0x05, 0x9d
+#define TM6010_REQ05_R91_CFG_FIFO14            0x05, 0x9e
+#define TM6010_REQ05_R91_CFG_FIFO15            0x05, 0x9f
+#define TM6010_REQ05_RA0_CTL_FIFO0             0x05, 0xa0
+#define TM6010_REQ05_RA1_CTL_FIFO1             0x05, 0xa1
+#define TM6010_REQ05_RA2_CTL_FIFO2             0x05, 0xa2
+#define TM6010_REQ05_RA3_CTL_FIFO3             0x05, 0xa3
+#define TM6010_REQ05_RA4_CTL_FIFO4             0x05, 0xa4
+#define TM6010_REQ05_RA5_CTL_FIFO5             0x05, 0xa5
+#define TM6010_REQ05_RA6_CTL_FIFO6             0x05, 0xa6
+#define TM6010_REQ05_RA7_CTL_FIFO7             0x05, 0xa7
+#define TM6010_REQ05_RA8_CTL_FIFO8             0x05, 0xa8
+#define TM6010_REQ05_RA9_CTL_FIFO9             0x05, 0xa9
+#define TM6010_REQ05_RA1_CTL_FIFO10            0x05, 0xaa
+#define TM6010_REQ05_RA1_CTL_FIFO11            0x05, 0xab
+#define TM6010_REQ05_RA1_CTL_FIFO12            0x05, 0xac
+#define TM6010_REQ05_RA1_CTL_FIFO13            0x05, 0xad
+#define TM6010_REQ05_RA1_CTL_FIFO14            0x05, 0xae
+#define TM6010_REQ05_RA1_CTL_FIFO15            0x05, 0xaf
+#define TM6010_REQ05_RB0_BC_LOW_FIFO0          0x05, 0xb0
+#define TM6010_REQ05_RB1_BC_LOW_FIFO1          0x05, 0xb1
+#define TM6010_REQ05_RB2_BC_LOW_FIFO2          0x05, 0xb2
+#define TM6010_REQ05_RB3_BC_LOW_FIFO3          0x05, 0xb3
+#define TM6010_REQ05_RB4_BC_LOW_FIFO4          0x05, 0xb4
+#define TM6010_REQ05_RB5_BC_LOW_FIFO5          0x05, 0xb5
+#define TM6010_REQ05_RB6_BC_LOW_FIFO6          0x05, 0xb6
+#define TM6010_REQ05_RB7_BC_LOW_FIFO7          0x05, 0xb7
+#define TM6010_REQ05_RB8_BC_LOW_FIFO8          0x05, 0xb8
+#define TM6010_REQ05_RB9_BC_LOW_FIFO9          0x05, 0xb9
+#define TM6010_REQ05_RB1_BC_LOW_FIFO10         0x05, 0xba
+#define TM6010_REQ05_RB1_BC_LOW_FIFO11         0x05, 0xbb
+#define TM6010_REQ05_RB1_BC_LOW_FIFO12         0x05, 0xbc
+#define TM6010_REQ05_RB1_BC_LOW_FIFO13         0x05, 0xbd
+#define TM6010_REQ05_RB1_BC_LOW_FIFO14         0x05, 0xbe
+#define TM6010_REQ05_RB1_BC_LOW_FIFO15         0x05, 0xbf
+#define TM6010_REQ05_RC0_DATA_FIFO0            0x05, 0xc0
+#define TM6010_REQ05_RC4_DATA_FIFO1            0x05, 0xc4
+#define TM6010_REQ05_RC8_DATA_FIFO2            0x05, 0xc8
+#define TM6010_REQ05_RCC_DATA_FIFO3            0x05, 0xcc
+#define TM6010_REQ05_RD0_DATA_FIFO4            0x05, 0xd0
+#define TM6010_REQ05_RD4_DATA_FIFO5            0x05, 0xd4
+#define TM6010_REQ05_RD8_DATA_FIFO6            0x05, 0xd8
+#define TM6010_REQ05_RDC_DATA_FIFO7            0x05, 0xdc
+#define TM6010_REQ05_RE0_DATA_FIFO8            0x05, 0xe0
+#define TM6010_REQ05_RE4_DATA_FIFO9            0x05, 0xe4
+#define TM6010_REQ05_RC4_DATA_FIFO10           0x05, 0xe8
+#define TM6010_REQ05_RC4_DATA_FIFO11           0x05, 0xec
+#define TM6010_REQ05_RC4_DATA_FIFO12           0x05, 0xf0
+#define TM6010_REQ05_RC4_DATA_FIFO13           0x05, 0xf4
+#define TM6010_REQ05_RC4_DATA_FIFO14           0x05, 0xf8
+#define TM6010_REQ05_RC4_DATA_FIFO15           0x05, 0xfc
+
+/* Define TM6010 Audio decoder registers */
+/* This core available only in TM6010 */
+#define TM6010_REQ08_R00_A_VERSION             0x08, 0x00
+#define TM6010_REQ08_R01_A_INIT                        0x08, 0x01
+#define TM6010_REQ08_R02_A_FIX_GAIN_CTRL       0x08, 0x02
+#define TM6010_REQ08_R03_A_AUTO_GAIN_CTRL      0x08, 0x03
+#define TM6010_REQ08_R04_A_SIF_AMP_CTRL                0x08, 0x04
+#define TM6010_REQ08_R05_A_STANDARD_MOD                0x08, 0x05
+#define TM6010_REQ08_R06_A_SOUND_MOD           0x08, 0x06
+#define TM6010_REQ08_R07_A_LEFT_VOL            0x08, 0x07
+#define TM6010_REQ08_R08_A_RIGHT_VOL           0x08, 0x08
+#define TM6010_REQ08_R09_A_MAIN_VOL            0x08, 0x09
+#define TM6010_REQ08_R0A_A_I2S_MOD             0x08, 0x0a
+#define TM6010_REQ08_R0B_A_ASD_THRES1          0x08, 0x0b
+#define TM6010_REQ08_R0C_A_ASD_THRES2          0x08, 0x0c
+#define TM6010_REQ08_R0D_A_AMD_THRES           0x08, 0x0d
+#define TM6010_REQ08_R0E_A_MONO_THRES1         0x08, 0x0e
+#define TM6010_REQ08_R0F_A_MONO_THRES2         0x08, 0x0f
+#define TM6010_REQ08_R10_A_MUTE_THRES1         0x08, 0x10
+#define TM6010_REQ08_R11_A_MUTE_THRES2         0x08, 0x11
+#define TM6010_REQ08_R12_A_AGC_U               0x08, 0x12
+#define TM6010_REQ08_R13_A_AGC_ERR_T           0x08, 0x13
+#define TM6010_REQ08_R14_A_AGC_GAIN_INIT       0x08, 0x14
+#define TM6010_REQ08_R15_A_AGC_STEP_THR                0x08, 0x15
+#define TM6010_REQ08_R16_A_AGC_GAIN_MAX                0x08, 0x16
+#define TM6010_REQ08_R17_A_AGC_GAIN_MIN                0x08, 0x17
+#define TM6010_REQ08_R18_A_TR_CTRL             0x08, 0x18
+#define TM6010_REQ08_R19_A_FH_2FH_GAIN         0x08, 0x19
+#define TM6010_REQ08_R1A_A_NICAM_SER_MAX       0x08, 0x1a
+#define TM6010_REQ08_R1B_A_NICAM_SER_MIN       0x08, 0x1b
+#define TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT     0x08, 0x1e
+#define TM6010_REQ08_R1F_A_TEST_INTF_SEL       0x08, 0x1f
+#define TM6010_REQ08_R20_A_TEST_PIN_SEL                0x08, 0x20
+#define TM6010_REQ08_R21_A_AGC_ERR             0x08, 0x21
+#define TM6010_REQ08_R22_A_AGC_GAIN            0x08, 0x22
+#define TM6010_REQ08_R23_A_NICAM_INFO          0x08, 0x23
+#define TM6010_REQ08_R24_A_SER                 0x08, 0x24
+#define TM6010_REQ08_R25_A_C1_AMP              0x08, 0x25
+#define TM6010_REQ08_R26_A_C2_AMP              0x08, 0x26
+#define TM6010_REQ08_R27_A_NOISE_AMP           0x08, 0x27
+#define TM6010_REQ08_R28_A_AUDIO_MODE_RES      0x08, 0x28
+
+/* Define TM6010 Video ADC registers */
+#define TM6010_REQ08_RE0_ADC_REF               0x08, 0xe0
+#define TM6010_REQ08_RE1_DAC_CLMP              0x08, 0xe1
+#define TM6010_REQ08_RE2_POWER_DOWN_CTRL1      0x08, 0xe2
+#define TM6010_REQ08_RE3_ADC_IN1_SEL           0x08, 0xe3
+#define TM6010_REQ08_RE4_ADC_IN2_SEL           0x08, 0xe4
+#define TM6010_REQ08_RE5_GAIN_PARAM            0x08, 0xe5
+#define TM6010_REQ08_RE6_POWER_DOWN_CTRL2      0x08, 0xe6
+#define TM6010_REQ08_RE7_REG_GAIN_Y            0x08, 0xe7
+#define TM6010_REQ08_RE8_REG_GAIN_C            0x08, 0xe8
+#define TM6010_REQ08_RE9_BIAS_CTRL             0x08, 0xe9
+#define TM6010_REQ08_REA_BUFF_DRV_CTRL         0x08, 0xea
+#define TM6010_REQ08_REB_SIF_GAIN_CTRL         0x08, 0xeb
+#define TM6010_REQ08_REC_REVERSE_YC_CTRL       0x08, 0xec
+#define TM6010_REQ08_RED_GAIN_SEL              0x08, 0xed
+
+/* Define TM6010 Audio ADC registers */
+#define TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG   0x08, 0xf0
+#define TM6010_REQ08_RF1_AADC_POWER_DOWN       0x08, 0xf1
+#define TM6010_REQ08_RF2_LEFT_CHANNEL_VOL      0x08, 0xf2
+#define TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL     0x08, 0xf3
diff --git a/drivers/media/video/tm6000/tm6000-stds.c b/drivers/media/video/tm6000/tm6000-stds.c
new file mode 100644 (file)
index 0000000..9a4145d
--- /dev/null
@@ -0,0 +1,659 @@
+/*
+ *  tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ *  Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation version 2
+ *
+ *  This program is distributed 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/module.h>
+#include <linux/kernel.h>
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+static unsigned int tm6010_a_mode;
+module_param(tm6010_a_mode, int, 0644);
+MODULE_PARM_DESC(tm6010_a_mode, "set tm6010 sif audio mode");
+
+struct tm6000_reg_settings {
+       unsigned char req;
+       unsigned char reg;
+       unsigned char value;
+};
+
+
+struct tm6000_std_settings {
+       v4l2_std_id id;
+       struct tm6000_reg_settings *common;
+};
+
+static struct tm6000_reg_settings composite_pal_m[] = {
+       { TM6010_REQ07_R3F_RESET, 0x01 },
+       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04 },
+       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
+       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
+       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
+       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
+       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 },
+       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a },
+       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 },
+       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
+       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20 },
+       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
+       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
+       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
+       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
+       { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
+       { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
+       { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
+       { TM6010_REQ07_R3F_RESET, 0x00 },
+       { 0, 0, 0 }
+};
+
+static struct tm6000_reg_settings composite_pal_nc[] = {
+       { TM6010_REQ07_R3F_RESET, 0x01 },
+       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36 },
+       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
+       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 },
+       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
+       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
+       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 },
+       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f },
+       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c },
+       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
+       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c },
+       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
+       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
+       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
+       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
+       { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
+       { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
+       { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
+       { TM6010_REQ07_R3F_RESET, 0x00 },
+       { 0, 0, 0 }
+};
+
+static struct tm6000_reg_settings composite_pal[] = {
+       { TM6010_REQ07_R3F_RESET, 0x01 },
+       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32 },
+       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
+       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 },
+       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
+       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 },
+       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 },
+       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 },
+       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 },
+       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
+       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c },
+       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
+       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
+       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
+       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
+       { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
+       { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
+       { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
+       { TM6010_REQ07_R3F_RESET, 0x00 },
+       { 0, 0, 0 }
+};
+
+static struct tm6000_reg_settings composite_secam[] = {
+       { TM6010_REQ07_R3F_RESET, 0x01 },
+       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38 },
+       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
+       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 },
+       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
+       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 },
+       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 },
+       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 },
+       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed },
+       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
+       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c },
+       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
+       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c },
+       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 },
+       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
+       { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff },
+       { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
+       { TM6010_REQ07_R3F_RESET, 0x00 },
+       { 0, 0, 0 }
+};
+
+static struct tm6000_reg_settings composite_ntsc[] = {
+       { TM6010_REQ07_R3F_RESET, 0x01 },
+       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
+       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f },
+       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
+       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
+       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
+       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
+       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
+       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
+       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
+       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
+       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
+       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
+       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
+       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
+       { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
+       { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd },
+       { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
+       { TM6010_REQ07_R3F_RESET, 0x00 },
+       { 0, 0, 0 }
+};
+
+static struct tm6000_std_settings composite_stds[] = {
+       { .id = V4L2_STD_PAL_M, .common = composite_pal_m, },
+       { .id = V4L2_STD_PAL_Nc, .common = composite_pal_nc, },
+       { .id = V4L2_STD_PAL, .common = composite_pal, },
+       { .id = V4L2_STD_SECAM, .common = composite_secam, },
+       { .id = V4L2_STD_NTSC, .common = composite_ntsc, },
+};
+
+static struct tm6000_reg_settings svideo_pal_m[] = {
+       { TM6010_REQ07_R3F_RESET, 0x01 },
+       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x05 },
+       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
+       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 },
+       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
+       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
+       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 },
+       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a },
+       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 },
+       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
+       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
+       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
+       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
+       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
+       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
+       { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
+       { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
+       { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
+       { TM6010_REQ07_R3F_RESET, 0x00 },
+       { 0, 0, 0 }
+};
+
+static struct tm6000_reg_settings svideo_pal_nc[] = {
+       { TM6010_REQ07_R3F_RESET, 0x01 },
+       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x37 },
+       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
+       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 },
+       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
+       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
+       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 },
+       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f },
+       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c },
+       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
+       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
+       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
+       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
+       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
+       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
+       { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
+       { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
+       { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
+       { TM6010_REQ07_R3F_RESET, 0x00 },
+       { 0, 0, 0 }
+};
+
+static struct tm6000_reg_settings svideo_pal[] = {
+       { TM6010_REQ07_R3F_RESET, 0x01 },
+       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x33 },
+       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
+       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 },
+       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 },
+       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 },
+       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 },
+       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 },
+       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 },
+       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
+       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a },
+       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
+       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
+       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
+       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
+       { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
+       { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
+       { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
+       { TM6010_REQ07_R3F_RESET, 0x00 },
+       { 0, 0, 0 }
+};
+
+static struct tm6000_reg_settings svideo_secam[] = {
+       { TM6010_REQ07_R3F_RESET, 0x01 },
+       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39 },
+       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
+       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 },
+       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
+       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 },
+       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 },
+       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 },
+       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed },
+       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
+       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a },
+       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
+       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c },
+       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 },
+       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
+       { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff },
+       { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
+       { TM6010_REQ07_R3F_RESET, 0x00 },
+       { 0, 0, 0 }
+};
+
+static struct tm6000_reg_settings svideo_ntsc[] = {
+       { TM6010_REQ07_R3F_RESET, 0x01 },
+       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x01 },
+       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f },
+       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
+       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 },
+       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 },
+       { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b },
+       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
+       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
+       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
+       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
+       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
+       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
+       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
+       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
+       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
+       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
+       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
+       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
+       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
+       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
+       { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
+       { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd },
+       { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
+       { TM6010_REQ07_R3F_RESET, 0x00 },
+       { 0, 0, 0 }
+};
+
+static struct tm6000_std_settings svideo_stds[] = {
+       { .id = V4L2_STD_PAL_M, .common = svideo_pal_m, },
+       { .id = V4L2_STD_PAL_Nc, .common = svideo_pal_nc, },
+       { .id = V4L2_STD_PAL, .common = svideo_pal, },
+       { .id = V4L2_STD_SECAM, .common = svideo_secam, },
+       { .id = V4L2_STD_NTSC, .common = svideo_ntsc, },
+};
+
+static int tm6000_set_audio_std(struct tm6000_core *dev)
+{
+       uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */
+       uint8_t areg_05 = 0x01; /* Auto 4.5 = M Japan, Auto 6.5 = DK */
+       uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */
+       uint8_t nicam_flag = 0; /* No NICAM */
+
+       if (dev->radio) {
+               tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
+               tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
+               tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
+               tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80);
+               tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c);
+               /* set mono or stereo */
+               if (dev->amode == V4L2_TUNER_MODE_MONO)
+                       tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
+               else if (dev->amode == V4L2_TUNER_MODE_STEREO)
+                       tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x02);
+               tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18);
+               tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a);
+               tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x40);
+               tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe);
+               tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
+               tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
+               tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0xff);
+               return 0;
+       }
+
+       switch (tm6010_a_mode) {
+       /* auto */
+       case 0:
+               switch (dev->norm) {
+               case V4L2_STD_NTSC_M_KR:
+                       areg_05 |= 0x00;
+                       break;
+               case V4L2_STD_NTSC_M_JP:
+                       areg_05 |= 0x40;
+                       break;
+               case V4L2_STD_NTSC_M:
+               case V4L2_STD_PAL_M:
+               case V4L2_STD_PAL_N:
+                       areg_05 |= 0x20;
+                       break;
+               case V4L2_STD_PAL_Nc:
+                       areg_05 |= 0x60;
+                       break;
+               case V4L2_STD_SECAM_L:
+                       areg_05 |= 0x00;
+                       break;
+               case V4L2_STD_DK:
+                       areg_05 |= 0x10;
+                       break;
+               }
+               break;
+       /* A2 */
+       case 1:
+               switch (dev->norm) {
+               case V4L2_STD_B:
+               case V4L2_STD_GH:
+                       areg_05 = 0x05;
+                       break;
+               case V4L2_STD_DK:
+                       areg_05 = 0x09;
+                       break;
+               }
+               break;
+       /* NICAM */
+       case 2:
+               switch (dev->norm) {
+               case V4L2_STD_B:
+               case V4L2_STD_GH:
+                       areg_05 = 0x07;
+                       break;
+               case V4L2_STD_DK:
+                       areg_05 = 0x06;
+                       break;
+               case V4L2_STD_PAL_I:
+                       areg_05 = 0x08;
+                       break;
+               case V4L2_STD_SECAM_L:
+                       areg_05 = 0x0a;
+                       areg_02 = 0x02;
+                       break;
+               }
+               nicam_flag = 1;
+               break;
+       /* other */
+       case 3:
+               switch (dev->norm) {
+               /* DK3_A2 */
+               case V4L2_STD_DK:
+                       areg_05 = 0x0b;
+                       break;
+               /* Korea */
+               case V4L2_STD_NTSC_M_KR:
+                       areg_05 = 0x04;
+                       break;
+               /* EIAJ */
+               case V4L2_STD_NTSC_M_JP:
+                       areg_05 = 0x03;
+                       break;
+               default:
+                       areg_05 = 0x02;
+                       break;
+               }
+               break;
+       }
+
+       tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, areg_02);
+       tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0);
+       tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, areg_05);
+       tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, areg_06);
+       tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08);
+       tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
+       tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20);
+       tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12);
+       tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20);
+       tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0);
+       tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80);
+       tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0);
+       tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80);
+       tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12);
+       tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe);
+       tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20);
+       tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14);
+       tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
+       tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
+       tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0);
+       tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32);
+       tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64);
+       tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20);
+       tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00);
+       tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
+       tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00);
+       tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
+
+       return 0;
+}
+
+void tm6000_get_std_res(struct tm6000_core *dev)
+{
+       /* Currently, those are the only supported resoltions */
+       if (dev->norm & V4L2_STD_525_60)
+               dev->height = 480;
+       else
+               dev->height = 576;
+
+       dev->width = 720;
+}
+
+static int tm6000_load_std(struct tm6000_core *dev, struct tm6000_reg_settings *set)
+{
+       int i, rc;
+
+       /* Load board's initialization table */
+       for (i = 0; set[i].req; i++) {
+               rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value);
+               if (rc < 0) {
+                       printk(KERN_ERR "Error %i while setting "
+                              "req %d, reg %d to value %d\n",
+                              rc, set[i].req, set[i].reg, set[i].value);
+                       return rc;
+               }
+       }
+
+       return 0;
+}
+
+int tm6000_set_standard(struct tm6000_core *dev)
+{
+       struct tm6000_input *input;
+       int i, rc = 0;
+       u8 reg_07_fe = 0x8a;
+       u8 reg_08_f1 = 0xfc;
+       u8 reg_08_e2 = 0xf0;
+       u8 reg_08_e6 = 0x0f;
+
+       tm6000_get_std_res(dev);
+
+       if (!dev->radio)
+               input = &dev->vinput[dev->input];
+       else
+               input = &dev->rinput;
+
+       if (dev->dev_type == TM6010) {
+               switch (input->vmux) {
+               case TM6000_VMUX_VIDEO_A:
+                       tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4);
+                       tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1);
+                       tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0);
+                       tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
+                       tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8);
+                       reg_07_fe |= 0x01;
+                       break;
+               case TM6000_VMUX_VIDEO_B:
+                       tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8);
+                       tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1);
+                       tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0);
+                       tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
+                       tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8);
+                       reg_07_fe |= 0x01;
+                       break;
+               case TM6000_VMUX_VIDEO_AB:
+                       tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc);
+                       tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8);
+                       reg_08_e6 = 0x00;
+                       tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2);
+                       tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0);
+                       tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
+                       tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe0);
+                       break;
+               default:
+                       break;
+               }
+               switch (input->amux) {
+               case TM6000_AMUX_ADC1:
+                       tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                               0x00, 0x0f);
+                       break;
+               case TM6000_AMUX_ADC2:
+                       tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                               0x08, 0x0f);
+                       break;
+               case TM6000_AMUX_SIF1:
+                       reg_08_e2 |= 0x02;
+                       reg_08_e6 = 0x08;
+                       reg_07_fe |= 0x40;
+                       reg_08_f1 |= 0x02;
+                       tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
+                       tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                               0x02, 0x0f);
+                       break;
+               case TM6000_AMUX_SIF2:
+                       reg_08_e2 |= 0x02;
+                       reg_08_e6 = 0x08;
+                       reg_07_fe |= 0x40;
+                       reg_08_f1 |= 0x02;
+                       tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf7);
+                       tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                               0x02, 0x0f);
+                       break;
+               default:
+                       break;
+               }
+               tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, reg_08_e2);
+               tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, reg_08_e6);
+               tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, reg_08_f1);
+               tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, reg_07_fe);
+       } else {
+               switch (input->vmux) {
+               case TM6000_VMUX_VIDEO_A:
+                       tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10);
+                       tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00);
+                       tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f);
+                       tm6000_set_reg(dev,
+                           REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0);
+                       break;
+               case TM6000_VMUX_VIDEO_B:
+                       tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00);
+                       tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00);
+                       tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f);
+                       tm6000_set_reg(dev,
+                           REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0);
+                       break;
+               case TM6000_VMUX_VIDEO_AB:
+                       tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10);
+                       tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x10);
+                       tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00);
+                       tm6000_set_reg(dev,
+                           REQ_03_SET_GET_MCU_PIN, input->v_gpio, 1);
+                       break;
+               default:
+                       break;
+               }
+               switch (input->amux) {
+               case TM6000_AMUX_ADC1:
+                       tm6000_set_reg_mask(dev,
+                               TM6000_REQ07_REB_VADC_AADC_MODE, 0x00, 0x0f);
+                       break;
+               case TM6000_AMUX_ADC2:
+                       tm6000_set_reg_mask(dev,
+                               TM6000_REQ07_REB_VADC_AADC_MODE, 0x04, 0x0f);
+                       break;
+               default:
+                       break;
+               }
+       }
+       if (input->type == TM6000_INPUT_SVIDEO) {
+               for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) {
+                       if (dev->norm & svideo_stds[i].id) {
+                               rc = tm6000_load_std(dev, svideo_stds[i].common);
+                               goto ret;
+                       }
+               }
+               return -EINVAL;
+       } else {
+               for (i = 0; i < ARRAY_SIZE(composite_stds); i++) {
+                       if (dev->norm & composite_stds[i].id) {
+                               rc = tm6000_load_std(dev, composite_stds[i].common);
+                               goto ret;
+                       }
+               }
+               return -EINVAL;
+       }
+
+ret:
+       if (rc < 0)
+               return rc;
+
+       if ((dev->dev_type == TM6010) &&
+           ((input->amux == TM6000_AMUX_SIF1) ||
+           (input->amux == TM6000_AMUX_SIF2)))
+               tm6000_set_audio_std(dev);
+
+       msleep(40);
+
+       return 0;
+}
diff --git a/drivers/media/video/tm6000/tm6000-usb-isoc.h b/drivers/media/video/tm6000/tm6000-usb-isoc.h
new file mode 100644 (file)
index 0000000..99d15a5
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.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 version 2
+ *
+ *  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/videodev2.h>
+
+#define TM6000_URB_MSG_LEN 180
+
+struct usb_isoc_ctl {
+               /* max packet size of isoc transaction */
+       int                             max_pkt_size;
+
+               /* number of allocated urbs */
+       int                             num_bufs;
+
+               /* urb for isoc transfers */
+       struct urb                      **urb;
+
+               /* transfer buffers for isoc transfer */
+       char                            **transfer_buffer;
+
+               /* Last buffer command and region */
+       u8                              cmd;
+       int                             pos, size, pktsize;
+
+               /* Last field: ODD or EVEN? */
+       int                             vfield, field;
+
+               /* Stores incomplete commands */
+       u32                             tmp_buf;
+       int                             tmp_buf_len;
+
+               /* Stores already requested buffers */
+       struct tm6000_buffer            *buf;
+};
diff --git a/drivers/media/video/tm6000/tm6000-video.c b/drivers/media/video/tm6000/tm6000-video.c
new file mode 100644 (file)
index 0000000..1e5ace0
--- /dev/null
@@ -0,0 +1,1813 @@
+/*
+ *   tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ *     - Fixed module load/unload
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation version 2
+ *
+ *  This program is distributed 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/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/random.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ioctl.h>
+#include <media/tuner.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/highmem.h>
+#include <linux/freezer.h>
+
+#include "tm6000-regs.h"
+#include "tm6000.h"
+
+#define BUFFER_TIMEOUT     msecs_to_jiffies(2000)  /* 2 seconds */
+
+/* Limits minimum and default number of buffers */
+#define TM6000_MIN_BUF 4
+#define TM6000_DEF_BUF 8
+
+#define TM6000_MAX_ISO_PACKETS 46      /* Max number of ISO packets */
+
+/* Declare static vars that will be used as parameters */
+static unsigned int vid_limit = 16;    /* Video memory limit, in Mb */
+static int video_nr = -1;              /* /dev/videoN, -1 for autodetect */
+static int radio_nr = -1;              /* /dev/radioN, -1 for autodetect */
+
+/* Debug level */
+int tm6000_debug;
+EXPORT_SYMBOL_GPL(tm6000_debug);
+
+static const struct v4l2_queryctrl no_ctrl = {
+       .name  = "42",
+       .flags = V4L2_CTRL_FLAG_DISABLED,
+};
+
+/* supported controls */
+static struct v4l2_queryctrl tm6000_qctrl[] = {
+       {
+               .id            = V4L2_CID_BRIGHTNESS,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Brightness",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = 54,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_CONTRAST,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Contrast",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 0x1,
+               .default_value = 119,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_SATURATION,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Saturation",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 0x1,
+               .default_value = 112,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_HUE,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Hue",
+               .minimum       = -128,
+               .maximum       = 127,
+               .step          = 0x1,
+               .default_value = 0,
+               .flags         = 0,
+       },
+               /* --- audio --- */
+       {
+               .id            = V4L2_CID_AUDIO_MUTE,
+               .name          = "Mute",
+               .minimum       = 0,
+               .maximum       = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       }, {
+               .id            = V4L2_CID_AUDIO_VOLUME,
+               .name          = "Volume",
+               .minimum       = -15,
+               .maximum       = 15,
+               .step          = 1,
+               .default_value = 0,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       }
+};
+
+static const unsigned int CTRLS = ARRAY_SIZE(tm6000_qctrl);
+static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];
+
+static struct tm6000_fmt format[] = {
+       {
+               .name     = "4:2:2, packed, YVY2",
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .depth    = 16,
+       }, {
+               .name     = "4:2:2, packed, UYVY",
+               .fourcc   = V4L2_PIX_FMT_UYVY,
+               .depth    = 16,
+       }, {
+               .name     = "A/V + VBI mux packet",
+               .fourcc   = V4L2_PIX_FMT_TM6000,
+               .depth    = 16,
+       }
+};
+
+static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id)
+{
+       unsigned int i;
+
+       for (i = 0; i < CTRLS; i++)
+               if (tm6000_qctrl[i].id == id)
+                       return tm6000_qctrl+i;
+       return NULL;
+}
+
+/* ------------------------------------------------------------------
+ *     DMA and thread functions
+ * ------------------------------------------------------------------
+ */
+
+#define norm_maxw(a) 720
+#define norm_maxh(a) 576
+
+#define norm_minw(a) norm_maxw(a)
+#define norm_minh(a) norm_maxh(a)
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
+                              struct tm6000_buffer   **buf)
+{
+       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+       char *outp;
+
+       if (list_empty(&dma_q->active)) {
+               dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n");
+               *buf = NULL;
+               return;
+       }
+
+       *buf = list_entry(dma_q->active.next,
+                       struct tm6000_buffer, vb.queue);
+
+       /* Cleans up buffer - Useful for testing for frame/URB loss */
+       outp = videobuf_to_vmalloc(&(*buf)->vb);
+
+       return;
+}
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct tm6000_core *dev,
+                                struct tm6000_dmaqueue *dma_q,
+                                struct tm6000_buffer *buf)
+{
+       /* Advice that buffer was filled */
+       dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i);
+       buf->vb.state = VIDEOBUF_DONE;
+       buf->vb.field_count++;
+       do_gettimeofday(&buf->vb.ts);
+
+       list_del(&buf->vb.queue);
+       wake_up(&buf->vb.done);
+}
+
+/*
+ * Identify the tm5600/6000 buffer header type and properly handles
+ */
+static int copy_streams(u8 *data, unsigned long len,
+                       struct urb *urb)
+{
+       struct tm6000_dmaqueue  *dma_q = urb->context;
+       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+       u8 *ptr = data, *endp = data+len, c;
+       unsigned long header = 0;
+       int rc = 0;
+       unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
+       struct tm6000_buffer *vbuf = NULL;
+       char *voutp = NULL;
+       unsigned int linewidth;
+
+       if (!dev->radio) {
+               /* get video buffer */
+               get_next_buf(dma_q, &vbuf);
+
+               if (!vbuf)
+                       return rc;
+               voutp = videobuf_to_vmalloc(&vbuf->vb);
+
+               if (!voutp)
+                       return 0;
+       }
+
+       for (ptr = data; ptr < endp;) {
+               if (!dev->isoc_ctl.cmd) {
+                       /* Header */
+                       if (dev->isoc_ctl.tmp_buf_len > 0) {
+                               /* from last urb or packet */
+                               header = dev->isoc_ctl.tmp_buf;
+                               if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
+                                       memcpy((u8 *)&header +
+                                               dev->isoc_ctl.tmp_buf_len,
+                                               ptr,
+                                               4 - dev->isoc_ctl.tmp_buf_len);
+                                       ptr += 4 - dev->isoc_ctl.tmp_buf_len;
+                               }
+                               dev->isoc_ctl.tmp_buf_len = 0;
+                       } else {
+                               if (ptr + 3 >= endp) {
+                                       /* have incomplete header */
+                                       dev->isoc_ctl.tmp_buf_len = endp - ptr;
+                                       memcpy(&dev->isoc_ctl.tmp_buf, ptr,
+                                               dev->isoc_ctl.tmp_buf_len);
+                                       return rc;
+                               }
+                               /* Seek for sync */
+                               for (; ptr < endp - 3; ptr++) {
+                                       if (*(ptr + 3) == 0x47)
+                                               break;
+                               }
+                               /* Get message header */
+                               header = *(unsigned long *)ptr;
+                               ptr += 4;
+                       }
+
+                       /* split the header fields */
+                       c = (header >> 24) & 0xff;
+                       size = ((header & 0x7e) << 1);
+                       if (size > 0)
+                               size -= 4;
+                       block = (header >> 7) & 0xf;
+                       field = (header >> 11) & 0x1;
+                       line  = (header >> 12) & 0x1ff;
+                       cmd   = (header >> 21) & 0x7;
+                       /* Validates haeder fields */
+                       if (size > TM6000_URB_MSG_LEN)
+                               size = TM6000_URB_MSG_LEN;
+                       pktsize = TM6000_URB_MSG_LEN;
+                       /*
+                        * calculate position in buffer and change the buffer
+                        */
+                       switch (cmd) {
+                       case TM6000_URB_MSG_VIDEO:
+                               if (!dev->radio) {
+                                       if ((dev->isoc_ctl.vfield != field) &&
+                                               (field == 1)) {
+                                               /*
+                                                * Announces that a new buffer
+                                                * were filled
+                                                */
+                                               buffer_filled(dev, dma_q, vbuf);
+                                               dprintk(dev, V4L2_DEBUG_ISOC,
+                                                       "new buffer filled\n");
+                                               get_next_buf(dma_q, &vbuf);
+                                               if (!vbuf)
+                                                       return rc;
+                                               voutp = videobuf_to_vmalloc(&vbuf->vb);
+                                               if (!voutp)
+                                                       return rc;
+                                               memset(voutp, 0, vbuf->vb.size);
+                                       }
+                                       linewidth = vbuf->vb.width << 1;
+                                       pos = ((line << 1) - field - 1) *
+                                       linewidth + block * TM6000_URB_MSG_LEN;
+                                       /* Don't allow to write out of the buffer */
+                                       if (pos + size > vbuf->vb.size)
+                                               cmd = TM6000_URB_MSG_ERR;
+                                       dev->isoc_ctl.vfield = field;
+                               }
+                               break;
+                       case TM6000_URB_MSG_VBI:
+                               break;
+                       case TM6000_URB_MSG_AUDIO:
+                       case TM6000_URB_MSG_PTS:
+                               size = pktsize; /* Size is always 180 bytes */
+                               break;
+                       }
+               } else {
+                       /* Continue the last copy */
+                       cmd = dev->isoc_ctl.cmd;
+                       size = dev->isoc_ctl.size;
+                       pos = dev->isoc_ctl.pos;
+                       pktsize = dev->isoc_ctl.pktsize;
+                       field = dev->isoc_ctl.field;
+               }
+               cpysize = (endp - ptr > size) ? size : endp - ptr;
+               if (cpysize) {
+                       /* copy data in different buffers */
+                       switch (cmd) {
+                       case TM6000_URB_MSG_VIDEO:
+                               /* Fills video buffer */
+                               if (vbuf)
+                                       memcpy(&voutp[pos], ptr, cpysize);
+                               break;
+                       case TM6000_URB_MSG_AUDIO: {
+                               int i;
+                               for (i = 0; i < cpysize; i += 2)
+                                       swab16s((u16 *)(ptr + i));
+
+                               tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize);
+                               break;
+                       }
+                       case TM6000_URB_MSG_VBI:
+                               /* Need some code to copy vbi buffer */
+                               break;
+                       case TM6000_URB_MSG_PTS: {
+                               /* Need some code to copy pts */
+                               u32 pts;
+                               pts = *(u32 *)ptr;
+                               dprintk(dev, V4L2_DEBUG_ISOC, "field %d, PTS %x",
+                                       field, pts);
+                               break;
+                       }
+                       }
+               }
+               if (ptr + pktsize > endp) {
+                       /*
+                        * End of URB packet, but cmd processing is not
+                        * complete. Preserve the state for a next packet
+                        */
+                       dev->isoc_ctl.pos = pos + cpysize;
+                       dev->isoc_ctl.size = size - cpysize;
+                       dev->isoc_ctl.cmd = cmd;
+                       dev->isoc_ctl.field = field;
+                       dev->isoc_ctl.pktsize = pktsize - (endp - ptr);
+                       ptr += endp - ptr;
+               } else {
+                       dev->isoc_ctl.cmd = 0;
+                       ptr += pktsize;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Identify the tm5600/6000 buffer header type and properly handles
+ */
+static int copy_multiplexed(u8 *ptr, unsigned long len,
+                       struct urb *urb)
+{
+       struct tm6000_dmaqueue  *dma_q = urb->context;
+       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+       unsigned int pos = dev->isoc_ctl.pos, cpysize;
+       int rc = 1;
+       struct tm6000_buffer *buf;
+       char *outp = NULL;
+
+       get_next_buf(dma_q, &buf);
+       if (buf)
+               outp = videobuf_to_vmalloc(&buf->vb);
+
+       if (!outp)
+               return 0;
+
+       while (len > 0) {
+               cpysize = min(len, buf->vb.size-pos);
+               memcpy(&outp[pos], ptr, cpysize);
+               pos += cpysize;
+               ptr += cpysize;
+               len -= cpysize;
+               if (pos >= buf->vb.size) {
+                       pos = 0;
+                       /* Announces that a new buffer were filled */
+                       buffer_filled(dev, dma_q, buf);
+                       dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
+                       get_next_buf(dma_q, &buf);
+                       if (!buf)
+                               break;
+                       outp = videobuf_to_vmalloc(&(buf->vb));
+                       if (!outp)
+                               return rc;
+                       pos = 0;
+               }
+       }
+
+       dev->isoc_ctl.pos = pos;
+       return rc;
+}
+
+static inline void print_err_status(struct tm6000_core *dev,
+                                    int packet, int status)
+{
+       char *errmsg = "Unknown";
+
+       switch (status) {
+       case -ENOENT:
+               errmsg = "unlinked synchronuously";
+               break;
+       case -ECONNRESET:
+               errmsg = "unlinked asynchronuously";
+               break;
+       case -ENOSR:
+               errmsg = "Buffer error (overrun)";
+               break;
+       case -EPIPE:
+               errmsg = "Stalled (device not responding)";
+               break;
+       case -EOVERFLOW:
+               errmsg = "Babble (bad cable?)";
+               break;
+       case -EPROTO:
+               errmsg = "Bit-stuff error (bad cable?)";
+               break;
+       case -EILSEQ:
+               errmsg = "CRC/Timeout (could be anything)";
+               break;
+       case -ETIME:
+               errmsg = "Device does not respond";
+               break;
+       }
+       if (packet < 0) {
+               dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
+                       status, errmsg);
+       } else {
+               dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n",
+                       packet, status, errmsg);
+       }
+}
+
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int tm6000_isoc_copy(struct urb *urb)
+{
+       struct tm6000_dmaqueue  *dma_q = urb->context;
+       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+       int i, len = 0, rc = 1, status;
+       char *p;
+
+       if (urb->status < 0) {
+               print_err_status(dev, -1, urb->status);
+               return 0;
+       }
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               status = urb->iso_frame_desc[i].status;
+
+               if (status < 0) {
+                       print_err_status(dev, i, status);
+                       continue;
+               }
+
+               len = urb->iso_frame_desc[i].actual_length;
+
+               if (len > 0) {
+                       p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+                       if (!urb->iso_frame_desc[i].status) {
+                               if ((dev->fourcc) == V4L2_PIX_FMT_TM6000) {
+                                       rc = copy_multiplexed(p, len, urb);
+                                       if (rc <= 0)
+                                               return rc;
+                               } else {
+                                       copy_streams(p, len, urb);
+                               }
+                       }
+               }
+       }
+       return rc;
+}
+
+/* ------------------------------------------------------------------
+ *     URB control
+ * ------------------------------------------------------------------
+ */
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void tm6000_irq_callback(struct urb *urb)
+{
+       struct tm6000_dmaqueue  *dma_q = urb->context;
+       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+       int i;
+
+       switch (urb->status) {
+       case 0:
+       case -ETIMEDOUT:
+               break;
+
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+
+       default:
+               tm6000_err("urb completion error %d.\n", urb->status);
+               break;
+       }
+
+       spin_lock(&dev->slock);
+       tm6000_isoc_copy(urb);
+       spin_unlock(&dev->slock);
+
+       /* Reset urb buffers */
+       for (i = 0; i < urb->number_of_packets; i++) {
+               urb->iso_frame_desc[i].status = 0;
+               urb->iso_frame_desc[i].actual_length = 0;
+       }
+
+       urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (urb->status)
+               tm6000_err("urb resubmit failed (error=%i)\n",
+                       urb->status);
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+static void tm6000_uninit_isoc(struct tm6000_core *dev)
+{
+       struct urb *urb;
+       int i;
+
+       dev->isoc_ctl.buf = NULL;
+       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+               urb = dev->isoc_ctl.urb[i];
+               if (urb) {
+                       usb_kill_urb(urb);
+                       usb_unlink_urb(urb);
+                       if (dev->isoc_ctl.transfer_buffer[i]) {
+                               usb_free_coherent(dev->udev,
+                                               urb->transfer_buffer_length,
+                                               dev->isoc_ctl.transfer_buffer[i],
+                                               urb->transfer_dma);
+                       }
+                       usb_free_urb(urb);
+                       dev->isoc_ctl.urb[i] = NULL;
+               }
+               dev->isoc_ctl.transfer_buffer[i] = NULL;
+       }
+
+       kfree(dev->isoc_ctl.urb);
+       kfree(dev->isoc_ctl.transfer_buffer);
+
+       dev->isoc_ctl.urb = NULL;
+       dev->isoc_ctl.transfer_buffer = NULL;
+       dev->isoc_ctl.num_bufs = 0;
+}
+
+/*
+ * Allocate URBs and start IRQ
+ */
+static int tm6000_prepare_isoc(struct tm6000_core *dev)
+{
+       struct tm6000_dmaqueue *dma_q = &dev->vidq;
+       int i, j, sb_size, pipe, size, max_packets, num_bufs = 8;
+       struct urb *urb;
+
+       /* De-allocates all pending stuff */
+       tm6000_uninit_isoc(dev);
+       /* Stop interrupt USB pipe */
+       tm6000_ir_int_stop(dev);
+
+       usb_set_interface(dev->udev,
+                         dev->isoc_in.bInterfaceNumber,
+                         dev->isoc_in.bAlternateSetting);
+
+       /* Start interrupt USB pipe */
+       tm6000_ir_int_start(dev);
+
+       pipe = usb_rcvisocpipe(dev->udev,
+                              dev->isoc_in.endp->desc.bEndpointAddress &
+                              USB_ENDPOINT_NUMBER_MASK);
+
+       size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+
+       if (size > dev->isoc_in.maxsize)
+               size = dev->isoc_in.maxsize;
+
+       dev->isoc_ctl.max_pkt_size = size;
+
+       max_packets = TM6000_MAX_ISO_PACKETS;
+       sb_size = max_packets * size;
+
+       dev->isoc_ctl.num_bufs = num_bufs;
+
+       dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+       if (!dev->isoc_ctl.urb) {
+               tm6000_err("cannot alloc memory for usb buffers\n");
+               return -ENOMEM;
+       }
+
+       dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs,
+                                  GFP_KERNEL);
+       if (!dev->isoc_ctl.transfer_buffer) {
+               tm6000_err("cannot allocate memory for usbtransfer\n");
+               kfree(dev->isoc_ctl.urb);
+               return -ENOMEM;
+       }
+
+       dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets"
+                   " (%d bytes) of %d bytes each to handle %u size\n",
+                   max_packets, num_bufs, sb_size,
+                   dev->isoc_in.maxsize, size);
+
+       /* allocate urbs and transfer buffers */
+       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+               urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+               if (!urb) {
+                       tm6000_err("cannot alloc isoc_ctl.urb %i\n", i);
+                       tm6000_uninit_isoc(dev);
+                       usb_free_urb(urb);
+                       return -ENOMEM;
+               }
+               dev->isoc_ctl.urb[i] = urb;
+
+               dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
+                       sb_size, GFP_KERNEL, &urb->transfer_dma);
+               if (!dev->isoc_ctl.transfer_buffer[i]) {
+                       tm6000_err("unable to allocate %i bytes for transfer"
+                                       " buffer %i%s\n",
+                                       sb_size, i,
+                                       in_interrupt() ? " while in int" : "");
+                       tm6000_uninit_isoc(dev);
+                       return -ENOMEM;
+               }
+               memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+               usb_fill_bulk_urb(urb, dev->udev, pipe,
+                                 dev->isoc_ctl.transfer_buffer[i], sb_size,
+                                 tm6000_irq_callback, dma_q);
+               urb->interval = dev->isoc_in.endp->desc.bInterval;
+               urb->number_of_packets = max_packets;
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+
+               for (j = 0; j < max_packets; j++) {
+                       urb->iso_frame_desc[j].offset = size * j;
+                       urb->iso_frame_desc[j].length = size;
+               }
+       }
+
+       return 0;
+}
+
+static int tm6000_start_thread(struct tm6000_core *dev)
+{
+       struct tm6000_dmaqueue *dma_q = &dev->vidq;
+       int i;
+
+       dma_q->frame = 0;
+       dma_q->ini_jiffies = jiffies;
+
+       init_waitqueue_head(&dma_q->wq);
+
+       /* submit urbs and enables IRQ */
+       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+               int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+               if (rc) {
+                       tm6000_err("submit of urb %i failed (error=%i)\n", i,
+                                  rc);
+                       tm6000_uninit_isoc(dev);
+                       return rc;
+               }
+       }
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------
+ *     Videobuf operations
+ * ------------------------------------------------------------------
+ */
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+       struct tm6000_fh *fh = vq->priv_data;
+
+       *size = fh->fmt->depth * fh->width * fh->height >> 3;
+       if (0 == *count)
+               *count = TM6000_DEF_BUF;
+
+       if (*count < TM6000_MIN_BUF)
+               *count = TM6000_MIN_BUF;
+
+       while (*size * *count > vid_limit * 1024 * 1024)
+               (*count)--;
+
+       return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf)
+{
+       struct tm6000_fh *fh = vq->priv_data;
+       struct tm6000_core   *dev = fh->dev;
+       unsigned long flags;
+
+       if (in_interrupt())
+               BUG();
+
+       /* We used to wait for the buffer to finish here, but this didn't work
+          because, as we were keeping the state as VIDEOBUF_QUEUED,
+          videobuf_queue_cancel marked it as finished for us.
+          (Also, it could wedge forever if the hardware was misconfigured.)
+
+          This should be safe; by the time we get here, the buffer isn't
+          queued anymore. If we ever start marking the buffers as
+          VIDEOBUF_ACTIVE, it won't be, though.
+       */
+       spin_lock_irqsave(&dev->slock, flags);
+       if (dev->isoc_ctl.buf == buf)
+               dev->isoc_ctl.buf = NULL;
+       spin_unlock_irqrestore(&dev->slock, flags);
+
+       videobuf_vmalloc_free(&buf->vb);
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+                                               enum v4l2_field field)
+{
+       struct tm6000_fh     *fh  = vq->priv_data;
+       struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
+       struct tm6000_core   *dev = fh->dev;
+       int rc = 0;
+
+       BUG_ON(NULL == fh->fmt);
+
+
+       /* FIXME: It assumes depth=2 */
+       /* The only currently supported format is 16 bits/pixel */
+       buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3;
+       if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+               return -EINVAL;
+
+       if (buf->fmt       != fh->fmt    ||
+           buf->vb.width  != fh->width  ||
+           buf->vb.height != fh->height ||
+           buf->vb.field  != field) {
+               buf->fmt       = fh->fmt;
+               buf->vb.width  = fh->width;
+               buf->vb.height = fh->height;
+               buf->vb.field  = field;
+               buf->vb.state = VIDEOBUF_NEEDS_INIT;
+       }
+
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+               rc = videobuf_iolock(vq, &buf->vb, NULL);
+               if (rc != 0)
+                       goto fail;
+       }
+
+       if (!dev->isoc_ctl.num_bufs) {
+               rc = tm6000_prepare_isoc(dev);
+               if (rc < 0)
+                       goto fail;
+
+               rc = tm6000_start_thread(dev);
+               if (rc < 0)
+                       goto fail;
+
+       }
+
+       buf->vb.state = VIDEOBUF_PREPARED;
+       return 0;
+
+fail:
+       free_buffer(vq, buf);
+       return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct tm6000_buffer    *buf     = container_of(vb, struct tm6000_buffer, vb);
+       struct tm6000_fh        *fh      = vq->priv_data;
+       struct tm6000_core      *dev     = fh->dev;
+       struct tm6000_dmaqueue  *vidq    = &dev->vidq;
+
+       buf->vb.state = VIDEOBUF_QUEUED;
+       list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct tm6000_buffer   *buf  = container_of(vb, struct tm6000_buffer, vb);
+
+       free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops tm6000_video_qops = {
+       .buf_setup      = buffer_setup,
+       .buf_prepare    = buffer_prepare,
+       .buf_queue      = buffer_queue,
+       .buf_release    = buffer_release,
+};
+
+/* ------------------------------------------------------------------
+ *     IOCTL handling
+ * ------------------------------------------------------------------
+ */
+
+static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+       /* Is the current fh handling it? if so, that's OK */
+       if (dev->resources == fh && dev->is_res_read)
+               return true;
+
+       return false;
+}
+
+static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+       /* Is the current fh handling it? if so, that's OK */
+       if (dev->resources == fh)
+               return true;
+
+       return false;
+}
+
+static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh,
+                  bool is_res_read)
+{
+       /* Is the current fh handling it? if so, that's OK */
+       if (dev->resources == fh && dev->is_res_read == is_res_read)
+               return true;
+
+       /* is it free? */
+       if (dev->resources)
+               return false;
+
+       /* grab it */
+       dev->resources = fh;
+       dev->is_res_read = is_res_read;
+       dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
+       return true;
+}
+
+static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+       /* Is the current fh handling it? if so, that's OK */
+       if (dev->resources != fh)
+               return;
+
+       dev->resources = NULL;
+       dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");
+}
+
+/* ------------------------------------------------------------------
+ *     IOCTL vidioc handling
+ * ------------------------------------------------------------------
+ */
+static int vidioc_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
+
+       strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
+       strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
+       cap->version = TM6000_VERSION;
+       cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_STREAMING     |
+                               V4L2_CAP_AUDIO         |
+                               V4L2_CAP_READWRITE;
+
+       if (dev->tuner_type != TUNER_ABSENT)
+               cap->capabilities |= V4L2_CAP_TUNER;
+
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (unlikely(f->index >= ARRAY_SIZE(format)))
+               return -EINVAL;
+
+       strlcpy(f->description, format[f->index].name, sizeof(f->description));
+       f->pixelformat = format[f->index].fourcc;
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct tm6000_fh  *fh = priv;
+
+       f->fmt.pix.width        = fh->width;
+       f->fmt.pix.height       = fh->height;
+       f->fmt.pix.field        = fh->vb_vidq.field;
+       f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fh->fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+       return 0;
+}
+
+static struct tm6000_fmt *format_by_fourcc(unsigned int fourcc)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(format); i++)
+               if (format[i].fourcc == fourcc)
+                       return format+i;
+       return NULL;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
+       struct tm6000_fmt *fmt;
+       enum v4l2_field field;
+
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (NULL == fmt) {
+               dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)"
+                               " invalid.\n", f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
+
+       field = f->fmt.pix.field;
+
+       if (field == V4L2_FIELD_ANY)
+               field = V4L2_FIELD_SEQ_TB;
+       else if (V4L2_FIELD_INTERLACED != field) {
+               dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n");
+               return -EINVAL;
+       }
+
+       tm6000_get_std_res(dev);
+
+       f->fmt.pix.width  = dev->width;
+       f->fmt.pix.height = dev->height;
+
+       f->fmt.pix.width &= ~0x01;
+
+       f->fmt.pix.field = field;
+
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+       return 0;
+}
+
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct tm6000_fh  *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+       int ret = vidioc_try_fmt_vid_cap(file, fh, f);
+       if (ret < 0)
+               return ret;
+
+       fh->fmt           = format_by_fourcc(f->fmt.pix.pixelformat);
+       fh->width         = f->fmt.pix.width;
+       fh->height        = f->fmt.pix.height;
+       fh->vb_vidq.field = f->fmt.pix.field;
+       fh->type          = f->type;
+
+       dev->fourcc       = f->fmt.pix.pixelformat;
+
+       tm6000_set_fourcc_format(dev);
+
+       return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                          struct v4l2_requestbuffers *p)
+{
+       struct tm6000_fh  *fh = priv;
+
+       return videobuf_reqbufs(&fh->vb_vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+                           struct v4l2_buffer *p)
+{
+       struct tm6000_fh  *fh = priv;
+
+       return videobuf_querybuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct tm6000_fh  *fh = priv;
+
+       return videobuf_qbuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct tm6000_fh  *fh = priv;
+
+       return videobuf_dqbuf(&fh->vb_vidq, p,
+                               file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct tm6000_fh *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (i != fh->type)
+               return -EINVAL;
+
+       if (!res_get(dev, fh, false))
+               return -EBUSY;
+       return videobuf_streamon(&fh->vb_vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct tm6000_fh *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (i != fh->type)
+               return -EINVAL;
+
+       videobuf_streamoff(&fh->vb_vidq);
+       res_free(dev, fh);
+
+       return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+       int rc = 0;
+       struct tm6000_fh *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       dev->norm = *norm;
+       rc = tm6000_init_analog_mode(dev);
+
+       fh->width  = dev->width;
+       fh->height = dev->height;
+
+       if (rc < 0)
+               return rc;
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+
+       return 0;
+}
+
+static const char *iname[] = {
+       [TM6000_INPUT_TV] = "Television",
+       [TM6000_INPUT_COMPOSITE1] = "Composite 1",
+       [TM6000_INPUT_COMPOSITE2] = "Composite 2",
+       [TM6000_INPUT_SVIDEO] = "S-Video",
+};
+
+static int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *i)
+{
+       struct tm6000_fh   *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+       unsigned int n;
+
+       n = i->index;
+       if (n >= 3)
+               return -EINVAL;
+
+       if (!dev->vinput[n].type)
+               return -EINVAL;
+
+       i->index = n;
+
+       if (dev->vinput[n].type == TM6000_INPUT_TV)
+               i->type = V4L2_INPUT_TYPE_TUNER;
+       else
+               i->type = V4L2_INPUT_TYPE_CAMERA;
+
+       strcpy(i->name, iname[dev->vinput[n].type]);
+
+       i->std = TM6000_STD;
+
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct tm6000_fh   *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       *i = dev->input;
+
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct tm6000_fh   *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+       int rc = 0;
+
+       if (i >= 3)
+               return -EINVAL;
+       if (!dev->vinput[i].type)
+               return -EINVAL;
+
+       dev->input = i;
+
+       rc = vidioc_s_std(file, priv, &dev->vfd->current_norm);
+
+       return rc;
+}
+
+/* --- controls ---------------------------------------------- */
+static int vidioc_queryctrl(struct file *file, void *priv,
+                               struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
+               if (qc->id && qc->id == tm6000_qctrl[i].id) {
+                       memcpy(qc, &(tm6000_qctrl[i]),
+                               sizeof(*qc));
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct tm6000_fh  *fh = priv;
+       struct tm6000_core *dev    = fh->dev;
+       int  val;
+
+       /* FIXME: Probably, those won't work! Maybe we need shadow regs */
+       switch (ctrl->id) {
+       case V4L2_CID_CONTRAST:
+               val = tm6000_get_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0);
+               break;
+       case V4L2_CID_BRIGHTNESS:
+               val = tm6000_get_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0);
+               return 0;
+       case V4L2_CID_SATURATION:
+               val = tm6000_get_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0);
+               return 0;
+       case V4L2_CID_HUE:
+               val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0);
+               return 0;
+       case V4L2_CID_AUDIO_MUTE:
+               val = dev->ctl_mute;
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+               val = dev->ctl_volume;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       if (val < 0)
+               return val;
+
+       ctrl->value = val;
+
+       return 0;
+}
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct tm6000_fh   *fh  = priv;
+       struct tm6000_core *dev = fh->dev;
+       u8  val = ctrl->value;
+
+       switch (ctrl->id) {
+       case V4L2_CID_CONTRAST:
+               tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
+               return 0;
+       case V4L2_CID_BRIGHTNESS:
+               tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
+               return 0;
+       case V4L2_CID_SATURATION:
+               tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
+               return 0;
+       case V4L2_CID_HUE:
+               tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
+               return 0;
+       case V4L2_CID_AUDIO_MUTE:
+               dev->ctl_mute = val;
+               tm6000_tvaudio_set_mute(dev, val);
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+               dev->ctl_volume = val;
+               tm6000_set_volume(dev, val);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct tm6000_fh   *fh  = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       if (unlikely(UNSET == dev->tuner_type))
+               return -EINVAL;
+       if (0 != t->index)
+               return -EINVAL;
+
+       strcpy(t->name, "Television");
+       t->type       = V4L2_TUNER_ANALOG_TV;
+       t->capability = V4L2_TUNER_CAP_NORM;
+       t->rangehigh  = 0xffffffffUL;
+       t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+
+       t->audmode = dev->amode;
+
+       return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct tm6000_fh   *fh  = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       if (UNSET == dev->tuner_type)
+               return -EINVAL;
+       if (0 != t->index)
+               return -EINVAL;
+
+       dev->amode = t->audmode;
+       dprintk(dev, 3, "audio mode: %x\n", t->audmode);
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+
+       return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct tm6000_fh   *fh  = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       if (unlikely(UNSET == dev->tuner_type))
+               return -EINVAL;
+
+       f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       f->frequency = dev->freq;
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
+
+       return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct tm6000_fh   *fh  = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       if (unlikely(UNSET == dev->tuner_type))
+               return -EINVAL;
+       if (unlikely(f->tuner != 0))
+               return -EINVAL;
+       if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
+               return -EINVAL;
+       if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
+               return -EINVAL;
+
+       dev->freq = f->frequency;
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
+
+       return 0;
+}
+
+static int radio_querycap(struct file *file, void *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct tm6000_fh *fh = file->private_data;
+       struct tm6000_core *dev = fh->dev;
+
+       strcpy(cap->driver, "tm6000");
+       strlcpy(cap->card, dev->name, sizeof(dev->name));
+       sprintf(cap->bus_info, "USB%04x:%04x",
+               le16_to_cpu(dev->udev->descriptor.idVendor),
+               le16_to_cpu(dev->udev->descriptor.idProduct));
+       cap->version = dev->dev_type;
+       cap->capabilities = V4L2_CAP_TUNER |
+                       V4L2_CAP_AUDIO     |
+                       V4L2_CAP_RADIO     |
+                       V4L2_CAP_READWRITE |
+                       V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+static int radio_g_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct tm6000_fh *fh = file->private_data;
+       struct tm6000_core *dev = fh->dev;
+
+       if (0 != t->index)
+               return -EINVAL;
+
+       memset(t, 0, sizeof(*t));
+       strcpy(t->name, "Radio");
+       t->type = V4L2_TUNER_RADIO;
+       t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+
+       return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct tm6000_fh *fh = file->private_data;
+       struct tm6000_core *dev = fh->dev;
+
+       if (0 != t->index)
+               return -EINVAL;
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+
+       return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv,
+                                       struct v4l2_input *i)
+{
+       struct tm6000_fh *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       if (i->index != 0)
+               return -EINVAL;
+
+       if (!dev->rinput.type)
+               return -EINVAL;
+
+       strcpy(i->name, "Radio");
+       i->type = V4L2_INPUT_TYPE_TUNER;
+
+       return 0;
+}
+
+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       struct tm6000_fh *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       if (dev->input != 5)
+               return -EINVAL;
+
+       *i = dev->input - 5;
+
+       return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       memset(a, 0, sizeof(*a));
+       strcpy(a->name, "Radio");
+       return 0;
+}
+
+static int radio_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       return 0;
+}
+
+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       struct tm6000_fh *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       if (i)
+               return -EINVAL;
+
+       if (!dev->rinput.type)
+               return -EINVAL;
+
+       dev->input = i + 5;
+
+       return 0;
+}
+
+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+       return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+                                       struct v4l2_queryctrl *c)
+{
+       const struct v4l2_queryctrl *ctrl;
+
+       if (c->id <  V4L2_CID_BASE ||
+           c->id >= V4L2_CID_LASTP1)
+               return -EINVAL;
+       if (c->id == V4L2_CID_AUDIO_MUTE) {
+               ctrl = ctrl_by_id(c->id);
+               *c = *ctrl;
+       } else
+               *c = no_ctrl;
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------
+       File operations for the device
+   ------------------------------------------------------------------*/
+
+static int tm6000_open(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct tm6000_core *dev = video_drvdata(file);
+       struct tm6000_fh *fh;
+       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       int i, rc;
+       int radio = 0;
+
+       dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n",
+               video_device_node_name(vdev));
+
+       switch (vdev->vfl_type) {
+       case VFL_TYPE_GRABBER:
+               type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               break;
+       case VFL_TYPE_VBI:
+               type = V4L2_BUF_TYPE_VBI_CAPTURE;
+               break;
+       case VFL_TYPE_RADIO:
+               radio = 1;
+               break;
+       }
+
+       /* If more than one user, mutex should be added */
+       dev->users++;
+
+       dprintk(dev, V4L2_DEBUG_OPEN, "open dev=%s type=%s users=%d\n",
+               video_device_node_name(vdev), v4l2_type_names[type],
+               dev->users);
+
+       /* allocate + initialize per filehandle data */
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (NULL == fh) {
+               dev->users--;
+               return -ENOMEM;
+       }
+
+       file->private_data = fh;
+       fh->dev      = dev;
+       fh->radio    = radio;
+       dev->radio   = radio;
+       fh->type     = type;
+       dev->fourcc  = format[0].fourcc;
+
+       fh->fmt      = format_by_fourcc(dev->fourcc);
+
+       tm6000_get_std_res(dev);
+
+       fh->width = dev->width;
+       fh->height = dev->height;
+
+       dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, "
+                                               "dev->vidq=0x%08lx\n",
+                       (unsigned long)fh, (unsigned long)dev,
+                       (unsigned long)&dev->vidq);
+       dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
+                               "queued=%d\n", list_empty(&dev->vidq.queued));
+       dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
+                               "active=%d\n", list_empty(&dev->vidq.active));
+
+       /* initialize hardware on analog mode */
+       rc = tm6000_init_analog_mode(dev);
+       if (rc < 0)
+               return rc;
+
+       if (dev->mode != TM6000_MODE_ANALOG) {
+               /* Put all controls at a sane state */
+               for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
+                       qctl_regs[i] = tm6000_qctrl[i].default_value;
+
+               dev->mode = TM6000_MODE_ANALOG;
+       }
+
+       if (!fh->radio) {
+               videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops,
+                               NULL, &dev->slock,
+                               fh->type,
+                               V4L2_FIELD_INTERLACED,
+                               sizeof(struct tm6000_buffer), fh, &dev->lock);
+       } else {
+               dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n");
+               dev->input = 5;
+               tm6000_set_audio_rinput(dev);
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
+               tm6000_prepare_isoc(dev);
+               tm6000_start_thread(dev);
+       }
+
+       return 0;
+}
+
+static ssize_t
+tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
+{
+       struct tm6000_fh        *fh = file->private_data;
+
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               if (!res_get(fh->dev, fh, true))
+                       return -EBUSY;
+
+               return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
+                                       file->f_flags & O_NONBLOCK);
+       }
+       return 0;
+}
+
+static unsigned int
+tm6000_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct tm6000_fh        *fh = file->private_data;
+       struct tm6000_buffer    *buf;
+
+       if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+               return POLLERR;
+
+       if (!!is_res_streaming(fh->dev, fh))
+               return POLLERR;
+
+       if (!is_res_read(fh->dev, fh)) {
+               /* streaming capture */
+               if (list_empty(&fh->vb_vidq.stream))
+                       return POLLERR;
+               buf = list_entry(fh->vb_vidq.stream.next, struct tm6000_buffer, vb.stream);
+       } else {
+               /* read() capture */
+               return videobuf_poll_stream(file, &fh->vb_vidq, wait);
+       }
+       poll_wait(file, &buf->vb.done, wait);
+       if (buf->vb.state == VIDEOBUF_DONE ||
+           buf->vb.state == VIDEOBUF_ERROR)
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+static int tm6000_release(struct file *file)
+{
+       struct tm6000_fh         *fh = file->private_data;
+       struct tm6000_core      *dev = fh->dev;
+       struct video_device    *vdev = video_devdata(file);
+
+       dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (dev=%s, users=%d)\n",
+               video_device_node_name(vdev), dev->users);
+
+       dev->users--;
+
+       res_free(dev, fh);
+
+       if (!dev->users) {
+               int err;
+
+               tm6000_uninit_isoc(dev);
+
+               if (!fh->radio)
+                       videobuf_mmap_free(&fh->vb_vidq);
+
+               err = tm6000_reset(dev);
+               if (err < 0)
+                       dev_err(&vdev->dev, "reset failed: %d\n", err);
+       }
+
+       kfree(fh);
+
+       return 0;
+}
+
+static int tm6000_mmap(struct file *file, struct vm_area_struct * vma)
+{
+       struct tm6000_fh *fh = file->private_data;
+
+       return videobuf_mmap_mapper(&fh->vb_vidq, vma);
+}
+
+static struct v4l2_file_operations tm6000_fops = {
+       .owner = THIS_MODULE,
+       .open = tm6000_open,
+       .release = tm6000_release,
+       .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+       .read = tm6000_read,
+       .poll = tm6000_poll,
+       .mmap = tm6000_mmap,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+       .vidioc_querycap          = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+       .vidioc_s_std             = vidioc_s_std,
+       .vidioc_enum_input        = vidioc_enum_input,
+       .vidioc_g_input           = vidioc_g_input,
+       .vidioc_s_input           = vidioc_s_input,
+       .vidioc_queryctrl         = vidioc_queryctrl,
+       .vidioc_g_ctrl            = vidioc_g_ctrl,
+       .vidioc_s_ctrl            = vidioc_s_ctrl,
+       .vidioc_g_tuner           = vidioc_g_tuner,
+       .vidioc_s_tuner           = vidioc_s_tuner,
+       .vidioc_g_frequency       = vidioc_g_frequency,
+       .vidioc_s_frequency       = vidioc_s_frequency,
+       .vidioc_streamon          = vidioc_streamon,
+       .vidioc_streamoff         = vidioc_streamoff,
+       .vidioc_reqbufs           = vidioc_reqbufs,
+       .vidioc_querybuf          = vidioc_querybuf,
+       .vidioc_qbuf              = vidioc_qbuf,
+       .vidioc_dqbuf             = vidioc_dqbuf,
+};
+
+static struct video_device tm6000_template = {
+       .name           = "tm6000",
+       .fops           = &tm6000_fops,
+       .ioctl_ops      = &video_ioctl_ops,
+       .release        = video_device_release,
+       .tvnorms        = TM6000_STD,
+       .current_norm   = V4L2_STD_NTSC_M,
+};
+
+static const struct v4l2_file_operations radio_fops = {
+       .owner          = THIS_MODULE,
+       .open           = tm6000_open,
+       .release        = tm6000_release,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+       .vidioc_querycap        = radio_querycap,
+       .vidioc_g_tuner         = radio_g_tuner,
+       .vidioc_enum_input      = radio_enum_input,
+       .vidioc_g_audio         = radio_g_audio,
+       .vidioc_s_tuner         = radio_s_tuner,
+       .vidioc_s_audio         = radio_s_audio,
+       .vidioc_s_input         = radio_s_input,
+       .vidioc_s_std           = radio_s_std,
+       .vidioc_queryctrl       = radio_queryctrl,
+       .vidioc_g_input         = radio_g_input,
+       .vidioc_g_ctrl          = vidioc_g_ctrl,
+       .vidioc_s_ctrl          = vidioc_s_ctrl,
+       .vidioc_g_frequency     = vidioc_g_frequency,
+       .vidioc_s_frequency     = vidioc_s_frequency,
+};
+
+static struct video_device tm6000_radio_template = {
+       .name                   = "tm6000",
+       .fops                   = &radio_fops,
+       .ioctl_ops              = &radio_ioctl_ops,
+};
+
+/* -----------------------------------------------------------------
+ *     Initialization and module stuff
+ * ------------------------------------------------------------------
+ */
+
+static struct video_device *vdev_init(struct tm6000_core *dev,
+               const struct video_device
+               *template, const char *type_name)
+{
+       struct video_device *vfd;
+
+       vfd = video_device_alloc();
+       if (NULL == vfd)
+               return NULL;
+
+       *vfd = *template;
+       vfd->v4l2_dev = &dev->v4l2_dev;
+       vfd->release = video_device_release;
+       vfd->debug = tm6000_debug;
+       vfd->lock = &dev->lock;
+
+       snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
+
+       video_set_drvdata(vfd, dev);
+       return vfd;
+}
+
+int tm6000_v4l2_register(struct tm6000_core *dev)
+{
+       int ret = -1;
+
+       dev->vfd = vdev_init(dev, &tm6000_template, "video");
+
+       if (!dev->vfd) {
+               printk(KERN_INFO "%s: can't register video device\n",
+                      dev->name);
+               return -ENOMEM;
+       }
+
+       /* init video dma queues */
+       INIT_LIST_HEAD(&dev->vidq.active);
+       INIT_LIST_HEAD(&dev->vidq.queued);
+
+       ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
+
+       if (ret < 0) {
+               printk(KERN_INFO "%s: can't register video device\n",
+                      dev->name);
+               return ret;
+       }
+
+       printk(KERN_INFO "%s: registered device %s\n",
+              dev->name, video_device_node_name(dev->vfd));
+
+       if (dev->caps.has_radio) {
+               dev->radio_dev = vdev_init(dev, &tm6000_radio_template,
+                                                          "radio");
+               if (!dev->radio_dev) {
+                       printk(KERN_INFO "%s: can't register radio device\n",
+                              dev->name);
+                       return ret; /* FIXME release resource */
+               }
+
+               ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+                                           radio_nr);
+               if (ret < 0) {
+                       printk(KERN_INFO "%s: can't register radio device\n",
+                              dev->name);
+                       return ret; /* FIXME release resource */
+               }
+
+               printk(KERN_INFO "%s: registered device %s\n",
+                      dev->name, video_device_node_name(dev->radio_dev));
+       }
+
+       printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
+       return ret;
+}
+
+int tm6000_v4l2_unregister(struct tm6000_core *dev)
+{
+       video_unregister_device(dev->vfd);
+
+       if (dev->radio_dev) {
+               if (video_is_registered(dev->radio_dev))
+                       video_unregister_device(dev->radio_dev);
+               else
+                       video_device_release(dev->radio_dev);
+               dev->radio_dev = NULL;
+       }
+
+       return 0;
+}
+
+int tm6000_v4l2_exit(void)
+{
+       return 0;
+}
+
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr, "Allow changing video device number");
+
+module_param_named(debug, tm6000_debug, int, 0444);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+module_param(vid_limit, int, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+
diff --git a/drivers/media/video/tm6000/tm6000.h b/drivers/media/video/tm6000/tm6000.h
new file mode 100644 (file)
index 0000000..2777e51
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ *  tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ *     - DVB-T support
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation version 2
+ *
+ *  This program is distributed 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/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/videobuf-vmalloc.h>
+#include "tm6000-usb-isoc.h"
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <media/v4l2-device.h>
+
+#include <linux/dvb/frontend.h>
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dmxdev.h"
+
+#define TM6000_VERSION KERNEL_VERSION(0, 0, 2)
+
+/* Inputs */
+enum tm6000_itype {
+       TM6000_INPUT_TV = 1,
+       TM6000_INPUT_COMPOSITE1,
+       TM6000_INPUT_COMPOSITE2,
+       TM6000_INPUT_SVIDEO,
+       TM6000_INPUT_DVB,
+       TM6000_INPUT_RADIO,
+};
+
+enum tm6000_mux {
+       TM6000_VMUX_VIDEO_A = 1,
+       TM6000_VMUX_VIDEO_B,
+       TM6000_VMUX_VIDEO_AB,
+       TM6000_AMUX_ADC1,
+       TM6000_AMUX_ADC2,
+       TM6000_AMUX_SIF1,
+       TM6000_AMUX_SIF2,
+       TM6000_AMUX_I2S,
+};
+
+enum tm6000_devtype {
+       TM6000 = 0,
+       TM5600,
+       TM6010,
+};
+
+struct tm6000_input {
+       enum tm6000_itype       type;
+       enum tm6000_mux         vmux;
+       enum tm6000_mux         amux;
+       unsigned int            v_gpio;
+       unsigned int            a_gpio;
+};
+
+/* ------------------------------------------------------------------
+ *     Basic structures
+ * ------------------------------------------------------------------
+ */
+
+struct tm6000_fmt {
+       char  *name;
+       u32   fourcc;          /* v4l2 format id */
+       int   depth;
+};
+
+/* buffer for one video frame */
+struct tm6000_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct videobuf_buffer vb;
+
+       struct tm6000_fmt      *fmt;
+};
+
+struct tm6000_dmaqueue {
+       struct list_head       active;
+       struct list_head       queued;
+
+       /* thread for generating video stream*/
+       struct task_struct         *kthread;
+       wait_queue_head_t          wq;
+       /* Counters to control fps rate */
+       int                        frame;
+       int                        ini_jiffies;
+};
+
+/* device states */
+enum tm6000_core_state {
+       DEV_INITIALIZED   = 0x01,
+       DEV_DISCONNECTED  = 0x02,
+       DEV_MISCONFIGURED = 0x04,
+};
+
+/* io methods */
+enum tm6000_io_method {
+       IO_NONE,
+       IO_READ,
+       IO_MMAP,
+};
+
+enum tm6000_mode {
+       TM6000_MODE_UNKNOWN = 0,
+       TM6000_MODE_ANALOG,
+       TM6000_MODE_DIGITAL,
+};
+
+struct tm6000_gpio {
+       int             tuner_reset;
+       int             tuner_on;
+       int             demod_reset;
+       int             demod_on;
+       int             power_led;
+       int             dvb_led;
+       int             ir;
+};
+
+struct tm6000_capabilities {
+       unsigned int    has_tuner:1;
+       unsigned int    has_tda9874:1;
+       unsigned int    has_dvb:1;
+       unsigned int    has_zl10353:1;
+       unsigned int    has_eeprom:1;
+       unsigned int    has_remote:1;
+       unsigned int    has_radio:1;
+};
+
+struct tm6000_dvb {
+       struct dvb_adapter      adapter;
+       struct dvb_demux        demux;
+       struct dvb_frontend     *frontend;
+       struct dmxdev           dmxdev;
+       unsigned int            streams;
+       struct urb              *bulk_urb;
+       struct mutex            mutex;
+};
+
+struct snd_tm6000_card {
+       struct snd_card                 *card;
+       spinlock_t                      reg_lock;
+       struct tm6000_core              *core;
+       struct snd_pcm_substream        *substream;
+
+       /* temporary data for buffer fill processing */
+       unsigned                        buf_pos;
+       unsigned                        period_pos;
+};
+
+struct tm6000_endpoint {
+       struct usb_host_endpoint        *endp;
+       __u8                            bInterfaceNumber;
+       __u8                            bAlternateSetting;
+       unsigned                        maxsize;
+};
+
+#define TM6000_QUIRK_NO_USB_DELAY (1 << 0)
+
+struct tm6000_core {
+       /* generic device properties */
+       char                            name[30];       /* name (including minor) of the device */
+       int                             model;          /* index in the device_data struct */
+       int                             devno;          /* marks the number of this device */
+       enum tm6000_devtype             dev_type;       /* type of device */
+       unsigned char                   eedata[256];    /* Eeprom data */
+       unsigned                        eedata_size;    /* Size of the eeprom info */
+
+       v4l2_std_id                     norm;           /* Current norm */
+       int                             width, height;  /* Selected resolution */
+
+       enum tm6000_core_state          state;
+
+       /* Device Capabilities*/
+       struct tm6000_capabilities      caps;
+
+       /* Tuner configuration */
+       int                             tuner_type;             /* type of the tuner */
+       int                             tuner_addr;             /* tuner address */
+
+       struct tm6000_gpio              gpio;
+
+       char                            *ir_codes;
+
+       __u8                            radio;
+
+       /* Demodulator configuration */
+       int                             demod_addr;     /* demodulator address */
+
+       int                             audio_bitrate;
+       /* i2c i/o */
+       struct i2c_adapter              i2c_adap;
+       struct i2c_client               i2c_client;
+
+
+       /* extension */
+       struct list_head                devlist;
+
+       /* video for linux */
+       int                             users;
+
+       /* various device info */
+       struct tm6000_fh                *resources;     /* Points to fh that is streaming */
+       bool                            is_res_read;
+
+       struct video_device             *vfd;
+       struct video_device             *radio_dev;
+       struct tm6000_dmaqueue          vidq;
+       struct v4l2_device              v4l2_dev;
+
+       int                             input;
+       struct tm6000_input             vinput[3];      /* video input */
+       struct tm6000_input             rinput;         /* radio input */
+
+       int                             freq;
+       unsigned int                    fourcc;
+
+       enum tm6000_mode                mode;
+
+       int                             ctl_mute;             /* audio */
+       int                             ctl_volume;
+       int                             amode;
+
+       /* DVB-T support */
+       struct tm6000_dvb               *dvb;
+
+       /* audio support */
+       struct snd_tm6000_card          *adev;
+       struct work_struct              wq_trigger;   /* Trigger to start/stop audio for alsa module */
+       atomic_t                        stream_started;  /* stream should be running if true */
+
+       struct tm6000_IR                *ir;
+
+       /* locks */
+       struct mutex                    lock;
+       struct mutex                    usb_lock;
+
+       /* usb transfer */
+       struct usb_device               *udev;          /* the usb device */
+
+       struct tm6000_endpoint          bulk_in, bulk_out, isoc_in, isoc_out;
+       struct tm6000_endpoint          int_in, int_out;
+
+       /* scaler!=0 if scaler is active*/
+       int                             scaler;
+
+               /* Isoc control struct */
+       struct usb_isoc_ctl          isoc_ctl;
+
+       spinlock_t                   slock;
+
+       unsigned long quirks;
+};
+
+enum tm6000_ops_type {
+       TM6000_AUDIO = 0x10,
+       TM6000_DVB = 0x20,
+};
+
+struct tm6000_ops {
+       struct list_head        next;
+       char                    *name;
+       enum tm6000_ops_type    type;
+       int (*init)(struct tm6000_core *);
+       int (*fini)(struct tm6000_core *);
+       int (*fillbuf)(struct tm6000_core *, char *buf, int size);
+};
+
+struct tm6000_fh {
+       struct tm6000_core           *dev;
+       unsigned int                 radio;
+
+       /* video capture */
+       struct tm6000_fmt            *fmt;
+       unsigned int                 width, height;
+       struct videobuf_queue        vb_vidq;
+
+       enum v4l2_buf_type           type;
+};
+
+#define TM6000_STD     (V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|    \
+                       V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \
+                       V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM)
+
+/* In tm6000-cards.c */
+
+int tm6000_tuner_callback(void *ptr, int component, int command, int arg);
+int tm6000_xc5000_callback(void *ptr, int component, int command, int arg);
+int tm6000_cards_setup(struct tm6000_core *dev);
+void tm6000_flash_led(struct tm6000_core *dev, u8 state);
+
+/* In tm6000-core.c */
+
+int tm6000_read_write_usb(struct tm6000_core *dev, u8 reqtype, u8 req,
+                          u16 value, u16 index, u8 *buf, u16 len);
+int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
+                                               u16 index, u16 mask);
+int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep);
+int tm6000_init(struct tm6000_core *dev);
+int tm6000_reset(struct tm6000_core *dev);
+
+int tm6000_init_analog_mode(struct tm6000_core *dev);
+int tm6000_init_digital_mode(struct tm6000_core *dev);
+int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate);
+int tm6000_set_audio_rinput(struct tm6000_core *dev);
+int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute);
+void tm6000_set_volume(struct tm6000_core *dev, int vol);
+
+int tm6000_v4l2_register(struct tm6000_core *dev);
+int tm6000_v4l2_unregister(struct tm6000_core *dev);
+int tm6000_v4l2_exit(void);
+void tm6000_set_fourcc_format(struct tm6000_core *dev);
+
+void tm6000_remove_from_devlist(struct tm6000_core *dev);
+void tm6000_add_into_devlist(struct tm6000_core *dev);
+int tm6000_register_extension(struct tm6000_ops *ops);
+void tm6000_unregister_extension(struct tm6000_ops *ops);
+void tm6000_init_extension(struct tm6000_core *dev);
+void tm6000_close_extension(struct tm6000_core *dev);
+int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
+                       char *buf, int size);
+
+
+/* In tm6000-stds.c */
+void tm6000_get_std_res(struct tm6000_core *dev);
+int tm6000_set_standard(struct tm6000_core *dev);
+
+/* In tm6000-i2c.c */
+int tm6000_i2c_register(struct tm6000_core *dev);
+int tm6000_i2c_unregister(struct tm6000_core *dev);
+
+/* In tm6000-queue.c */
+
+int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma);
+
+int tm6000_vidioc_streamon(struct file *file, void *priv,
+                          enum v4l2_buf_type i);
+int tm6000_vidioc_streamoff(struct file *file, void *priv,
+                           enum v4l2_buf_type i);
+int tm6000_vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *rb);
+int tm6000_vidioc_querybuf(struct file *file, void *priv,
+                          struct v4l2_buffer *b);
+int tm6000_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b);
+int tm6000_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b);
+ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count,
+                        loff_t *f_pos);
+unsigned int tm6000_v4l2_poll(struct file *file,
+                             struct poll_table_struct *wait);
+int tm6000_queue_init(struct tm6000_core *dev);
+
+/* In tm6000-alsa.c */
+/*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/
+
+/* In tm6000-input.c */
+int tm6000_ir_init(struct tm6000_core *dev);
+int tm6000_ir_fini(struct tm6000_core *dev);
+void tm6000_ir_wait(struct tm6000_core *dev, u8 state);
+int tm6000_ir_int_start(struct tm6000_core *dev);
+void tm6000_ir_int_stop(struct tm6000_core *dev);
+
+/* Debug stuff */
+
+extern int tm6000_debug;
+
+#define dprintk(dev, level, fmt, arg...) do {\
+       if (tm6000_debug & level) \
+               printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \
+                        dev->name, __func__ , ##arg); } while (0)
+
+#define V4L2_DEBUG_REG         0x0004
+#define V4L2_DEBUG_I2C         0x0008
+#define V4L2_DEBUG_QUEUE       0x0010
+#define V4L2_DEBUG_ISOC                0x0020
+#define V4L2_DEBUG_RES_LOCK    0x0040  /* Resource locking */
+#define V4L2_DEBUG_OPEN                0x0080  /* video open/close debug */
+
+#define tm6000_err(fmt, arg...) do {\
+       printk(KERN_ERR "tm6000 %s :"fmt, \
+               __func__ , ##arg); } while (0)
index c46a3bb..f22dbef 100644 (file)
@@ -1695,14 +1695,17 @@ static int tvaudio_s_ctrl(struct v4l2_subdev *sd,
        case V4L2_CID_AUDIO_BALANCE:
        {
                int volume, balance;
+
                if (!(desc->flags & CHIP_HAS_VOLUME))
                        break;
 
-               volume = max(chip->left,chip->right);
+               volume = max(chip->left, chip->right);
                balance = ctrl->value;
+               chip->left = (min(65536 - balance, 32768) * volume) / 32768;
+               chip->right = (min(balance, volume * (__u16)32768)) / 32768;
 
-               chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
-               chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+               chip_write(chip, desc->leftreg, desc->volfunc(chip->left));
+               chip_write(chip, desc->rightreg, desc->volfunc(chip->right));
 
                return 0;
        }
index 4240043..25a9949 100644 (file)
 
 /* Reserved 1Fh-27h */
 
-#define TVP5150_VIDEO_STD           0x28 /* Video standard */
+#define VIDEO_STD_MASK                  (0x07 >> 1)
+#define TVP5150_VIDEO_STD                0x28 /* Video standard */
+#define VIDEO_STD_AUTO_SWITCH_BIT       0x00
+#define VIDEO_STD_NTSC_MJ_BIT           0x02
+#define VIDEO_STD_PAL_BDGHIN_BIT        0x04
+#define VIDEO_STD_PAL_M_BIT             0x06
+#define VIDEO_STD_PAL_COMBINATION_N_BIT         0x08
+#define VIDEO_STD_NTSC_4_43_BIT                 0x0a
+#define VIDEO_STD_SECAM_BIT             0x0c
+
+#define VIDEO_STD_NTSC_MJ_BIT_AS                 0x01
+#define VIDEO_STD_PAL_BDGHIN_BIT_AS              0x03
+#define VIDEO_STD_PAL_M_BIT_AS                  0x05
+#define VIDEO_STD_PAL_COMBINATION_N_BIT_AS      0x07
+#define VIDEO_STD_NTSC_4_43_BIT_AS              0x09
+#define VIDEO_STD_SECAM_BIT_AS                  0x0b
 
 /* Reserved 29h-2bh */
 
index b799851..2e6059a 100644 (file)
@@ -128,7 +128,7 @@ static const struct i2c_reg_value tvp7002_init_default[] = {
        { TVP7002_ADC_SETUP, 0x50, TVP7002_WRITE },
        { TVP7002_COARSE_CLAMP_CTL, 0x00, TVP7002_WRITE },
        { TVP7002_SOG_CLAMP, 0x80, TVP7002_WRITE },
-       { TVP7002_RGB_COARSE_CLAMP_CTL, 0x00, TVP7002_WRITE },
+       { TVP7002_RGB_COARSE_CLAMP_CTL, 0x8c, TVP7002_WRITE },
        { TVP7002_SOG_COARSE_CLAMP_CTL, 0x04, TVP7002_WRITE },
        { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
        { 0x32, 0x18, TVP7002_RESERVED },
@@ -182,7 +182,6 @@ static const struct i2c_reg_value tvp7002_parms_480P[] = {
        { TVP7002_HPLL_FDBK_DIV_MSBS, 0x35, TVP7002_WRITE },
        { TVP7002_HPLL_FDBK_DIV_LSBS, 0xa0, TVP7002_WRITE },
        { TVP7002_HPLL_CRTL, 0x02, TVP7002_WRITE },
-       { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_LSBS, 0x91, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_MSBS, 0x00, TVP7002_WRITE },
        { TVP7002_AVID_STOP_PIXEL_LSBS, 0x0B, TVP7002_WRITE },
@@ -204,7 +203,6 @@ static const struct i2c_reg_value tvp7002_parms_576P[] = {
        { TVP7002_HPLL_FDBK_DIV_MSBS, 0x36, TVP7002_WRITE },
        { TVP7002_HPLL_FDBK_DIV_LSBS, 0x00, TVP7002_WRITE },
        { TVP7002_HPLL_CRTL, 0x18, TVP7002_WRITE },
-       { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_LSBS, 0x9B, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_MSBS, 0x00, TVP7002_WRITE },
        { TVP7002_AVID_STOP_PIXEL_LSBS, 0x0F, TVP7002_WRITE },
@@ -226,7 +224,6 @@ static const struct i2c_reg_value tvp7002_parms_1080I60[] = {
        { TVP7002_HPLL_FDBK_DIV_MSBS, 0x89, TVP7002_WRITE },
        { TVP7002_HPLL_FDBK_DIV_LSBS, 0x80, TVP7002_WRITE },
        { TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE },
-       { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
        { TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE },
@@ -248,7 +245,6 @@ static const struct i2c_reg_value tvp7002_parms_1080P60[] = {
        { TVP7002_HPLL_FDBK_DIV_MSBS, 0x89, TVP7002_WRITE },
        { TVP7002_HPLL_FDBK_DIV_LSBS, 0x80, TVP7002_WRITE },
        { TVP7002_HPLL_CRTL, 0xE0, TVP7002_WRITE },
-       { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
        { TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE },
@@ -270,7 +266,6 @@ static const struct i2c_reg_value tvp7002_parms_1080I50[] = {
        { TVP7002_HPLL_FDBK_DIV_MSBS, 0xa5, TVP7002_WRITE },
        { TVP7002_HPLL_FDBK_DIV_LSBS, 0x00, TVP7002_WRITE },
        { TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE },
-       { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
        { TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE },
@@ -292,7 +287,6 @@ static const struct i2c_reg_value tvp7002_parms_720P60[] = {
        { TVP7002_HPLL_FDBK_DIV_MSBS, 0x67, TVP7002_WRITE },
        { TVP7002_HPLL_FDBK_DIV_LSBS, 0x20, TVP7002_WRITE },
        { TVP7002_HPLL_CRTL, 0xa0, TVP7002_WRITE },
-       { TVP7002_HPLL_PHASE_SEL, 0x16, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_LSBS, 0x47, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
        { TVP7002_AVID_STOP_PIXEL_LSBS, 0x4B, TVP7002_WRITE },
@@ -314,7 +308,6 @@ static const struct i2c_reg_value tvp7002_parms_720P50[] = {
        { TVP7002_HPLL_FDBK_DIV_MSBS, 0x7b, TVP7002_WRITE },
        { TVP7002_HPLL_FDBK_DIV_LSBS, 0xc0, TVP7002_WRITE },
        { TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE },
-       { TVP7002_HPLL_PHASE_SEL, 0x16, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_LSBS, 0x47, TVP7002_WRITE },
        { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
        { TVP7002_AVID_STOP_PIXEL_LSBS, 0x4B, TVP7002_WRITE },
@@ -687,6 +680,9 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
        u8 cpl_msb;
        int index;
 
+       /* Return invalid preset if no active input is detected */
+       qpreset->preset = V4L2_DV_INVALID;
+
        device = to_tvp7002(sd);
 
        /* Read standards from device registers */
@@ -720,8 +716,6 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
        if (index == NUM_PRESETS) {
                v4l2_dbg(1, debug, sd, "detection failed: lpf = %x, cpl = %x\n",
                                                                lpfr, cpln);
-               /* Could not detect a signal, so return the 'invalid' preset */
-               qpreset->preset = V4L2_DV_INVALID;
                return 0;
        }
 
index 3387187..aea1e3b 100644 (file)
@@ -2,5 +2,5 @@ usbvision-objs  := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision-
 
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o
 
-EXTRA_CFLAGS += -Idrivers/media/video
-EXTRA_CFLAGS += -Idrivers/media/common/tuners
+ccflags-y += -Idrivers/media/video
+ccflags-y += -Idrivers/media/common/tuners
index e4100b1..656d4c9 100644 (file)
@@ -114,6 +114,11 @@ static struct uvc_format_desc uvc_fmts[] = {
                .guid           = UVC_GUID_FORMAT_RGBP,
                .fcc            = V4L2_PIX_FMT_RGB565,
        },
+       {
+               .name           = "H.264",
+               .guid           = UVC_GUID_FORMAT_H264,
+               .fcc            = V4L2_PIX_FMT_H264,
+       },
 };
 
 /* ------------------------------------------------------------------------
@@ -2331,6 +2336,14 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_DEF },
+       /* The Imaging Source USB CCD cameras */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x199e,
+         .idProduct            = 0x8102,
+         .bInterfaceClass      = USB_CLASS_VENDOR_SPEC,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0 },
        /* Bodelin ProScopeHR */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_DEV_HI
index ea71d5f..dadf11f 100644 (file)
@@ -32,7 +32,7 @@
  * UVC ioctls
  */
 static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
-       struct uvc_xu_control_mapping *xmap, int old)
+       struct uvc_xu_control_mapping *xmap)
 {
        struct uvc_control_mapping *map;
        unsigned int size;
@@ -58,13 +58,6 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
                break;
 
        case V4L2_CTRL_TYPE_MENU:
-               if (old) {
-                       uvc_trace(UVC_TRACE_CONTROL, "V4L2_CTRL_TYPE_MENU not "
-                                 "supported for UVCIOC_CTRL_MAP_OLD.\n");
-                       ret = -EINVAL;
-                       goto done;
-               }
-
                size = xmap->menu_count * sizeof(*map->menu_info);
                map->menu_info = kmalloc(size, GFP_KERNEL);
                if (map->menu_info == NULL) {
@@ -538,20 +531,6 @@ static int uvc_v4l2_release(struct file *file)
        return 0;
 }
 
-static void uvc_v4l2_ioctl_warn(void)
-{
-       static int warned;
-
-       if (warned)
-               return;
-
-       uvc_printk(KERN_INFO, "Deprecated UVCIOC_CTRL_{ADD,MAP_OLD,GET,SET} "
-                  "ioctls will be removed in 2.6.42.\n");
-       uvc_printk(KERN_INFO, "See http://www.ideasonboard.org/uvc/upgrade/ "
-                  "for upgrade instructions.\n");
-       warned = 1;
-}
-
 static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *vdev = video_devdata(file);
@@ -1032,37 +1011,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd);
                return -EINVAL;
 
-       /* Dynamic controls. UVCIOC_CTRL_ADD, UVCIOC_CTRL_MAP_OLD,
-        * UVCIOC_CTRL_GET and UVCIOC_CTRL_SET are deprecated and scheduled for
-        * removal in 2.6.42.
-        */
-       case __UVCIOC_CTRL_ADD:
-               uvc_v4l2_ioctl_warn();
-               return -EEXIST;
-
-       case __UVCIOC_CTRL_MAP_OLD:
-               uvc_v4l2_ioctl_warn();
-       case __UVCIOC_CTRL_MAP:
        case UVCIOC_CTRL_MAP:
-               return uvc_ioctl_ctrl_map(chain, arg,
-                                         cmd == __UVCIOC_CTRL_MAP_OLD);
-
-       case __UVCIOC_CTRL_GET:
-       case __UVCIOC_CTRL_SET:
-       {
-               struct uvc_xu_control *xctrl = arg;
-               struct uvc_xu_control_query xqry = {
-                       .unit           = xctrl->unit,
-                       .selector       = xctrl->selector,
-                       .query          = cmd == __UVCIOC_CTRL_GET
-                                       ? UVC_GET_CUR : UVC_SET_CUR,
-                       .size           = xctrl->size,
-                       .data           = xctrl->data,
-               };
-
-               uvc_v4l2_ioctl_warn();
-               return uvc_xu_ctrl_query(chain, &xqry);
-       }
+               return uvc_ioctl_ctrl_map(chain, arg);
 
        case UVCIOC_CTRL_QUERY:
                return uvc_xu_ctrl_query(chain, arg);
index ffd1158..b015e8e 100644 (file)
@@ -790,8 +790,12 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream)
 
        for (i = 0; i < UVC_URBS; ++i) {
                if (stream->urb_buffer[i]) {
+#ifndef CONFIG_DMA_NONCOHERENT
                        usb_free_coherent(stream->dev->udev, stream->urb_size,
                                stream->urb_buffer[i], stream->urb_dma[i]);
+#else
+                       kfree(stream->urb_buffer[i]);
+#endif
                        stream->urb_buffer[i] = NULL;
                }
        }
@@ -831,9 +835,14 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
        for (; npackets > 1; npackets /= 2) {
                for (i = 0; i < UVC_URBS; ++i) {
                        stream->urb_size = psize * npackets;
+#ifndef CONFIG_DMA_NONCOHERENT
                        stream->urb_buffer[i] = usb_alloc_coherent(
                                stream->dev->udev, stream->urb_size,
                                gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
+#else
+                       stream->urb_buffer[i] =
+                           kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN);
+#endif
                        if (!stream->urb_buffer[i]) {
                                uvc_free_urb_buffers(stream);
                                break;
@@ -908,10 +917,14 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream,
                urb->context = stream;
                urb->pipe = usb_rcvisocpipe(stream->dev->udev,
                                ep->desc.bEndpointAddress);
+#ifndef CONFIG_DMA_NONCOHERENT
                urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+               urb->transfer_dma = stream->urb_dma[i];
+#else
+               urb->transfer_flags = URB_ISO_ASAP;
+#endif
                urb->interval = ep->desc.bInterval;
                urb->transfer_buffer = stream->urb_buffer[i];
-               urb->transfer_dma = stream->urb_dma[i];
                urb->complete = uvc_video_complete;
                urb->number_of_packets = npackets;
                urb->transfer_buffer_length = size;
@@ -969,8 +982,10 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
                usb_fill_bulk_urb(urb, stream->dev->udev, pipe,
                        stream->urb_buffer[i], size, uvc_video_complete,
                        stream);
+#ifndef CONFIG_DMA_NONCOHERENT
                urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
                urb->transfer_dma = stream->urb_dma[i];
+#endif
 
                stream->urb[i] = urb;
        }
index cbdd49b..4c1392e 100644 (file)
 #ifndef _USB_VIDEO_H_
 #define _USB_VIDEO_H_
 
-#include <linux/kernel.h>
-#include <linux/videodev2.h>
-
-#ifndef __KERNEL__
-/*
- * This header provides binary compatibility with applications using the private
- * uvcvideo API. This API is deprecated and will be removed in 2.6.42.
- * Applications should be recompiled against the public linux/uvcvideo.h header.
- */
-#warn "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead."
-
-/*
- * Dynamic controls
- */
-
-/* Data types for UVC control data */
-#define UVC_CTRL_DATA_TYPE_RAW         0
-#define UVC_CTRL_DATA_TYPE_SIGNED      1
-#define UVC_CTRL_DATA_TYPE_UNSIGNED    2
-#define UVC_CTRL_DATA_TYPE_BOOLEAN     3
-#define UVC_CTRL_DATA_TYPE_ENUM                4
-#define UVC_CTRL_DATA_TYPE_BITMASK     5
-
-/* Control flags */
-#define UVC_CONTROL_SET_CUR    (1 << 0)
-#define UVC_CONTROL_GET_CUR    (1 << 1)
-#define UVC_CONTROL_GET_MIN    (1 << 2)
-#define UVC_CONTROL_GET_MAX    (1 << 3)
-#define UVC_CONTROL_GET_RES    (1 << 4)
-#define UVC_CONTROL_GET_DEF    (1 << 5)
-#define UVC_CONTROL_RESTORE    (1 << 6)
-#define UVC_CONTROL_AUTO_UPDATE        (1 << 7)
-
-#define UVC_CONTROL_GET_RANGE  (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
-                                UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
-                                UVC_CONTROL_GET_DEF)
-
-struct uvc_menu_info {
-       __u32 value;
-       __u8 name[32];
-};
-
-struct uvc_xu_control_mapping {
-       __u32 id;
-       __u8 name[32];
-       __u8 entity[16];
-       __u8 selector;
-
-       __u8 size;
-       __u8 offset;
-       __u32 v4l2_type;
-       __u32 data_type;
-
-       struct uvc_menu_info __user *menu_info;
-       __u32 menu_count;
-
-       __u32 reserved[4];
-};
-
-#endif
-
-struct uvc_xu_control_info {
-       __u8 entity[16];
-       __u8 index;
-       __u8 selector;
-       __u16 size;
-       __u32 flags;
-};
-
-struct uvc_xu_control_mapping_old {
-       __u8 reserved[64];
-};
-
-struct uvc_xu_control {
-       __u8 unit;
-       __u8 selector;
-       __u16 size;
-       __u8 __user *data;
-};
-
 #ifndef __KERNEL__
-#define UVCIOC_CTRL_ADD                _IOW('U', 1, struct uvc_xu_control_info)
-#define UVCIOC_CTRL_MAP_OLD    _IOWR('U', 2, struct uvc_xu_control_mapping_old)
-#define UVCIOC_CTRL_MAP                _IOWR('U', 2, struct uvc_xu_control_mapping)
-#define UVCIOC_CTRL_GET                _IOWR('U', 3, struct uvc_xu_control)
-#define UVCIOC_CTRL_SET                _IOW('U', 4, struct uvc_xu_control)
-#else
-#define __UVCIOC_CTRL_ADD      _IOW('U', 1, struct uvc_xu_control_info)
-#define __UVCIOC_CTRL_MAP_OLD  _IOWR('U', 2, struct uvc_xu_control_mapping_old)
-#define __UVCIOC_CTRL_MAP      _IOWR('U', 2, struct uvc_xu_control_mapping)
-#define __UVCIOC_CTRL_GET      _IOWR('U', 3, struct uvc_xu_control)
-#define __UVCIOC_CTRL_SET      _IOW('U', 4, struct uvc_xu_control)
-#endif
-
-#ifdef __KERNEL__
+#error "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead."
+#endif /* __KERNEL__ */
 
+#include <linux/kernel.h>
 #include <linux/poll.h>
 #include <linux/usb.h>
 #include <linux/usb/video.h>
 #include <linux/uvcvideo.h>
+#include <linux/videodev2.h>
 #include <media/media-device.h>
 #include <media/v4l2-device.h>
 
@@ -179,6 +89,10 @@ struct uvc_xu_control {
        { 'M',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
         0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
 
+#define UVC_GUID_FORMAT_H264 \
+       { 'H',  '2',  '6',  '4', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
 /* ------------------------------------------------------------------------
  * Driver specific constants.
  */
@@ -698,6 +612,4 @@ extern struct usb_host_endpoint *uvc_find_endpoint(
 void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
                struct uvc_buffer *buf);
 
-#endif /* __KERNEL__ */
-
 #endif
index 06b6014..fc8666a 100644 (file)
@@ -43,7 +43,7 @@ struct v4l2_ctrl_helper {
 };
 
 /* Small helper function to determine if the autocluster is set to manual
-   mode. In that case the is_volatile flag should be ignored. */
+   mode. */
 static bool is_cur_manual(const struct v4l2_ctrl *master)
 {
        return master->is_auto && master->cur.val == master->manual_mode_value;
@@ -937,9 +937,14 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
                break;
        }
        if (update_inactive) {
-               ctrl->flags &= ~V4L2_CTRL_FLAG_INACTIVE;
-               if (!is_cur_manual(ctrl->cluster[0]))
+               /* Note: update_inactive can only be true for auto clusters. */
+               ctrl->flags &=
+                       ~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE);
+               if (!is_cur_manual(ctrl->cluster[0])) {
                        ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+                       if (ctrl->cluster[0]->has_volatiles)
+                               ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+               }
        }
        if (changed || update_inactive) {
                /* If a control was changed that was not one of the controls
@@ -1394,10 +1399,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
                        type, min, max,
                        is_menu ? cfg->menu_skip_mask : step,
                        def, flags, qmenu, priv);
-       if (ctrl) {
+       if (ctrl)
                ctrl->is_private = cfg->is_private;
-               ctrl->is_volatile = cfg->is_volatile;
-       }
        return ctrl;
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_custom);
@@ -1491,6 +1494,7 @@ EXPORT_SYMBOL(v4l2_ctrl_add_handler);
 /* Cluster controls */
 void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
 {
+       bool has_volatiles = false;
        int i;
 
        /* The first control is the master control and it must not be NULL */
@@ -1500,8 +1504,11 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
                if (controls[i]) {
                        controls[i]->cluster = controls;
                        controls[i]->ncontrols = ncontrols;
+                       if (controls[i]->flags & V4L2_CTRL_FLAG_VOLATILE)
+                               has_volatiles = true;
                }
        }
+       controls[0]->has_volatiles = has_volatiles;
 }
 EXPORT_SYMBOL(v4l2_ctrl_cluster);
 
@@ -1509,22 +1516,25 @@ void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
                            u8 manual_val, bool set_volatile)
 {
        struct v4l2_ctrl *master = controls[0];
-       u32 flag;
+       u32 flag = 0;
        int i;
 
        v4l2_ctrl_cluster(ncontrols, controls);
        WARN_ON(ncontrols <= 1);
        WARN_ON(manual_val < master->minimum || manual_val > master->maximum);
+       WARN_ON(set_volatile && !has_op(master, g_volatile_ctrl));
        master->is_auto = true;
+       master->has_volatiles = set_volatile;
        master->manual_mode_value = manual_val;
        master->flags |= V4L2_CTRL_FLAG_UPDATE;
-       flag = is_cur_manual(master) ? 0 : V4L2_CTRL_FLAG_INACTIVE;
+
+       if (!is_cur_manual(master))
+               flag = V4L2_CTRL_FLAG_INACTIVE |
+                       (set_volatile ? V4L2_CTRL_FLAG_VOLATILE : 0);
 
        for (i = 1; i < ncontrols; i++)
-               if (controls[i]) {
-                       controls[i]->is_volatile = set_volatile;
+               if (controls[i])
                        controls[i]->flags |= flag;
-               }
 }
 EXPORT_SYMBOL(v4l2_ctrl_auto_cluster);
 
@@ -1579,9 +1589,6 @@ EXPORT_SYMBOL(v4l2_ctrl_grab);
 static void log_ctrl(const struct v4l2_ctrl *ctrl,
                     const char *prefix, const char *colon)
 {
-       int fl_inact = ctrl->flags & V4L2_CTRL_FLAG_INACTIVE;
-       int fl_grabbed = ctrl->flags & V4L2_CTRL_FLAG_GRABBED;
-
        if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY))
                return;
        if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
@@ -1612,14 +1619,17 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
                printk(KERN_CONT "unknown type %d", ctrl->type);
                break;
        }
-       if (fl_inact && fl_grabbed)
-               printk(KERN_CONT " (inactive, grabbed)\n");
-       else if (fl_inact)
-               printk(KERN_CONT " (inactive)\n");
-       else if (fl_grabbed)
-               printk(KERN_CONT " (grabbed)\n");
-       else
-               printk(KERN_CONT "\n");
+       if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE |
+                          V4L2_CTRL_FLAG_GRABBED |
+                          V4L2_CTRL_FLAG_VOLATILE)) {
+               if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+                       printk(KERN_CONT " inactive");
+               if (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)
+                       printk(KERN_CONT " grabbed");
+               if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE)
+                       printk(KERN_CONT " volatile");
+       }
+       printk(KERN_CONT "\n");
 }
 
 /* Log all controls owned by the handler */
@@ -1959,7 +1969,8 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
                v4l2_ctrl_lock(master);
 
                /* g_volatile_ctrl will update the new control values */
-               if (has_op(master, g_volatile_ctrl) && !is_cur_manual(master)) {
+               if ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
+                       (master->has_volatiles && !is_cur_manual(master))) {
                        for (j = 0; j < master->ncontrols; j++)
                                cur_to_new(master->cluster[j]);
                        ret = call_op(master, g_volatile_ctrl);
@@ -2004,7 +2015,7 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
 
        v4l2_ctrl_lock(master);
        /* g_volatile_ctrl will update the current control values */
-       if (ctrl->is_volatile && !is_cur_manual(master)) {
+       if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
                for (i = 0; i < master->ncontrols; i++)
                        cur_to_new(master->cluster[i]);
                ret = call_op(master, g_volatile_ctrl);
@@ -2120,6 +2131,20 @@ static int validate_ctrls(struct v4l2_ext_controls *cs,
        return 0;
 }
 
+/* Obtain the current volatile values of an autocluster and mark them
+   as new. */
+static void update_from_auto_cluster(struct v4l2_ctrl *master)
+{
+       int i;
+
+       for (i = 0; i < master->ncontrols; i++)
+               cur_to_new(master->cluster[i]);
+       if (!call_op(master, g_volatile_ctrl))
+               for (i = 1; i < master->ncontrols; i++)
+                       if (master->cluster[i])
+                               master->cluster[i]->is_new = 1;
+}
+
 /* Try or try-and-set controls */
 static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
                             struct v4l2_ext_controls *cs,
@@ -2165,6 +2190,31 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
                        if (master->cluster[j])
                                master->cluster[j]->is_new = 0;
 
+               /* For volatile autoclusters that are currently in auto mode
+                  we need to discover if it will be set to manual mode.
+                  If so, then we have to copy the current volatile values
+                  first since those will become the new manual values (which
+                  may be overwritten by explicit new values from this set
+                  of controls). */
+               if (master->is_auto && master->has_volatiles &&
+                                               !is_cur_manual(master)) {
+                       /* Pick an initial non-manual value */
+                       s32 new_auto_val = master->manual_mode_value + 1;
+                       u32 tmp_idx = idx;
+
+                       do {
+                               /* Check if the auto control is part of the
+                                  list, and remember the new value. */
+                               if (helpers[tmp_idx].ctrl == master)
+                                       new_auto_val = cs->controls[tmp_idx].value;
+                               tmp_idx = helpers[tmp_idx].next;
+                       } while (tmp_idx);
+                       /* If the new value == the manual value, then copy
+                          the current volatile values. */
+                       if (new_auto_val == master->manual_mode_value)
+                               update_from_auto_cluster(master);
+               }
+
                /* Copy the new caller-supplied control values.
                   user_to_new() sets 'is_new' to 1. */
                do {
@@ -2235,6 +2285,12 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, s32 *val)
                if (master->cluster[i])
                        master->cluster[i]->is_new = 0;
 
+       /* For autoclusters with volatiles that are switched from auto to
+          manual mode we have to update the current volatile values since
+          those will become the initial manual values after such a switch. */
+       if (master->is_auto && master->has_volatiles && ctrl == master &&
+           !is_cur_manual(master) && *val == master->manual_mode_value)
+               update_from_auto_cluster(master);
        ctrl->val = *val;
        ctrl->is_new = 1;
        ret = try_or_set_cluster(fh, master, true);
index 002ce13..24fd433 100644 (file)
        memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \
        0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field))
 
+#define have_fmt_ops(foo) (                                            \
+       ops->vidioc_##foo##_fmt_vid_cap ||                              \
+       ops->vidioc_##foo##_fmt_vid_out ||                              \
+       ops->vidioc_##foo##_fmt_vid_cap_mplane ||                       \
+       ops->vidioc_##foo##_fmt_vid_out_mplane ||                       \
+       ops->vidioc_##foo##_fmt_vid_overlay ||                          \
+       ops->vidioc_##foo##_fmt_vbi_cap ||                              \
+       ops->vidioc_##foo##_fmt_vid_out_overlay ||                      \
+       ops->vidioc_##foo##_fmt_vbi_out ||                              \
+       ops->vidioc_##foo##_fmt_sliced_vbi_cap ||                       \
+       ops->vidioc_##foo##_fmt_sliced_vbi_out ||                       \
+       ops->vidioc_##foo##_fmt_type_private)
+
 struct std_descr {
        v4l2_std_id std;
        const char *descr;
@@ -477,63 +490,6 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
        return -EINVAL;
 }
 
-/**
- * fmt_sp_to_mp() - Convert a single-plane format to its multi-planar 1-plane
- * equivalent
- */
-static int fmt_sp_to_mp(const struct v4l2_format *f_sp,
-                       struct v4l2_format *f_mp)
-{
-       struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp;
-       const struct v4l2_pix_format *pix = &f_sp->fmt.pix;
-
-       if (f_sp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               f_mp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-       else if (f_sp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
-               f_mp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-       else
-               return -EINVAL;
-
-       pix_mp->width = pix->width;
-       pix_mp->height = pix->height;
-       pix_mp->pixelformat = pix->pixelformat;
-       pix_mp->field = pix->field;
-       pix_mp->colorspace = pix->colorspace;
-       pix_mp->num_planes = 1;
-       pix_mp->plane_fmt[0].sizeimage = pix->sizeimage;
-       pix_mp->plane_fmt[0].bytesperline = pix->bytesperline;
-
-       return 0;
-}
-
-/**
- * fmt_mp_to_sp() - Convert a multi-planar 1-plane format to its single-planar
- * equivalent
- */
-static int fmt_mp_to_sp(const struct v4l2_format *f_mp,
-                       struct v4l2_format *f_sp)
-{
-       const struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp;
-       struct v4l2_pix_format *pix = &f_sp->fmt.pix;
-
-       if (f_mp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-               f_sp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       else if (f_mp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-               f_sp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-       else
-               return -EINVAL;
-
-       pix->width = pix_mp->width;
-       pix->height = pix_mp->height;
-       pix->pixelformat = pix_mp->pixelformat;
-       pix->field = pix_mp->field;
-       pix->colorspace = pix_mp->colorspace;
-       pix->sizeimage = pix_mp->plane_fmt[0].sizeimage;
-       pix->bytesperline = pix_mp->plane_fmt[0].bytesperline;
-
-       return 0;
-}
-
 static long __video_do_ioctl(struct file *file,
                unsigned int cmd, void *arg)
 {
@@ -541,8 +497,8 @@ static long __video_do_ioctl(struct file *file,
        const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
        void *fh = file->private_data;
        struct v4l2_fh *vfh = NULL;
-       struct v4l2_format f_copy;
        int use_fh_prio = 0;
+       long ret_prio = 0;
        long ret = -ENOTTY;
 
        if (ops == NULL) {
@@ -562,39 +518,8 @@ static long __video_do_ioctl(struct file *file,
                use_fh_prio = test_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
        }
 
-       if (use_fh_prio) {
-               switch (cmd) {
-               case VIDIOC_S_CTRL:
-               case VIDIOC_S_STD:
-               case VIDIOC_S_INPUT:
-               case VIDIOC_S_OUTPUT:
-               case VIDIOC_S_TUNER:
-               case VIDIOC_S_FREQUENCY:
-               case VIDIOC_S_FMT:
-               case VIDIOC_S_CROP:
-               case VIDIOC_S_AUDIO:
-               case VIDIOC_S_AUDOUT:
-               case VIDIOC_S_EXT_CTRLS:
-               case VIDIOC_S_FBUF:
-               case VIDIOC_S_PRIORITY:
-               case VIDIOC_S_DV_PRESET:
-               case VIDIOC_S_DV_TIMINGS:
-               case VIDIOC_S_JPEGCOMP:
-               case VIDIOC_S_MODULATOR:
-               case VIDIOC_S_PARM:
-               case VIDIOC_S_HW_FREQ_SEEK:
-               case VIDIOC_ENCODER_CMD:
-               case VIDIOC_OVERLAY:
-               case VIDIOC_REQBUFS:
-               case VIDIOC_STREAMON:
-               case VIDIOC_STREAMOFF:
-                       ret = v4l2_prio_check(vfd->prio, vfh->prio);
-                       if (ret)
-                               goto exit_prio;
-                       ret = -EINVAL;
-                       break;
-               }
-       }
+       if (use_fh_prio)
+               ret_prio = v4l2_prio_check(vfd->prio, vfh->prio);
 
        switch (cmd) {
 
@@ -638,12 +563,14 @@ static long __video_do_ioctl(struct file *file,
                enum v4l2_priority *p = arg;
 
                if (!ops->vidioc_s_priority && !use_fh_prio)
-                               break;
+                       break;
                dbgarg(cmd, "setting priority to %d\n", *p);
                if (ops->vidioc_s_priority)
                        ret = ops->vidioc_s_priority(file, fh, *p);
                else
-                       ret = v4l2_prio_change(&vfd->v4l2_dev->prio, &vfh->prio, *p);
+                       ret = ret_prio ? ret_prio :
+                               v4l2_prio_change(&vfd->v4l2_dev->prio,
+                                                       &vfh->prio, *p);
                break;
        }
 
@@ -654,37 +581,37 @@ static long __video_do_ioctl(struct file *file,
 
                switch (f->type) {
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       if (ops->vidioc_enum_fmt_vid_cap)
+                       if (likely(ops->vidioc_enum_fmt_vid_cap))
                                ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-                       if (ops->vidioc_enum_fmt_vid_cap_mplane)
+                       if (likely(ops->vidioc_enum_fmt_vid_cap_mplane))
                                ret = ops->vidioc_enum_fmt_vid_cap_mplane(file,
                                                                        fh, f);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       if (ops->vidioc_enum_fmt_vid_overlay)
+                       if (likely(ops->vidioc_enum_fmt_vid_overlay))
                                ret = ops->vidioc_enum_fmt_vid_overlay(file,
                                        fh, f);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-                       if (ops->vidioc_enum_fmt_vid_out)
+                       if (likely(ops->vidioc_enum_fmt_vid_out))
                                ret = ops->vidioc_enum_fmt_vid_out(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-                       if (ops->vidioc_enum_fmt_vid_out_mplane)
+                       if (likely(ops->vidioc_enum_fmt_vid_out_mplane))
                                ret = ops->vidioc_enum_fmt_vid_out_mplane(file,
                                                                        fh, f);
                        break;
                case V4L2_BUF_TYPE_PRIVATE:
-                       if (ops->vidioc_enum_fmt_type_private)
+                       if (likely(ops->vidioc_enum_fmt_type_private))
                                ret = ops->vidioc_enum_fmt_type_private(file,
                                                                fh, f);
                        break;
                default:
                        break;
                }
-               if (!ret)
+               if (likely (!ret))
                        dbgarg(cmd, "index=%d, type=%d, flags=%d, "
                                "pixelformat=%c%c%c%c, description='%s'\n",
                                f->index, f->type, f->flags,
@@ -693,6 +620,14 @@ static long __video_do_ioctl(struct file *file,
                                (f->pixelformat >> 16) & 0xff,
                                (f->pixelformat >> 24) & 0xff,
                                f->description);
+               else if (ret == -ENOTTY &&
+                        (ops->vidioc_enum_fmt_vid_cap ||
+                         ops->vidioc_enum_fmt_vid_out ||
+                         ops->vidioc_enum_fmt_vid_cap_mplane ||
+                         ops->vidioc_enum_fmt_vid_out_mplane ||
+                         ops->vidioc_enum_fmt_vid_overlay ||
+                         ops->vidioc_enum_fmt_type_private))
+                       ret = -EINVAL;
                break;
        }
        case VIDIOC_G_FMT:
@@ -704,119 +639,67 @@ static long __video_do_ioctl(struct file *file,
 
                switch (f->type) {
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       if (ops->vidioc_g_fmt_vid_cap) {
+                       if (ops->vidioc_g_fmt_vid_cap)
                                ret = ops->vidioc_g_fmt_vid_cap(file, fh, f);
-                       } else if (ops->vidioc_g_fmt_vid_cap_mplane) {
-                               if (fmt_sp_to_mp(f, &f_copy))
-                                       break;
-                               ret = ops->vidioc_g_fmt_vid_cap_mplane(file, fh,
-                                                                      &f_copy);
-                               if (ret)
-                                       break;
-
-                               /* Driver is currently in multi-planar format,
-                                * we can't return it in single-planar API*/
-                               if (f_copy.fmt.pix_mp.num_planes > 1) {
-                                       ret = -EBUSY;
-                                       break;
-                               }
-
-                               ret = fmt_mp_to_sp(&f_copy, f);
-                       }
                        if (!ret)
                                v4l_print_pix_fmt(vfd, &f->fmt.pix);
                        break;
                case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-                       if (ops->vidioc_g_fmt_vid_cap_mplane) {
+                       if (ops->vidioc_g_fmt_vid_cap_mplane)
                                ret = ops->vidioc_g_fmt_vid_cap_mplane(file,
                                                                        fh, f);
-                       } else if (ops->vidioc_g_fmt_vid_cap) {
-                               if (fmt_mp_to_sp(f, &f_copy))
-                                       break;
-                               ret = ops->vidioc_g_fmt_vid_cap(file,
-                                                               fh, &f_copy);
-                               if (ret)
-                                       break;
-
-                               ret = fmt_sp_to_mp(&f_copy, f);
-                       }
                        if (!ret)
                                v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       if (ops->vidioc_g_fmt_vid_overlay)
+                       if (likely(ops->vidioc_g_fmt_vid_overlay))
                                ret = ops->vidioc_g_fmt_vid_overlay(file,
                                                                    fh, f);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-                       if (ops->vidioc_g_fmt_vid_out) {
+                       if (ops->vidioc_g_fmt_vid_out)
                                ret = ops->vidioc_g_fmt_vid_out(file, fh, f);
-                       } else if (ops->vidioc_g_fmt_vid_out_mplane) {
-                               if (fmt_sp_to_mp(f, &f_copy))
-                                       break;
-                               ret = ops->vidioc_g_fmt_vid_out_mplane(file, fh,
-                                                                       &f_copy);
-                               if (ret)
-                                       break;
-
-                               /* Driver is currently in multi-planar format,
-                                * we can't return it in single-planar API*/
-                               if (f_copy.fmt.pix_mp.num_planes > 1) {
-                                       ret = -EBUSY;
-                                       break;
-                               }
-
-                               ret = fmt_mp_to_sp(&f_copy, f);
-                       }
                        if (!ret)
                                v4l_print_pix_fmt(vfd, &f->fmt.pix);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-                       if (ops->vidioc_g_fmt_vid_out_mplane) {
+                       if (ops->vidioc_g_fmt_vid_out_mplane)
                                ret = ops->vidioc_g_fmt_vid_out_mplane(file,
                                                                        fh, f);
-                       } else if (ops->vidioc_g_fmt_vid_out) {
-                               if (fmt_mp_to_sp(f, &f_copy))
-                                       break;
-                               ret = ops->vidioc_g_fmt_vid_out(file,
-                                                               fh, &f_copy);
-                               if (ret)
-                                       break;
-
-                               ret = fmt_sp_to_mp(&f_copy, f);
-                       }
                        if (!ret)
                                v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-                       if (ops->vidioc_g_fmt_vid_out_overlay)
+                       if (likely(ops->vidioc_g_fmt_vid_out_overlay))
                                ret = ops->vidioc_g_fmt_vid_out_overlay(file,
                                       fh, f);
                        break;
                case V4L2_BUF_TYPE_VBI_CAPTURE:
-                       if (ops->vidioc_g_fmt_vbi_cap)
+                       if (likely(ops->vidioc_g_fmt_vbi_cap))
                                ret = ops->vidioc_g_fmt_vbi_cap(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_VBI_OUTPUT:
-                       if (ops->vidioc_g_fmt_vbi_out)
+                       if (likely(ops->vidioc_g_fmt_vbi_out))
                                ret = ops->vidioc_g_fmt_vbi_out(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-                       if (ops->vidioc_g_fmt_sliced_vbi_cap)
+                       if (likely(ops->vidioc_g_fmt_sliced_vbi_cap))
                                ret = ops->vidioc_g_fmt_sliced_vbi_cap(file,
                                                                        fh, f);
                        break;
                case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-                       if (ops->vidioc_g_fmt_sliced_vbi_out)
+                       if (likely(ops->vidioc_g_fmt_sliced_vbi_out))
                                ret = ops->vidioc_g_fmt_sliced_vbi_out(file,
                                                                        fh, f);
                        break;
                case V4L2_BUF_TYPE_PRIVATE:
-                       if (ops->vidioc_g_fmt_type_private)
+                       if (likely(ops->vidioc_g_fmt_type_private))
                                ret = ops->vidioc_g_fmt_type_private(file,
                                                                fh, f);
                        break;
                }
+               if (unlikely(ret == -ENOTTY && have_fmt_ops(g)))
+                       ret = -EINVAL;
 
                break;
        }
@@ -824,6 +707,14 @@ static long __video_do_ioctl(struct file *file,
        {
                struct v4l2_format *f = (struct v4l2_format *)arg;
 
+               if (!have_fmt_ops(s))
+                       break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
+               ret = -EINVAL;
+
                /* FIXME: Should be one dump per type */
                dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
 
@@ -831,44 +722,15 @@ static long __video_do_ioctl(struct file *file,
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                        CLEAR_AFTER_FIELD(f, fmt.pix);
                        v4l_print_pix_fmt(vfd, &f->fmt.pix);
-                       if (ops->vidioc_s_fmt_vid_cap) {
+                       if (ops->vidioc_s_fmt_vid_cap)
                                ret = ops->vidioc_s_fmt_vid_cap(file, fh, f);
-                       } else if (ops->vidioc_s_fmt_vid_cap_mplane) {
-                               if (fmt_sp_to_mp(f, &f_copy))
-                                       break;
-                               ret = ops->vidioc_s_fmt_vid_cap_mplane(file, fh,
-                                                                       &f_copy);
-                               if (ret)
-                                       break;
-
-                               if (f_copy.fmt.pix_mp.num_planes > 1) {
-                                       /* Drivers shouldn't adjust from 1-plane
-                                        * to more than 1-plane formats */
-                                       ret = -EBUSY;
-                                       WARN_ON(1);
-                                       break;
-                               }
-
-                               ret = fmt_mp_to_sp(&f_copy, f);
-                       }
                        break;
                case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
                        CLEAR_AFTER_FIELD(f, fmt.pix_mp);
                        v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
-                       if (ops->vidioc_s_fmt_vid_cap_mplane) {
+                       if (ops->vidioc_s_fmt_vid_cap_mplane)
                                ret = ops->vidioc_s_fmt_vid_cap_mplane(file,
                                                                        fh, f);
-                       } else if (ops->vidioc_s_fmt_vid_cap &&
-                                       f->fmt.pix_mp.num_planes == 1) {
-                               if (fmt_mp_to_sp(f, &f_copy))
-                                       break;
-                               ret = ops->vidioc_s_fmt_vid_cap(file,
-                                                               fh, &f_copy);
-                               if (ret)
-                                       break;
-
-                               ret = fmt_sp_to_mp(&f_copy, f);
-                       }
                        break;
                case V4L2_BUF_TYPE_VIDEO_OVERLAY:
                        CLEAR_AFTER_FIELD(f, fmt.win);
@@ -879,44 +741,15 @@ static long __video_do_ioctl(struct file *file,
                case V4L2_BUF_TYPE_VIDEO_OUTPUT:
                        CLEAR_AFTER_FIELD(f, fmt.pix);
                        v4l_print_pix_fmt(vfd, &f->fmt.pix);
-                       if (ops->vidioc_s_fmt_vid_out) {
+                       if (ops->vidioc_s_fmt_vid_out)
                                ret = ops->vidioc_s_fmt_vid_out(file, fh, f);
-                       } else if (ops->vidioc_s_fmt_vid_out_mplane) {
-                               if (fmt_sp_to_mp(f, &f_copy))
-                                       break;
-                               ret = ops->vidioc_s_fmt_vid_out_mplane(file, fh,
-                                                                       &f_copy);
-                               if (ret)
-                                       break;
-
-                               if (f_copy.fmt.pix_mp.num_planes > 1) {
-                                       /* Drivers shouldn't adjust from 1-plane
-                                        * to more than 1-plane formats */
-                                       ret = -EBUSY;
-                                       WARN_ON(1);
-                                       break;
-                               }
-
-                               ret = fmt_mp_to_sp(&f_copy, f);
-                       }
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
                        CLEAR_AFTER_FIELD(f, fmt.pix_mp);
                        v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
-                       if (ops->vidioc_s_fmt_vid_out_mplane) {
+                       if (ops->vidioc_s_fmt_vid_out_mplane)
                                ret = ops->vidioc_s_fmt_vid_out_mplane(file,
                                                                        fh, f);
-                       } else if (ops->vidioc_s_fmt_vid_out &&
-                                       f->fmt.pix_mp.num_planes == 1) {
-                               if (fmt_mp_to_sp(f, &f_copy))
-                                       break;
-                               ret = ops->vidioc_s_fmt_vid_out(file,
-                                                               fh, &f_copy);
-                               if (ret)
-                                       break;
-
-                               ret = fmt_mp_to_sp(&f_copy, f);
-                       }
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                        CLEAR_AFTER_FIELD(f, fmt.win);
@@ -926,29 +759,30 @@ static long __video_do_ioctl(struct file *file,
                        break;
                case V4L2_BUF_TYPE_VBI_CAPTURE:
                        CLEAR_AFTER_FIELD(f, fmt.vbi);
-                       if (ops->vidioc_s_fmt_vbi_cap)
+                       if (likely(ops->vidioc_s_fmt_vbi_cap))
                                ret = ops->vidioc_s_fmt_vbi_cap(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_VBI_OUTPUT:
                        CLEAR_AFTER_FIELD(f, fmt.vbi);
-                       if (ops->vidioc_s_fmt_vbi_out)
+                       if (likely(ops->vidioc_s_fmt_vbi_out))
                                ret = ops->vidioc_s_fmt_vbi_out(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
                        CLEAR_AFTER_FIELD(f, fmt.sliced);
-                       if (ops->vidioc_s_fmt_sliced_vbi_cap)
+                       if (likely(ops->vidioc_s_fmt_sliced_vbi_cap))
                                ret = ops->vidioc_s_fmt_sliced_vbi_cap(file,
                                                                        fh, f);
                        break;
                case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
                        CLEAR_AFTER_FIELD(f, fmt.sliced);
-                       if (ops->vidioc_s_fmt_sliced_vbi_out)
+                       if (likely(ops->vidioc_s_fmt_sliced_vbi_out))
                                ret = ops->vidioc_s_fmt_sliced_vbi_out(file,
                                                                        fh, f);
+
                        break;
                case V4L2_BUF_TYPE_PRIVATE:
                        /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */
-                       if (ops->vidioc_s_fmt_type_private)
+                       if (likely(ops->vidioc_s_fmt_type_private))
                                ret = ops->vidioc_s_fmt_type_private(file,
                                                                fh, f);
                        break;
@@ -965,132 +799,77 @@ static long __video_do_ioctl(struct file *file,
                switch (f->type) {
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                        CLEAR_AFTER_FIELD(f, fmt.pix);
-                       if (ops->vidioc_try_fmt_vid_cap) {
+                       if (ops->vidioc_try_fmt_vid_cap)
                                ret = ops->vidioc_try_fmt_vid_cap(file, fh, f);
-                       } else if (ops->vidioc_try_fmt_vid_cap_mplane) {
-                               if (fmt_sp_to_mp(f, &f_copy))
-                                       break;
-                               ret = ops->vidioc_try_fmt_vid_cap_mplane(file,
-                                                               fh, &f_copy);
-                               if (ret)
-                                       break;
-
-                               if (f_copy.fmt.pix_mp.num_planes > 1) {
-                                       /* Drivers shouldn't adjust from 1-plane
-                                        * to more than 1-plane formats */
-                                       ret = -EBUSY;
-                                       WARN_ON(1);
-                                       break;
-                               }
-                               ret = fmt_mp_to_sp(&f_copy, f);
-                       }
                        if (!ret)
                                v4l_print_pix_fmt(vfd, &f->fmt.pix);
                        break;
                case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
                        CLEAR_AFTER_FIELD(f, fmt.pix_mp);
-                       if (ops->vidioc_try_fmt_vid_cap_mplane) {
+                       if (ops->vidioc_try_fmt_vid_cap_mplane)
                                ret = ops->vidioc_try_fmt_vid_cap_mplane(file,
                                                                         fh, f);
-                       } else if (ops->vidioc_try_fmt_vid_cap &&
-                                       f->fmt.pix_mp.num_planes == 1) {
-                               if (fmt_mp_to_sp(f, &f_copy))
-                                       break;
-                               ret = ops->vidioc_try_fmt_vid_cap(file,
-                                                                 fh, &f_copy);
-                               if (ret)
-                                       break;
-
-                               ret = fmt_sp_to_mp(&f_copy, f);
-                       }
                        if (!ret)
                                v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OVERLAY:
                        CLEAR_AFTER_FIELD(f, fmt.win);
-                       if (ops->vidioc_try_fmt_vid_overlay)
+                       if (likely(ops->vidioc_try_fmt_vid_overlay))
                                ret = ops->vidioc_try_fmt_vid_overlay(file,
                                        fh, f);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT:
                        CLEAR_AFTER_FIELD(f, fmt.pix);
-                       if (ops->vidioc_try_fmt_vid_out) {
+                       if (ops->vidioc_try_fmt_vid_out)
                                ret = ops->vidioc_try_fmt_vid_out(file, fh, f);
-                       } else if (ops->vidioc_try_fmt_vid_out_mplane) {
-                               if (fmt_sp_to_mp(f, &f_copy))
-                                       break;
-                               ret = ops->vidioc_try_fmt_vid_out_mplane(file,
-                                                               fh, &f_copy);
-                               if (ret)
-                                       break;
-
-                               if (f_copy.fmt.pix_mp.num_planes > 1) {
-                                       /* Drivers shouldn't adjust from 1-plane
-                                        * to more than 1-plane formats */
-                                       ret = -EBUSY;
-                                       WARN_ON(1);
-                                       break;
-                               }
-                               ret = fmt_mp_to_sp(&f_copy, f);
-                       }
                        if (!ret)
                                v4l_print_pix_fmt(vfd, &f->fmt.pix);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
                        CLEAR_AFTER_FIELD(f, fmt.pix_mp);
-                       if (ops->vidioc_try_fmt_vid_out_mplane) {
+                       if (ops->vidioc_try_fmt_vid_out_mplane)
                                ret = ops->vidioc_try_fmt_vid_out_mplane(file,
                                                                         fh, f);
-                       } else if (ops->vidioc_try_fmt_vid_out &&
-                                       f->fmt.pix_mp.num_planes == 1) {
-                               if (fmt_mp_to_sp(f, &f_copy))
-                                       break;
-                               ret = ops->vidioc_try_fmt_vid_out(file,
-                                                                 fh, &f_copy);
-                               if (ret)
-                                       break;
-
-                               ret = fmt_sp_to_mp(&f_copy, f);
-                       }
                        if (!ret)
                                v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                        CLEAR_AFTER_FIELD(f, fmt.win);
-                       if (ops->vidioc_try_fmt_vid_out_overlay)
+                       if (likely(ops->vidioc_try_fmt_vid_out_overlay))
                                ret = ops->vidioc_try_fmt_vid_out_overlay(file,
                                       fh, f);
                        break;
                case V4L2_BUF_TYPE_VBI_CAPTURE:
                        CLEAR_AFTER_FIELD(f, fmt.vbi);
-                       if (ops->vidioc_try_fmt_vbi_cap)
+                       if (likely(ops->vidioc_try_fmt_vbi_cap))
                                ret = ops->vidioc_try_fmt_vbi_cap(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_VBI_OUTPUT:
                        CLEAR_AFTER_FIELD(f, fmt.vbi);
-                       if (ops->vidioc_try_fmt_vbi_out)
+                       if (likely(ops->vidioc_try_fmt_vbi_out))
                                ret = ops->vidioc_try_fmt_vbi_out(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
                        CLEAR_AFTER_FIELD(f, fmt.sliced);
-                       if (ops->vidioc_try_fmt_sliced_vbi_cap)
+                       if (likely(ops->vidioc_try_fmt_sliced_vbi_cap))
                                ret = ops->vidioc_try_fmt_sliced_vbi_cap(file,
                                                                fh, f);
                        break;
                case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
                        CLEAR_AFTER_FIELD(f, fmt.sliced);
-                       if (ops->vidioc_try_fmt_sliced_vbi_out)
+                       if (likely(ops->vidioc_try_fmt_sliced_vbi_out))
                                ret = ops->vidioc_try_fmt_sliced_vbi_out(file,
                                                                fh, f);
                        break;
                case V4L2_BUF_TYPE_PRIVATE:
                        /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */
-                       if (ops->vidioc_try_fmt_type_private)
+                       if (likely(ops->vidioc_try_fmt_type_private))
                                ret = ops->vidioc_try_fmt_type_private(file,
                                                                fh, f);
                        break;
                }
-
+               if (unlikely(ret == -ENOTTY && have_fmt_ops(try)))
+                       ret = -EINVAL;
                break;
        }
        /* FIXME: Those buf reqs could be handled here,
@@ -1103,6 +882,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_reqbufs)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                ret = check_fmt(ops, p->type);
                if (ret)
                        break;
@@ -1168,6 +951,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_overlay)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                dbgarg(cmd, "value=%d\n", *i);
                ret = ops->vidioc_overlay(file, fh, *i);
                break;
@@ -1193,6 +980,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_fbuf)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n",
                        p->capability, p->flags, (unsigned long)p->base);
                v4l_print_pix_fmt(vfd, &p->fmt);
@@ -1205,6 +996,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_streamon)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
                ret = ops->vidioc_streamon(file, fh, i);
                break;
@@ -1215,6 +1010,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_streamoff)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
                ret = ops->vidioc_streamoff(file, fh, i);
                break;
@@ -1227,6 +1026,10 @@ static long __video_do_ioctl(struct file *file,
                unsigned int index = p->index, i, j = 0;
                const char *descr = "";
 
+               if (id == 0)
+                       break;
+               ret = -EINVAL;
+
                /* Return norm array in a canonical way */
                for (i = 0; i <= index && id; i++) {
                        /* last std value in the standards array is 0, so this
@@ -1262,16 +1065,15 @@ static long __video_do_ioctl(struct file *file,
        {
                v4l2_std_id *id = arg;
 
-               ret = 0;
                /* Calls the specific handler */
                if (ops->vidioc_g_std)
                        ret = ops->vidioc_g_std(file, fh, id);
-               else if (vfd->current_norm)
+               else if (vfd->current_norm) {
+                       ret = 0;
                        *id = vfd->current_norm;
-               else
-                       ret = -EINVAL;
+               }
 
-               if (!ret)
+               if (likely(!ret))
                        dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id);
                break;
        }
@@ -1281,15 +1083,20 @@ static long __video_do_ioctl(struct file *file,
 
                dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id);
 
+               if (!ops->vidioc_s_std)
+                       break;
+
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
+               ret = -EINVAL;
                norm = (*id) & vfd->tvnorms;
                if (vfd->tvnorms && !norm)      /* Check if std is supported */
                        break;
 
                /* Calls the specific handler */
-               if (ops->vidioc_s_std)
-                       ret = ops->vidioc_s_std(file, fh, &norm);
-               else
-                       ret = -EINVAL;
+               ret = ops->vidioc_s_std(file, fh, &norm);
 
                /* Updates standard information */
                if (ret >= 0)
@@ -1302,6 +1109,14 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_querystd)
                        break;
+               /*
+                * If nothing detected, it should return all supported
+                * Drivers just need to mask the std argument, in order
+                * to remove the standards that don't apply from the mask.
+                * This means that tuners, audio and video decoders can join
+                * their efforts to improve the standards detection
+                */
+               *p = vfd->tvnorms;
                ret = ops->vidioc_querystd(file, fh, arg);
                if (!ret)
                        dbgarg(cmd, "detected std=%08Lx\n",
@@ -1358,6 +1173,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_input)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                dbgarg(cmd, "value=%d\n", *i);
                ret = ops->vidioc_s_input(file, fh, *i);
                break;
@@ -1410,6 +1229,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_output)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                dbgarg(cmd, "value=%d\n", *i);
                ret = ops->vidioc_s_output(file, fh, *i);
                break;
@@ -1479,6 +1302,10 @@ static long __video_do_ioctl(struct file *file,
                if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
                        !ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
 
                dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
 
@@ -1504,6 +1331,8 @@ static long __video_do_ioctl(struct file *file,
                ctrl.value = p->value;
                if (check_ext_ctrls(&ctrls, 1))
                        ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls);
+               else
+                       ret = -EINVAL;
                break;
        }
        case VIDIOC_G_EXT_CTRLS:
@@ -1515,8 +1344,10 @@ static long __video_do_ioctl(struct file *file,
                        ret = v4l2_g_ext_ctrls(vfh->ctrl_handler, p);
                else if (vfd->ctrl_handler)
                        ret = v4l2_g_ext_ctrls(vfd->ctrl_handler, p);
-               else if (ops->vidioc_g_ext_ctrls && check_ext_ctrls(p, 0))
-                       ret = ops->vidioc_g_ext_ctrls(file, fh, p);
+               else if (ops->vidioc_g_ext_ctrls)
+                       ret = check_ext_ctrls(p, 0) ?
+                               ops->vidioc_g_ext_ctrls(file, fh, p) :
+                               -EINVAL;
                else
                        break;
                v4l_print_ext_ctrls(cmd, vfd, p, !ret);
@@ -1530,6 +1361,10 @@ static long __video_do_ioctl(struct file *file,
                if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
                                !ops->vidioc_s_ext_ctrls)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                v4l_print_ext_ctrls(cmd, vfd, p, 1);
                if (vfh && vfh->ctrl_handler)
                        ret = v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p);
@@ -1537,6 +1372,8 @@ static long __video_do_ioctl(struct file *file,
                        ret = v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, p);
                else if (check_ext_ctrls(p, 0))
                        ret = ops->vidioc_s_ext_ctrls(file, fh, p);
+               else
+                       ret = -EINVAL;
                break;
        }
        case VIDIOC_TRY_EXT_CTRLS:
@@ -1554,6 +1391,8 @@ static long __video_do_ioctl(struct file *file,
                        ret = v4l2_try_ext_ctrls(vfd->ctrl_handler, p);
                else if (check_ext_ctrls(p, 0))
                        ret = ops->vidioc_try_ext_ctrls(file, fh, p);
+               else
+                       ret = -EINVAL;
                break;
        }
        case VIDIOC_QUERYMENU:
@@ -1614,6 +1453,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_audio)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
                                        "mode=0x%x\n", p->index, p->name,
                                        p->capability, p->mode);
@@ -1654,6 +1497,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_audout)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                dbgarg(cmd, "index=%d, name=%s, capability=%d, "
                                        "mode=%d\n", p->index, p->name,
                                        p->capability, p->mode);
@@ -1683,6 +1530,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_modulator)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                dbgarg(cmd, "index=%d, name=%s, capability=%d, "
                                "rangelow=%d, rangehigh=%d, txsubchans=%d\n",
                                p->index, p->name, p->capability, p->rangelow,
@@ -1709,6 +1560,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_crop)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
                dbgrect(vfd, "", &p->c);
                ret = ops->vidioc_s_crop(file, fh, p);
@@ -1752,11 +1607,15 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_g_jpegcomp)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                dbgarg(cmd, "quality=%d, APPn=%d, APP_len=%d, "
                                        "COM_len=%d, jpeg_markers=%d\n",
                                        p->quality, p->APPn, p->APP_len,
                                        p->COM_len, p->jpeg_markers);
-                       ret = ops->vidioc_s_jpegcomp(file, fh, p);
+               ret = ops->vidioc_s_jpegcomp(file, fh, p);
                break;
        }
        case VIDIOC_G_ENC_INDEX:
@@ -1777,6 +1636,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_encoder_cmd)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                ret = ops->vidioc_encoder_cmd(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1797,6 +1660,8 @@ static long __video_do_ioctl(struct file *file,
        {
                struct v4l2_streamparm *p = arg;
 
+               if (!ops->vidioc_g_parm && !vfd->current_norm)
+                       break;
                if (ops->vidioc_g_parm) {
                        ret = check_fmt(ops, p->type);
                        if (ret)
@@ -1805,14 +1670,13 @@ static long __video_do_ioctl(struct file *file,
                } else {
                        v4l2_std_id std = vfd->current_norm;
 
+                       ret = -EINVAL;
                        if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                                break;
 
                        ret = 0;
                        if (ops->vidioc_g_std)
                                ret = ops->vidioc_g_std(file, fh, &std);
-                       else if (std == 0)
-                               ret = -EINVAL;
                        if (ret == 0)
                                v4l2_video_std_frame_period(std,
                                                    &p->parm.capture.timeperframe);
@@ -1827,6 +1691,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_parm)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                ret = check_fmt(ops, p->type);
                if (ret)
                        break;
@@ -1862,6 +1730,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_tuner)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
                        V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
                dbgarg(cmd, "index=%d, name=%s, type=%d, "
@@ -1896,6 +1768,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_frequency)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
                                p->tuner, p->type, p->frequency);
                ret = ops->vidioc_s_frequency(file, fh, p);
@@ -1970,6 +1846,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_hw_freq_seek)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
                type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
                        V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
                dbgarg(cmd,
@@ -2074,6 +1954,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_dv_preset)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
 
                dbgarg(cmd, "preset=%d\n", p->preset);
                ret = ops->vidioc_s_dv_preset(file, fh, p);
@@ -2109,6 +1993,10 @@ static long __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_s_dv_timings)
                        break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
 
                switch (p->type) {
                case V4L2_DV_BT_656_1120:
@@ -2217,19 +2105,12 @@ static long __video_do_ioctl(struct file *file,
                break;
        }
        default:
-       {
-               bool valid_prio = true;
-
                if (!ops->vidioc_default)
                        break;
-               if (use_fh_prio)
-                       valid_prio = v4l2_prio_check(vfd->prio, vfh->prio) >= 0;
-               ret = ops->vidioc_default(file, fh, valid_prio, cmd, arg);
+               ret = ops->vidioc_default(file, fh, ret_prio >= 0, cmd, arg);
                break;
-       }
        } /* switch */
 
-exit_prio:
        if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
                if (ret < 0) {
                        v4l_print_ioctl(vfd->name, cmd);
index 3b15bf5..975d0fa 100644 (file)
@@ -97,11 +97,12 @@ void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx)
 
        spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
 
-       if (list_empty(&q_ctx->rdy_queue))
-               goto end;
+       if (list_empty(&q_ctx->rdy_queue)) {
+               spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
+               return NULL;
+       }
 
        b = list_entry(q_ctx->rdy_queue.next, struct v4l2_m2m_buffer, list);
-end:
        spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
        return &b->vb;
 }
@@ -117,12 +118,13 @@ void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx)
        unsigned long flags;
 
        spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
-       if (!list_empty(&q_ctx->rdy_queue)) {
-               b = list_entry(q_ctx->rdy_queue.next, struct v4l2_m2m_buffer,
-                               list);
-               list_del(&b->list);
-               q_ctx->num_rdy--;
+       if (list_empty(&q_ctx->rdy_queue)) {
+               spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
+               return NULL;
        }
+       b = list_entry(q_ctx->rdy_queue.next, struct v4l2_m2m_buffer, list);
+       list_del(&b->list);
+       q_ctx->num_rdy--;
        spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
 
        return &b->vb;
index b7967c9..179e20e 100644 (file)
@@ -173,6 +173,25 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        case VIDIOC_UNSUBSCRIBE_EVENT:
                return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       case VIDIOC_DBG_G_REGISTER:
+       {
+               struct v4l2_dbg_register *p = arg;
+
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               return v4l2_subdev_call(sd, core, g_register, p);
+       }
+       case VIDIOC_DBG_S_REGISTER:
+       {
+               struct v4l2_dbg_register *p = arg;
+
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               return v4l2_subdev_call(sd, core, s_register, p);
+       }
+#endif
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
        case VIDIOC_SUBDEV_G_FMT: {
                struct v4l2_subdev_format *format = arg;
index 3015e60..3f5c7a3 100644 (file)
@@ -43,8 +43,7 @@ module_param(debug, int, 0644);
 /**
  * __vb2_buf_mem_alloc() - allocate video memory for the given buffer
  */
-static int __vb2_buf_mem_alloc(struct vb2_buffer *vb,
-                               unsigned long *plane_sizes)
+static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
 {
        struct vb2_queue *q = vb->vb2_queue;
        void *mem_priv;
@@ -53,13 +52,13 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb,
        /* Allocate memory for all planes in this buffer */
        for (plane = 0; plane < vb->num_planes; ++plane) {
                mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane],
-                                       plane_sizes[plane]);
+                                     q->plane_sizes[plane]);
                if (IS_ERR_OR_NULL(mem_priv))
                        goto free;
 
                /* Associate allocator private data with this plane */
                vb->planes[plane].mem_priv = mem_priv;
-               vb->v4l2_planes[plane].length = plane_sizes[plane];
+               vb->v4l2_planes[plane].length = q->plane_sizes[plane];
        }
 
        return 0;
@@ -141,8 +140,7 @@ static void __setup_offsets(struct vb2_queue *q)
  * Returns the number of buffers successfully allocated.
  */
 static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
-                            unsigned int num_buffers, unsigned int num_planes,
-                            unsigned long plane_sizes[])
+                            unsigned int num_buffers, unsigned int num_planes)
 {
        unsigned int buffer;
        struct vb2_buffer *vb;
@@ -169,7 +167,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
 
                /* Allocate video buffer memory for the MMAP type */
                if (memory == V4L2_MEMORY_MMAP) {
-                       ret = __vb2_buf_mem_alloc(vb, plane_sizes);
+                       ret = __vb2_buf_mem_alloc(vb);
                        if (ret) {
                                dprintk(1, "Failed allocating memory for "
                                                "buffer %d\n", buffer);
@@ -278,6 +276,41 @@ static int __verify_planes_array(struct vb2_buffer *vb, struct v4l2_buffer *b)
        return 0;
 }
 
+/**
+ * __buffer_in_use() - return true if the buffer is in use and
+ * the queue cannot be freed (by the means of REQBUFS(0)) call
+ */
+static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
+{
+       unsigned int plane;
+       for (plane = 0; plane < vb->num_planes; ++plane) {
+               /*
+                * If num_users() has not been provided, call_memop
+                * will return 0, apparently nobody cares about this
+                * case anyway. If num_users() returns more than 1,
+                * we are not the only user of the plane's memory.
+                */
+               if (call_memop(q, plane, num_users,
+                               vb->planes[plane].mem_priv) > 1)
+                       return true;
+       }
+       return false;
+}
+
+/**
+ * __buffers_in_use() - return true if any buffers on the queue are in use and
+ * the queue cannot be freed (by the means of REQBUFS(0)) call
+ */
+static bool __buffers_in_use(struct vb2_queue *q)
+{
+       unsigned int buffer;
+       for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+               if (__buffer_in_use(q, q->bufs[buffer]))
+                       return true;
+       }
+       return false;
+}
+
 /**
  * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
  * returned to userspace
@@ -337,7 +370,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
                break;
        }
 
-       if (vb->num_planes_mapped == vb->num_planes)
+       if (__buffer_in_use(q, vb))
                b->flags |= V4L2_BUF_FLAG_MAPPED;
 
        return ret;
@@ -401,33 +434,6 @@ static int __verify_mmap_ops(struct vb2_queue *q)
        return 0;
 }
 
-/**
- * __buffers_in_use() - return true if any buffers on the queue are in use and
- * the queue cannot be freed (by the means of REQBUFS(0)) call
- */
-static bool __buffers_in_use(struct vb2_queue *q)
-{
-       unsigned int buffer, plane;
-       struct vb2_buffer *vb;
-
-       for (buffer = 0; buffer < q->num_buffers; ++buffer) {
-               vb = q->bufs[buffer];
-               for (plane = 0; plane < vb->num_planes; ++plane) {
-                       /*
-                        * If num_users() has not been provided, call_memop
-                        * will return 0, apparently nobody cares about this
-                        * case anyway. If num_users() returns more than 1,
-                        * we are not the only user of the plane's memory.
-                        */
-                       if (call_memop(q, plane, num_users,
-                                       vb->planes[plane].mem_priv) > 1)
-                               return true;
-               }
-       }
-
-       return false;
-}
-
 /**
  * vb2_reqbufs() - Initiate streaming
  * @q:         videobuf2 queue
@@ -454,7 +460,6 @@ static bool __buffers_in_use(struct vb2_queue *q)
 int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 {
        unsigned int num_buffers, num_planes;
-       unsigned long plane_sizes[VIDEO_MAX_PLANES];
        int ret = 0;
 
        if (q->fileio) {
@@ -516,7 +521,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
         * Make sure the requested values and current defaults are sane.
         */
        num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME);
-       memset(plane_sizes, 0, sizeof(plane_sizes));
+       memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
        memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
        q->memory = req->memory;
 
@@ -525,13 +530,12 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
         * Driver also sets the size and allocator context for each plane.
         */
        ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes,
-                      plane_sizes, q->alloc_ctx);
+                      q->plane_sizes, q->alloc_ctx);
        if (ret)
                return ret;
 
        /* Finally, allocate buffers and video memory */
-       ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes,
-                               plane_sizes);
+       ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes);
        if (ret == 0) {
                dprintk(1, "Memory allocation failed\n");
                return -ENOMEM;
@@ -545,7 +549,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 
                orig_num_buffers = num_buffers = ret;
                ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes,
-                              plane_sizes, q->alloc_ctx);
+                              q->plane_sizes, q->alloc_ctx);
                if (ret)
                        goto free_mem;
 
@@ -745,12 +749,20 @@ static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b)
                dprintk(3, "qbuf: userspace address for plane %d changed, "
                                "reacquiring memory\n", plane);
 
+               /* Check if the provided plane buffer is large enough */
+               if (planes[plane].length < q->plane_sizes[plane]) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+
                /* Release previously acquired memory if present */
                if (vb->planes[plane].mem_priv)
                        call_memop(q, plane, put_userptr,
                                        vb->planes[plane].mem_priv);
 
                vb->planes[plane].mem_priv = NULL;
+               vb->v4l2_planes[plane].m.userptr = 0;
+               vb->v4l2_planes[plane].length = 0;
 
                /* Acquire each plane's memory */
                if (q->mem_ops->get_userptr) {
@@ -788,10 +800,13 @@ static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b)
        return 0;
 err:
        /* In case of errors, release planes that were already acquired */
-       for (; plane > 0; --plane) {
-               call_memop(q, plane, put_userptr,
-                               vb->planes[plane - 1].mem_priv);
-               vb->planes[plane - 1].mem_priv = NULL;
+       for (plane = 0; plane < vb->num_planes; ++plane) {
+               if (vb->planes[plane].mem_priv)
+                       call_memop(q, plane, put_userptr,
+                                  vb->planes[plane].mem_priv);
+               vb->planes[plane].mem_priv = NULL;
+               vb->v4l2_planes[plane].m.userptr = 0;
+               vb->v4l2_planes[plane].length = 0;
        }
 
        return ret;
@@ -1095,6 +1110,43 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
 }
 EXPORT_SYMBOL_GPL(vb2_dqbuf);
 
+/**
+ * __vb2_queue_cancel() - cancel and stop (pause) streaming
+ *
+ * Removes all queued buffers from driver's queue and all buffers queued by
+ * userspace from videobuf's queue. Returns to state after reqbufs.
+ */
+static void __vb2_queue_cancel(struct vb2_queue *q)
+{
+       unsigned int i;
+
+       /*
+        * Tell driver to stop all transactions and release all queued
+        * buffers.
+        */
+       if (q->streaming)
+               call_qop(q, stop_streaming, q);
+       q->streaming = 0;
+
+       /*
+        * Remove all buffers from videobuf's list...
+        */
+       INIT_LIST_HEAD(&q->queued_list);
+       /*
+        * ...and done list; userspace will not receive any buffers it
+        * has not already dequeued before initiating cancel.
+        */
+       INIT_LIST_HEAD(&q->done_list);
+       atomic_set(&q->queued_count, 0);
+       wake_up_all(&q->done_wq);
+
+       /*
+        * Reinitialize all buffers for next use.
+        */
+       for (i = 0; i < q->num_buffers; ++i)
+               q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED;
+}
+
 /**
  * vb2_streamon - start streaming
  * @q:         videobuf2 queue
@@ -1103,7 +1155,7 @@ EXPORT_SYMBOL_GPL(vb2_dqbuf);
  * Should be called from vidioc_streamon handler of a driver.
  * This function:
  * 1) verifies current state
- * 2) starts streaming and passes any previously queued buffers to the driver
+ * 2) passes any previously queued buffers to the driver and starts streaming
  *
  * The return values from this function are intended to be directly returned
  * from vidioc_streamon handler in the driver.
@@ -1129,75 +1181,29 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
        }
 
        /*
-        * Cannot start streaming on an OUTPUT device if no buffers have
-        * been queued yet.
+        * If any buffers were queued before streamon,
+        * we can now pass them to driver for processing.
         */
-       if (V4L2_TYPE_IS_OUTPUT(q->type)) {
-               if (list_empty(&q->queued_list)) {
-                       dprintk(1, "streamon: no output buffers queued\n");
-                       return -EINVAL;
-               }
-       }
+       list_for_each_entry(vb, &q->queued_list, queued_entry)
+               __enqueue_in_driver(vb);
 
        /*
         * Let driver notice that streaming state has been enabled.
         */
-       ret = call_qop(q, start_streaming, q);
+       ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
        if (ret) {
                dprintk(1, "streamon: driver refused to start streaming\n");
+               __vb2_queue_cancel(q);
                return ret;
        }
 
        q->streaming = 1;
 
-       /*
-        * If any buffers were queued before streamon,
-        * we can now pass them to driver for processing.
-        */
-       list_for_each_entry(vb, &q->queued_list, queued_entry)
-               __enqueue_in_driver(vb);
-
        dprintk(3, "Streamon successful\n");
        return 0;
 }
 EXPORT_SYMBOL_GPL(vb2_streamon);
 
-/**
- * __vb2_queue_cancel() - cancel and stop (pause) streaming
- *
- * Removes all queued buffers from driver's queue and all buffers queued by
- * userspace from videobuf's queue. Returns to state after reqbufs.
- */
-static void __vb2_queue_cancel(struct vb2_queue *q)
-{
-       unsigned int i;
-
-       /*
-        * Tell driver to stop all transactions and release all queued
-        * buffers.
-        */
-       if (q->streaming)
-               call_qop(q, stop_streaming, q);
-       q->streaming = 0;
-
-       /*
-        * Remove all buffers from videobuf's list...
-        */
-       INIT_LIST_HEAD(&q->queued_list);
-       /*
-        * ...and done list; userspace will not receive any buffers it
-        * has not already dequeued before initiating cancel.
-        */
-       INIT_LIST_HEAD(&q->done_list);
-       atomic_set(&q->queued_count, 0);
-       wake_up_all(&q->done_wq);
-
-       /*
-        * Reinitialize all buffers for next use.
-        */
-       for (i = 0; i < q->num_buffers; ++i)
-               q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED;
-}
 
 /**
  * vb2_streamoff - stop streaming
@@ -1336,9 +1342,6 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
        if (ret)
                return ret;
 
-       vb_plane->mapped = 1;
-       vb->num_planes_mapped++;
-
        dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane);
        return 0;
 }
index a790a5f..f17ad98 100644 (file)
@@ -24,7 +24,7 @@ struct vb2_dc_conf {
 struct vb2_dc_buf {
        struct vb2_dc_conf              *conf;
        void                            *vaddr;
-       dma_addr_t                      paddr;
+       dma_addr_t                      dma_addr;
        unsigned long                   size;
        struct vm_area_struct           *vma;
        atomic_t                        refcount;
@@ -42,7 +42,7 @@ static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size)
        if (!buf)
                return ERR_PTR(-ENOMEM);
 
-       buf->vaddr = dma_alloc_coherent(conf->dev, size, &buf->paddr,
+       buf->vaddr = dma_alloc_coherent(conf->dev, size, &buf->dma_addr,
                                        GFP_KERNEL);
        if (!buf->vaddr) {
                dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n",
@@ -69,7 +69,7 @@ static void vb2_dma_contig_put(void *buf_priv)
 
        if (atomic_dec_and_test(&buf->refcount)) {
                dma_free_coherent(buf->conf->dev, buf->size, buf->vaddr,
-                                 buf->paddr);
+                                 buf->dma_addr);
                kfree(buf);
        }
 }
@@ -78,7 +78,7 @@ static void *vb2_dma_contig_cookie(void *buf_priv)
 {
        struct vb2_dc_buf *buf = buf_priv;
 
-       return &buf->paddr;
+       return &buf->dma_addr;
 }
 
 static void *vb2_dma_contig_vaddr(void *buf_priv)
@@ -106,7 +106,7 @@ static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma)
                return -EINVAL;
        }
 
-       return vb2_mmap_pfn_range(vma, buf->paddr, buf->size,
+       return vb2_mmap_pfn_range(vma, buf->dma_addr, buf->size,
                                  &vb2_common_vm_ops, &buf->handler);
 }
 
@@ -115,14 +115,14 @@ static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr,
 {
        struct vb2_dc_buf *buf;
        struct vm_area_struct *vma;
-       dma_addr_t paddr = 0;
+       dma_addr_t dma_addr = 0;
        int ret;
 
        buf = kzalloc(sizeof *buf, GFP_KERNEL);
        if (!buf)
                return ERR_PTR(-ENOMEM);
 
-       ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr);
+       ret = vb2_get_contig_userptr(vaddr, size, &vma, &dma_addr);
        if (ret) {
                printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n",
                                vaddr);
@@ -131,7 +131,7 @@ static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr,
        }
 
        buf->size = size;
-       buf->paddr = paddr;
+       buf->dma_addr = dma_addr;
        buf->vma = vma;
 
        return buf;
index 065f468..3bad8b1 100644 (file)
@@ -75,12 +75,6 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size)
 
        printk(KERN_DEBUG "%s: Allocated buffer of %d pages\n",
                __func__, buf->sg_desc.num_pages);
-
-       if (!buf->vaddr)
-               buf->vaddr = vm_map_ram(buf->pages,
-                                       buf->sg_desc.num_pages,
-                                       -1,
-                                       PAGE_KERNEL);
        return buf;
 
 fail_pages_alloc:
index 569eeb3..71a7a78 100644 (file)
@@ -68,12 +68,12 @@ void vb2_put_vma(struct vm_area_struct *vma)
        if (!vma)
                return;
 
-       if (vma->vm_file)
-               fput(vma->vm_file);
-
        if (vma->vm_ops && vma->vm_ops->close)
                vma->vm_ops->close(vma);
 
+       if (vma->vm_file)
+               fput(vma->vm_file);
+
        kfree(vma);
 }
 EXPORT_SYMBOL_GPL(vb2_put_vma);
index a848bd2..7cf94c0 100644 (file)
@@ -651,7 +651,7 @@ static void vivi_stop_generating(struct vivi_dev *dev)
        Videobuf operations
    ------------------------------------------------------------------*/
 static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
-                               unsigned int *nplanes, unsigned long sizes[],
+                               unsigned int *nplanes, unsigned int sizes[],
                                void *alloc_ctxs[])
 {
        struct vivi_dev *dev = vb2_get_drv_priv(vq);
@@ -766,7 +766,7 @@ static void buffer_queue(struct vb2_buffer *vb)
        spin_unlock_irqrestore(&dev->slock, flags);
 }
 
-static int start_streaming(struct vb2_queue *vq)
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct vivi_dev *dev = vb2_get_drv_priv(vq);
        dprintk(dev, 1, "%s\n", __func__);
@@ -852,6 +852,11 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
                (f->fmt.pix.width * dev->fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
                f->fmt.pix.height * f->fmt.pix.bytesperline;
+       if (dev->fmt->fourcc == V4L2_PIX_FMT_YUYV ||
+           dev->fmt->fourcc == V4L2_PIX_FMT_UYVY)
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       else
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
        return 0;
 }
 
@@ -885,6 +890,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                (f->fmt.pix.width * fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
                f->fmt.pix.height * f->fmt.pix.bytesperline;
+       if (fmt->fourcc == V4L2_PIX_FMT_YUYV ||
+           fmt->fourcc == V4L2_PIX_FMT_UYVY)
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       else
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
        return 0;
 }
 
@@ -948,6 +958,14 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
        return vb2_streamoff(&dev->vb_vidq, i);
 }
 
+static int vidioc_log_status(struct file *file, void *priv)
+{
+       struct vivi_dev *dev = video_drvdata(file);
+
+       v4l2_ctrl_handler_log_status(&dev->ctrl_handler, dev->v4l2_dev.name);
+       return 0;
+}
+
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
 {
        return 0;
@@ -1191,6 +1209,7 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
        .vidioc_s_input       = vidioc_s_input,
        .vidioc_streamon      = vidioc_streamon,
        .vidioc_streamoff     = vidioc_streamoff,
+       .vidioc_log_status    = vidioc_log_status,
        .vidioc_subscribe_event = vidioc_subscribe_event,
        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
index ca372eb..e5cad6f 100644 (file)
@@ -331,7 +331,7 @@ static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pst
        if (pstd)
                *pstd = std;
        if (pstatus)
-               *pstatus = status;
+               *pstatus = res;
        return 0;
 }
 
index c492846..e78cf94 100644 (file)
@@ -1638,6 +1638,9 @@ static int zr364xx_probe(struct usb_interface *intf,
 
        if (!cam->read_endpoint) {
                dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
+               video_device_release(cam->vdev);
+               kfree(cam);
+               cam = NULL;
                return -ENOMEM;
        }
 
index 2d6423c..50d5f27 100644 (file)
@@ -506,5 +506,6 @@ source "drivers/misc/iwmc3200top/Kconfig"
 source "drivers/misc/ti-st/Kconfig"
 source "drivers/misc/lis3lv02d/Kconfig"
 source "drivers/misc/carma/Kconfig"
+source "drivers/misc/altera-stapl/Kconfig"
 
 endif # MISC_DEVICES
index 8f3efb6..b26495a 100644 (file)
@@ -47,3 +47,4 @@ obj-$(CONFIG_AB8500_PWM)      += ab8500-pwm.o
 obj-y                          += lis3lv02d/
 obj-y                          += carma/
 obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
+obj-$(CONFIG_ALTERA_STAPL)     +=altera-stapl/
diff --git a/drivers/misc/altera-stapl/Kconfig b/drivers/misc/altera-stapl/Kconfig
new file mode 100644 (file)
index 0000000..7f01d8e
--- /dev/null
@@ -0,0 +1,8 @@
+comment "Altera FPGA firmware download module"
+
+config ALTERA_STAPL
+       tristate "Altera FPGA firmware download module"
+       depends on I2C
+       default n
+       help
+         An Altera FPGA module. Say Y when you want to support this tool.
diff --git a/drivers/misc/altera-stapl/Makefile b/drivers/misc/altera-stapl/Makefile
new file mode 100644 (file)
index 0000000..055f61e
--- /dev/null
@@ -0,0 +1,3 @@
+altera-stapl-objs = altera-lpt.o altera-jtag.o altera-comp.o altera.o
+
+obj-$(CONFIG_ALTERA_STAPL) += altera-stapl.o
diff --git a/drivers/misc/altera-stapl/altera-comp.c b/drivers/misc/altera-stapl/altera-comp.c
new file mode 100644 (file)
index 0000000..49b103b
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * altera-comp.c
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include "altera-exprt.h"
+
+#define        SHORT_BITS              16
+#define        CHAR_BITS               8
+#define        DATA_BLOB_LENGTH        3
+#define        MATCH_DATA_LENGTH       8192
+#define ALTERA_REQUEST_SIZE    1024
+#define ALTERA_BUFFER_SIZE     (MATCH_DATA_LENGTH + ALTERA_REQUEST_SIZE)
+
+static u32 altera_bits_req(u32 n)
+{
+       u32 result = SHORT_BITS;
+
+       if (n == 0)
+               result = 1;
+       else {
+               /* Look for the highest non-zero bit position */
+               while ((n & (1 << (SHORT_BITS - 1))) == 0) {
+                       n <<= 1;
+                       --result;
+               }
+       }
+
+       return result;
+}
+
+static u32 altera_read_packed(u8 *buffer, u32 bits, u32 *bits_avail,
+                                                       u32 *in_index)
+{
+       u32 result = 0;
+       u32 shift = 0;
+       u32 databyte = 0;
+
+       while (bits > 0) {
+               databyte = buffer[*in_index];
+               result |= (((databyte >> (CHAR_BITS - *bits_avail))
+                       & (0xff >> (CHAR_BITS - *bits_avail))) << shift);
+
+               if (bits <= *bits_avail) {
+                       result &= (0xffff >> (SHORT_BITS - (bits + shift)));
+                       *bits_avail -= bits;
+                       bits = 0;
+               } else {
+                       ++(*in_index);
+                       shift += *bits_avail;
+                       bits -= *bits_avail;
+                       *bits_avail = CHAR_BITS;
+               }
+       }
+
+       return result;
+}
+
+u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version)
+{
+       u32 i, j, data_length = 0L;
+       u32 offset, length;
+       u32 match_data_length = MATCH_DATA_LENGTH;
+       u32 bits_avail = CHAR_BITS;
+       u32 in_index = 0L;
+
+       if (version > 0)
+               --match_data_length;
+
+       for (i = 0; i < out_length; ++i)
+               out[i] = 0;
+
+       /* Read number of bytes in data. */
+       for (i = 0; i < sizeof(in_length); ++i) {
+               data_length = data_length | (
+                       altera_read_packed(in,
+                                       CHAR_BITS,
+                                       &bits_avail,
+                                       &in_index) << (i * CHAR_BITS));
+       }
+
+       if (data_length > out_length) {
+               data_length = 0L;
+               return data_length;
+       }
+
+       i = 0;
+       while (i < data_length) {
+               /* A 0 bit indicates literal data. */
+               if (altera_read_packed(in, 1, &bits_avail,
+                                               &in_index) == 0) {
+                       for (j = 0; j < DATA_BLOB_LENGTH; ++j) {
+                               if (i < data_length) {
+                                       out[i] = (u8)altera_read_packed(in,
+                                                       CHAR_BITS,
+                                                       &bits_avail,
+                                                       &in_index);
+                                       i++;
+                               }
+                       }
+               } else {
+                       /* A 1 bit indicates offset/length to follow. */
+                       offset = altera_read_packed(in, altera_bits_req((s16)
+                                       (i > match_data_length ?
+                                               match_data_length : i)),
+                                       &bits_avail,
+                                       &in_index);
+                       length = altera_read_packed(in, CHAR_BITS,
+                                       &bits_avail,
+                                       &in_index);
+                       for (j = 0; j < length; ++j) {
+                               if (i < data_length) {
+                                       out[i] = out[i - offset];
+                                       i++;
+                               }
+                       }
+               }
+       }
+
+       return data_length;
+}
diff --git a/drivers/misc/altera-stapl/altera-exprt.h b/drivers/misc/altera-stapl/altera-exprt.h
new file mode 100644 (file)
index 0000000..39c38d8
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * altera-exprt.h
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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 ALTERA_EXPRT_H
+#define ALTERA_EXPRT_H
+
+
+u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version);
+int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo);
+
+#endif /* ALTERA_EXPRT_H */
diff --git a/drivers/misc/altera-stapl/altera-jtag.c b/drivers/misc/altera-stapl/altera-jtag.c
new file mode 100644 (file)
index 0000000..f4bf200
--- /dev/null
@@ -0,0 +1,1021 @@
+/*
+ * altera-jtag.c
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <misc/altera.h>
+#include "altera-exprt.h"
+#include "altera-jtag.h"
+
+#define        alt_jtag_io(a, b, c)\
+               astate->config->jtag_io(astate->config->dev, a, b, c);
+
+#define        alt_malloc(a)   kzalloc(a, GFP_KERNEL);
+
+/*
+ * This structure shows, for each JTAG state, which state is reached after
+ * a single TCK clock cycle with TMS high or TMS low, respectively.  This
+ * describes all possible state transitions in the JTAG state machine.
+ */
+struct altera_jtag_machine {
+       enum altera_jtag_state tms_high;
+       enum altera_jtag_state tms_low;
+};
+
+static const struct altera_jtag_machine altera_transitions[] = {
+       /* RESET     */ { RESET,        IDLE },
+       /* IDLE      */ { DRSELECT,     IDLE },
+       /* DRSELECT  */ { IRSELECT,     DRCAPTURE },
+       /* DRCAPTURE */ { DREXIT1,      DRSHIFT },
+       /* DRSHIFT   */ { DREXIT1,      DRSHIFT },
+       /* DREXIT1   */ { DRUPDATE,     DRPAUSE },
+       /* DRPAUSE   */ { DREXIT2,      DRPAUSE },
+       /* DREXIT2   */ { DRUPDATE,     DRSHIFT },
+       /* DRUPDATE  */ { DRSELECT,     IDLE },
+       /* IRSELECT  */ { RESET,        IRCAPTURE },
+       /* IRCAPTURE */ { IREXIT1,      IRSHIFT },
+       /* IRSHIFT   */ { IREXIT1,      IRSHIFT },
+       /* IREXIT1   */ { IRUPDATE,     IRPAUSE },
+       /* IRPAUSE   */ { IREXIT2,      IRPAUSE },
+       /* IREXIT2   */ { IRUPDATE,     IRSHIFT },
+       /* IRUPDATE  */ { DRSELECT,     IDLE }
+};
+
+/*
+ * This table contains the TMS value to be used to take the NEXT STEP on
+ * the path to the desired state.  The array index is the current state,
+ * and the bit position is the desired endstate.  To find out which state
+ * is used as the intermediate state, look up the TMS value in the
+ * altera_transitions[] table.
+ */
+static const u16 altera_jtag_path_map[16] = {
+       /* RST  RTI     SDRS    CDR     SDR     E1DR    PDR     E2DR */
+       0x0001, 0xFFFD, 0xFE01, 0xFFE7, 0xFFEF, 0xFF0F, 0xFFBF, 0xFFFF,
+       /* UDR  SIRS    CIR     SIR     E1IR    PIR     E2IR    UIR */
+       0xFEFD, 0x0001, 0xF3FF, 0xF7FF, 0x87FF, 0xDFFF, 0xFFFF, 0x7FFD
+};
+
+/* Flag bits for alt_jtag_io() function */
+#define TMS_HIGH   1
+#define TMS_LOW    0
+#define TDI_HIGH   1
+#define TDI_LOW    0
+#define READ_TDO   1
+#define IGNORE_TDO 0
+
+int altera_jinit(struct altera_state *astate)
+{
+       struct altera_jtag *js = &astate->js;
+
+       /* initial JTAG state is unknown */
+       js->jtag_state = ILLEGAL_JTAG_STATE;
+
+       /* initialize to default state */
+       js->drstop_state = IDLE;
+       js->irstop_state = IDLE;
+       js->dr_pre  = 0;
+       js->dr_post = 0;
+       js->ir_pre  = 0;
+       js->ir_post = 0;
+       js->dr_length    = 0;
+       js->ir_length    = 0;
+
+       js->dr_pre_data  = NULL;
+       js->dr_post_data = NULL;
+       js->ir_pre_data  = NULL;
+       js->ir_post_data = NULL;
+       js->dr_buffer    = NULL;
+       js->ir_buffer    = NULL;
+
+       return 0;
+}
+
+int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state)
+{
+       js->drstop_state = state;
+
+       return 0;
+}
+
+int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state)
+{
+       js->irstop_state = state;
+
+       return 0;
+}
+
+int altera_set_dr_pre(struct altera_jtag *js,
+                               u32 count, u32 start_index,
+                               u8 *preamble_data)
+{
+       int status = 0;
+       u32 i;
+       u32 j;
+
+       if (count > js->dr_pre) {
+               kfree(js->dr_pre_data);
+               js->dr_pre_data = (u8 *)alt_malloc((count + 7) >> 3);
+               if (js->dr_pre_data == NULL)
+                       status = -ENOMEM;
+               else
+                       js->dr_pre = count;
+       } else
+               js->dr_pre = count;
+
+       if (status == 0) {
+               for (i = 0; i < count; ++i) {
+                       j = i + start_index;
+
+                       if (preamble_data == NULL)
+                               js->dr_pre_data[i >> 3] |= (1 << (i & 7));
+                       else {
+                               if (preamble_data[j >> 3] & (1 << (j & 7)))
+                                       js->dr_pre_data[i >> 3] |=
+                                                       (1 << (i & 7));
+                               else
+                                       js->dr_pre_data[i >> 3] &=
+                                                       ~(u32)(1 << (i & 7));
+
+                       }
+               }
+       }
+
+       return status;
+}
+
+int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index,
+                                                       u8 *preamble_data)
+{
+       int status = 0;
+       u32 i;
+       u32 j;
+
+       if (count > js->ir_pre) {
+               kfree(js->ir_pre_data);
+               js->ir_pre_data = (u8 *)alt_malloc((count + 7) >> 3);
+               if (js->ir_pre_data == NULL)
+                       status = -ENOMEM;
+               else
+                       js->ir_pre = count;
+
+       } else
+               js->ir_pre = count;
+
+       if (status == 0) {
+               for (i = 0; i < count; ++i) {
+                       j = i + start_index;
+                       if (preamble_data == NULL)
+                               js->ir_pre_data[i >> 3] |= (1 << (i & 7));
+                       else {
+                               if (preamble_data[j >> 3] & (1 << (j & 7)))
+                                       js->ir_pre_data[i >> 3] |=
+                                                       (1 << (i & 7));
+                               else
+                                       js->ir_pre_data[i >> 3] &=
+                                                       ~(u32)(1 << (i & 7));
+
+                       }
+               }
+       }
+
+       return status;
+}
+
+int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index,
+                                               u8 *postamble_data)
+{
+       int status = 0;
+       u32 i;
+       u32 j;
+
+       if (count > js->dr_post) {
+               kfree(js->dr_post_data);
+               js->dr_post_data = (u8 *)alt_malloc((count + 7) >> 3);
+
+               if (js->dr_post_data == NULL)
+                       status = -ENOMEM;
+               else
+                       js->dr_post = count;
+
+       } else
+               js->dr_post = count;
+
+       if (status == 0) {
+               for (i = 0; i < count; ++i) {
+                       j = i + start_index;
+
+                       if (postamble_data == NULL)
+                               js->dr_post_data[i >> 3] |= (1 << (i & 7));
+                       else {
+                               if (postamble_data[j >> 3] & (1 << (j & 7)))
+                                       js->dr_post_data[i >> 3] |=
+                                                               (1 << (i & 7));
+                               else
+                                       js->dr_post_data[i >> 3] &=
+                                           ~(u32)(1 << (i & 7));
+
+                       }
+               }
+       }
+
+       return status;
+}
+
+int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index,
+                                               u8 *postamble_data)
+{
+       int status = 0;
+       u32 i;
+       u32 j;
+
+       if (count > js->ir_post) {
+               kfree(js->ir_post_data);
+               js->ir_post_data = (u8 *)alt_malloc((count + 7) >> 3);
+               if (js->ir_post_data == NULL)
+                       status = -ENOMEM;
+               else
+                       js->ir_post = count;
+
+       } else
+               js->ir_post = count;
+
+       if (status != 0)
+               return status;
+
+       for (i = 0; i < count; ++i) {
+               j = i + start_index;
+
+               if (postamble_data == NULL)
+                       js->ir_post_data[i >> 3] |= (1 << (i & 7));
+               else {
+                       if (postamble_data[j >> 3] & (1 << (j & 7)))
+                               js->ir_post_data[i >> 3] |= (1 << (i & 7));
+                       else
+                               js->ir_post_data[i >> 3] &=
+                                   ~(u32)(1 << (i & 7));
+
+               }
+       }
+
+       return status;
+}
+
+static void altera_jreset_idle(struct altera_state *astate)
+{
+       struct altera_jtag *js = &astate->js;
+       int i;
+       /* Go to Test Logic Reset (no matter what the starting state may be) */
+       for (i = 0; i < 5; ++i)
+               alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO);
+
+       /* Now step to Run Test / Idle */
+       alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO);
+       js->jtag_state = IDLE;
+}
+
+int altera_goto_jstate(struct altera_state *astate,
+                                       enum altera_jtag_state state)
+{
+       struct altera_jtag *js = &astate->js;
+       int tms;
+       int count = 0;
+       int status = 0;
+
+       if (js->jtag_state == ILLEGAL_JTAG_STATE)
+               /* initialize JTAG chain to known state */
+               altera_jreset_idle(astate);
+
+       if (js->jtag_state == state) {
+               /*
+                * We are already in the desired state.
+                * If it is a stable state, loop here.
+                * Otherwise do nothing (no clock cycles).
+                */
+               if ((state == IDLE) || (state == DRSHIFT) ||
+                       (state == DRPAUSE) || (state == IRSHIFT) ||
+                               (state == IRPAUSE)) {
+                       alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO);
+               } else if (state == RESET)
+                       alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO);
+
+       } else {
+               while ((js->jtag_state != state) && (count < 9)) {
+                       /* Get TMS value to take a step toward desired state */
+                       tms = (altera_jtag_path_map[js->jtag_state] &
+                                                       (1 << state))
+                                                       ? TMS_HIGH : TMS_LOW;
+
+                       /* Take a step */
+                       alt_jtag_io(tms, TDI_LOW, IGNORE_TDO);
+
+                       if (tms)
+                               js->jtag_state =
+                                       altera_transitions[js->jtag_state].tms_high;
+                       else
+                               js->jtag_state =
+                                       altera_transitions[js->jtag_state].tms_low;
+
+                       ++count;
+               }
+       }
+
+       if (js->jtag_state != state)
+               status = -EREMOTEIO;
+
+       return status;
+}
+
+int altera_wait_cycles(struct altera_state *astate,
+                                       s32 cycles,
+                                       enum altera_jtag_state wait_state)
+{
+       struct altera_jtag *js = &astate->js;
+       int tms;
+       s32 count;
+       int status = 0;
+
+       if (js->jtag_state != wait_state)
+               status = altera_goto_jstate(astate, wait_state);
+
+       if (status == 0) {
+               /*
+                * Set TMS high to loop in RESET state
+                * Set TMS low to loop in any other stable state
+                */
+               tms = (wait_state == RESET) ? TMS_HIGH : TMS_LOW;
+
+               for (count = 0L; count < cycles; count++)
+                       alt_jtag_io(tms, TDI_LOW, IGNORE_TDO);
+
+       }
+
+       return status;
+}
+
+int altera_wait_msecs(struct altera_state *astate,
+                       s32 microseconds, enum altera_jtag_state wait_state)
+/*
+ * Causes JTAG hardware to sit in the specified stable
+ * state for the specified duration of real time.  If
+ * no JTAG operations have been performed yet, then only
+ * a delay is performed.  This permits the WAIT USECS
+ * statement to be used in VECTOR programs without causing
+ * any JTAG operations.
+ * Returns 0 for success, else appropriate error code.
+ */
+{
+       struct altera_jtag *js = &astate->js;
+       int status = 0;
+
+       if ((js->jtag_state != ILLEGAL_JTAG_STATE) &&
+           (js->jtag_state != wait_state))
+               status = altera_goto_jstate(astate, wait_state);
+
+       if (status == 0)
+               /* Wait for specified time interval */
+               udelay(microseconds);
+
+       return status;
+}
+
+static void altera_concatenate_data(u8 *buffer,
+                               u8 *preamble_data,
+                               u32 preamble_count,
+                               u8 *target_data,
+                               u32 start_index,
+                               u32 target_count,
+                               u8 *postamble_data,
+                               u32 postamble_count)
+/*
+ * Copies preamble data, target data, and postamble data
+ * into one buffer for IR or DR scans.
+ */
+{
+       u32 i, j, k;
+
+       for (i = 0L; i < preamble_count; ++i) {
+               if (preamble_data[i >> 3L] & (1L << (i & 7L)))
+                       buffer[i >> 3L] |= (1L << (i & 7L));
+               else
+                       buffer[i >> 3L] &= ~(u32)(1L << (i & 7L));
+
+       }
+
+       j = start_index;
+       k = preamble_count + target_count;
+       for (; i < k; ++i, ++j) {
+               if (target_data[j >> 3L] & (1L << (j & 7L)))
+                       buffer[i >> 3L] |= (1L << (i & 7L));
+               else
+                       buffer[i >> 3L] &= ~(u32)(1L << (i & 7L));
+
+       }
+
+       j = 0L;
+       k = preamble_count + target_count + postamble_count;
+       for (; i < k; ++i, ++j) {
+               if (postamble_data[j >> 3L] & (1L << (j & 7L)))
+                       buffer[i >> 3L] |= (1L << (i & 7L));
+               else
+                       buffer[i >> 3L] &= ~(u32)(1L << (i & 7L));
+
+       }
+}
+
+static int alt_jtag_drscan(struct altera_state *astate,
+                       int start_state,
+                       int count,
+                       u8 *tdi,
+                       u8 *tdo)
+{
+       int i = 0;
+       int tdo_bit = 0;
+       int status = 1;
+
+       /* First go to DRSHIFT state */
+       switch (start_state) {
+       case 0:                                         /* IDLE */
+               alt_jtag_io(1, 0, 0);   /* DRSELECT */
+               alt_jtag_io(0, 0, 0);   /* DRCAPTURE */
+               alt_jtag_io(0, 0, 0);   /* DRSHIFT */
+               break;
+
+       case 1:                                         /* DRPAUSE */
+               alt_jtag_io(1, 0, 0);   /* DREXIT2 */
+               alt_jtag_io(1, 0, 0);   /* DRUPDATE */
+               alt_jtag_io(1, 0, 0);   /* DRSELECT */
+               alt_jtag_io(0, 0, 0);   /* DRCAPTURE */
+               alt_jtag_io(0, 0, 0);   /* DRSHIFT */
+               break;
+
+       case 2:                                         /* IRPAUSE */
+               alt_jtag_io(1, 0, 0);   /* IREXIT2 */
+               alt_jtag_io(1, 0, 0);   /* IRUPDATE */
+               alt_jtag_io(1, 0, 0);   /* DRSELECT */
+               alt_jtag_io(0, 0, 0);   /* DRCAPTURE */
+               alt_jtag_io(0, 0, 0);   /* DRSHIFT */
+               break;
+
+       default:
+               status = 0;
+       }
+
+       if (status) {
+               /* loop in the SHIFT-DR state */
+               for (i = 0; i < count; i++) {
+                       tdo_bit = alt_jtag_io(
+                                       (i == count - 1),
+                                       tdi[i >> 3] & (1 << (i & 7)),
+                                       (tdo != NULL));
+
+                       if (tdo != NULL) {
+                               if (tdo_bit)
+                                       tdo[i >> 3] |= (1 << (i & 7));
+                               else
+                                       tdo[i >> 3] &= ~(u32)(1 << (i & 7));
+
+                       }
+               }
+
+               alt_jtag_io(0, 0, 0);   /* DRPAUSE */
+       }
+
+       return status;
+}
+
+static int alt_jtag_irscan(struct altera_state *astate,
+                   int start_state,
+                   int count,
+                   u8 *tdi,
+                   u8 *tdo)
+{
+       int i = 0;
+       int tdo_bit = 0;
+       int status = 1;
+
+       /* First go to IRSHIFT state */
+       switch (start_state) {
+       case 0:                                         /* IDLE */
+               alt_jtag_io(1, 0, 0);   /* DRSELECT */
+               alt_jtag_io(1, 0, 0);   /* IRSELECT */
+               alt_jtag_io(0, 0, 0);   /* IRCAPTURE */
+               alt_jtag_io(0, 0, 0);   /* IRSHIFT */
+               break;
+
+       case 1:                                         /* DRPAUSE */
+               alt_jtag_io(1, 0, 0);   /* DREXIT2 */
+               alt_jtag_io(1, 0, 0);   /* DRUPDATE */
+               alt_jtag_io(1, 0, 0);   /* DRSELECT */
+               alt_jtag_io(1, 0, 0);   /* IRSELECT */
+               alt_jtag_io(0, 0, 0);   /* IRCAPTURE */
+               alt_jtag_io(0, 0, 0);   /* IRSHIFT */
+               break;
+
+       case 2:                                         /* IRPAUSE */
+               alt_jtag_io(1, 0, 0);   /* IREXIT2 */
+               alt_jtag_io(1, 0, 0);   /* IRUPDATE */
+               alt_jtag_io(1, 0, 0);   /* DRSELECT */
+               alt_jtag_io(1, 0, 0);   /* IRSELECT */
+               alt_jtag_io(0, 0, 0);   /* IRCAPTURE */
+               alt_jtag_io(0, 0, 0);   /* IRSHIFT */
+               break;
+
+       default:
+               status = 0;
+       }
+
+       if (status) {
+               /* loop in the SHIFT-IR state */
+               for (i = 0; i < count; i++) {
+                       tdo_bit = alt_jtag_io(
+                                     (i == count - 1),
+                                     tdi[i >> 3] & (1 << (i & 7)),
+                                     (tdo != NULL));
+                       if (tdo != NULL) {
+                               if (tdo_bit)
+                                       tdo[i >> 3] |= (1 << (i & 7));
+                               else
+                                       tdo[i >> 3] &= ~(u32)(1 << (i & 7));
+
+                       }
+               }
+
+               alt_jtag_io(0, 0, 0);   /* IRPAUSE */
+       }
+
+       return status;
+}
+
+static void altera_extract_target_data(u8 *buffer,
+                               u8 *target_data,
+                               u32 start_index,
+                               u32 preamble_count,
+                               u32 target_count)
+/*
+ * Copies target data from scan buffer, filtering out
+ * preamble and postamble data.
+ */
+{
+       u32 i;
+       u32 j;
+       u32 k;
+
+       j = preamble_count;
+       k = start_index + target_count;
+       for (i = start_index; i < k; ++i, ++j) {
+               if (buffer[j >> 3] & (1 << (j & 7)))
+                       target_data[i >> 3] |= (1 << (i & 7));
+               else
+                       target_data[i >> 3] &= ~(u32)(1 << (i & 7));
+
+       }
+}
+
+int altera_irscan(struct altera_state *astate,
+                               u32 count,
+                               u8 *tdi_data,
+                               u32 start_index)
+/* Shifts data into instruction register */
+{
+       struct altera_jtag *js = &astate->js;
+       int start_code = 0;
+       u32 alloc_chars = 0;
+       u32 shift_count = js->ir_pre + count + js->ir_post;
+       int status = 0;
+       enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE;
+
+       switch (js->jtag_state) {
+       case ILLEGAL_JTAG_STATE:
+       case RESET:
+       case IDLE:
+               start_code = 0;
+               start_state = IDLE;
+               break;
+
+       case DRSELECT:
+       case DRCAPTURE:
+       case DRSHIFT:
+       case DREXIT1:
+       case DRPAUSE:
+       case DREXIT2:
+       case DRUPDATE:
+               start_code = 1;
+               start_state = DRPAUSE;
+               break;
+
+       case IRSELECT:
+       case IRCAPTURE:
+       case IRSHIFT:
+       case IREXIT1:
+       case IRPAUSE:
+       case IREXIT2:
+       case IRUPDATE:
+               start_code = 2;
+               start_state = IRPAUSE;
+               break;
+
+       default:
+               status = -EREMOTEIO;
+               break;
+       }
+
+       if (status == 0)
+               if (js->jtag_state != start_state)
+                       status = altera_goto_jstate(astate, start_state);
+
+       if (status == 0) {
+               if (shift_count > js->ir_length) {
+                       alloc_chars = (shift_count + 7) >> 3;
+                       kfree(js->ir_buffer);
+                       js->ir_buffer = (u8 *)alt_malloc(alloc_chars);
+                       if (js->ir_buffer == NULL)
+                               status = -ENOMEM;
+                       else
+                               js->ir_length = alloc_chars * 8;
+
+               }
+       }
+
+       if (status == 0) {
+               /*
+                * Copy preamble data, IR data,
+                * and postamble data into a buffer
+                */
+               altera_concatenate_data(js->ir_buffer,
+                                       js->ir_pre_data,
+                                       js->ir_pre,
+                                       tdi_data,
+                                       start_index,
+                                       count,
+                                       js->ir_post_data,
+                                       js->ir_post);
+               /* Do the IRSCAN */
+               alt_jtag_irscan(astate,
+                               start_code,
+                               shift_count,
+                               js->ir_buffer,
+                               NULL);
+
+               /* alt_jtag_irscan() always ends in IRPAUSE state */
+               js->jtag_state = IRPAUSE;
+       }
+
+       if (status == 0)
+               if (js->irstop_state != IRPAUSE)
+                       status = altera_goto_jstate(astate, js->irstop_state);
+
+
+       return status;
+}
+
+int altera_swap_ir(struct altera_state *astate,
+                           u32 count,
+                           u8 *in_data,
+                           u32 in_index,
+                           u8 *out_data,
+                           u32 out_index)
+/* Shifts data into instruction register, capturing output data */
+{
+       struct altera_jtag *js = &astate->js;
+       int start_code = 0;
+       u32 alloc_chars = 0;
+       u32 shift_count = js->ir_pre + count + js->ir_post;
+       int status = 0;
+       enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE;
+
+       switch (js->jtag_state) {
+       case ILLEGAL_JTAG_STATE:
+       case RESET:
+       case IDLE:
+               start_code = 0;
+               start_state = IDLE;
+               break;
+
+       case DRSELECT:
+       case DRCAPTURE:
+       case DRSHIFT:
+       case DREXIT1:
+       case DRPAUSE:
+       case DREXIT2:
+       case DRUPDATE:
+               start_code = 1;
+               start_state = DRPAUSE;
+               break;
+
+       case IRSELECT:
+       case IRCAPTURE:
+       case IRSHIFT:
+       case IREXIT1:
+       case IRPAUSE:
+       case IREXIT2:
+       case IRUPDATE:
+               start_code = 2;
+               start_state = IRPAUSE;
+               break;
+
+       default:
+               status = -EREMOTEIO;
+               break;
+       }
+
+       if (status == 0)
+               if (js->jtag_state != start_state)
+                       status = altera_goto_jstate(astate, start_state);
+
+       if (status == 0) {
+               if (shift_count > js->ir_length) {
+                       alloc_chars = (shift_count + 7) >> 3;
+                       kfree(js->ir_buffer);
+                       js->ir_buffer = (u8 *)alt_malloc(alloc_chars);
+                       if (js->ir_buffer == NULL)
+                               status = -ENOMEM;
+                       else
+                               js->ir_length = alloc_chars * 8;
+
+               }
+       }
+
+       if (status == 0) {
+               /*
+                * Copy preamble data, IR data,
+                * and postamble data into a buffer
+                */
+               altera_concatenate_data(js->ir_buffer,
+                                       js->ir_pre_data,
+                                       js->ir_pre,
+                                       in_data,
+                                       in_index,
+                                       count,
+                                       js->ir_post_data,
+                                       js->ir_post);
+
+               /* Do the IRSCAN */
+               alt_jtag_irscan(astate,
+                               start_code,
+                               shift_count,
+                               js->ir_buffer,
+                               js->ir_buffer);
+
+               /* alt_jtag_irscan() always ends in IRPAUSE state */
+               js->jtag_state = IRPAUSE;
+       }
+
+       if (status == 0)
+               if (js->irstop_state != IRPAUSE)
+                       status = altera_goto_jstate(astate, js->irstop_state);
+
+
+       if (status == 0)
+               /* Now extract the returned data from the buffer */
+               altera_extract_target_data(js->ir_buffer,
+                                       out_data, out_index,
+                                       js->ir_pre, count);
+
+       return status;
+}
+
+int altera_drscan(struct altera_state *astate,
+                               u32 count,
+                               u8 *tdi_data,
+                               u32 start_index)
+/* Shifts data into data register (ignoring output data) */
+{
+       struct altera_jtag *js = &astate->js;
+       int start_code = 0;
+       u32 alloc_chars = 0;
+       u32 shift_count = js->dr_pre + count + js->dr_post;
+       int status = 0;
+       enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE;
+
+       switch (js->jtag_state) {
+       case ILLEGAL_JTAG_STATE:
+       case RESET:
+       case IDLE:
+               start_code = 0;
+               start_state = IDLE;
+               break;
+
+       case DRSELECT:
+       case DRCAPTURE:
+       case DRSHIFT:
+       case DREXIT1:
+       case DRPAUSE:
+       case DREXIT2:
+       case DRUPDATE:
+               start_code = 1;
+               start_state = DRPAUSE;
+               break;
+
+       case IRSELECT:
+       case IRCAPTURE:
+       case IRSHIFT:
+       case IREXIT1:
+       case IRPAUSE:
+       case IREXIT2:
+       case IRUPDATE:
+               start_code = 2;
+               start_state = IRPAUSE;
+               break;
+
+       default:
+               status = -EREMOTEIO;
+               break;
+       }
+
+       if (status == 0)
+               if (js->jtag_state != start_state)
+                       status = altera_goto_jstate(astate, start_state);
+
+       if (status == 0) {
+               if (shift_count > js->dr_length) {
+                       alloc_chars = (shift_count + 7) >> 3;
+                       kfree(js->dr_buffer);
+                       js->dr_buffer = (u8 *)alt_malloc(alloc_chars);
+                       if (js->dr_buffer == NULL)
+                               status = -ENOMEM;
+                       else
+                               js->dr_length = alloc_chars * 8;
+
+               }
+       }
+
+       if (status == 0) {
+               /*
+                * Copy preamble data, DR data,
+                * and postamble data into a buffer
+                */
+               altera_concatenate_data(js->dr_buffer,
+                                       js->dr_pre_data,
+                                       js->dr_pre,
+                                       tdi_data,
+                                       start_index,
+                                       count,
+                                       js->dr_post_data,
+                                       js->dr_post);
+               /* Do the DRSCAN */
+               alt_jtag_drscan(astate, start_code, shift_count,
+                               js->dr_buffer, NULL);
+               /* alt_jtag_drscan() always ends in DRPAUSE state */
+               js->jtag_state = DRPAUSE;
+       }
+
+       if (status == 0)
+               if (js->drstop_state != DRPAUSE)
+                       status = altera_goto_jstate(astate, js->drstop_state);
+
+       return status;
+}
+
+int altera_swap_dr(struct altera_state *astate, u32 count,
+                               u8 *in_data, u32 in_index,
+                               u8 *out_data, u32 out_index)
+/* Shifts data into data register, capturing output data */
+{
+       struct altera_jtag *js = &astate->js;
+       int start_code = 0;
+       u32 alloc_chars = 0;
+       u32 shift_count = js->dr_pre + count + js->dr_post;
+       int status = 0;
+       enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE;
+
+       switch (js->jtag_state) {
+       case ILLEGAL_JTAG_STATE:
+       case RESET:
+       case IDLE:
+               start_code = 0;
+               start_state = IDLE;
+               break;
+
+       case DRSELECT:
+       case DRCAPTURE:
+       case DRSHIFT:
+       case DREXIT1:
+       case DRPAUSE:
+       case DREXIT2:
+       case DRUPDATE:
+               start_code = 1;
+               start_state = DRPAUSE;
+               break;
+
+       case IRSELECT:
+       case IRCAPTURE:
+       case IRSHIFT:
+       case IREXIT1:
+       case IRPAUSE:
+       case IREXIT2:
+       case IRUPDATE:
+               start_code = 2;
+               start_state = IRPAUSE;
+               break;
+
+       default:
+               status = -EREMOTEIO;
+               break;
+       }
+
+       if (status == 0)
+               if (js->jtag_state != start_state)
+                       status = altera_goto_jstate(astate, start_state);
+
+       if (status == 0) {
+               if (shift_count > js->dr_length) {
+                       alloc_chars = (shift_count + 7) >> 3;
+                       kfree(js->dr_buffer);
+                       js->dr_buffer = (u8 *)alt_malloc(alloc_chars);
+
+                       if (js->dr_buffer == NULL)
+                               status = -ENOMEM;
+                       else
+                               js->dr_length = alloc_chars * 8;
+
+               }
+       }
+
+       if (status == 0) {
+               /*
+                * Copy preamble data, DR data,
+                * and postamble data into a buffer
+                */
+               altera_concatenate_data(js->dr_buffer,
+                               js->dr_pre_data,
+                               js->dr_pre,
+                               in_data,
+                               in_index,
+                               count,
+                               js->dr_post_data,
+                               js->dr_post);
+
+               /* Do the DRSCAN */
+               alt_jtag_drscan(astate,
+                               start_code,
+                               shift_count,
+                               js->dr_buffer,
+                               js->dr_buffer);
+
+               /* alt_jtag_drscan() always ends in DRPAUSE state */
+               js->jtag_state = DRPAUSE;
+       }
+
+       if (status == 0)
+               if (js->drstop_state != DRPAUSE)
+                       status = altera_goto_jstate(astate, js->drstop_state);
+
+       if (status == 0)
+               /* Now extract the returned data from the buffer */
+               altera_extract_target_data(js->dr_buffer,
+                                       out_data,
+                                       out_index,
+                                       js->dr_pre,
+                                       count);
+
+       return status;
+}
+
+void altera_free_buffers(struct altera_state *astate)
+{
+       struct altera_jtag *js = &astate->js;
+       /* If the JTAG interface was used, reset it to TLR */
+       if (js->jtag_state != ILLEGAL_JTAG_STATE)
+               altera_jreset_idle(astate);
+
+       kfree(js->dr_pre_data);
+       js->dr_pre_data = NULL;
+
+       kfree(js->dr_post_data);
+       js->dr_post_data = NULL;
+
+       kfree(js->dr_buffer);
+       js->dr_buffer = NULL;
+
+       kfree(js->ir_pre_data);
+       js->ir_pre_data = NULL;
+
+       kfree(js->ir_post_data);
+       js->ir_post_data = NULL;
+
+       kfree(js->ir_buffer);
+       js->ir_buffer = NULL;
+}
diff --git a/drivers/misc/altera-stapl/altera-jtag.h b/drivers/misc/altera-stapl/altera-jtag.h
new file mode 100644 (file)
index 0000000..2f97e36
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * altera-jtag.h
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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 ALTERA_JTAG_H
+#define ALTERA_JTAG_H
+
+/* Function Prototypes */
+enum altera_jtag_state {
+       ILLEGAL_JTAG_STATE = -1,
+       RESET = 0,
+       IDLE = 1,
+       DRSELECT = 2,
+       DRCAPTURE = 3,
+       DRSHIFT = 4,
+       DREXIT1 = 5,
+       DRPAUSE = 6,
+       DREXIT2 = 7,
+       DRUPDATE = 8,
+       IRSELECT = 9,
+       IRCAPTURE = 10,
+       IRSHIFT = 11,
+       IREXIT1 = 12,
+       IRPAUSE = 13,
+       IREXIT2 = 14,
+       IRUPDATE = 15
+
+};
+
+struct altera_jtag {
+       /* Global variable to store the current JTAG state */
+       enum altera_jtag_state jtag_state;
+
+       /* Store current stop-state for DR and IR scan commands */
+       enum altera_jtag_state drstop_state;
+       enum altera_jtag_state irstop_state;
+
+       /* Store current padding values */
+       u32 dr_pre;
+       u32 dr_post;
+       u32 ir_pre;
+       u32 ir_post;
+       u32 dr_length;
+       u32 ir_length;
+       u8 *dr_pre_data;
+       u8 *dr_post_data;
+       u8 *ir_pre_data;
+       u8 *ir_post_data;
+       u8 *dr_buffer;
+       u8 *ir_buffer;
+};
+
+#define ALTERA_STACK_SIZE 128
+#define ALTERA_MESSAGE_LENGTH 1024
+
+struct altera_state {
+       struct altera_config    *config;
+       struct altera_jtag      js;
+       char                    msg_buff[ALTERA_MESSAGE_LENGTH + 1];
+       long                    stack[ALTERA_STACK_SIZE];
+};
+
+int altera_jinit(struct altera_state *astate);
+int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state);
+int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state);
+int altera_set_dr_pre(struct altera_jtag *js, u32 count, u32 start_index,
+                               u8 *preamble_data);
+int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index,
+                               u8 *preamble_data);
+int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index,
+                               u8 *postamble_data);
+int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index,
+                               u8 *postamble_data);
+int altera_goto_jstate(struct altera_state *astate,
+                               enum altera_jtag_state state);
+int altera_wait_cycles(struct altera_state *astate, s32 cycles,
+                               enum altera_jtag_state wait_state);
+int altera_wait_msecs(struct altera_state *astate, s32 microseconds,
+                               enum altera_jtag_state wait_state);
+int altera_irscan(struct altera_state *astate, u32 count,
+                               u8 *tdi_data, u32 start_index);
+int altera_swap_ir(struct altera_state *astate,
+                               u32 count, u8 *in_data,
+                               u32 in_index, u8 *out_data,
+                               u32 out_index);
+int altera_drscan(struct altera_state *astate, u32 count,
+                               u8 *tdi_data, u32 start_index);
+int altera_swap_dr(struct altera_state *astate, u32 count,
+                               u8 *in_data, u32 in_index,
+                               u8 *out_data, u32 out_index);
+void altera_free_buffers(struct altera_state *astate);
+#endif /* ALTERA_JTAG_H */
diff --git a/drivers/misc/altera-stapl/altera-lpt.c b/drivers/misc/altera-stapl/altera-lpt.c
new file mode 100644 (file)
index 0000000..91456a0
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * altera-lpt.c
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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/io.h>
+#include <linux/kernel.h>
+#include "altera-exprt.h"
+
+static int lpt_hardware_initialized;
+
+static void byteblaster_write(int port, int data)
+{
+       outb((u8)data, (u16)(port + 0x378));
+};
+
+static int byteblaster_read(int port)
+{
+       int data = 0;
+       data = inb((u16)(port + 0x378));
+       return data & 0xff;
+};
+
+int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo)
+{
+       int data = 0;
+       int tdo = 0;
+       int initial_lpt_ctrl = 0;
+
+       if (!lpt_hardware_initialized) {
+               initial_lpt_ctrl = byteblaster_read(2);
+               byteblaster_write(2, (initial_lpt_ctrl | 0x02) & 0xdf);
+               lpt_hardware_initialized = 1;
+       }
+
+       data = ((tdi ? 0x40 : 0) | (tms ? 0x02 : 0));
+
+       byteblaster_write(0, data);
+
+       if (read_tdo) {
+               tdo = byteblaster_read(1);
+               tdo = ((tdo & 0x80) ? 0 : 1);
+       }
+
+       byteblaster_write(0, data | 0x01);
+
+       byteblaster_write(0, data);
+
+       return tdo;
+}
diff --git a/drivers/misc/altera-stapl/altera.c b/drivers/misc/altera-stapl/altera.c
new file mode 100644 (file)
index 0000000..24272e0
--- /dev/null
@@ -0,0 +1,2537 @@
+/*
+ * altera.c
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010,2011 NetUP Inc.
+ * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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 <asm/unaligned.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <misc/altera.h>
+#include "altera-exprt.h"
+#include "altera-jtag.h"
+
+static int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debugging information");
+
+MODULE_DESCRIPTION("altera FPGA kernel module");
+MODULE_AUTHOR("Igor M. Liplianin  <liplianin@netup.ru>");
+MODULE_LICENSE("GPL");
+
+#define dprintk(args...) \
+       if (debug) { \
+               printk(KERN_DEBUG args); \
+       }
+
+enum altera_fpga_opcode {
+       OP_NOP = 0,
+       OP_DUP,
+       OP_SWP,
+       OP_ADD,
+       OP_SUB,
+       OP_MULT,
+       OP_DIV,
+       OP_MOD,
+       OP_SHL,
+       OP_SHR,
+       OP_NOT,
+       OP_AND,
+       OP_OR,
+       OP_XOR,
+       OP_INV,
+       OP_GT,
+       OP_LT,
+       OP_RET,
+       OP_CMPS,
+       OP_PINT,
+       OP_PRNT,
+       OP_DSS,
+       OP_DSSC,
+       OP_ISS,
+       OP_ISSC,
+       OP_DPR = 0x1c,
+       OP_DPRL,
+       OP_DPO,
+       OP_DPOL,
+       OP_IPR,
+       OP_IPRL,
+       OP_IPO,
+       OP_IPOL,
+       OP_PCHR,
+       OP_EXIT,
+       OP_EQU,
+       OP_POPT,
+       OP_ABS = 0x2c,
+       OP_BCH0,
+       OP_PSH0 = 0x2f,
+       OP_PSHL = 0x40,
+       OP_PSHV,
+       OP_JMP,
+       OP_CALL,
+       OP_NEXT,
+       OP_PSTR,
+       OP_SINT = 0x47,
+       OP_ST,
+       OP_ISTP,
+       OP_DSTP,
+       OP_SWPN,
+       OP_DUPN,
+       OP_POPV,
+       OP_POPE,
+       OP_POPA,
+       OP_JMPZ,
+       OP_DS,
+       OP_IS,
+       OP_DPRA,
+       OP_DPOA,
+       OP_IPRA,
+       OP_IPOA,
+       OP_EXPT,
+       OP_PSHE,
+       OP_PSHA,
+       OP_DYNA,
+       OP_EXPV = 0x5c,
+       OP_COPY = 0x80,
+       OP_REVA,
+       OP_DSC,
+       OP_ISC,
+       OP_WAIT,
+       OP_VS,
+       OP_CMPA = 0xc0,
+       OP_VSC,
+};
+
+struct altera_procinfo {
+       char                    *name;
+       u8                      attrs;
+       struct altera_procinfo  *next;
+};
+
+/* This function checks if enough parameters are available on the stack. */
+static int altera_check_stack(int stack_ptr, int count, int *status)
+{
+       if (stack_ptr < count) {
+               *status = -EOVERFLOW;
+               return 0;
+       }
+
+       return 1;
+}
+
+static void altera_export_int(char *key, s32 value)
+{
+       dprintk("Export: key = \"%s\", value = %d\n", key, value);
+}
+
+#define HEX_LINE_CHARS 72
+#define HEX_LINE_BITS (HEX_LINE_CHARS * 4)
+
+static void altera_export_bool_array(char *key, u8 *data, s32 count)
+{
+       char string[HEX_LINE_CHARS + 1];
+       s32 i, offset;
+       u32 size, line, lines, linebits, value, j, k;
+
+       if (count > HEX_LINE_BITS) {
+               dprintk("Export: key = \"%s\", %d bits, value = HEX\n",
+                                                       key, count);
+               lines = (count + (HEX_LINE_BITS - 1)) / HEX_LINE_BITS;
+
+               for (line = 0; line < lines; ++line) {
+                       if (line < (lines - 1)) {
+                               linebits = HEX_LINE_BITS;
+                               size = HEX_LINE_CHARS;
+                               offset = count - ((line + 1) * HEX_LINE_BITS);
+                       } else {
+                               linebits =
+                                       count - ((lines - 1) * HEX_LINE_BITS);
+                               size = (linebits + 3) / 4;
+                               offset = 0L;
+                       }
+
+                       string[size] = '\0';
+                       j = size - 1;
+                       value = 0;
+
+                       for (k = 0; k < linebits; ++k) {
+                               i = k + offset;
+                               if (data[i >> 3] & (1 << (i & 7)))
+                                       value |= (1 << (i & 3));
+                               if ((i & 3) == 3) {
+                                       sprintf(&string[j], "%1x", value);
+                                       value = 0;
+                                       --j;
+                               }
+                       }
+                       if ((k & 3) > 0)
+                               sprintf(&string[j], "%1x", value);
+
+                       dprintk("%s\n", string);
+               }
+
+       } else {
+               size = (count + 3) / 4;
+               string[size] = '\0';
+               j = size - 1;
+               value = 0;
+
+               for (i = 0; i < count; ++i) {
+                       if (data[i >> 3] & (1 << (i & 7)))
+                               value |= (1 << (i & 3));
+                       if ((i & 3) == 3) {
+                               sprintf(&string[j], "%1x", value);
+                               value = 0;
+                               --j;
+                       }
+               }
+               if ((i & 3) > 0)
+                       sprintf(&string[j], "%1x", value);
+
+               dprintk("Export: key = \"%s\", %d bits, value = HEX %s\n",
+                       key, count, string);
+       }
+}
+
+static int altera_execute(struct altera_state *astate,
+                               u8 *p,
+                               s32 program_size,
+                               s32 *error_address,
+                               int *exit_code,
+                               int *format_version)
+{
+       struct altera_config *aconf = astate->config;
+       char *msg_buff = astate->msg_buff;
+       long *stack = astate->stack;
+       int status = 0;
+       u32 first_word = 0L;
+       u32 action_table = 0L;
+       u32 proc_table = 0L;
+       u32 str_table = 0L;
+       u32 sym_table = 0L;
+       u32 data_sect = 0L;
+       u32 code_sect = 0L;
+       u32 debug_sect = 0L;
+       u32 action_count = 0L;
+       u32 proc_count = 0L;
+       u32 sym_count = 0L;
+       long *vars = NULL;
+       s32 *var_size = NULL;
+       char *attrs = NULL;
+       u8 *proc_attributes = NULL;
+       u32 pc;
+       u32 opcode_address;
+       u32 args[3];
+       u32 opcode;
+       u32 name_id;
+       u8 charbuf[4];
+       long long_tmp;
+       u32 variable_id;
+       u8 *charptr_tmp;
+       u8 *charptr_tmp2;
+       long *longptr_tmp;
+       int version = 0;
+       int delta = 0;
+       int stack_ptr = 0;
+       u32 arg_count;
+       int done = 0;
+       int bad_opcode = 0;
+       u32 count;
+       u32 index;
+       u32 index2;
+       s32 long_count;
+       s32 long_idx;
+       s32 long_idx2;
+       u32 i;
+       u32 j;
+       u32 uncomp_size;
+       u32 offset;
+       u32 value;
+       int current_proc = 0;
+       int reverse;
+
+       char *name;
+
+       dprintk("%s\n", __func__);
+
+       /* Read header information */
+       if (program_size > 52L) {
+               first_word    = get_unaligned_be32(&p[0]);
+               version = (first_word & 1L);
+               *format_version = version + 1;
+               delta = version * 8;
+
+               action_table  = get_unaligned_be32(&p[4]);
+               proc_table    = get_unaligned_be32(&p[8]);
+               str_table  = get_unaligned_be32(&p[4 + delta]);
+               sym_table  = get_unaligned_be32(&p[16 + delta]);
+               data_sect  = get_unaligned_be32(&p[20 + delta]);
+               code_sect  = get_unaligned_be32(&p[24 + delta]);
+               debug_sect = get_unaligned_be32(&p[28 + delta]);
+               action_count  = get_unaligned_be32(&p[40 + delta]);
+               proc_count    = get_unaligned_be32(&p[44 + delta]);
+               sym_count  = get_unaligned_be32(&p[48 + (2 * delta)]);
+       }
+
+       if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) {
+               done = 1;
+               status = -EIO;
+               goto exit_done;
+       }
+
+       if (sym_count <= 0)
+               goto exit_done;
+
+       vars = kzalloc(sym_count * sizeof(long), GFP_KERNEL);
+
+       if (vars == NULL)
+               status = -ENOMEM;
+
+       if (status == 0) {
+               var_size = kzalloc(sym_count * sizeof(s32), GFP_KERNEL);
+
+               if (var_size == NULL)
+                       status = -ENOMEM;
+       }
+
+       if (status == 0) {
+               attrs = kzalloc(sym_count, GFP_KERNEL);
+
+               if (attrs == NULL)
+                       status = -ENOMEM;
+       }
+
+       if ((status == 0) && (version > 0)) {
+               proc_attributes = kzalloc(proc_count, GFP_KERNEL);
+
+               if (proc_attributes == NULL)
+                       status = -ENOMEM;
+       }
+
+       if (status != 0)
+               goto exit_done;
+
+       delta = version * 2;
+
+       for (i = 0; i < sym_count; ++i) {
+               offset = (sym_table + ((11 + delta) * i));
+
+               value = get_unaligned_be32(&p[offset + 3 + delta]);
+
+               attrs[i] = p[offset];
+
+               /*
+                * use bit 7 of attribute byte to indicate that
+                * this buffer was dynamically allocated
+                * and should be freed later
+                */
+               attrs[i] &= 0x7f;
+
+               var_size[i] = get_unaligned_be32(&p[offset + 7 + delta]);
+
+               /*
+                * Attribute bits:
+                * bit 0: 0 = read-only, 1 = read-write
+                * bit 1: 0 = not compressed, 1 = compressed
+                * bit 2: 0 = not initialized, 1 = initialized
+                * bit 3: 0 = scalar, 1 = array
+                * bit 4: 0 = Boolean, 1 = integer
+                * bit 5: 0 = declared variable,
+                *      1 = compiler created temporary variable
+                */
+
+               if ((attrs[i] & 0x0c) == 0x04)
+                       /* initialized scalar variable */
+                       vars[i] = value;
+               else if ((attrs[i] & 0x1e) == 0x0e) {
+                       /* initialized compressed Boolean array */
+                       uncomp_size = get_unaligned_le32(&p[data_sect + value]);
+
+                       /* allocate a buffer for the uncompressed data */
+                       vars[i] = (long)kzalloc(uncomp_size, GFP_KERNEL);
+                       if (vars[i] == 0L)
+                               status = -ENOMEM;
+                       else {
+                               /* set flag so buffer will be freed later */
+                               attrs[i] |= 0x80;
+
+                               /* uncompress the data */
+                               if (altera_shrink(&p[data_sect + value],
+                                               var_size[i],
+                                               (u8 *)vars[i],
+                                               uncomp_size,
+                                               version) != uncomp_size)
+                                       /* decompression failed */
+                                       status = -EIO;
+                               else
+                                       var_size[i] = uncomp_size * 8L;
+
+                       }
+               } else if ((attrs[i] & 0x1e) == 0x0c) {
+                       /* initialized Boolean array */
+                       vars[i] = value + data_sect + (long)p;
+               } else if ((attrs[i] & 0x1c) == 0x1c) {
+                       /* initialized integer array */
+                       vars[i] = value + data_sect;
+               } else if ((attrs[i] & 0x0c) == 0x08) {
+                       /* uninitialized array */
+
+                       /* flag attrs so that memory is freed */
+                       attrs[i] |= 0x80;
+
+                       if (var_size[i] > 0) {
+                               u32 size;
+
+                               if (attrs[i] & 0x10)
+                                       /* integer array */
+                                       size = (var_size[i] * sizeof(s32));
+                               else
+                                       /* Boolean array */
+                                       size = ((var_size[i] + 7L) / 8L);
+
+                               vars[i] = (long)kzalloc(size, GFP_KERNEL);
+
+                               if (vars[i] == 0) {
+                                       status = -ENOMEM;
+                               } else {
+                                       /* zero out memory */
+                                       for (j = 0; j < size; ++j)
+                                               ((u8 *)(vars[i]))[j] = 0;
+
+                               }
+                       } else
+                               vars[i] = 0;
+
+               } else
+                       vars[i] = 0;
+
+       }
+
+exit_done:
+       if (status != 0)
+               done = 1;
+
+       altera_jinit(astate);
+
+       pc = code_sect;
+       msg_buff[0] = '\0';
+
+       /*
+        * For JBC version 2, we will execute the procedures corresponding to
+        * the selected ACTION
+        */
+       if (version > 0) {
+               if (aconf->action == NULL) {
+                       status = -EINVAL;
+                       done = 1;
+               } else {
+                       int action_found = 0;
+                       for (i = 0; (i < action_count) && !action_found; ++i) {
+                               name_id = get_unaligned_be32(&p[action_table +
+                                                               (12 * i)]);
+
+                               name = &p[str_table + name_id];
+
+                               if (strnicmp(aconf->action, name, strlen(name)) == 0) {
+                                       action_found = 1;
+                                       current_proc =
+                                               get_unaligned_be32(&p[action_table +
+                                                               (12 * i) + 8]);
+                               }
+                       }
+
+                       if (!action_found) {
+                               status = -EINVAL;
+                               done = 1;
+                       }
+               }
+
+               if (status == 0) {
+                       int first_time = 1;
+                       i = current_proc;
+                       while ((i != 0) || first_time) {
+                               first_time = 0;
+                               /* check procedure attribute byte */
+                               proc_attributes[i] =
+                                               (p[proc_table +
+                                                               (13 * i) + 8] &
+                                                                       0x03);
+
+                               /*
+                                * BIT0 - OPTIONAL
+                                * BIT1 - RECOMMENDED
+                                * BIT6 - FORCED OFF
+                                * BIT7 - FORCED ON
+                                */
+
+                               i = get_unaligned_be32(&p[proc_table +
+                                                       (13 * i) + 4]);
+                       }
+
+                       /*
+                        * Set current_proc to the first procedure
+                        * to be executed
+                        */
+                       i = current_proc;
+                       while ((i != 0) &&
+                               ((proc_attributes[i] == 1) ||
+                               ((proc_attributes[i] & 0xc0) == 0x40))) {
+                               i = get_unaligned_be32(&p[proc_table +
+                                                       (13 * i) + 4]);
+                       }
+
+                       if ((i != 0) || ((i == 0) && (current_proc == 0) &&
+                               ((proc_attributes[0] != 1) &&
+                               ((proc_attributes[0] & 0xc0) != 0x40)))) {
+                               current_proc = i;
+                               pc = code_sect +
+                                       get_unaligned_be32(&p[proc_table +
+                                                               (13 * i) + 9]);
+                               if ((pc < code_sect) || (pc >= debug_sect))
+                                       status = -ERANGE;
+                       } else
+                               /* there are no procedures to execute! */
+                               done = 1;
+
+               }
+       }
+
+       msg_buff[0] = '\0';
+
+       while (!done) {
+               opcode = (p[pc] & 0xff);
+               opcode_address = pc;
+               ++pc;
+
+               if (debug > 1)
+                       printk("opcode: %02x\n", opcode);
+
+               arg_count = (opcode >> 6) & 3;
+               for (i = 0; i < arg_count; ++i) {
+                       args[i] = get_unaligned_be32(&p[pc]);
+                       pc += 4;
+               }
+
+               switch (opcode) {
+               case OP_NOP:
+                       break;
+               case OP_DUP:
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               stack[stack_ptr] = stack[stack_ptr - 1];
+                               ++stack_ptr;
+                       }
+                       break;
+               case OP_SWP:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               long_tmp = stack[stack_ptr - 2];
+                               stack[stack_ptr - 2] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+                       break;
+               case OP_ADD:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] += stack[stack_ptr];
+                       }
+                       break;
+               case OP_SUB:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] -= stack[stack_ptr];
+                       }
+                       break;
+               case OP_MULT:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] *= stack[stack_ptr];
+                       }
+                       break;
+               case OP_DIV:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] /= stack[stack_ptr];
+                       }
+                       break;
+               case OP_MOD:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] %= stack[stack_ptr];
+                       }
+                       break;
+               case OP_SHL:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] <<= stack[stack_ptr];
+                       }
+                       break;
+               case OP_SHR:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] >>= stack[stack_ptr];
+                       }
+                       break;
+               case OP_NOT:
+                       if (altera_check_stack(stack_ptr, 1, &status))
+                               stack[stack_ptr - 1] ^= (-1L);
+
+                       break;
+               case OP_AND:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] &= stack[stack_ptr];
+                       }
+                       break;
+               case OP_OR:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] |= stack[stack_ptr];
+                       }
+                       break;
+               case OP_XOR:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] ^= stack[stack_ptr];
+                       }
+                       break;
+               case OP_INV:
+                       if (!altera_check_stack(stack_ptr, 1, &status))
+                               break;
+                       stack[stack_ptr - 1] = stack[stack_ptr - 1] ? 0L : 1L;
+                       break;
+               case OP_GT:
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       --stack_ptr;
+                       stack[stack_ptr - 1] =
+                               (stack[stack_ptr - 1] > stack[stack_ptr]) ?
+                                                                       1L : 0L;
+
+                       break;
+               case OP_LT:
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       --stack_ptr;
+                       stack[stack_ptr - 1] =
+                               (stack[stack_ptr - 1] < stack[stack_ptr]) ?
+                                                                       1L : 0L;
+
+                       break;
+               case OP_RET:
+                       if ((version > 0) && (stack_ptr == 0)) {
+                               /*
+                                * We completed one of the main procedures
+                                * of an ACTION.
+                                * Find the next procedure
+                                * to be executed and jump to it.
+                                * If there are no more procedures, then EXIT.
+                                */
+                               i = get_unaligned_be32(&p[proc_table +
+                                               (13 * current_proc) + 4]);
+                               while ((i != 0) &&
+                                       ((proc_attributes[i] == 1) ||
+                                       ((proc_attributes[i] & 0xc0) == 0x40)))
+                                       i = get_unaligned_be32(&p[proc_table +
+                                                               (13 * i) + 4]);
+
+                               if (i == 0) {
+                                       /* no procedures to execute! */
+                                       done = 1;
+                                       *exit_code = 0; /* success */
+                               } else {
+                                       current_proc = i;
+                                       pc = code_sect + get_unaligned_be32(
+                                                               &p[proc_table +
+                                                               (13 * i) + 9]);
+                                       if ((pc < code_sect) ||
+                                           (pc >= debug_sect))
+                                               status = -ERANGE;
+                               }
+
+                       } else
+                               if (altera_check_stack(stack_ptr, 1, &status)) {
+                                       pc = stack[--stack_ptr] + code_sect;
+                                       if ((pc <= code_sect) ||
+                                           (pc >= debug_sect))
+                                               status = -ERANGE;
+
+                               }
+
+                       break;
+               case OP_CMPS:
+                       /*
+                        * Array short compare
+                        * ...stack 0 is source 1 value
+                        * ...stack 1 is source 2 value
+                        * ...stack 2 is mask value
+                        * ...stack 3 is count
+                        */
+                       if (altera_check_stack(stack_ptr, 4, &status)) {
+                               s32 a = stack[--stack_ptr];
+                               s32 b = stack[--stack_ptr];
+                               long_tmp = stack[--stack_ptr];
+                               count = stack[stack_ptr - 1];
+
+                               if ((count < 1) || (count > 32))
+                                       status = -ERANGE;
+                               else {
+                                       long_tmp &= ((-1L) >> (32 - count));
+
+                                       stack[stack_ptr - 1] =
+                                       ((a & long_tmp) == (b & long_tmp))
+                                                               ? 1L : 0L;
+                               }
+                       }
+                       break;
+               case OP_PINT:
+                       /*
+                        * PRINT add integer
+                        * ...stack 0 is integer value
+                        */
+                       if (!altera_check_stack(stack_ptr, 1, &status))
+                               break;
+                       sprintf(&msg_buff[strlen(msg_buff)],
+                                       "%ld", stack[--stack_ptr]);
+                       break;
+               case OP_PRNT:
+                       /* PRINT finish */
+                       if (debug)
+                               printk(msg_buff, "\n");
+
+                       msg_buff[0] = '\0';
+                       break;
+               case OP_DSS:
+                       /*
+                        * DRSCAN short
+                        * ...stack 0 is scan data
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       long_tmp = stack[--stack_ptr];
+                       count = stack[--stack_ptr];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_drscan(astate, count, charbuf, 0);
+                       break;
+               case OP_DSSC:
+                       /*
+                        * DRSCAN short with capture
+                        * ...stack 0 is scan data
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       long_tmp = stack[--stack_ptr];
+                       count = stack[stack_ptr - 1];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_swap_dr(astate, count, charbuf,
+                                                       0, charbuf, 0);
+                       stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]);
+                       break;
+               case OP_ISS:
+                       /*
+                        * IRSCAN short
+                        * ...stack 0 is scan data
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       long_tmp = stack[--stack_ptr];
+                       count = stack[--stack_ptr];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_irscan(astate, count, charbuf, 0);
+                       break;
+               case OP_ISSC:
+                       /*
+                        * IRSCAN short with capture
+                        * ...stack 0 is scan data
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       long_tmp = stack[--stack_ptr];
+                       count = stack[stack_ptr - 1];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_swap_ir(astate, count, charbuf,
+                                                       0, charbuf, 0);
+                       stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]);
+                       break;
+               case OP_DPR:
+                       if (!altera_check_stack(stack_ptr, 1, &status))
+                               break;
+                       count = stack[--stack_ptr];
+                       status = altera_set_dr_pre(&astate->js, count, 0, NULL);
+                       break;
+               case OP_DPRL:
+                       /*
+                        * DRPRE with literal data
+                        * ...stack 0 is count
+                        * ...stack 1 is literal data
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       count = stack[--stack_ptr];
+                       long_tmp = stack[--stack_ptr];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_set_dr_pre(&astate->js, count, 0,
+                                               charbuf);
+                       break;
+               case OP_DPO:
+                       /*
+                        * DRPOST
+                        * ...stack 0 is count
+                        */
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               count = stack[--stack_ptr];
+                               status = altera_set_dr_post(&astate->js, count,
+                                                               0, NULL);
+                       }
+                       break;
+               case OP_DPOL:
+                       /*
+                        * DRPOST with literal data
+                        * ...stack 0 is count
+                        * ...stack 1 is literal data
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       count = stack[--stack_ptr];
+                       long_tmp = stack[--stack_ptr];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_set_dr_post(&astate->js, count, 0,
+                                                       charbuf);
+                       break;
+               case OP_IPR:
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               count = stack[--stack_ptr];
+                               status = altera_set_ir_pre(&astate->js, count,
+                                                               0, NULL);
+                       }
+                       break;
+               case OP_IPRL:
+                       /*
+                        * IRPRE with literal data
+                        * ...stack 0 is count
+                        * ...stack 1 is literal data
+                        */
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               count = stack[--stack_ptr];
+                               long_tmp = stack[--stack_ptr];
+                               put_unaligned_le32(long_tmp, &charbuf[0]);
+                               status = altera_set_ir_pre(&astate->js, count,
+                                                       0, charbuf);
+                       }
+                       break;
+               case OP_IPO:
+                       /*
+                        * IRPOST
+                        * ...stack 0 is count
+                        */
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               count = stack[--stack_ptr];
+                               status = altera_set_ir_post(&astate->js, count,
+                                                       0, NULL);
+                       }
+                       break;
+               case OP_IPOL:
+                       /*
+                        * IRPOST with literal data
+                        * ...stack 0 is count
+                        * ...stack 1 is literal data
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       count = stack[--stack_ptr];
+                       long_tmp = stack[--stack_ptr];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_set_ir_post(&astate->js, count, 0,
+                                                       charbuf);
+                       break;
+               case OP_PCHR:
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               u8 ch;
+                               count = strlen(msg_buff);
+                               ch = (char) stack[--stack_ptr];
+                               if ((ch < 1) || (ch > 127)) {
+                                       /*
+                                        * character code out of range
+                                        * instead of flagging an error,
+                                        * force the value to 127
+                                        */
+                                       ch = 127;
+                               }
+                               msg_buff[count] = ch;
+                               msg_buff[count + 1] = '\0';
+                       }
+                       break;
+               case OP_EXIT:
+                       if (altera_check_stack(stack_ptr, 1, &status))
+                               *exit_code = stack[--stack_ptr];
+
+                       done = 1;
+                       break;
+               case OP_EQU:
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       --stack_ptr;
+                       stack[stack_ptr - 1] =
+                               (stack[stack_ptr - 1] == stack[stack_ptr]) ?
+                                                                       1L : 0L;
+                       break;
+               case OP_POPT:
+                       if (altera_check_stack(stack_ptr, 1, &status))
+                               --stack_ptr;
+
+                       break;
+               case OP_ABS:
+                       if (!altera_check_stack(stack_ptr, 1, &status))
+                               break;
+                       if (stack[stack_ptr - 1] < 0)
+                               stack[stack_ptr - 1] = 0 - stack[stack_ptr - 1];
+
+                       break;
+               case OP_BCH0:
+                       /*
+                        * Batch operation 0
+                        * SWP
+                        * SWPN 7
+                        * SWP
+                        * SWPN 6
+                        * DUPN 8
+                        * SWPN 2
+                        * SWP
+                        * DUPN 6
+                        * DUPN 6
+                        */
+
+                       /* SWP  */
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               long_tmp = stack[stack_ptr - 2];
+                               stack[stack_ptr - 2] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+
+                       /* SWPN 7 */
+                       index = 7 + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               long_tmp = stack[stack_ptr - index];
+                               stack[stack_ptr - index] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+
+                       /* SWP  */
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               long_tmp = stack[stack_ptr - 2];
+                               stack[stack_ptr - 2] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+
+                       /* SWPN 6 */
+                       index = 6 + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               long_tmp = stack[stack_ptr - index];
+                               stack[stack_ptr - index] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+
+                       /* DUPN 8 */
+                       index = 8 + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               stack[stack_ptr] = stack[stack_ptr - index];
+                               ++stack_ptr;
+                       }
+
+                       /* SWPN 2 */
+                       index = 2 + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               long_tmp = stack[stack_ptr - index];
+                               stack[stack_ptr - index] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+
+                       /* SWP  */
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               long_tmp = stack[stack_ptr - 2];
+                               stack[stack_ptr - 2] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+
+                       /* DUPN 6 */
+                       index = 6 + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               stack[stack_ptr] = stack[stack_ptr - index];
+                               ++stack_ptr;
+                       }
+
+                       /* DUPN 6 */
+                       index = 6 + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               stack[stack_ptr] = stack[stack_ptr - index];
+                               ++stack_ptr;
+                       }
+                       break;
+               case OP_PSH0:
+                       stack[stack_ptr++] = 0;
+                       break;
+               case OP_PSHL:
+                       stack[stack_ptr++] = (s32) args[0];
+                       break;
+               case OP_PSHV:
+                       stack[stack_ptr++] = vars[args[0]];
+                       break;
+               case OP_JMP:
+                       pc = args[0] + code_sect;
+                       if ((pc < code_sect) || (pc >= debug_sect))
+                               status = -ERANGE;
+                       break;
+               case OP_CALL:
+                       stack[stack_ptr++] = pc;
+                       pc = args[0] + code_sect;
+                       if ((pc < code_sect) || (pc >= debug_sect))
+                               status = -ERANGE;
+                       break;
+               case OP_NEXT:
+                       /*
+                        * Process FOR / NEXT loop
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is step value
+                        * ...stack 1 is end value
+                        * ...stack 2 is top address
+                        */
+                       if (altera_check_stack(stack_ptr, 3, &status)) {
+                               s32 step = stack[stack_ptr - 1];
+                               s32 end = stack[stack_ptr - 2];
+                               s32 top = stack[stack_ptr - 3];
+                               s32 iterator = vars[args[0]];
+                               int break_out = 0;
+
+                               if (step < 0) {
+                                       if (iterator <= end)
+                                               break_out = 1;
+                               } else if (iterator >= end)
+                                       break_out = 1;
+
+                               if (break_out) {
+                                       stack_ptr -= 3;
+                               } else {
+                                       vars[args[0]] = iterator + step;
+                                       pc = top + code_sect;
+                                       if ((pc < code_sect) ||
+                                           (pc >= debug_sect))
+                                               status = -ERANGE;
+                               }
+                       }
+                       break;
+               case OP_PSTR:
+                       /*
+                        * PRINT add string
+                        * ...argument 0 is string ID
+                        */
+                       count = strlen(msg_buff);
+                       strlcpy(&msg_buff[count],
+                               &p[str_table + args[0]],
+                               ALTERA_MESSAGE_LENGTH - count);
+                       break;
+               case OP_SINT:
+                       /*
+                        * STATE intermediate state
+                        * ...argument 0 is state code
+                        */
+                       status = altera_goto_jstate(astate, args[0]);
+                       break;
+               case OP_ST:
+                       /*
+                        * STATE final state
+                        * ...argument 0 is state code
+                        */
+                       status = altera_goto_jstate(astate, args[0]);
+                       break;
+               case OP_ISTP:
+                       /*
+                        * IRSTOP state
+                        * ...argument 0 is state code
+                        */
+                       status = altera_set_irstop(&astate->js, args[0]);
+                       break;
+               case OP_DSTP:
+                       /*
+                        * DRSTOP state
+                        * ...argument 0 is state code
+                        */
+                       status = altera_set_drstop(&astate->js, args[0]);
+                       break;
+
+               case OP_SWPN:
+                       /*
+                        * Exchange top with Nth stack value
+                        * ...argument 0 is 0-based stack entry
+                        * to swap with top element
+                        */
+                       index = (args[0]) + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               long_tmp = stack[stack_ptr - index];
+                               stack[stack_ptr - index] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+                       break;
+               case OP_DUPN:
+                       /*
+                        * Duplicate Nth stack value
+                        * ...argument 0 is 0-based stack entry to duplicate
+                        */
+                       index = (args[0]) + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               stack[stack_ptr] = stack[stack_ptr - index];
+                               ++stack_ptr;
+                       }
+                       break;
+               case OP_POPV:
+                       /*
+                        * Pop stack into scalar variable
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is value
+                        */
+                       if (altera_check_stack(stack_ptr, 1, &status))
+                               vars[args[0]] = stack[--stack_ptr];
+
+                       break;
+               case OP_POPE:
+                       /*
+                        * Pop stack into integer array element
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is array index
+                        * ...stack 1 is value
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       variable_id = args[0];
+
+                       /*
+                        * If variable is read-only,
+                        * convert to writable array
+                        */
+                       if ((version > 0) &&
+                               ((attrs[variable_id] & 0x9c) == 0x1c)) {
+                               /* Allocate a writable buffer for this array */
+                               count = var_size[variable_id];
+                               long_tmp = vars[variable_id];
+                               longptr_tmp = kzalloc(count * sizeof(long),
+                                                               GFP_KERNEL);
+                               vars[variable_id] = (long)longptr_tmp;
+
+                               if (vars[variable_id] == 0) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               /* copy previous contents into buffer */
+                               for (i = 0; i < count; ++i) {
+                                       longptr_tmp[i] =
+                                               get_unaligned_be32(&p[long_tmp]);
+                                       long_tmp += sizeof(long);
+                               }
+
+                               /*
+                                * set bit 7 - buffer was
+                                * dynamically allocated
+                                */
+                               attrs[variable_id] |= 0x80;
+
+                               /* clear bit 2 - variable is writable */
+                               attrs[variable_id] &= ~0x04;
+                               attrs[variable_id] |= 0x01;
+
+                       }
+
+                       /* check that variable is a writable integer array */
+                       if ((attrs[variable_id] & 0x1c) != 0x18)
+                               status = -ERANGE;
+                       else {
+                               longptr_tmp = (long *)vars[variable_id];
+
+                               /* pop the array index */
+                               index = stack[--stack_ptr];
+
+                               /* pop the value and store it into the array */
+                               longptr_tmp[index] = stack[--stack_ptr];
+                       }
+
+                       break;
+               case OP_POPA:
+                       /*
+                        * Pop stack into Boolean array
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is count
+                        * ...stack 1 is array index
+                        * ...stack 2 is value
+                        */
+                       if (!altera_check_stack(stack_ptr, 3, &status))
+                               break;
+                       variable_id = args[0];
+
+                       /*
+                        * If variable is read-only,
+                        * convert to writable array
+                        */
+                       if ((version > 0) &&
+                               ((attrs[variable_id] & 0x9c) == 0x0c)) {
+                               /* Allocate a writable buffer for this array */
+                               long_tmp =
+                                       (var_size[variable_id] + 7L) >> 3L;
+                               charptr_tmp2 = (u8 *)vars[variable_id];
+                               charptr_tmp =
+                                       kzalloc(long_tmp, GFP_KERNEL);
+                               vars[variable_id] = (long)charptr_tmp;
+
+                               if (vars[variable_id] == 0) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               /* zero the buffer */
+                               for (long_idx = 0L;
+                                       long_idx < long_tmp;
+                                       ++long_idx) {
+                                       charptr_tmp[long_idx] = 0;
+                               }
+
+                               /* copy previous contents into buffer */
+                               for (long_idx = 0L;
+                                       long_idx < var_size[variable_id];
+                                       ++long_idx) {
+                                       long_idx2 = long_idx;
+
+                                       if (charptr_tmp2[long_idx2 >> 3] &
+                                               (1 << (long_idx2 & 7))) {
+                                               charptr_tmp[long_idx >> 3] |=
+                                                       (1 << (long_idx & 7));
+                                       }
+                               }
+
+                               /*
+                                * set bit 7 - buffer was
+                                * dynamically allocated
+                                */
+                               attrs[variable_id] |= 0x80;
+
+                               /* clear bit 2 - variable is writable */
+                               attrs[variable_id] &= ~0x04;
+                               attrs[variable_id] |= 0x01;
+
+                       }
+
+                       /*
+                        * check that variable is
+                        * a writable Boolean array
+                        */
+                       if ((attrs[variable_id] & 0x1c) != 0x08) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       charptr_tmp = (u8 *)vars[variable_id];
+
+                       /* pop the count (number of bits to copy) */
+                       long_count = stack[--stack_ptr];
+
+                       /* pop the array index */
+                       long_idx = stack[--stack_ptr];
+
+                       reverse = 0;
+
+                       if (version > 0) {
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                */
+
+                               if (long_idx > long_count) {
+                                       reverse = 1;
+                                       long_tmp = long_count;
+                                       long_count = 1 + long_idx -
+                                                               long_count;
+                                       long_idx = long_tmp;
+
+                                       /* reverse POPA is not supported */
+                                       status = -ERANGE;
+                                       break;
+                               } else
+                                       long_count = 1 + long_count -
+                                                               long_idx;
+
+                       }
+
+                       /* pop the data */
+                       long_tmp = stack[--stack_ptr];
+
+                       if (long_count < 1) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       for (i = 0; i < long_count; ++i) {
+                               if (long_tmp & (1L << (s32) i))
+                                       charptr_tmp[long_idx >> 3L] |=
+                                               (1L << (long_idx & 7L));
+                               else
+                                       charptr_tmp[long_idx >> 3L] &=
+                                               ~(1L << (long_idx & 7L));
+
+                               ++long_idx;
+                       }
+
+                       break;
+               case OP_JMPZ:
+                       /*
+                        * Pop stack and branch if zero
+                        * ...argument 0 is address
+                        * ...stack 0 is condition value
+                        */
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               if (stack[--stack_ptr] == 0) {
+                                       pc = args[0] + code_sect;
+                                       if ((pc < code_sect) ||
+                                           (pc >= debug_sect))
+                                               status = -ERANGE;
+                               }
+                       }
+                       break;
+               case OP_DS:
+               case OP_IS:
+                       /*
+                        * DRSCAN
+                        * IRSCAN
+                        * ...argument 0 is scan data variable ID
+                        * ...stack 0 is array index
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       long_idx = stack[--stack_ptr];
+                       long_count = stack[--stack_ptr];
+                       reverse = 0;
+                       if (version > 0) {
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                * stack 2 = count
+                                */
+                               long_tmp = long_count;
+                               long_count = stack[--stack_ptr];
+
+                               if (long_idx > long_tmp) {
+                                       reverse = 1;
+                                       long_idx = long_tmp;
+                               }
+                       }
+
+                       charptr_tmp = (u8 *)vars[args[0]];
+
+                       if (reverse) {
+                               /*
+                                * allocate a buffer
+                                * and reverse the data order
+                                */
+                               charptr_tmp2 = charptr_tmp;
+                               charptr_tmp = kzalloc((long_count >> 3) + 1,
+                                                               GFP_KERNEL);
+                               if (charptr_tmp == NULL) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               long_tmp = long_idx + long_count - 1;
+                               long_idx2 = 0;
+                               while (long_idx2 < long_count) {
+                                       if (charptr_tmp2[long_tmp >> 3] &
+                                                       (1 << (long_tmp & 7)))
+                                               charptr_tmp[long_idx2 >> 3] |=
+                                                       (1 << (long_idx2 & 7));
+                                       else
+                                               charptr_tmp[long_idx2 >> 3] &=
+                                                       ~(1 << (long_idx2 & 7));
+
+                                       --long_tmp;
+                                       ++long_idx2;
+                               }
+                       }
+
+                       if (opcode == 0x51) /* DS */
+                               status = altera_drscan(astate, long_count,
+                                               charptr_tmp, long_idx);
+                       else /* IS */
+                               status = altera_irscan(astate, long_count,
+                                               charptr_tmp, long_idx);
+
+                       if (reverse)
+                               kfree(charptr_tmp);
+
+                       break;
+               case OP_DPRA:
+                       /*
+                        * DRPRE with array data
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is array index
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       index = stack[--stack_ptr];
+                       count = stack[--stack_ptr];
+
+                       if (version > 0)
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                */
+                               count = 1 + count - index;
+
+                       charptr_tmp = (u8 *)vars[args[0]];
+                       status = altera_set_dr_pre(&astate->js, count, index,
+                                                       charptr_tmp);
+                       break;
+               case OP_DPOA:
+                       /*
+                        * DRPOST with array data
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is array index
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       index = stack[--stack_ptr];
+                       count = stack[--stack_ptr];
+
+                       if (version > 0)
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                */
+                               count = 1 + count - index;
+
+                       charptr_tmp = (u8 *)vars[args[0]];
+                       status = altera_set_dr_post(&astate->js, count, index,
+                                                       charptr_tmp);
+                       break;
+               case OP_IPRA:
+                       /*
+                        * IRPRE with array data
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is array index
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       index = stack[--stack_ptr];
+                       count = stack[--stack_ptr];
+
+                       if (version > 0)
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                */
+                               count = 1 + count - index;
+
+                       charptr_tmp = (u8 *)vars[args[0]];
+                       status = altera_set_ir_pre(&astate->js, count, index,
+                                                       charptr_tmp);
+
+                       break;
+               case OP_IPOA:
+                       /*
+                        * IRPOST with array data
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is array index
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       index = stack[--stack_ptr];
+                       count = stack[--stack_ptr];
+
+                       if (version > 0)
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                */
+                               count = 1 + count - index;
+
+                       charptr_tmp = (u8 *)vars[args[0]];
+                       status = altera_set_ir_post(&astate->js, count, index,
+                                                       charptr_tmp);
+
+                       break;
+               case OP_EXPT:
+                       /*
+                        * EXPORT
+                        * ...argument 0 is string ID
+                        * ...stack 0 is integer expression
+                        */
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               name = &p[str_table + args[0]];
+                               long_tmp = stack[--stack_ptr];
+                               altera_export_int(name, long_tmp);
+                       }
+                       break;
+               case OP_PSHE:
+                       /*
+                        * Push integer array element
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is array index
+                        */
+                       if (!altera_check_stack(stack_ptr, 1, &status))
+                               break;
+                       variable_id = args[0];
+                       index = stack[stack_ptr - 1];
+
+                       /* check variable type */
+                       if ((attrs[variable_id] & 0x1f) == 0x19) {
+                               /* writable integer array */
+                               longptr_tmp = (long *)vars[variable_id];
+                               stack[stack_ptr - 1] = longptr_tmp[index];
+                       } else if ((attrs[variable_id] & 0x1f) == 0x1c) {
+                               /* read-only integer array */
+                               long_tmp = vars[variable_id] +
+                                               (index * sizeof(long));
+                               stack[stack_ptr - 1] =
+                                       get_unaligned_be32(&p[long_tmp]);
+                       } else
+                               status = -ERANGE;
+
+                       break;
+               case OP_PSHA:
+                       /*
+                        * Push Boolean array
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is count
+                        * ...stack 1 is array index
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       variable_id = args[0];
+
+                       /* check that variable is a Boolean array */
+                       if ((attrs[variable_id] & 0x18) != 0x08) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       charptr_tmp = (u8 *)vars[variable_id];
+
+                       /* pop the count (number of bits to copy) */
+                       count = stack[--stack_ptr];
+
+                       /* pop the array index */
+                       index = stack[stack_ptr - 1];
+
+                       if (version > 0)
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                */
+                               count = 1 + count - index;
+
+                       if ((count < 1) || (count > 32)) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       long_tmp = 0L;
+
+                       for (i = 0; i < count; ++i)
+                               if (charptr_tmp[(i + index) >> 3] &
+                                               (1 << ((i + index) & 7)))
+                                       long_tmp |= (1L << i);
+
+                       stack[stack_ptr - 1] = long_tmp;
+
+                       break;
+               case OP_DYNA:
+                       /*
+                        * Dynamically change size of array
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is new size
+                        */
+                       if (!altera_check_stack(stack_ptr, 1, &status))
+                               break;
+                       variable_id = args[0];
+                       long_tmp = stack[--stack_ptr];
+
+                       if (long_tmp > var_size[variable_id]) {
+                               var_size[variable_id] = long_tmp;
+
+                               if (attrs[variable_id] & 0x10)
+                                       /* allocate integer array */
+                                       long_tmp *= sizeof(long);
+                               else
+                                       /* allocate Boolean array */
+                                       long_tmp = (long_tmp + 7) >> 3;
+
+                               /*
+                                * If the buffer was previously allocated,
+                                * free it
+                                */
+                               if (attrs[variable_id] & 0x80) {
+                                       kfree((void *)vars[variable_id]);
+                                       vars[variable_id] = 0;
+                               }
+
+                               /*
+                                * Allocate a new buffer
+                                * of the requested size
+                                */
+                               vars[variable_id] = (long)
+                                       kzalloc(long_tmp, GFP_KERNEL);
+
+                               if (vars[variable_id] == 0) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               /*
+                                * Set the attribute bit to indicate that
+                                * this buffer was dynamically allocated and
+                                * should be freed later
+                                */
+                               attrs[variable_id] |= 0x80;
+
+                               /* zero out memory */
+                               count = ((var_size[variable_id] + 7L) /
+                                                                       8L);
+                               charptr_tmp = (u8 *)(vars[variable_id]);
+                               for (index = 0; index < count; ++index)
+                                       charptr_tmp[index] = 0;
+
+                       }
+
+                       break;
+               case OP_EXPV:
+                       /*
+                        * Export Boolean array
+                        * ...argument 0 is string ID
+                        * ...stack 0 is variable ID
+                        * ...stack 1 is array right index
+                        * ...stack 2 is array left index
+                        */
+                       if (!altera_check_stack(stack_ptr, 3, &status))
+                               break;
+                       if (version == 0) {
+                               /* EXPV is not supported in JBC 1.0 */
+                               bad_opcode = 1;
+                               break;
+                       }
+                       name = &p[str_table + args[0]];
+                       variable_id = stack[--stack_ptr];
+                       long_idx = stack[--stack_ptr];/* right indx */
+                       long_idx2 = stack[--stack_ptr];/* left indx */
+
+                       if (long_idx > long_idx2) {
+                               /* reverse indices not supported */
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       long_count = 1 + long_idx2 - long_idx;
+
+                       charptr_tmp = (u8 *)vars[variable_id];
+                       charptr_tmp2 = NULL;
+
+                       if ((long_idx & 7L) != 0) {
+                               s32 k = long_idx;
+                               charptr_tmp2 =
+                                       kzalloc(((long_count + 7L) / 8L),
+                                                       GFP_KERNEL);
+                               if (charptr_tmp2 == NULL) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               for (i = 0; i < long_count; ++i) {
+                                       if (charptr_tmp[k >> 3] &
+                                                       (1 << (k & 7)))
+                                               charptr_tmp2[i >> 3] |=
+                                                               (1 << (i & 7));
+                                       else
+                                               charptr_tmp2[i >> 3] &=
+                                                               ~(1 << (i & 7));
+
+                                       ++k;
+                               }
+                               charptr_tmp = charptr_tmp2;
+
+                       } else if (long_idx != 0)
+                               charptr_tmp = &charptr_tmp[long_idx >> 3];
+
+                       altera_export_bool_array(name, charptr_tmp,
+                                                       long_count);
+
+                       /* free allocated buffer */
+                       if ((long_idx & 7L) != 0)
+                               kfree(charptr_tmp2);
+
+                       break;
+               case OP_COPY: {
+                       /*
+                        * Array copy
+                        * ...argument 0 is dest ID
+                        * ...argument 1 is source ID
+                        * ...stack 0 is count
+                        * ...stack 1 is dest index
+                        * ...stack 2 is source index
+                        */
+                       s32 copy_count;
+                       s32 copy_index;
+                       s32 copy_index2;
+                       s32 destleft;
+                       s32 src_count;
+                       s32 dest_count;
+                       int src_reverse = 0;
+                       int dest_reverse = 0;
+
+                       if (!altera_check_stack(stack_ptr, 3, &status))
+                               break;
+
+                       copy_count = stack[--stack_ptr];
+                       copy_index = stack[--stack_ptr];
+                       copy_index2 = stack[--stack_ptr];
+                       reverse = 0;
+
+                       if (version > 0) {
+                               /*
+                                * stack 0 = source right index
+                                * stack 1 = source left index
+                                * stack 2 = destination right index
+                                * stack 3 = destination left index
+                                */
+                               destleft = stack[--stack_ptr];
+
+                               if (copy_count > copy_index) {
+                                       src_reverse = 1;
+                                       reverse = 1;
+                                       src_count = 1 + copy_count - copy_index;
+                                       /* copy_index = source start index */
+                               } else {
+                                       src_count = 1 + copy_index - copy_count;
+                                       /* source start index */
+                                       copy_index = copy_count;
+                               }
+
+                               if (copy_index2 > destleft) {
+                                       dest_reverse = 1;
+                                       reverse = !reverse;
+                                       dest_count = 1 + copy_index2 - destleft;
+                                       /* destination start index */
+                                       copy_index2 = destleft;
+                               } else
+                                       dest_count = 1 + destleft - copy_index2;
+
+                               copy_count = (src_count < dest_count) ?
+                                                       src_count : dest_count;
+
+                               if ((src_reverse || dest_reverse) &&
+                                       (src_count != dest_count))
+                                       /*
+                                        * If either the source or destination
+                                        * is reversed, we can't tolerate
+                                        * a length mismatch, because we
+                                        * "left justify" arrays when copying.
+                                        * This won't work correctly
+                                        * with reversed arrays.
+                                        */
+                                       status = -ERANGE;
+
+                       }
+
+                       count = copy_count;
+                       index = copy_index;
+                       index2 = copy_index2;
+
+                       /*
+                        * If destination is a read-only array,
+                        * allocate a buffer and convert it to a writable array
+                        */
+                       variable_id = args[1];
+                       if ((version > 0) &&
+                               ((attrs[variable_id] & 0x9c) == 0x0c)) {
+                               /* Allocate a writable buffer for this array */
+                               long_tmp =
+                                       (var_size[variable_id] + 7L) >> 3L;
+                               charptr_tmp2 = (u8 *)vars[variable_id];
+                               charptr_tmp =
+                                       kzalloc(long_tmp, GFP_KERNEL);
+                               vars[variable_id] = (long)charptr_tmp;
+
+                               if (vars[variable_id] == 0) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               /* zero the buffer */
+                               for (long_idx = 0L; long_idx < long_tmp;
+                                                               ++long_idx)
+                                       charptr_tmp[long_idx] = 0;
+
+                               /* copy previous contents into buffer */
+                               for (long_idx = 0L;
+                                       long_idx < var_size[variable_id];
+                                                               ++long_idx) {
+                                       long_idx2 = long_idx;
+
+                                       if (charptr_tmp2[long_idx2 >> 3] &
+                                               (1 << (long_idx2 & 7)))
+                                               charptr_tmp[long_idx >> 3] |=
+                                                       (1 << (long_idx & 7));
+
+                               }
+
+                               /*
+                               set bit 7 - buffer was dynamically allocated */
+                               attrs[variable_id] |= 0x80;
+
+                               /* clear bit 2 - variable is writable */
+                               attrs[variable_id] &= ~0x04;
+                               attrs[variable_id] |= 0x01;
+                       }
+
+                       charptr_tmp = (u8 *)vars[args[1]];
+                       charptr_tmp2 = (u8 *)vars[args[0]];
+
+                       /* check if destination is a writable Boolean array */
+                       if ((attrs[args[1]] & 0x1c) != 0x08) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       if (count < 1) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       if (reverse)
+                               index2 += (count - 1);
+
+                       for (i = 0; i < count; ++i) {
+                               if (charptr_tmp2[index >> 3] &
+                                                       (1 << (index & 7)))
+                                       charptr_tmp[index2 >> 3] |=
+                                                       (1 << (index2 & 7));
+                               else
+                                       charptr_tmp[index2 >> 3] &=
+                                               ~(1 << (index2 & 7));
+
+                               ++index;
+                               if (reverse)
+                                       --index2;
+                               else
+                                       ++index2;
+                       }
+
+                       break;
+               }
+               case OP_DSC:
+               case OP_ISC: {
+                       /*
+                        * DRSCAN with capture
+                        * IRSCAN with capture
+                        * ...argument 0 is scan data variable ID
+                        * ...argument 1 is capture variable ID
+                        * ...stack 0 is capture index
+                        * ...stack 1 is scan data index
+                        * ...stack 2 is count
+                        */
+                       s32 scan_right, scan_left;
+                       s32 capture_count = 0;
+                       s32 scan_count = 0;
+                       s32 capture_index;
+                       s32 scan_index;
+
+                       if (!altera_check_stack(stack_ptr, 3, &status))
+                               break;
+
+                       capture_index = stack[--stack_ptr];
+                       scan_index = stack[--stack_ptr];
+
+                       if (version > 0) {
+                               /*
+                                * stack 0 = capture right index
+                                * stack 1 = capture left index
+                                * stack 2 = scan right index
+                                * stack 3 = scan left index
+                                * stack 4 = count
+                                */
+                               scan_right = stack[--stack_ptr];
+                               scan_left = stack[--stack_ptr];
+                               capture_count = 1 + scan_index - capture_index;
+                               scan_count = 1 + scan_left - scan_right;
+                               scan_index = scan_right;
+                       }
+
+                       long_count = stack[--stack_ptr];
+                       /*
+                        * If capture array is read-only, allocate a buffer
+                        * and convert it to a writable array
+                        */
+                       variable_id = args[1];
+                       if ((version > 0) &&
+                               ((attrs[variable_id] & 0x9c) == 0x0c)) {
+                               /* Allocate a writable buffer for this array */
+                               long_tmp =
+                                       (var_size[variable_id] + 7L) >> 3L;
+                               charptr_tmp2 = (u8 *)vars[variable_id];
+                               charptr_tmp =
+                                       kzalloc(long_tmp, GFP_KERNEL);
+                               vars[variable_id] = (long)charptr_tmp;
+
+                               if (vars[variable_id] == 0) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               /* zero the buffer */
+                               for (long_idx = 0L; long_idx < long_tmp;
+                                                               ++long_idx)
+                                       charptr_tmp[long_idx] = 0;
+
+                               /* copy previous contents into buffer */
+                               for (long_idx = 0L;
+                                       long_idx < var_size[variable_id];
+                                                               ++long_idx) {
+                                       long_idx2 = long_idx;
+
+                                       if (charptr_tmp2[long_idx2 >> 3] &
+                                               (1 << (long_idx2 & 7)))
+                                               charptr_tmp[long_idx >> 3] |=
+                                                       (1 << (long_idx & 7));
+
+                               }
+
+                               /*
+                                * set bit 7 - buffer was
+                                * dynamically allocated
+                                */
+                               attrs[variable_id] |= 0x80;
+
+                               /* clear bit 2 - variable is writable */
+                               attrs[variable_id] &= ~0x04;
+                               attrs[variable_id] |= 0x01;
+
+                       }
+
+                       charptr_tmp = (u8 *)vars[args[0]];
+                       charptr_tmp2 = (u8 *)vars[args[1]];
+
+                       if ((version > 0) &&
+                                       ((long_count > capture_count) ||
+                                       (long_count > scan_count))) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       /*
+                        * check that capture array
+                        * is a writable Boolean array
+                        */
+                       if ((attrs[args[1]] & 0x1c) != 0x08) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       if (status == 0) {
+                               if (opcode == 0x82) /* DSC */
+                                       status = altera_swap_dr(astate,
+                                                       long_count,
+                                                       charptr_tmp,
+                                                       scan_index,
+                                                       charptr_tmp2,
+                                                       capture_index);
+                               else /* ISC */
+                                       status = altera_swap_ir(astate,
+                                                       long_count,
+                                                       charptr_tmp,
+                                                       scan_index,
+                                                       charptr_tmp2,
+                                                       capture_index);
+
+                       }
+
+                       break;
+               }
+               case OP_WAIT:
+                       /*
+                        * WAIT
+                        * ...argument 0 is wait state
+                        * ...argument 1 is end state
+                        * ...stack 0 is cycles
+                        * ...stack 1 is microseconds
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       long_tmp = stack[--stack_ptr];
+
+                       if (long_tmp != 0L)
+                               status = altera_wait_cycles(astate, long_tmp,
+                                                               args[0]);
+
+                       long_tmp = stack[--stack_ptr];
+
+                       if ((status == 0) && (long_tmp != 0L))
+                               status = altera_wait_msecs(astate,
+                                                               long_tmp,
+                                                               args[0]);
+
+                       if ((status == 0) && (args[1] != args[0]))
+                               status = altera_goto_jstate(astate,
+                                                               args[1]);
+
+                       if (version > 0) {
+                               --stack_ptr; /* throw away MAX cycles */
+                               --stack_ptr; /* throw away MAX microseconds */
+                       }
+                       break;
+               case OP_CMPA: {
+                       /*
+                        * Array compare
+                        * ...argument 0 is source 1 ID
+                        * ...argument 1 is source 2 ID
+                        * ...argument 2 is mask ID
+                        * ...stack 0 is source 1 index
+                        * ...stack 1 is source 2 index
+                        * ...stack 2 is mask index
+                        * ...stack 3 is count
+                        */
+                       s32 a, b;
+                       u8 *source1 = (u8 *)vars[args[0]];
+                       u8 *source2 = (u8 *)vars[args[1]];
+                       u8 *mask = (u8 *)vars[args[2]];
+                       u32 index1;
+                       u32 index2;
+                       u32 mask_index;
+
+                       if (!altera_check_stack(stack_ptr, 4, &status))
+                               break;
+
+                       index1 = stack[--stack_ptr];
+                       index2 = stack[--stack_ptr];
+                       mask_index = stack[--stack_ptr];
+                       long_count = stack[--stack_ptr];
+
+                       if (version > 0) {
+                               /*
+                                * stack 0 = source 1 right index
+                                * stack 1 = source 1 left index
+                                * stack 2 = source 2 right index
+                                * stack 3 = source 2 left index
+                                * stack 4 = mask right index
+                                * stack 5 = mask left index
+                                */
+                               s32 mask_right = stack[--stack_ptr];
+                               s32 mask_left = stack[--stack_ptr];
+                               /* source 1 count */
+                               a = 1 + index2 - index1;
+                               /* source 2 count */
+                               b = 1 + long_count - mask_index;
+                               a = (a < b) ? a : b;
+                               /* mask count */
+                               b = 1 + mask_left - mask_right;
+                               a = (a < b) ? a : b;
+                               /* source 2 start index */
+                               index2 = mask_index;
+                               /* mask start index */
+                               mask_index = mask_right;
+                               long_count = a;
+                       }
+
+                       long_tmp = 1L;
+
+                       if (long_count < 1)
+                               status = -ERANGE;
+                       else {
+                               count = long_count;
+
+                               for (i = 0; i < count; ++i) {
+                                       if (mask[mask_index >> 3] &
+                                               (1 << (mask_index & 7))) {
+                                               a = source1[index1 >> 3] &
+                                                       (1 << (index1 & 7))
+                                                               ? 1 : 0;
+                                               b = source2[index2 >> 3] &
+                                                       (1 << (index2 & 7))
+                                                               ? 1 : 0;
+
+                                               if (a != b) /* failure */
+                                                       long_tmp = 0L;
+                                       }
+                                       ++index1;
+                                       ++index2;
+                                       ++mask_index;
+                               }
+                       }
+
+                       stack[stack_ptr++] = long_tmp;
+
+                       break;
+               }
+               default:
+                       /* Unrecognized opcode -- ERROR! */
+                       bad_opcode = 1;
+                       break;
+               }
+
+               if (bad_opcode)
+                       status = -ENOSYS;
+
+               if ((stack_ptr < 0) || (stack_ptr >= ALTERA_STACK_SIZE))
+                       status = -EOVERFLOW;
+
+               if (status != 0) {
+                       done = 1;
+                       *error_address = (s32)(opcode_address - code_sect);
+               }
+       }
+
+       altera_free_buffers(astate);
+
+       /* Free all dynamically allocated arrays */
+       if ((attrs != NULL) && (vars != NULL))
+               for (i = 0; i < sym_count; ++i)
+                       if (attrs[i] & 0x80)
+                               kfree((void *)vars[i]);
+
+       kfree(vars);
+       kfree(var_size);
+       kfree(attrs);
+       kfree(proc_attributes);
+
+       return status;
+}
+
+static int altera_get_note(u8 *p, s32 program_size,
+                       s32 *offset, char *key, char *value, int length)
+/*
+ * Gets key and value of NOTE fields in the JBC file.
+ * Can be called in two modes:  if offset pointer is NULL,
+ * then the function searches for note fields which match
+ * the key string provided.  If offset is not NULL, then
+ * the function finds the next note field of any key,
+ * starting at the offset specified by the offset pointer.
+ * Returns 0 for success, else appropriate error code
+ */
+{
+       int status = -ENODATA;
+       u32 note_strings = 0L;
+       u32 note_table = 0L;
+       u32 note_count = 0L;
+       u32 first_word = 0L;
+       int version = 0;
+       int delta = 0;
+       char *key_ptr;
+       char *value_ptr;
+       int i;
+
+       /* Read header information */
+       if (program_size > 52L) {
+               first_word    = get_unaligned_be32(&p[0]);
+               version = (first_word & 1L);
+               delta = version * 8;
+
+               note_strings  = get_unaligned_be32(&p[8 + delta]);
+               note_table    = get_unaligned_be32(&p[12 + delta]);
+               note_count    = get_unaligned_be32(&p[44 + (2 * delta)]);
+       }
+
+       if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L))
+               return -EIO;
+
+       if (note_count <= 0L)
+               return status;
+
+       if (offset == NULL) {
+               /*
+                * We will search for the first note with a specific key,
+                * and return only the value
+                */
+               for (i = 0; (i < note_count) &&
+                                               (status != 0); ++i) {
+                       key_ptr = &p[note_strings +
+                                       get_unaligned_be32(
+                                       &p[note_table + (8 * i)])];
+                       if ((strnicmp(key, key_ptr, strlen(key_ptr)) == 0) &&
+                                               (key != NULL)) {
+                               status = 0;
+
+                               value_ptr = &p[note_strings +
+                                               get_unaligned_be32(
+                                               &p[note_table + (8 * i) + 4])];
+
+                               if (value != NULL)
+                                       strlcpy(value, value_ptr, length);
+
+                       }
+               }
+       } else {
+               /*
+                * We will search for the next note, regardless of the key,
+                * and return both the value and the key
+                */
+
+               i = *offset;
+
+               if ((i >= 0) && (i < note_count)) {
+                       status = 0;
+
+                       if (key != NULL)
+                               strlcpy(key, &p[note_strings +
+                                               get_unaligned_be32(
+                                               &p[note_table + (8 * i)])],
+                                       length);
+
+                       if (value != NULL)
+                               strlcpy(value, &p[note_strings +
+                                               get_unaligned_be32(
+                                               &p[note_table + (8 * i) + 4])],
+                                       length);
+
+                       *offset = i + 1;
+               }
+       }
+
+       return status;
+}
+
+static int altera_check_crc(u8 *p, s32 program_size)
+{
+       int status = 0;
+       u16 local_expected = 0,
+           local_actual = 0,
+           shift_reg = 0xffff;
+       int bit, feedback;
+       u8 databyte;
+       u32 i;
+       u32 crc_section = 0L;
+       u32 first_word = 0L;
+       int version = 0;
+       int delta = 0;
+
+       if (program_size > 52L) {
+               first_word  = get_unaligned_be32(&p[0]);
+               version = (first_word & 1L);
+               delta = version * 8;
+
+               crc_section = get_unaligned_be32(&p[32 + delta]);
+       }
+
+       if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L))
+               status = -EIO;
+
+       if (crc_section >= program_size)
+               status = -EIO;
+
+       if (status == 0) {
+               local_expected = (u16)get_unaligned_be16(&p[crc_section]);
+
+               for (i = 0; i < crc_section; ++i) {
+                       databyte = p[i];
+                       for (bit = 0; bit < 8; bit++) {
+                               feedback = (databyte ^ shift_reg) & 0x01;
+                               shift_reg >>= 1;
+                               if (feedback)
+                                       shift_reg ^= 0x8408;
+
+                               databyte >>= 1;
+                       }
+               }
+
+               local_actual = (u16)~shift_reg;
+
+               if (local_expected != local_actual)
+                       status = -EILSEQ;
+
+       }
+
+       if (debug || status) {
+               switch (status) {
+               case 0:
+                       printk(KERN_INFO "%s: CRC matched: %04x\n", __func__,
+                               local_actual);
+                       break;
+               case -EILSEQ:
+                       printk(KERN_ERR "%s: CRC mismatch: expected %04x, "
+                               "actual %04x\n", __func__, local_expected,
+                               local_actual);
+                       break;
+               case -ENODATA:
+                       printk(KERN_ERR "%s: expected CRC not found, "
+                               "actual CRC = %04x\n", __func__,
+                               local_actual);
+                       break;
+               case -EIO:
+                       printk(KERN_ERR "%s: error: format isn't "
+                               "recognized.\n", __func__);
+                       break;
+               default:
+                       printk(KERN_ERR "%s: CRC function returned error "
+                               "code %d\n", __func__, status);
+                       break;
+               }
+       }
+
+       return status;
+}
+
+static int altera_get_file_info(u8 *p,
+                                       s32 program_size,
+                                       int *format_version,
+                                       int *action_count,
+                                       int *procedure_count)
+{
+       int status = -EIO;
+       u32 first_word = 0;
+       int version = 0;
+
+       if (program_size <= 52L)
+               return status;
+
+       first_word = get_unaligned_be32(&p[0]);
+
+       if ((first_word == 0x4A414D00L) || (first_word == 0x4A414D01L)) {
+               status = 0;
+
+               version = (first_word & 1L);
+               *format_version = version + 1;
+
+               if (version > 0) {
+                       *action_count = get_unaligned_be32(&p[48]);
+                       *procedure_count = get_unaligned_be32(&p[52]);
+               }
+       }
+
+       return status;
+}
+
+static int altera_get_act_info(u8 *p,
+                                       s32 program_size,
+                                       int index,
+                                       char **name,
+                                       char **description,
+                                       struct altera_procinfo **proc_list)
+{
+       int status = -EIO;
+       struct altera_procinfo *procptr = NULL;
+       struct altera_procinfo *tmpptr = NULL;
+       u32 first_word = 0L;
+       u32 action_table = 0L;
+       u32 proc_table = 0L;
+       u32 str_table = 0L;
+       u32 note_strings = 0L;
+       u32 action_count = 0L;
+       u32 proc_count = 0L;
+       u32 act_name_id = 0L;
+       u32 act_desc_id = 0L;
+       u32 act_proc_id = 0L;
+       u32 act_proc_name = 0L;
+       u8 act_proc_attribute = 0;
+
+       if (program_size <= 52L)
+               return status;
+       /* Read header information */
+       first_word = get_unaligned_be32(&p[0]);
+
+       if (first_word != 0x4A414D01L)
+               return status;
+
+       action_table = get_unaligned_be32(&p[4]);
+       proc_table   = get_unaligned_be32(&p[8]);
+       str_table = get_unaligned_be32(&p[12]);
+       note_strings = get_unaligned_be32(&p[16]);
+       action_count = get_unaligned_be32(&p[48]);
+       proc_count   = get_unaligned_be32(&p[52]);
+
+       if (index >= action_count)
+               return status;
+
+       act_name_id = get_unaligned_be32(&p[action_table + (12 * index)]);
+       act_desc_id = get_unaligned_be32(&p[action_table + (12 * index) + 4]);
+       act_proc_id = get_unaligned_be32(&p[action_table + (12 * index) + 8]);
+
+       *name = &p[str_table + act_name_id];
+
+       if (act_desc_id < (note_strings - str_table))
+               *description = &p[str_table + act_desc_id];
+
+       do {
+               act_proc_name = get_unaligned_be32(
+                                       &p[proc_table + (13 * act_proc_id)]);
+               act_proc_attribute =
+                       (p[proc_table + (13 * act_proc_id) + 8] & 0x03);
+
+               procptr =
+                               kzalloc(sizeof(struct altera_procinfo),
+                                                               GFP_KERNEL);
+
+               if (procptr == NULL)
+                       status = -ENOMEM;
+               else {
+                       procptr->name = &p[str_table + act_proc_name];
+                       procptr->attrs = act_proc_attribute;
+                       procptr->next = NULL;
+
+                       /* add record to end of linked list */
+                       if (*proc_list == NULL)
+                               *proc_list = procptr;
+                       else {
+                               tmpptr = *proc_list;
+                               while (tmpptr->next != NULL)
+                                       tmpptr = tmpptr->next;
+                               tmpptr->next = procptr;
+                       }
+               }
+
+               act_proc_id = get_unaligned_be32(
+                               &p[proc_table + (13 * act_proc_id) + 4]);
+       } while ((act_proc_id != 0) && (act_proc_id < proc_count));
+
+       return status;
+}
+
+int altera_init(struct altera_config *config, const struct firmware *fw)
+{
+       struct altera_state *astate = NULL;
+       struct altera_procinfo *proc_list = NULL;
+       struct altera_procinfo *procptr = NULL;
+       char *key = NULL;
+       char *value = NULL;
+       char *action_name = NULL;
+       char *description = NULL;
+       int exec_result = 0;
+       int exit_code = 0;
+       int format_version = 0;
+       int action_count = 0;
+       int procedure_count = 0;
+       int index = 0;
+       s32 offset = 0L;
+       s32 error_address = 0L;
+       int retval = 0;
+
+       key = kzalloc(33, GFP_KERNEL);
+       if (!key) {
+               retval = -ENOMEM;
+               goto out;
+       }
+       value = kzalloc(257, GFP_KERNEL);
+       if (!value) {
+               retval = -ENOMEM;
+               goto free_key;
+       }
+       astate = kzalloc(sizeof(struct altera_state), GFP_KERNEL);
+       if (!astate) {
+               retval = -ENOMEM;
+               goto free_value;
+       }
+
+       astate->config = config;
+       if (!astate->config->jtag_io) {
+               dprintk(KERN_INFO "%s: using byteblaster!\n", __func__);
+               astate->config->jtag_io = netup_jtag_io_lpt;
+       }
+
+       altera_check_crc((u8 *)fw->data, fw->size);
+
+       if (debug) {
+               altera_get_file_info((u8 *)fw->data, fw->size, &format_version,
+                                       &action_count, &procedure_count);
+               printk(KERN_INFO "%s: File format is %s ByteCode format\n",
+                       __func__, (format_version == 2) ? "Jam STAPL" :
+                                               "pre-standardized Jam 1.1");
+               while (altera_get_note((u8 *)fw->data, fw->size,
+                                       &offset, key, value, 256) == 0)
+                       printk(KERN_INFO "%s: NOTE \"%s\" = \"%s\"\n",
+                                       __func__, key, value);
+       }
+
+       if (debug && (format_version == 2) && (action_count > 0)) {
+               printk(KERN_INFO "%s: Actions available:\n", __func__);
+               for (index = 0; index < action_count; ++index) {
+                       altera_get_act_info((u8 *)fw->data, fw->size,
+                                               index, &action_name,
+                                               &description,
+                                               &proc_list);
+
+                       if (description == NULL)
+                               printk(KERN_INFO "%s: %s\n",
+                                               __func__,
+                                               action_name);
+                       else
+                               printk(KERN_INFO "%s: %s \"%s\"\n",
+                                               __func__,
+                                               action_name,
+                                               description);
+
+                       procptr = proc_list;
+                       while (procptr != NULL) {
+                               if (procptr->attrs != 0)
+                                       printk(KERN_INFO "%s:    %s (%s)\n",
+                                               __func__,
+                                               procptr->name,
+                                               (procptr->attrs == 1) ?
+                                               "optional" : "recommended");
+
+                               proc_list = procptr->next;
+                               kfree(procptr);
+                               procptr = proc_list;
+                       }
+               }
+
+               printk(KERN_INFO "\n");
+       }
+
+       exec_result = altera_execute(astate, (u8 *)fw->data, fw->size,
+                               &error_address, &exit_code, &format_version);
+
+       if (exit_code)
+               exec_result = -EREMOTEIO;
+
+       if ((format_version == 2) && (exec_result == -EINVAL)) {
+               if (astate->config->action == NULL)
+                       printk(KERN_ERR "%s: error: no action specified for "
+                               "Jam STAPL file.\nprogram terminated.\n",
+                               __func__);
+               else
+                       printk(KERN_ERR "%s: error: action \"%s\""
+                               " is not supported "
+                               "for this Jam STAPL file.\n"
+                               "Program terminated.\n", __func__,
+                               astate->config->action);
+
+       } else if (exec_result)
+               printk(KERN_ERR "%s: error %d\n", __func__, exec_result);
+
+       kfree(astate);
+free_value:
+       kfree(value);
+free_key:
+       kfree(key);
+out:
+       return retval;
+}
+EXPORT_SYMBOL(altera_init);
index b33c099..0ae0d7c 100644 (file)
@@ -2110,9 +2110,6 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
 
        read_lock(&bond->lock);
 
-       if (bond->kill_timers)
-               goto out;
-
        //check if there are any slaves
        if (bond->slave_cnt == 0)
                goto re_arm;
@@ -2161,9 +2158,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        }
 
 re_arm:
-       if (!bond->kill_timers)
-               queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
-out:
+       queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
+
        read_unlock(&bond->lock);
 }
 
index d4fbd2e..106b88a 100644 (file)
@@ -1343,10 +1343,6 @@ void bond_alb_monitor(struct work_struct *work)
 
        read_lock(&bond->lock);
 
-       if (bond->kill_timers) {
-               goto out;
-       }
-
        if (bond->slave_cnt == 0) {
                bond_info->tx_rebalance_counter = 0;
                bond_info->lp_counter = 0;
@@ -1401,10 +1397,13 @@ void bond_alb_monitor(struct work_struct *work)
 
                        /*
                         * dev_set_promiscuity requires rtnl and
-                        * nothing else.
+                        * nothing else.  Avoid race with bond_close.
                         */
                        read_unlock(&bond->lock);
-                       rtnl_lock();
+                       if (!rtnl_trylock()) {
+                               read_lock(&bond->lock);
+                               goto re_arm;
+                       }
 
                        bond_info->rlb_promisc_timeout_counter = 0;
 
@@ -1440,9 +1439,8 @@ void bond_alb_monitor(struct work_struct *work)
        }
 
 re_arm:
-       if (!bond->kill_timers)
-               queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks);
-out:
+       queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks);
+
        read_unlock(&bond->lock);
 }
 
index c5944f1..c34cc1e 100644 (file)
@@ -773,9 +773,6 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
 
        read_lock(&bond->lock);
 
-       if (bond->kill_timers)
-               goto out;
-
        /* rejoin all groups on bond device */
        __bond_resend_igmp_join_requests(bond->dev);
 
@@ -789,9 +786,9 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
                        __bond_resend_igmp_join_requests(vlan_dev);
        }
 
-       if ((--bond->igmp_retrans > 0) && !bond->kill_timers)
+       if (--bond->igmp_retrans > 0)
                queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
-out:
+
        read_unlock(&bond->lock);
 }
 
@@ -2517,10 +2514,11 @@ void bond_mii_monitor(struct work_struct *work)
        struct bonding *bond = container_of(work, struct bonding,
                                            mii_work.work);
        bool should_notify_peers = false;
+       unsigned long delay;
 
        read_lock(&bond->lock);
-       if (bond->kill_timers)
-               goto out;
+
+       delay = msecs_to_jiffies(bond->params.miimon);
 
        if (bond->slave_cnt == 0)
                goto re_arm;
@@ -2529,7 +2527,15 @@ void bond_mii_monitor(struct work_struct *work)
 
        if (bond_miimon_inspect(bond)) {
                read_unlock(&bond->lock);
-               rtnl_lock();
+
+               /* Race avoidance with bond_close cancel of workqueue */
+               if (!rtnl_trylock()) {
+                       read_lock(&bond->lock);
+                       delay = 1;
+                       should_notify_peers = false;
+                       goto re_arm;
+               }
+
                read_lock(&bond->lock);
 
                bond_miimon_commit(bond);
@@ -2540,14 +2546,18 @@ void bond_mii_monitor(struct work_struct *work)
        }
 
 re_arm:
-       if (bond->params.miimon && !bond->kill_timers)
-               queue_delayed_work(bond->wq, &bond->mii_work,
-                                  msecs_to_jiffies(bond->params.miimon));
-out:
+       if (bond->params.miimon)
+               queue_delayed_work(bond->wq, &bond->mii_work, delay);
+
        read_unlock(&bond->lock);
 
        if (should_notify_peers) {
-               rtnl_lock();
+               if (!rtnl_trylock()) {
+                       read_lock(&bond->lock);
+                       bond->send_peer_notif++;
+                       read_unlock(&bond->lock);
+                       return;
+               }
                netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS);
                rtnl_unlock();
        }
@@ -2789,9 +2799,6 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
 
        delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
 
-       if (bond->kill_timers)
-               goto out;
-
        if (bond->slave_cnt == 0)
                goto re_arm;
 
@@ -2888,9 +2895,9 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
        }
 
 re_arm:
-       if (bond->params.arp_interval && !bond->kill_timers)
+       if (bond->params.arp_interval)
                queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
-out:
+
        read_unlock(&bond->lock);
 }
 
@@ -3131,9 +3138,6 @@ void bond_activebackup_arp_mon(struct work_struct *work)
 
        read_lock(&bond->lock);
 
-       if (bond->kill_timers)
-               goto out;
-
        delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
 
        if (bond->slave_cnt == 0)
@@ -3143,7 +3147,15 @@ void bond_activebackup_arp_mon(struct work_struct *work)
 
        if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
                read_unlock(&bond->lock);
-               rtnl_lock();
+
+               /* Race avoidance with bond_close flush of workqueue */
+               if (!rtnl_trylock()) {
+                       read_lock(&bond->lock);
+                       delta_in_ticks = 1;
+                       should_notify_peers = false;
+                       goto re_arm;
+               }
+
                read_lock(&bond->lock);
 
                bond_ab_arp_commit(bond, delta_in_ticks);
@@ -3156,13 +3168,18 @@ void bond_activebackup_arp_mon(struct work_struct *work)
        bond_ab_arp_probe(bond);
 
 re_arm:
-       if (bond->params.arp_interval && !bond->kill_timers)
+       if (bond->params.arp_interval)
                queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
-out:
+
        read_unlock(&bond->lock);
 
        if (should_notify_peers) {
-               rtnl_lock();
+               if (!rtnl_trylock()) {
+                       read_lock(&bond->lock);
+                       bond->send_peer_notif++;
+                       read_unlock(&bond->lock);
+                       return;
+               }
                netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS);
                rtnl_unlock();
        }
@@ -3424,8 +3441,6 @@ static int bond_open(struct net_device *bond_dev)
        struct slave *slave;
        int i;
 
-       bond->kill_timers = 0;
-
        /* reset slave->backup and slave->inactive */
        read_lock(&bond->lock);
        if (bond->slave_cnt > 0) {
@@ -3494,33 +3509,30 @@ static int bond_close(struct net_device *bond_dev)
 
        bond->send_peer_notif = 0;
 
-       /* signal timers not to re-arm */
-       bond->kill_timers = 1;
-
        write_unlock_bh(&bond->lock);
 
        if (bond->params.miimon) {  /* link check interval, in milliseconds. */
-               cancel_delayed_work(&bond->mii_work);
+               cancel_delayed_work_sync(&bond->mii_work);
        }
 
        if (bond->params.arp_interval) {  /* arp interval, in milliseconds. */
-               cancel_delayed_work(&bond->arp_work);
+               cancel_delayed_work_sync(&bond->arp_work);
        }
 
        switch (bond->params.mode) {
        case BOND_MODE_8023AD:
-               cancel_delayed_work(&bond->ad_work);
+               cancel_delayed_work_sync(&bond->ad_work);
                break;
        case BOND_MODE_TLB:
        case BOND_MODE_ALB:
-               cancel_delayed_work(&bond->alb_work);
+               cancel_delayed_work_sync(&bond->alb_work);
                break;
        default:
                break;
        }
 
        if (delayed_work_pending(&bond->mcast_work))
-               cancel_delayed_work(&bond->mcast_work);
+               cancel_delayed_work_sync(&bond->mcast_work);
 
        if (bond_is_lb(bond)) {
                /* Must be called only after all
@@ -4367,26 +4379,22 @@ static void bond_setup(struct net_device *bond_dev)
 
 static void bond_work_cancel_all(struct bonding *bond)
 {
-       write_lock_bh(&bond->lock);
-       bond->kill_timers = 1;
-       write_unlock_bh(&bond->lock);
-
        if (bond->params.miimon && delayed_work_pending(&bond->mii_work))
-               cancel_delayed_work(&bond->mii_work);
+               cancel_delayed_work_sync(&bond->mii_work);
 
        if (bond->params.arp_interval && delayed_work_pending(&bond->arp_work))
-               cancel_delayed_work(&bond->arp_work);
+               cancel_delayed_work_sync(&bond->arp_work);
 
        if (bond->params.mode == BOND_MODE_ALB &&
            delayed_work_pending(&bond->alb_work))
-               cancel_delayed_work(&bond->alb_work);
+               cancel_delayed_work_sync(&bond->alb_work);
 
        if (bond->params.mode == BOND_MODE_8023AD &&
            delayed_work_pending(&bond->ad_work))
-               cancel_delayed_work(&bond->ad_work);
+               cancel_delayed_work_sync(&bond->ad_work);
 
        if (delayed_work_pending(&bond->mcast_work))
-               cancel_delayed_work(&bond->mcast_work);
+               cancel_delayed_work_sync(&bond->mcast_work);
 }
 
 /*
index 82fec5f..1aecc37 100644 (file)
@@ -222,7 +222,6 @@ struct bonding {
                               struct slave *);
        rwlock_t lock;
        rwlock_t curr_slave_lock;
-       s8       kill_timers;
        u8       send_peer_notif;
        s8       setup_by_slave;
        s8       igmp_retrans;
index 627a580..aec7212 100644 (file)
@@ -23,8 +23,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.70.00-0"
-#define DRV_MODULE_RELDATE      "2011/06/13"
+#define DRV_MODULE_VERSION      "1.70.30-0"
+#define DRV_MODULE_RELDATE      "2011/10/25"
 #define BNX2X_BC_VER            0x040200
 
 #if defined(CONFIG_DCB)
index 1a6e37c..f0ca8b2 100644 (file)
@@ -329,6 +329,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                        PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
                break;
        case PORT_FIBRE:
+       case PORT_DA:
                if (bp->port.supported[cfg_idx] & SUPPORTED_FIBRE)
                        break; /* no port change */
 
index e44b858..fc754cb 100644 (file)
@@ -2550,7 +2550,7 @@ struct host_func_stats {
 
 #define BCM_5710_FW_MAJOR_VERSION                      7
 #define BCM_5710_FW_MINOR_VERSION                      0
-#define BCM_5710_FW_REVISION_VERSION           23
+#define BCM_5710_FW_REVISION_VERSION           29
 #define BCM_5710_FW_ENGINEERING_VERSION                0
 #define BCM_5710_FW_COMPILE_FLAGS                      1
 
index 818723c..bce203f 100644 (file)
@@ -45,6 +45,9 @@
 #define MCPR_IMC_COMMAND_READ_OP       1
 #define MCPR_IMC_COMMAND_WRITE_OP      2
 
+/* LED Blink rate that will achieve ~15.9Hz */
+#define LED_BLINK_RATE_VAL_E3          354
+#define LED_BLINK_RATE_VAL_E1X_E2      480
 /***********************************************************/
 /*                     Shortcut definitions               */
 /***********************************************************/
 
 #define MAX_PACKET_SIZE                                        (9700)
 #define WC_UC_TIMEOUT                                  100
+#define MAX_KR_LINK_RETRY                              4
 
 /**********************************************************/
 /*                     INTERFACE                          */
@@ -1490,6 +1494,18 @@ static void bnx2x_set_xumac_nig(struct link_params *params,
               NIG_REG_P0_MAC_PAUSE_OUT_EN, tx_pause_en);
 }
 
+static void bnx2x_umac_disable(struct link_params *params)
+{
+       u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
+       struct bnx2x *bp = params->bp;
+       if (!(REG_RD(bp, MISC_REG_RESET_REG_2) &
+                  (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port)))
+               return;
+
+       /* Disable RX and TX */
+       REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, 0);
+}
+
 static void bnx2x_umac_enable(struct link_params *params,
                            struct link_vars *vars, u8 lb)
 {
@@ -1599,8 +1615,9 @@ static u8 bnx2x_is_4_port_mode(struct bnx2x *bp)
 }
 
 /* Define the XMAC mode */
-static void bnx2x_xmac_init(struct bnx2x *bp, u32 max_speed)
+static void bnx2x_xmac_init(struct link_params *params, u32 max_speed)
 {
+       struct bnx2x *bp = params->bp;
        u32 is_port4mode = bnx2x_is_4_port_mode(bp);
 
        /**
@@ -1610,7 +1627,8 @@ static void bnx2x_xmac_init(struct bnx2x *bp, u32 max_speed)
        * ports of the path
        **/
 
-       if (is_port4mode && (REG_RD(bp, MISC_REG_RESET_REG_2) &
+       if ((CHIP_NUM(bp) == CHIP_NUM_57840) &&
+           (REG_RD(bp, MISC_REG_RESET_REG_2) &
             MISC_REGISTERS_RESET_REG_2_XMAC)) {
                DP(NETIF_MSG_LINK,
                   "XMAC already out of reset in 4-port mode\n");
@@ -1677,10 +1695,6 @@ static void bnx2x_xmac_disable(struct link_params *params)
                       (pfc_ctrl | (1<<1)));
                DP(NETIF_MSG_LINK, "Disable XMAC on port %x\n", port);
                REG_WR(bp, xmac_base + XMAC_REG_CTRL, 0);
-               usleep_range(1000, 1000);
-               bnx2x_set_xumac_nig(params, 0, 0);
-               REG_WR(bp, xmac_base + XMAC_REG_CTRL,
-                      XMAC_CTRL_REG_SOFT_RESET);
        }
 }
 
@@ -1693,7 +1707,7 @@ static int bnx2x_xmac_enable(struct link_params *params,
 
        xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
 
-       bnx2x_xmac_init(bp, vars->line_speed);
+       bnx2x_xmac_init(params, vars->line_speed);
 
        /*
         * This register determines on which events the MAC will assert
@@ -3575,6 +3589,11 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
        u16 val16 = 0, lane, bam37 = 0;
        struct bnx2x *bp = params->bp;
        DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n");
+
+       /* Disable Autoneg: re-enable it after adv is done. */
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                        MDIO_WC_REG_IEEE0BLK_MIICNTL, 0);
+
        /* Check adding advertisement for 1G KX */
        if (((vars->line_speed == SPEED_AUTO_NEG) &&
             (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
@@ -3616,9 +3635,6 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
        bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
                         MDIO_WC_REG_CL72_USERB0_CL72_2P5_DEF_CTRL,
                         0x03f0);
-       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-                        MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
-                        0x383f);
 
        /* Advertised speeds */
        bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
@@ -3645,19 +3661,22 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
        /* Advertise pause */
        bnx2x_ext_phy_set_pause(params, phy, vars);
 
-       /* Enable Autoneg */
-       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
-                        MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1000);
-
-       /* Over 1G - AN local device user page 1 */
-       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-                       MDIO_WC_REG_DIGITAL3_UP1, 0x1f);
+       vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
 
        bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
                        MDIO_WC_REG_DIGITAL5_MISC7, &val16);
 
        bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
                         MDIO_WC_REG_DIGITAL5_MISC7, val16 | 0x100);
+
+       /* Over 1G - AN local device user page 1 */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_DIGITAL3_UP1, 0x1f);
+
+       /* Enable Autoneg */
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                        MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1000);
+
 }
 
 static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy,
@@ -4126,6 +4145,85 @@ static int bnx2x_is_sfp_module_plugged(struct bnx2x_phy *phy,
        else
                return 0;
 }
+static int bnx2x_warpcore_get_sigdet(struct bnx2x_phy *phy,
+                                       struct link_params *params)
+{
+       u16 gp2_status_reg0, lane;
+       struct bnx2x *bp = params->bp;
+
+       lane = bnx2x_get_warpcore_lane(phy, params);
+
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, MDIO_WC_REG_GP2_STATUS_GP_2_0,
+                                &gp2_status_reg0);
+
+       return (gp2_status_reg0 >> (8+lane)) & 0x1;
+}
+
+static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
+                                      struct link_params *params,
+                                      struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u32 serdes_net_if;
+       u16 gp_status1 = 0, lnkup = 0, lnkup_kr = 0;
+       u16 lane = bnx2x_get_warpcore_lane(phy, params);
+
+       vars->turn_to_run_wc_rt = vars->turn_to_run_wc_rt ? 0 : 1;
+
+       if (!vars->turn_to_run_wc_rt)
+               return;
+
+       /* return if there is no link partner */
+       if (!(bnx2x_warpcore_get_sigdet(phy, params))) {
+               DP(NETIF_MSG_LINK, "bnx2x_warpcore_get_sigdet false\n");
+               return;
+       }
+
+       if (vars->rx_tx_asic_rst) {
+               serdes_net_if = (REG_RD(bp, params->shmem_base +
+                               offsetof(struct shmem_region, dev_info.
+                               port_hw_config[params->port].default_cfg)) &
+                               PORT_HW_CFG_NET_SERDES_IF_MASK);
+
+               switch (serdes_net_if) {
+               case PORT_HW_CFG_NET_SERDES_IF_KR:
+                       /* Do we get link yet? */
+                       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, 0x81d1,
+                                                               &gp_status1);
+                       lnkup = (gp_status1 >> (8+lane)) & 0x1;/* 1G */
+                               /*10G KR*/
+                       lnkup_kr = (gp_status1 >> (12+lane)) & 0x1;
+
+                       DP(NETIF_MSG_LINK,
+                               "gp_status1 0x%x\n", gp_status1);
+
+                       if (lnkup_kr || lnkup) {
+                                       vars->rx_tx_asic_rst = 0;
+                                       DP(NETIF_MSG_LINK,
+                                       "link up, rx_tx_asic_rst 0x%x\n",
+                                       vars->rx_tx_asic_rst);
+                       } else {
+                               /*reset the lane to see if link comes up.*/
+                               bnx2x_warpcore_reset_lane(bp, phy, 1);
+                               bnx2x_warpcore_reset_lane(bp, phy, 0);
+
+                               /* restart Autoneg */
+                               bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                                       MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1200);
+
+                               vars->rx_tx_asic_rst--;
+                               DP(NETIF_MSG_LINK, "0x%x retry left\n",
+                               vars->rx_tx_asic_rst);
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+
+       } /*params->rx_tx_asic_rst*/
+
+}
 
 static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
                                       struct link_params *params,
@@ -5896,7 +5994,13 @@ int bnx2x_set_led(struct link_params *params,
                       SHARED_HW_CFG_LED_MAC1);
 
                tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
-               EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
+               if (params->phy[EXT_PHY1].type ==
+                         PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE)
+                       EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp & 0xfff1);
+               else {
+                       EMAC_WR(bp, EMAC_REG_EMAC_LED,
+                               (tmp | EMAC_LED_OVERRIDE));
+               }
                break;
 
        case LED_MODE_OPER:
@@ -5949,17 +6053,33 @@ int bnx2x_set_led(struct link_params *params,
                        else
                                REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
                                       hw_led_mode);
+               } else if ((params->phy[EXT_PHY1].type ==
+                           PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) &&
+                          (mode != LED_MODE_OPER)) {
+                       REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
+                       tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
+                       EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp | 0x3);
                } else
-                       REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
+                       REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
+                              hw_led_mode);
 
                REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0);
                /* Set blinking rate to ~15.9Hz */
-               REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
-                      LED_BLINK_RATE_VAL);
+               if (CHIP_IS_E3(bp))
+                       REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
+                              LED_BLINK_RATE_VAL_E3);
+               else
+                       REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
+                              LED_BLINK_RATE_VAL_E1X_E2);
                REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
                       port*4, 1);
-               tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
-               EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp & (~EMAC_LED_OVERRIDE)));
+               if ((params->phy[EXT_PHY1].type !=
+                    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) &&
+                   (mode != LED_MODE_OPER)) {
+                       tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
+                       EMAC_WR(bp, EMAC_REG_EMAC_LED,
+                               (tmp & (~EMAC_LED_OVERRIDE)));
+               }
 
                if (CHIP_IS_E1(bp) &&
                    ((speed == SPEED_2500) ||
@@ -6218,8 +6338,10 @@ static int bnx2x_update_link_down(struct link_params *params,
                       MISC_REGISTERS_RESET_REG_2_CLEAR,
               (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
        }
-       if (CHIP_IS_E3(bp))
+       if (CHIP_IS_E3(bp)) {
                bnx2x_xmac_disable(params);
+               bnx2x_umac_disable(params);
+       }
 
        return 0;
 }
@@ -10205,22 +10327,6 @@ static int bnx2x_54618se_config_init(struct bnx2x_phy *phy,
        return 0;
 }
 
-static void bnx2x_54618se_set_link_led(struct bnx2x_phy *phy,
-                                      struct link_params *params, u8 mode)
-{
-       struct bnx2x *bp = params->bp;
-       DP(NETIF_MSG_LINK, "54618SE set link led (mode=%x)\n", mode);
-       switch (mode) {
-       case LED_MODE_FRONT_PANEL_OFF:
-       case LED_MODE_OFF:
-       case LED_MODE_OPER:
-       case LED_MODE_ON:
-       default:
-               break;
-       }
-       return;
-}
-
 static void bnx2x_54618se_link_reset(struct bnx2x_phy *phy,
                                     struct link_params *params)
 {
@@ -10997,7 +11103,7 @@ static struct bnx2x_phy phy_54618se = {
        .config_loopback = (config_loopback_t)bnx2x_54618se_config_loopback,
        .format_fw_ver  = (format_fw_ver_t)NULL,
        .hw_reset       = (hw_reset_t)NULL,
-       .set_link_led   = (set_link_led_t)bnx2x_54618se_set_link_led,
+       .set_link_led   = (set_link_led_t)NULL,
        .phy_specific_func = (phy_specific_func_t)NULL
 };
 /*****************************************************************/
@@ -11718,8 +11824,10 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
        /* Stop BigMac rx */
        if (!CHIP_IS_E3(bp))
                bnx2x_bmac_rx_disable(bp, port);
-       else
+       else {
                bnx2x_xmac_disable(params);
+               bnx2x_umac_disable(params);
+       }
        /* disable emac */
        if (!CHIP_IS_E3(bp))
                REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
@@ -11757,14 +11865,21 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
        if (params->phy[INT_PHY].link_reset)
                params->phy[INT_PHY].link_reset(
                        &params->phy[INT_PHY], params);
-       /* reset BigMac */
-       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
-              (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
 
        /* disable nig ingress interface */
        if (!CHIP_IS_E3(bp)) {
+               /* reset BigMac */
+               REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+                      (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
                REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
                REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
+       } else {
+               u32 xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
+               bnx2x_set_xumac_nig(params, 0, 0);
+               if (REG_RD(bp, MISC_REG_RESET_REG_2) &
+                   MISC_REGISTERS_RESET_REG_2_XMAC)
+                       REG_WR(bp, xmac_base + XMAC_REG_CTRL,
+                              XMAC_CTRL_REG_SOFT_RESET);
        }
        vars->link_up = 0;
        vars->phy_flags = 0;
@@ -12332,11 +12447,6 @@ void bnx2x_period_func(struct link_params *params, struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u16 phy_idx;
-       if (!params) {
-               DP(NETIF_MSG_LINK, "Uninitialized params !\n");
-               return;
-       }
-
        for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
                if (params->phy[phy_idx].flags & FLAGS_TX_ERROR_CHECK) {
                        bnx2x_set_aer_mmd(params, &params->phy[phy_idx]);
@@ -12345,8 +12455,13 @@ void bnx2x_period_func(struct link_params *params, struct link_vars *vars)
                }
        }
 
-       if (CHIP_IS_E3(bp))
+       if (CHIP_IS_E3(bp)) {
+               struct bnx2x_phy *phy = &params->phy[INT_PHY];
+               bnx2x_set_aer_mmd(params, phy);
                bnx2x_check_over_curr(params, vars);
+               bnx2x_warpcore_config_runtime(phy, params, vars);
+       }
+
 }
 
 u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
index c12db6d..2a46e63 100644 (file)
@@ -303,6 +303,9 @@ struct link_vars {
 #define PERIODIC_FLAGS_LINK_EVENT      0x0001
 
        u32 aeu_int_mask;
+       u8 rx_tx_asic_rst;
+       u8 turn_to_run_wc_rt;
+       u16 rsrv2;
 };
 
 /***********************************************************/
index e0ff961..824b8e6 100644 (file)
@@ -428,28 +428,33 @@ static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb)
        return &wrb->payload.sgl[0];
 }
 
-/* Don't touch the hdr after it's prepared */
-static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
-                               bool embedded, u8 sge_cnt, u32 opcode)
-{
-       if (embedded)
-               wrb->embedded |= MCC_WRB_EMBEDDED_MASK;
-       else
-               wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) <<
-                               MCC_WRB_SGE_CNT_SHIFT;
-       wrb->payload_length = payload_len;
-       wrb->tag0 = opcode;
-       be_dws_cpu_to_le(wrb, 8);
-}
 
 /* Don't touch the hdr after it's prepared */
-static void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
-                               u8 subsystem, u8 opcode, int cmd_len)
+/* mem will be NULL for embedded commands */
+static void be_wrb_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
+                               u8 subsystem, u8 opcode, int cmd_len,
+                               struct be_mcc_wrb *wrb, struct be_dma_mem *mem)
 {
+       struct be_sge *sge;
+
        req_hdr->opcode = opcode;
        req_hdr->subsystem = subsystem;
        req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr));
        req_hdr->version = 0;
+
+       wrb->tag0 = opcode;
+       wrb->tag1 = subsystem;
+       wrb->payload_length = cmd_len;
+       if (mem) {
+               wrb->embedded |= (1 & MCC_WRB_SGE_CNT_MASK) <<
+                       MCC_WRB_SGE_CNT_SHIFT;
+               sge = nonembedded_sgl(wrb);
+               sge->pa_hi = cpu_to_le32(upper_32_bits(mem->dma));
+               sge->pa_lo = cpu_to_le32(mem->dma & 0xFFFFFFFF);
+               sge->len = cpu_to_le32(mem->size);
+       } else
+               wrb->embedded |= MCC_WRB_EMBEDDED_MASK;
+       be_dws_cpu_to_le(wrb, 8);
 }
 
 static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages,
@@ -586,10 +591,8 @@ int be_cmd_eq_create(struct be_adapter *adapter,
        wrb = wrb_from_mbox(adapter);
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_COMMON_EQ_CREATE);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_EQ_CREATE, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_EQ_CREATE, sizeof(*req), wrb, NULL);
 
        req->num_pages =  cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
 
@@ -632,12 +635,8 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_NTWK_MAC_QUERY);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_NTWK_MAC_QUERY, sizeof(*req));
-
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_MAC_QUERY, sizeof(*req), wrb, NULL);
        req->type = type;
        if (permanent) {
                req->permanent = 1;
@@ -674,11 +673,8 @@ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_NTWK_PMAC_ADD);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_NTWK_PMAC_ADD, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_PMAC_ADD, sizeof(*req), wrb, NULL);
 
        req->hdr.domain = domain;
        req->if_id = cpu_to_le32(if_id);
@@ -692,6 +688,10 @@ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
 
 err:
        spin_unlock_bh(&adapter->mcc_lock);
+
+        if (status == MCC_STATUS_UNAUTHORIZED_REQUEST)
+               status = -EPERM;
+
        return status;
 }
 
@@ -711,11 +711,8 @@ int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id, u32 dom)
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_NTWK_PMAC_DEL);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_NTWK_PMAC_DEL, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_PMAC_DEL, sizeof(*req), wrb, NULL);
 
        req->hdr.domain = dom;
        req->if_id = cpu_to_le32(if_id);
@@ -746,11 +743,8 @@ int be_cmd_cq_create(struct be_adapter *adapter,
        req = embedded_payload(wrb);
        ctxt = &req->context;
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_CQ_CREATE);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_CQ_CREATE, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_CQ_CREATE, sizeof(*req), wrb, NULL);
 
        req->num_pages =  cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
        if (lancer_chip(adapter)) {
@@ -822,11 +816,8 @@ int be_cmd_mccq_ext_create(struct be_adapter *adapter,
        req = embedded_payload(wrb);
        ctxt = &req->context;
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_MCC_CREATE_EXT);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-                       OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                       OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req), wrb, NULL);
 
        req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
        if (lancer_chip(adapter)) {
@@ -882,11 +873,8 @@ int be_cmd_mccq_org_create(struct be_adapter *adapter,
        req = embedded_payload(wrb);
        ctxt = &req->context;
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_MCC_CREATE);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-                       OPCODE_COMMON_MCC_CREATE, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                       OPCODE_COMMON_MCC_CREATE, sizeof(*req), wrb, NULL);
 
        req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
 
@@ -943,11 +931,8 @@ int be_cmd_txq_create(struct be_adapter *adapter,
        req = embedded_payload(wrb);
        ctxt = &req->context;
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_ETH_TX_CREATE);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_TX_CREATE,
-               sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
+               OPCODE_ETH_TX_CREATE, sizeof(*req), wrb, NULL);
 
        if (lancer_chip(adapter)) {
                req->hdr.version = 1;
@@ -999,11 +984,8 @@ int be_cmd_rxq_create(struct be_adapter *adapter,
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_ETH_RX_CREATE);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_RX_CREATE,
-               sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
+                               OPCODE_ETH_RX_CREATE, sizeof(*req), wrb, NULL);
 
        req->cq_id = cpu_to_le16(cq_id);
        req->frag_size = fls(frag_size) - 1;
@@ -1071,9 +1053,8 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
                BUG();
        }
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, opcode);
-
-       be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req), wrb,
+                               NULL);
        req->id = cpu_to_le16(q->id);
 
        status = be_mbox_notify_wait(adapter);
@@ -1100,9 +1081,8 @@ int be_cmd_rxq_destroy(struct be_adapter *adapter, struct be_queue_info *q)
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_ETH_RX_DESTROY);
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_RX_DESTROY,
-               sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
+                       OPCODE_ETH_RX_DESTROY, sizeof(*req), wrb, NULL);
        req->id = cpu_to_le16(q->id);
 
        status = be_mcc_notify_wait(adapter);
@@ -1133,12 +1113,8 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_NTWK_INTERFACE_CREATE);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_NTWK_INTERFACE_CREATE, sizeof(*req));
-
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_INTERFACE_CREATE, sizeof(*req), wrb, NULL);
        req->hdr.domain = domain;
        req->capability_flags = cpu_to_le32(cap_flags);
        req->enable_flags = cpu_to_le32(en_flags);
@@ -1182,12 +1158,8 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain)
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_NTWK_INTERFACE_DESTROY);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req));
-
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req), wrb, NULL);
        req->hdr.domain = domain;
        req->interface_id = cpu_to_le32(interface_id);
 
@@ -1205,7 +1177,6 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_hdr *hdr;
-       struct be_sge *sge;
        int status = 0;
 
        if (MODULO(adapter->work_counter, be_get_temp_freq) == 0)
@@ -1219,22 +1190,13 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
                goto err;
        }
        hdr = nonemb_cmd->va;
-       sge = nonembedded_sgl(wrb);
-
-       be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1,
-                       OPCODE_ETH_GET_STATISTICS);
 
-       be_cmd_hdr_prepare(hdr, CMD_SUBSYSTEM_ETH,
-               OPCODE_ETH_GET_STATISTICS, nonemb_cmd->size);
+       be_wrb_cmd_hdr_prepare(hdr, CMD_SUBSYSTEM_ETH,
+               OPCODE_ETH_GET_STATISTICS, nonemb_cmd->size, wrb, nonemb_cmd);
 
        if (adapter->generation == BE_GEN3)
                hdr->version = 1;
 
-       wrb->tag1 = CMD_SUBSYSTEM_ETH;
-       sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
-       sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
-       sge->len = cpu_to_le32(nonemb_cmd->size);
-
        be_mcc_notify(adapter);
        adapter->stats_cmd_sent = true;
 
@@ -1250,7 +1212,6 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
 
        struct be_mcc_wrb *wrb;
        struct lancer_cmd_req_pport_stats *req;
-       struct be_sge *sge;
        int status = 0;
 
        spin_lock_bh(&adapter->mcc_lock);
@@ -1261,23 +1222,14 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
                goto err;
        }
        req = nonemb_cmd->va;
-       sge = nonembedded_sgl(wrb);
-
-       be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1,
-                       OPCODE_ETH_GET_PPORT_STATS);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
-                       OPCODE_ETH_GET_PPORT_STATS, nonemb_cmd->size);
 
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
+                       OPCODE_ETH_GET_PPORT_STATS, nonemb_cmd->size, wrb,
+                       nonemb_cmd);
 
        req->cmd_params.params.pport_num = cpu_to_le16(adapter->port_num);
        req->cmd_params.params.reset_stats = 0;
 
-       wrb->tag1 = CMD_SUBSYSTEM_ETH;
-       sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
-       sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
-       sge->len = cpu_to_le32(nonemb_cmd->size);
-
        be_mcc_notify(adapter);
        adapter->stats_cmd_sent = true;
 
@@ -1303,11 +1255,8 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed,
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_NTWK_LINK_STATUS_QUERY);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req), wrb, NULL);
 
        status = be_mcc_notify_wait(adapter);
        if (!status) {
@@ -1343,11 +1292,9 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter)
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, sizeof(*req),
+               wrb, NULL);
 
        wrb->tag1 = mccq_index;
 
@@ -1374,11 +1321,8 @@ int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size)
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_MANAGE_FAT);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_MANAGE_FAT, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_MANAGE_FAT, sizeof(*req), wrb, NULL);
        req->fat_operation = cpu_to_le32(QUERY_FAT);
        status = be_mcc_notify_wait(adapter);
        if (!status) {
@@ -1397,7 +1341,6 @@ void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
        struct be_dma_mem get_fat_cmd;
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_get_fat *req;
-       struct be_sge *sge;
        u32 offset = 0, total_size, buf_size,
                                log_offset = sizeof(u32), payload_len;
        int status;
@@ -1430,18 +1373,11 @@ void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
                        goto err;
                }
                req = get_fat_cmd.va;
-               sge = nonembedded_sgl(wrb);
 
                payload_len = sizeof(struct be_cmd_req_get_fat) + buf_size;
-               be_wrb_hdr_prepare(wrb, payload_len, false, 1,
-                               OPCODE_COMMON_MANAGE_FAT);
-
-               be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-                               OPCODE_COMMON_MANAGE_FAT, payload_len);
-
-               sge->pa_hi = cpu_to_le32(upper_32_bits(get_fat_cmd.dma));
-               sge->pa_lo = cpu_to_le32(get_fat_cmd.dma & 0xFFFFFFFF);
-               sge->len = cpu_to_le32(get_fat_cmd.size);
+               be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                               OPCODE_COMMON_MANAGE_FAT, payload_len, wrb,
+                               &get_fat_cmd);
 
                req->fat_operation = cpu_to_le32(RETRIEVE_FAT);
                req->read_log_offset = cpu_to_le32(log_offset);
@@ -1485,11 +1421,9 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver,
        }
 
        req = embedded_payload(wrb);
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                               OPCODE_COMMON_GET_FW_VERSION);
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-                               OPCODE_COMMON_GET_FW_VERSION, sizeof(*req));
 
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_GET_FW_VERSION, sizeof(*req), wrb, NULL);
        status = be_mcc_notify_wait(adapter);
        if (!status) {
                struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb);
@@ -1520,11 +1454,8 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd)
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_MODIFY_EQ_DELAY);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req), wrb, NULL);
 
        req->num_eq = cpu_to_le32(1);
        req->delay[0].eq_id = cpu_to_le32(eq_id);
@@ -1555,11 +1486,8 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_NTWK_VLAN_CONFIG);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req), wrb, NULL);
 
        req->interface_id = if_id;
        req->promiscuous = promiscuous;
@@ -1582,7 +1510,6 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
        struct be_mcc_wrb *wrb;
        struct be_dma_mem *mem = &adapter->rx_filter;
        struct be_cmd_req_rx_filter *req = mem->va;
-       struct be_sge *sge;
        int status;
 
        spin_lock_bh(&adapter->mcc_lock);
@@ -1592,16 +1519,10 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
                status = -EBUSY;
                goto err;
        }
-       sge = nonembedded_sgl(wrb);
-       sge->pa_hi = cpu_to_le32(upper_32_bits(mem->dma));
-       sge->pa_lo = cpu_to_le32(mem->dma & 0xFFFFFFFF);
-       sge->len = cpu_to_le32(mem->size);
-       be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
-                               OPCODE_COMMON_NTWK_RX_FILTER);
-
        memset(req, 0, sizeof(*req));
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-                               OPCODE_COMMON_NTWK_RX_FILTER, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                               OPCODE_COMMON_NTWK_RX_FILTER, sizeof(*req),
+                               wrb, mem);
 
        req->if_id = cpu_to_le32(adapter->if_handle);
        if (flags & IFF_PROMISC) {
@@ -1646,11 +1567,8 @@ int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc)
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_SET_FLOW_CONTROL);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_SET_FLOW_CONTROL, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_SET_FLOW_CONTROL, sizeof(*req), wrb, NULL);
 
        req->tx_flow_control = cpu_to_le16((u16)tx_fc);
        req->rx_flow_control = cpu_to_le16((u16)rx_fc);
@@ -1678,11 +1596,8 @@ int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc)
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_GET_FLOW_CONTROL);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req), wrb, NULL);
 
        status = be_mcc_notify_wait(adapter);
        if (!status) {
@@ -1711,11 +1626,8 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num,
        wrb = wrb_from_mbox(adapter);
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_QUERY_FIRMWARE_CONFIG);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req), wrb, NULL);
 
        status = be_mbox_notify_wait(adapter);
        if (!status) {
@@ -1742,11 +1654,8 @@ int be_cmd_reset_function(struct be_adapter *adapter)
        wrb = wrb_from_mbox(adapter);
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_FUNCTION_RESET);
-
-       be_cmd_hdr_prepare(req, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_FUNCTION_RESET, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(req, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_FUNCTION_RESET, sizeof(*req), wrb, NULL);
 
        status = be_mbox_notify_wait(adapter);
 
@@ -1768,11 +1677,8 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size)
        wrb = wrb_from_mbox(adapter);
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-               OPCODE_ETH_RSS_CONFIG);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
-               OPCODE_ETH_RSS_CONFIG, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
+               OPCODE_ETH_RSS_CONFIG, sizeof(*req), wrb, NULL);
 
        req->if_id = cpu_to_le32(adapter->if_handle);
        req->enable_rss = cpu_to_le16(RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4);
@@ -1804,11 +1710,8 @@ int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num,
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_ENABLE_DISABLE_BEACON);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_ENABLE_DISABLE_BEACON, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_ENABLE_DISABLE_BEACON, sizeof(*req), wrb, NULL);
 
        req->port_num = port_num;
        req->beacon_state = state;
@@ -1838,11 +1741,8 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state)
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                       OPCODE_COMMON_GET_BEACON_STATE);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_GET_BEACON_STATE, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_GET_BEACON_STATE, sizeof(*req), wrb, NULL);
 
        req->port_num = port_num;
 
@@ -1879,13 +1779,10 @@ int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
 
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(struct lancer_cmd_req_write_object),
-                       true, 1, OPCODE_COMMON_WRITE_OBJECT);
-       wrb->tag1 = CMD_SUBSYSTEM_COMMON;
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                                OPCODE_COMMON_WRITE_OBJECT,
-                               sizeof(struct lancer_cmd_req_write_object));
+                               sizeof(struct lancer_cmd_req_write_object), wrb,
+                               NULL);
 
        ctxt = &req->context;
        AMAP_SET_BITS(struct amap_lancer_write_obj_context,
@@ -1938,7 +1835,6 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_write_flashrom *req;
-       struct be_sge *sge;
        int status;
 
        spin_lock_bh(&adapter->mcc_lock);
@@ -1950,17 +1846,9 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
                goto err_unlock;
        }
        req = cmd->va;
-       sge = nonembedded_sgl(wrb);
-
-       be_wrb_hdr_prepare(wrb, cmd->size, false, 1,
-                       OPCODE_COMMON_WRITE_FLASHROM);
-       wrb->tag1 = CMD_SUBSYSTEM_COMMON;
 
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_WRITE_FLASHROM, cmd->size);
-       sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma));
-       sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF);
-       sge->len = cpu_to_le32(cmd->size);
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_WRITE_FLASHROM, cmd->size, wrb, cmd);
 
        req->params.op_type = cpu_to_le32(flash_type);
        req->params.op_code = cpu_to_le32(flash_opcode);
@@ -1998,11 +1886,8 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
        }
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req)+4, true, 0,
-                       OPCODE_COMMON_READ_FLASHROM);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_READ_FLASHROM, sizeof(*req)+4);
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_READ_FLASHROM, sizeof(*req)+4, wrb, NULL);
 
        req->params.op_type = cpu_to_le32(IMG_TYPE_REDBOOT);
        req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT);
@@ -2023,7 +1908,6 @@ int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_acpi_wol_magic_config *req;
-       struct be_sge *sge;
        int status;
 
        spin_lock_bh(&adapter->mcc_lock);
@@ -2034,19 +1918,12 @@ int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
                goto err;
        }
        req = nonemb_cmd->va;
-       sge = nonembedded_sgl(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
-                       OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
-               OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
+               OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, sizeof(*req), wrb,
+               nonemb_cmd);
        memcpy(req->magic_mac, mac, ETH_ALEN);
 
-       sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
-       sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
-       sge->len = cpu_to_le32(nonemb_cmd->size);
-
        status = be_mcc_notify_wait(adapter);
 
 err:
@@ -2071,12 +1948,9 @@ int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
 
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                               OPCODE_LOWLEVEL_SET_LOOPBACK_MODE);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
-                       OPCODE_LOWLEVEL_SET_LOOPBACK_MODE,
-                       sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
+                       OPCODE_LOWLEVEL_SET_LOOPBACK_MODE, sizeof(*req), wrb,
+                       NULL);
 
        req->src_port = port_num;
        req->dest_port = port_num;
@@ -2106,11 +1980,8 @@ int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num,
 
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                               OPCODE_LOWLEVEL_LOOPBACK_TEST);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
-                       OPCODE_LOWLEVEL_LOOPBACK_TEST, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
+                       OPCODE_LOWLEVEL_LOOPBACK_TEST, sizeof(*req), wrb, NULL);
        req->hdr.timeout = cpu_to_le32(4);
 
        req->pattern = cpu_to_le64(pattern);
@@ -2136,7 +2007,6 @@ int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern,
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_ddrdma_test *req;
-       struct be_sge *sge;
        int status;
        int i, j = 0;
 
@@ -2148,15 +2018,8 @@ int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern,
                goto err;
        }
        req = cmd->va;
-       sge = nonembedded_sgl(wrb);
-       be_wrb_hdr_prepare(wrb, cmd->size, false, 1,
-                               OPCODE_LOWLEVEL_HOST_DDR_DMA);
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
-                       OPCODE_LOWLEVEL_HOST_DDR_DMA, cmd->size);
-
-       sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma));
-       sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF);
-       sge->len = cpu_to_le32(cmd->size);
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
+                       OPCODE_LOWLEVEL_HOST_DDR_DMA, cmd->size, wrb, cmd);
 
        req->pattern = cpu_to_le64(pattern);
        req->byte_count = cpu_to_le32(byte_cnt);
@@ -2201,15 +2064,9 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
        req = nonemb_cmd->va;
        sge = nonembedded_sgl(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
-                       OPCODE_COMMON_SEEPROM_READ);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-                       OPCODE_COMMON_SEEPROM_READ, sizeof(*req));
-
-       sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
-       sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
-       sge->len = cpu_to_le32(nonemb_cmd->size);
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                       OPCODE_COMMON_SEEPROM_READ, sizeof(*req), wrb,
+                       nonemb_cmd);
 
        status = be_mcc_notify_wait(adapter);
 
@@ -2223,7 +2080,6 @@ int be_cmd_get_phy_info(struct be_adapter *adapter,
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_get_phy_info *req;
-       struct be_sge *sge;
        struct be_dma_mem cmd;
        int status;
 
@@ -2244,18 +2100,10 @@ int be_cmd_get_phy_info(struct be_adapter *adapter,
        }
 
        req = cmd.va;
-       sge = nonembedded_sgl(wrb);
-
-       be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
-                               OPCODE_COMMON_GET_PHY_DETAILS);
 
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-                       OPCODE_COMMON_GET_PHY_DETAILS,
-                       sizeof(*req));
-
-       sge->pa_hi = cpu_to_le32(upper_32_bits(cmd.dma));
-       sge->pa_lo = cpu_to_le32(cmd.dma & 0xFFFFFFFF);
-       sge->len = cpu_to_le32(cmd.size);
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                       OPCODE_COMMON_GET_PHY_DETAILS, sizeof(*req),
+                       wrb, &cmd);
 
        status = be_mcc_notify_wait(adapter);
        if (!status) {
@@ -2288,11 +2136,8 @@ int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain)
 
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-                               OPCODE_COMMON_SET_QOS);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-                       OPCODE_COMMON_SET_QOS, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                       OPCODE_COMMON_SET_QOS, sizeof(*req), wrb, NULL);
 
        req->hdr.domain = domain;
        req->valid_bits = cpu_to_le32(BE_QOS_BITS_NIC);
@@ -2310,7 +2155,6 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter)
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_cntl_attribs *req;
        struct be_cmd_resp_cntl_attribs *resp;
-       struct be_sge *sge;
        int status;
        int payload_len = max(sizeof(*req), sizeof(*resp));
        struct mgmt_controller_attrib *attribs;
@@ -2335,15 +2179,10 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter)
                goto err;
        }
        req = attribs_cmd.va;
-       sge = nonembedded_sgl(wrb);
 
-       be_wrb_hdr_prepare(wrb, payload_len, false, 1,
-                       OPCODE_COMMON_GET_CNTL_ATTRIBUTES);
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-                        OPCODE_COMMON_GET_CNTL_ATTRIBUTES, payload_len);
-       sge->pa_hi = cpu_to_le32(upper_32_bits(attribs_cmd.dma));
-       sge->pa_lo = cpu_to_le32(attribs_cmd.dma & 0xFFFFFFFF);
-       sge->len = cpu_to_le32(attribs_cmd.size);
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                        OPCODE_COMMON_GET_CNTL_ATTRIBUTES, payload_len, wrb,
+                       &attribs_cmd);
 
        status = be_mbox_notify_wait(adapter);
        if (!status) {
@@ -2376,11 +2215,8 @@ int be_cmd_req_native_mode(struct be_adapter *adapter)
 
        req = embedded_payload(wrb);
 
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
-               OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP);
-
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-               OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP, sizeof(*req));
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP, sizeof(*req), wrb, NULL);
 
        req->valid_cap_flags = cpu_to_le32(CAPABILITY_SW_TIMESTAMPS |
                                CAPABILITY_BE3_NATIVE_ERX_API);
index d6a232a..2180497 100644 (file)
@@ -229,27 +229,29 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
        struct be_adapter *adapter = netdev_priv(netdev);
        struct sockaddr *addr = p;
        int status = 0;
+       u8 current_mac[ETH_ALEN];
+       u32 pmac_id = adapter->pmac_id;
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
-       /* MAC addr configuration will be done in hardware for VFs
-        * by their corresponding PFs. Just copy to netdev addr here
-        */
-       if (!be_physfn(adapter))
-               goto netdev_addr;
-
-       status = be_cmd_pmac_del(adapter, adapter->if_handle,
-                               adapter->pmac_id, 0);
+       status = be_cmd_mac_addr_query(adapter, current_mac,
+                       MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle);
        if (status)
-               return status;
+               goto err;
 
-       status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data,
+       if (memcmp(addr->sa_data, current_mac, ETH_ALEN)) {
+               status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data,
                                adapter->if_handle, &adapter->pmac_id, 0);
-netdev_addr:
-       if (!status)
-               memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+               if (status)
+                       goto err;
 
+               be_cmd_pmac_del(adapter, adapter->if_handle, pmac_id, 0);
+       }
+       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+       return 0;
+err:
+       dev_err(&adapter->pdev->dev, "MAC %pM set Failed\n", addr->sa_data);
        return status;
 }
 
index 2be4698..ca1ae98 100644 (file)
@@ -85,7 +85,7 @@ config APRICOT
 
 config BVME6000_NET
        tristate "BVME6000 Ethernet support"
-       depends on BVME6000MVME16x
+       depends on BVME6000
        ---help---
          This is the driver for the Ethernet interface on BVME4000 and
          BVME6000 VME boards.  Say Y here to include the driver for this chip
index 2fd1ba8..7ed53db 100644 (file)
@@ -36,8 +36,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 24
-#define QLCNIC_LINUX_VERSIONID  "5.0.24"
+#define _QLCNIC_LINUX_SUBVERSION 25
+#define QLCNIC_LINUX_VERSIONID  "5.0.25"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
                 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
index 5d8bec2..8aa1c6e 100644 (file)
@@ -935,31 +935,49 @@ static int qlcnic_set_led(struct net_device *dev,
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        int max_sds_rings = adapter->max_sds_rings;
+       int err = -EIO, active = 1;
+
+       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+               netdev_warn(dev, "LED test not supported for non "
+                               "privilege function\n");
+               return -EOPNOTSUPP;
+       }
 
        switch (state) {
        case ETHTOOL_ID_ACTIVE:
                if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
                        return -EBUSY;
 
-               if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
-                       if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
-                               return -EIO;
+               if (test_bit(__QLCNIC_RESETTING, &adapter->state))
+                       break;
 
-                       if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST)) {
-                               clear_bit(__QLCNIC_RESETTING, &adapter->state);
-                               return -EIO;
-                       }
+               if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+                       if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
+                               break;
                        set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
                }
 
-               if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0)
-                       return 0;
+               if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) {
+                       err = 0;
+                       break;
+               }
 
                dev_err(&adapter->pdev->dev,
                        "Failed to set LED blink state.\n");
                break;
 
        case ETHTOOL_ID_INACTIVE:
+               active = 0;
+
+               if (test_bit(__QLCNIC_RESETTING, &adapter->state))
+                       break;
+
+               if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+                       if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
+                               break;
+                       set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
+               }
+
                if (adapter->nic_ops->config_led(adapter, 0, 0xf))
                        dev_err(&adapter->pdev->dev,
                                "Failed to reset LED blink state.\n");
@@ -970,14 +988,13 @@ static int qlcnic_set_led(struct net_device *dev,
                return -EINVAL;
        }
 
-       if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) {
+       if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
                qlcnic_diag_free_res(dev, max_sds_rings);
-               clear_bit(__QLCNIC_RESETTING, &adapter->state);
-       }
 
-       clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+       if (!active || err)
+               clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
 
-       return -EIO;
+       return err;
 }
 
 static void
index 92bc8ce..a528193 100644 (file)
@@ -407,7 +407,9 @@ enum {
 #define QLCNIC_CRB_SRE         QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SRE)
 #define QLCNIC_CRB_ROMUSB      \
        QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_ROMUSB)
+#define QLCNIC_CRB_EPG         QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_EG)
 #define QLCNIC_CRB_I2Q         QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_I2Q)
+#define QLCNIC_CRB_TIMER       QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_TIMR)
 #define QLCNIC_CRB_I2C0        QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_I2C0)
 #define QLCNIC_CRB_SMB         QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SMB)
 #define QLCNIC_CRB_MAX         QLCNIC_PCI_CRB_WINDOW(64)
index 74e9d7b..bcb81e4 100644 (file)
@@ -566,7 +566,7 @@ int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
                return -EIO;
 
        if (qlcnic_nic_set_promisc(adapter, VPORT_MISS_MODE_ACCEPT_ALL)) {
-               qlcnic_set_fw_loopback(adapter, mode);
+               qlcnic_set_fw_loopback(adapter, 0);
                return -EIO;
        }
 
index 312c1c3..3866958 100644 (file)
@@ -422,9 +422,53 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
        QLCWR32(adapter, CRB_RCVPEG_STATE, 0);
 
-       qlcnic_rom_lock(adapter);
-       QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xfeffffff);
+       /* Halt all the indiviual PEGs and other blocks */
+       /* disable all I2Q */
+       QLCWR32(adapter, QLCNIC_CRB_I2Q + 0x10, 0x0);
+       QLCWR32(adapter, QLCNIC_CRB_I2Q + 0x14, 0x0);
+       QLCWR32(adapter, QLCNIC_CRB_I2Q + 0x18, 0x0);
+       QLCWR32(adapter, QLCNIC_CRB_I2Q + 0x1c, 0x0);
+       QLCWR32(adapter, QLCNIC_CRB_I2Q + 0x20, 0x0);
+       QLCWR32(adapter, QLCNIC_CRB_I2Q + 0x24, 0x0);
+
+       /* disable all niu interrupts */
+       QLCWR32(adapter, QLCNIC_CRB_NIU + 0x40, 0xff);
+       /* disable xge rx/tx */
+       QLCWR32(adapter, QLCNIC_CRB_NIU + 0x70000, 0x00);
+       /* disable xg1 rx/tx */
+       QLCWR32(adapter, QLCNIC_CRB_NIU + 0x80000, 0x00);
+       /* disable sideband mac */
+       QLCWR32(adapter, QLCNIC_CRB_NIU + 0x90000, 0x00);
+       /* disable ap0 mac */
+       QLCWR32(adapter, QLCNIC_CRB_NIU + 0xa0000, 0x00);
+       /* disable ap1 mac */
+       QLCWR32(adapter, QLCNIC_CRB_NIU + 0xb0000, 0x00);
+
+       /* halt sre */
+       val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000);
+       QLCWR32(adapter, QLCNIC_CRB_SRE + 0x1000, val & (~(0x1)));
+
+       /* halt epg */
+       QLCWR32(adapter, QLCNIC_CRB_EPG + 0x1300, 0x1);
+
+       /* halt timers */
+       QLCWR32(adapter, QLCNIC_CRB_TIMER + 0x0, 0x0);
+       QLCWR32(adapter, QLCNIC_CRB_TIMER + 0x8, 0x0);
+       QLCWR32(adapter, QLCNIC_CRB_TIMER + 0x10, 0x0);
+       QLCWR32(adapter, QLCNIC_CRB_TIMER + 0x18, 0x0);
+       QLCWR32(adapter, QLCNIC_CRB_TIMER + 0x100, 0x0);
+       QLCWR32(adapter, QLCNIC_CRB_TIMER + 0x200, 0x0);
+       /* halt pegs */
+       QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c, 1);
+       QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c, 1);
+       QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c, 1);
+       QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c, 1);
+       QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c, 1);
+       msleep(20);
+
        qlcnic_rom_unlock(adapter);
+       /* big hammer don't reset CAM block on reset */
+       QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xfeffffff);
 
        /* Init HW CRB block */
        if (qlcnic_rom_fast_read(adapter, 0, &n) != 0 || (n != 0xcafecafe) ||
@@ -522,8 +566,10 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x8, 0);
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0xc, 0);
        msleep(1);
+
        QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
        QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
+
        return 0;
 }
 
index 106503f..0bd1638 100644 (file)
@@ -2840,8 +2840,15 @@ qlcnic_fwinit_work(struct work_struct *work)
                goto wait_npar;
        }
 
+       if (dev_state == QLCNIC_DEV_INITIALIZING ||
+           dev_state == QLCNIC_DEV_READY) {
+               dev_info(&adapter->pdev->dev, "Detected state change from "
+                               "DEV_NEED_RESET, skipping ack check\n");
+               goto skip_ack_check;
+       }
+
        if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
-               dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
+               dev_info(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
                                        adapter->reset_ack_timeo);
                goto skip_ack_check;
        }
@@ -3497,11 +3504,16 @@ qlcnic_store_beacon(struct device *dev,
 {
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
        int max_sds_rings = adapter->max_sds_rings;
-       int dev_down = 0;
        u16 beacon;
        u8 b_state, b_rate;
        int err;
 
+       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+               dev_warn(dev, "LED test not supported for non "
+                               "privilege function\n");
+               return -EOPNOTSUPP;
+       }
+
        if (len != sizeof(u16))
                return QL_STATUS_INVALID_PARAM;
 
@@ -3513,36 +3525,40 @@ qlcnic_store_beacon(struct device *dev,
        if (adapter->ahw->beacon_state == b_state)
                return len;
 
+       rtnl_lock();
+
        if (!adapter->ahw->beacon_state)
-               if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
+               if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) {
+                       rtnl_unlock();
                        return -EBUSY;
+               }
+
+       if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+               err = -EIO;
+               goto out;
+       }
 
        if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
-               if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
-                       return -EIO;
                err = qlcnic_diag_alloc_res(adapter->netdev, QLCNIC_LED_TEST);
-               if (err) {
-                       clear_bit(__QLCNIC_RESETTING, &adapter->state);
-                       clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
-                       return err;
-               }
-               dev_down = 1;
+               if (err)
+                       goto out;
+               set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
        }
 
        err = qlcnic_config_led(adapter, b_state, b_rate);
 
        if (!err) {
-               adapter->ahw->beacon_state = b_state;
                err = len;
+               adapter->ahw->beacon_state = b_state;
        }
 
-       if (dev_down) {
+       if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
                qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
-               clear_bit(__QLCNIC_RESETTING, &adapter->state);
-       }
 
-       if (!b_state)
+ out:
+       if (!adapter->ahw->beacon_state)
                clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+       rtnl_unlock();
 
        return err;
 }
index 9100c10..2cc1192 100644 (file)
@@ -49,7 +49,7 @@ struct stmmac_extra_stats {
        unsigned long tx_underflow ____cacheline_aligned;
        unsigned long tx_carrier;
        unsigned long tx_losscarrier;
-       unsigned long tx_heartbeat;
+       unsigned long vlan_tag;
        unsigned long tx_deferred;
        unsigned long tx_vlan;
        unsigned long tx_jabber;
@@ -58,9 +58,9 @@ struct stmmac_extra_stats {
        unsigned long tx_ip_header_error;
        /* Receive errors */
        unsigned long rx_desc;
-       unsigned long rx_partial;
-       unsigned long rx_runt;
-       unsigned long rx_toolong;
+       unsigned long sa_filter_fail;
+       unsigned long overflow_error;
+       unsigned long ipc_csum_error;
        unsigned long rx_collision;
        unsigned long rx_crc;
        unsigned long rx_length;
index 63a03e2..9820ec8 100644 (file)
@@ -25,33 +25,34 @@ struct dma_desc {
        union {
                struct {
                        /* RDES0 */
-                       u32 reserved1:1;
+                       u32 payload_csum_error:1;
                        u32 crc_error:1;
                        u32 dribbling:1;
                        u32 mii_error:1;
                        u32 receive_watchdog:1;
                        u32 frame_type:1;
                        u32 collision:1;
-                       u32 frame_too_long:1;
+                       u32 ipc_csum_error:1;
                        u32 last_descriptor:1;
                        u32 first_descriptor:1;
-                       u32 multicast_frame:1;
-                       u32 run_frame:1;
+                       u32 vlan_tag:1;
+                       u32 overflow_error:1;
                        u32 length_error:1;
-                       u32 partial_frame_error:1;
+                       u32 sa_filter_fail:1;
                        u32 descriptor_error:1;
                        u32 error_summary:1;
                        u32 frame_length:14;
-                       u32 filtering_fail:1;
+                       u32 da_filter_fail:1;
                        u32 own:1;
                        /* RDES1 */
                        u32 buffer1_size:11;
                        u32 buffer2_size:11;
-                       u32 reserved2:2;
+                       u32 reserved1:2;
                        u32 second_address_chained:1;
                        u32 end_ring:1;
-                       u32 reserved3:5;
+                       u32 reserved2:5;
                        u32 disable_ic:1;
+
                } rx;
                struct {
                        /* RDES0 */
@@ -91,24 +92,28 @@ struct dma_desc {
                        u32 underflow_error:1;
                        u32 excessive_deferral:1;
                        u32 collision_count:4;
-                       u32 heartbeat_fail:1;
+                       u32 vlan_frame:1;
                        u32 excessive_collisions:1;
                        u32 late_collision:1;
                        u32 no_carrier:1;
                        u32 loss_carrier:1;
-                       u32 reserved1:3;
+                       u32 payload_error:1;
+                       u32 frame_flushed:1;
+                       u32 jabber_timeout:1;
                        u32 error_summary:1;
-                       u32 reserved2:15;
+                       u32 ip_header_error:1;
+                       u32 time_stamp_status:1;
+                       u32 reserved1:13;
                        u32 own:1;
                        /* TDES1 */
                        u32 buffer1_size:11;
                        u32 buffer2_size:11;
-                       u32 reserved3:1;
+                       u32 time_stamp_enable:1;
                        u32 disable_padding:1;
                        u32 second_address_chained:1;
                        u32 end_ring:1;
                        u32 crc_disable:1;
-                       u32 reserved4:2;
+                       u32 checksum_insertion:2;
                        u32 first_segment:1;
                        u32 last_segment:1;
                        u32 interrupt:1;
index f7e8ba7..fda5d2b 100644 (file)
@@ -50,11 +50,12 @@ static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
                        stats->collisions += p->des01.tx.collision_count;
                ret = -1;
        }
-       if (unlikely(p->des01.tx.heartbeat_fail)) {
-               x->tx_heartbeat++;
-               stats->tx_heartbeat_errors++;
-               ret = -1;
+
+       if (p->des01.etx.vlan_frame) {
+               CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n");
+               x->tx_vlan++;
        }
+
        if (unlikely(p->des01.tx.deferred))
                x->tx_deferred++;
 
@@ -68,12 +69,12 @@ static int ndesc_get_tx_len(struct dma_desc *p)
 
 /* This function verifies if each incoming frame has some errors
  * and, if required, updates the multicast statistics.
- * In case of success, it returns csum_none because the device
- * is not able to compute the csum in HW. */
+ * In case of success, it returns good_frame because the GMAC device
+ * is supposed to be able to compute the csum in HW. */
 static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
                               struct dma_desc *p)
 {
-       int ret = csum_none;
+       int ret = good_frame;
        struct net_device_stats *stats = (struct net_device_stats *)data;
 
        if (unlikely(p->des01.rx.last_descriptor == 0)) {
@@ -86,12 +87,12 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
        if (unlikely(p->des01.rx.error_summary)) {
                if (unlikely(p->des01.rx.descriptor_error))
                        x->rx_desc++;
-               if (unlikely(p->des01.rx.partial_frame_error))
-                       x->rx_partial++;
-               if (unlikely(p->des01.rx.run_frame))
-                       x->rx_runt++;
-               if (unlikely(p->des01.rx.frame_too_long))
-                       x->rx_toolong++;
+               if (unlikely(p->des01.rx.sa_filter_fail))
+                       x->sa_filter_fail++;
+               if (unlikely(p->des01.rx.overflow_error))
+                       x->overflow_error++;
+               if (unlikely(p->des01.rx.ipc_csum_error))
+                       x->ipc_csum_error++;
                if (unlikely(p->des01.rx.collision)) {
                        x->rx_collision++;
                        stats->collisions++;
@@ -113,10 +114,10 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
                x->rx_mii++;
                ret = discard_frame;
        }
-       if (p->des01.rx.multicast_frame) {
-               x->rx_multicast++;
-               stats->multicast++;
-       }
+#ifdef STMMAC_VLAN_TAG_USED
+       if (p->des01.rx.vlan_tag)
+               x->vlan_tag++;
+#endif
        return ret;
 }
 
@@ -184,6 +185,9 @@ static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
 {
        p->des01.tx.first_segment = is_fs;
        norm_set_tx_desc_len(p, len);
+
+       if (likely(csum_flag))
+               p->des01.tx.checksum_insertion = cic_full;
 }
 
 static void ndesc_clear_tx_ic(struct dma_desc *p)
index 406404f..e8eff09 100644 (file)
@@ -50,7 +50,7 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
        STMMAC_STAT(tx_underflow),
        STMMAC_STAT(tx_carrier),
        STMMAC_STAT(tx_losscarrier),
-       STMMAC_STAT(tx_heartbeat),
+       STMMAC_STAT(vlan_tag),
        STMMAC_STAT(tx_deferred),
        STMMAC_STAT(tx_vlan),
        STMMAC_STAT(rx_vlan),
@@ -59,9 +59,9 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
        STMMAC_STAT(tx_payload_error),
        STMMAC_STAT(tx_ip_header_error),
        STMMAC_STAT(rx_desc),
-       STMMAC_STAT(rx_partial),
-       STMMAC_STAT(rx_runt),
-       STMMAC_STAT(rx_toolong),
+       STMMAC_STAT(sa_filter_fail),
+       STMMAC_STAT(overflow_error),
+       STMMAC_STAT(ipc_csum_error),
        STMMAC_STAT(rx_collision),
        STMMAC_STAT(rx_crc),
        STMMAC_STAT(rx_length),
index aeaa15b..20546bb 100644 (file)
@@ -325,7 +325,7 @@ static int stmmac_init_phy(struct net_device *dev)
            (interface == PHY_INTERFACE_MODE_RMII))) {
                phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
                                      SUPPORTED_Asym_Pause);
-               priv->phydev->advertising = priv->phydev->supported;
+               phydev->advertising = phydev->supported;
        }
 
        /*
@@ -812,9 +812,11 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
  */
 static int stmmac_get_hw_features(struct stmmac_priv *priv)
 {
-       u32 hw_cap = priv->hw->dma->get_hw_feature(priv->ioaddr);
+       u32 hw_cap = 0;
+
+       if (priv->hw->dma->get_hw_feature) {
+               hw_cap = priv->hw->dma->get_hw_feature(priv->ioaddr);
 
-       if (likely(hw_cap)) {
                priv->dma_cap.mbps_10_100 = (hw_cap & DMA_HW_FEAT_MIISEL);
                priv->dma_cap.mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1;
                priv->dma_cap.half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2;
@@ -937,6 +939,7 @@ static int stmmac_open(struct net_device *dev)
 
        stmmac_get_hw_features(priv);
 
+       priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr);
        if (priv->rx_coe)
                pr_info("stmmac: Rx Checksum Offload Engine supported\n");
        if (priv->plat->tx_coe)
@@ -1274,8 +1277,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 #endif
                        skb->protocol = eth_type_trans(skb, priv->dev);
 
-                       if (unlikely(status == csum_none)) {
-                               /* always for the old mac 10/100 */
+                       if (unlikely(!priv->rx_coe)) {
+                               /* No RX COE for old mac10/100 devices */
                                skb_checksum_none_assert(skb);
                                netif_receive_skb(skb);
                        } else {
index 10cf250..f4e3d82 100644 (file)
@@ -61,15 +61,18 @@ config ASUS_LAPTOP
        depends on INPUT
        depends on RFKILL || RFKILL = n
        select INPUT_SPARSEKMAP
+       select INPUT_POLLDEV
        ---help---
-         This is the new Linux driver for Asus laptops. It may also support some
-         MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
-         standard ACPI events and input events. It also adds
-         support for video output switching, LCD backlight control, Bluetooth and
-         Wlan control, and most importantly, allows you to blink those fancy LEDs.
+         This is a driver for Asus laptops, Lenovo SL and the Pegatron
+         Lucid tablet. It may also support some MEDION, JVC or VICTOR
+         laptops. It makes all the extra buttons generate standard
+         ACPI events and input events, and on the Lucid the built-in
+         accelerometer appears as an input device.  It also adds
+         support for video output switching, LCD backlight control,
+         Bluetooth and Wlan control, and most importantly, allows you
+         to blink those fancy LEDs.
 
-         For more information and a userspace daemon for handling the extra
-         buttons see <http://acpi4asus.sf.net>.
+         For more information see <http://acpi4asus.sf.net>.
 
          If you have an ACPI-compatible ASUS laptop, say Y or M here.
 
index af2bb20..b848277 100644 (file)
@@ -190,6 +190,7 @@ enum interface_flags {
        ACER_AMW0,
        ACER_AMW0_V2,
        ACER_WMID,
+       ACER_WMID_v2,
 };
 
 #define ACER_DEFAULT_WIRELESS  0
@@ -205,6 +206,7 @@ static int threeg = -1;
 static int force_series;
 static bool ec_raw_mode;
 static bool has_type_aa;
+static u16 commun_func_bitmap;
 
 module_param(mailled, int, 0444);
 module_param(brightness, int, 0444);
@@ -464,6 +466,15 @@ static struct dmi_system_id acer_quirks[] = {
                },
                .driver_data = &quirk_lenovo_ideapad_s205,
        },
+       {
+               .callback = dmi_matched,
+               .ident = "Lenovo 3000 N200",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "0687A31"),
+               },
+               .driver_data = &quirk_fujitsu_amilo_li_1718,
+       },
        {}
 };
 
@@ -868,6 +879,174 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
        return WMI_execute_u32(method_id, (u32)value, NULL);
 }
 
+static acpi_status wmid3_get_device_status(u32 *value, u16 device)
+{
+       struct wmid3_gds_return_value return_value;
+       acpi_status status;
+       union acpi_object *obj;
+       struct wmid3_gds_input_param params = {
+               .function_num = 0x1,
+               .hotkey_number = 0x01,
+               .devices = device,
+       };
+       struct acpi_buffer input = {
+               sizeof(struct wmid3_gds_input_param),
+               &params
+       };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = output.pointer;
+
+       if (!obj)
+               return AE_ERROR;
+       else if (obj->type != ACPI_TYPE_BUFFER) {
+               kfree(obj);
+               return AE_ERROR;
+       }
+       if (obj->buffer.length != 8) {
+               pr_warn("Unknown buffer length %d\n", obj->buffer.length);
+               kfree(obj);
+               return AE_ERROR;
+       }
+
+       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
+       kfree(obj);
+
+       if (return_value.error_code || return_value.ec_return_value)
+               pr_warn("Get 0x%x Device Status failed: 0x%x - 0x%x\n",
+                       device,
+                       return_value.error_code,
+                       return_value.ec_return_value);
+       else
+               *value = !!(return_value.devices & device);
+
+       return status;
+}
+
+static acpi_status wmid_v2_get_u32(u32 *value, u32 cap)
+{
+       u16 device;
+
+       switch (cap) {
+       case ACER_CAP_WIRELESS:
+               device = ACER_WMID3_GDS_WIRELESS;
+               break;
+       case ACER_CAP_BLUETOOTH:
+               device = ACER_WMID3_GDS_BLUETOOTH;
+               break;
+       case ACER_CAP_THREEG:
+               device = ACER_WMID3_GDS_THREEG;
+               break;
+       default:
+               return AE_ERROR;
+       }
+       return wmid3_get_device_status(value, device);
+}
+
+static acpi_status wmid3_set_device_status(u32 value, u16 device)
+{
+       struct wmid3_gds_return_value return_value;
+       acpi_status status;
+       union acpi_object *obj;
+       u16 devices;
+       struct wmid3_gds_input_param params = {
+               .function_num = 0x1,
+               .hotkey_number = 0x01,
+               .devices = commun_func_bitmap,
+       };
+       struct acpi_buffer input = {
+               sizeof(struct wmid3_gds_input_param),
+               &params
+       };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
+
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = output.pointer;
+
+       if (!obj)
+               return AE_ERROR;
+       else if (obj->type != ACPI_TYPE_BUFFER) {
+               kfree(obj);
+               return AE_ERROR;
+       }
+       if (obj->buffer.length != 8) {
+               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+               kfree(obj);
+               return AE_ERROR;
+       }
+
+       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
+       kfree(obj);
+
+       if (return_value.error_code || return_value.ec_return_value) {
+               pr_warning("Get Current Device Status failed: "
+                       "0x%x - 0x%x\n", return_value.error_code,
+                       return_value.ec_return_value);
+               return status;
+       }
+
+       devices = return_value.devices;
+       params.function_num = 0x2;
+       params.hotkey_number = 0x01;
+       params.devices = (value) ? (devices | device) : (devices & ~device);
+
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = output2.pointer;
+
+       if (!obj)
+               return AE_ERROR;
+       else if (obj->type != ACPI_TYPE_BUFFER) {
+               kfree(obj);
+               return AE_ERROR;
+       }
+       if (obj->buffer.length != 4) {
+               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+               kfree(obj);
+               return AE_ERROR;
+       }
+
+       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
+       kfree(obj);
+
+       if (return_value.error_code || return_value.ec_return_value)
+               pr_warning("Set Device Status failed: "
+                       "0x%x - 0x%x\n", return_value.error_code,
+                       return_value.ec_return_value);
+
+       return status;
+}
+
+static acpi_status wmid_v2_set_u32(u32 value, u32 cap)
+{
+       u16 device;
+
+       switch (cap) {
+       case ACER_CAP_WIRELESS:
+               device = ACER_WMID3_GDS_WIRELESS;
+               break;
+       case ACER_CAP_BLUETOOTH:
+               device = ACER_WMID3_GDS_BLUETOOTH;
+               break;
+       case ACER_CAP_THREEG:
+               device = ACER_WMID3_GDS_THREEG;
+               break;
+       default:
+               return AE_ERROR;
+       }
+       return wmid3_set_device_status(value, device);
+}
+
 static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
 {
        struct hotkey_function_type_aa *type_aa;
@@ -881,6 +1060,7 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
 
        pr_info("Function bitmap for Communication Button: 0x%x\n",
                type_aa->commun_func_bitmap);
+       commun_func_bitmap = type_aa->commun_func_bitmap;
 
        if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
                interface->capability |= ACER_CAP_WIRELESS;
@@ -913,17 +1093,13 @@ static acpi_status WMID_set_capabilities(void)
                return AE_ERROR;
        }
 
-       dmi_walk(type_aa_dmi_decode, NULL);
-       if (!has_type_aa) {
+       pr_info("Function bitmap for Communication Device: 0x%x\n", devices);
+       if (devices & 0x07)
                interface->capability |= ACER_CAP_WIRELESS;
-               if (devices & 0x40)
-                       interface->capability |= ACER_CAP_THREEG;
-               if (devices & 0x10)
-                       interface->capability |= ACER_CAP_BLUETOOTH;
-       }
-
-       /* WMID always provides brightness methods */
-       interface->capability |= ACER_CAP_BRIGHTNESS;
+       if (devices & 0x40)
+               interface->capability |= ACER_CAP_THREEG;
+       if (devices & 0x10)
+               interface->capability |= ACER_CAP_BLUETOOTH;
 
        if (!(devices & 0x20))
                max_brightness = 0x9;
@@ -936,6 +1112,10 @@ static struct wmi_interface wmid_interface = {
        .type = ACER_WMID,
 };
 
+static struct wmi_interface wmid_v2_interface = {
+       .type = ACER_WMID_v2,
+};
+
 /*
  * Generic Device (interface-independent)
  */
@@ -956,6 +1136,14 @@ static acpi_status get_u32(u32 *value, u32 cap)
        case ACER_WMID:
                status = WMID_get_u32(value, cap, interface);
                break;
+       case ACER_WMID_v2:
+               if (cap & (ACER_CAP_WIRELESS |
+                          ACER_CAP_BLUETOOTH |
+                          ACER_CAP_THREEG))
+                       status = wmid_v2_get_u32(value, cap);
+               else if (wmi_has_guid(WMID_GUID2))
+                       status = WMID_get_u32(value, cap, interface);
+               break;
        }
 
        return status;
@@ -989,6 +1177,13 @@ static acpi_status set_u32(u32 value, u32 cap)
                        }
                case ACER_WMID:
                        return WMID_set_u32(value, cap, interface);
+               case ACER_WMID_v2:
+                       if (cap & (ACER_CAP_WIRELESS |
+                                  ACER_CAP_BLUETOOTH |
+                                  ACER_CAP_THREEG))
+                               return wmid_v2_set_u32(value, cap);
+                       else if (wmi_has_guid(WMID_GUID2))
+                               return WMID_set_u32(value, cap, interface);
                default:
                        return AE_BAD_PARAMETER;
                }
@@ -1095,186 +1290,6 @@ static void acer_backlight_exit(void)
        backlight_device_unregister(acer_backlight_device);
 }
 
-static acpi_status wmid3_get_device_status(u32 *value, u16 device)
-{
-       struct wmid3_gds_return_value return_value;
-       acpi_status status;
-       union acpi_object *obj;
-       struct wmid3_gds_input_param params = {
-               .function_num = 0x1,
-               .hotkey_number = 0x01,
-               .devices = device,
-       };
-       struct acpi_buffer input = {
-               sizeof(struct wmid3_gds_input_param),
-               &params
-       };
-       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
-
-       status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
-       if (ACPI_FAILURE(status))
-               return status;
-
-       obj = output.pointer;
-
-       if (!obj)
-               return AE_ERROR;
-       else if (obj->type != ACPI_TYPE_BUFFER) {
-               kfree(obj);
-               return AE_ERROR;
-       }
-       if (obj->buffer.length != 8) {
-               pr_warn("Unknown buffer length %d\n", obj->buffer.length);
-               kfree(obj);
-               return AE_ERROR;
-       }
-
-       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
-       kfree(obj);
-
-       if (return_value.error_code || return_value.ec_return_value)
-               pr_warn("Get Device Status failed: 0x%x - 0x%x\n",
-                       return_value.error_code,
-                       return_value.ec_return_value);
-       else
-               *value = !!(return_value.devices & device);
-
-       return status;
-}
-
-static acpi_status get_device_status(u32 *value, u32 cap)
-{
-       if (wmi_has_guid(WMID_GUID3)) {
-               u16 device;
-
-               switch (cap) {
-               case ACER_CAP_WIRELESS:
-                       device = ACER_WMID3_GDS_WIRELESS;
-                       break;
-               case ACER_CAP_BLUETOOTH:
-                       device = ACER_WMID3_GDS_BLUETOOTH;
-                       break;
-               case ACER_CAP_THREEG:
-                       device = ACER_WMID3_GDS_THREEG;
-                       break;
-               default:
-                       return AE_ERROR;
-               }
-               return wmid3_get_device_status(value, device);
-
-       } else {
-               return get_u32(value, cap);
-       }
-}
-
-static acpi_status wmid3_set_device_status(u32 value, u16 device)
-{
-       struct wmid3_gds_return_value return_value;
-       acpi_status status;
-       union acpi_object *obj;
-       u16 devices;
-       struct wmid3_gds_input_param params = {
-               .function_num = 0x1,
-               .hotkey_number = 0x01,
-               .devices = ACER_WMID3_GDS_WIRELESS |
-                               ACER_WMID3_GDS_THREEG |
-                               ACER_WMID3_GDS_WIMAX |
-                               ACER_WMID3_GDS_BLUETOOTH,
-       };
-       struct acpi_buffer input = {
-               sizeof(struct wmid3_gds_input_param),
-               &params
-       };
-       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
-
-       status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
-       if (ACPI_FAILURE(status))
-               return status;
-
-       obj = output.pointer;
-
-       if (!obj)
-               return AE_ERROR;
-       else if (obj->type != ACPI_TYPE_BUFFER) {
-               kfree(obj);
-               return AE_ERROR;
-       }
-       if (obj->buffer.length != 8) {
-               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
-               kfree(obj);
-               return AE_ERROR;
-       }
-
-       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
-       kfree(obj);
-
-       if (return_value.error_code || return_value.ec_return_value) {
-               pr_warning("Get Current Device Status failed: "
-                       "0x%x - 0x%x\n", return_value.error_code,
-                       return_value.ec_return_value);
-               return status;
-       }
-
-       devices = return_value.devices;
-       params.function_num = 0x2;
-       params.hotkey_number = 0x01;
-       params.devices = (value) ? (devices | device) : (devices & ~device);
-
-       status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2);
-       if (ACPI_FAILURE(status))
-               return status;
-
-       obj = output2.pointer;
-
-       if (!obj)
-               return AE_ERROR;
-       else if (obj->type != ACPI_TYPE_BUFFER) {
-               kfree(obj);
-               return AE_ERROR;
-       }
-       if (obj->buffer.length != 4) {
-               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
-               kfree(obj);
-               return AE_ERROR;
-       }
-
-       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
-       kfree(obj);
-
-       if (return_value.error_code || return_value.ec_return_value)
-               pr_warning("Set Device Status failed: "
-                       "0x%x - 0x%x\n", return_value.error_code,
-                       return_value.ec_return_value);
-
-       return status;
-}
-
-static acpi_status set_device_status(u32 value, u32 cap)
-{
-       if (wmi_has_guid(WMID_GUID3)) {
-               u16 device;
-
-               switch (cap) {
-               case ACER_CAP_WIRELESS:
-                       device = ACER_WMID3_GDS_WIRELESS;
-                       break;
-               case ACER_CAP_BLUETOOTH:
-                       device = ACER_WMID3_GDS_BLUETOOTH;
-                       break;
-               case ACER_CAP_THREEG:
-                       device = ACER_WMID3_GDS_THREEG;
-                       break;
-               default:
-                       return AE_ERROR;
-               }
-               return wmid3_set_device_status(value, device);
-
-       } else {
-               return set_u32(value, cap);
-       }
-}
-
 /*
  * Rfkill devices
  */
@@ -1285,12 +1300,13 @@ static void acer_rfkill_update(struct work_struct *ignored)
        u32 state;
        acpi_status status;
 
-       status = get_u32(&state, ACER_CAP_WIRELESS);
-       if (ACPI_SUCCESS(status)) {
-               if (quirks->wireless == 3) {
-                       rfkill_set_hw_state(wireless_rfkill, !state);
-               } else {
-                       rfkill_set_sw_state(wireless_rfkill, !state);
+       if (has_cap(ACER_CAP_WIRELESS)) {
+               status = get_u32(&state, ACER_CAP_WIRELESS);
+               if (ACPI_SUCCESS(status)) {
+                       if (quirks->wireless == 3)
+                               rfkill_set_hw_state(wireless_rfkill, !state);
+                       else
+                               rfkill_set_sw_state(wireless_rfkill, !state);
                }
        }
 
@@ -1301,8 +1317,7 @@ static void acer_rfkill_update(struct work_struct *ignored)
        }
 
        if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
-               status = wmid3_get_device_status(&state,
-                               ACER_WMID3_GDS_THREEG);
+               status = get_u32(&state, ACER_WMID3_GDS_THREEG);
                if (ACPI_SUCCESS(status))
                        rfkill_set_sw_state(threeg_rfkill, !state);
        }
@@ -1316,7 +1331,7 @@ static int acer_rfkill_set(void *data, bool blocked)
        u32 cap = (unsigned long)data;
 
        if (rfkill_inited) {
-               status = set_device_status(!blocked, cap);
+               status = set_u32(!blocked, cap);
                if (ACPI_FAILURE(status))
                        return -ENODEV;
        }
@@ -1343,7 +1358,7 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
        if (!rfkill_dev)
                return ERR_PTR(-ENOMEM);
 
-       status = get_device_status(&state, cap);
+       status = get_u32(&state, cap);
 
        err = rfkill_register(rfkill_dev);
        if (err) {
@@ -1359,19 +1374,24 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
 
 static int acer_rfkill_init(struct device *dev)
 {
-       wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
-               "acer-wireless", ACER_CAP_WIRELESS);
-       if (IS_ERR(wireless_rfkill))
-               return PTR_ERR(wireless_rfkill);
+       int err;
+
+       if (has_cap(ACER_CAP_WIRELESS)) {
+               wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
+                       "acer-wireless", ACER_CAP_WIRELESS);
+               if (IS_ERR(wireless_rfkill)) {
+                       err = PTR_ERR(wireless_rfkill);
+                       goto error_wireless;
+               }
+       }
 
        if (has_cap(ACER_CAP_BLUETOOTH)) {
                bluetooth_rfkill = acer_rfkill_register(dev,
                        RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
                        ACER_CAP_BLUETOOTH);
                if (IS_ERR(bluetooth_rfkill)) {
-                       rfkill_unregister(wireless_rfkill);
-                       rfkill_destroy(wireless_rfkill);
-                       return PTR_ERR(bluetooth_rfkill);
+                       err = PTR_ERR(bluetooth_rfkill);
+                       goto error_bluetooth;
                }
        }
 
@@ -1380,30 +1400,44 @@ static int acer_rfkill_init(struct device *dev)
                        RFKILL_TYPE_WWAN, "acer-threeg",
                        ACER_CAP_THREEG);
                if (IS_ERR(threeg_rfkill)) {
-                       rfkill_unregister(wireless_rfkill);
-                       rfkill_destroy(wireless_rfkill);
-                       rfkill_unregister(bluetooth_rfkill);
-                       rfkill_destroy(bluetooth_rfkill);
-                       return PTR_ERR(threeg_rfkill);
+                       err = PTR_ERR(threeg_rfkill);
+                       goto error_threeg;
                }
        }
 
        rfkill_inited = true;
 
-       if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID))
+       if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
+           has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
                schedule_delayed_work(&acer_rfkill_work,
                        round_jiffies_relative(HZ));
 
        return 0;
+
+error_threeg:
+       if (has_cap(ACER_CAP_BLUETOOTH)) {
+               rfkill_unregister(bluetooth_rfkill);
+               rfkill_destroy(bluetooth_rfkill);
+       }
+error_bluetooth:
+       if (has_cap(ACER_CAP_WIRELESS)) {
+               rfkill_unregister(wireless_rfkill);
+               rfkill_destroy(wireless_rfkill);
+       }
+error_wireless:
+       return err;
 }
 
 static void acer_rfkill_exit(void)
 {
-       if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID))
+       if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
+           has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
                cancel_delayed_work_sync(&acer_rfkill_work);
 
-       rfkill_unregister(wireless_rfkill);
-       rfkill_destroy(wireless_rfkill);
+       if (has_cap(ACER_CAP_WIRELESS)) {
+               rfkill_unregister(wireless_rfkill);
+               rfkill_destroy(wireless_rfkill);
+       }
 
        if (has_cap(ACER_CAP_BLUETOOTH)) {
                rfkill_unregister(bluetooth_rfkill);
@@ -1428,11 +1462,7 @@ static ssize_t show_bool_threeg(struct device *dev,
 
        pr_info("This threeg sysfs will be removed in 2012"
                " - used by: %s\n", current->comm);
-       if (wmi_has_guid(WMID_GUID3))
-               status = wmid3_get_device_status(&result,
-                               ACER_WMID3_GDS_THREEG);
-       else
-               status = get_u32(&result, ACER_CAP_THREEG);
+       status = get_u32(&result, ACER_CAP_THREEG);
        if (ACPI_SUCCESS(status))
                return sprintf(buf, "%u\n", result);
        return sprintf(buf, "Read error\n");
@@ -1464,6 +1494,8 @@ static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
                return sprintf(buf, "AMW0 v2\n");
        case ACER_WMID:
                return sprintf(buf, "WMID\n");
+       case ACER_WMID_v2:
+               return sprintf(buf, "WMID v2\n");
        default:
                return sprintf(buf, "Error!\n");
        }
@@ -1883,12 +1915,20 @@ static int __init acer_wmi_init(void)
        if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
                interface = &wmid_interface;
 
+       if (wmi_has_guid(WMID_GUID3))
+               interface = &wmid_v2_interface;
+
+       if (interface)
+               dmi_walk(type_aa_dmi_decode, NULL);
+
        if (wmi_has_guid(WMID_GUID2) && interface) {
-               if (ACPI_FAILURE(WMID_set_capabilities())) {
+               if (!has_type_aa && ACPI_FAILURE(WMID_set_capabilities())) {
                        pr_err("Unable to detect available WMID devices\n");
                        return -ENODEV;
                }
-       } else if (!wmi_has_guid(WMID_GUID2) && interface) {
+               /* WMID always provides brightness methods */
+               interface->capability |= ACER_CAP_BRIGHTNESS;
+       } else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa) {
                pr_err("No WMID device detection method found\n");
                return -ENODEV;
        }
@@ -1912,7 +1952,7 @@ static int __init acer_wmi_init(void)
 
        set_quirks();
 
-       if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) {
+       if (acpi_video_backlight_support()) {
                interface->capability &= ~ACER_CAP_BRIGHTNESS;
                pr_info("Brightness must be controlled by "
                       "generic video driver\n");
index fa6d7ec..edaccad 100644 (file)
@@ -4,6 +4,7 @@
  *
  *  Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
  *  Copyright (C) 2006-2007 Corentin Chary
+ *  Copyright (C) 2011 Wind River Systems
  *
  *  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
@@ -48,6 +49,7 @@
 #include <linux/uaccess.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
+#include <linux/input-polldev.h>
 #include <linux/rfkill.h>
 #include <linux/slab.h>
 #include <linux/dmi.h>
@@ -83,26 +85,32 @@ static int wlan_status = 1;
 static int bluetooth_status = 1;
 static int wimax_status = -1;
 static int wwan_status = -1;
+static int als_status;
 
 module_param(wlan_status, int, 0444);
 MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot "
                 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
-                "default is 1");
+                "default is -1");
 
 module_param(bluetooth_status, int, 0444);
 MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
                 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
-                "default is 1");
+                "default is -1");
 
 module_param(wimax_status, int, 0444);
 MODULE_PARM_DESC(wimax_status, "Set the wireless status on boot "
                 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
-                "default is 1");
+                "default is -1");
 
 module_param(wwan_status, int, 0444);
 MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
                 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
-                "default is 1");
+                "default is -1");
+
+module_param(als_status, int, 0444);
+MODULE_PARM_DESC(als_status, "Set the ALS status on boot "
+                "(0 = disabled, 1 = enabled). "
+                "default is 0");
 
 /*
  * Some events we use, same for all Asus
@@ -173,6 +181,29 @@ MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
 #define METHOD_KBD_LIGHT_SET   "SLKB"
 #define METHOD_KBD_LIGHT_GET   "GLKB"
 
+/* For Pegatron Lucid tablet */
+#define DEVICE_NAME_PEGA       "Lucid"
+
+#define METHOD_PEGA_ENABLE     "ENPR"
+#define METHOD_PEGA_DISABLE    "DAPR"
+#define PEGA_WLAN      0x00
+#define PEGA_BLUETOOTH 0x01
+#define PEGA_WWAN      0x02
+#define PEGA_ALS       0x04
+#define PEGA_ALS_POWER 0x05
+
+#define METHOD_PEGA_READ       "RDLN"
+#define PEGA_READ_ALS_H        0x02
+#define PEGA_READ_ALS_L        0x03
+
+#define PEGA_ACCEL_NAME "pega_accel"
+#define PEGA_ACCEL_DESC "Pegatron Lucid Tablet Accelerometer"
+#define METHOD_XLRX "XLRX"
+#define METHOD_XLRY "XLRY"
+#define METHOD_XLRZ "XLRZ"
+#define PEGA_ACC_CLAMP 512 /* 1G accel is reported as ~256, so clamp to 2G */
+#define PEGA_ACC_RETRIES 3
+
 /*
  * Define a specific led structure to keep the main structure clean
  */
@@ -184,6 +215,15 @@ struct asus_led {
        const char *method;
 };
 
+/*
+ * Same thing for rfkill
+ */
+struct asus_pega_rfkill {
+       int control_id;         /* type of control. Maps to PEGA_* values */
+       struct rfkill *rfkill;
+       struct asus_laptop *asus;
+};
+
 /*
  * This is the main structure, we can use it to store anything interesting
  * about the hotk device
@@ -198,6 +238,7 @@ struct asus_laptop {
 
        struct input_dev *inputdev;
        struct key_entry *keymap;
+       struct input_polled_dev *pega_accel_poll;
 
        struct asus_led mled;
        struct asus_led tled;
@@ -209,9 +250,18 @@ struct asus_laptop {
 
        int wireless_status;
        bool have_rsts;
+       bool is_pega_lucid;
+       bool pega_acc_live;
+       int pega_acc_x;
+       int pega_acc_y;
+       int pega_acc_z;
 
        struct rfkill *gps_rfkill;
 
+       struct asus_pega_rfkill wlanrfk;
+       struct asus_pega_rfkill btrfk;
+       struct asus_pega_rfkill wwanrfk;
+
        acpi_handle handle;     /* the handle of the hotk device */
        u32 ledd_status;        /* status of the LED display */
        u8 light_level;         /* light sensor level */
@@ -323,6 +373,127 @@ static int acpi_check_handle(acpi_handle handle, const char *method,
        return 0;
 }
 
+static bool asus_check_pega_lucid(struct asus_laptop *asus)
+{
+       return !strcmp(asus->name, DEVICE_NAME_PEGA) &&
+          !acpi_check_handle(asus->handle, METHOD_PEGA_ENABLE, NULL) &&
+          !acpi_check_handle(asus->handle, METHOD_PEGA_DISABLE, NULL) &&
+          !acpi_check_handle(asus->handle, METHOD_PEGA_READ, NULL);
+}
+
+static int asus_pega_lucid_set(struct asus_laptop *asus, int unit, bool enable)
+{
+       char *method = enable ? METHOD_PEGA_ENABLE : METHOD_PEGA_DISABLE;
+       return write_acpi_int(asus->handle, method, unit);
+}
+
+static int pega_acc_axis(struct asus_laptop *asus, int curr, char *method)
+{
+       int i, delta;
+       unsigned long long val;
+       for (i = 0; i < PEGA_ACC_RETRIES; i++) {
+               acpi_evaluate_integer(asus->handle, method, NULL, &val);
+
+               /* The output is noisy.  From reading the ASL
+                * dissassembly, timeout errors are returned with 1's
+                * in the high word, and the lack of locking around
+                * thei hi/lo byte reads means that a transition
+                * between (for example) -1 and 0 could be read as
+                * 0xff00 or 0x00ff. */
+               delta = abs(curr - (short)val);
+               if (delta < 128 && !(val & ~0xffff))
+                       break;
+       }
+       return clamp_val((short)val, -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP);
+}
+
+static void pega_accel_poll(struct input_polled_dev *ipd)
+{
+       struct device *parent = ipd->input->dev.parent;
+       struct asus_laptop *asus = dev_get_drvdata(parent);
+
+       /* In some cases, the very first call to poll causes a
+        * recursive fault under the polldev worker.  This is
+        * apparently related to very early userspace access to the
+        * device, and perhaps a firmware bug. Fake the first report. */
+       if (!asus->pega_acc_live) {
+               asus->pega_acc_live = true;
+               input_report_abs(ipd->input, ABS_X, 0);
+               input_report_abs(ipd->input, ABS_Y, 0);
+               input_report_abs(ipd->input, ABS_Z, 0);
+               input_sync(ipd->input);
+               return;
+       }
+
+       asus->pega_acc_x = pega_acc_axis(asus, asus->pega_acc_x, METHOD_XLRX);
+       asus->pega_acc_y = pega_acc_axis(asus, asus->pega_acc_y, METHOD_XLRY);
+       asus->pega_acc_z = pega_acc_axis(asus, asus->pega_acc_z, METHOD_XLRZ);
+
+       /* Note transform, convert to "right/up/out" in the native
+        * landscape orientation (i.e. the vector is the direction of
+        * "real up" in the device's cartiesian coordinates). */
+       input_report_abs(ipd->input, ABS_X, -asus->pega_acc_x);
+       input_report_abs(ipd->input, ABS_Y, -asus->pega_acc_y);
+       input_report_abs(ipd->input, ABS_Z,  asus->pega_acc_z);
+       input_sync(ipd->input);
+}
+
+static void pega_accel_exit(struct asus_laptop *asus)
+{
+       if (asus->pega_accel_poll) {
+               input_unregister_polled_device(asus->pega_accel_poll);
+               input_free_polled_device(asus->pega_accel_poll);
+       }
+       asus->pega_accel_poll = NULL;
+}
+
+static int pega_accel_init(struct asus_laptop *asus)
+{
+       int err;
+       struct input_polled_dev *ipd;
+
+       if (!asus->is_pega_lucid)
+               return -ENODEV;
+
+       if (acpi_check_handle(asus->handle, METHOD_XLRX, NULL) ||
+           acpi_check_handle(asus->handle, METHOD_XLRY, NULL) ||
+           acpi_check_handle(asus->handle, METHOD_XLRZ, NULL))
+               return -ENODEV;
+
+       ipd = input_allocate_polled_device();
+       if (!ipd)
+               return -ENOMEM;
+
+       ipd->poll = pega_accel_poll;
+       ipd->poll_interval = 125;
+       ipd->poll_interval_min = 50;
+       ipd->poll_interval_max = 2000;
+
+       ipd->input->name = PEGA_ACCEL_DESC;
+       ipd->input->phys = PEGA_ACCEL_NAME "/input0";
+       ipd->input->dev.parent = &asus->platform_device->dev;
+       ipd->input->id.bustype = BUS_HOST;
+
+       set_bit(EV_ABS, ipd->input->evbit);
+       input_set_abs_params(ipd->input, ABS_X,
+                            -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
+       input_set_abs_params(ipd->input, ABS_Y,
+                            -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
+       input_set_abs_params(ipd->input, ABS_Z,
+                            -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
+
+       err = input_register_polled_device(ipd);
+       if (err)
+               goto exit;
+
+       asus->pega_accel_poll = ipd;
+       return 0;
+
+exit:
+       input_free_polled_device(ipd);
+       return err;
+}
+
 /* Generic LED function */
 static int asus_led_set(struct asus_laptop *asus, const char *method,
                         int value)
@@ -430,17 +601,17 @@ static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
 
 static void asus_led_exit(struct asus_laptop *asus)
 {
-       if (asus->mled.led.dev)
+       if (!IS_ERR_OR_NULL(asus->mled.led.dev))
                led_classdev_unregister(&asus->mled.led);
-       if (asus->tled.led.dev)
+       if (!IS_ERR_OR_NULL(asus->tled.led.dev))
                led_classdev_unregister(&asus->tled.led);
-       if (asus->pled.led.dev)
+       if (!IS_ERR_OR_NULL(asus->pled.led.dev))
                led_classdev_unregister(&asus->pled.led);
-       if (asus->rled.led.dev)
+       if (!IS_ERR_OR_NULL(asus->rled.led.dev))
                led_classdev_unregister(&asus->rled.led);
-       if (asus->gled.led.dev)
+       if (!IS_ERR_OR_NULL(asus->gled.led.dev))
                led_classdev_unregister(&asus->gled.led);
-       if (asus->kled.led.dev)
+       if (!IS_ERR_OR_NULL(asus->kled.led.dev))
                led_classdev_unregister(&asus->kled.led);
        if (asus->led_workqueue) {
                destroy_workqueue(asus->led_workqueue);
@@ -473,6 +644,13 @@ static int asus_led_init(struct asus_laptop *asus)
 {
        int r;
 
+       /*
+        * The Pegatron Lucid has no physical leds, but all methods are
+        * available in the DSDT...
+        */
+       if (asus->is_pega_lucid)
+               return 0;
+
        /*
         * Functions that actually update the LED's are called from a
         * workqueue. By doing this as separate work rather than when the LED
@@ -907,8 +1085,18 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
  */
 static void asus_als_switch(struct asus_laptop *asus, int value)
 {
-       if (write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value))
-               pr_warn("Error setting light sensor switch\n");
+       int ret;
+
+       if (asus->is_pega_lucid) {
+               ret = asus_pega_lucid_set(asus, PEGA_ALS, value);
+               if (!ret)
+                       ret = asus_pega_lucid_set(asus, PEGA_ALS_POWER, value);
+       } else {
+               ret = write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value);
+       }
+       if (ret)
+               pr_warning("Error setting light sensor switch\n");
+
        asus->light_switch = value;
 }
 
@@ -964,6 +1152,35 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
        return rv;
 }
 
+static int pega_int_read(struct asus_laptop *asus, int arg, int *result)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       int err = write_acpi_int_ret(asus->handle, METHOD_PEGA_READ, arg,
+                                    &buffer);
+       if (!err) {
+               union acpi_object *obj = buffer.pointer;
+               if (obj && obj->type == ACPI_TYPE_INTEGER)
+                       *result = obj->integer.value;
+               else
+                       err = -EIO;
+       }
+       return err;
+}
+
+static ssize_t show_lsvalue(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct asus_laptop *asus = dev_get_drvdata(dev);
+       int err, hi, lo;
+
+       err = pega_int_read(asus, PEGA_READ_ALS_H, &hi);
+       if (!err)
+               err = pega_int_read(asus, PEGA_READ_ALS_L, &lo);
+       if (!err)
+               return sprintf(buf, "%d\n", 10 * hi + lo);
+       return err;
+}
+
 /*
  * GPS
  */
@@ -1062,6 +1279,86 @@ static int asus_rfkill_init(struct asus_laptop *asus)
        return result;
 }
 
+static int pega_rfkill_set(void *data, bool blocked)
+{
+       struct asus_pega_rfkill *pega_rfk = data;
+
+       int ret = asus_pega_lucid_set(pega_rfk->asus, pega_rfk->control_id, !blocked);
+       pr_warn("Setting rfkill %d, to %d; returned %d\n", pega_rfk->control_id, !blocked, ret);
+
+       return ret;
+}
+
+static const struct rfkill_ops pega_rfkill_ops = {
+       .set_block = pega_rfkill_set,
+};
+
+static void pega_rfkill_terminate(struct asus_pega_rfkill *pega_rfk)
+{
+       pr_warn("Terminating %d\n", pega_rfk->control_id);
+       if (pega_rfk->rfkill) {
+               rfkill_unregister(pega_rfk->rfkill);
+               rfkill_destroy(pega_rfk->rfkill);
+               pega_rfk->rfkill = NULL;
+       }
+}
+
+static void pega_rfkill_exit(struct asus_laptop *asus)
+{
+       pega_rfkill_terminate(&asus->wwanrfk);
+       pega_rfkill_terminate(&asus->btrfk);
+       pega_rfkill_terminate(&asus->wlanrfk);
+}
+
+static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_pega_rfkill *pega_rfk,
+               const char *name, int controlid, int rfkill_type)
+{
+       int result;
+
+       pr_warn("Setting up rfk %s, control %d, type %d\n", name, controlid, rfkill_type);
+       pega_rfk->control_id = controlid;
+       pega_rfk->asus = asus;
+       pega_rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
+                                       rfkill_type, &pega_rfkill_ops, pega_rfk);
+       if (!pega_rfk->rfkill)
+               return -EINVAL;
+
+       result = rfkill_register(pega_rfk->rfkill);
+       if (result) {
+               rfkill_destroy(pega_rfk->rfkill);
+               pega_rfk->rfkill = NULL;
+       }
+
+       return result;
+}
+
+static int pega_rfkill_init(struct asus_laptop *asus)
+{
+       int ret = 0;
+
+       if(!asus->is_pega_lucid)
+               return -ENODEV;
+
+       ret = pega_rfkill_setup(asus, &asus->wlanrfk, "pega-wlan", PEGA_WLAN, RFKILL_TYPE_WLAN);
+       if(ret)
+               return ret;
+       ret = pega_rfkill_setup(asus, &asus->btrfk, "pega-bt", PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
+       if(ret)
+               goto err_btrfk;
+       ret = pega_rfkill_setup(asus, &asus->wwanrfk, "pega-wwan", PEGA_WWAN, RFKILL_TYPE_WWAN);
+       if(ret)
+               goto err_wwanrfk;
+
+       pr_warn("Pega rfkill init succeeded\n");
+       return 0;
+err_wwanrfk:
+       pega_rfkill_terminate(&asus->btrfk);
+err_btrfk:
+       pega_rfkill_terminate(&asus->wlanrfk);
+
+       return ret;
+}
+
 /*
  * Input device (i.e. hotkeys)
  */
@@ -1141,6 +1438,14 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
                }
                return ;
        }
+
+       /* Accelerometer "coarse orientation change" event */
+       if (asus->pega_accel_poll && event == 0xEA) {
+               kobject_uevent(&asus->pega_accel_poll->input->dev.kobj,
+                              KOBJ_CHANGE);
+               return ;
+       }
+
        asus_input_notify(asus, event);
 }
 
@@ -1152,6 +1457,7 @@ static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax);
 static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan);
 static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp);
 static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
+static DEVICE_ATTR(ls_value, S_IRUGO, show_lsvalue, NULL);
 static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
 static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
 static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps);
@@ -1164,6 +1470,7 @@ static struct attribute *asus_attributes[] = {
        &dev_attr_wwan.attr,
        &dev_attr_display.attr,
        &dev_attr_ledd.attr,
+       &dev_attr_ls_value.attr,
        &dev_attr_ls_level.attr,
        &dev_attr_ls_switch.attr,
        &dev_attr_gps.attr,
@@ -1180,6 +1487,19 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj,
        acpi_handle handle = asus->handle;
        bool supported;
 
+       if (asus->is_pega_lucid) {
+               /* no ls_level interface on the Lucid */
+               if (attr == &dev_attr_ls_switch.attr)
+                       supported = true;
+               else if (attr == &dev_attr_ls_level.attr)
+                       supported = false;
+               else
+                       goto normal;
+
+               return supported;
+       }
+
+normal:
        if (attr == &dev_attr_wlan.attr) {
                supported = !acpi_check_handle(handle, METHOD_WLAN, NULL);
 
@@ -1202,8 +1522,9 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj,
        } else if (attr == &dev_attr_ls_switch.attr ||
                   attr == &dev_attr_ls_level.attr) {
                supported = !acpi_check_handle(handle, METHOD_ALS_CONTROL, NULL) &&
-                           !acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL);
-
+                       !acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL);
+       } else if (attr == &dev_attr_ls_value.attr) {
+               supported = asus->is_pega_lucid;
        } else if (attr == &dev_attr_gps.attr) {
                supported = !acpi_check_handle(handle, METHOD_GPS_ON, NULL) &&
                            !acpi_check_handle(handle, METHOD_GPS_OFF, NULL) &&
@@ -1258,7 +1579,7 @@ static struct platform_driver platform_driver = {
        .driver = {
                .name = ASUS_LAPTOP_FILE,
                .owner = THIS_MODULE,
-       }
+       },
 };
 
 /*
@@ -1388,11 +1709,13 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
        asus->ledd_status = 0xFFF;
 
        /* Set initial values of light sensor and level */
-       asus->light_switch = 0; /* Default to light sensor disabled */
+       asus->light_switch = !!als_status;
        asus->light_level = 5;  /* level 5 for sensor sensitivity */
 
-       if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
-           !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
+       if (asus->is_pega_lucid) {
+               asus_als_switch(asus, asus->light_switch);
+       } else if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
+                  !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
                asus_als_switch(asus, asus->light_switch);
                asus_als_level(asus, asus->light_level);
        }
@@ -1439,9 +1762,10 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
                goto fail_platform;
 
        /*
-        * Register the platform device first.  It is used as a parent for the
-        * sub-devices below.
+        * Need platform type detection first, then the platform
+        * device.  It is used as a parent for the sub-devices below.
         */
+       asus->is_pega_lucid = asus_check_pega_lucid(asus);
        result = asus_platform_init(asus);
        if (result)
                goto fail_platform;
@@ -1465,9 +1789,21 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
        if (result)
                goto fail_rfkill;
 
+       result = pega_accel_init(asus);
+       if (result && result != -ENODEV)
+               goto fail_pega_accel;
+
+       result = pega_rfkill_init(asus);
+       if (result && result != -ENODEV)
+               goto fail_pega_rfkill;
+
        asus_device_present = true;
        return 0;
 
+fail_pega_rfkill:
+       pega_accel_exit(asus);
+fail_pega_accel:
+       asus_rfkill_exit(asus);
 fail_rfkill:
        asus_led_exit(asus);
 fail_led:
@@ -1491,6 +1827,8 @@ static int asus_acpi_remove(struct acpi_device *device, int type)
        asus_rfkill_exit(asus);
        asus_led_exit(asus);
        asus_input_exit(asus);
+       pega_accel_exit(asus);
+       pega_rfkill_exit(asus);
        asus_platform_exit(asus);
 
        kfree(asus->name);
index 95cba9e..d1049ee 100644 (file)
@@ -453,7 +453,9 @@ static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
 
 static void asus_wmi_led_exit(struct asus_wmi *asus)
 {
-       if (asus->tpd_led.dev)
+       if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
+               led_classdev_unregister(&asus->kbd_led);
+       if (!IS_ERR_OR_NULL(asus->tpd_led.dev))
                led_classdev_unregister(&asus->tpd_led);
        if (asus->led_workqueue)
                destroy_workqueue(asus->led_workqueue);
index f31fa4e..a43cfd9 100644 (file)
@@ -60,6 +60,22 @@ struct calling_interface_structure {
        struct calling_interface_token tokens[];
 } __packed;
 
+struct quirk_entry {
+       u8 touchpad_led;
+};
+
+static struct quirk_entry *quirks;
+
+static struct quirk_entry quirk_dell_vostro_v130 = {
+       .touchpad_led = 1,
+};
+
+static int dmi_matched(const struct dmi_system_id *dmi)
+{
+       quirks = dmi->driver_data;
+       return 1;
+}
+
 static int da_command_address;
 static int da_command_code;
 static int da_num_tokens;
@@ -149,6 +165,27 @@ static struct dmi_system_id __devinitdata dell_blacklist[] = {
        {}
 };
 
+static struct dmi_system_id __devinitdata dell_quirks[] = {
+       {
+               .callback = dmi_matched,
+               .ident = "Dell Vostro V130",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V130"),
+               },
+               .driver_data = &quirk_dell_vostro_v130,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Dell Vostro V131",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
+               },
+               .driver_data = &quirk_dell_vostro_v130,
+       },
+};
+
 static struct calling_interface_buffer *buffer;
 static struct page *bufferpage;
 static DEFINE_MUTEX(buffer_mutex);
@@ -552,6 +589,44 @@ static const struct backlight_ops dell_ops = {
        .update_status  = dell_send_intensity,
 };
 
+static void touchpad_led_on()
+{
+       int command = 0x97;
+       char data = 1;
+       i8042_command(&data, command | 1 << 12);
+}
+
+static void touchpad_led_off()
+{
+       int command = 0x97;
+       char data = 2;
+       i8042_command(&data, command | 1 << 12);
+}
+
+static void touchpad_led_set(struct led_classdev *led_cdev,
+       enum led_brightness value)
+{
+       if (value > 0)
+               touchpad_led_on();
+       else
+               touchpad_led_off();
+}
+
+static struct led_classdev touchpad_led = {
+       .name = "dell-laptop::touchpad",
+       .brightness_set = touchpad_led_set,
+};
+
+static int __devinit touchpad_led_init(struct device *dev)
+{
+       return led_classdev_register(dev, &touchpad_led);
+}
+
+static void touchpad_led_exit(void)
+{
+       led_classdev_unregister(&touchpad_led);
+}
+
 static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
                              struct serio *port)
 {
@@ -584,6 +659,10 @@ static int __init dell_init(void)
        if (!dmi_check_system(dell_device_table))
                return -ENODEV;
 
+       quirks = NULL;
+       /* find if this machine support other functions */
+       dmi_check_system(dell_quirks);
+
        dmi_walk(find_tokens, NULL);
 
        if (!da_tokens)  {
@@ -626,6 +705,9 @@ static int __init dell_init(void)
                goto fail_filter;
        }
 
+       if (quirks && quirks->touchpad_led)
+               touchpad_led_init(&platform_device->dev);
+
        dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL);
        if (dell_laptop_dir != NULL)
                debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
@@ -692,6 +774,8 @@ fail_platform_driver:
 static void __exit dell_exit(void)
 {
        debugfs_remove_recursive(dell_laptop_dir);
+       if (quirks && quirks->touchpad_led)
+               touchpad_led_exit();
        i8042_remove_filter(dell_laptop_i8042_filter);
        cancel_delayed_work_sync(&dell_rfkill_work);
        backlight_device_unregister(dell_backlight_device);
index 1c45d92..ea44abd 100644 (file)
@@ -568,7 +568,7 @@ static int eeepc_led_init(struct eeepc_laptop *eeepc)
 
 static void eeepc_led_exit(struct eeepc_laptop *eeepc)
 {
-       if (eeepc->tpd_led.dev)
+       if (!IS_ERR_OR_NULL(eeepc->tpd_led.dev))
                led_classdev_unregister(&eeepc->tpd_led);
        if (eeepc->led_workqueue)
                destroy_workqueue(eeepc->led_workqueue);
index 1b52d00..64b4548 100644 (file)
@@ -76,6 +76,7 @@ static inline void delayed_sysfs_set(struct led_classdev *led_cdev,
 /* For automatic insertion of the module */
 static struct acpi_device_id lis3lv02d_device_ids[] = {
        {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
+       {"HPQ6000", 0}, /* HP Mobile Data Protection System PNP */
        {"", 0},
 };
 MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
@@ -228,6 +229,10 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
        AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
        AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted),
        AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd),
+       AXIS_DMI_MATCH("HPB63xx", "HP ProBook 63", xy_swap),
+       AXIS_DMI_MATCH("HPB64xx", "HP ProBook 64", xy_swap),
+       AXIS_DMI_MATCH("HPB64xx", "HP EliteBook 84", xy_swap),
+       AXIS_DMI_MATCH("HPB65xx", "HP ProBook 65", x_inverted),
        { NULL, }
 /* Laptop models without axis info (yet):
  * "NC6910" "HP Compaq 6910"
index 0c59541..a36addf 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/input/sparse-keymap.h>
 #include <linux/backlight.h>
 #include <linux/fb.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #define IDEAPAD_RFKILL_DEV_NUM (3)
 
 #define CFG_WIFI_BIT   (18)
 #define CFG_CAMERA_BIT (19)
 
+enum {
+       VPCCMD_R_VPC1 = 0x10,
+       VPCCMD_R_BL_MAX,
+       VPCCMD_R_BL,
+       VPCCMD_W_BL,
+       VPCCMD_R_WIFI,
+       VPCCMD_W_WIFI,
+       VPCCMD_R_BT,
+       VPCCMD_W_BT,
+       VPCCMD_R_BL_POWER,
+       VPCCMD_R_NOVO,
+       VPCCMD_R_VPC2,
+       VPCCMD_R_TOUCHPAD,
+       VPCCMD_W_TOUCHPAD,
+       VPCCMD_R_CAMERA,
+       VPCCMD_W_CAMERA,
+       VPCCMD_R_3G,
+       VPCCMD_W_3G,
+       VPCCMD_R_ODD, /* 0x21 */
+       VPCCMD_R_RF = 0x23,
+       VPCCMD_W_RF,
+       VPCCMD_W_BL_POWER = 0x33,
+};
+
 struct ideapad_private {
        struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
        struct platform_device *platform_device;
        struct input_dev *inputdev;
        struct backlight_device *blightdev;
+       struct dentry *debug;
        unsigned long cfg;
 };
 
 static acpi_handle ideapad_handle;
+static struct ideapad_private *ideapad_priv;
 static bool no_bt_rfkill;
 module_param(no_bt_rfkill, bool, 0444);
 MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
@@ -163,6 +191,146 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
        return -1;
 }
 
+/*
+ * debugfs
+ */
+#define DEBUGFS_EVENT_LEN (4096)
+static int debugfs_status_show(struct seq_file *s, void *data)
+{
+       unsigned long value;
+
+       if (!read_ec_data(ideapad_handle, VPCCMD_R_BL_MAX, &value))
+               seq_printf(s, "Backlight max:\t%lu\n", value);
+       if (!read_ec_data(ideapad_handle, VPCCMD_R_BL, &value))
+               seq_printf(s, "Backlight now:\t%lu\n", value);
+       if (!read_ec_data(ideapad_handle, VPCCMD_R_BL_POWER, &value))
+               seq_printf(s, "BL power value:\t%s\n", value ? "On" : "Off");
+       seq_printf(s, "=====================\n");
+
+       if (!read_ec_data(ideapad_handle, VPCCMD_R_RF, &value))
+               seq_printf(s, "Radio status:\t%s(%lu)\n",
+                          value ? "On" : "Off", value);
+       if (!read_ec_data(ideapad_handle, VPCCMD_R_WIFI, &value))
+               seq_printf(s, "Wifi status:\t%s(%lu)\n",
+                          value ? "On" : "Off", value);
+       if (!read_ec_data(ideapad_handle, VPCCMD_R_BT, &value))
+               seq_printf(s, "BT status:\t%s(%lu)\n",
+                          value ? "On" : "Off", value);
+       if (!read_ec_data(ideapad_handle, VPCCMD_R_3G, &value))
+               seq_printf(s, "3G status:\t%s(%lu)\n",
+                          value ? "On" : "Off", value);
+       seq_printf(s, "=====================\n");
+
+       if (!read_ec_data(ideapad_handle, VPCCMD_R_TOUCHPAD, &value))
+               seq_printf(s, "Touchpad status:%s(%lu)\n",
+                          value ? "On" : "Off", value);
+       if (!read_ec_data(ideapad_handle, VPCCMD_R_CAMERA, &value))
+               seq_printf(s, "Camera status:\t%s(%lu)\n",
+                          value ? "On" : "Off", value);
+
+       return 0;
+}
+
+static int debugfs_status_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_status_show, NULL);
+}
+
+static const struct file_operations debugfs_status_fops = {
+       .owner = THIS_MODULE,
+       .open = debugfs_status_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int debugfs_cfg_show(struct seq_file *s, void *data)
+{
+       if (!ideapad_priv) {
+               seq_printf(s, "cfg: N/A\n");
+       } else {
+               seq_printf(s, "cfg: 0x%.8lX\n\nCapability: ",
+                          ideapad_priv->cfg);
+               if (test_bit(CFG_BT_BIT, &ideapad_priv->cfg))
+                       seq_printf(s, "Bluetooth ");
+               if (test_bit(CFG_3G_BIT, &ideapad_priv->cfg))
+                       seq_printf(s, "3G ");
+               if (test_bit(CFG_WIFI_BIT, &ideapad_priv->cfg))
+                       seq_printf(s, "Wireless ");
+               if (test_bit(CFG_CAMERA_BIT, &ideapad_priv->cfg))
+                       seq_printf(s, "Camera ");
+               seq_printf(s, "\nGraphic: ");
+               switch ((ideapad_priv->cfg)&0x700) {
+               case 0x100:
+                       seq_printf(s, "Intel");
+                       break;
+               case 0x200:
+                       seq_printf(s, "ATI");
+                       break;
+               case 0x300:
+                       seq_printf(s, "Nvidia");
+                       break;
+               case 0x400:
+                       seq_printf(s, "Intel and ATI");
+                       break;
+               case 0x500:
+                       seq_printf(s, "Intel and Nvidia");
+                       break;
+               }
+               seq_printf(s, "\n");
+       }
+       return 0;
+}
+
+static int debugfs_cfg_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_cfg_show, NULL);
+}
+
+static const struct file_operations debugfs_cfg_fops = {
+       .owner = THIS_MODULE,
+       .open = debugfs_cfg_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int __devinit ideapad_debugfs_init(struct ideapad_private *priv)
+{
+       struct dentry *node;
+
+       priv->debug = debugfs_create_dir("ideapad", NULL);
+       if (priv->debug == NULL) {
+               pr_err("failed to create debugfs directory");
+               goto errout;
+       }
+
+       node = debugfs_create_file("cfg", S_IRUGO, priv->debug, NULL,
+                                  &debugfs_cfg_fops);
+       if (!node) {
+               pr_err("failed to create cfg in debugfs");
+               goto errout;
+       }
+
+       node = debugfs_create_file("status", S_IRUGO, priv->debug, NULL,
+                                  &debugfs_status_fops);
+       if (!node) {
+               pr_err("failed to create event in debugfs");
+               goto errout;
+       }
+
+       return 0;
+
+errout:
+       return -ENOMEM;
+}
+
+static void ideapad_debugfs_exit(struct ideapad_private *priv)
+{
+       debugfs_remove_recursive(priv->debug);
+       priv->debug = NULL;
+}
+
 /*
  * sysfs
  */
@@ -172,7 +340,7 @@ static ssize_t show_ideapad_cam(struct device *dev,
 {
        unsigned long result;
 
-       if (read_ec_data(ideapad_handle, 0x1D, &result))
+       if (read_ec_data(ideapad_handle, VPCCMD_R_CAMERA, &result))
                return sprintf(buf, "-1\n");
        return sprintf(buf, "%lu\n", result);
 }
@@ -187,7 +355,7 @@ static ssize_t store_ideapad_cam(struct device *dev,
                return 0;
        if (sscanf(buf, "%i", &state) != 1)
                return -EINVAL;
-       ret = write_ec_cmd(ideapad_handle, 0x1E, state);
+       ret = write_ec_cmd(ideapad_handle, VPCCMD_W_CAMERA, state);
        if (ret < 0)
                return ret;
        return count;
@@ -195,20 +363,8 @@ static ssize_t store_ideapad_cam(struct device *dev,
 
 static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
 
-static ssize_t show_ideapad_cfg(struct device *dev,
-                               struct device_attribute *attr,
-                               char *buf)
-{
-       struct ideapad_private *priv = dev_get_drvdata(dev);
-
-       return sprintf(buf, "0x%.8lX\n", priv->cfg);
-}
-
-static DEVICE_ATTR(cfg, 0444, show_ideapad_cfg, NULL);
-
 static struct attribute *ideapad_attributes[] = {
        &dev_attr_camera_power.attr,
-       &dev_attr_cfg.attr,
        NULL
 };
 
@@ -244,9 +400,9 @@ struct ideapad_rfk_data {
 };
 
 const struct ideapad_rfk_data ideapad_rfk_data[] = {
-       { "ideapad_wlan",      CFG_WIFI_BIT, 0x15, RFKILL_TYPE_WLAN },
-       { "ideapad_bluetooth", CFG_BT_BIT,   0x17, RFKILL_TYPE_BLUETOOTH },
-       { "ideapad_3g",        CFG_3G_BIT,   0x20, RFKILL_TYPE_WWAN },
+       { "ideapad_wlan",    CFG_WIFI_BIT, VPCCMD_W_WIFI, RFKILL_TYPE_WLAN },
+       { "ideapad_bluetooth", CFG_BT_BIT, VPCCMD_W_BT, RFKILL_TYPE_BLUETOOTH },
+       { "ideapad_3g",        CFG_3G_BIT, VPCCMD_W_3G, RFKILL_TYPE_WWAN },
 };
 
 static int ideapad_rfk_set(void *data, bool blocked)
@@ -260,13 +416,12 @@ static struct rfkill_ops ideapad_rfk_ops = {
        .set_block = ideapad_rfk_set,
 };
 
-static void ideapad_sync_rfk_state(struct acpi_device *adevice)
+static void ideapad_sync_rfk_state(struct ideapad_private *priv)
 {
-       struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
        unsigned long hw_blocked;
        int i;
 
-       if (read_ec_data(ideapad_handle, 0x23, &hw_blocked))
+       if (read_ec_data(ideapad_handle, VPCCMD_R_RF, &hw_blocked))
                return;
        hw_blocked = !hw_blocked;
 
@@ -363,8 +518,10 @@ static void ideapad_platform_exit(struct ideapad_private *priv)
  * input device
  */
 static const struct key_entry ideapad_keymap[] = {
-       { KE_KEY, 0x06, { KEY_SWITCHVIDEOMODE } },
-       { KE_KEY, 0x0D, { KEY_WLAN } },
+       { KE_KEY, 6,  { KEY_SWITCHVIDEOMODE } },
+       { KE_KEY, 13, { KEY_WLAN } },
+       { KE_KEY, 16, { KEY_PROG1 } },
+       { KE_KEY, 17, { KEY_PROG2 } },
        { KE_END, 0 },
 };
 
@@ -419,6 +576,18 @@ static void ideapad_input_report(struct ideapad_private *priv,
        sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
 }
 
+static void ideapad_input_novokey(struct ideapad_private *priv)
+{
+       unsigned long long_pressed;
+
+       if (read_ec_data(ideapad_handle, VPCCMD_R_NOVO, &long_pressed))
+               return;
+       if (long_pressed)
+               ideapad_input_report(priv, 17);
+       else
+               ideapad_input_report(priv, 16);
+}
+
 /*
  * backlight
  */
@@ -426,16 +595,17 @@ static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
 {
        unsigned long now;
 
-       if (read_ec_data(ideapad_handle, 0x12, &now))
+       if (read_ec_data(ideapad_handle, VPCCMD_R_BL, &now))
                return -EIO;
        return now;
 }
 
 static int ideapad_backlight_update_status(struct backlight_device *blightdev)
 {
-       if (write_ec_cmd(ideapad_handle, 0x13, blightdev->props.brightness))
+       if (write_ec_cmd(ideapad_handle, VPCCMD_W_BL,
+                        blightdev->props.brightness))
                return -EIO;
-       if (write_ec_cmd(ideapad_handle, 0x33,
+       if (write_ec_cmd(ideapad_handle, VPCCMD_W_BL_POWER,
                         blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1))
                return -EIO;
 
@@ -453,11 +623,11 @@ static int ideapad_backlight_init(struct ideapad_private *priv)
        struct backlight_properties props;
        unsigned long max, now, power;
 
-       if (read_ec_data(ideapad_handle, 0x11, &max))
+       if (read_ec_data(ideapad_handle, VPCCMD_R_BL_MAX, &max))
                return -EIO;
-       if (read_ec_data(ideapad_handle, 0x12, &now))
+       if (read_ec_data(ideapad_handle, VPCCMD_R_BL, &now))
                return -EIO;
-       if (read_ec_data(ideapad_handle, 0x18, &power))
+       if (read_ec_data(ideapad_handle, VPCCMD_R_BL_POWER, &power))
                return -EIO;
 
        memset(&props, 0, sizeof(struct backlight_properties));
@@ -493,7 +663,9 @@ static void ideapad_backlight_notify_power(struct ideapad_private *priv)
        unsigned long power;
        struct backlight_device *blightdev = priv->blightdev;
 
-       if (read_ec_data(ideapad_handle, 0x18, &power))
+       if (!blightdev)
+               return;
+       if (read_ec_data(ideapad_handle, VPCCMD_R_BL_POWER, &power))
                return;
        blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
 }
@@ -504,7 +676,7 @@ static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
 
        /* if we control brightness via acpi video driver */
        if (priv->blightdev == NULL) {
-               read_ec_data(ideapad_handle, 0x12, &now);
+               read_ec_data(ideapad_handle, VPCCMD_R_BL, &now);
                return;
        }
 
@@ -533,6 +705,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
        if (!priv)
                return -ENOMEM;
        dev_set_drvdata(&adevice->dev, priv);
+       ideapad_priv = priv;
        ideapad_handle = adevice->handle;
        priv->cfg = cfg;
 
@@ -540,6 +713,10 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
        if (ret)
                goto platform_failed;
 
+       ret = ideapad_debugfs_init(priv);
+       if (ret)
+               goto debugfs_failed;
+
        ret = ideapad_input_init(priv);
        if (ret)
                goto input_failed;
@@ -550,7 +727,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
                else
                        priv->rfk[i] = NULL;
        }
-       ideapad_sync_rfk_state(adevice);
+       ideapad_sync_rfk_state(priv);
 
        if (!acpi_video_backlight_support()) {
                ret = ideapad_backlight_init(priv);
@@ -565,6 +742,8 @@ backlight_failed:
                ideapad_unregister_rfkill(adevice, i);
        ideapad_input_exit(priv);
 input_failed:
+       ideapad_debugfs_exit(priv);
+debugfs_failed:
        ideapad_platform_exit(priv);
 platform_failed:
        kfree(priv);
@@ -580,6 +759,7 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type)
        for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
                ideapad_unregister_rfkill(adevice, i);
        ideapad_input_exit(priv);
+       ideapad_debugfs_exit(priv);
        ideapad_platform_exit(priv);
        dev_set_drvdata(&adevice->dev, NULL);
        kfree(priv);
@@ -593,9 +773,9 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
        acpi_handle handle = adevice->handle;
        unsigned long vpc1, vpc2, vpc_bit;
 
-       if (read_ec_data(handle, 0x10, &vpc1))
+       if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
                return;
-       if (read_ec_data(handle, 0x1A, &vpc2))
+       if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
                return;
 
        vpc1 = (vpc2 << 8) | vpc1;
@@ -603,11 +783,14 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
                if (test_bit(vpc_bit, &vpc1)) {
                        switch (vpc_bit) {
                        case 9:
-                               ideapad_sync_rfk_state(adevice);
+                               ideapad_sync_rfk_state(priv);
                                break;
                        case 4:
                                ideapad_backlight_notify_brightness(priv);
                                break;
+                       case 3:
+                               ideapad_input_novokey(priv);
+                               break;
                        case 2:
                                ideapad_backlight_notify_power(priv);
                                break;
index b93a032..2d0f913 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/init.h>
 #include <asm/intel_scu_ipc.h>
 
-static u32 major;
+static int major;
 
 #define MAX_FW_SIZE 264192
 
@@ -117,7 +117,11 @@ static const struct file_operations scu_ipc_fops = {
 
 static int __init ipc_module_init(void)
 {
-       return register_chrdev(0, "intel_mid_scu", &scu_ipc_fops);
+       major = register_chrdev(0, "intel_mid_scu", &scu_ipc_fops);
+       if (major < 0)
+               return major;
+
+       return 0;
 }
 
 static void __exit ipc_module_exit(void)
index 3591630..09e26bf 100644 (file)
@@ -226,6 +226,7 @@ static struct backlight_device *backlight_device;
 static struct mutex sabi_mutex;
 static struct platform_device *sdev;
 static struct rfkill *rfk;
+static bool has_stepping_quirk;
 
 static int force;
 module_param(force, bool, 0);
@@ -370,15 +371,28 @@ static u8 read_brightness(void)
                                  &sretval);
        if (!retval) {
                user_brightness = sretval.retval[0];
-               if (user_brightness != 0)
+               if (user_brightness > sabi_config->min_brightness)
                        user_brightness -= sabi_config->min_brightness;
+               else
+                       user_brightness = 0;
        }
        return user_brightness;
 }
 
 static void set_brightness(u8 user_brightness)
 {
-       u8 user_level = user_brightness - sabi_config->min_brightness;
+       u8 user_level = user_brightness + sabi_config->min_brightness;
+
+       if (has_stepping_quirk && user_level != 0) {
+               /*
+                * short circuit if the specified level is what's already set
+                * to prevent the screen from flickering needlessly
+                */
+               if (user_brightness == read_brightness())
+                       return;
+
+               sabi_set_command(sabi_config->commands.set_brightness, 0);
+       }
 
        sabi_set_command(sabi_config->commands.set_brightness, user_level);
 }
@@ -388,6 +402,40 @@ static int get_brightness(struct backlight_device *bd)
        return (int)read_brightness();
 }
 
+static void check_for_stepping_quirk(void)
+{
+       u8 initial_level;
+       u8 check_level;
+       u8 orig_level = read_brightness();
+
+       /*
+        * Some laptops exhibit the strange behaviour of stepping toward
+        * (rather than setting) the brightness except when changing to/from
+        * brightness level 0. This behaviour is checked for here and worked
+        * around in set_brightness.
+        */
+
+       if (orig_level == 0)
+               set_brightness(1);
+
+       initial_level = read_brightness();
+
+       if (initial_level <= 2)
+               check_level = initial_level + 2;
+       else
+               check_level = initial_level - 2;
+
+       has_stepping_quirk = false;
+       set_brightness(check_level);
+
+       if (read_brightness() != check_level) {
+               has_stepping_quirk = true;
+               pr_info("enabled workaround for brightness stepping quirk\n");
+       }
+
+       set_brightness(orig_level);
+}
+
 static int update_status(struct backlight_device *bd)
 {
        set_brightness(bd->props.brightness);
@@ -620,6 +668,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
                },
                .callback = dmi_check_cb,
        },
+       {
+               .ident = "N220",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                                       "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "N220"),
+                       DMI_MATCH(DMI_BOARD_NAME, "N220"),
+               },
+               .callback = dmi_check_cb,
+       },
        {
                .ident = "N150/N210/N220/N230",
                .matches = {
@@ -640,6 +698,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
                },
                .callback = dmi_check_cb,
        },
+       {
+               .ident = "R700",
+               .matches = {
+                     DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+                     DMI_MATCH(DMI_PRODUCT_NAME, "SR700"),
+                     DMI_MATCH(DMI_BOARD_NAME, "SR700"),
+               },
+               .callback = dmi_check_cb,
+       },
        {
                .ident = "R530/R730",
                .matches = {
@@ -686,6 +753,33 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
                },
                .callback = dmi_check_cb,
        },
+       {
+               .ident = "R528/R728",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "R528/R728"),
+                       DMI_MATCH(DMI_BOARD_NAME, "R528/R728"),
+               },
+               .callback = dmi_check_cb,
+       },
+       {
+               .ident = "NC210/NC110",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
+                       DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
+               },
+               .callback = dmi_check_cb,
+       },
+               {
+               .ident = "X520",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X520"),
+                       DMI_MATCH(DMI_BOARD_NAME, "X520"),
+               },
+               .callback = dmi_check_cb,
+       },
        { },
 };
 MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
@@ -770,7 +864,7 @@ static int __init samsung_init(void)
        sabi_iface = ioremap_nocache(ifaceP, 16);
        if (!sabi_iface) {
                pr_err("Can't remap %x\n", ifaceP);
-               goto exit;
+               goto error_no_signature;
        }
        if (debug) {
                printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
@@ -794,6 +888,9 @@ static int __init samsung_init(void)
                }
        }
 
+       /* Check for stepping quirk */
+       check_for_stepping_quirk();
+
        /* knock up a platform device to hang stuff off of */
        sdev = platform_device_register_simple("samsung", -1, NULL, 0);
        if (IS_ERR(sdev))
@@ -802,7 +899,8 @@ static int __init samsung_init(void)
        /* create a backlight device to talk to this one */
        memset(&props, 0, sizeof(struct backlight_properties));
        props.type = BACKLIGHT_PLATFORM;
-       props.max_brightness = sabi_config->max_brightness;
+       props.max_brightness = sabi_config->max_brightness -
+                               sabi_config->min_brightness;
        backlight_device = backlight_device_register("samsung", &sdev->dev,
                                                     NULL, &backlight_ops,
                                                     &props);
@@ -821,7 +919,6 @@ static int __init samsung_init(void)
        if (retval)
                goto error_file_create;
 
-exit:
        return 0;
 
 error_file_create:
index bbd182e..c006dee 100644 (file)
@@ -3281,7 +3281,7 @@ static int sony_pic_add(struct acpi_device *device)
        /* request IRQ */
        list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
                if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
-                                       IRQF_DISABLED, "sony-laptop", &spic_dev)) {
+                                       0, "sony-laptop", &spic_dev)) {
                        dprintk("IRQ: %d - triggering: %d - "
                                        "polarity: %d - shr: %d\n",
                                        irq->irq.interrupts[0],
index 4c20447..d528daa 100644 (file)
@@ -41,6 +41,7 @@ static const struct key_entry topstar_keymap[] = {
        { KE_KEY, 0x8c, { KEY_MEDIA } },
 
        /* Known non hotkey events don't handled or that we don't care yet */
+       { KE_IGNORE, 0x82, }, /* backlight event */
        { KE_IGNORE, 0x8e, },
        { KE_IGNORE, 0x8f, },
        { KE_IGNORE, 0x90, },
index cb009b2..13ef8c3 100644 (file)
@@ -47,7 +47,6 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/backlight.h>
-#include <linux/platform_device.h>
 #include <linux/rfkill.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
@@ -63,11 +62,7 @@ MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
 MODULE_LICENSE("GPL");
 
 /* Toshiba ACPI method paths */
-#define METHOD_LCD_BRIGHTNESS  "\\_SB_.PCI0.VGA_.LCD_._BCM"
-#define TOSH_INTERFACE_1       "\\_SB_.VALD"
-#define TOSH_INTERFACE_2       "\\_SB_.VALZ"
 #define METHOD_VIDEO_OUT       "\\_SB_.VALX.DSSX"
-#define GHCI_METHOD            ".GHCI"
 
 /* Toshiba HCI interface definitions
  *
@@ -111,6 +106,25 @@ MODULE_LICENSE("GPL");
 #define HCI_WIRELESS_BT_ATTACH         0x40
 #define HCI_WIRELESS_BT_POWER          0x80
 
+struct toshiba_acpi_dev {
+       struct acpi_device *acpi_dev;
+       const char *method_hci;
+       struct rfkill *bt_rfk;
+       struct input_dev *hotkey_dev;
+       struct backlight_device *backlight_dev;
+       struct led_classdev led_dev;
+
+       int force_fan;
+       int last_key_event;
+       int key_event_valid;
+
+       int illumination_supported:1;
+       int video_supported:1;
+       int fan_supported:1;
+
+       struct mutex mutex;
+};
+
 static const struct acpi_device_id toshiba_device_ids[] = {
        {"TOS6200", 0},
        {"TOS6208", 0},
@@ -119,7 +133,7 @@ static const struct acpi_device_id toshiba_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
 
-static const struct key_entry toshiba_acpi_keymap[] __initconst = {
+static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
        { KE_KEY, 0x101, { KEY_MUTE } },
        { KE_KEY, 0x102, { KEY_ZOOMOUT } },
        { KE_KEY, 0x103, { KEY_ZOOMIN } },
@@ -155,15 +169,6 @@ static __inline__ void _set_bit(u32 * word, u32 mask, int value)
 /* acpi interface wrappers
  */
 
-static int is_valid_acpi_path(const char *methodName)
-{
-       acpi_handle handle;
-       acpi_status status;
-
-       status = acpi_get_handle(NULL, (char *)methodName, &handle);
-       return !ACPI_FAILURE(status);
-}
-
 static int write_acpi_int(const char *methodName, int val)
 {
        struct acpi_object_list params;
@@ -176,32 +181,14 @@ static int write_acpi_int(const char *methodName, int val)
        in_objs[0].integer.value = val;
 
        status = acpi_evaluate_object(NULL, (char *)methodName, &params, NULL);
-       return (status == AE_OK);
-}
-
-#if 0
-static int read_acpi_int(const char *methodName, int *pVal)
-{
-       struct acpi_buffer results;
-       union acpi_object out_objs[1];
-       acpi_status status;
-
-       results.length = sizeof(out_objs);
-       results.pointer = out_objs;
-
-       status = acpi_evaluate_object(0, (char *)methodName, 0, &results);
-       *pVal = out_objs[0].integer.value;
-
-       return (status == AE_OK) && (out_objs[0].type == ACPI_TYPE_INTEGER);
+       return (status == AE_OK) ? 0 : -EIO;
 }
-#endif
-
-static const char *method_hci /*= 0*/ ;
 
 /* Perform a raw HCI call.  Here we don't care about input or output buffer
  * format.
  */
-static acpi_status hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
+static acpi_status hci_raw(struct toshiba_acpi_dev *dev,
+                          const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
 {
        struct acpi_object_list params;
        union acpi_object in_objs[HCI_WORDS];
@@ -220,7 +207,8 @@ static acpi_status hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
        results.length = sizeof(out_objs);
        results.pointer = out_objs;
 
-       status = acpi_evaluate_object(NULL, (char *)method_hci, &params,
+       status = acpi_evaluate_object(dev->acpi_dev->handle,
+                                     (char *)dev->method_hci, &params,
                                      &results);
        if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) {
                for (i = 0; i < out_objs->package.count; ++i) {
@@ -237,85 +225,79 @@ static acpi_status hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
  * may be useful (such as "not supported").
  */
 
-static acpi_status hci_write1(u32 reg, u32 in1, u32 * result)
+static acpi_status hci_write1(struct toshiba_acpi_dev *dev, u32 reg,
+                             u32 in1, u32 *result)
 {
        u32 in[HCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
        u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(in, out);
+       acpi_status status = hci_raw(dev, in, out);
        *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
        return status;
 }
 
-static acpi_status hci_read1(u32 reg, u32 * out1, u32 * result)
+static acpi_status hci_read1(struct toshiba_acpi_dev *dev, u32 reg,
+                            u32 *out1, u32 *result)
 {
        u32 in[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
        u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(in, out);
+       acpi_status status = hci_raw(dev, in, out);
        *out1 = out[2];
        *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
        return status;
 }
 
-static acpi_status hci_write2(u32 reg, u32 in1, u32 in2, u32 *result)
+static acpi_status hci_write2(struct toshiba_acpi_dev *dev, u32 reg,
+                             u32 in1, u32 in2, u32 *result)
 {
        u32 in[HCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
        u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(in, out);
+       acpi_status status = hci_raw(dev, in, out);
        *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
        return status;
 }
 
-static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
+static acpi_status hci_read2(struct toshiba_acpi_dev *dev, u32 reg,
+                            u32 *out1, u32 *out2, u32 *result)
 {
        u32 in[HCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
        u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(in, out);
+       acpi_status status = hci_raw(dev, in, out);
        *out1 = out[2];
        *out2 = out[3];
        *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
        return status;
 }
 
-struct toshiba_acpi_dev {
-       struct platform_device *p_dev;
-       struct rfkill *bt_rfk;
-       struct input_dev *hotkey_dev;
-       int illumination_installed;
-       acpi_handle handle;
-
-       const char *bt_name;
-
-       struct mutex mutex;
-};
-
 /* Illumination support */
-static int toshiba_illumination_available(void)
+static int toshiba_illumination_available(struct toshiba_acpi_dev *dev)
 {
        u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 };
        u32 out[HCI_WORDS];
        acpi_status status;
 
        in[0] = 0xf100;
-       status = hci_raw(in, out);
+       status = hci_raw(dev, in, out);
        if (ACPI_FAILURE(status)) {
                pr_info("Illumination device not available\n");
                return 0;
        }
        in[0] = 0xf400;
-       status = hci_raw(in, out);
+       status = hci_raw(dev, in, out);
        return 1;
 }
 
 static void toshiba_illumination_set(struct led_classdev *cdev,
                                     enum led_brightness brightness)
 {
+       struct toshiba_acpi_dev *dev = container_of(cdev,
+                       struct toshiba_acpi_dev, led_dev);
        u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 };
        u32 out[HCI_WORDS];
        acpi_status status;
 
        /* First request : initialize communication. */
        in[0] = 0xf100;
-       status = hci_raw(in, out);
+       status = hci_raw(dev, in, out);
        if (ACPI_FAILURE(status)) {
                pr_info("Illumination device not available\n");
                return;
@@ -326,7 +308,7 @@ static void toshiba_illumination_set(struct led_classdev *cdev,
                in[0] = 0xf400;
                in[1] = 0x14e;
                in[2] = 1;
-               status = hci_raw(in, out);
+               status = hci_raw(dev, in, out);
                if (ACPI_FAILURE(status)) {
                        pr_info("ACPI call for illumination failed\n");
                        return;
@@ -336,7 +318,7 @@ static void toshiba_illumination_set(struct led_classdev *cdev,
                in[0] = 0xf400;
                in[1] = 0x14e;
                in[2] = 0;
-               status = hci_raw(in, out);
+               status = hci_raw(dev, in, out);
                if (ACPI_FAILURE(status)) {
                        pr_info("ACPI call for illumination failed.\n");
                        return;
@@ -347,11 +329,13 @@ static void toshiba_illumination_set(struct led_classdev *cdev,
        in[0] = 0xf200;
        in[1] = 0;
        in[2] = 0;
-       hci_raw(in, out);
+       hci_raw(dev, in, out);
 }
 
 static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
 {
+       struct toshiba_acpi_dev *dev = container_of(cdev,
+                       struct toshiba_acpi_dev, led_dev);
        u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 };
        u32 out[HCI_WORDS];
        acpi_status status;
@@ -359,7 +343,7 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
 
        /* First request : initialize communication. */
        in[0] = 0xf100;
-       status = hci_raw(in, out);
+       status = hci_raw(dev, in, out);
        if (ACPI_FAILURE(status)) {
                pr_info("Illumination device not available\n");
                return LED_OFF;
@@ -368,7 +352,7 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
        /* Check the illumination */
        in[0] = 0xf300;
        in[1] = 0x14e;
-       status = hci_raw(in, out);
+       status = hci_raw(dev, in, out);
        if (ACPI_FAILURE(status)) {
                pr_info("ACPI call for illumination failed.\n");
                return LED_OFF;
@@ -380,46 +364,35 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
        in[0] = 0xf200;
        in[1] = 0;
        in[2] = 0;
-       hci_raw(in, out);
+       hci_raw(dev, in, out);
 
        return result;
 }
 
-static struct led_classdev toshiba_led = {
-       .name           = "toshiba::illumination",
-       .max_brightness = 1,
-       .brightness_set = toshiba_illumination_set,
-       .brightness_get = toshiba_illumination_get,
-};
-
-static struct toshiba_acpi_dev toshiba_acpi = {
-       .bt_name = "Toshiba Bluetooth",
-};
-
 /* Bluetooth rfkill handlers */
 
-static u32 hci_get_bt_present(bool *present)
+static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present)
 {
        u32 hci_result;
        u32 value, value2;
 
        value = 0;
        value2 = 0;
-       hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
+       hci_read2(dev, HCI_WIRELESS, &value, &value2, &hci_result);
        if (hci_result == HCI_SUCCESS)
                *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
 
        return hci_result;
 }
 
-static u32 hci_get_radio_state(bool *radio_state)
+static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state)
 {
        u32 hci_result;
        u32 value, value2;
 
        value = 0;
        value2 = 0x0001;
-       hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
+       hci_read2(dev, HCI_WIRELESS, &value, &value2, &hci_result);
 
        *radio_state = value & HCI_WIRELESS_KILL_SWITCH;
        return hci_result;
@@ -436,8 +409,8 @@ static int bt_rfkill_set_block(void *data, bool blocked)
        value = (blocked == false);
 
        mutex_lock(&dev->mutex);
-       if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) {
-               err = -EBUSY;
+       if (hci_get_radio_state(dev, &radio_state) != HCI_SUCCESS) {
+               err = -EIO;
                goto out;
        }
 
@@ -446,11 +419,11 @@ static int bt_rfkill_set_block(void *data, bool blocked)
                goto out;
        }
 
-       hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
-       hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
+       hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
+       hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
 
        if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
-               err = -EBUSY;
+               err = -EIO;
        else
                err = 0;
  out:
@@ -467,7 +440,7 @@ static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
 
        mutex_lock(&dev->mutex);
 
-       hci_result = hci_get_radio_state(&value);
+       hci_result = hci_get_radio_state(dev, &value);
        if (hci_result != HCI_SUCCESS) {
                /* Can't do anything useful */
                mutex_unlock(&dev->mutex);
@@ -488,63 +461,64 @@ static const struct rfkill_ops toshiba_rfk_ops = {
 };
 
 static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
-static struct backlight_device *toshiba_backlight_device;
-static int force_fan;
-static int last_key_event;
-static int key_event_valid;
 
 static int get_lcd(struct backlight_device *bd)
 {
+       struct toshiba_acpi_dev *dev = bl_get_data(bd);
        u32 hci_result;
        u32 value;
 
-       hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result);
-       if (hci_result == HCI_SUCCESS) {
+       hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result);
+       if (hci_result == HCI_SUCCESS)
                return (value >> HCI_LCD_BRIGHTNESS_SHIFT);
-       } else
-               return -EFAULT;
+
+       return -EIO;
 }
 
 static int lcd_proc_show(struct seq_file *m, void *v)
 {
-       int value = get_lcd(NULL);
+       struct toshiba_acpi_dev *dev = m->private;
+       int value;
+
+       if (!dev->backlight_dev)
+               return -ENODEV;
 
+       value = get_lcd(dev->backlight_dev);
        if (value >= 0) {
                seq_printf(m, "brightness:              %d\n", value);
                seq_printf(m, "brightness_levels:       %d\n",
                             HCI_LCD_BRIGHTNESS_LEVELS);
-       } else {
-               pr_err("Error reading LCD brightness\n");
+               return 0;
        }
 
-       return 0;
+       pr_err("Error reading LCD brightness\n");
+       return -EIO;
 }
 
 static int lcd_proc_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, lcd_proc_show, NULL);
+       return single_open(file, lcd_proc_show, PDE(inode)->data);
 }
 
-static int set_lcd(int value)
+static int set_lcd(struct toshiba_acpi_dev *dev, int value)
 {
        u32 hci_result;
 
        value = value << HCI_LCD_BRIGHTNESS_SHIFT;
-       hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
-       if (hci_result != HCI_SUCCESS)
-               return -EFAULT;
-
-       return 0;
+       hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result);
+       return hci_result == HCI_SUCCESS ? 0 : -EIO;
 }
 
 static int set_lcd_status(struct backlight_device *bd)
 {
-       return set_lcd(bd->props.brightness);
+       struct toshiba_acpi_dev *dev = bl_get_data(bd);
+       return set_lcd(dev, bd->props.brightness);
 }
 
 static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
                              size_t count, loff_t *pos)
 {
+       struct toshiba_acpi_dev *dev = PDE(file->f_path.dentry->d_inode)->data;
        char cmd[42];
        size_t len;
        int value;
@@ -557,7 +531,7 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
 
        if (sscanf(cmd, " brightness : %i", &value) == 1 &&
            value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
-               ret = set_lcd(value);
+               ret = set_lcd(dev, value);
                if (ret == 0)
                        ret = count;
        } else {
@@ -575,41 +549,49 @@ static const struct file_operations lcd_proc_fops = {
        .write          = lcd_proc_write,
 };
 
-static int video_proc_show(struct seq_file *m, void *v)
+static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status)
 {
        u32 hci_result;
+
+       hci_read1(dev, HCI_VIDEO_OUT, status, &hci_result);
+       return hci_result == HCI_SUCCESS ? 0 : -EIO;
+}
+
+static int video_proc_show(struct seq_file *m, void *v)
+{
+       struct toshiba_acpi_dev *dev = m->private;
        u32 value;
+       int ret;
 
-       hci_read1(HCI_VIDEO_OUT, &value, &hci_result);
-       if (hci_result == HCI_SUCCESS) {
+       ret = get_video_status(dev, &value);
+       if (!ret) {
                int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
                int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
                int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
                seq_printf(m, "lcd_out:                 %d\n", is_lcd);
                seq_printf(m, "crt_out:                 %d\n", is_crt);
                seq_printf(m, "tv_out:                  %d\n", is_tv);
-       } else {
-               pr_err("Error reading video out status\n");
        }
 
-       return 0;
+       return ret;
 }
 
 static int video_proc_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, video_proc_show, NULL);
+       return single_open(file, video_proc_show, PDE(inode)->data);
 }
 
 static ssize_t video_proc_write(struct file *file, const char __user *buf,
                                size_t count, loff_t *pos)
 {
+       struct toshiba_acpi_dev *dev = PDE(file->f_path.dentry->d_inode)->data;
        char *cmd, *buffer;
+       int ret;
        int value;
        int remain = count;
        int lcd_out = -1;
        int crt_out = -1;
        int tv_out = -1;
-       u32 hci_result;
        u32 video_out;
 
        cmd = kmalloc(count + 1, GFP_KERNEL);
@@ -644,8 +626,8 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf,
 
        kfree(cmd);
 
-       hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result);
-       if (hci_result == HCI_SUCCESS) {
+       ret = get_video_status(dev, &video_out);
+       if (!ret) {
                unsigned int new_video_out = video_out;
                if (lcd_out != -1)
                        _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
@@ -656,12 +638,10 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf,
                /* To avoid unnecessary video disruption, only write the new
                 * video setting if something changed. */
                if (new_video_out != video_out)
-                       write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
-       } else {
-               return -EFAULT;
+                       ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
        }
 
-       return count;
+       return ret ? ret : count;
 }
 
 static const struct file_operations video_proc_fops = {
@@ -673,30 +653,38 @@ static const struct file_operations video_proc_fops = {
        .write          = video_proc_write,
 };
 
-static int fan_proc_show(struct seq_file *m, void *v)
+static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status)
 {
        u32 hci_result;
+
+       hci_read1(dev, HCI_FAN, status, &hci_result);
+       return hci_result == HCI_SUCCESS ? 0 : -EIO;
+}
+
+static int fan_proc_show(struct seq_file *m, void *v)
+{
+       struct toshiba_acpi_dev *dev = m->private;
+       int ret;
        u32 value;
 
-       hci_read1(HCI_FAN, &value, &hci_result);
-       if (hci_result == HCI_SUCCESS) {
+       ret = get_fan_status(dev, &value);
+       if (!ret) {
                seq_printf(m, "running:                 %d\n", (value > 0));
-               seq_printf(m, "force_on:                %d\n", force_fan);
-       } else {
-               pr_err("Error reading fan status\n");
+               seq_printf(m, "force_on:                %d\n", dev->force_fan);
        }
 
-       return 0;
+       return ret;
 }
 
 static int fan_proc_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, fan_proc_show, NULL);
+       return single_open(file, fan_proc_show, PDE(inode)->data);
 }
 
 static ssize_t fan_proc_write(struct file *file, const char __user *buf,
                              size_t count, loff_t *pos)
 {
+       struct toshiba_acpi_dev *dev = PDE(file->f_path.dentry->d_inode)->data;
        char cmd[42];
        size_t len;
        int value;
@@ -709,11 +697,11 @@ static ssize_t fan_proc_write(struct file *file, const char __user *buf,
 
        if (sscanf(cmd, " force_on : %i", &value) == 1 &&
            value >= 0 && value <= 1) {
-               hci_write1(HCI_FAN, value, &hci_result);
+               hci_write1(dev, HCI_FAN, value, &hci_result);
                if (hci_result != HCI_SUCCESS)
-                       return -EFAULT;
+                       return -EIO;
                else
-                       force_fan = value;
+                       dev->force_fan = value;
        } else {
                return -EINVAL;
        }
@@ -732,42 +720,43 @@ static const struct file_operations fan_proc_fops = {
 
 static int keys_proc_show(struct seq_file *m, void *v)
 {
+       struct toshiba_acpi_dev *dev = m->private;
        u32 hci_result;
        u32 value;
 
-       if (!key_event_valid) {
-               hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
+       if (!dev->key_event_valid) {
+               hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
                if (hci_result == HCI_SUCCESS) {
-                       key_event_valid = 1;
-                       last_key_event = value;
+                       dev->key_event_valid = 1;
+                       dev->last_key_event = value;
                } else if (hci_result == HCI_EMPTY) {
                        /* better luck next time */
                } else if (hci_result == HCI_NOT_SUPPORTED) {
                        /* This is a workaround for an unresolved issue on
                         * some machines where system events sporadically
                         * become disabled. */
-                       hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
+                       hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
                        pr_notice("Re-enabled hotkeys\n");
                } else {
                        pr_err("Error reading hotkey status\n");
-                       goto end;
+                       return -EIO;
                }
        }
 
-       seq_printf(m, "hotkey_ready:            %d\n", key_event_valid);
-       seq_printf(m, "hotkey:                  0x%04x\n", last_key_event);
-end:
+       seq_printf(m, "hotkey_ready:            %d\n", dev->key_event_valid);
+       seq_printf(m, "hotkey:                  0x%04x\n", dev->last_key_event);
        return 0;
 }
 
 static int keys_proc_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, keys_proc_show, NULL);
+       return single_open(file, keys_proc_show, PDE(inode)->data);
 }
 
 static ssize_t keys_proc_write(struct file *file, const char __user *buf,
                               size_t count, loff_t *pos)
 {
+       struct toshiba_acpi_dev *dev = PDE(file->f_path.dentry->d_inode)->data;
        char cmd[42];
        size_t len;
        int value;
@@ -778,7 +767,7 @@ static ssize_t keys_proc_write(struct file *file, const char __user *buf,
        cmd[len] = '\0';
 
        if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) {
-               key_event_valid = 0;
+               dev->key_event_valid = 0;
        } else {
                return -EINVAL;
        }
@@ -820,21 +809,35 @@ static const struct file_operations version_proc_fops = {
 
 #define PROC_TOSHIBA           "toshiba"
 
-static void __init create_toshiba_proc_entries(void)
+static void __devinit
+create_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
 {
-       proc_create("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, &lcd_proc_fops);
-       proc_create("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, &video_proc_fops);
-       proc_create("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, &fan_proc_fops);
-       proc_create("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, &keys_proc_fops);
-       proc_create("version", S_IRUGO, toshiba_proc_dir, &version_proc_fops);
+       if (dev->backlight_dev)
+               proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir,
+                                &lcd_proc_fops, dev);
+       if (dev->video_supported)
+               proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir,
+                                &video_proc_fops, dev);
+       if (dev->fan_supported)
+               proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir,
+                                &fan_proc_fops, dev);
+       if (dev->hotkey_dev)
+               proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir,
+                                &keys_proc_fops, dev);
+       proc_create_data("version", S_IRUGO, toshiba_proc_dir,
+                        &version_proc_fops, dev);
 }
 
-static void remove_toshiba_proc_entries(void)
+static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
 {
-       remove_proc_entry("lcd", toshiba_proc_dir);
-       remove_proc_entry("video", toshiba_proc_dir);
-       remove_proc_entry("fan", toshiba_proc_dir);
-       remove_proc_entry("keys", toshiba_proc_dir);
+       if (dev->backlight_dev)
+               remove_proc_entry("lcd", toshiba_proc_dir);
+       if (dev->video_supported)
+               remove_proc_entry("video", toshiba_proc_dir);
+       if (dev->fan_supported)
+               remove_proc_entry("fan", toshiba_proc_dir);
+       if (dev->hotkey_dev)
+               remove_proc_entry("keys", toshiba_proc_dir);
        remove_proc_entry("version", toshiba_proc_dir);
 }
 
@@ -843,224 +846,256 @@ static const struct backlight_ops toshiba_backlight_data = {
         .update_status  = set_lcd_status,
 };
 
-static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
-{
-       u32 hci_result, value;
-
-       if (event != 0x80)
-               return;
-       do {
-               hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
-               if (hci_result == HCI_SUCCESS) {
-                       if (value == 0x100)
-                               continue;
-                       /* act on key press; ignore key release */
-                       if (value & 0x80)
-                               continue;
-
-                       if (!sparse_keymap_report_event(toshiba_acpi.hotkey_dev,
-                                                       value, 1, true)) {
-                               pr_info("Unknown key %x\n",
-                                      value);
-                       }
-               } else if (hci_result == HCI_NOT_SUPPORTED) {
-                       /* This is a workaround for an unresolved issue on
-                        * some machines where system events sporadically
-                        * become disabled. */
-                       hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
-                       pr_notice("Re-enabled hotkeys\n");
-               }
-       } while (hci_result != HCI_EMPTY);
-}
-
-static int __init toshiba_acpi_setup_keyboard(char *device)
+static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
 {
        acpi_status status;
        int error;
 
-       status = acpi_get_handle(NULL, device, &toshiba_acpi.handle);
-       if (ACPI_FAILURE(status)) {
-               pr_info("Unable to get notification device\n");
-               return -ENODEV;
-       }
-
-       toshiba_acpi.hotkey_dev = input_allocate_device();
-       if (!toshiba_acpi.hotkey_dev) {
+       dev->hotkey_dev = input_allocate_device();
+       if (!dev->hotkey_dev) {
                pr_info("Unable to register input device\n");
                return -ENOMEM;
        }
 
-       toshiba_acpi.hotkey_dev->name = "Toshiba input device";
-       toshiba_acpi.hotkey_dev->phys = device;
-       toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST;
+       dev->hotkey_dev->name = "Toshiba input device";
+       dev->hotkey_dev->phys = "toshiba_acpi/input0";
+       dev->hotkey_dev->id.bustype = BUS_HOST;
 
-       error = sparse_keymap_setup(toshiba_acpi.hotkey_dev,
-                                   toshiba_acpi_keymap, NULL);
+       error = sparse_keymap_setup(dev->hotkey_dev, toshiba_acpi_keymap, NULL);
        if (error)
                goto err_free_dev;
 
-       status = acpi_install_notify_handler(toshiba_acpi.handle,
-                               ACPI_DEVICE_NOTIFY, toshiba_acpi_notify, NULL);
-       if (ACPI_FAILURE(status)) {
-               pr_info("Unable to install hotkey notification\n");
-               error = -ENODEV;
-               goto err_free_keymap;
-       }
-
-       status = acpi_evaluate_object(toshiba_acpi.handle, "ENAB", NULL, NULL);
+       status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL);
        if (ACPI_FAILURE(status)) {
                pr_info("Unable to enable hotkeys\n");
                error = -ENODEV;
-               goto err_remove_notify;
+               goto err_free_keymap;
        }
 
-       error = input_register_device(toshiba_acpi.hotkey_dev);
+       error = input_register_device(dev->hotkey_dev);
        if (error) {
                pr_info("Unable to register input device\n");
-               goto err_remove_notify;
+               goto err_free_keymap;
        }
 
        return 0;
 
- err_remove_notify:
-       acpi_remove_notify_handler(toshiba_acpi.handle,
-                                  ACPI_DEVICE_NOTIFY, toshiba_acpi_notify);
  err_free_keymap:
-       sparse_keymap_free(toshiba_acpi.hotkey_dev);
+       sparse_keymap_free(dev->hotkey_dev);
  err_free_dev:
-       input_free_device(toshiba_acpi.hotkey_dev);
-       toshiba_acpi.hotkey_dev = NULL;
+       input_free_device(dev->hotkey_dev);
+       dev->hotkey_dev = NULL;
        return error;
 }
 
-static void toshiba_acpi_exit(void)
+static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
 {
-       if (toshiba_acpi.hotkey_dev) {
-               acpi_remove_notify_handler(toshiba_acpi.handle,
-                               ACPI_DEVICE_NOTIFY, toshiba_acpi_notify);
-               sparse_keymap_free(toshiba_acpi.hotkey_dev);
-               input_unregister_device(toshiba_acpi.hotkey_dev);
+       struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
+
+       remove_toshiba_proc_entries(dev);
+
+       if (dev->hotkey_dev) {
+               input_unregister_device(dev->hotkey_dev);
+               sparse_keymap_free(dev->hotkey_dev);
        }
 
-       if (toshiba_acpi.bt_rfk) {
-               rfkill_unregister(toshiba_acpi.bt_rfk);
-               rfkill_destroy(toshiba_acpi.bt_rfk);
+       if (dev->bt_rfk) {
+               rfkill_unregister(dev->bt_rfk);
+               rfkill_destroy(dev->bt_rfk);
        }
 
-       if (toshiba_backlight_device)
-               backlight_device_unregister(toshiba_backlight_device);
+       if (dev->backlight_dev)
+               backlight_device_unregister(dev->backlight_dev);
 
-       remove_toshiba_proc_entries();
+       if (dev->illumination_supported)
+               led_classdev_unregister(&dev->led_dev);
 
-       if (toshiba_proc_dir)
-               remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+       kfree(dev);
+
+       return 0;
+}
+
+static const char * __devinit find_hci_method(acpi_handle handle)
+{
+       acpi_status status;
+       acpi_handle hci_handle;
 
-       if (toshiba_acpi.illumination_installed)
-               led_classdev_unregister(&toshiba_led);
+       status = acpi_get_handle(handle, "GHCI", &hci_handle);
+       if (ACPI_SUCCESS(status))
+               return "GHCI";
 
-       platform_device_unregister(toshiba_acpi.p_dev);
+       status = acpi_get_handle(handle, "SPFC", &hci_handle);
+       if (ACPI_SUCCESS(status))
+               return "SPFC";
 
-       return;
+       return NULL;
 }
 
-static int __init toshiba_acpi_init(void)
+static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
 {
+       struct toshiba_acpi_dev *dev;
+       const char *hci_method;
        u32 hci_result;
+       u32 dummy;
        bool bt_present;
        int ret = 0;
        struct backlight_properties props;
 
-       if (acpi_disabled)
-               return -ENODEV;
-
-       /* simple device detection: look for HCI method */
-       if (is_valid_acpi_path(TOSH_INTERFACE_1 GHCI_METHOD)) {
-               method_hci = TOSH_INTERFACE_1 GHCI_METHOD;
-               if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_1))
-                       pr_info("Unable to activate hotkeys\n");
-       } else if (is_valid_acpi_path(TOSH_INTERFACE_2 GHCI_METHOD)) {
-               method_hci = TOSH_INTERFACE_2 GHCI_METHOD;
-               if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_2))
-                       pr_info("Unable to activate hotkeys\n");
-       } else
-               return -ENODEV;
-
        pr_info("Toshiba Laptop ACPI Extras version %s\n",
               TOSHIBA_ACPI_VERSION);
-       pr_info("    HCI method: %s\n", method_hci);
-
-       mutex_init(&toshiba_acpi.mutex);
-
-       toshiba_acpi.p_dev = platform_device_register_simple("toshiba_acpi",
-                                                             -1, NULL, 0);
-       if (IS_ERR(toshiba_acpi.p_dev)) {
-               ret = PTR_ERR(toshiba_acpi.p_dev);
-               pr_err("unable to register platform device\n");
-               toshiba_acpi.p_dev = NULL;
-               toshiba_acpi_exit();
-               return ret;
+
+       hci_method = find_hci_method(acpi_dev->handle);
+       if (!hci_method) {
+               pr_err("HCI interface not found\n");
+               return -ENODEV;
        }
 
-       force_fan = 0;
-       key_event_valid = 0;
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+       dev->acpi_dev = acpi_dev;
+       dev->method_hci = hci_method;
+       acpi_dev->driver_data = dev;
 
-       /* enable event fifo */
-       hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
+       if (toshiba_acpi_setup_keyboard(dev))
+               pr_info("Unable to activate hotkeys\n");
 
-       toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
-       if (!toshiba_proc_dir) {
-               toshiba_acpi_exit();
-               return -ENODEV;
-       } else {
-               create_toshiba_proc_entries();
-       }
+       mutex_init(&dev->mutex);
+
+       /* enable event fifo */
+       hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
 
        props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
-       toshiba_backlight_device = backlight_device_register("toshiba",
-                                                            &toshiba_acpi.p_dev->dev,
-                                                            NULL,
-                                                            &toshiba_backlight_data,
-                                                            &props);
-        if (IS_ERR(toshiba_backlight_device)) {
-               ret = PTR_ERR(toshiba_backlight_device);
+       dev->backlight_dev = backlight_device_register("toshiba",
+                                                      &acpi_dev->dev,
+                                                      dev,
+                                                      &toshiba_backlight_data,
+                                                      &props);
+       if (IS_ERR(dev->backlight_dev)) {
+               ret = PTR_ERR(dev->backlight_dev);
 
                pr_err("Could not register toshiba backlight device\n");
-               toshiba_backlight_device = NULL;
-               toshiba_acpi_exit();
-               return ret;
+               dev->backlight_dev = NULL;
+               goto error;
        }
+       dev->backlight_dev->props.brightness = get_lcd(dev->backlight_dev);
 
        /* Register rfkill switch for Bluetooth */
-       if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
-               toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name,
-                                                  &toshiba_acpi.p_dev->dev,
-                                                  RFKILL_TYPE_BLUETOOTH,
-                                                  &toshiba_rfk_ops,
-                                                  &toshiba_acpi);
-               if (!toshiba_acpi.bt_rfk) {
+       if (hci_get_bt_present(dev, &bt_present) == HCI_SUCCESS && bt_present) {
+               dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth",
+                                          &acpi_dev->dev,
+                                          RFKILL_TYPE_BLUETOOTH,
+                                          &toshiba_rfk_ops,
+                                          dev);
+               if (!dev->bt_rfk) {
                        pr_err("unable to allocate rfkill device\n");
-                       toshiba_acpi_exit();
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto error;
                }
 
-               ret = rfkill_register(toshiba_acpi.bt_rfk);
+               ret = rfkill_register(dev->bt_rfk);
                if (ret) {
                        pr_err("unable to register rfkill device\n");
-                       rfkill_destroy(toshiba_acpi.bt_rfk);
-                       toshiba_acpi_exit();
-                       return ret;
+                       rfkill_destroy(dev->bt_rfk);
+                       goto error;
                }
        }
 
-       toshiba_acpi.illumination_installed = 0;
-       if (toshiba_illumination_available()) {
-               if (!led_classdev_register(&(toshiba_acpi.p_dev->dev),
-                                          &toshiba_led))
-                       toshiba_acpi.illumination_installed = 1;
+       if (toshiba_illumination_available(dev)) {
+               dev->led_dev.name = "toshiba::illumination";
+               dev->led_dev.max_brightness = 1;
+               dev->led_dev.brightness_set = toshiba_illumination_set;
+               dev->led_dev.brightness_get = toshiba_illumination_get;
+               if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev))
+                       dev->illumination_supported = 1;
        }
 
+       /* Determine whether or not BIOS supports fan and video interfaces */
+
+       ret = get_video_status(dev, &dummy);
+       dev->video_supported = !ret;
+
+       ret = get_fan_status(dev, &dummy);
+       dev->fan_supported = !ret;
+
+       create_toshiba_proc_entries(dev);
+
        return 0;
+
+error:
+       toshiba_acpi_remove(acpi_dev, 0);
+       return ret;
+}
+
+static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
+{
+       struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
+       u32 hci_result, value;
+
+       if (event != 0x80)
+               return;
+       do {
+               hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
+               if (hci_result == HCI_SUCCESS) {
+                       if (value == 0x100)
+                               continue;
+                       /* act on key press; ignore key release */
+                       if (value & 0x80)
+                               continue;
+
+                       if (!sparse_keymap_report_event(dev->hotkey_dev,
+                                                       value, 1, true)) {
+                               pr_info("Unknown key %x\n",
+                                      value);
+                       }
+               } else if (hci_result == HCI_NOT_SUPPORTED) {
+                       /* This is a workaround for an unresolved issue on
+                        * some machines where system events sporadically
+                        * become disabled. */
+                       hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
+                       pr_notice("Re-enabled hotkeys\n");
+               }
+       } while (hci_result != HCI_EMPTY);
+}
+
+
+static struct acpi_driver toshiba_acpi_driver = {
+       .name   = "Toshiba ACPI driver",
+       .owner  = THIS_MODULE,
+       .ids    = toshiba_device_ids,
+       .flags  = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
+       .ops    = {
+               .add            = toshiba_acpi_add,
+               .remove         = toshiba_acpi_remove,
+               .notify         = toshiba_acpi_notify,
+       },
+};
+
+static int __init toshiba_acpi_init(void)
+{
+       int ret;
+
+       toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
+       if (!toshiba_proc_dir) {
+               pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
+               return -ENODEV;
+       }
+
+       ret = acpi_bus_register_driver(&toshiba_acpi_driver);
+       if (ret) {
+               pr_err("Failed to register ACPI driver: %d\n", ret);
+               remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+       }
+
+       return ret;
+}
+
+static void __exit toshiba_acpi_exit(void)
+{
+       acpi_bus_unregister_driver(&toshiba_acpi_driver);
+       if (toshiba_proc_dir)
+               remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
 }
 
 module_init(toshiba_acpi_init);
index f23d5a8..9b88be4 100644 (file)
@@ -754,9 +754,13 @@ static void wmi_free_devices(void)
        struct wmi_block *wblock, *next;
 
        /* Delete devices for all the GUIDs */
-       list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
+       list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
+               list_del(&wblock->list);
                if (wblock->dev.class)
                        device_unregister(&wblock->dev);
+               else
+                       kfree(wblock);
+       }
 }
 
 static bool guid_already_parsed(const char *guid_string)
index a329613..d132c27 100644 (file)
@@ -34,8 +34,6 @@ source "drivers/staging/go7007/Kconfig"
 
 source "drivers/staging/cx25821/Kconfig"
 
-source "drivers/staging/tm6000/Kconfig"
-
 source "drivers/staging/cxd2099/Kconfig"
 
 source "drivers/staging/usbip/Kconfig"
@@ -142,8 +140,6 @@ source "drivers/staging/ste_rmi4/Kconfig"
 
 source "drivers/staging/gma500/Kconfig"
 
-source "drivers/staging/altera-stapl/Kconfig"
-
 source "drivers/staging/mei/Kconfig"
 
 source "drivers/staging/nvec/Kconfig"
index d7a5a04..936b7c2 100644 (file)
@@ -8,7 +8,6 @@ obj-$(CONFIG_ET131X)            += et131x/
 obj-$(CONFIG_SLICOSS)          += slicoss/
 obj-$(CONFIG_VIDEO_GO7007)     += go7007/
 obj-$(CONFIG_VIDEO_CX25821)    += cx25821/
-obj-$(CONFIG_VIDEO_TM6000)     += tm6000/
 obj-$(CONFIG_DVB_CXD2099)      += cxd2099/
 obj-$(CONFIG_LIRC_STAGING)     += lirc/
 obj-$(CONFIG_USBIP_CORE)       += usbip/
@@ -59,7 +58,6 @@ obj-$(CONFIG_BCM_WIMAX)               += bcm/
 obj-$(CONFIG_FT1000)           += ft1000/
 obj-$(CONFIG_SND_INTEL_SST)    += intel_sst/
 obj-$(CONFIG_SPEAKUP)          += speakup/
-obj-$(CONFIG_ALTERA_STAPL)     +=altera-stapl/
 obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217)      += cptm1217/
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)   += ste_rmi4/
 obj-$(CONFIG_DRM_PSB)          += gma500/
diff --git a/drivers/staging/altera-stapl/Kconfig b/drivers/staging/altera-stapl/Kconfig
deleted file mode 100644 (file)
index b653732..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-config ALTERA_STAPL
-       tristate "Altera FPGA firmware download module"
-       depends on I2C
-       default n
-       help
-         An Altera FPGA module. Say Y when you want to support this tool.
diff --git a/drivers/staging/altera-stapl/Makefile b/drivers/staging/altera-stapl/Makefile
deleted file mode 100644 (file)
index ddeede3..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-altera-stapl-y := altera-lpt.o altera-jtag.o altera-comp.o altera.o
-
-obj-$(CONFIG_ALTERA_STAPL) += altera-stapl.o
diff --git a/drivers/staging/altera-stapl/altera-comp.c b/drivers/staging/altera-stapl/altera-comp.c
deleted file mode 100644 (file)
index 49b103b..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * altera-comp.c
- *
- * altera FPGA driver
- *
- * Copyright (C) Altera Corporation 1998-2001
- * Copyright (C) 2010 NetUP Inc.
- * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include "altera-exprt.h"
-
-#define        SHORT_BITS              16
-#define        CHAR_BITS               8
-#define        DATA_BLOB_LENGTH        3
-#define        MATCH_DATA_LENGTH       8192
-#define ALTERA_REQUEST_SIZE    1024
-#define ALTERA_BUFFER_SIZE     (MATCH_DATA_LENGTH + ALTERA_REQUEST_SIZE)
-
-static u32 altera_bits_req(u32 n)
-{
-       u32 result = SHORT_BITS;
-
-       if (n == 0)
-               result = 1;
-       else {
-               /* Look for the highest non-zero bit position */
-               while ((n & (1 << (SHORT_BITS - 1))) == 0) {
-                       n <<= 1;
-                       --result;
-               }
-       }
-
-       return result;
-}
-
-static u32 altera_read_packed(u8 *buffer, u32 bits, u32 *bits_avail,
-                                                       u32 *in_index)
-{
-       u32 result = 0;
-       u32 shift = 0;
-       u32 databyte = 0;
-
-       while (bits > 0) {
-               databyte = buffer[*in_index];
-               result |= (((databyte >> (CHAR_BITS - *bits_avail))
-                       & (0xff >> (CHAR_BITS - *bits_avail))) << shift);
-
-               if (bits <= *bits_avail) {
-                       result &= (0xffff >> (SHORT_BITS - (bits + shift)));
-                       *bits_avail -= bits;
-                       bits = 0;
-               } else {
-                       ++(*in_index);
-                       shift += *bits_avail;
-                       bits -= *bits_avail;
-                       *bits_avail = CHAR_BITS;
-               }
-       }
-
-       return result;
-}
-
-u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version)
-{
-       u32 i, j, data_length = 0L;
-       u32 offset, length;
-       u32 match_data_length = MATCH_DATA_LENGTH;
-       u32 bits_avail = CHAR_BITS;
-       u32 in_index = 0L;
-
-       if (version > 0)
-               --match_data_length;
-
-       for (i = 0; i < out_length; ++i)
-               out[i] = 0;
-
-       /* Read number of bytes in data. */
-       for (i = 0; i < sizeof(in_length); ++i) {
-               data_length = data_length | (
-                       altera_read_packed(in,
-                                       CHAR_BITS,
-                                       &bits_avail,
-                                       &in_index) << (i * CHAR_BITS));
-       }
-
-       if (data_length > out_length) {
-               data_length = 0L;
-               return data_length;
-       }
-
-       i = 0;
-       while (i < data_length) {
-               /* A 0 bit indicates literal data. */
-               if (altera_read_packed(in, 1, &bits_avail,
-                                               &in_index) == 0) {
-                       for (j = 0; j < DATA_BLOB_LENGTH; ++j) {
-                               if (i < data_length) {
-                                       out[i] = (u8)altera_read_packed(in,
-                                                       CHAR_BITS,
-                                                       &bits_avail,
-                                                       &in_index);
-                                       i++;
-                               }
-                       }
-               } else {
-                       /* A 1 bit indicates offset/length to follow. */
-                       offset = altera_read_packed(in, altera_bits_req((s16)
-                                       (i > match_data_length ?
-                                               match_data_length : i)),
-                                       &bits_avail,
-                                       &in_index);
-                       length = altera_read_packed(in, CHAR_BITS,
-                                       &bits_avail,
-                                       &in_index);
-                       for (j = 0; j < length; ++j) {
-                               if (i < data_length) {
-                                       out[i] = out[i - offset];
-                                       i++;
-                               }
-                       }
-               }
-       }
-
-       return data_length;
-}
diff --git a/drivers/staging/altera-stapl/altera-exprt.h b/drivers/staging/altera-stapl/altera-exprt.h
deleted file mode 100644 (file)
index 39c38d8..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * altera-exprt.h
- *
- * altera FPGA driver
- *
- * Copyright (C) Altera Corporation 1998-2001
- * Copyright (C) 2010 NetUP Inc.
- * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
- *
- * 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 ALTERA_EXPRT_H
-#define ALTERA_EXPRT_H
-
-
-u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version);
-int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo);
-
-#endif /* ALTERA_EXPRT_H */
diff --git a/drivers/staging/altera-stapl/altera-jtag.c b/drivers/staging/altera-stapl/altera-jtag.c
deleted file mode 100644 (file)
index 8b1620b..0000000
+++ /dev/null
@@ -1,1021 +0,0 @@
-/*
- * altera-jtag.c
- *
- * altera FPGA driver
- *
- * Copyright (C) Altera Corporation 1998-2001
- * Copyright (C) 2010 NetUP Inc.
- * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include "altera.h"
-#include "altera-exprt.h"
-#include "altera-jtag.h"
-
-#define        alt_jtag_io(a, b, c)\
-               astate->config->jtag_io(astate->config->dev, a, b, c);
-
-#define        alt_malloc(a)   kzalloc(a, GFP_KERNEL);
-
-/*
- * This structure shows, for each JTAG state, which state is reached after
- * a single TCK clock cycle with TMS high or TMS low, respectively.  This
- * describes all possible state transitions in the JTAG state machine.
- */
-struct altera_jtag_machine {
-       enum altera_jtag_state tms_high;
-       enum altera_jtag_state tms_low;
-};
-
-static const struct altera_jtag_machine altera_transitions[] = {
-       /* RESET     */ { RESET,        IDLE },
-       /* IDLE      */ { DRSELECT,     IDLE },
-       /* DRSELECT  */ { IRSELECT,     DRCAPTURE },
-       /* DRCAPTURE */ { DREXIT1,      DRSHIFT },
-       /* DRSHIFT   */ { DREXIT1,      DRSHIFT },
-       /* DREXIT1   */ { DRUPDATE,     DRPAUSE },
-       /* DRPAUSE   */ { DREXIT2,      DRPAUSE },
-       /* DREXIT2   */ { DRUPDATE,     DRSHIFT },
-       /* DRUPDATE  */ { DRSELECT,     IDLE },
-       /* IRSELECT  */ { RESET,        IRCAPTURE },
-       /* IRCAPTURE */ { IREXIT1,      IRSHIFT },
-       /* IRSHIFT   */ { IREXIT1,      IRSHIFT },
-       /* IREXIT1   */ { IRUPDATE,     IRPAUSE },
-       /* IRPAUSE   */ { IREXIT2,      IRPAUSE },
-       /* IREXIT2   */ { IRUPDATE,     IRSHIFT },
-       /* IRUPDATE  */ { DRSELECT,     IDLE }
-};
-
-/*
- * This table contains the TMS value to be used to take the NEXT STEP on
- * the path to the desired state.  The array index is the current state,
- * and the bit position is the desired endstate.  To find out which state
- * is used as the intermediate state, look up the TMS value in the
- * altera_transitions[] table.
- */
-static const u16 altera_jtag_path_map[16] = {
-       /* RST  RTI     SDRS    CDR     SDR     E1DR    PDR     E2DR */
-       0x0001, 0xFFFD, 0xFE01, 0xFFE7, 0xFFEF, 0xFF0F, 0xFFBF, 0xFFFF,
-       /* UDR  SIRS    CIR     SIR     E1IR    PIR     E2IR    UIR */
-       0xFEFD, 0x0001, 0xF3FF, 0xF7FF, 0x87FF, 0xDFFF, 0xFFFF, 0x7FFD
-};
-
-/* Flag bits for alt_jtag_io() function */
-#define TMS_HIGH   1
-#define TMS_LOW    0
-#define TDI_HIGH   1
-#define TDI_LOW    0
-#define READ_TDO   1
-#define IGNORE_TDO 0
-
-int altera_jinit(struct altera_state *astate)
-{
-       struct altera_jtag *js = &astate->js;
-
-       /* initial JTAG state is unknown */
-       js->jtag_state = ILLEGAL_JTAG_STATE;
-
-       /* initialize to default state */
-       js->drstop_state = IDLE;
-       js->irstop_state = IDLE;
-       js->dr_pre  = 0;
-       js->dr_post = 0;
-       js->ir_pre  = 0;
-       js->ir_post = 0;
-       js->dr_length    = 0;
-       js->ir_length    = 0;
-
-       js->dr_pre_data  = NULL;
-       js->dr_post_data = NULL;
-       js->ir_pre_data  = NULL;
-       js->ir_post_data = NULL;
-       js->dr_buffer    = NULL;
-       js->ir_buffer    = NULL;
-
-       return 0;
-}
-
-int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state)
-{
-       js->drstop_state = state;
-
-       return 0;
-}
-
-int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state)
-{
-       js->irstop_state = state;
-
-       return 0;
-}
-
-int altera_set_dr_pre(struct altera_jtag *js,
-                               u32 count, u32 start_index,
-                               u8 *preamble_data)
-{
-       int status = 0;
-       u32 i;
-       u32 j;
-
-       if (count > js->dr_pre) {
-               kfree(js->dr_pre_data);
-               js->dr_pre_data = (u8 *)alt_malloc((count + 7) >> 3);
-               if (js->dr_pre_data == NULL)
-                       status = -ENOMEM;
-               else
-                       js->dr_pre = count;
-       } else
-               js->dr_pre = count;
-
-       if (status == 0) {
-               for (i = 0; i < count; ++i) {
-                       j = i + start_index;
-
-                       if (preamble_data == NULL)
-                               js->dr_pre_data[i >> 3] |= (1 << (i & 7));
-                       else {
-                               if (preamble_data[j >> 3] & (1 << (j & 7)))
-                                       js->dr_pre_data[i >> 3] |=
-                                                       (1 << (i & 7));
-                               else
-                                       js->dr_pre_data[i >> 3] &=
-                                                       ~(u32)(1 << (i & 7));
-
-                       }
-               }
-       }
-
-       return status;
-}
-
-int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index,
-                                                       u8 *preamble_data)
-{
-       int status = 0;
-       u32 i;
-       u32 j;
-
-       if (count > js->ir_pre) {
-               kfree(js->ir_pre_data);
-               js->ir_pre_data = (u8 *)alt_malloc((count + 7) >> 3);
-               if (js->ir_pre_data == NULL)
-                       status = -ENOMEM;
-               else
-                       js->ir_pre = count;
-
-       } else
-               js->ir_pre = count;
-
-       if (status == 0) {
-               for (i = 0; i < count; ++i) {
-                       j = i + start_index;
-                       if (preamble_data == NULL)
-                               js->ir_pre_data[i >> 3] |= (1 << (i & 7));
-                       else {
-                               if (preamble_data[j >> 3] & (1 << (j & 7)))
-                                       js->ir_pre_data[i >> 3] |=
-                                                       (1 << (i & 7));
-                               else
-                                       js->ir_pre_data[i >> 3] &=
-                                                       ~(u32)(1 << (i & 7));
-
-                       }
-               }
-       }
-
-       return status;
-}
-
-int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index,
-                                               u8 *postamble_data)
-{
-       int status = 0;
-       u32 i;
-       u32 j;
-
-       if (count > js->dr_post) {
-               kfree(js->dr_post_data);
-               js->dr_post_data = (u8 *)alt_malloc((count + 7) >> 3);
-
-               if (js->dr_post_data == NULL)
-                       status = -ENOMEM;
-               else
-                       js->dr_post = count;
-
-       } else
-               js->dr_post = count;
-
-       if (status == 0) {
-               for (i = 0; i < count; ++i) {
-                       j = i + start_index;
-
-                       if (postamble_data == NULL)
-                               js->dr_post_data[i >> 3] |= (1 << (i & 7));
-                       else {
-                               if (postamble_data[j >> 3] & (1 << (j & 7)))
-                                       js->dr_post_data[i >> 3] |=
-                                                               (1 << (i & 7));
-                               else
-                                       js->dr_post_data[i >> 3] &=
-                                           ~(u32)(1 << (i & 7));
-
-                       }
-               }
-       }
-
-       return status;
-}
-
-int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index,
-                                               u8 *postamble_data)
-{
-       int status = 0;
-       u32 i;
-       u32 j;
-
-       if (count > js->ir_post) {
-               kfree(js->ir_post_data);
-               js->ir_post_data = (u8 *)alt_malloc((count + 7) >> 3);
-               if (js->ir_post_data == NULL)
-                       status = -ENOMEM;
-               else
-                       js->ir_post = count;
-
-       } else
-               js->ir_post = count;
-
-       if (status != 0)
-               return status;
-
-       for (i = 0; i < count; ++i) {
-               j = i + start_index;
-
-               if (postamble_data == NULL)
-                       js->ir_post_data[i >> 3] |= (1 << (i & 7));
-               else {
-                       if (postamble_data[j >> 3] & (1 << (j & 7)))
-                               js->ir_post_data[i >> 3] |= (1 << (i & 7));
-                       else
-                               js->ir_post_data[i >> 3] &=
-                                   ~(u32)(1 << (i & 7));
-
-               }
-       }
-
-       return status;
-}
-
-static void altera_jreset_idle(struct altera_state *astate)
-{
-       struct altera_jtag *js = &astate->js;
-       int i;
-       /* Go to Test Logic Reset (no matter what the starting state may be) */
-       for (i = 0; i < 5; ++i)
-               alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO);
-
-       /* Now step to Run Test / Idle */
-       alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO);
-       js->jtag_state = IDLE;
-}
-
-int altera_goto_jstate(struct altera_state *astate,
-                                       enum altera_jtag_state state)
-{
-       struct altera_jtag *js = &astate->js;
-       int tms;
-       int count = 0;
-       int status = 0;
-
-       if (js->jtag_state == ILLEGAL_JTAG_STATE)
-               /* initialize JTAG chain to known state */
-               altera_jreset_idle(astate);
-
-       if (js->jtag_state == state) {
-               /*
-                * We are already in the desired state.
-                * If it is a stable state, loop here.
-                * Otherwise do nothing (no clock cycles).
-                */
-               if ((state == IDLE) || (state == DRSHIFT) ||
-                       (state == DRPAUSE) || (state == IRSHIFT) ||
-                               (state == IRPAUSE)) {
-                       alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO);
-               } else if (state == RESET)
-                       alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO);
-
-       } else {
-               while ((js->jtag_state != state) && (count < 9)) {
-                       /* Get TMS value to take a step toward desired state */
-                       tms = (altera_jtag_path_map[js->jtag_state] &
-                                                       (1 << state))
-                                                       ? TMS_HIGH : TMS_LOW;
-
-                       /* Take a step */
-                       alt_jtag_io(tms, TDI_LOW, IGNORE_TDO);
-
-                       if (tms)
-                               js->jtag_state =
-                                       altera_transitions[js->jtag_state].tms_high;
-                       else
-                               js->jtag_state =
-                                       altera_transitions[js->jtag_state].tms_low;
-
-                       ++count;
-               }
-       }
-
-       if (js->jtag_state != state)
-               status = -EREMOTEIO;
-
-       return status;
-}
-
-int altera_wait_cycles(struct altera_state *astate,
-                                       s32 cycles,
-                                       enum altera_jtag_state wait_state)
-{
-       struct altera_jtag *js = &astate->js;
-       int tms;
-       s32 count;
-       int status = 0;
-
-       if (js->jtag_state != wait_state)
-               status = altera_goto_jstate(astate, wait_state);
-
-       if (status == 0) {
-               /*
-                * Set TMS high to loop in RESET state
-                * Set TMS low to loop in any other stable state
-                */
-               tms = (wait_state == RESET) ? TMS_HIGH : TMS_LOW;
-
-               for (count = 0L; count < cycles; count++)
-                       alt_jtag_io(tms, TDI_LOW, IGNORE_TDO);
-
-       }
-
-       return status;
-}
-
-int altera_wait_msecs(struct altera_state *astate,
-                       s32 microseconds, enum altera_jtag_state wait_state)
-/*
- * Causes JTAG hardware to sit in the specified stable
- * state for the specified duration of real time.  If
- * no JTAG operations have been performed yet, then only
- * a delay is performed.  This permits the WAIT USECS
- * statement to be used in VECTOR programs without causing
- * any JTAG operations.
- * Returns 0 for success, else appropriate error code.
- */
-{
-       struct altera_jtag *js = &astate->js;
-       int status = 0;
-
-       if ((js->jtag_state != ILLEGAL_JTAG_STATE) &&
-           (js->jtag_state != wait_state))
-               status = altera_goto_jstate(astate, wait_state);
-
-       if (status == 0)
-               /* Wait for specified time interval */
-               udelay(microseconds);
-
-       return status;
-}
-
-static void altera_concatenate_data(u8 *buffer,
-                               u8 *preamble_data,
-                               u32 preamble_count,
-                               u8 *target_data,
-                               u32 start_index,
-                               u32 target_count,
-                               u8 *postamble_data,
-                               u32 postamble_count)
-/*
- * Copies preamble data, target data, and postamble data
- * into one buffer for IR or DR scans.
- */
-{
-       u32 i, j, k;
-
-       for (i = 0L; i < preamble_count; ++i) {
-               if (preamble_data[i >> 3L] & (1L << (i & 7L)))
-                       buffer[i >> 3L] |= (1L << (i & 7L));
-               else
-                       buffer[i >> 3L] &= ~(u32)(1L << (i & 7L));
-
-       }
-
-       j = start_index;
-       k = preamble_count + target_count;
-       for (; i < k; ++i, ++j) {
-               if (target_data[j >> 3L] & (1L << (j & 7L)))
-                       buffer[i >> 3L] |= (1L << (i & 7L));
-               else
-                       buffer[i >> 3L] &= ~(u32)(1L << (i & 7L));
-
-       }
-
-       j = 0L;
-       k = preamble_count + target_count + postamble_count;
-       for (; i < k; ++i, ++j) {
-               if (postamble_data[j >> 3L] & (1L << (j & 7L)))
-                       buffer[i >> 3L] |= (1L << (i & 7L));
-               else
-                       buffer[i >> 3L] &= ~(u32)(1L << (i & 7L));
-
-       }
-}
-
-static int alt_jtag_drscan(struct altera_state *astate,
-                       int start_state,
-                       int count,
-                       u8 *tdi,
-                       u8 *tdo)
-{
-       int i = 0;
-       int tdo_bit = 0;
-       int status = 1;
-
-       /* First go to DRSHIFT state */
-       switch (start_state) {
-       case 0:                                         /* IDLE */
-               alt_jtag_io(1, 0, 0);   /* DRSELECT */
-               alt_jtag_io(0, 0, 0);   /* DRCAPTURE */
-               alt_jtag_io(0, 0, 0);   /* DRSHIFT */
-               break;
-
-       case 1:                                         /* DRPAUSE */
-               alt_jtag_io(1, 0, 0);   /* DREXIT2 */
-               alt_jtag_io(1, 0, 0);   /* DRUPDATE */
-               alt_jtag_io(1, 0, 0);   /* DRSELECT */
-               alt_jtag_io(0, 0, 0);   /* DRCAPTURE */
-               alt_jtag_io(0, 0, 0);   /* DRSHIFT */
-               break;
-
-       case 2:                                         /* IRPAUSE */
-               alt_jtag_io(1, 0, 0);   /* IREXIT2 */
-               alt_jtag_io(1, 0, 0);   /* IRUPDATE */
-               alt_jtag_io(1, 0, 0);   /* DRSELECT */
-               alt_jtag_io(0, 0, 0);   /* DRCAPTURE */
-               alt_jtag_io(0, 0, 0);   /* DRSHIFT */
-               break;
-
-       default:
-               status = 0;
-       }
-
-       if (status) {
-               /* loop in the SHIFT-DR state */
-               for (i = 0; i < count; i++) {
-                       tdo_bit = alt_jtag_io(
-                                       (i == count - 1),
-                                       tdi[i >> 3] & (1 << (i & 7)),
-                                       (tdo != NULL));
-
-                       if (tdo != NULL) {
-                               if (tdo_bit)
-                                       tdo[i >> 3] |= (1 << (i & 7));
-                               else
-                                       tdo[i >> 3] &= ~(u32)(1 << (i & 7));
-
-                       }
-               }
-
-               alt_jtag_io(0, 0, 0);   /* DRPAUSE */
-       }
-
-       return status;
-}
-
-static int alt_jtag_irscan(struct altera_state *astate,
-                   int start_state,
-                   int count,
-                   u8 *tdi,
-                   u8 *tdo)
-{
-       int i = 0;
-       int tdo_bit = 0;
-       int status = 1;
-
-       /* First go to IRSHIFT state */
-       switch (start_state) {
-       case 0:                                         /* IDLE */
-               alt_jtag_io(1, 0, 0);   /* DRSELECT */
-               alt_jtag_io(1, 0, 0);   /* IRSELECT */
-               alt_jtag_io(0, 0, 0);   /* IRCAPTURE */
-               alt_jtag_io(0, 0, 0);   /* IRSHIFT */
-               break;
-
-       case 1:                                         /* DRPAUSE */
-               alt_jtag_io(1, 0, 0);   /* DREXIT2 */
-               alt_jtag_io(1, 0, 0);   /* DRUPDATE */
-               alt_jtag_io(1, 0, 0);   /* DRSELECT */
-               alt_jtag_io(1, 0, 0);   /* IRSELECT */
-               alt_jtag_io(0, 0, 0);   /* IRCAPTURE */
-               alt_jtag_io(0, 0, 0);   /* IRSHIFT */
-               break;
-
-       case 2:                                         /* IRPAUSE */
-               alt_jtag_io(1, 0, 0);   /* IREXIT2 */
-               alt_jtag_io(1, 0, 0);   /* IRUPDATE */
-               alt_jtag_io(1, 0, 0);   /* DRSELECT */
-               alt_jtag_io(1, 0, 0);   /* IRSELECT */
-               alt_jtag_io(0, 0, 0);   /* IRCAPTURE */
-               alt_jtag_io(0, 0, 0);   /* IRSHIFT */
-               break;
-
-       default:
-               status = 0;
-       }
-
-       if (status) {
-               /* loop in the SHIFT-IR state */
-               for (i = 0; i < count; i++) {
-                       tdo_bit = alt_jtag_io(
-                                     (i == count - 1),
-                                     tdi[i >> 3] & (1 << (i & 7)),
-                                     (tdo != NULL));
-                       if (tdo != NULL) {
-                               if (tdo_bit)
-                                       tdo[i >> 3] |= (1 << (i & 7));
-                               else
-                                       tdo[i >> 3] &= ~(u32)(1 << (i & 7));
-
-                       }
-               }
-
-               alt_jtag_io(0, 0, 0);   /* IRPAUSE */
-       }
-
-       return status;
-}
-
-static void altera_extract_target_data(u8 *buffer,
-                               u8 *target_data,
-                               u32 start_index,
-                               u32 preamble_count,
-                               u32 target_count)
-/*
- * Copies target data from scan buffer, filtering out
- * preamble and postamble data.
- */
-{
-       u32 i;
-       u32 j;
-       u32 k;
-
-       j = preamble_count;
-       k = start_index + target_count;
-       for (i = start_index; i < k; ++i, ++j) {
-               if (buffer[j >> 3] & (1 << (j & 7)))
-                       target_data[i >> 3] |= (1 << (i & 7));
-               else
-                       target_data[i >> 3] &= ~(u32)(1 << (i & 7));
-
-       }
-}
-
-int altera_irscan(struct altera_state *astate,
-                               u32 count,
-                               u8 *tdi_data,
-                               u32 start_index)
-/* Shifts data into instruction register */
-{
-       struct altera_jtag *js = &astate->js;
-       int start_code = 0;
-       u32 alloc_chars = 0;
-       u32 shift_count = js->ir_pre + count + js->ir_post;
-       int status = 0;
-       enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE;
-
-       switch (js->jtag_state) {
-       case ILLEGAL_JTAG_STATE:
-       case RESET:
-       case IDLE:
-               start_code = 0;
-               start_state = IDLE;
-               break;
-
-       case DRSELECT:
-       case DRCAPTURE:
-       case DRSHIFT:
-       case DREXIT1:
-       case DRPAUSE:
-       case DREXIT2:
-       case DRUPDATE:
-               start_code = 1;
-               start_state = DRPAUSE;
-               break;
-
-       case IRSELECT:
-       case IRCAPTURE:
-       case IRSHIFT:
-       case IREXIT1:
-       case IRPAUSE:
-       case IREXIT2:
-       case IRUPDATE:
-               start_code = 2;
-               start_state = IRPAUSE;
-               break;
-
-       default:
-               status = -EREMOTEIO;
-               break;
-       }
-
-       if (status == 0)
-               if (js->jtag_state != start_state)
-                       status = altera_goto_jstate(astate, start_state);
-
-       if (status == 0) {
-               if (shift_count > js->ir_length) {
-                       alloc_chars = (shift_count + 7) >> 3;
-                       kfree(js->ir_buffer);
-                       js->ir_buffer = (u8 *)alt_malloc(alloc_chars);
-                       if (js->ir_buffer == NULL)
-                               status = -ENOMEM;
-                       else
-                               js->ir_length = alloc_chars * 8;
-
-               }
-       }
-
-       if (status == 0) {
-               /*
-                * Copy preamble data, IR data,
-                * and postamble data into a buffer
-                */
-               altera_concatenate_data(js->ir_buffer,
-                                       js->ir_pre_data,
-                                       js->ir_pre,
-                                       tdi_data,
-                                       start_index,
-                                       count,
-                                       js->ir_post_data,
-                                       js->ir_post);
-               /* Do the IRSCAN */
-               alt_jtag_irscan(astate,
-                               start_code,
-                               shift_count,
-                               js->ir_buffer,
-                               NULL);
-
-               /* alt_jtag_irscan() always ends in IRPAUSE state */
-               js->jtag_state = IRPAUSE;
-       }
-
-       if (status == 0)
-               if (js->irstop_state != IRPAUSE)
-                       status = altera_goto_jstate(astate, js->irstop_state);
-
-
-       return status;
-}
-
-int altera_swap_ir(struct altera_state *astate,
-                           u32 count,
-                           u8 *in_data,
-                           u32 in_index,
-                           u8 *out_data,
-                           u32 out_index)
-/* Shifts data into instruction register, capturing output data */
-{
-       struct altera_jtag *js = &astate->js;
-       int start_code = 0;
-       u32 alloc_chars = 0;
-       u32 shift_count = js->ir_pre + count + js->ir_post;
-       int status = 0;
-       enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE;
-
-       switch (js->jtag_state) {
-       case ILLEGAL_JTAG_STATE:
-       case RESET:
-       case IDLE:
-               start_code = 0;
-               start_state = IDLE;
-               break;
-
-       case DRSELECT:
-       case DRCAPTURE:
-       case DRSHIFT:
-       case DREXIT1:
-       case DRPAUSE:
-       case DREXIT2:
-       case DRUPDATE:
-               start_code = 1;
-               start_state = DRPAUSE;
-               break;
-
-       case IRSELECT:
-       case IRCAPTURE:
-       case IRSHIFT:
-       case IREXIT1:
-       case IRPAUSE:
-       case IREXIT2:
-       case IRUPDATE:
-               start_code = 2;
-               start_state = IRPAUSE;
-               break;
-
-       default:
-               status = -EREMOTEIO;
-               break;
-       }
-
-       if (status == 0)
-               if (js->jtag_state != start_state)
-                       status = altera_goto_jstate(astate, start_state);
-
-       if (status == 0) {
-               if (shift_count > js->ir_length) {
-                       alloc_chars = (shift_count + 7) >> 3;
-                       kfree(js->ir_buffer);
-                       js->ir_buffer = (u8 *)alt_malloc(alloc_chars);
-                       if (js->ir_buffer == NULL)
-                               status = -ENOMEM;
-                       else
-                               js->ir_length = alloc_chars * 8;
-
-               }
-       }
-
-       if (status == 0) {
-               /*
-                * Copy preamble data, IR data,
-                * and postamble data into a buffer
-                */
-               altera_concatenate_data(js->ir_buffer,
-                                       js->ir_pre_data,
-                                       js->ir_pre,
-                                       in_data,
-                                       in_index,
-                                       count,
-                                       js->ir_post_data,
-                                       js->ir_post);
-
-               /* Do the IRSCAN */
-               alt_jtag_irscan(astate,
-                               start_code,
-                               shift_count,
-                               js->ir_buffer,
-                               js->ir_buffer);
-
-               /* alt_jtag_irscan() always ends in IRPAUSE state */
-               js->jtag_state = IRPAUSE;
-       }
-
-       if (status == 0)
-               if (js->irstop_state != IRPAUSE)
-                       status = altera_goto_jstate(astate, js->irstop_state);
-
-
-       if (status == 0)
-               /* Now extract the returned data from the buffer */
-               altera_extract_target_data(js->ir_buffer,
-                                       out_data, out_index,
-                                       js->ir_pre, count);
-
-       return status;
-}
-
-int altera_drscan(struct altera_state *astate,
-                               u32 count,
-                               u8 *tdi_data,
-                               u32 start_index)
-/* Shifts data into data register (ignoring output data) */
-{
-       struct altera_jtag *js = &astate->js;
-       int start_code = 0;
-       u32 alloc_chars = 0;
-       u32 shift_count = js->dr_pre + count + js->dr_post;
-       int status = 0;
-       enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE;
-
-       switch (js->jtag_state) {
-       case ILLEGAL_JTAG_STATE:
-       case RESET:
-       case IDLE:
-               start_code = 0;
-               start_state = IDLE;
-               break;
-
-       case DRSELECT:
-       case DRCAPTURE:
-       case DRSHIFT:
-       case DREXIT1:
-       case DRPAUSE:
-       case DREXIT2:
-       case DRUPDATE:
-               start_code = 1;
-               start_state = DRPAUSE;
-               break;
-
-       case IRSELECT:
-       case IRCAPTURE:
-       case IRSHIFT:
-       case IREXIT1:
-       case IRPAUSE:
-       case IREXIT2:
-       case IRUPDATE:
-               start_code = 2;
-               start_state = IRPAUSE;
-               break;
-
-       default:
-               status = -EREMOTEIO;
-               break;
-       }
-
-       if (status == 0)
-               if (js->jtag_state != start_state)
-                       status = altera_goto_jstate(astate, start_state);
-
-       if (status == 0) {
-               if (shift_count > js->dr_length) {
-                       alloc_chars = (shift_count + 7) >> 3;
-                       kfree(js->dr_buffer);
-                       js->dr_buffer = (u8 *)alt_malloc(alloc_chars);
-                       if (js->dr_buffer == NULL)
-                               status = -ENOMEM;
-                       else
-                               js->dr_length = alloc_chars * 8;
-
-               }
-       }
-
-       if (status == 0) {
-               /*
-                * Copy preamble data, DR data,
-                * and postamble data into a buffer
-                */
-               altera_concatenate_data(js->dr_buffer,
-                                       js->dr_pre_data,
-                                       js->dr_pre,
-                                       tdi_data,
-                                       start_index,
-                                       count,
-                                       js->dr_post_data,
-                                       js->dr_post);
-               /* Do the DRSCAN */
-               alt_jtag_drscan(astate, start_code, shift_count,
-                               js->dr_buffer, NULL);
-               /* alt_jtag_drscan() always ends in DRPAUSE state */
-               js->jtag_state = DRPAUSE;
-       }
-
-       if (status == 0)
-               if (js->drstop_state != DRPAUSE)
-                       status = altera_goto_jstate(astate, js->drstop_state);
-
-       return status;
-}
-
-int altera_swap_dr(struct altera_state *astate, u32 count,
-                               u8 *in_data, u32 in_index,
-                               u8 *out_data, u32 out_index)
-/* Shifts data into data register, capturing output data */
-{
-       struct altera_jtag *js = &astate->js;
-       int start_code = 0;
-       u32 alloc_chars = 0;
-       u32 shift_count = js->dr_pre + count + js->dr_post;
-       int status = 0;
-       enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE;
-
-       switch (js->jtag_state) {
-       case ILLEGAL_JTAG_STATE:
-       case RESET:
-       case IDLE:
-               start_code = 0;
-               start_state = IDLE;
-               break;
-
-       case DRSELECT:
-       case DRCAPTURE:
-       case DRSHIFT:
-       case DREXIT1:
-       case DRPAUSE:
-       case DREXIT2:
-       case DRUPDATE:
-               start_code = 1;
-               start_state = DRPAUSE;
-               break;
-
-       case IRSELECT:
-       case IRCAPTURE:
-       case IRSHIFT:
-       case IREXIT1:
-       case IRPAUSE:
-       case IREXIT2:
-       case IRUPDATE:
-               start_code = 2;
-               start_state = IRPAUSE;
-               break;
-
-       default:
-               status = -EREMOTEIO;
-               break;
-       }
-
-       if (status == 0)
-               if (js->jtag_state != start_state)
-                       status = altera_goto_jstate(astate, start_state);
-
-       if (status == 0) {
-               if (shift_count > js->dr_length) {
-                       alloc_chars = (shift_count + 7) >> 3;
-                       kfree(js->dr_buffer);
-                       js->dr_buffer = (u8 *)alt_malloc(alloc_chars);
-
-                       if (js->dr_buffer == NULL)
-                               status = -ENOMEM;
-                       else
-                               js->dr_length = alloc_chars * 8;
-
-               }
-       }
-
-       if (status == 0) {
-               /*
-                * Copy preamble data, DR data,
-                * and postamble data into a buffer
-                */
-               altera_concatenate_data(js->dr_buffer,
-                               js->dr_pre_data,
-                               js->dr_pre,
-                               in_data,
-                               in_index,
-                               count,
-                               js->dr_post_data,
-                               js->dr_post);
-
-               /* Do the DRSCAN */
-               alt_jtag_drscan(astate,
-                               start_code,
-                               shift_count,
-                               js->dr_buffer,
-                               js->dr_buffer);
-
-               /* alt_jtag_drscan() always ends in DRPAUSE state */
-               js->jtag_state = DRPAUSE;
-       }
-
-       if (status == 0)
-               if (js->drstop_state != DRPAUSE)
-                       status = altera_goto_jstate(astate, js->drstop_state);
-
-       if (status == 0)
-               /* Now extract the returned data from the buffer */
-               altera_extract_target_data(js->dr_buffer,
-                                       out_data,
-                                       out_index,
-                                       js->dr_pre,
-                                       count);
-
-       return status;
-}
-
-void altera_free_buffers(struct altera_state *astate)
-{
-       struct altera_jtag *js = &astate->js;
-       /* If the JTAG interface was used, reset it to TLR */
-       if (js->jtag_state != ILLEGAL_JTAG_STATE)
-               altera_jreset_idle(astate);
-
-       kfree(js->dr_pre_data);
-       js->dr_pre_data = NULL;
-
-       kfree(js->dr_post_data);
-       js->dr_post_data = NULL;
-
-       kfree(js->dr_buffer);
-       js->dr_buffer = NULL;
-
-       kfree(js->ir_pre_data);
-       js->ir_pre_data = NULL;
-
-       kfree(js->ir_post_data);
-       js->ir_post_data = NULL;
-
-       kfree(js->ir_buffer);
-       js->ir_buffer = NULL;
-}
diff --git a/drivers/staging/altera-stapl/altera-jtag.h b/drivers/staging/altera-stapl/altera-jtag.h
deleted file mode 100644 (file)
index 2f97e36..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * altera-jtag.h
- *
- * altera FPGA driver
- *
- * Copyright (C) Altera Corporation 1998-2001
- * Copyright (C) 2010 NetUP Inc.
- * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
- *
- * 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 ALTERA_JTAG_H
-#define ALTERA_JTAG_H
-
-/* Function Prototypes */
-enum altera_jtag_state {
-       ILLEGAL_JTAG_STATE = -1,
-       RESET = 0,
-       IDLE = 1,
-       DRSELECT = 2,
-       DRCAPTURE = 3,
-       DRSHIFT = 4,
-       DREXIT1 = 5,
-       DRPAUSE = 6,
-       DREXIT2 = 7,
-       DRUPDATE = 8,
-       IRSELECT = 9,
-       IRCAPTURE = 10,
-       IRSHIFT = 11,
-       IREXIT1 = 12,
-       IRPAUSE = 13,
-       IREXIT2 = 14,
-       IRUPDATE = 15
-
-};
-
-struct altera_jtag {
-       /* Global variable to store the current JTAG state */
-       enum altera_jtag_state jtag_state;
-
-       /* Store current stop-state for DR and IR scan commands */
-       enum altera_jtag_state drstop_state;
-       enum altera_jtag_state irstop_state;
-
-       /* Store current padding values */
-       u32 dr_pre;
-       u32 dr_post;
-       u32 ir_pre;
-       u32 ir_post;
-       u32 dr_length;
-       u32 ir_length;
-       u8 *dr_pre_data;
-       u8 *dr_post_data;
-       u8 *ir_pre_data;
-       u8 *ir_post_data;
-       u8 *dr_buffer;
-       u8 *ir_buffer;
-};
-
-#define ALTERA_STACK_SIZE 128
-#define ALTERA_MESSAGE_LENGTH 1024
-
-struct altera_state {
-       struct altera_config    *config;
-       struct altera_jtag      js;
-       char                    msg_buff[ALTERA_MESSAGE_LENGTH + 1];
-       long                    stack[ALTERA_STACK_SIZE];
-};
-
-int altera_jinit(struct altera_state *astate);
-int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state);
-int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state);
-int altera_set_dr_pre(struct altera_jtag *js, u32 count, u32 start_index,
-                               u8 *preamble_data);
-int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index,
-                               u8 *preamble_data);
-int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index,
-                               u8 *postamble_data);
-int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index,
-                               u8 *postamble_data);
-int altera_goto_jstate(struct altera_state *astate,
-                               enum altera_jtag_state state);
-int altera_wait_cycles(struct altera_state *astate, s32 cycles,
-                               enum altera_jtag_state wait_state);
-int altera_wait_msecs(struct altera_state *astate, s32 microseconds,
-                               enum altera_jtag_state wait_state);
-int altera_irscan(struct altera_state *astate, u32 count,
-                               u8 *tdi_data, u32 start_index);
-int altera_swap_ir(struct altera_state *astate,
-                               u32 count, u8 *in_data,
-                               u32 in_index, u8 *out_data,
-                               u32 out_index);
-int altera_drscan(struct altera_state *astate, u32 count,
-                               u8 *tdi_data, u32 start_index);
-int altera_swap_dr(struct altera_state *astate, u32 count,
-                               u8 *in_data, u32 in_index,
-                               u8 *out_data, u32 out_index);
-void altera_free_buffers(struct altera_state *astate);
-#endif /* ALTERA_JTAG_H */
diff --git a/drivers/staging/altera-stapl/altera-lpt.c b/drivers/staging/altera-stapl/altera-lpt.c
deleted file mode 100644 (file)
index 91456a0..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * altera-lpt.c
- *
- * altera FPGA driver
- *
- * Copyright (C) Altera Corporation 1998-2001
- * Copyright (C) 2010 NetUP Inc.
- * Copyright (C) 2010 Abylay Ospan <aospan@netup.ru>
- *
- * 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/io.h>
-#include <linux/kernel.h>
-#include "altera-exprt.h"
-
-static int lpt_hardware_initialized;
-
-static void byteblaster_write(int port, int data)
-{
-       outb((u8)data, (u16)(port + 0x378));
-};
-
-static int byteblaster_read(int port)
-{
-       int data = 0;
-       data = inb((u16)(port + 0x378));
-       return data & 0xff;
-};
-
-int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo)
-{
-       int data = 0;
-       int tdo = 0;
-       int initial_lpt_ctrl = 0;
-
-       if (!lpt_hardware_initialized) {
-               initial_lpt_ctrl = byteblaster_read(2);
-               byteblaster_write(2, (initial_lpt_ctrl | 0x02) & 0xdf);
-               lpt_hardware_initialized = 1;
-       }
-
-       data = ((tdi ? 0x40 : 0) | (tms ? 0x02 : 0));
-
-       byteblaster_write(0, data);
-
-       if (read_tdo) {
-               tdo = byteblaster_read(1);
-               tdo = ((tdo & 0x80) ? 0 : 1);
-       }
-
-       byteblaster_write(0, data | 0x01);
-
-       byteblaster_write(0, data);
-
-       return tdo;
-}
diff --git a/drivers/staging/altera-stapl/altera.c b/drivers/staging/altera-stapl/altera.c
deleted file mode 100644 (file)
index c2eff6a..0000000
+++ /dev/null
@@ -1,2537 +0,0 @@
-/*
- * altera.c
- *
- * altera FPGA driver
- *
- * Copyright (C) Altera Corporation 1998-2001
- * Copyright (C) 2010,2011 NetUP Inc.
- * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
- *
- * 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 <asm/unaligned.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include "altera.h"
-#include "altera-exprt.h"
-#include "altera-jtag.h"
-
-static int debug = 1;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debugging information");
-
-MODULE_DESCRIPTION("altera FPGA kernel module");
-MODULE_AUTHOR("Igor M. Liplianin  <liplianin@netup.ru>");
-MODULE_LICENSE("GPL");
-
-#define dprintk(args...) \
-       if (debug) { \
-               printk(KERN_DEBUG args); \
-       }
-
-enum altera_fpga_opcode {
-       OP_NOP = 0,
-       OP_DUP,
-       OP_SWP,
-       OP_ADD,
-       OP_SUB,
-       OP_MULT,
-       OP_DIV,
-       OP_MOD,
-       OP_SHL,
-       OP_SHR,
-       OP_NOT,
-       OP_AND,
-       OP_OR,
-       OP_XOR,
-       OP_INV,
-       OP_GT,
-       OP_LT,
-       OP_RET,
-       OP_CMPS,
-       OP_PINT,
-       OP_PRNT,
-       OP_DSS,
-       OP_DSSC,
-       OP_ISS,
-       OP_ISSC,
-       OP_DPR = 0x1c,
-       OP_DPRL,
-       OP_DPO,
-       OP_DPOL,
-       OP_IPR,
-       OP_IPRL,
-       OP_IPO,
-       OP_IPOL,
-       OP_PCHR,
-       OP_EXIT,
-       OP_EQU,
-       OP_POPT,
-       OP_ABS = 0x2c,
-       OP_BCH0,
-       OP_PSH0 = 0x2f,
-       OP_PSHL = 0x40,
-       OP_PSHV,
-       OP_JMP,
-       OP_CALL,
-       OP_NEXT,
-       OP_PSTR,
-       OP_SINT = 0x47,
-       OP_ST,
-       OP_ISTP,
-       OP_DSTP,
-       OP_SWPN,
-       OP_DUPN,
-       OP_POPV,
-       OP_POPE,
-       OP_POPA,
-       OP_JMPZ,
-       OP_DS,
-       OP_IS,
-       OP_DPRA,
-       OP_DPOA,
-       OP_IPRA,
-       OP_IPOA,
-       OP_EXPT,
-       OP_PSHE,
-       OP_PSHA,
-       OP_DYNA,
-       OP_EXPV = 0x5c,
-       OP_COPY = 0x80,
-       OP_REVA,
-       OP_DSC,
-       OP_ISC,
-       OP_WAIT,
-       OP_VS,
-       OP_CMPA = 0xc0,
-       OP_VSC,
-};
-
-struct altera_procinfo {
-       char                    *name;
-       u8                      attrs;
-       struct altera_procinfo  *next;
-};
-
-/* This function checks if enough parameters are available on the stack. */
-static int altera_check_stack(int stack_ptr, int count, int *status)
-{
-       if (stack_ptr < count) {
-               *status = -EOVERFLOW;
-               return 0;
-       }
-
-       return 1;
-}
-
-static void altera_export_int(char *key, s32 value)
-{
-       dprintk("Export: key = \"%s\", value = %d\n", key, value);
-}
-
-#define HEX_LINE_CHARS 72
-#define HEX_LINE_BITS (HEX_LINE_CHARS * 4)
-
-static void altera_export_bool_array(char *key, u8 *data, s32 count)
-{
-       char string[HEX_LINE_CHARS + 1];
-       s32 i, offset;
-       u32 size, line, lines, linebits, value, j, k;
-
-       if (count > HEX_LINE_BITS) {
-               dprintk("Export: key = \"%s\", %d bits, value = HEX\n",
-                                                       key, count);
-               lines = (count + (HEX_LINE_BITS - 1)) / HEX_LINE_BITS;
-
-               for (line = 0; line < lines; ++line) {
-                       if (line < (lines - 1)) {
-                               linebits = HEX_LINE_BITS;
-                               size = HEX_LINE_CHARS;
-                               offset = count - ((line + 1) * HEX_LINE_BITS);
-                       } else {
-                               linebits =
-                                       count - ((lines - 1) * HEX_LINE_BITS);
-                               size = (linebits + 3) / 4;
-                               offset = 0L;
-                       }
-
-                       string[size] = '\0';
-                       j = size - 1;
-                       value = 0;
-
-                       for (k = 0; k < linebits; ++k) {
-                               i = k + offset;
-                               if (data[i >> 3] & (1 << (i & 7)))
-                                       value |= (1 << (i & 3));
-                               if ((i & 3) == 3) {
-                                       sprintf(&string[j], "%1x", value);
-                                       value = 0;
-                                       --j;
-                               }
-                       }
-                       if ((k & 3) > 0)
-                               sprintf(&string[j], "%1x", value);
-
-                       dprintk("%s\n", string);
-               }
-
-       } else {
-               size = (count + 3) / 4;
-               string[size] = '\0';
-               j = size - 1;
-               value = 0;
-
-               for (i = 0; i < count; ++i) {
-                       if (data[i >> 3] & (1 << (i & 7)))
-                               value |= (1 << (i & 3));
-                       if ((i & 3) == 3) {
-                               sprintf(&string[j], "%1x", value);
-                               value = 0;
-                               --j;
-                       }
-               }
-               if ((i & 3) > 0)
-                       sprintf(&string[j], "%1x", value);
-
-               dprintk("Export: key = \"%s\", %d bits, value = HEX %s\n",
-                       key, count, string);
-       }
-}
-
-static int altera_execute(struct altera_state *astate,
-                               u8 *p,
-                               s32 program_size,
-                               s32 *error_address,
-                               int *exit_code,
-                               int *format_version)
-{
-       struct altera_config *aconf = astate->config;
-       char *msg_buff = astate->msg_buff;
-       long *stack = astate->stack;
-       int status = 0;
-       u32 first_word = 0L;
-       u32 action_table = 0L;
-       u32 proc_table = 0L;
-       u32 str_table = 0L;
-       u32 sym_table = 0L;
-       u32 data_sect = 0L;
-       u32 code_sect = 0L;
-       u32 debug_sect = 0L;
-       u32 action_count = 0L;
-       u32 proc_count = 0L;
-       u32 sym_count = 0L;
-       long *vars = NULL;
-       s32 *var_size = NULL;
-       char *attrs = NULL;
-       u8 *proc_attributes = NULL;
-       u32 pc;
-       u32 opcode_address;
-       u32 args[3];
-       u32 opcode;
-       u32 name_id;
-       u8 charbuf[4];
-       long long_tmp;
-       u32 variable_id;
-       u8 *charptr_tmp;
-       u8 *charptr_tmp2;
-       long *longptr_tmp;
-       int version = 0;
-       int delta = 0;
-       int stack_ptr = 0;
-       u32 arg_count;
-       int done = 0;
-       int bad_opcode = 0;
-       u32 count;
-       u32 index;
-       u32 index2;
-       s32 long_count;
-       s32 long_idx;
-       s32 long_idx2;
-       u32 i;
-       u32 j;
-       u32 uncomp_size;
-       u32 offset;
-       u32 value;
-       int current_proc = 0;
-       int reverse;
-
-       char *name;
-
-       dprintk("%s\n", __func__);
-
-       /* Read header information */
-       if (program_size > 52L) {
-               first_word    = get_unaligned_be32(&p[0]);
-               version = (first_word & 1L);
-               *format_version = version + 1;
-               delta = version * 8;
-
-               action_table  = get_unaligned_be32(&p[4]);
-               proc_table    = get_unaligned_be32(&p[8]);
-               str_table  = get_unaligned_be32(&p[4 + delta]);
-               sym_table  = get_unaligned_be32(&p[16 + delta]);
-               data_sect  = get_unaligned_be32(&p[20 + delta]);
-               code_sect  = get_unaligned_be32(&p[24 + delta]);
-               debug_sect = get_unaligned_be32(&p[28 + delta]);
-               action_count  = get_unaligned_be32(&p[40 + delta]);
-               proc_count    = get_unaligned_be32(&p[44 + delta]);
-               sym_count  = get_unaligned_be32(&p[48 + (2 * delta)]);
-       }
-
-       if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) {
-               done = 1;
-               status = -EIO;
-               goto exit_done;
-       }
-
-       if (sym_count <= 0)
-               goto exit_done;
-
-       vars = kzalloc(sym_count * sizeof(long), GFP_KERNEL);
-
-       if (vars == NULL)
-               status = -ENOMEM;
-
-       if (status == 0) {
-               var_size = kzalloc(sym_count * sizeof(s32), GFP_KERNEL);
-
-               if (var_size == NULL)
-                       status = -ENOMEM;
-       }
-
-       if (status == 0) {
-               attrs = kzalloc(sym_count, GFP_KERNEL);
-
-               if (attrs == NULL)
-                       status = -ENOMEM;
-       }
-
-       if ((status == 0) && (version > 0)) {
-               proc_attributes = kzalloc(proc_count, GFP_KERNEL);
-
-               if (proc_attributes == NULL)
-                       status = -ENOMEM;
-       }
-
-       if (status != 0)
-               goto exit_done;
-
-       delta = version * 2;
-
-       for (i = 0; i < sym_count; ++i) {
-               offset = (sym_table + ((11 + delta) * i));
-
-               value = get_unaligned_be32(&p[offset + 3 + delta]);
-
-               attrs[i] = p[offset];
-
-               /*
-                * use bit 7 of attribute byte to indicate that
-                * this buffer was dynamically allocated
-                * and should be freed later
-                */
-               attrs[i] &= 0x7f;
-
-               var_size[i] = get_unaligned_be32(&p[offset + 7 + delta]);
-
-               /*
-                * Attribute bits:
-                * bit 0: 0 = read-only, 1 = read-write
-                * bit 1: 0 = not compressed, 1 = compressed
-                * bit 2: 0 = not initialized, 1 = initialized
-                * bit 3: 0 = scalar, 1 = array
-                * bit 4: 0 = Boolean, 1 = integer
-                * bit 5: 0 = declared variable,
-                *      1 = compiler created temporary variable
-                */
-
-               if ((attrs[i] & 0x0c) == 0x04)
-                       /* initialized scalar variable */
-                       vars[i] = value;
-               else if ((attrs[i] & 0x1e) == 0x0e) {
-                       /* initialized compressed Boolean array */
-                       uncomp_size = get_unaligned_le32(&p[data_sect + value]);
-
-                       /* allocate a buffer for the uncompressed data */
-                       vars[i] = (long)kzalloc(uncomp_size, GFP_KERNEL);
-                       if (vars[i] == 0L)
-                               status = -ENOMEM;
-                       else {
-                               /* set flag so buffer will be freed later */
-                               attrs[i] |= 0x80;
-
-                               /* uncompress the data */
-                               if (altera_shrink(&p[data_sect + value],
-                                               var_size[i],
-                                               (u8 *)vars[i],
-                                               uncomp_size,
-                                               version) != uncomp_size)
-                                       /* decompression failed */
-                                       status = -EIO;
-                               else
-                                       var_size[i] = uncomp_size * 8L;
-
-                       }
-               } else if ((attrs[i] & 0x1e) == 0x0c) {
-                       /* initialized Boolean array */
-                       vars[i] = value + data_sect + (long)p;
-               } else if ((attrs[i] & 0x1c) == 0x1c) {
-                       /* initialized integer array */
-                       vars[i] = value + data_sect;
-               } else if ((attrs[i] & 0x0c) == 0x08) {
-                       /* uninitialized array */
-
-                       /* flag attrs so that memory is freed */
-                       attrs[i] |= 0x80;
-
-                       if (var_size[i] > 0) {
-                               u32 size;
-
-                               if (attrs[i] & 0x10)
-                                       /* integer array */
-                                       size = (var_size[i] * sizeof(s32));
-                               else
-                                       /* Boolean array */
-                                       size = ((var_size[i] + 7L) / 8L);
-
-                               vars[i] = (long)kzalloc(size, GFP_KERNEL);
-
-                               if (vars[i] == 0) {
-                                       status = -ENOMEM;
-                               } else {
-                                       /* zero out memory */
-                                       for (j = 0; j < size; ++j)
-                                               ((u8 *)(vars[i]))[j] = 0;
-
-                               }
-                       } else
-                               vars[i] = 0;
-
-               } else
-                       vars[i] = 0;
-
-       }
-
-exit_done:
-       if (status != 0)
-               done = 1;
-
-       altera_jinit(astate);
-
-       pc = code_sect;
-       msg_buff[0] = '\0';
-
-       /*
-        * For JBC version 2, we will execute the procedures corresponding to
-        * the selected ACTION
-        */
-       if (version > 0) {
-               if (aconf->action == NULL) {
-                       status = -EINVAL;
-                       done = 1;
-               } else {
-                       int action_found = 0;
-                       for (i = 0; (i < action_count) && !action_found; ++i) {
-                               name_id = get_unaligned_be32(&p[action_table +
-                                                               (12 * i)]);
-
-                               name = &p[str_table + name_id];
-
-                               if (strnicmp(aconf->action, name, strlen(name)) == 0) {
-                                       action_found = 1;
-                                       current_proc =
-                                               get_unaligned_be32(&p[action_table +
-                                                               (12 * i) + 8]);
-                               }
-                       }
-
-                       if (!action_found) {
-                               status = -EINVAL;
-                               done = 1;
-                       }
-               }
-
-               if (status == 0) {
-                       int first_time = 1;
-                       i = current_proc;
-                       while ((i != 0) || first_time) {
-                               first_time = 0;
-                               /* check procedure attribute byte */
-                               proc_attributes[i] =
-                                               (p[proc_table +
-                                                               (13 * i) + 8] &
-                                                                       0x03);
-
-                               /*
-                                * BIT0 - OPTIONAL
-                                * BIT1 - RECOMMENDED
-                                * BIT6 - FORCED OFF
-                                * BIT7 - FORCED ON
-                                */
-
-                               i = get_unaligned_be32(&p[proc_table +
-                                                       (13 * i) + 4]);
-                       }
-
-                       /*
-                        * Set current_proc to the first procedure
-                        * to be executed
-                        */
-                       i = current_proc;
-                       while ((i != 0) &&
-                               ((proc_attributes[i] == 1) ||
-                               ((proc_attributes[i] & 0xc0) == 0x40))) {
-                               i = get_unaligned_be32(&p[proc_table +
-                                                       (13 * i) + 4]);
-                       }
-
-                       if ((i != 0) || ((i == 0) && (current_proc == 0) &&
-                               ((proc_attributes[0] != 1) &&
-                               ((proc_attributes[0] & 0xc0) != 0x40)))) {
-                               current_proc = i;
-                               pc = code_sect +
-                                       get_unaligned_be32(&p[proc_table +
-                                                               (13 * i) + 9]);
-                               if ((pc < code_sect) || (pc >= debug_sect))
-                                       status = -ERANGE;
-                       } else
-                               /* there are no procedures to execute! */
-                               done = 1;
-
-               }
-       }
-
-       msg_buff[0] = '\0';
-
-       while (!done) {
-               opcode = (p[pc] & 0xff);
-               opcode_address = pc;
-               ++pc;
-
-               if (debug > 1)
-                       printk("opcode: %02x\n", opcode);
-
-               arg_count = (opcode >> 6) & 3;
-               for (i = 0; i < arg_count; ++i) {
-                       args[i] = get_unaligned_be32(&p[pc]);
-                       pc += 4;
-               }
-
-               switch (opcode) {
-               case OP_NOP:
-                       break;
-               case OP_DUP:
-                       if (altera_check_stack(stack_ptr, 1, &status)) {
-                               stack[stack_ptr] = stack[stack_ptr - 1];
-                               ++stack_ptr;
-                       }
-                       break;
-               case OP_SWP:
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               long_tmp = stack[stack_ptr - 2];
-                               stack[stack_ptr - 2] = stack[stack_ptr - 1];
-                               stack[stack_ptr - 1] = long_tmp;
-                       }
-                       break;
-               case OP_ADD:
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               --stack_ptr;
-                               stack[stack_ptr - 1] += stack[stack_ptr];
-                       }
-                       break;
-               case OP_SUB:
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               --stack_ptr;
-                               stack[stack_ptr - 1] -= stack[stack_ptr];
-                       }
-                       break;
-               case OP_MULT:
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               --stack_ptr;
-                               stack[stack_ptr - 1] *= stack[stack_ptr];
-                       }
-                       break;
-               case OP_DIV:
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               --stack_ptr;
-                               stack[stack_ptr - 1] /= stack[stack_ptr];
-                       }
-                       break;
-               case OP_MOD:
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               --stack_ptr;
-                               stack[stack_ptr - 1] %= stack[stack_ptr];
-                       }
-                       break;
-               case OP_SHL:
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               --stack_ptr;
-                               stack[stack_ptr - 1] <<= stack[stack_ptr];
-                       }
-                       break;
-               case OP_SHR:
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               --stack_ptr;
-                               stack[stack_ptr - 1] >>= stack[stack_ptr];
-                       }
-                       break;
-               case OP_NOT:
-                       if (altera_check_stack(stack_ptr, 1, &status))
-                               stack[stack_ptr - 1] ^= (-1L);
-
-                       break;
-               case OP_AND:
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               --stack_ptr;
-                               stack[stack_ptr - 1] &= stack[stack_ptr];
-                       }
-                       break;
-               case OP_OR:
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               --stack_ptr;
-                               stack[stack_ptr - 1] |= stack[stack_ptr];
-                       }
-                       break;
-               case OP_XOR:
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               --stack_ptr;
-                               stack[stack_ptr - 1] ^= stack[stack_ptr];
-                       }
-                       break;
-               case OP_INV:
-                       if (!altera_check_stack(stack_ptr, 1, &status))
-                               break;
-                       stack[stack_ptr - 1] = stack[stack_ptr - 1] ? 0L : 1L;
-                       break;
-               case OP_GT:
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       --stack_ptr;
-                       stack[stack_ptr - 1] =
-                               (stack[stack_ptr - 1] > stack[stack_ptr]) ?
-                                                                       1L : 0L;
-
-                       break;
-               case OP_LT:
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       --stack_ptr;
-                       stack[stack_ptr - 1] =
-                               (stack[stack_ptr - 1] < stack[stack_ptr]) ?
-                                                                       1L : 0L;
-
-                       break;
-               case OP_RET:
-                       if ((version > 0) && (stack_ptr == 0)) {
-                               /*
-                                * We completed one of the main procedures
-                                * of an ACTION.
-                                * Find the next procedure
-                                * to be executed and jump to it.
-                                * If there are no more procedures, then EXIT.
-                                */
-                               i = get_unaligned_be32(&p[proc_table +
-                                               (13 * current_proc) + 4]);
-                               while ((i != 0) &&
-                                       ((proc_attributes[i] == 1) ||
-                                       ((proc_attributes[i] & 0xc0) == 0x40)))
-                                       i = get_unaligned_be32(&p[proc_table +
-                                                               (13 * i) + 4]);
-
-                               if (i == 0) {
-                                       /* no procedures to execute! */
-                                       done = 1;
-                                       *exit_code = 0; /* success */
-                               } else {
-                                       current_proc = i;
-                                       pc = code_sect + get_unaligned_be32(
-                                                               &p[proc_table +
-                                                               (13 * i) + 9]);
-                                       if ((pc < code_sect) ||
-                                           (pc >= debug_sect))
-                                               status = -ERANGE;
-                               }
-
-                       } else
-                               if (altera_check_stack(stack_ptr, 1, &status)) {
-                                       pc = stack[--stack_ptr] + code_sect;
-                                       if ((pc <= code_sect) ||
-                                           (pc >= debug_sect))
-                                               status = -ERANGE;
-
-                               }
-
-                       break;
-               case OP_CMPS:
-                       /*
-                        * Array short compare
-                        * ...stack 0 is source 1 value
-                        * ...stack 1 is source 2 value
-                        * ...stack 2 is mask value
-                        * ...stack 3 is count
-                        */
-                       if (altera_check_stack(stack_ptr, 4, &status)) {
-                               s32 a = stack[--stack_ptr];
-                               s32 b = stack[--stack_ptr];
-                               long_tmp = stack[--stack_ptr];
-                               count = stack[stack_ptr - 1];
-
-                               if ((count < 1) || (count > 32))
-                                       status = -ERANGE;
-                               else {
-                                       long_tmp &= ((-1L) >> (32 - count));
-
-                                       stack[stack_ptr - 1] =
-                                       ((a & long_tmp) == (b & long_tmp))
-                                                               ? 1L : 0L;
-                               }
-                       }
-                       break;
-               case OP_PINT:
-                       /*
-                        * PRINT add integer
-                        * ...stack 0 is integer value
-                        */
-                       if (!altera_check_stack(stack_ptr, 1, &status))
-                               break;
-                       sprintf(&msg_buff[strlen(msg_buff)],
-                                       "%ld", stack[--stack_ptr]);
-                       break;
-               case OP_PRNT:
-                       /* PRINT finish */
-                       if (debug)
-                               printk(msg_buff, "\n");
-
-                       msg_buff[0] = '\0';
-                       break;
-               case OP_DSS:
-                       /*
-                        * DRSCAN short
-                        * ...stack 0 is scan data
-                        * ...stack 1 is count
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       long_tmp = stack[--stack_ptr];
-                       count = stack[--stack_ptr];
-                       put_unaligned_le32(long_tmp, &charbuf[0]);
-                       status = altera_drscan(astate, count, charbuf, 0);
-                       break;
-               case OP_DSSC:
-                       /*
-                        * DRSCAN short with capture
-                        * ...stack 0 is scan data
-                        * ...stack 1 is count
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       long_tmp = stack[--stack_ptr];
-                       count = stack[stack_ptr - 1];
-                       put_unaligned_le32(long_tmp, &charbuf[0]);
-                       status = altera_swap_dr(astate, count, charbuf,
-                                                       0, charbuf, 0);
-                       stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]);
-                       break;
-               case OP_ISS:
-                       /*
-                        * IRSCAN short
-                        * ...stack 0 is scan data
-                        * ...stack 1 is count
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       long_tmp = stack[--stack_ptr];
-                       count = stack[--stack_ptr];
-                       put_unaligned_le32(long_tmp, &charbuf[0]);
-                       status = altera_irscan(astate, count, charbuf, 0);
-                       break;
-               case OP_ISSC:
-                       /*
-                        * IRSCAN short with capture
-                        * ...stack 0 is scan data
-                        * ...stack 1 is count
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       long_tmp = stack[--stack_ptr];
-                       count = stack[stack_ptr - 1];
-                       put_unaligned_le32(long_tmp, &charbuf[0]);
-                       status = altera_swap_ir(astate, count, charbuf,
-                                                       0, charbuf, 0);
-                       stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]);
-                       break;
-               case OP_DPR:
-                       if (!altera_check_stack(stack_ptr, 1, &status))
-                               break;
-                       count = stack[--stack_ptr];
-                       status = altera_set_dr_pre(&astate->js, count, 0, NULL);
-                       break;
-               case OP_DPRL:
-                       /*
-                        * DRPRE with literal data
-                        * ...stack 0 is count
-                        * ...stack 1 is literal data
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       count = stack[--stack_ptr];
-                       long_tmp = stack[--stack_ptr];
-                       put_unaligned_le32(long_tmp, &charbuf[0]);
-                       status = altera_set_dr_pre(&astate->js, count, 0,
-                                               charbuf);
-                       break;
-               case OP_DPO:
-                       /*
-                        * DRPOST
-                        * ...stack 0 is count
-                        */
-                       if (altera_check_stack(stack_ptr, 1, &status)) {
-                               count = stack[--stack_ptr];
-                               status = altera_set_dr_post(&astate->js, count,
-                                                               0, NULL);
-                       }
-                       break;
-               case OP_DPOL:
-                       /*
-                        * DRPOST with literal data
-                        * ...stack 0 is count
-                        * ...stack 1 is literal data
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       count = stack[--stack_ptr];
-                       long_tmp = stack[--stack_ptr];
-                       put_unaligned_le32(long_tmp, &charbuf[0]);
-                       status = altera_set_dr_post(&astate->js, count, 0,
-                                                       charbuf);
-                       break;
-               case OP_IPR:
-                       if (altera_check_stack(stack_ptr, 1, &status)) {
-                               count = stack[--stack_ptr];
-                               status = altera_set_ir_pre(&astate->js, count,
-                                                               0, NULL);
-                       }
-                       break;
-               case OP_IPRL:
-                       /*
-                        * IRPRE with literal data
-                        * ...stack 0 is count
-                        * ...stack 1 is literal data
-                        */
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               count = stack[--stack_ptr];
-                               long_tmp = stack[--stack_ptr];
-                               put_unaligned_le32(long_tmp, &charbuf[0]);
-                               status = altera_set_ir_pre(&astate->js, count,
-                                                       0, charbuf);
-                       }
-                       break;
-               case OP_IPO:
-                       /*
-                        * IRPOST
-                        * ...stack 0 is count
-                        */
-                       if (altera_check_stack(stack_ptr, 1, &status)) {
-                               count = stack[--stack_ptr];
-                               status = altera_set_ir_post(&astate->js, count,
-                                                       0, NULL);
-                       }
-                       break;
-               case OP_IPOL:
-                       /*
-                        * IRPOST with literal data
-                        * ...stack 0 is count
-                        * ...stack 1 is literal data
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       count = stack[--stack_ptr];
-                       long_tmp = stack[--stack_ptr];
-                       put_unaligned_le32(long_tmp, &charbuf[0]);
-                       status = altera_set_ir_post(&astate->js, count, 0,
-                                                       charbuf);
-                       break;
-               case OP_PCHR:
-                       if (altera_check_stack(stack_ptr, 1, &status)) {
-                               u8 ch;
-                               count = strlen(msg_buff);
-                               ch = (char) stack[--stack_ptr];
-                               if ((ch < 1) || (ch > 127)) {
-                                       /*
-                                        * character code out of range
-                                        * instead of flagging an error,
-                                        * force the value to 127
-                                        */
-                                       ch = 127;
-                               }
-                               msg_buff[count] = ch;
-                               msg_buff[count + 1] = '\0';
-                       }
-                       break;
-               case OP_EXIT:
-                       if (altera_check_stack(stack_ptr, 1, &status))
-                               *exit_code = stack[--stack_ptr];
-
-                       done = 1;
-                       break;
-               case OP_EQU:
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       --stack_ptr;
-                       stack[stack_ptr - 1] =
-                               (stack[stack_ptr - 1] == stack[stack_ptr]) ?
-                                                                       1L : 0L;
-                       break;
-               case OP_POPT:
-                       if (altera_check_stack(stack_ptr, 1, &status))
-                               --stack_ptr;
-
-                       break;
-               case OP_ABS:
-                       if (!altera_check_stack(stack_ptr, 1, &status))
-                               break;
-                       if (stack[stack_ptr - 1] < 0)
-                               stack[stack_ptr - 1] = 0 - stack[stack_ptr - 1];
-
-                       break;
-               case OP_BCH0:
-                       /*
-                        * Batch operation 0
-                        * SWP
-                        * SWPN 7
-                        * SWP
-                        * SWPN 6
-                        * DUPN 8
-                        * SWPN 2
-                        * SWP
-                        * DUPN 6
-                        * DUPN 6
-                        */
-
-                       /* SWP  */
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               long_tmp = stack[stack_ptr - 2];
-                               stack[stack_ptr - 2] = stack[stack_ptr - 1];
-                               stack[stack_ptr - 1] = long_tmp;
-                       }
-
-                       /* SWPN 7 */
-                       index = 7 + 1;
-                       if (altera_check_stack(stack_ptr, index, &status)) {
-                               long_tmp = stack[stack_ptr - index];
-                               stack[stack_ptr - index] = stack[stack_ptr - 1];
-                               stack[stack_ptr - 1] = long_tmp;
-                       }
-
-                       /* SWP  */
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               long_tmp = stack[stack_ptr - 2];
-                               stack[stack_ptr - 2] = stack[stack_ptr - 1];
-                               stack[stack_ptr - 1] = long_tmp;
-                       }
-
-                       /* SWPN 6 */
-                       index = 6 + 1;
-                       if (altera_check_stack(stack_ptr, index, &status)) {
-                               long_tmp = stack[stack_ptr - index];
-                               stack[stack_ptr - index] = stack[stack_ptr - 1];
-                               stack[stack_ptr - 1] = long_tmp;
-                       }
-
-                       /* DUPN 8 */
-                       index = 8 + 1;
-                       if (altera_check_stack(stack_ptr, index, &status)) {
-                               stack[stack_ptr] = stack[stack_ptr - index];
-                               ++stack_ptr;
-                       }
-
-                       /* SWPN 2 */
-                       index = 2 + 1;
-                       if (altera_check_stack(stack_ptr, index, &status)) {
-                               long_tmp = stack[stack_ptr - index];
-                               stack[stack_ptr - index] = stack[stack_ptr - 1];
-                               stack[stack_ptr - 1] = long_tmp;
-                       }
-
-                       /* SWP  */
-                       if (altera_check_stack(stack_ptr, 2, &status)) {
-                               long_tmp = stack[stack_ptr - 2];
-                               stack[stack_ptr - 2] = stack[stack_ptr - 1];
-                               stack[stack_ptr - 1] = long_tmp;
-                       }
-
-                       /* DUPN 6 */
-                       index = 6 + 1;
-                       if (altera_check_stack(stack_ptr, index, &status)) {
-                               stack[stack_ptr] = stack[stack_ptr - index];
-                               ++stack_ptr;
-                       }
-
-                       /* DUPN 6 */
-                       index = 6 + 1;
-                       if (altera_check_stack(stack_ptr, index, &status)) {
-                               stack[stack_ptr] = stack[stack_ptr - index];
-                               ++stack_ptr;
-                       }
-                       break;
-               case OP_PSH0:
-                       stack[stack_ptr++] = 0;
-                       break;
-               case OP_PSHL:
-                       stack[stack_ptr++] = (s32) args[0];
-                       break;
-               case OP_PSHV:
-                       stack[stack_ptr++] = vars[args[0]];
-                       break;
-               case OP_JMP:
-                       pc = args[0] + code_sect;
-                       if ((pc < code_sect) || (pc >= debug_sect))
-                               status = -ERANGE;
-                       break;
-               case OP_CALL:
-                       stack[stack_ptr++] = pc;
-                       pc = args[0] + code_sect;
-                       if ((pc < code_sect) || (pc >= debug_sect))
-                               status = -ERANGE;
-                       break;
-               case OP_NEXT:
-                       /*
-                        * Process FOR / NEXT loop
-                        * ...argument 0 is variable ID
-                        * ...stack 0 is step value
-                        * ...stack 1 is end value
-                        * ...stack 2 is top address
-                        */
-                       if (altera_check_stack(stack_ptr, 3, &status)) {
-                               s32 step = stack[stack_ptr - 1];
-                               s32 end = stack[stack_ptr - 2];
-                               s32 top = stack[stack_ptr - 3];
-                               s32 iterator = vars[args[0]];
-                               int break_out = 0;
-
-                               if (step < 0) {
-                                       if (iterator <= end)
-                                               break_out = 1;
-                               } else if (iterator >= end)
-                                       break_out = 1;
-
-                               if (break_out) {
-                                       stack_ptr -= 3;
-                               } else {
-                                       vars[args[0]] = iterator + step;
-                                       pc = top + code_sect;
-                                       if ((pc < code_sect) ||
-                                           (pc >= debug_sect))
-                                               status = -ERANGE;
-                               }
-                       }
-                       break;
-               case OP_PSTR:
-                       /*
-                        * PRINT add string
-                        * ...argument 0 is string ID
-                        */
-                       count = strlen(msg_buff);
-                       strlcpy(&msg_buff[count],
-                               &p[str_table + args[0]],
-                               ALTERA_MESSAGE_LENGTH - count);
-                       break;
-               case OP_SINT:
-                       /*
-                        * STATE intermediate state
-                        * ...argument 0 is state code
-                        */
-                       status = altera_goto_jstate(astate, args[0]);
-                       break;
-               case OP_ST:
-                       /*
-                        * STATE final state
-                        * ...argument 0 is state code
-                        */
-                       status = altera_goto_jstate(astate, args[0]);
-                       break;
-               case OP_ISTP:
-                       /*
-                        * IRSTOP state
-                        * ...argument 0 is state code
-                        */
-                       status = altera_set_irstop(&astate->js, args[0]);
-                       break;
-               case OP_DSTP:
-                       /*
-                        * DRSTOP state
-                        * ...argument 0 is state code
-                        */
-                       status = altera_set_drstop(&astate->js, args[0]);
-                       break;
-
-               case OP_SWPN:
-                       /*
-                        * Exchange top with Nth stack value
-                        * ...argument 0 is 0-based stack entry
-                        * to swap with top element
-                        */
-                       index = (args[0]) + 1;
-                       if (altera_check_stack(stack_ptr, index, &status)) {
-                               long_tmp = stack[stack_ptr - index];
-                               stack[stack_ptr - index] = stack[stack_ptr - 1];
-                               stack[stack_ptr - 1] = long_tmp;
-                       }
-                       break;
-               case OP_DUPN:
-                       /*
-                        * Duplicate Nth stack value
-                        * ...argument 0 is 0-based stack entry to duplicate
-                        */
-                       index = (args[0]) + 1;
-                       if (altera_check_stack(stack_ptr, index, &status)) {
-                               stack[stack_ptr] = stack[stack_ptr - index];
-                               ++stack_ptr;
-                       }
-                       break;
-               case OP_POPV:
-                       /*
-                        * Pop stack into scalar variable
-                        * ...argument 0 is variable ID
-                        * ...stack 0 is value
-                        */
-                       if (altera_check_stack(stack_ptr, 1, &status))
-                               vars[args[0]] = stack[--stack_ptr];
-
-                       break;
-               case OP_POPE:
-                       /*
-                        * Pop stack into integer array element
-                        * ...argument 0 is variable ID
-                        * ...stack 0 is array index
-                        * ...stack 1 is value
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       variable_id = args[0];
-
-                       /*
-                        * If variable is read-only,
-                        * convert to writable array
-                        */
-                       if ((version > 0) &&
-                               ((attrs[variable_id] & 0x9c) == 0x1c)) {
-                               /* Allocate a writable buffer for this array */
-                               count = var_size[variable_id];
-                               long_tmp = vars[variable_id];
-                               longptr_tmp = kzalloc(count * sizeof(long),
-                                                               GFP_KERNEL);
-                               vars[variable_id] = (long)longptr_tmp;
-
-                               if (vars[variable_id] == 0) {
-                                       status = -ENOMEM;
-                                       break;
-                               }
-
-                               /* copy previous contents into buffer */
-                               for (i = 0; i < count; ++i) {
-                                       longptr_tmp[i] =
-                                               get_unaligned_be32(&p[long_tmp]);
-                                       long_tmp += sizeof(long);
-                               }
-
-                               /*
-                                * set bit 7 - buffer was
-                                * dynamically allocated
-                                */
-                               attrs[variable_id] |= 0x80;
-
-                               /* clear bit 2 - variable is writable */
-                               attrs[variable_id] &= ~0x04;
-                               attrs[variable_id] |= 0x01;
-
-                       }
-
-                       /* check that variable is a writable integer array */
-                       if ((attrs[variable_id] & 0x1c) != 0x18)
-                               status = -ERANGE;
-                       else {
-                               longptr_tmp = (long *)vars[variable_id];
-
-                               /* pop the array index */
-                               index = stack[--stack_ptr];
-
-                               /* pop the value and store it into the array */
-                               longptr_tmp[index] = stack[--stack_ptr];
-                       }
-
-                       break;
-               case OP_POPA:
-                       /*
-                        * Pop stack into Boolean array
-                        * ...argument 0 is variable ID
-                        * ...stack 0 is count
-                        * ...stack 1 is array index
-                        * ...stack 2 is value
-                        */
-                       if (!altera_check_stack(stack_ptr, 3, &status))
-                               break;
-                       variable_id = args[0];
-
-                       /*
-                        * If variable is read-only,
-                        * convert to writable array
-                        */
-                       if ((version > 0) &&
-                               ((attrs[variable_id] & 0x9c) == 0x0c)) {
-                               /* Allocate a writable buffer for this array */
-                               long_tmp =
-                                       (var_size[variable_id] + 7L) >> 3L;
-                               charptr_tmp2 = (u8 *)vars[variable_id];
-                               charptr_tmp =
-                                       kzalloc(long_tmp, GFP_KERNEL);
-                               vars[variable_id] = (long)charptr_tmp;
-
-                               if (vars[variable_id] == 0) {
-                                       status = -ENOMEM;
-                                       break;
-                               }
-
-                               /* zero the buffer */
-                               for (long_idx = 0L;
-                                       long_idx < long_tmp;
-                                       ++long_idx) {
-                                       charptr_tmp[long_idx] = 0;
-                               }
-
-                               /* copy previous contents into buffer */
-                               for (long_idx = 0L;
-                                       long_idx < var_size[variable_id];
-                                       ++long_idx) {
-                                       long_idx2 = long_idx;
-
-                                       if (charptr_tmp2[long_idx2 >> 3] &
-                                               (1 << (long_idx2 & 7))) {
-                                               charptr_tmp[long_idx >> 3] |=
-                                                       (1 << (long_idx & 7));
-                                       }
-                               }
-
-                               /*
-                                * set bit 7 - buffer was
-                                * dynamically allocated
-                                */
-                               attrs[variable_id] |= 0x80;
-
-                               /* clear bit 2 - variable is writable */
-                               attrs[variable_id] &= ~0x04;
-                               attrs[variable_id] |= 0x01;
-
-                       }
-
-                       /*
-                        * check that variable is
-                        * a writable Boolean array
-                        */
-                       if ((attrs[variable_id] & 0x1c) != 0x08) {
-                               status = -ERANGE;
-                               break;
-                       }
-
-                       charptr_tmp = (u8 *)vars[variable_id];
-
-                       /* pop the count (number of bits to copy) */
-                       long_count = stack[--stack_ptr];
-
-                       /* pop the array index */
-                       long_idx = stack[--stack_ptr];
-
-                       reverse = 0;
-
-                       if (version > 0) {
-                               /*
-                                * stack 0 = array right index
-                                * stack 1 = array left index
-                                */
-
-                               if (long_idx > long_count) {
-                                       reverse = 1;
-                                       long_tmp = long_count;
-                                       long_count = 1 + long_idx -
-                                                               long_count;
-                                       long_idx = long_tmp;
-
-                                       /* reverse POPA is not supported */
-                                       status = -ERANGE;
-                                       break;
-                               } else
-                                       long_count = 1 + long_count -
-                                                               long_idx;
-
-                       }
-
-                       /* pop the data */
-                       long_tmp = stack[--stack_ptr];
-
-                       if (long_count < 1) {
-                               status = -ERANGE;
-                               break;
-                       }
-
-                       for (i = 0; i < long_count; ++i) {
-                               if (long_tmp & (1L << (s32) i))
-                                       charptr_tmp[long_idx >> 3L] |=
-                                               (1L << (long_idx & 7L));
-                               else
-                                       charptr_tmp[long_idx >> 3L] &=
-                                               ~(1L << (long_idx & 7L));
-
-                               ++long_idx;
-                       }
-
-                       break;
-               case OP_JMPZ:
-                       /*
-                        * Pop stack and branch if zero
-                        * ...argument 0 is address
-                        * ...stack 0 is condition value
-                        */
-                       if (altera_check_stack(stack_ptr, 1, &status)) {
-                               if (stack[--stack_ptr] == 0) {
-                                       pc = args[0] + code_sect;
-                                       if ((pc < code_sect) ||
-                                           (pc >= debug_sect))
-                                               status = -ERANGE;
-                               }
-                       }
-                       break;
-               case OP_DS:
-               case OP_IS:
-                       /*
-                        * DRSCAN
-                        * IRSCAN
-                        * ...argument 0 is scan data variable ID
-                        * ...stack 0 is array index
-                        * ...stack 1 is count
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       long_idx = stack[--stack_ptr];
-                       long_count = stack[--stack_ptr];
-                       reverse = 0;
-                       if (version > 0) {
-                               /*
-                                * stack 0 = array right index
-                                * stack 1 = array left index
-                                * stack 2 = count
-                                */
-                               long_tmp = long_count;
-                               long_count = stack[--stack_ptr];
-
-                               if (long_idx > long_tmp) {
-                                       reverse = 1;
-                                       long_idx = long_tmp;
-                               }
-                       }
-
-                       charptr_tmp = (u8 *)vars[args[0]];
-
-                       if (reverse) {
-                               /*
-                                * allocate a buffer
-                                * and reverse the data order
-                                */
-                               charptr_tmp2 = charptr_tmp;
-                               charptr_tmp = kzalloc((long_count >> 3) + 1,
-                                                               GFP_KERNEL);
-                               if (charptr_tmp == NULL) {
-                                       status = -ENOMEM;
-                                       break;
-                               }
-
-                               long_tmp = long_idx + long_count - 1;
-                               long_idx2 = 0;
-                               while (long_idx2 < long_count) {
-                                       if (charptr_tmp2[long_tmp >> 3] &
-                                                       (1 << (long_tmp & 7)))
-                                               charptr_tmp[long_idx2 >> 3] |=
-                                                       (1 << (long_idx2 & 7));
-                                       else
-                                               charptr_tmp[long_idx2 >> 3] &=
-                                                       ~(1 << (long_idx2 & 7));
-
-                                       --long_tmp;
-                                       ++long_idx2;
-                               }
-                       }
-
-                       if (opcode == 0x51) /* DS */
-                               status = altera_drscan(astate, long_count,
-                                               charptr_tmp, long_idx);
-                       else /* IS */
-                               status = altera_irscan(astate, long_count,
-                                               charptr_tmp, long_idx);
-
-                       if (reverse)
-                               kfree(charptr_tmp);
-
-                       break;
-               case OP_DPRA:
-                       /*
-                        * DRPRE with array data
-                        * ...argument 0 is variable ID
-                        * ...stack 0 is array index
-                        * ...stack 1 is count
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       index = stack[--stack_ptr];
-                       count = stack[--stack_ptr];
-
-                       if (version > 0)
-                               /*
-                                * stack 0 = array right index
-                                * stack 1 = array left index
-                                */
-                               count = 1 + count - index;
-
-                       charptr_tmp = (u8 *)vars[args[0]];
-                       status = altera_set_dr_pre(&astate->js, count, index,
-                                                       charptr_tmp);
-                       break;
-               case OP_DPOA:
-                       /*
-                        * DRPOST with array data
-                        * ...argument 0 is variable ID
-                        * ...stack 0 is array index
-                        * ...stack 1 is count
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       index = stack[--stack_ptr];
-                       count = stack[--stack_ptr];
-
-                       if (version > 0)
-                               /*
-                                * stack 0 = array right index
-                                * stack 1 = array left index
-                                */
-                               count = 1 + count - index;
-
-                       charptr_tmp = (u8 *)vars[args[0]];
-                       status = altera_set_dr_post(&astate->js, count, index,
-                                                       charptr_tmp);
-                       break;
-               case OP_IPRA:
-                       /*
-                        * IRPRE with array data
-                        * ...argument 0 is variable ID
-                        * ...stack 0 is array index
-                        * ...stack 1 is count
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       index = stack[--stack_ptr];
-                       count = stack[--stack_ptr];
-
-                       if (version > 0)
-                               /*
-                                * stack 0 = array right index
-                                * stack 1 = array left index
-                                */
-                               count = 1 + count - index;
-
-                       charptr_tmp = (u8 *)vars[args[0]];
-                       status = altera_set_ir_pre(&astate->js, count, index,
-                                                       charptr_tmp);
-
-                       break;
-               case OP_IPOA:
-                       /*
-                        * IRPOST with array data
-                        * ...argument 0 is variable ID
-                        * ...stack 0 is array index
-                        * ...stack 1 is count
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       index = stack[--stack_ptr];
-                       count = stack[--stack_ptr];
-
-                       if (version > 0)
-                               /*
-                                * stack 0 = array right index
-                                * stack 1 = array left index
-                                */
-                               count = 1 + count - index;
-
-                       charptr_tmp = (u8 *)vars[args[0]];
-                       status = altera_set_ir_post(&astate->js, count, index,
-                                                       charptr_tmp);
-
-                       break;
-               case OP_EXPT:
-                       /*
-                        * EXPORT
-                        * ...argument 0 is string ID
-                        * ...stack 0 is integer expression
-                        */
-                       if (altera_check_stack(stack_ptr, 1, &status)) {
-                               name = &p[str_table + args[0]];
-                               long_tmp = stack[--stack_ptr];
-                               altera_export_int(name, long_tmp);
-                       }
-                       break;
-               case OP_PSHE:
-                       /*
-                        * Push integer array element
-                        * ...argument 0 is variable ID
-                        * ...stack 0 is array index
-                        */
-                       if (!altera_check_stack(stack_ptr, 1, &status))
-                               break;
-                       variable_id = args[0];
-                       index = stack[stack_ptr - 1];
-
-                       /* check variable type */
-                       if ((attrs[variable_id] & 0x1f) == 0x19) {
-                               /* writable integer array */
-                               longptr_tmp = (long *)vars[variable_id];
-                               stack[stack_ptr - 1] = longptr_tmp[index];
-                       } else if ((attrs[variable_id] & 0x1f) == 0x1c) {
-                               /* read-only integer array */
-                               long_tmp = vars[variable_id] +
-                                               (index * sizeof(long));
-                               stack[stack_ptr - 1] =
-                                       get_unaligned_be32(&p[long_tmp]);
-                       } else
-                               status = -ERANGE;
-
-                       break;
-               case OP_PSHA:
-                       /*
-                        * Push Boolean array
-                        * ...argument 0 is variable ID
-                        * ...stack 0 is count
-                        * ...stack 1 is array index
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       variable_id = args[0];
-
-                       /* check that variable is a Boolean array */
-                       if ((attrs[variable_id] & 0x18) != 0x08) {
-                               status = -ERANGE;
-                               break;
-                       }
-
-                       charptr_tmp = (u8 *)vars[variable_id];
-
-                       /* pop the count (number of bits to copy) */
-                       count = stack[--stack_ptr];
-
-                       /* pop the array index */
-                       index = stack[stack_ptr - 1];
-
-                       if (version > 0)
-                               /*
-                                * stack 0 = array right index
-                                * stack 1 = array left index
-                                */
-                               count = 1 + count - index;
-
-                       if ((count < 1) || (count > 32)) {
-                               status = -ERANGE;
-                               break;
-                       }
-
-                       long_tmp = 0L;
-
-                       for (i = 0; i < count; ++i)
-                               if (charptr_tmp[(i + index) >> 3] &
-                                               (1 << ((i + index) & 7)))
-                                       long_tmp |= (1L << i);
-
-                       stack[stack_ptr - 1] = long_tmp;
-
-                       break;
-               case OP_DYNA:
-                       /*
-                        * Dynamically change size of array
-                        * ...argument 0 is variable ID
-                        * ...stack 0 is new size
-                        */
-                       if (!altera_check_stack(stack_ptr, 1, &status))
-                               break;
-                       variable_id = args[0];
-                       long_tmp = stack[--stack_ptr];
-
-                       if (long_tmp > var_size[variable_id]) {
-                               var_size[variable_id] = long_tmp;
-
-                               if (attrs[variable_id] & 0x10)
-                                       /* allocate integer array */
-                                       long_tmp *= sizeof(long);
-                               else
-                                       /* allocate Boolean array */
-                                       long_tmp = (long_tmp + 7) >> 3;
-
-                               /*
-                                * If the buffer was previously allocated,
-                                * free it
-                                */
-                               if (attrs[variable_id] & 0x80) {
-                                       kfree((void *)vars[variable_id]);
-                                       vars[variable_id] = 0;
-                               }
-
-                               /*
-                                * Allocate a new buffer
-                                * of the requested size
-                                */
-                               vars[variable_id] = (long)
-                                       kzalloc(long_tmp, GFP_KERNEL);
-
-                               if (vars[variable_id] == 0) {
-                                       status = -ENOMEM;
-                                       break;
-                               }
-
-                               /*
-                                * Set the attribute bit to indicate that
-                                * this buffer was dynamically allocated and
-                                * should be freed later
-                                */
-                               attrs[variable_id] |= 0x80;
-
-                               /* zero out memory */
-                               count = ((var_size[variable_id] + 7L) /
-                                                                       8L);
-                               charptr_tmp = (u8 *)(vars[variable_id]);
-                               for (index = 0; index < count; ++index)
-                                       charptr_tmp[index] = 0;
-
-                       }
-
-                       break;
-               case OP_EXPV:
-                       /*
-                        * Export Boolean array
-                        * ...argument 0 is string ID
-                        * ...stack 0 is variable ID
-                        * ...stack 1 is array right index
-                        * ...stack 2 is array left index
-                        */
-                       if (!altera_check_stack(stack_ptr, 3, &status))
-                               break;
-                       if (version == 0) {
-                               /* EXPV is not supported in JBC 1.0 */
-                               bad_opcode = 1;
-                               break;
-                       }
-                       name = &p[str_table + args[0]];
-                       variable_id = stack[--stack_ptr];
-                       long_idx = stack[--stack_ptr];/* right indx */
-                       long_idx2 = stack[--stack_ptr];/* left indx */
-
-                       if (long_idx > long_idx2) {
-                               /* reverse indices not supported */
-                               status = -ERANGE;
-                               break;
-                       }
-
-                       long_count = 1 + long_idx2 - long_idx;
-
-                       charptr_tmp = (u8 *)vars[variable_id];
-                       charptr_tmp2 = NULL;
-
-                       if ((long_idx & 7L) != 0) {
-                               s32 k = long_idx;
-                               charptr_tmp2 =
-                                       kzalloc(((long_count + 7L) / 8L),
-                                                       GFP_KERNEL);
-                               if (charptr_tmp2 == NULL) {
-                                       status = -ENOMEM;
-                                       break;
-                               }
-
-                               for (i = 0; i < long_count; ++i) {
-                                       if (charptr_tmp[k >> 3] &
-                                                       (1 << (k & 7)))
-                                               charptr_tmp2[i >> 3] |=
-                                                               (1 << (i & 7));
-                                       else
-                                               charptr_tmp2[i >> 3] &=
-                                                               ~(1 << (i & 7));
-
-                                       ++k;
-                               }
-                               charptr_tmp = charptr_tmp2;
-
-                       } else if (long_idx != 0)
-                               charptr_tmp = &charptr_tmp[long_idx >> 3];
-
-                       altera_export_bool_array(name, charptr_tmp,
-                                                       long_count);
-
-                       /* free allocated buffer */
-                       if ((long_idx & 7L) != 0)
-                               kfree(charptr_tmp2);
-
-                       break;
-               case OP_COPY: {
-                       /*
-                        * Array copy
-                        * ...argument 0 is dest ID
-                        * ...argument 1 is source ID
-                        * ...stack 0 is count
-                        * ...stack 1 is dest index
-                        * ...stack 2 is source index
-                        */
-                       s32 copy_count;
-                       s32 copy_index;
-                       s32 copy_index2;
-                       s32 destleft;
-                       s32 src_count;
-                       s32 dest_count;
-                       int src_reverse = 0;
-                       int dest_reverse = 0;
-
-                       if (!altera_check_stack(stack_ptr, 3, &status))
-                               break;
-
-                       copy_count = stack[--stack_ptr];
-                       copy_index = stack[--stack_ptr];
-                       copy_index2 = stack[--stack_ptr];
-                       reverse = 0;
-
-                       if (version > 0) {
-                               /*
-                                * stack 0 = source right index
-                                * stack 1 = source left index
-                                * stack 2 = destination right index
-                                * stack 3 = destination left index
-                                */
-                               destleft = stack[--stack_ptr];
-
-                               if (copy_count > copy_index) {
-                                       src_reverse = 1;
-                                       reverse = 1;
-                                       src_count = 1 + copy_count - copy_index;
-                                       /* copy_index = source start index */
-                               } else {
-                                       src_count = 1 + copy_index - copy_count;
-                                       /* source start index */
-                                       copy_index = copy_count;
-                               }
-
-                               if (copy_index2 > destleft) {
-                                       dest_reverse = 1;
-                                       reverse = !reverse;
-                                       dest_count = 1 + copy_index2 - destleft;
-                                       /* destination start index */
-                                       copy_index2 = destleft;
-                               } else
-                                       dest_count = 1 + destleft - copy_index2;
-
-                               copy_count = (src_count < dest_count) ?
-                                                       src_count : dest_count;
-
-                               if ((src_reverse || dest_reverse) &&
-                                       (src_count != dest_count))
-                                       /*
-                                        * If either the source or destination
-                                        * is reversed, we can't tolerate
-                                        * a length mismatch, because we
-                                        * "left justify" arrays when copying.
-                                        * This won't work correctly
-                                        * with reversed arrays.
-                                        */
-                                       status = -ERANGE;
-
-                       }
-
-                       count = copy_count;
-                       index = copy_index;
-                       index2 = copy_index2;
-
-                       /*
-                        * If destination is a read-only array,
-                        * allocate a buffer and convert it to a writable array
-                        */
-                       variable_id = args[1];
-                       if ((version > 0) &&
-                               ((attrs[variable_id] & 0x9c) == 0x0c)) {
-                               /* Allocate a writable buffer for this array */
-                               long_tmp =
-                                       (var_size[variable_id] + 7L) >> 3L;
-                               charptr_tmp2 = (u8 *)vars[variable_id];
-                               charptr_tmp =
-                                       kzalloc(long_tmp, GFP_KERNEL);
-                               vars[variable_id] = (long)charptr_tmp;
-
-                               if (vars[variable_id] == 0) {
-                                       status = -ENOMEM;
-                                       break;
-                               }
-
-                               /* zero the buffer */
-                               for (long_idx = 0L; long_idx < long_tmp;
-                                                               ++long_idx)
-                                       charptr_tmp[long_idx] = 0;
-
-                               /* copy previous contents into buffer */
-                               for (long_idx = 0L;
-                                       long_idx < var_size[variable_id];
-                                                               ++long_idx) {
-                                       long_idx2 = long_idx;
-
-                                       if (charptr_tmp2[long_idx2 >> 3] &
-                                               (1 << (long_idx2 & 7)))
-                                               charptr_tmp[long_idx >> 3] |=
-                                                       (1 << (long_idx & 7));
-
-                               }
-
-                               /*
-                               set bit 7 - buffer was dynamically allocated */
-                               attrs[variable_id] |= 0x80;
-
-                               /* clear bit 2 - variable is writable */
-                               attrs[variable_id] &= ~0x04;
-                               attrs[variable_id] |= 0x01;
-                       }
-
-                       charptr_tmp = (u8 *)vars[args[1]];
-                       charptr_tmp2 = (u8 *)vars[args[0]];
-
-                       /* check if destination is a writable Boolean array */
-                       if ((attrs[args[1]] & 0x1c) != 0x08) {
-                               status = -ERANGE;
-                               break;
-                       }
-
-                       if (count < 1) {
-                               status = -ERANGE;
-                               break;
-                       }
-
-                       if (reverse)
-                               index2 += (count - 1);
-
-                       for (i = 0; i < count; ++i) {
-                               if (charptr_tmp2[index >> 3] &
-                                                       (1 << (index & 7)))
-                                       charptr_tmp[index2 >> 3] |=
-                                                       (1 << (index2 & 7));
-                               else
-                                       charptr_tmp[index2 >> 3] &=
-                                               ~(1 << (index2 & 7));
-
-                               ++index;
-                               if (reverse)
-                                       --index2;
-                               else
-                                       ++index2;
-                       }
-
-                       break;
-               }
-               case OP_DSC:
-               case OP_ISC: {
-                       /*
-                        * DRSCAN with capture
-                        * IRSCAN with capture
-                        * ...argument 0 is scan data variable ID
-                        * ...argument 1 is capture variable ID
-                        * ...stack 0 is capture index
-                        * ...stack 1 is scan data index
-                        * ...stack 2 is count
-                        */
-                       s32 scan_right, scan_left;
-                       s32 capture_count = 0;
-                       s32 scan_count = 0;
-                       s32 capture_index;
-                       s32 scan_index;
-
-                       if (!altera_check_stack(stack_ptr, 3, &status))
-                               break;
-
-                       capture_index = stack[--stack_ptr];
-                       scan_index = stack[--stack_ptr];
-
-                       if (version > 0) {
-                               /*
-                                * stack 0 = capture right index
-                                * stack 1 = capture left index
-                                * stack 2 = scan right index
-                                * stack 3 = scan left index
-                                * stack 4 = count
-                                */
-                               scan_right = stack[--stack_ptr];
-                               scan_left = stack[--stack_ptr];
-                               capture_count = 1 + scan_index - capture_index;
-                               scan_count = 1 + scan_left - scan_right;
-                               scan_index = scan_right;
-                       }
-
-                       long_count = stack[--stack_ptr];
-                       /*
-                        * If capture array is read-only, allocate a buffer
-                        * and convert it to a writable array
-                        */
-                       variable_id = args[1];
-                       if ((version > 0) &&
-                               ((attrs[variable_id] & 0x9c) == 0x0c)) {
-                               /* Allocate a writable buffer for this array */
-                               long_tmp =
-                                       (var_size[variable_id] + 7L) >> 3L;
-                               charptr_tmp2 = (u8 *)vars[variable_id];
-                               charptr_tmp =
-                                       kzalloc(long_tmp, GFP_KERNEL);
-                               vars[variable_id] = (long)charptr_tmp;
-
-                               if (vars[variable_id] == 0) {
-                                       status = -ENOMEM;
-                                       break;
-                               }
-
-                               /* zero the buffer */
-                               for (long_idx = 0L; long_idx < long_tmp;
-                                                               ++long_idx)
-                                       charptr_tmp[long_idx] = 0;
-
-                               /* copy previous contents into buffer */
-                               for (long_idx = 0L;
-                                       long_idx < var_size[variable_id];
-                                                               ++long_idx) {
-                                       long_idx2 = long_idx;
-
-                                       if (charptr_tmp2[long_idx2 >> 3] &
-                                               (1 << (long_idx2 & 7)))
-                                               charptr_tmp[long_idx >> 3] |=
-                                                       (1 << (long_idx & 7));
-
-                               }
-
-                               /*
-                                * set bit 7 - buffer was
-                                * dynamically allocated
-                                */
-                               attrs[variable_id] |= 0x80;
-
-                               /* clear bit 2 - variable is writable */
-                               attrs[variable_id] &= ~0x04;
-                               attrs[variable_id] |= 0x01;
-
-                       }
-
-                       charptr_tmp = (u8 *)vars[args[0]];
-                       charptr_tmp2 = (u8 *)vars[args[1]];
-
-                       if ((version > 0) &&
-                                       ((long_count > capture_count) ||
-                                       (long_count > scan_count))) {
-                               status = -ERANGE;
-                               break;
-                       }
-
-                       /*
-                        * check that capture array
-                        * is a writable Boolean array
-                        */
-                       if ((attrs[args[1]] & 0x1c) != 0x08) {
-                               status = -ERANGE;
-                               break;
-                       }
-
-                       if (status == 0) {
-                               if (opcode == 0x82) /* DSC */
-                                       status = altera_swap_dr(astate,
-                                                       long_count,
-                                                       charptr_tmp,
-                                                       scan_index,
-                                                       charptr_tmp2,
-                                                       capture_index);
-                               else /* ISC */
-                                       status = altera_swap_ir(astate,
-                                                       long_count,
-                                                       charptr_tmp,
-                                                       scan_index,
-                                                       charptr_tmp2,
-                                                       capture_index);
-
-                       }
-
-                       break;
-               }
-               case OP_WAIT:
-                       /*
-                        * WAIT
-                        * ...argument 0 is wait state
-                        * ...argument 1 is end state
-                        * ...stack 0 is cycles
-                        * ...stack 1 is microseconds
-                        */
-                       if (!altera_check_stack(stack_ptr, 2, &status))
-                               break;
-                       long_tmp = stack[--stack_ptr];
-
-                       if (long_tmp != 0L)
-                               status = altera_wait_cycles(astate, long_tmp,
-                                                               args[0]);
-
-                       long_tmp = stack[--stack_ptr];
-
-                       if ((status == 0) && (long_tmp != 0L))
-                               status = altera_wait_msecs(astate,
-                                                               long_tmp,
-                                                               args[0]);
-
-                       if ((status == 0) && (args[1] != args[0]))
-                               status = altera_goto_jstate(astate,
-                                                               args[1]);
-
-                       if (version > 0) {
-                               --stack_ptr; /* throw away MAX cycles */
-                               --stack_ptr; /* throw away MAX microseconds */
-                       }
-                       break;
-               case OP_CMPA: {
-                       /*
-                        * Array compare
-                        * ...argument 0 is source 1 ID
-                        * ...argument 1 is source 2 ID
-                        * ...argument 2 is mask ID
-                        * ...stack 0 is source 1 index
-                        * ...stack 1 is source 2 index
-                        * ...stack 2 is mask index
-                        * ...stack 3 is count
-                        */
-                       s32 a, b;
-                       u8 *source1 = (u8 *)vars[args[0]];
-                       u8 *source2 = (u8 *)vars[args[1]];
-                       u8 *mask = (u8 *)vars[args[2]];
-                       u32 index1;
-                       u32 index2;
-                       u32 mask_index;
-
-                       if (!altera_check_stack(stack_ptr, 4, &status))
-                               break;
-
-                       index1 = stack[--stack_ptr];
-                       index2 = stack[--stack_ptr];
-                       mask_index = stack[--stack_ptr];
-                       long_count = stack[--stack_ptr];
-
-                       if (version > 0) {
-                               /*
-                                * stack 0 = source 1 right index
-                                * stack 1 = source 1 left index
-                                * stack 2 = source 2 right index
-                                * stack 3 = source 2 left index
-                                * stack 4 = mask right index
-                                * stack 5 = mask left index
-                                */
-                               s32 mask_right = stack[--stack_ptr];
-                               s32 mask_left = stack[--stack_ptr];
-                               /* source 1 count */
-                               a = 1 + index2 - index1;
-                               /* source 2 count */
-                               b = 1 + long_count - mask_index;
-                               a = (a < b) ? a : b;
-                               /* mask count */
-                               b = 1 + mask_left - mask_right;
-                               a = (a < b) ? a : b;
-                               /* source 2 start index */
-                               index2 = mask_index;
-                               /* mask start index */
-                               mask_index = mask_right;
-                               long_count = a;
-                       }
-
-                       long_tmp = 1L;
-
-                       if (long_count < 1)
-                               status = -ERANGE;
-                       else {
-                               count = long_count;
-
-                               for (i = 0; i < count; ++i) {
-                                       if (mask[mask_index >> 3] &
-                                               (1 << (mask_index & 7))) {
-                                               a = source1[index1 >> 3] &
-                                                       (1 << (index1 & 7))
-                                                               ? 1 : 0;
-                                               b = source2[index2 >> 3] &
-                                                       (1 << (index2 & 7))
-                                                               ? 1 : 0;
-
-                                               if (a != b) /* failure */
-                                                       long_tmp = 0L;
-                                       }
-                                       ++index1;
-                                       ++index2;
-                                       ++mask_index;
-                               }
-                       }
-
-                       stack[stack_ptr++] = long_tmp;
-
-                       break;
-               }
-               default:
-                       /* Unrecognized opcode -- ERROR! */
-                       bad_opcode = 1;
-                       break;
-               }
-
-               if (bad_opcode)
-                       status = -ENOSYS;
-
-               if ((stack_ptr < 0) || (stack_ptr >= ALTERA_STACK_SIZE))
-                       status = -EOVERFLOW;
-
-               if (status != 0) {
-                       done = 1;
-                       *error_address = (s32)(opcode_address - code_sect);
-               }
-       }
-
-       altera_free_buffers(astate);
-
-       /* Free all dynamically allocated arrays */
-       if ((attrs != NULL) && (vars != NULL))
-               for (i = 0; i < sym_count; ++i)
-                       if (attrs[i] & 0x80)
-                               kfree((void *)vars[i]);
-
-       kfree(vars);
-       kfree(var_size);
-       kfree(attrs);
-       kfree(proc_attributes);
-
-       return status;
-}
-
-static int altera_get_note(u8 *p, s32 program_size,
-                       s32 *offset, char *key, char *value, int length)
-/*
- * Gets key and value of NOTE fields in the JBC file.
- * Can be called in two modes:  if offset pointer is NULL,
- * then the function searches for note fields which match
- * the key string provided.  If offset is not NULL, then
- * the function finds the next note field of any key,
- * starting at the offset specified by the offset pointer.
- * Returns 0 for success, else appropriate error code
- */
-{
-       int status = -ENODATA;
-       u32 note_strings = 0L;
-       u32 note_table = 0L;
-       u32 note_count = 0L;
-       u32 first_word = 0L;
-       int version = 0;
-       int delta = 0;
-       char *key_ptr;
-       char *value_ptr;
-       int i;
-
-       /* Read header information */
-       if (program_size > 52L) {
-               first_word    = get_unaligned_be32(&p[0]);
-               version = (first_word & 1L);
-               delta = version * 8;
-
-               note_strings  = get_unaligned_be32(&p[8 + delta]);
-               note_table    = get_unaligned_be32(&p[12 + delta]);
-               note_count    = get_unaligned_be32(&p[44 + (2 * delta)]);
-       }
-
-       if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L))
-               return -EIO;
-
-       if (note_count <= 0L)
-               return status;
-
-       if (offset == NULL) {
-               /*
-                * We will search for the first note with a specific key,
-                * and return only the value
-                */
-               for (i = 0; (i < note_count) &&
-                                               (status != 0); ++i) {
-                       key_ptr = &p[note_strings +
-                                       get_unaligned_be32(
-                                       &p[note_table + (8 * i)])];
-                       if ((strnicmp(key, key_ptr, strlen(key_ptr)) == 0) &&
-                                               (key != NULL)) {
-                               status = 0;
-
-                               value_ptr = &p[note_strings +
-                                               get_unaligned_be32(
-                                               &p[note_table + (8 * i) + 4])];
-
-                               if (value != NULL)
-                                       strlcpy(value, value_ptr, length);
-
-                       }
-               }
-       } else {
-               /*
-                * We will search for the next note, regardless of the key,
-                * and return both the value and the key
-                */
-
-               i = *offset;
-
-               if ((i >= 0) && (i < note_count)) {
-                       status = 0;
-
-                       if (key != NULL)
-                               strlcpy(key, &p[note_strings +
-                                               get_unaligned_be32(
-                                               &p[note_table + (8 * i)])],
-                                       length);
-
-                       if (value != NULL)
-                               strlcpy(value, &p[note_strings +
-                                               get_unaligned_be32(
-                                               &p[note_table + (8 * i) + 4])],
-                                       length);
-
-                       *offset = i + 1;
-               }
-       }
-
-       return status;
-}
-
-static int altera_check_crc(u8 *p, s32 program_size)
-{
-       int status = 0;
-       u16 local_expected = 0,
-           local_actual = 0,
-           shift_reg = 0xffff;
-       int bit, feedback;
-       u8 databyte;
-       u32 i;
-       u32 crc_section = 0L;
-       u32 first_word = 0L;
-       int version = 0;
-       int delta = 0;
-
-       if (program_size > 52L) {
-               first_word  = get_unaligned_be32(&p[0]);
-               version = (first_word & 1L);
-               delta = version * 8;
-
-               crc_section = get_unaligned_be32(&p[32 + delta]);
-       }
-
-       if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L))
-               status = -EIO;
-
-       if (crc_section >= program_size)
-               status = -EIO;
-
-       if (status == 0) {
-               local_expected = (u16)get_unaligned_be16(&p[crc_section]);
-
-               for (i = 0; i < crc_section; ++i) {
-                       databyte = p[i];
-                       for (bit = 0; bit < 8; bit++) {
-                               feedback = (databyte ^ shift_reg) & 0x01;
-                               shift_reg >>= 1;
-                               if (feedback)
-                                       shift_reg ^= 0x8408;
-
-                               databyte >>= 1;
-                       }
-               }
-
-               local_actual = (u16)~shift_reg;
-
-               if (local_expected != local_actual)
-                       status = -EILSEQ;
-
-       }
-
-       if (debug || status) {
-               switch (status) {
-               case 0:
-                       printk(KERN_INFO "%s: CRC matched: %04x\n", __func__,
-                               local_actual);
-                       break;
-               case -EILSEQ:
-                       printk(KERN_ERR "%s: CRC mismatch: expected %04x, "
-                               "actual %04x\n", __func__, local_expected,
-                               local_actual);
-                       break;
-               case -ENODATA:
-                       printk(KERN_ERR "%s: expected CRC not found, "
-                               "actual CRC = %04x\n", __func__,
-                               local_actual);
-                       break;
-               case -EIO:
-                       printk(KERN_ERR "%s: error: format isn't "
-                               "recognized.\n", __func__);
-                       break;
-               default:
-                       printk(KERN_ERR "%s: CRC function returned error "
-                               "code %d\n", __func__, status);
-                       break;
-               }
-       }
-
-       return status;
-}
-
-static int altera_get_file_info(u8 *p,
-                                       s32 program_size,
-                                       int *format_version,
-                                       int *action_count,
-                                       int *procedure_count)
-{
-       int status = -EIO;
-       u32 first_word = 0;
-       int version = 0;
-
-       if (program_size <= 52L)
-               return status;
-
-       first_word = get_unaligned_be32(&p[0]);
-
-       if ((first_word == 0x4A414D00L) || (first_word == 0x4A414D01L)) {
-               status = 0;
-
-               version = (first_word & 1L);
-               *format_version = version + 1;
-
-               if (version > 0) {
-                       *action_count = get_unaligned_be32(&p[48]);
-                       *procedure_count = get_unaligned_be32(&p[52]);
-               }
-       }
-
-       return status;
-}
-
-static int altera_get_act_info(u8 *p,
-                                       s32 program_size,
-                                       int index,
-                                       char **name,
-                                       char **description,
-                                       struct altera_procinfo **proc_list)
-{
-       int status = -EIO;
-       struct altera_procinfo *procptr = NULL;
-       struct altera_procinfo *tmpptr = NULL;
-       u32 first_word = 0L;
-       u32 action_table = 0L;
-       u32 proc_table = 0L;
-       u32 str_table = 0L;
-       u32 note_strings = 0L;
-       u32 action_count = 0L;
-       u32 proc_count = 0L;
-       u32 act_name_id = 0L;
-       u32 act_desc_id = 0L;
-       u32 act_proc_id = 0L;
-       u32 act_proc_name = 0L;
-       u8 act_proc_attribute = 0;
-
-       if (program_size <= 52L)
-               return status;
-       /* Read header information */
-       first_word = get_unaligned_be32(&p[0]);
-
-       if (first_word != 0x4A414D01L)
-               return status;
-
-       action_table = get_unaligned_be32(&p[4]);
-       proc_table   = get_unaligned_be32(&p[8]);
-       str_table = get_unaligned_be32(&p[12]);
-       note_strings = get_unaligned_be32(&p[16]);
-       action_count = get_unaligned_be32(&p[48]);
-       proc_count   = get_unaligned_be32(&p[52]);
-
-       if (index >= action_count)
-               return status;
-
-       act_name_id = get_unaligned_be32(&p[action_table + (12 * index)]);
-       act_desc_id = get_unaligned_be32(&p[action_table + (12 * index) + 4]);
-       act_proc_id = get_unaligned_be32(&p[action_table + (12 * index) + 8]);
-
-       *name = &p[str_table + act_name_id];
-
-       if (act_desc_id < (note_strings - str_table))
-               *description = &p[str_table + act_desc_id];
-
-       do {
-               act_proc_name = get_unaligned_be32(
-                                       &p[proc_table + (13 * act_proc_id)]);
-               act_proc_attribute =
-                       (p[proc_table + (13 * act_proc_id) + 8] & 0x03);
-
-               procptr =
-                               kzalloc(sizeof(struct altera_procinfo),
-                                                               GFP_KERNEL);
-
-               if (procptr == NULL)
-                       status = -ENOMEM;
-               else {
-                       procptr->name = &p[str_table + act_proc_name];
-                       procptr->attrs = act_proc_attribute;
-                       procptr->next = NULL;
-
-                       /* add record to end of linked list */
-                       if (*proc_list == NULL)
-                               *proc_list = procptr;
-                       else {
-                               tmpptr = *proc_list;
-                               while (tmpptr->next != NULL)
-                                       tmpptr = tmpptr->next;
-                               tmpptr->next = procptr;
-                       }
-               }
-
-               act_proc_id = get_unaligned_be32(
-                               &p[proc_table + (13 * act_proc_id) + 4]);
-       } while ((act_proc_id != 0) && (act_proc_id < proc_count));
-
-       return status;
-}
-
-int altera_init(struct altera_config *config, const struct firmware *fw)
-{
-       struct altera_state *astate = NULL;
-       struct altera_procinfo *proc_list = NULL;
-       struct altera_procinfo *procptr = NULL;
-       char *key = NULL;
-       char *value = NULL;
-       char *action_name = NULL;
-       char *description = NULL;
-       int exec_result = 0;
-       int exit_code = 0;
-       int format_version = 0;
-       int action_count = 0;
-       int procedure_count = 0;
-       int index = 0;
-       s32 offset = 0L;
-       s32 error_address = 0L;
-       int retval = 0;
-
-       key = kzalloc(33, GFP_KERNEL);
-       if (!key) {
-               retval = -ENOMEM;
-               goto out;
-       }
-       value = kzalloc(257, GFP_KERNEL);
-       if (!value) {
-               retval = -ENOMEM;
-               goto free_key;
-       }
-       astate = kzalloc(sizeof(struct altera_state), GFP_KERNEL);
-       if (!astate) {
-               retval = -ENOMEM;
-               goto free_value;
-       }
-
-       astate->config = config;
-       if (!astate->config->jtag_io) {
-               dprintk(KERN_INFO "%s: using byteblaster!\n", __func__);
-               astate->config->jtag_io = netup_jtag_io_lpt;
-       }
-
-       altera_check_crc((u8 *)fw->data, fw->size);
-
-       if (debug) {
-               altera_get_file_info((u8 *)fw->data, fw->size, &format_version,
-                                       &action_count, &procedure_count);
-               printk(KERN_INFO "%s: File format is %s ByteCode format\n",
-                       __func__, (format_version == 2) ? "Jam STAPL" :
-                                               "pre-standardized Jam 1.1");
-               while (altera_get_note((u8 *)fw->data, fw->size,
-                                       &offset, key, value, 256) == 0)
-                       printk(KERN_INFO "%s: NOTE \"%s\" = \"%s\"\n",
-                                       __func__, key, value);
-       }
-
-       if (debug && (format_version == 2) && (action_count > 0)) {
-               printk(KERN_INFO "%s: Actions available:\n", __func__);
-               for (index = 0; index < action_count; ++index) {
-                       altera_get_act_info((u8 *)fw->data, fw->size,
-                                               index, &action_name,
-                                               &description,
-                                               &proc_list);
-
-                       if (description == NULL)
-                               printk(KERN_INFO "%s: %s\n",
-                                               __func__,
-                                               action_name);
-                       else
-                               printk(KERN_INFO "%s: %s \"%s\"\n",
-                                               __func__,
-                                               action_name,
-                                               description);
-
-                       procptr = proc_list;
-                       while (procptr != NULL) {
-                               if (procptr->attrs != 0)
-                                       printk(KERN_INFO "%s:    %s (%s)\n",
-                                               __func__,
-                                               procptr->name,
-                                               (procptr->attrs == 1) ?
-                                               "optional" : "recommended");
-
-                               proc_list = procptr->next;
-                               kfree(procptr);
-                               procptr = proc_list;
-                       }
-               }
-
-               printk(KERN_INFO "\n");
-       }
-
-       exec_result = altera_execute(astate, (u8 *)fw->data, fw->size,
-                               &error_address, &exit_code, &format_version);
-
-       if (exit_code)
-               exec_result = -EREMOTEIO;
-
-       if ((format_version == 2) && (exec_result == -EINVAL)) {
-               if (astate->config->action == NULL)
-                       printk(KERN_ERR "%s: error: no action specified for "
-                               "Jam STAPL file.\nprogram terminated.\n",
-                               __func__);
-               else
-                       printk(KERN_ERR "%s: error: action \"%s\""
-                               " is not supported "
-                               "for this Jam STAPL file.\n"
-                               "Program terminated.\n", __func__,
-                               astate->config->action);
-
-       } else if (exec_result)
-               printk(KERN_ERR "%s: error %d\n", __func__, exec_result);
-
-       kfree(astate);
-free_value:
-       kfree(value);
-free_key:
-       kfree(key);
-out:
-       return retval;
-}
-EXPORT_SYMBOL(altera_init);
diff --git a/drivers/staging/altera-stapl/altera.h b/drivers/staging/altera-stapl/altera.h
deleted file mode 100644 (file)
index 94c0c61..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * altera.h
- *
- * altera FPGA driver
- *
- * Copyright (C) Altera Corporation 1998-2001
- * Copyright (C) 2010 NetUP Inc.
- * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
- *
- * 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 _ALTERA_H_
-#define _ALTERA_H_
-
-struct altera_config {
-       void *dev;
-       u8 *action;
-       int (*jtag_io) (void *dev, int tms, int tdi, int tdo);
-};
-
-#if defined(CONFIG_ALTERA_STAPL) || \
-               (defined(CONFIG_ALTERA_STAPL_MODULE) && defined(MODULE))
-
-extern int altera_init(struct altera_config *config, const struct firmware *fw);
-#else
-
-static inline int altera_init(struct altera_config *config,
-                                               const struct firmware *fw)
-{
-       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-       return 0;
-}
-#endif /* CONFIG_ALTERA_STAPL */
-
-#endif /* _ALTERA_H_ */
index 5b212dc..04e93c4 100644 (file)
@@ -193,7 +193,7 @@ dt3155_start_acq(struct dt3155_priv *pd)
        struct vb2_buffer *vb = pd->curr_buf;
        dma_addr_t dma_addr;
 
-       dma_addr = vb2_dma_contig_plane_paddr(vb, 0);
+       dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
        iowrite32(dma_addr, pd->regs + EVEN_DMA_START);
        iowrite32(dma_addr + img_width, pd->regs + ODD_DMA_START);
        iowrite32(img_width, pd->regs + EVEN_DMA_STRIDE);
@@ -357,7 +357,7 @@ dt3155_irq_handler_even(int irq, void *dev_id)
        ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry);
        list_del(&ivb->done_entry);
        ipd->curr_buf = ivb;
-       dma_addr = vb2_dma_contig_plane_paddr(ivb, 0);
+       dma_addr = vb2_dma_contig_plane_dma_addr(ivb, 0);
        iowrite32(dma_addr, ipd->regs + EVEN_DMA_START);
        iowrite32(dma_addr + img_width, ipd->regs + ODD_DMA_START);
        iowrite32(img_width, ipd->regs + EVEN_DMA_STRIDE);
diff --git a/drivers/staging/tm6000/CARDLIST b/drivers/staging/tm6000/CARDLIST
deleted file mode 100644 (file)
index b5edce4..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-  1 -> Generic tm5600 board                   (tm5600)          [6000:0001]
-  2 -> Generic tm6000 board                   (tm6000)          [6000:0001]
-  3 -> Generic tm6010 board                   (tm6010)          [6000:0002]
-  4 -> 10Moons UT821                          (tm5600)          [6000:0001]
-  5 -> 10Moons UT330                          (tm5600)
-  6 -> ADSTech Dual TV                        (tm6000)          [06e1:f332]
-  7 -> FreeCom and similar                    (tm6000)          [14aa:0620]
-  8 -> ADSTech Mini Dual TV                   (tm6000)          [06e1:b339]
-  9 -> Hauppauge WinTV HVR-900H/USB2 Stick    (tm6010)          [2040:6600,2040:6601,2040:6610,2040:6611]
- 10 -> Beholder Wander                        (tm6010)          [6000:dec0]
- 11 -> Beholder Voyager                       (tm6010)          [6000:dec1]
- 12 -> TerraTec Cinergy Hybrid XE/Cinergy Hybrid Stick (tm6010) [0ccd:0086,0ccd:00a5]
- 13 -> TwinHan TU501                          (tm6010)          [13d3:3240,13d3:3241,13d3:3243,13d3:3264]
- 14 -> Beholder Wander Lite                   (tm6010)          [6000:dec2]
- 15 -> Beholder Voyager Lite                  (tm6010)          [6000:dec3]
-
diff --git a/drivers/staging/tm6000/Kconfig b/drivers/staging/tm6000/Kconfig
deleted file mode 100644 (file)
index 114eec8..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-config VIDEO_TM6000
-       tristate "TV Master TM5600/6000/6010 driver"
-       depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB && EXPERIMENTAL
-       select VIDEO_TUNER
-       select MEDIA_TUNER_XC2028
-       select MEDIA_TUNER_XC5000
-       select VIDEOBUF_VMALLOC
-       help
-         Support for TM5600/TM6000/TM6010 USB Device
-
-         Since these cards have no MPEG decoder onboard, they transmit
-         only compressed MPEG data over the usb bus, so you need
-         an external software decoder to watch TV on your computer.
-
-         Say Y if you own such a device and want to use it.
-
-config VIDEO_TM6000_ALSA
-       tristate "TV Master TM5600/6000/6010 audio support"
-       depends on VIDEO_TM6000 && SND && EXPERIMENTAL
-       select SND_PCM
-       ---help---
-         This is a video4linux driver for direct (DMA) audio for
-         TM5600/TM6000/TM6010 USB Devices.
-
-         To compile this driver as a module, choose M here: the
-         module will be called tm6000-alsa.
-
-config VIDEO_TM6000_DVB
-       tristate "DVB Support for tm6000 based TV cards"
-       depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL
-       select DVB_ZL10353
-       ---help---
-         This adds support for DVB cards based on the tm5600/tm6000 chip.
diff --git a/drivers/staging/tm6000/Makefile b/drivers/staging/tm6000/Makefile
deleted file mode 100644 (file)
index 395515b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-tm6000-y := tm6000-cards.o \
-                  tm6000-core.o  \
-                  tm6000-i2c.o   \
-                  tm6000-video.o \
-                  tm6000-stds.o \
-                  tm6000-input.o
-
-obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
-obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o
-obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o
-
-ccflags-y := -Idrivers/media/video
-ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
diff --git a/drivers/staging/tm6000/README b/drivers/staging/tm6000/README
deleted file mode 100644 (file)
index c340ebc..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Todo:
-       - Fix the loss of some blocks when receiving the video URB's
-       - Add a lock at tm6000_read_write_usb() to prevent two simultaneous access to the
-         URB control transfers
-       - Properly add the locks at tm6000-video
-       - Add audio support
-       - Add vbi support
-       - Add IR support
-       - Do several cleanups
-       - I think that frame1/frame0 are inverted. This causes a funny effect at the image.
-         the fix is trivial, but require some tests
-       - My tm6010 devices sometimes insist on stop working. I need to turn them off, removing
-         from my machine and wait for a while for it to work again. I'm starting to think that
-         it is an overheat issue - is there a workaround that we could do?
-       - Sometimes, tm6010 doesn't read eeprom at the proper time (hardware bug). So, the device
-         got miss-detected as a "generic" tm6000. This can be really bad if the tuner is the
-         Low Power one, as it may result on loading the high power firmware, that could damage
-         the device. Maybe we may read eeprom to double check, when the device is marked as "generic"
-       - Coding Style fixes
-       - sparse cleanups
-
-Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/tm6000/TODO b/drivers/staging/tm6000/TODO
deleted file mode 100644 (file)
index 135d0ea..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-There a few things to do before putting this driver in production:
-       - IR NEC with tm5600/6000 TV cards
-       - IR RC5 with tm5600/6000/6010 TV cards
-       - CodingStyle;
-       - Fix audio;
-       - Fix some panic/OOPS conditions.
-
-Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c
deleted file mode 100644 (file)
index bd5fa89..0000000
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- *
- *  Support for audio capture for tm5600/6000/6010
- *    (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- *  Based on cx88-alsa.c
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/usb.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <linux/delay.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/control.h>
-#include <sound/initval.h>
-
-
-#include "tm6000.h"
-#include "tm6000-regs.h"
-
-#undef dprintk
-
-#define dprintk(level, fmt, arg...) do {                                  \
-       if (debug >= level)                                                \
-               printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
-       } while (0)
-
-/****************************************************************************
-                       Module global static vars
- ****************************************************************************/
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
-
-static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
-
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled.");
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
-
-
-/****************************************************************************
-                               Module macros
- ****************************************************************************/
-
-MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
-                       "{{Trident,tm6000},"
-                       "{{Trident,tm6010}");
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debug messages");
-
-/****************************************************************************
-                       Module specific funtions
- ****************************************************************************/
-
-/*
- * BOARD Specific: Sets audio DMA
- */
-
-static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
-{
-       struct tm6000_core *core = chip->core;
-
-       dprintk(1, "Starting audio DMA\n");
-
-       /* Enables audio */
-       tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x40, 0x40);
-
-       tm6000_set_audio_bitrate(core, 48000);
-
-       return 0;
-}
-
-/*
- * BOARD Specific: Resets audio DMA
- */
-static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
-{
-       struct tm6000_core *core = chip->core;
-
-       dprintk(1, "Stopping audio DMA\n");
-
-       /* Disables audio */
-       tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x00, 0x40);
-
-       return 0;
-}
-
-static void dsp_buffer_free(struct snd_pcm_substream *substream)
-{
-       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-
-       dprintk(2, "Freeing buffer\n");
-
-       vfree(substream->runtime->dma_area);
-       substream->runtime->dma_area = NULL;
-       substream->runtime->dma_bytes = 0;
-}
-
-static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
-{
-       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-
-       dprintk(2, "Allocating buffer\n");
-
-       if (substream->runtime->dma_area) {
-               if (substream->runtime->dma_bytes > size)
-                       return 0;
-
-               dsp_buffer_free(substream);
-       }
-
-       substream->runtime->dma_area = vmalloc(size);
-       if (!substream->runtime->dma_area)
-               return -ENOMEM;
-
-       substream->runtime->dma_bytes = size;
-
-       return 0;
-}
-
-
-/****************************************************************************
-                               ALSA PCM Interface
- ****************************************************************************/
-
-/*
- * Digital hardware definition
- */
-#define DEFAULT_FIFO_SIZE      4096
-
-static struct snd_pcm_hardware snd_tm6000_digital_hw = {
-       .info = SNDRV_PCM_INFO_MMAP |
-               SNDRV_PCM_INFO_INTERLEAVED |
-               SNDRV_PCM_INFO_BLOCK_TRANSFER |
-               SNDRV_PCM_INFO_MMAP_VALID,
-       .formats = SNDRV_PCM_FMTBIT_S16_LE,
-
-       .rates = SNDRV_PCM_RATE_CONTINUOUS,
-       .rate_min = 48000,
-       .rate_max = 48000,
-       .channels_min = 2,
-       .channels_max = 2,
-       .period_bytes_min = 64,
-       .period_bytes_max = 12544,
-       .periods_min = 1,
-       .periods_max = 98,
-       .buffer_bytes_max = 62720 * 8,
-};
-
-/*
- * audio pcm capture open callback
- */
-static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int err;
-
-       err = snd_pcm_hw_constraint_pow2(runtime, 0,
-                                        SNDRV_PCM_HW_PARAM_PERIODS);
-       if (err < 0)
-               goto _error;
-
-       chip->substream = substream;
-
-       runtime->hw = snd_tm6000_digital_hw;
-
-       return 0;
-_error:
-       dprintk(1, "Error opening PCM!\n");
-       return err;
-}
-
-/*
- * audio close callback
- */
-static int snd_tm6000_close(struct snd_pcm_substream *substream)
-{
-       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-       struct tm6000_core *core = chip->core;
-
-       if (atomic_read(&core->stream_started) > 0) {
-               atomic_set(&core->stream_started, 0);
-               schedule_work(&core->wq_trigger);
-       }
-
-       return 0;
-}
-
-static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
-{
-       struct snd_tm6000_card *chip = core->adev;
-       struct snd_pcm_substream *substream = chip->substream;
-       struct snd_pcm_runtime *runtime;
-       int period_elapsed = 0;
-       unsigned int stride, buf_pos;
-       int length;
-
-       if (atomic_read(&core->stream_started) == 0)
-               return 0;
-
-       if (!size || !substream) {
-               dprintk(1, "substream was NULL\n");
-               return -EINVAL;
-       }
-
-       runtime = substream->runtime;
-       if (!runtime || !runtime->dma_area) {
-               dprintk(1, "runtime was NULL\n");
-               return -EINVAL;
-       }
-
-       buf_pos = chip->buf_pos;
-       stride = runtime->frame_bits >> 3;
-
-       if (stride == 0) {
-               dprintk(1, "stride is zero\n");
-               return -EINVAL;
-       }
-
-       length = size / stride;
-       if (length == 0) {
-               dprintk(1, "%s: length was zero\n", __func__);
-               return -EINVAL;
-       }
-
-       dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
-               runtime->dma_area, buf_pos,
-               (unsigned int)runtime->buffer_size, stride);
-
-       if (buf_pos + length >= runtime->buffer_size) {
-               unsigned int cnt = runtime->buffer_size - buf_pos;
-               memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride);
-               memcpy(runtime->dma_area, buf + cnt * stride,
-                       length * stride - cnt * stride);
-       } else
-               memcpy(runtime->dma_area + buf_pos * stride, buf,
-                       length * stride);
-
-       snd_pcm_stream_lock(substream);
-
-       chip->buf_pos += length;
-       if (chip->buf_pos >= runtime->buffer_size)
-               chip->buf_pos -= runtime->buffer_size;
-
-       chip->period_pos += length;
-       if (chip->period_pos >= runtime->period_size) {
-               chip->period_pos -= runtime->period_size;
-               period_elapsed = 1;
-       }
-
-       snd_pcm_stream_unlock(substream);
-
-       if (period_elapsed)
-               snd_pcm_period_elapsed(substream);
-
-       return 0;
-}
-
-/*
- * hw_params callback
- */
-static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *hw_params)
-{
-       int size, rc;
-
-       size = params_period_bytes(hw_params) * params_periods(hw_params);
-
-       rc = dsp_buffer_alloc(substream, size);
-       if (rc < 0)
-               return rc;
-
-       return 0;
-}
-
-/*
- * hw free callback
- */
-static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-       struct tm6000_core *core = chip->core;
-
-       if (atomic_read(&core->stream_started) > 0) {
-               atomic_set(&core->stream_started, 0);
-               schedule_work(&core->wq_trigger);
-       }
-
-       return 0;
-}
-
-/*
- * prepare callback
- */
-static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-
-       chip->buf_pos = 0;
-       chip->period_pos = 0;
-
-       return 0;
-}
-
-
-/*
- * trigger callback
- */
-static void audio_trigger(struct work_struct *work)
-{
-       struct tm6000_core *core = container_of(work, struct tm6000_core,
-                                               wq_trigger);
-       struct snd_tm6000_card *chip = core->adev;
-
-       if (atomic_read(&core->stream_started)) {
-               dprintk(1, "starting capture");
-               _tm6000_start_audio_dma(chip);
-       } else {
-               dprintk(1, "stopping capture");
-               _tm6000_stop_audio_dma(chip);
-       }
-}
-
-static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-       struct tm6000_core *core = chip->core;
-       int err = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               atomic_set(&core->stream_started, 1);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               atomic_set(&core->stream_started, 0);
-               break;
-       default:
-               err = -EINVAL;
-               break;
-       }
-       schedule_work(&core->wq_trigger);
-
-       return err;
-}
-/*
- * pointer callback
- */
-static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-
-       return chip->buf_pos;
-}
-
-/*
- * operators
- */
-static struct snd_pcm_ops snd_tm6000_pcm_ops = {
-       .open = snd_tm6000_pcm_open,
-       .close = snd_tm6000_close,
-       .ioctl = snd_pcm_lib_ioctl,
-       .hw_params = snd_tm6000_hw_params,
-       .hw_free = snd_tm6000_hw_free,
-       .prepare = snd_tm6000_prepare,
-       .trigger = snd_tm6000_card_trigger,
-       .pointer = snd_tm6000_pointer,
-};
-
-/*
- * create a PCM device
- */
-
-/* FIXME: Control interface - How to control volume/mute? */
-
-/****************************************************************************
-                       Basic Flow for Sound Devices
- ****************************************************************************/
-
-/*
- * Alsa Constructor - Component probe
- */
-int tm6000_audio_init(struct tm6000_core *dev)
-{
-       struct snd_card         *card;
-       struct snd_tm6000_card  *chip;
-       int                     rc;
-       static int              devnr;
-       char                    component[14];
-       struct snd_pcm          *pcm;
-
-       if (!dev)
-               return 0;
-
-       if (devnr >= SNDRV_CARDS)
-               return -ENODEV;
-
-       if (!enable[devnr])
-               return -ENOENT;
-
-       rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
-       if (rc < 0) {
-               snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
-               return rc;
-       }
-       strcpy(card->driver, "tm6000-alsa");
-       strcpy(card->shortname, "TM5600/60x0");
-       sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
-               dev->udev->bus->busnum, dev->udev->devnum);
-
-       sprintf(component, "USB%04x:%04x",
-               le16_to_cpu(dev->udev->descriptor.idVendor),
-               le16_to_cpu(dev->udev->descriptor.idProduct));
-       snd_component_add(card, component);
-       snd_card_set_dev(card, &dev->udev->dev);
-
-       chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
-       if (!chip) {
-               rc = -ENOMEM;
-               goto error;
-       }
-
-       chip->core = dev;
-       chip->card = card;
-       dev->adev = chip;
-       spin_lock_init(&chip->reg_lock);
-
-       rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
-       if (rc < 0)
-               goto error_chip;
-
-       pcm->info_flags = 0;
-       pcm->private_data = chip;
-       strcpy(pcm->name, "Trident TM5600/60x0");
-
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
-
-       INIT_WORK(&dev->wq_trigger, audio_trigger);
-       rc = snd_card_register(card);
-       if (rc < 0)
-               goto error_chip;
-
-       dprintk(1, "Registered audio driver for %s\n", card->longname);
-
-       return 0;
-
-error_chip:
-       kfree(chip);
-       dev->adev = NULL;
-error:
-       snd_card_free(card);
-       return rc;
-}
-
-static int tm6000_audio_fini(struct tm6000_core *dev)
-{
-       struct snd_tm6000_card  *chip = dev->adev;
-
-       if (!dev)
-               return 0;
-
-       if (!chip)
-               return 0;
-
-       if (!chip->card)
-               return 0;
-
-       snd_card_free(chip->card);
-       chip->card = NULL;
-       kfree(chip);
-       dev->adev = NULL;
-
-       return 0;
-}
-
-struct tm6000_ops audio_ops = {
-       .type   = TM6000_AUDIO,
-       .name   = "TM6000 Audio Extension",
-       .init   = tm6000_audio_init,
-       .fini   = tm6000_audio_fini,
-       .fillbuf = tm6000_fillbuf,
-};
-
-static int __init tm6000_alsa_register(void)
-{
-       return tm6000_register_extension(&audio_ops);
-}
-
-static void __exit tm6000_alsa_unregister(void)
-{
-       tm6000_unregister_extension(&audio_ops);
-}
-
-module_init(tm6000_alsa_register);
-module_exit(tm6000_alsa_unregister);
diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c
deleted file mode 100644 (file)
index 9227db5..0000000
+++ /dev/null
@@ -1,1382 +0,0 @@
-/*
- *  tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.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 version 2
- *
- *  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/pci.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/usb.h>
-#include <linux/slab.h>
-#include <media/v4l2-common.h>
-#include <media/tuner.h>
-#include <media/tvaudio.h>
-#include <media/i2c-addr.h>
-#include <media/rc-map.h>
-
-#include "tm6000.h"
-#include "tm6000-regs.h"
-#include "tuner-xc2028.h"
-#include "xc5000.h"
-
-#define TM6000_BOARD_UNKNOWN                   0
-#define TM5600_BOARD_GENERIC                   1
-#define TM6000_BOARD_GENERIC                   2
-#define TM6010_BOARD_GENERIC                   3
-#define TM5600_BOARD_10MOONS_UT821             4
-#define TM5600_BOARD_10MOONS_UT330             5
-#define TM6000_BOARD_ADSTECH_DUAL_TV           6
-#define TM6000_BOARD_FREECOM_AND_SIMILAR       7
-#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV      8
-#define TM6010_BOARD_HAUPPAUGE_900H            9
-#define TM6010_BOARD_BEHOLD_WANDER             10
-#define TM6010_BOARD_BEHOLD_VOYAGER            11
-#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE        12
-#define TM6010_BOARD_TWINHAN_TU501             13
-#define TM6010_BOARD_BEHOLD_WANDER_LITE                14
-#define TM6010_BOARD_BEHOLD_VOYAGER_LITE       15
-#define TM5600_BOARD_TERRATEC_GRABSTER         16
-
-#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
-                          (model == TM5600_BOARD_GENERIC) || \
-                          (model == TM6000_BOARD_GENERIC) || \
-                          (model == TM6010_BOARD_GENERIC))
-
-#define TM6000_MAXBOARDS        16
-static unsigned int card[]     = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
-
-module_param_array(card,  int, NULL, 0444);
-
-static unsigned long tm6000_devused;
-
-
-struct tm6000_board {
-       char            *name;
-       char            eename[16];             /* EEPROM name */
-       unsigned        eename_size;            /* size of EEPROM name */
-       unsigned        eename_pos;             /* Position where it appears at ROM */
-
-       struct tm6000_capabilities caps;
-
-       enum            tm6000_devtype type;    /* variant of the chipset */
-       int             tuner_type;     /* type of the tuner */
-       int             tuner_addr;     /* tuner address */
-       int             demod_addr;     /* demodulator address */
-
-       struct tm6000_gpio gpio;
-
-       struct tm6000_input     vinput[3];
-       struct tm6000_input     rinput;
-
-       char            *ir_codes;
-};
-
-struct tm6000_board tm6000_boards[] = {
-       [TM6000_BOARD_UNKNOWN] = {
-               .name         = "Unknown tm6000 video grabber",
-               .caps = {
-                       .has_tuner      = 1,
-                       .has_eeprom     = 1,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6000_GPIO_1,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_ADC1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM5600_BOARD_GENERIC] = {
-               .name         = "Generic tm5600 board",
-               .type         = TM5600,
-               .tuner_type   = TUNER_XC2028,
-               .tuner_addr   = 0xc2 >> 1,
-               .caps = {
-                       .has_tuner      = 1,
-                       .has_eeprom     = 1,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6000_GPIO_1,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_ADC1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM6000_BOARD_GENERIC] = {
-               .name         = "Generic tm6000 board",
-               .tuner_type   = TUNER_XC2028,
-               .tuner_addr   = 0xc2 >> 1,
-               .caps = {
-                       .has_tuner      = 1,
-                       .has_eeprom     = 1,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6000_GPIO_1,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_ADC1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM6010_BOARD_GENERIC] = {
-               .name         = "Generic tm6010 board",
-               .type         = TM6010,
-               .tuner_type   = TUNER_XC2028,
-               .tuner_addr   = 0xc2 >> 1,
-               .demod_addr   = 0x1e >> 1,
-               .caps = {
-                       .has_tuner      = 1,
-                       .has_dvb        = 1,
-                       .has_zl10353    = 1,
-                       .has_eeprom     = 1,
-                       .has_remote     = 1,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6010_GPIO_2,
-                       .tuner_on       = TM6010_GPIO_3,
-                       .demod_reset    = TM6010_GPIO_1,
-                       .demod_on       = TM6010_GPIO_4,
-                       .power_led      = TM6010_GPIO_7,
-                       .dvb_led        = TM6010_GPIO_5,
-                       .ir             = TM6010_GPIO_0,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_SIF1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM5600_BOARD_10MOONS_UT821] = {
-               .name         = "10Moons UT 821",
-               .tuner_type   = TUNER_XC2028,
-               .eename       = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
-               .eename_size  = 14,
-               .eename_pos   = 0x14,
-               .type         = TM5600,
-               .tuner_addr   = 0xc2 >> 1,
-               .caps = {
-                       .has_tuner    = 1,
-                       .has_eeprom   = 1,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6000_GPIO_1,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_ADC1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM5600_BOARD_10MOONS_UT330] = {
-               .name         = "10Moons UT 330",
-               .tuner_type   = TUNER_PHILIPS_FQ1216AME_MK4,
-               .tuner_addr   = 0xc8 >> 1,
-               .caps = {
-                       .has_tuner    = 1,
-                       .has_dvb      = 0,
-                       .has_zl10353  = 0,
-                       .has_eeprom   = 1,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_ADC1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM6000_BOARD_ADSTECH_DUAL_TV] = {
-               .name         = "ADSTECH Dual TV USB",
-               .tuner_type   = TUNER_XC2028,
-               .tuner_addr   = 0xc8 >> 1,
-               .caps = {
-                       .has_tuner    = 1,
-                       .has_tda9874  = 1,
-                       .has_dvb      = 1,
-                       .has_zl10353  = 1,
-                       .has_eeprom   = 1,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_ADC1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM6000_BOARD_FREECOM_AND_SIMILAR] = {
-               .name         = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
-               .tuner_type   = TUNER_XC2028, /* has a XC3028 */
-               .tuner_addr   = 0xc2 >> 1,
-               .demod_addr   = 0x1e >> 1,
-               .caps = {
-                       .has_tuner    = 1,
-                       .has_dvb      = 1,
-                       .has_zl10353  = 1,
-                       .has_eeprom   = 0,
-                       .has_remote   = 1,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6000_GPIO_4,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_ADC1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
-               .name         = "ADSTECH Mini Dual TV USB",
-               .tuner_type   = TUNER_XC2028, /* has a XC3028 */
-               .tuner_addr   = 0xc8 >> 1,
-               .demod_addr   = 0x1e >> 1,
-               .caps = {
-                       .has_tuner    = 1,
-                       .has_dvb      = 1,
-                       .has_zl10353  = 1,
-                       .has_eeprom   = 0,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6000_GPIO_4,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_ADC1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM6010_BOARD_HAUPPAUGE_900H] = {
-               .name         = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
-               .eename       = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
-               .eename_size  = 14,
-               .eename_pos   = 0x42,
-               .tuner_type   = TUNER_XC2028, /* has a XC3028 */
-               .tuner_addr   = 0xc2 >> 1,
-               .demod_addr   = 0x1e >> 1,
-               .type         = TM6010,
-               .caps = {
-                       .has_tuner    = 1,
-                       .has_dvb      = 1,
-                       .has_zl10353  = 1,
-                       .has_eeprom   = 1,
-                       .has_remote   = 1,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6010_GPIO_2,
-                       .tuner_on       = TM6010_GPIO_3,
-                       .demod_reset    = TM6010_GPIO_1,
-                       .demod_on       = TM6010_GPIO_4,
-                       .power_led      = TM6010_GPIO_7,
-                       .dvb_led        = TM6010_GPIO_5,
-                       .ir             = TM6010_GPIO_0,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_SIF1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM6010_BOARD_BEHOLD_WANDER] = {
-               .name         = "Beholder Wander DVB-T/TV/FM USB2.0",
-               .tuner_type   = TUNER_XC5000,
-               .tuner_addr   = 0xc2 >> 1,
-               .demod_addr   = 0x1e >> 1,
-               .type         = TM6010,
-               .caps = {
-                       .has_tuner      = 1,
-                       .has_dvb        = 1,
-                       .has_zl10353    = 1,
-                       .has_eeprom     = 1,
-                       .has_remote     = 1,
-                       .has_radio      = 1.
-               },
-               .gpio = {
-                       .tuner_reset    = TM6010_GPIO_0,
-                       .demod_reset    = TM6010_GPIO_1,
-                       .power_led      = TM6010_GPIO_6,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_SIF1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-               .rinput = {
-                       .type   = TM6000_INPUT_RADIO,
-                       .amux   = TM6000_AMUX_ADC1,
-               },
-       },
-       [TM6010_BOARD_BEHOLD_VOYAGER] = {
-               .name         = "Beholder Voyager TV/FM USB2.0",
-               .tuner_type   = TUNER_XC5000,
-               .tuner_addr   = 0xc2 >> 1,
-               .type         = TM6010,
-               .caps = {
-                       .has_tuner      = 1,
-                       .has_dvb        = 0,
-                       .has_zl10353    = 0,
-                       .has_eeprom     = 1,
-                       .has_remote     = 1,
-                       .has_radio      = 1,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6010_GPIO_0,
-                       .power_led      = TM6010_GPIO_6,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_SIF1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-               .rinput = {
-                       .type   = TM6000_INPUT_RADIO,
-                       .amux   = TM6000_AMUX_ADC1,
-               },
-       },
-       [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
-               .name         = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
-               .tuner_type   = TUNER_XC2028, /* has a XC3028 */
-               .tuner_addr   = 0xc2 >> 1,
-               .demod_addr   = 0x1e >> 1,
-               .type         = TM6010,
-               .caps = {
-                       .has_tuner    = 1,
-                       .has_dvb      = 1,
-                       .has_zl10353  = 1,
-                       .has_eeprom   = 1,
-                       .has_remote   = 1,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6010_GPIO_2,
-                       .tuner_on       = TM6010_GPIO_3,
-                       .demod_reset    = TM6010_GPIO_1,
-                       .demod_on       = TM6010_GPIO_4,
-                       .power_led      = TM6010_GPIO_7,
-                       .dvb_led        = TM6010_GPIO_5,
-                       .ir             = TM6010_GPIO_0,
-               },
-               .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_SIF1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM5600_BOARD_TERRATEC_GRABSTER] = {
-               .name         = "Terratec Grabster AV 150/250 MX",
-               .type         = TM5600,
-               .tuner_type   = TUNER_ABSENT,
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_ADC1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM6010_BOARD_TWINHAN_TU501] = {
-               .name         = "Twinhan TU501(704D1)",
-               .tuner_type   = TUNER_XC2028, /* has a XC3028 */
-               .tuner_addr   = 0xc2 >> 1,
-               .demod_addr   = 0x1e >> 1,
-               .type         = TM6010,
-               .caps = {
-                       .has_tuner    = 1,
-                       .has_dvb      = 1,
-                       .has_zl10353  = 1,
-                       .has_eeprom   = 1,
-                       .has_remote   = 1,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6010_GPIO_2,
-                       .tuner_on       = TM6010_GPIO_3,
-                       .demod_reset    = TM6010_GPIO_1,
-                       .demod_on       = TM6010_GPIO_4,
-                       .power_led      = TM6010_GPIO_7,
-                       .dvb_led        = TM6010_GPIO_5,
-                       .ir             = TM6010_GPIO_0,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_SIF1,
-                       }, {
-                       .type   = TM6000_INPUT_COMPOSITE1,
-                       .vmux   = TM6000_VMUX_VIDEO_A,
-                       .amux   = TM6000_AMUX_ADC2,
-                       }, {
-                       .type   = TM6000_INPUT_SVIDEO,
-                       .vmux   = TM6000_VMUX_VIDEO_AB,
-                       .amux   = TM6000_AMUX_ADC2,
-                       },
-               },
-       },
-       [TM6010_BOARD_BEHOLD_WANDER_LITE] = {
-               .name         = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
-               .tuner_type   = TUNER_XC5000,
-               .tuner_addr   = 0xc2 >> 1,
-               .demod_addr   = 0x1e >> 1,
-               .type         = TM6010,
-               .caps = {
-                       .has_tuner      = 1,
-                       .has_dvb        = 1,
-                       .has_zl10353    = 1,
-                       .has_eeprom     = 1,
-                       .has_remote     = 0,
-                       .has_radio      = 1,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6010_GPIO_0,
-                       .demod_reset    = TM6010_GPIO_1,
-                       .power_led      = TM6010_GPIO_6,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_SIF1,
-                       },
-               },
-               .rinput = {
-                       .type   = TM6000_INPUT_RADIO,
-                       .amux   = TM6000_AMUX_ADC1,
-               },
-       },
-       [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
-               .name         = "Beholder Voyager Lite TV/FM USB2.0",
-               .tuner_type   = TUNER_XC5000,
-               .tuner_addr   = 0xc2 >> 1,
-               .type         = TM6010,
-               .caps = {
-                       .has_tuner      = 1,
-                       .has_dvb        = 0,
-                       .has_zl10353    = 0,
-                       .has_eeprom     = 1,
-                       .has_remote     = 0,
-                       .has_radio      = 1,
-               },
-               .gpio = {
-                       .tuner_reset    = TM6010_GPIO_0,
-                       .power_led      = TM6010_GPIO_6,
-               },
-               .vinput = { {
-                       .type   = TM6000_INPUT_TV,
-                       .vmux   = TM6000_VMUX_VIDEO_B,
-                       .amux   = TM6000_AMUX_SIF1,
-                       },
-               },
-               .rinput = {
-                       .type   = TM6000_INPUT_RADIO,
-                       .amux   = TM6000_AMUX_ADC1,
-               },
-       },
-};
-
-/* table of devices that work with this driver */
-struct usb_device_id tm6000_id_table[] = {
-       { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
-       { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
-       { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
-       { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
-       { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
-       { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
-       { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
-       { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
-       { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
-       { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
-       { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
-       { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
-       { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
-       { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
-       { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
-       { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
-       { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
-       { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
-       { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
-       { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
-       { },
-};
-
-/* Control power led for show some activity */
-void tm6000_flash_led(struct tm6000_core *dev, u8 state)
-{
-       /* Power LED unconfigured */
-       if (!dev->gpio.power_led)
-               return;
-
-       /* ON Power LED */
-       if (state) {
-               switch (dev->model) {
-               case TM6010_BOARD_HAUPPAUGE_900H:
-               case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
-               case TM6010_BOARD_TWINHAN_TU501:
-                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                               dev->gpio.power_led, 0x00);
-                       break;
-               case TM6010_BOARD_BEHOLD_WANDER:
-               case TM6010_BOARD_BEHOLD_VOYAGER:
-               case TM6010_BOARD_BEHOLD_WANDER_LITE:
-               case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
-                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                               dev->gpio.power_led, 0x01);
-                       break;
-               }
-       }
-       /* OFF Power LED */
-       else {
-               switch (dev->model) {
-               case TM6010_BOARD_HAUPPAUGE_900H:
-               case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
-               case TM6010_BOARD_TWINHAN_TU501:
-                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                               dev->gpio.power_led, 0x01);
-                       break;
-               case TM6010_BOARD_BEHOLD_WANDER:
-               case TM6010_BOARD_BEHOLD_VOYAGER:
-               case TM6010_BOARD_BEHOLD_WANDER_LITE:
-               case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
-                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                               dev->gpio.power_led, 0x00);
-                       break;
-               }
-       }
-}
-
-/* Tuner callback to provide the proper gpio changes needed for xc5000 */
-int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
-{
-       int rc = 0;
-       struct tm6000_core *dev = ptr;
-
-       if (dev->tuner_type != TUNER_XC5000)
-               return 0;
-
-       switch (command) {
-       case XC5000_TUNER_RESET:
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                              dev->gpio.tuner_reset, 0x01);
-               msleep(15);
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                              dev->gpio.tuner_reset, 0x00);
-               msleep(15);
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                              dev->gpio.tuner_reset, 0x01);
-               break;
-       }
-       return rc;
-}
-EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
-
-/* Tuner callback to provide the proper gpio changes needed for xc2028 */
-
-int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
-{
-       int rc = 0;
-       struct tm6000_core *dev = ptr;
-
-       if (dev->tuner_type != TUNER_XC2028)
-               return 0;
-
-       switch (command) {
-       case XC2028_RESET_CLK:
-               tm6000_ir_wait(dev, 0);
-
-               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
-                                       0x02, arg);
-               msleep(10);
-               rc = tm6000_i2c_reset(dev, 10);
-               break;
-       case XC2028_TUNER_RESET:
-               /* Reset codes during load firmware */
-               switch (arg) {
-               case 0:
-                       /* newer tuner can faster reset */
-                       switch (dev->model) {
-                       case TM5600_BOARD_10MOONS_UT821:
-                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                              dev->gpio.tuner_reset, 0x01);
-                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                              0x300, 0x01);
-                               msleep(10);
-                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                              dev->gpio.tuner_reset, 0x00);
-                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                              0x300, 0x00);
-                               msleep(10);
-                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                              dev->gpio.tuner_reset, 0x01);
-                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                              0x300, 0x01);
-                               break;
-                       case TM6010_BOARD_HAUPPAUGE_900H:
-                       case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
-                       case TM6010_BOARD_TWINHAN_TU501:
-                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                              dev->gpio.tuner_reset, 0x01);
-                               msleep(60);
-                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                              dev->gpio.tuner_reset, 0x00);
-                               msleep(75);
-                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                              dev->gpio.tuner_reset, 0x01);
-                               msleep(60);
-                               break;
-                       default:
-                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                              dev->gpio.tuner_reset, 0x00);
-                               msleep(130);
-                               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                              dev->gpio.tuner_reset, 0x01);
-                               msleep(130);
-                               break;
-                       }
-
-                       tm6000_ir_wait(dev, 1);
-                       break;
-               case 1:
-                       tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
-                                               0x02, 0x01);
-                       msleep(10);
-                       break;
-               case 2:
-                       rc = tm6000_i2c_reset(dev, 100);
-                       break;
-               }
-       }
-       return rc;
-}
-EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
-
-int tm6000_cards_setup(struct tm6000_core *dev)
-{
-       int i, rc;
-
-       /*
-        * Board-specific initialization sequence. Handles all GPIO
-        * initialization sequences that are board-specific.
-        * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
-        * Probably, they're all based on some reference device. Due to that,
-        * there's a common routine at the end to handle those GPIO's. Devices
-        * that use different pinups or init sequences can just return at
-        * the board-specific session.
-        */
-       switch (dev->model) {
-       case TM6010_BOARD_HAUPPAUGE_900H:
-       case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
-       case TM6010_BOARD_TWINHAN_TU501:
-       case TM6010_BOARD_GENERIC:
-               /* Turn xceive 3028 on */
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
-               msleep(15);
-               /* Turn zarlink zl10353 on */
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
-               msleep(15);
-               /* Reset zarlink zl10353 */
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
-               msleep(50);
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
-               msleep(15);
-               /* Turn zarlink zl10353 off */
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
-               msleep(15);
-               /* ir ? */
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
-               msleep(15);
-               /* Power led on (blue) */
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
-               msleep(15);
-               /* DVB led off (orange) */
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
-               msleep(15);
-               /* Turn zarlink zl10353 on */
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
-               msleep(15);
-               break;
-       case TM6010_BOARD_BEHOLD_WANDER:
-       case TM6010_BOARD_BEHOLD_WANDER_LITE:
-               /* Power led on (blue) */
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
-               msleep(15);
-               /* Reset zarlink zl10353 */
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
-               msleep(50);
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
-               msleep(15);
-               break;
-       case TM6010_BOARD_BEHOLD_VOYAGER:
-       case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
-               /* Power led on (blue) */
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
-               msleep(15);
-               break;
-       default:
-               break;
-       }
-
-       /*
-        * Default initialization. Most of the devices seem to use GPIO1
-        * and GPIO4.on the same way, so, this handles the common sequence
-        * used by most devices.
-        * If a device uses a different sequence or different GPIO pins for
-        * reset, just add the code at the board-specific part
-        */
-
-       if (dev->gpio.tuner_reset) {
-               for (i = 0; i < 2; i++) {
-                       rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                               dev->gpio.tuner_reset, 0x00);
-                       if (rc < 0) {
-                               printk(KERN_ERR "Error %i doing tuner reset\n", rc);
-                               return rc;
-                       }
-
-                       msleep(10); /* Just to be conservative */
-                       rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                                               dev->gpio.tuner_reset, 0x01);
-                       if (rc < 0) {
-                               printk(KERN_ERR "Error %i doing tuner reset\n", rc);
-                               return rc;
-                       }
-               }
-       } else {
-               printk(KERN_ERR "Tuner reset is not configured\n");
-               return -1;
-       }
-
-       msleep(50);
-
-       return 0;
-};
-
-static void tm6000_config_tuner(struct tm6000_core *dev)
-{
-       struct tuner_setup tun_setup;
-
-       /* Load tuner module */
-       v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-               "tuner", dev->tuner_addr, NULL);
-
-       memset(&tun_setup, 0, sizeof(tun_setup));
-       tun_setup.type = dev->tuner_type;
-       tun_setup.addr = dev->tuner_addr;
-
-       tun_setup.mode_mask = 0;
-       if (dev->caps.has_tuner)
-               tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
-
-       switch (dev->tuner_type) {
-       case TUNER_XC2028:
-               tun_setup.tuner_callback = tm6000_tuner_callback;
-               break;
-       case TUNER_XC5000:
-               tun_setup.tuner_callback = tm6000_xc5000_callback;
-               break;
-       }
-
-       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
-
-       switch (dev->tuner_type) {
-       case TUNER_XC2028: {
-               struct v4l2_priv_tun_config xc2028_cfg;
-               struct xc2028_ctrl ctl;
-
-               memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
-               memset(&ctl, 0, sizeof(ctl));
-
-               ctl.demod = XC3028_FE_ZARLINK456;
-
-               xc2028_cfg.tuner = TUNER_XC2028;
-               xc2028_cfg.priv  = &ctl;
-
-               switch (dev->model) {
-               case TM6010_BOARD_HAUPPAUGE_900H:
-               case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
-               case TM6010_BOARD_TWINHAN_TU501:
-                       ctl.fname = "xc3028L-v36.fw";
-                       break;
-               default:
-                       if (dev->dev_type == TM6010)
-                               ctl.fname = "xc3028-v27.fw";
-                       else
-                               ctl.fname = "xc3028-v24.fw";
-               }
-
-               printk(KERN_INFO "Setting firmware parameters for xc2028\n");
-               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
-                                    &xc2028_cfg);
-
-               }
-               break;
-       case TUNER_XC5000:
-               {
-               struct v4l2_priv_tun_config  xc5000_cfg;
-               struct xc5000_config ctl = {
-                       .i2c_address = dev->tuner_addr,
-                       .if_khz      = 4570,
-                       .radio_input = XC5000_RADIO_FM1_MONO,
-                       };
-
-               xc5000_cfg.tuner = TUNER_XC5000;
-               xc5000_cfg.priv  = &ctl;
-
-               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
-                                    &xc5000_cfg);
-               }
-               break;
-       default:
-               printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
-               break;
-       }
-}
-
-static int fill_board_specific_data(struct tm6000_core *dev)
-{
-       int rc;
-
-       dev->dev_type   = tm6000_boards[dev->model].type;
-       dev->tuner_type = tm6000_boards[dev->model].tuner_type;
-       dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
-
-       dev->gpio = tm6000_boards[dev->model].gpio;
-
-       dev->ir_codes = tm6000_boards[dev->model].ir_codes;
-
-       dev->demod_addr = tm6000_boards[dev->model].demod_addr;
-
-       dev->caps = tm6000_boards[dev->model].caps;
-
-       dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
-       dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
-       dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
-       dev->rinput = tm6000_boards[dev->model].rinput;
-
-       /* initialize hardware */
-       rc = tm6000_init(dev);
-       if (rc < 0)
-               return rc;
-
-       return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
-}
-
-
-static void use_alternative_detection_method(struct tm6000_core *dev)
-{
-       int i, model = -1;
-
-       if (!dev->eedata_size)
-               return;
-
-       for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
-               if (!tm6000_boards[i].eename_size)
-                       continue;
-               if (dev->eedata_size < tm6000_boards[i].eename_pos +
-                                      tm6000_boards[i].eename_size)
-                       continue;
-
-               if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
-                           tm6000_boards[i].eename,
-                           tm6000_boards[i].eename_size)) {
-                       model = i;
-                       break;
-               }
-       }
-       if (model < 0) {
-               printk(KERN_INFO "Device has eeprom but is currently unknown\n");
-               return;
-       }
-
-       dev->model = model;
-
-       printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
-              tm6000_boards[model].name, model);
-}
-
-static int tm6000_init_dev(struct tm6000_core *dev)
-{
-       struct v4l2_frequency f;
-       int rc = 0;
-
-       mutex_init(&dev->lock);
-       mutex_lock(&dev->lock);
-
-       if (!is_generic(dev->model)) {
-               rc = fill_board_specific_data(dev);
-               if (rc < 0)
-                       goto err;
-
-               /* register i2c bus */
-               rc = tm6000_i2c_register(dev);
-               if (rc < 0)
-                       goto err;
-       } else {
-               /* register i2c bus */
-               rc = tm6000_i2c_register(dev);
-               if (rc < 0)
-                       goto err;
-
-               use_alternative_detection_method(dev);
-
-               rc = fill_board_specific_data(dev);
-               if (rc < 0)
-                       goto err;
-       }
-
-       /* Default values for STD and resolutions */
-       dev->width = 720;
-       dev->height = 480;
-       dev->norm = V4L2_STD_PAL_M;
-
-       /* Configure tuner */
-       tm6000_config_tuner(dev);
-
-       /* Set video standard */
-       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
-
-       /* Set tuner frequency - also loads firmware on xc2028/xc3028 */
-       f.tuner = 0;
-       f.type = V4L2_TUNER_ANALOG_TV;
-       f.frequency = 3092;     /* 193.25 MHz */
-       dev->freq = f.frequency;
-       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
-
-       if (dev->caps.has_tda9874)
-               v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-                       "tvaudio", I2C_ADDR_TDA9874, NULL);
-
-       /* register and initialize V4L2 */
-       rc = tm6000_v4l2_register(dev);
-       if (rc < 0)
-               goto err;
-
-       tm6000_add_into_devlist(dev);
-       tm6000_init_extension(dev);
-
-       tm6000_ir_init(dev);
-
-       mutex_unlock(&dev->lock);
-       return 0;
-
-err:
-       mutex_unlock(&dev->lock);
-       return rc;
-}
-
-/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
-#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
-
-static void get_max_endpoint(struct usb_device *udev,
-                            struct usb_host_interface *alt,
-                            char *msgtype,
-                            struct usb_host_endpoint *curr_e,
-                            struct tm6000_endpoint *tm_ep)
-{
-       u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
-       unsigned int size = tmp & 0x7ff;
-
-       if (udev->speed == USB_SPEED_HIGH)
-               size = size * hb_mult(tmp);
-
-       if (size > tm_ep->maxsize) {
-               tm_ep->endp = curr_e;
-               tm_ep->maxsize = size;
-               tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
-               tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
-
-               printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
-                                       msgtype, curr_e->desc.bEndpointAddress,
-                                       size);
-       }
-}
-
-/*
- * tm6000_usb_probe()
- * checks for supported devices
- */
-static int tm6000_usb_probe(struct usb_interface *interface,
-                           const struct usb_device_id *id)
-{
-       struct usb_device *usbdev;
-       struct tm6000_core *dev = NULL;
-       int i, rc = 0;
-       int nr = 0;
-       char *speed;
-
-       usbdev = usb_get_dev(interface_to_usbdev(interface));
-
-       /* Selects the proper interface */
-       rc = usb_set_interface(usbdev, 0, 1);
-       if (rc < 0)
-               goto err;
-
-       /* Check to see next free device and mark as used */
-       nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
-       if (nr >= TM6000_MAXBOARDS) {
-               printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
-               usb_put_dev(usbdev);
-               return -ENOMEM;
-       }
-
-       /* Create and initialize dev struct */
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (dev == NULL) {
-               printk(KERN_ERR "tm6000" ": out of memory!\n");
-               usb_put_dev(usbdev);
-               return -ENOMEM;
-       }
-       spin_lock_init(&dev->slock);
-
-       /* Increment usage count */
-       tm6000_devused |= 1<<nr;
-       snprintf(dev->name, 29, "tm6000 #%d", nr);
-
-       dev->model = id->driver_info;
-       if ((card[nr] >= 0) && (card[nr] < ARRAY_SIZE(tm6000_boards)))
-               dev->model = card[nr];
-
-       dev->udev = usbdev;
-       dev->devno = nr;
-
-       switch (usbdev->speed) {
-       case USB_SPEED_LOW:
-               speed = "1.5";
-               break;
-       case USB_SPEED_UNKNOWN:
-       case USB_SPEED_FULL:
-               speed = "12";
-               break;
-       case USB_SPEED_HIGH:
-               speed = "480";
-               break;
-       default:
-               speed = "unknown";
-       }
-
-
-
-       /* Get endpoints */
-       for (i = 0; i < interface->num_altsetting; i++) {
-               int ep;
-
-               for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
-                       struct usb_host_endpoint        *e;
-                       int dir_out;
-
-                       e = &interface->altsetting[i].endpoint[ep];
-
-                       dir_out = ((e->desc.bEndpointAddress &
-                                       USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
-
-                       printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
-                              i,
-                              interface->altsetting[i].desc.bInterfaceNumber,
-                              interface->altsetting[i].desc.bInterfaceClass);
-
-                       switch (e->desc.bmAttributes) {
-                       case USB_ENDPOINT_XFER_BULK:
-                               if (!dir_out) {
-                                       get_max_endpoint(usbdev,
-                                                        &interface->altsetting[i],
-                                                        "Bulk IN", e,
-                                                        &dev->bulk_in);
-                               } else {
-                                       get_max_endpoint(usbdev,
-                                                        &interface->altsetting[i],
-                                                        "Bulk OUT", e,
-                                                        &dev->bulk_out);
-                               }
-                               break;
-                       case USB_ENDPOINT_XFER_ISOC:
-                               if (!dir_out) {
-                                       get_max_endpoint(usbdev,
-                                                        &interface->altsetting[i],
-                                                        "ISOC IN", e,
-                                                        &dev->isoc_in);
-                               } else {
-                                       get_max_endpoint(usbdev,
-                                                        &interface->altsetting[i],
-                                                        "ISOC OUT", e,
-                                                        &dev->isoc_out);
-                               }
-                               break;
-                       case USB_ENDPOINT_XFER_INT:
-                               if (!dir_out) {
-                                       get_max_endpoint(usbdev,
-                                                       &interface->altsetting[i],
-                                                       "INT IN", e,
-                                                       &dev->int_in);
-                               } else {
-                                       get_max_endpoint(usbdev,
-                                                       &interface->altsetting[i],
-                                                       "INT OUT", e,
-                                                       &dev->int_out);
-                               }
-                               break;
-                       }
-               }
-       }
-
-
-       printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
-               speed,
-               le16_to_cpu(dev->udev->descriptor.idVendor),
-               le16_to_cpu(dev->udev->descriptor.idProduct),
-               interface->altsetting->desc.bInterfaceNumber);
-
-/* check if the the device has the iso in endpoint at the correct place */
-       if (!dev->isoc_in.endp) {
-               printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
-               rc = -ENODEV;
-
-               goto err;
-       }
-
-       /* save our data pointer in this interface device */
-       usb_set_intfdata(interface, dev);
-
-       printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
-
-       rc = tm6000_init_dev(dev);
-
-       if (rc < 0)
-               goto err;
-
-       return 0;
-
-err:
-       printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
-
-       tm6000_devused &= ~(1<<nr);
-       usb_put_dev(usbdev);
-
-       kfree(dev);
-       return rc;
-}
-
-/*
- * tm6000_usb_disconnect()
- * called when the device gets diconencted
- * video device will be unregistered on v4l2_close in case it is still open
- */
-static void tm6000_usb_disconnect(struct usb_interface *interface)
-{
-       struct tm6000_core *dev = usb_get_intfdata(interface);
-       usb_set_intfdata(interface, NULL);
-
-       if (!dev)
-               return;
-
-       printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
-
-       tm6000_ir_fini(dev);
-
-       if (dev->gpio.power_led) {
-               switch (dev->model) {
-               case TM6010_BOARD_HAUPPAUGE_900H:
-               case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
-               case TM6010_BOARD_TWINHAN_TU501:
-                       /* Power led off */
-                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                               dev->gpio.power_led, 0x01);
-                       msleep(15);
-                       break;
-               case TM6010_BOARD_BEHOLD_WANDER:
-               case TM6010_BOARD_BEHOLD_VOYAGER:
-               case TM6010_BOARD_BEHOLD_WANDER_LITE:
-               case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
-                       /* Power led off */
-                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                               dev->gpio.power_led, 0x00);
-                       msleep(15);
-                       break;
-               }
-       }
-       tm6000_v4l2_unregister(dev);
-
-       tm6000_i2c_unregister(dev);
-
-       v4l2_device_unregister(&dev->v4l2_dev);
-
-       dev->state |= DEV_DISCONNECTED;
-
-       usb_put_dev(dev->udev);
-
-       tm6000_close_extension(dev);
-       tm6000_remove_from_devlist(dev);
-
-       kfree(dev);
-}
-
-static struct usb_driver tm6000_usb_driver = {
-               .name = "tm6000",
-               .probe = tm6000_usb_probe,
-               .disconnect = tm6000_usb_disconnect,
-               .id_table = tm6000_id_table,
-};
-
-static int __init tm6000_module_init(void)
-{
-       int result;
-
-       printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n",
-              (TM6000_VERSION  >> 16) & 0xff,
-              (TM6000_VERSION  >> 8) & 0xff, TM6000_VERSION  & 0xff);
-
-       /* register this driver with the USB subsystem */
-       result = usb_register(&tm6000_usb_driver);
-       if (result)
-               printk(KERN_ERR "tm6000"
-                          " usb_register failed. Error number %d.\n", result);
-
-       return result;
-}
-
-static void __exit tm6000_module_exit(void)
-{
-       /* deregister at USB subsystem */
-       usb_deregister(&tm6000_usb_driver);
-}
-
-module_init(tm6000_module_init);
-module_exit(tm6000_module_exit);
-
-MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
-MODULE_AUTHOR("Mauro Carvalho Chehab");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c
deleted file mode 100644 (file)
index d7eb2e2..0000000
+++ /dev/null
@@ -1,909 +0,0 @@
-/*
- *  tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
- *
- *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- *      - DVB-T support
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation version 2
- *
- *  This program is distributed 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/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include "tm6000.h"
-#include "tm6000-regs.h"
-#include <media/v4l2-common.h>
-#include <media/tuner.h>
-
-#define USB_TIMEOUT    (5 * HZ) /* ms */
-
-int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
-                         u16 value, u16 index, u8 *buf, u16 len)
-{
-       int          ret, i;
-       unsigned int pipe;
-       u8           *data = NULL;
-
-       if (len)
-               data = kzalloc(len, GFP_KERNEL);
-
-
-       if (req_type & USB_DIR_IN)
-               pipe = usb_rcvctrlpipe(dev->udev, 0);
-       else {
-               pipe = usb_sndctrlpipe(dev->udev, 0);
-               memcpy(data, buf, len);
-       }
-
-       if (tm6000_debug & V4L2_DEBUG_I2C) {
-               printk("(dev %p, pipe %08x): ", dev->udev, pipe);
-
-               printk("%s: %02x %02x %02x %02x %02x %02x %02x %02x ",
-                       (req_type & USB_DIR_IN) ? " IN" : "OUT",
-                       req_type, req, value&0xff, value>>8, index&0xff,
-                       index>>8, len&0xff, len>>8);
-
-               if (!(req_type & USB_DIR_IN)) {
-                       printk(">>> ");
-                       for (i = 0; i < len; i++)
-                               printk(" %02x", buf[i]);
-               printk("\n");
-               }
-       }
-
-       ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index,
-                             data, len, USB_TIMEOUT);
-
-       if (req_type &  USB_DIR_IN)
-               memcpy(buf, data, len);
-
-       if (tm6000_debug & V4L2_DEBUG_I2C) {
-               if (ret < 0) {
-                       if (req_type &  USB_DIR_IN)
-                               printk("<<< (len=%d)\n", len);
-
-                       printk("%s: Error #%d\n", __FUNCTION__, ret);
-               } else if (req_type &  USB_DIR_IN) {
-                       printk("<<< ");
-                       for (i = 0; i < len; i++)
-                               printk(" %02x", buf[i]);
-                       printk("\n");
-               }
-       }
-
-       kfree(data);
-
-       msleep(5);
-
-       return ret;
-}
-
-int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
-{
-       return
-               tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
-                                     req, value, index, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(tm6000_set_reg);
-
-int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
-{
-       int rc;
-       u8 buf[1];
-
-       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
-                                       value, index, buf, 1);
-
-       if (rc < 0)
-               return rc;
-
-       return *buf;
-}
-EXPORT_SYMBOL_GPL(tm6000_get_reg);
-
-int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
-                                               u16 index, u16 mask)
-{
-       int rc;
-       u8 buf[1];
-       u8 new_index;
-
-       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
-                                       value, index, buf, 1);
-
-       if (rc < 0)
-               return rc;
-
-       new_index = (buf[0] & ~mask) | (index & mask);
-
-       if (new_index == index)
-               return 0;
-
-       return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
-                                     req, value, new_index, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(tm6000_set_reg_mask);
-
-int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index)
-{
-       int rc;
-       u8 buf[2];
-
-       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
-                                       value, index, buf, 2);
-
-       if (rc < 0)
-               return rc;
-
-       return buf[1]|buf[0]<<8;
-}
-
-int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index)
-{
-       int rc;
-       u8 buf[4];
-
-       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
-                                       value, index, buf, 4);
-
-       if (rc < 0)
-               return rc;
-
-       return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24;
-}
-
-int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep)
-{
-       int rc;
-
-       rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0);
-       if (rc < 0)
-               return rc;
-
-       msleep(tsleep);
-
-       rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1);
-       msleep(tsleep);
-
-       return rc;
-}
-
-void tm6000_set_fourcc_format(struct tm6000_core *dev)
-{
-       if (dev->dev_type == TM6010) {
-               int val;
-
-               val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0) & 0xfc;
-               if (dev->fourcc == V4L2_PIX_FMT_UYVY)
-                       tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
-               else
-                       tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val | 1);
-       } else {
-               if (dev->fourcc == V4L2_PIX_FMT_UYVY)
-                       tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
-               else
-                       tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0x90);
-       }
-}
-
-static void tm6000_set_vbi(struct tm6000_core *dev)
-{
-       /*
-        * FIXME:
-        * VBI lines and start/end are different between 60Hz and 50Hz
-        * So, it is very likely that we need to change the config to
-        * something that takes it into account, doing something different
-        * if (dev->norm & V4L2_STD_525_60)
-        */
-
-       if (dev->dev_type == TM6010) {
-               tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
-               tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27);
-               tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55);
-               tm6000_set_reg(dev, TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7, 0x66);
-               tm6000_set_reg(dev, TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8, 0x66);
-               tm6000_set_reg(dev, TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22, 0x66);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23, 0x00);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES, 0x00);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN, 0x00);
-               tm6000_set_reg(dev,
-                       TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02);
-               tm6000_set_reg(dev, TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35);
-               tm6000_set_reg(dev, TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0);
-               tm6000_set_reg(dev, TM6010_REQ07_R5A_VBI_TELETEXT_DTO1, 0x11);
-               tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c);
-               tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01);
-               tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
-       }
-}
-
-int tm6000_init_analog_mode(struct tm6000_core *dev)
-{
-       struct v4l2_frequency f;
-
-       if (dev->dev_type == TM6010) {
-               /* Enable video and audio */
-               tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF,
-                                                       0x60, 0x60);
-               /* Disable TS input */
-               tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
-                                                       0x00, 0x40);
-       } else {
-               /* Enables soft reset */
-               tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
-
-               if (dev->scaler)
-                       /* Disable Hfilter and Enable TS Drop err */
-                       tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20);
-               else    /* Enable Hfilter and disable TS Drop err */
-                       tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80);
-
-               tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88);
-               tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x23);
-               tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0);
-               tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8);
-               tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06);
-               tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f);
-
-               /* AP Software reset */
-               tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
-               tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
-
-               tm6000_set_fourcc_format(dev);
-
-               /* Disables soft reset */
-               tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
-       }
-       msleep(20);
-
-       /* Tuner firmware can now be loaded */
-
-       /*
-        * FIXME: This is a hack! xc3028 "sleeps" when no channel is detected
-        * for more than a few seconds. Not sure why, as this behavior does
-        * not happen on other devices with xc3028. So, I suspect that it
-        * is yet another bug at tm6000. After start sleeping, decoding 
-        * doesn't start automatically. Instead, it requires some
-        * I2C commands to wake it up. As we want to have image at the
-        * beginning, we needed to add this hack. The better would be to
-        * discover some way to make tm6000 to wake up without this hack.
-        */
-       f.frequency = dev->freq;
-       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
-
-       msleep(100);
-       tm6000_set_standard(dev);
-       tm6000_set_vbi(dev);
-       tm6000_set_audio_bitrate(dev, 48000);
-
-       /* switch dvb led off */
-       if (dev->gpio.dvb_led) {
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                       dev->gpio.dvb_led, 0x01);
-       }
-
-       return 0;
-}
-
-int tm6000_init_digital_mode(struct tm6000_core *dev)
-{
-       if (dev->dev_type == TM6010) {
-               /* Disable video and audio */
-               tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF,
-                               0x00, 0x60);
-               /* Enable TS input */
-               tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
-                               0x40, 0x40);
-               /* all power down, but not the digital data port */
-               tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28);
-               tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc);
-               tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff);
-       } else  {
-               tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
-               tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
-               tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x08);
-               tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c);
-               tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff);
-               tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0xd8);
-               tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40);
-               tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
-               tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09);
-               tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x37);
-               tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8);
-               tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0);
-               tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60);
-
-               tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c);
-               tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff);
-               tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x08);
-               msleep(50);
-
-               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
-               msleep(50);
-               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
-               msleep(50);
-               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
-               msleep(100);
-       }
-
-       /* switch dvb led on */
-       if (dev->gpio.dvb_led) {
-               tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                       dev->gpio.dvb_led, 0x00);
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(tm6000_init_digital_mode);
-
-struct reg_init {
-       u8 req;
-       u8 reg;
-       u8 val;
-};
-
-/* The meaning of those initializations are unknown */
-struct reg_init tm6000_init_tab[] = {
-       /* REG  VALUE */
-       { TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f },
-       { TM6010_REQ07_RFF_SOFT_RESET, 0x08 },
-       { TM6010_REQ07_RFF_SOFT_RESET, 0x00 },
-       { TM6010_REQ07_RD5_POWERSAVE, 0x4f },
-       { TM6000_REQ07_RDA_CLK_SEL, 0x23 },
-       { TM6000_REQ07_RDB_OUT_SEL, 0x08 },
-       { TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x00 },
-       { TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10 },
-       { TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00 },
-       { TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00 },
-       { TM6000_REQ07_REB_VADC_AADC_MODE, 0x64 },      /* 48000 bits/sample, external input */
-       { TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL, 0xc2 },
-
-       { TM6010_REQ07_R3F_RESET, 0x01 },               /* Start of soft reset */
-       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
-       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
-       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
-       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
-       { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 },
-       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 },
-       { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 },
-       { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 },
-       { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 },
-       { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a },
-       { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 },
-       { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 },
-       { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b },
-       { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 },
-       { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f },
-       { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd },
-       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
-       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
-       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
-       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
-       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
-       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
-       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
-       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
-       { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c },
-       { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c },
-       { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 },
-       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
-       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
-       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
-       { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 },
-       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
-       { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 },
-       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
-       { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a },
-       { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 },
-       { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 },
-       { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a },
-       { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 },
-       { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 },
-       { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 },
-       { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 },
-       { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 },
-       { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 },
-       { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 },
-       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
-       { TM6010_REQ07_RC1_TRESHOLD, 0xd0 },
-       { TM6010_REQ07_RC3_HSTART1, 0x88 },
-       { TM6010_REQ07_R3F_RESET, 0x00 },               /* End of the soft reset */
-       { TM6010_REQ05_R18_IMASK7, 0x00 },
-};
-
-struct reg_init tm6010_init_tab[] = {
-       { TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00 },
-       { TM6010_REQ07_RC4_HSTART0, 0xa0 },
-       { TM6010_REQ07_RC6_HEND0, 0x40 },
-       { TM6010_REQ07_RCA_VEND0, 0x31 },
-       { TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0xe1 },
-       { TM6010_REQ07_RE0_DVIDEO_SOURCE, 0x03 },
-       { TM6010_REQ07_RFE_POWER_DOWN, 0x7f },
-
-       { TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0 },
-       { TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4 },
-       { TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8 },
-       { TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00 },
-       { TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2 },
-       { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 },
-       { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 },
-       { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 },
-       { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc },
-
-       { TM6010_REQ07_R3F_RESET, 0x01 },
-       { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
-       { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
-       { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
-       { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
-       { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 },
-       { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 },
-       { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 },
-       { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 },
-       { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 },
-       { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a },
-       { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 },
-       { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 },
-       { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b },
-       { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 },
-       { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f },
-       { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd },
-       { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
-       { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
-       { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
-       { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
-       { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
-       { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
-       { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
-       { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
-       { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c },
-       { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c },
-       { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 },
-       { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
-       { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
-       { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
-       { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 },
-       { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
-       { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 },
-       { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
-       { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a },
-       { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 },
-       { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 },
-       { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a },
-       { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 },
-       { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 },
-       { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 },
-       { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 },
-       { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 },
-       { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 },
-       { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 },
-       { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
-       { TM6010_REQ07_RC1_TRESHOLD, 0xd0 },
-       { TM6010_REQ07_RC3_HSTART1, 0x88 },
-       { TM6010_REQ07_R3F_RESET, 0x00 },
-
-       { TM6010_REQ05_R18_IMASK7, 0x00 },
-
-       { TM6010_REQ07_RD8_IR_LEADER1, 0xaa },
-       { TM6010_REQ07_RD8_IR_LEADER0, 0x30 },
-       { TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 },
-       { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 },
-       { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 },
-       { TM6010_REQ07_RD8_IR, 0x2f },
-
-       /* set remote wakeup key:any key wakeup */
-       { TM6010_REQ07_RE5_REMOTE_WAKEUP,  0xfe },
-       { TM6010_REQ07_RD8_IR_WAKEUP_SEL,  0xff },
-};
-
-int tm6000_init(struct tm6000_core *dev)
-{
-       int board, rc = 0, i, size;
-       struct reg_init *tab;
-
-       /* Check board revision */
-       board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0);
-       if (board >= 0) {
-               switch (board & 0xff) {
-               case 0xf3:
-                       printk(KERN_INFO "Found tm6000\n");
-                       if (dev->dev_type != TM6000)
-                               dev->dev_type = TM6000;
-                       break;
-               case 0xf4:
-                       printk(KERN_INFO "Found tm6010\n");
-                       if (dev->dev_type != TM6010)
-                               dev->dev_type = TM6010;
-                       break;
-               default:
-                       printk(KERN_INFO "Unknown board version = 0x%08x\n", board);
-               }
-       } else
-               printk(KERN_ERR "Error %i while retrieving board version\n", board);
-
-       if (dev->dev_type == TM6010) {
-               tab = tm6010_init_tab;
-               size = ARRAY_SIZE(tm6010_init_tab);
-       } else {
-               tab = tm6000_init_tab;
-               size = ARRAY_SIZE(tm6000_init_tab);
-       }
-
-       /* Load board's initialization table */
-       for (i = 0; i < size; i++) {
-               rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val);
-               if (rc < 0) {
-                       printk(KERN_ERR "Error %i while setting req %d, "
-                                       "reg %d to value %d\n", rc,
-                                       tab[i].req, tab[i].reg, tab[i].val);
-                       return rc;
-               }
-       }
-
-       msleep(5); /* Just to be conservative */
-
-       rc = tm6000_cards_setup(dev);
-
-       return rc;
-}
-
-int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
-{
-       int val = 0;
-       u8 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
-       u8 areg_0a = 0x91; /* SIF 48KHz */
-
-       switch (bitrate) {
-       case 48000:
-               areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
-               areg_0a = 0x91; /* SIF 48KHz */
-               dev->audio_bitrate = bitrate;
-               break;
-       case 32000:
-               areg_f0 = 0x00; /* ADC MCLK = 375 Fs */
-               areg_0a = 0x90; /* SIF 32KHz */
-               dev->audio_bitrate = bitrate;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-
-       /* enable I2S, if we use sif or external I2S device */
-       if (dev->dev_type == TM6010) {
-               val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a);
-               if (val < 0)
-                       return val;
-
-               val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
-                                                       areg_f0, 0xf0);
-               if (val < 0)
-                       return val;
-       } else {
-               val = tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
-                                                       areg_f0, 0xf0);
-               if (val < 0)
-                       return val;
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
-
-int tm6000_set_audio_rinput(struct tm6000_core *dev)
-{
-       if (dev->dev_type == TM6010) {
-               /* Audio crossbar setting, default SIF1 */
-               u8 areg_f0;
-
-               switch (dev->rinput.amux) {
-               case TM6000_AMUX_SIF1:
-               case TM6000_AMUX_SIF2:
-                       areg_f0 = 0x03;
-                       break;
-               case TM6000_AMUX_ADC1:
-                       areg_f0 = 0x00;
-                       break;
-               case TM6000_AMUX_ADC2:
-                       areg_f0 = 0x08;
-                       break;
-               case TM6000_AMUX_I2S:
-                       areg_f0 = 0x04;
-                       break;
-               default:
-                       printk(KERN_INFO "%s: audio input dosn't support\n",
-                               dev->name);
-                       return 0;
-                       break;
-               }
-               /* Set audio input crossbar */
-               tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
-                                                       areg_f0, 0x0f);
-       } else {
-               u8 areg_eb;
-               /* Audio setting, default LINE1 */
-               switch (dev->rinput.amux) {
-               case TM6000_AMUX_ADC1:
-                       areg_eb = 0x00;
-                       break;
-               case TM6000_AMUX_ADC2:
-                       areg_eb = 0x04;
-                       break;
-               default:
-                       printk(KERN_INFO "%s: audio input dosn't support\n",
-                               dev->name);
-                       return 0;
-                       break;
-               }
-               /* Set audio input */
-               tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
-                                                       areg_eb, 0x0f);
-       }
-       return 0;
-}
-
-void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute)
-{
-       u8 mute_reg = 0;
-
-       if (mute)
-               mute_reg = 0x08;
-
-       tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08);
-}
-
-void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute)
-{
-       u8 mute_reg = 0;
-
-       if (mute)
-               mute_reg = 0x20;
-
-       if (dev->dev_type == TM6010) {
-               tm6000_set_reg_mask(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL,
-                                                       mute_reg, 0x20);
-               tm6000_set_reg_mask(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL,
-                                                       mute_reg, 0x20);
-       } else {
-               tm6000_set_reg_mask(dev, TM6000_REQ07_REC_VADC_AADC_LVOL,
-                                                       mute_reg, 0x20);
-               tm6000_set_reg_mask(dev, TM6000_REQ07_RED_VADC_AADC_RVOL,
-                                                       mute_reg, 0x20);
-       }
-}
-
-int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute)
-{
-       enum tm6000_mux mux;
-
-       if (dev->radio)
-               mux = dev->rinput.amux;
-       else
-               mux = dev->vinput[dev->input].amux;
-
-       switch (mux) {
-       case TM6000_AMUX_SIF1:
-       case TM6000_AMUX_SIF2:
-               if (dev->dev_type == TM6010)
-                       tm6010_set_mute_sif(dev, mute);
-               else {
-                       printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has"
-                                       " SIF audio inputs. Please check the %s"
-                                       " configuration.\n", dev->name);
-                       return -EINVAL;
-               }
-               break;
-       case TM6000_AMUX_ADC1:
-       case TM6000_AMUX_ADC2:
-               tm6010_set_mute_adc(dev, mute);
-               break;
-       default:
-               return -EINVAL;
-               break;
-       }
-       return 0;
-}
-
-void tm6010_set_volume_sif(struct tm6000_core *dev, int vol)
-{
-       u8 vol_reg;
-
-       vol_reg = vol & 0x0F;
-
-       if (vol < 0)
-               vol_reg |= 0x40;
-
-       tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, vol_reg);
-       tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg);
-}
-
-void tm6010_set_volume_adc(struct tm6000_core *dev, int vol)
-{
-       u8 vol_reg;
-
-       vol_reg = (vol + 0x10) & 0x1f;
-
-       if (dev->dev_type == TM6010) {
-               tm6000_set_reg(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, vol_reg);
-               tm6000_set_reg(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, vol_reg);
-       } else {
-               tm6000_set_reg(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, vol_reg);
-               tm6000_set_reg(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, vol_reg);
-       }
-}
-
-void tm6000_set_volume(struct tm6000_core *dev, int vol)
-{
-       enum tm6000_mux mux;
-
-       if (dev->radio) {
-               mux = dev->rinput.amux;
-               vol += 8; /* Offset to 0 dB */
-       } else
-               mux = dev->vinput[dev->input].amux;
-
-       switch (mux) {
-       case TM6000_AMUX_SIF1:
-       case TM6000_AMUX_SIF2:
-               if (dev->dev_type == TM6010)
-                       tm6010_set_volume_sif(dev, vol);
-               else
-                       printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has"
-                                       " SIF audio inputs. Please check the %s"
-                                       " configuration.\n", dev->name);
-               break;
-       case TM6000_AMUX_ADC1:
-       case TM6000_AMUX_ADC2:
-               tm6010_set_volume_adc(dev, vol);
-               break;
-       default:
-               break;
-       }
-}
-
-static LIST_HEAD(tm6000_devlist);
-static DEFINE_MUTEX(tm6000_devlist_mutex);
-
-/*
- * tm6000_realease_resource()
- */
-
-void tm6000_remove_from_devlist(struct tm6000_core *dev)
-{
-       mutex_lock(&tm6000_devlist_mutex);
-       list_del(&dev->devlist);
-       mutex_unlock(&tm6000_devlist_mutex);
-};
-
-void tm6000_add_into_devlist(struct tm6000_core *dev)
-{
-       mutex_lock(&tm6000_devlist_mutex);
-       list_add_tail(&dev->devlist, &tm6000_devlist);
-       mutex_unlock(&tm6000_devlist_mutex);
-};
-
-/*
- * Extension interface
- */
-
-static LIST_HEAD(tm6000_extension_devlist);
-
-int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
-                       char *buf, int size)
-{
-       struct tm6000_ops *ops = NULL;
-
-       /* FIXME: tm6000_extension_devlist_lock should be a spinlock */
-
-       if (!list_empty(&tm6000_extension_devlist)) {
-               list_for_each_entry(ops, &tm6000_extension_devlist, next) {
-                       if (ops->fillbuf && ops->type == type)
-                               ops->fillbuf(dev, buf, size);
-               }
-       }
-
-       return 0;
-}
-
-int tm6000_register_extension(struct tm6000_ops *ops)
-{
-       struct tm6000_core *dev = NULL;
-
-       mutex_lock(&tm6000_devlist_mutex);
-       list_add_tail(&ops->next, &tm6000_extension_devlist);
-       list_for_each_entry(dev, &tm6000_devlist, devlist) {
-               ops->init(dev);
-               printk(KERN_INFO "%s: Initialized (%s) extension\n",
-                      dev->name, ops->name);
-       }
-       mutex_unlock(&tm6000_devlist_mutex);
-       return 0;
-}
-EXPORT_SYMBOL(tm6000_register_extension);
-
-void tm6000_unregister_extension(struct tm6000_ops *ops)
-{
-       struct tm6000_core *dev = NULL;
-
-       mutex_lock(&tm6000_devlist_mutex);
-       list_for_each_entry(dev, &tm6000_devlist, devlist)
-               ops->fini(dev);
-
-       printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name);
-       list_del(&ops->next);
-       mutex_unlock(&tm6000_devlist_mutex);
-}
-EXPORT_SYMBOL(tm6000_unregister_extension);
-
-void tm6000_init_extension(struct tm6000_core *dev)
-{
-       struct tm6000_ops *ops = NULL;
-
-       mutex_lock(&tm6000_devlist_mutex);
-       if (!list_empty(&tm6000_extension_devlist)) {
-               list_for_each_entry(ops, &tm6000_extension_devlist, next) {
-                       if (ops->init)
-                               ops->init(dev);
-               }
-       }
-       mutex_unlock(&tm6000_devlist_mutex);
-}
-
-void tm6000_close_extension(struct tm6000_core *dev)
-{
-       struct tm6000_ops *ops = NULL;
-
-       mutex_lock(&tm6000_devlist_mutex);
-       if (!list_empty(&tm6000_extension_devlist)) {
-               list_for_each_entry(ops, &tm6000_extension_devlist, next) {
-                       if (ops->fini)
-                               ops->fini(dev);
-               }
-       }
-       mutex_unlock(&tm6000_devlist_mutex);
-}
diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c
deleted file mode 100644 (file)
index 0e0dfce..0000000
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- *  tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices
- *
- *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation version 2
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include "tm6000.h"
-#include "tm6000-regs.h"
-
-#include "zl10353.h"
-
-#include <media/tuner.h>
-
-#include "tuner-xc2028.h"
-#include "xc5000.h"
-
-MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_LICENSE("GPL");
-
-MODULE_SUPPORTED_DEVICE("{{Trident, tm5600},"
-                       "{{Trident, tm6000},"
-                       "{{Trident, tm6010}");
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debug message");
-
-static inline void print_err_status(struct tm6000_core *dev,
-                                   int packet, int status)
-{
-       char *errmsg = "Unknown";
-
-       switch (status) {
-       case -ENOENT:
-               errmsg = "unlinked synchronuously";
-               break;
-       case -ECONNRESET:
-               errmsg = "unlinked asynchronuously";
-               break;
-       case -ENOSR:
-               errmsg = "Buffer error (overrun)";
-               break;
-       case -EPIPE:
-               errmsg = "Stalled (device not responding)";
-               break;
-       case -EOVERFLOW:
-               errmsg = "Babble (bad cable?)";
-               break;
-       case -EPROTO:
-               errmsg = "Bit-stuff error (bad cable?)";
-               break;
-       case -EILSEQ:
-               errmsg = "CRC/Timeout (could be anything)";
-               break;
-       case -ETIME:
-               errmsg = "Device does not respond";
-               break;
-       }
-       if (packet < 0) {
-               dprintk(dev, 1, "URB status %d [%s].\n",
-                       status, errmsg);
-       } else {
-               dprintk(dev, 1, "URB packet %d, status %d [%s].\n",
-                       packet, status, errmsg);
-       }
-}
-
-static void tm6000_urb_received(struct urb *urb)
-{
-       int ret;
-       struct tm6000_core *dev = urb->context;
-
-       if (urb->status != 0)
-               print_err_status(dev, 0, urb->status);
-       else if (urb->actual_length > 0)
-               dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
-                                                  urb->actual_length);
-
-       if (dev->dvb->streams > 0) {
-               ret = usb_submit_urb(urb, GFP_ATOMIC);
-               if (ret < 0) {
-                       printk(KERN_ERR "tm6000:  error %s\n", __func__);
-                       kfree(urb->transfer_buffer);
-                       usb_free_urb(urb);
-               }
-       }
-}
-
-int tm6000_start_stream(struct tm6000_core *dev)
-{
-       int ret;
-       unsigned int pipe, size;
-       struct tm6000_dvb *dvb = dev->dvb;
-
-       printk(KERN_INFO "tm6000: got start stream request %s\n", __func__);
-
-       if (dev->mode != TM6000_MODE_DIGITAL) {
-               tm6000_init_digital_mode(dev);
-               dev->mode = TM6000_MODE_DIGITAL;
-       }
-
-       dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (dvb->bulk_urb == NULL) {
-               printk(KERN_ERR "tm6000: couldn't allocate urb\n");
-               return -ENOMEM;
-       }
-
-       pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress
-                                                         & USB_ENDPOINT_NUMBER_MASK);
-
-       size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
-       size = size * 15; /* 512 x 8 or 12 or 15 */
-
-       dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
-       if (dvb->bulk_urb->transfer_buffer == NULL) {
-               usb_free_urb(dvb->bulk_urb);
-               printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
-               return -ENOMEM;
-       }
-
-       usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
-                                                dvb->bulk_urb->transfer_buffer,
-                                                size,
-                                                tm6000_urb_received, dev);
-
-       ret = usb_clear_halt(dev->udev, pipe);
-       if (ret < 0) {
-               printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",
-                                                       ret, __func__);
-               return ret;
-       } else
-               printk(KERN_ERR "tm6000: pipe resetted\n");
-
-/*     mutex_lock(&tm6000_driver.open_close_mutex); */
-       ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
-
-/*     mutex_unlock(&tm6000_driver.open_close_mutex); */
-       if (ret) {
-               printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",
-                                                                       ret);
-
-               kfree(dvb->bulk_urb->transfer_buffer);
-               usb_free_urb(dvb->bulk_urb);
-               return ret;
-       }
-
-       return 0;
-}
-
-void tm6000_stop_stream(struct tm6000_core *dev)
-{
-       struct tm6000_dvb *dvb = dev->dvb;
-
-       if (dvb->bulk_urb) {
-               printk(KERN_INFO "urb killing\n");
-               usb_kill_urb(dvb->bulk_urb);
-               printk(KERN_INFO "urb buffer free\n");
-               kfree(dvb->bulk_urb->transfer_buffer);
-               usb_free_urb(dvb->bulk_urb);
-               dvb->bulk_urb = NULL;
-       }
-}
-
-int tm6000_start_feed(struct dvb_demux_feed *feed)
-{
-       struct dvb_demux *demux = feed->demux;
-       struct tm6000_core *dev = demux->priv;
-       struct tm6000_dvb *dvb = dev->dvb;
-       printk(KERN_INFO "tm6000: got start feed request %s\n", __func__);
-
-       mutex_lock(&dvb->mutex);
-       if (dvb->streams == 0) {
-               dvb->streams = 1;
-/*             mutex_init(&tm6000_dev->streming_mutex); */
-               tm6000_start_stream(dev);
-       } else
-               ++(dvb->streams);
-       mutex_unlock(&dvb->mutex);
-
-       return 0;
-}
-
-int tm6000_stop_feed(struct dvb_demux_feed *feed)
-{
-       struct dvb_demux *demux = feed->demux;
-       struct tm6000_core *dev = demux->priv;
-       struct tm6000_dvb *dvb = dev->dvb;
-
-       printk(KERN_INFO "tm6000: got stop feed request %s\n", __func__);
-
-       mutex_lock(&dvb->mutex);
-
-       printk(KERN_INFO "stream %#x\n", dvb->streams);
-       --(dvb->streams);
-       if (dvb->streams == 0) {
-               printk(KERN_INFO "stop stream\n");
-               tm6000_stop_stream(dev);
-/*             mutex_destroy(&tm6000_dev->streaming_mutex); */
-       }
-       mutex_unlock(&dvb->mutex);
-/*     mutex_destroy(&tm6000_dev->streaming_mutex); */
-
-       return 0;
-}
-
-int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
-{
-       struct tm6000_dvb *dvb = dev->dvb;
-
-       if (dev->caps.has_zl10353) {
-               struct zl10353_config config = {
-                                    .demod_address = dev->demod_addr,
-                                    .no_tuner = 1,
-                                    .parallel_ts = 1,
-                                    .if2 = 45700,
-                                    .disable_i2c_gate_ctrl = 1,
-                                   };
-
-               dvb->frontend = dvb_attach(zl10353_attach, &config,
-                                                          &dev->i2c_adap);
-       } else {
-               printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
-               return -1;
-       }
-
-       return (!dvb->frontend) ? -1 : 0;
-}
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-int register_dvb(struct tm6000_core *dev)
-{
-       int ret = -1;
-       struct tm6000_dvb *dvb = dev->dvb;
-
-       mutex_init(&dvb->mutex);
-
-       dvb->streams = 0;
-
-       /* attach the frontend */
-       ret = tm6000_dvb_attach_frontend(dev);
-       if (ret < 0) {
-               printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
-               goto err;
-       }
-
-       ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
-                                       THIS_MODULE, &dev->udev->dev, adapter_nr);
-       dvb->adapter.priv = dev;
-
-       if (dvb->frontend) {
-               switch (dev->tuner_type) {
-               case TUNER_XC2028: {
-                       struct xc2028_config cfg = {
-                               .i2c_adap = &dev->i2c_adap,
-                               .i2c_addr = dev->tuner_addr,
-                       };
-
-                       dvb->frontend->callback = tm6000_tuner_callback;
-                       ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
-                       if (ret < 0) {
-                               printk(KERN_ERR
-                                       "tm6000: couldn't register frontend\n");
-                               goto adapter_err;
-                       }
-
-                       if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) {
-                               printk(KERN_ERR "tm6000: couldn't register "
-                                               "frontend (xc3028)\n");
-                               ret = -EINVAL;
-                               goto frontend_err;
-                       }
-                       printk(KERN_INFO "tm6000: XC2028/3028 asked to be "
-                                        "attached to frontend!\n");
-                       break;
-                       }
-               case TUNER_XC5000: {
-                       struct xc5000_config cfg = {
-                               .i2c_address = dev->tuner_addr,
-                       };
-
-                       dvb->frontend->callback = tm6000_xc5000_callback;
-                       ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
-                       if (ret < 0) {
-                               printk(KERN_ERR
-                                       "tm6000: couldn't register frontend\n");
-                               goto adapter_err;
-                       }
-
-                       if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) {
-                               printk(KERN_ERR "tm6000: couldn't register "
-                                               "frontend (xc5000)\n");
-                               ret = -EINVAL;
-                               goto frontend_err;
-                       }
-                       printk(KERN_INFO "tm6000: XC5000 asked to be "
-                                        "attached to frontend!\n");
-                       break;
-                       }
-               }
-       } else
-               printk(KERN_ERR "tm6000: no frontend found\n");
-
-       dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
-                                                           | DMX_MEMORY_BASED_FILTERING;
-       dvb->demux.priv = dev;
-       dvb->demux.filternum = 8;
-       dvb->demux.feednum = 8;
-       dvb->demux.start_feed = tm6000_start_feed;
-       dvb->demux.stop_feed = tm6000_stop_feed;
-       dvb->demux.write_to_decoder = NULL;
-       ret = dvb_dmx_init(&dvb->demux);
-       if (ret < 0) {
-               printk("tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
-               goto frontend_err;
-       }
-
-       dvb->dmxdev.filternum = dev->dvb->demux.filternum;
-       dvb->dmxdev.demux = &dev->dvb->demux.dmx;
-       dvb->dmxdev.capabilities = 0;
-
-       ret =  dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
-       if (ret < 0) {
-               printk("tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
-               goto dvb_dmx_err;
-       }
-
-       return 0;
-
-dvb_dmx_err:
-       dvb_dmx_release(&dvb->demux);
-frontend_err:
-       if (dvb->frontend) {
-               dvb_frontend_detach(dvb->frontend);
-               dvb_unregister_frontend(dvb->frontend);
-       }
-adapter_err:
-       dvb_unregister_adapter(&dvb->adapter);
-err:
-       return ret;
-}
-
-void unregister_dvb(struct tm6000_core *dev)
-{
-       struct tm6000_dvb *dvb = dev->dvb;
-
-       if (dvb->bulk_urb != NULL) {
-               struct urb *bulk_urb = dvb->bulk_urb;
-
-               kfree(bulk_urb->transfer_buffer);
-               bulk_urb->transfer_buffer = NULL;
-               usb_unlink_urb(bulk_urb);
-               usb_free_urb(bulk_urb);
-       }
-
-/*     mutex_lock(&tm6000_driver.open_close_mutex); */
-       if (dvb->frontend) {
-               dvb_frontend_detach(dvb->frontend);
-               dvb_unregister_frontend(dvb->frontend);
-       }
-
-       dvb_dmxdev_release(&dvb->dmxdev);
-       dvb_dmx_release(&dvb->demux);
-       dvb_unregister_adapter(&dvb->adapter);
-       mutex_destroy(&dvb->mutex);
-/*     mutex_unlock(&tm6000_driver.open_close_mutex); */
-}
-
-static int dvb_init(struct tm6000_core *dev)
-{
-       struct tm6000_dvb *dvb;
-       int rc;
-
-       if (!dev)
-               return 0;
-
-       if (!dev->caps.has_dvb)
-               return 0;
-
-       dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL);
-       if (!dvb) {
-               printk(KERN_INFO "Cannot allocate memory\n");
-               return -ENOMEM;
-       }
-
-       dev->dvb = dvb;
-
-       rc = register_dvb(dev);
-       if (rc < 0) {
-               kfree(dvb);
-               dev->dvb = NULL;
-               return 0;
-       }
-
-       return 0;
-}
-
-static int dvb_fini(struct tm6000_core *dev)
-{
-       if (!dev)
-               return 0;
-
-       if (!dev->caps.has_dvb)
-               return 0;
-
-       if (dev->dvb) {
-               unregister_dvb(dev);
-               kfree(dev->dvb);
-               dev->dvb = NULL;
-       }
-
-       return 0;
-}
-
-static struct tm6000_ops dvb_ops = {
-       .type   = TM6000_DVB,
-       .name   = "TM6000 dvb Extension",
-       .init   = dvb_init,
-       .fini   = dvb_fini,
-};
-
-static int __init tm6000_dvb_register(void)
-{
-       return tm6000_register_extension(&dvb_ops);
-}
-
-static void __exit tm6000_dvb_unregister(void)
-{
-       tm6000_unregister_extension(&dvb_ops);
-}
-
-module_init(tm6000_dvb_register);
-module_exit(tm6000_dvb_unregister);
diff --git a/drivers/staging/tm6000/tm6000-i2c.c b/drivers/staging/tm6000/tm6000-i2c.c
deleted file mode 100644 (file)
index 5a651ea..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- *  tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
- *
- *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- *     - Fix SMBus Read Byte command
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation version 2
- *
- *  This program is distributed 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/module.h>
-#include <linux/kernel.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-
-#include "tm6000.h"
-#include "tm6000-regs.h"
-#include <media/v4l2-common.h>
-#include <media/tuner.h>
-#include "tuner-xc2028.h"
-
-
-/* ----------------------------------------------------------- */
-
-static unsigned int i2c_debug;
-module_param(i2c_debug, int, 0644);
-MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
-
-#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \
-                       printk(KERN_DEBUG "%s at %s: " fmt, \
-                       dev->name, __func__, ##args); } while (0)
-
-static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr,
-                               __u8 reg, char *buf, int len)
-{
-       int rc;
-       unsigned int tsleep;
-       unsigned int i2c_packet_limit = 16;
-
-       if (dev->dev_type == TM6010)
-               i2c_packet_limit = 64;
-
-       if (!buf)
-               return -1;
-
-       if (len < 1 || len > i2c_packet_limit) {
-               printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
-                       len, i2c_packet_limit);
-               return -1;
-       }
-
-       /* capture mutex */
-       rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
-               USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
-               addr | reg << 8, 0, buf, len);
-
-       if (rc < 0) {
-               /* release mutex */
-               return rc;
-       }
-
-       /* Calculate delay time, 14000us for 64 bytes */
-       tsleep = ((len * 200) + 200 + 1000) / 1000;
-       msleep(tsleep);
-
-       /* release mutex */
-       return rc;
-}
-
-/* Generic read - doesn't work fine with 16bit registers */
-static int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr,
-                               __u8 reg, char *buf, int len)
-{
-       int rc;
-       u8 b[2];
-       unsigned int i2c_packet_limit = 16;
-
-       if (dev->dev_type == TM6010)
-               i2c_packet_limit = 64;
-
-       if (!buf)
-               return -1;
-
-       if (len < 1 || len > i2c_packet_limit) {
-               printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
-                       len, i2c_packet_limit);
-               return -1;
-       }
-
-       /* capture mutex */
-       if ((dev->caps.has_zl10353) && (dev->demod_addr << 1 == addr) && (reg % 2 == 0)) {
-               /*
-                * Workaround an I2C bug when reading from zl10353
-                */
-               reg -= 1;
-               len += 1;
-
-               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, b, len);
-
-               *buf = b[1];
-       } else {
-               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, buf, len);
-       }
-
-       /* release mutex */
-       return rc;
-}
-
-/*
- * read from a 16bit register
- * for example xc2028, xc3028 or xc3028L
- */
-static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr,
-                                 __u16 reg, char *buf, int len)
-{
-       int rc;
-       unsigned char ureg;
-
-       if (!buf || len != 2)
-               return -1;
-
-       /* capture mutex */
-       if (dev->dev_type == TM6010) {
-               ureg = reg & 0xFF;
-               rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
-                       USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
-                       addr | (reg & 0xFF00), 0, &ureg, 1);
-
-               if (rc < 0) {
-                       /* release mutex */
-                       return rc;
-               }
-
-               msleep(1400 / 1000);
-               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
-                       USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ,
-                       reg, 0, buf, len);
-       } else {
-               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
-                       USB_RECIP_DEVICE, REQ_14_SET_GET_I2C_WR2_RDN,
-                       addr, reg, buf, len);
-       }
-
-       /* release mutex */
-       return rc;
-}
-
-static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
-                          struct i2c_msg msgs[], int num)
-{
-       struct tm6000_core *dev = i2c_adap->algo_data;
-       int addr, rc, i, byte;
-
-       if (num <= 0)
-               return 0;
-       for (i = 0; i < num; i++) {
-               addr = (msgs[i].addr << 1) & 0xff;
-               i2c_dprintk(2, "%s %s addr=0x%x len=%d:",
-                        (msgs[i].flags & I2C_M_RD) ? "read" : "write",
-                        i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
-               if (msgs[i].flags & I2C_M_RD) {
-                       /* read request without preceding register selection */
-                       /*
-                        * The TM6000 only supports a read transaction
-                        * immediately after a 1 or 2 byte write to select
-                        * a register.  We cannot fulfil this request.
-                        */
-                       i2c_dprintk(2, " read without preceding write not"
-                                      " supported");
-                       rc = -EOPNOTSUPP;
-                       goto err;
-               } else if (i + 1 < num && msgs[i].len <= 2 &&
-                          (msgs[i + 1].flags & I2C_M_RD) &&
-                          msgs[i].addr == msgs[i + 1].addr) {
-                       /* 1 or 2 byte write followed by a read */
-                       if (i2c_debug >= 2)
-                               for (byte = 0; byte < msgs[i].len; byte++)
-                                       printk(" %02x", msgs[i].buf[byte]);
-                       i2c_dprintk(2, "; joined to read %s len=%d:",
-                                   i == num - 2 ? "stop" : "nonstop",
-                                   msgs[i + 1].len);
-
-                       if (msgs[i].len == 2) {
-                               rc = tm6000_i2c_recv_regs16(dev, addr,
-                                       msgs[i].buf[0] << 8 | msgs[i].buf[1],
-                                       msgs[i + 1].buf, msgs[i + 1].len);
-                       } else {
-                               rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0],
-                                       msgs[i + 1].buf, msgs[i + 1].len);
-                       }
-
-                       i++;
-
-                       if (addr == dev->tuner_addr << 1) {
-                               tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
-                               tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
-                       }
-                       if (i2c_debug >= 2)
-                               for (byte = 0; byte < msgs[i].len; byte++)
-                                       printk(" %02x", msgs[i].buf[byte]);
-               } else {
-                       /* write bytes */
-                       if (i2c_debug >= 2)
-                               for (byte = 0; byte < msgs[i].len; byte++)
-                                       printk(" %02x", msgs[i].buf[byte]);
-                       rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0],
-                               msgs[i].buf + 1, msgs[i].len - 1);
-
-                       if (addr == dev->tuner_addr  << 1) {
-                               tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
-                               tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
-                       }
-               }
-               if (i2c_debug >= 2)
-                       printk("\n");
-               if (rc < 0)
-                       goto err;
-       }
-
-       return num;
-err:
-       i2c_dprintk(2, " ERROR: %i\n", rc);
-       return rc;
-}
-
-static int tm6000_i2c_eeprom(struct tm6000_core *dev)
-{
-       int i, rc;
-       unsigned char *p = dev->eedata;
-       unsigned char bytes[17];
-
-       dev->i2c_client.addr = 0xa0 >> 1;
-       dev->eedata_size = 0;
-
-       bytes[16] = '\0';
-       for (i = 0; i < sizeof(dev->eedata); ) {
-               *p = i;
-               rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1);
-               if (rc < 1) {
-                       if (p == dev->eedata)
-                               goto noeeprom;
-                       else {
-                               printk(KERN_WARNING
-                               "%s: i2c eeprom read error (err=%d)\n",
-                               dev->name, rc);
-                       }
-                       return -EINVAL;
-               }
-               dev->eedata_size++;
-               p++;
-               if (0 == (i % 16))
-                       printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
-               printk(" %02x", dev->eedata[i]);
-               if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z'))
-                       bytes[i%16] = dev->eedata[i];
-               else
-                       bytes[i%16] = '.';
-
-               i++;
-
-               if (0 == (i % 16)) {
-                       bytes[16] = '\0';
-                       printk("  %s\n", bytes);
-               }
-       }
-       if (0 != (i%16)) {
-               bytes[i%16] = '\0';
-               for (i %= 16; i < 16; i++)
-                       printk("   ");
-               printk("  %s\n", bytes);
-       }
-
-       return 0;
-
-noeeprom:
-       printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
-              dev->name, rc);
-       return -EINVAL;
-}
-
-/* ----------------------------------------------------------- */
-
-/*
- * functionality()
- */
-static u32 functionality(struct i2c_adapter *adap)
-{
-       return I2C_FUNC_SMBUS_EMUL;
-}
-
-static const struct i2c_algorithm tm6000_algo = {
-       .master_xfer   = tm6000_i2c_xfer,
-       .functionality = functionality,
-};
-
-/* ----------------------------------------------------------- */
-
-/*
- * tm6000_i2c_register()
- * register i2c bus
- */
-int tm6000_i2c_register(struct tm6000_core *dev)
-{
-       int rc;
-
-       dev->i2c_adap.owner = THIS_MODULE;
-       dev->i2c_adap.algo = &tm6000_algo;
-       dev->i2c_adap.dev.parent = &dev->udev->dev;
-       strlcpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name));
-       dev->i2c_adap.algo_data = dev;
-       i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
-       rc = i2c_add_adapter(&dev->i2c_adap);
-       if (rc)
-               return rc;
-
-       dev->i2c_client.adapter = &dev->i2c_adap;
-       strlcpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE);
-       tm6000_i2c_eeprom(dev);
-
-       return 0;
-}
-
-/*
- * tm6000_i2c_unregister()
- * unregister i2c_bus
- */
-int tm6000_i2c_unregister(struct tm6000_core *dev)
-{
-       i2c_del_adapter(&dev->i2c_adap);
-       return 0;
-}
diff --git a/drivers/staging/tm6000/tm6000-input.c b/drivers/staging/tm6000/tm6000-input.c
deleted file mode 100644 (file)
index 70a2c5f..0000000
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- *  tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- *  Copyright (C) 2010 Stefan Ringel <stefan.ringel@arcor.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation version 2
- *
- *  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/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <linux/input.h>
-#include <linux/usb.h>
-
-#include <media/rc-core.h>
-
-#include "tm6000.h"
-#include "tm6000-regs.h"
-
-static unsigned int ir_debug;
-module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug, "enable debug message [IR]");
-
-static unsigned int enable_ir = 1;
-module_param(enable_ir, int, 0644);
-MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
-
-/* number of 50ms for ON-OFF-ON power led */
-/* show IR activity */
-#define PWLED_OFF 2
-
-#undef dprintk
-
-#define dprintk(fmt, arg...) \
-       if (ir_debug) { \
-               printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
-       }
-
-struct tm6000_ir_poll_result {
-       u16 rc_data;
-};
-
-struct tm6000_IR {
-       struct tm6000_core      *dev;
-       struct rc_dev           *rc;
-       char                    name[32];
-       char                    phys[32];
-
-       /* poll expernal decoder */
-       int                     polling;
-       struct delayed_work     work;
-       u8                      wait:1;
-       u8                      key:1;
-       u8                      pwled:1;
-       u8                      pwledcnt;
-       u16                     key_addr;
-       struct urb              *int_urb;
-       u8                      *urb_data;
-
-       int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *);
-
-       /* IR device properties */
-       u64                     rc_type;
-};
-
-
-void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
-{
-       struct tm6000_IR *ir = dev->ir;
-
-       if (!dev->ir)
-               return;
-
-       if (state)
-               ir->wait = 1;
-       else
-               ir->wait = 0;
-}
-
-
-static int tm6000_ir_config(struct tm6000_IR *ir)
-{
-       struct tm6000_core *dev = ir->dev;
-       u8 buf[10];
-       int rc;
-
-       switch (ir->rc_type) {
-       case RC_TYPE_NEC:
-               /* Setup IR decoder for NEC standard 12MHz system clock */
-               /* IR_LEADER_CNT = 0.9ms             */
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa);
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30);
-               /* IR_PULSE_CNT = 0.7ms              */
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20);
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0);
-               /* Remote WAKEUP = enable */
-               tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe);
-               /* IR_WKUP_SEL = Low byte in decoded IR data */
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff);
-               /* IR_WKU_ADD code */
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff);
-               tm6000_flash_led(dev, 0);
-               msleep(100);
-               tm6000_flash_led(dev, 1);
-               break;
-       default:
-               /* hack */
-               buf[0] = 0xff;
-               buf[1] = 0xff;
-               buf[2] = 0xf2;
-               buf[3] = 0x2b;
-               buf[4] = 0x20;
-               buf[5] = 0x35;
-               buf[6] = 0x60;
-               buf[7] = 0x04;
-               buf[8] = 0xc0;
-               buf[9] = 0x08;
-
-               rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
-                       USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
-               msleep(100);
-
-               if (rc < 0) {
-                       printk(KERN_INFO "IR configuration failed");
-                       return rc;
-               }
-               break;
-       }
-
-       return 0;
-}
-
-static void tm6000_ir_urb_received(struct urb *urb)
-{
-       struct tm6000_core *dev = urb->context;
-       struct tm6000_IR *ir = dev->ir;
-       int rc;
-
-       if (urb->status != 0)
-               printk(KERN_INFO "not ready\n");
-       else if (urb->actual_length > 0) {
-               memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length);
-
-               dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0],
-                       ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]);
-
-               ir->key = 1;
-       }
-
-       rc = usb_submit_urb(urb, GFP_ATOMIC);
-}
-
-static int default_polling_getkey(struct tm6000_IR *ir,
-                               struct tm6000_ir_poll_result *poll_result)
-{
-       struct tm6000_core *dev = ir->dev;
-       int rc;
-       u8 buf[2];
-
-       if (ir->wait && !&dev->int_in)
-               return 0;
-
-       if (&dev->int_in) {
-               switch (ir->rc_type) {
-               case RC_TYPE_RC5:
-                       poll_result->rc_data = ir->urb_data[0];
-                       break;
-               case RC_TYPE_NEC:
-                       if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) {
-                               poll_result->rc_data = ir->urb_data[0]
-                                                       | ir->urb_data[1] << 8;
-                       }
-                       break;
-               default:
-                       poll_result->rc_data = ir->urb_data[0]
-                                       | ir->urb_data[1] << 8;
-                       break;
-               }
-       } else {
-               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
-               msleep(10);
-               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
-               msleep(10);
-
-               if (ir->rc_type == RC_TYPE_RC5) {
-                       rc = tm6000_read_write_usb(dev, USB_DIR_IN |
-                               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               REQ_02_GET_IR_CODE, 0, 0, buf, 1);
-
-                       msleep(10);
-
-                       dprintk("read data=%02x\n", buf[0]);
-                       if (rc < 0)
-                               return rc;
-
-                       poll_result->rc_data = buf[0];
-               } else {
-                       rc = tm6000_read_write_usb(dev, USB_DIR_IN |
-                               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               REQ_02_GET_IR_CODE, 0, 0, buf, 2);
-
-                       msleep(10);
-
-                       dprintk("read data=%04x\n", buf[0] | buf[1] << 8);
-                       if (rc < 0)
-                               return rc;
-
-                       poll_result->rc_data = buf[0] | buf[1] << 8;
-               }
-               if ((poll_result->rc_data & 0x00ff) != 0xff)
-                       ir->key = 1;
-       }
-       return 0;
-}
-
-static void tm6000_ir_handle_key(struct tm6000_IR *ir)
-{
-       struct tm6000_core *dev = ir->dev;
-       int result;
-       struct tm6000_ir_poll_result poll_result;
-
-       /* read the registers containing the IR status */
-       result = ir->get_key(ir, &poll_result);
-       if (result < 0) {
-               printk(KERN_INFO "ir->get_key() failed %d\n", result);
-               return;
-       }
-
-       dprintk("ir->get_key result data=%04x\n", poll_result.rc_data);
-
-       if (ir->pwled) {
-               if (ir->pwledcnt >= PWLED_OFF) {
-                       ir->pwled = 0;
-                       ir->pwledcnt = 0;
-                       tm6000_flash_led(dev, 1);
-               } else
-                       ir->pwledcnt += 1;
-       }
-
-       if (ir->key) {
-               rc_keydown(ir->rc, poll_result.rc_data, 0);
-               ir->key = 0;
-               ir->pwled = 1;
-               ir->pwledcnt = 0;
-               tm6000_flash_led(dev, 0);
-       }
-       return;
-}
-
-static void tm6000_ir_work(struct work_struct *work)
-{
-       struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
-
-       tm6000_ir_handle_key(ir);
-       schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
-}
-
-static int tm6000_ir_start(struct rc_dev *rc)
-{
-       struct tm6000_IR *ir = rc->priv;
-
-       INIT_DELAYED_WORK(&ir->work, tm6000_ir_work);
-       schedule_delayed_work(&ir->work, 0);
-
-       return 0;
-}
-
-static void tm6000_ir_stop(struct rc_dev *rc)
-{
-       struct tm6000_IR *ir = rc->priv;
-
-       cancel_delayed_work_sync(&ir->work);
-}
-
-int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
-{
-       struct tm6000_IR *ir = rc->priv;
-
-       if (!ir)
-               return 0;
-
-       if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC))
-               ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff);
-
-       ir->get_key = default_polling_getkey;
-       ir->rc_type = rc_type;
-
-       tm6000_ir_config(ir);
-       /* TODO */
-       return 0;
-}
-
-int tm6000_ir_int_start(struct tm6000_core *dev)
-{
-       struct tm6000_IR *ir = dev->ir;
-       int pipe, size;
-       int err = -ENOMEM;
-
-
-       if (!ir)
-               return -ENODEV;
-
-       ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!ir->int_urb)
-               return -ENOMEM;
-
-       pipe = usb_rcvintpipe(dev->udev,
-               dev->int_in.endp->desc.bEndpointAddress
-               & USB_ENDPOINT_NUMBER_MASK);
-
-       size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
-       dprintk("IR max size: %d\n", size);
-
-       ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
-       if (ir->int_urb->transfer_buffer == NULL) {
-               usb_free_urb(ir->int_urb);
-               return err;
-       }
-       dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
-       usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
-               ir->int_urb->transfer_buffer, size,
-               tm6000_ir_urb_received, dev,
-               dev->int_in.endp->desc.bInterval);
-       err = usb_submit_urb(ir->int_urb, GFP_KERNEL);
-       if (err) {
-               kfree(ir->int_urb->transfer_buffer);
-               usb_free_urb(ir->int_urb);
-               return err;
-       }
-       ir->urb_data = kzalloc(size, GFP_KERNEL);
-
-       return 0;
-}
-
-void tm6000_ir_int_stop(struct tm6000_core *dev)
-{
-       struct tm6000_IR *ir = dev->ir;
-
-       if (!ir)
-               return;
-
-       usb_kill_urb(ir->int_urb);
-       kfree(ir->int_urb->transfer_buffer);
-       usb_free_urb(ir->int_urb);
-       ir->int_urb = NULL;
-       kfree(ir->urb_data);
-       ir->urb_data = NULL;
-}
-
-int tm6000_ir_init(struct tm6000_core *dev)
-{
-       struct tm6000_IR *ir;
-       struct rc_dev *rc;
-       int err = -ENOMEM;
-
-       if (!enable_ir)
-               return -ENODEV;
-
-       if (!dev->caps.has_remote)
-               return 0;
-
-       if (!dev->ir_codes)
-               return 0;
-
-       ir = kzalloc(sizeof(*ir), GFP_KERNEL);
-       rc = rc_allocate_device();
-       if (!ir || !rc)
-               goto out;
-
-       /* record handles to ourself */
-       ir->dev = dev;
-       dev->ir = ir;
-       ir->rc = rc;
-
-       /* input einrichten */
-       rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC;
-       rc->priv = ir;
-       rc->change_protocol = tm6000_ir_change_protocol;
-       rc->open = tm6000_ir_start;
-       rc->close = tm6000_ir_stop;
-       rc->driver_type = RC_DRIVER_SCANCODE;
-
-       ir->polling = 50;
-       ir->pwled = 0;
-       ir->pwledcnt = 0;
-
-
-       snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
-                                               dev->name);
-
-       usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
-       strlcat(ir->phys, "/input0", sizeof(ir->phys));
-
-       tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN);
-
-       rc->input_name = ir->name;
-       rc->input_phys = ir->phys;
-       rc->input_id.bustype = BUS_USB;
-       rc->input_id.version = 1;
-       rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
-       rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
-       rc->map_name = dev->ir_codes;
-       rc->driver_name = "tm6000";
-       rc->dev.parent = &dev->udev->dev;
-
-       if (&dev->int_in) {
-               dprintk("IR over int\n");
-
-               err = tm6000_ir_int_start(dev);
-
-               if (err)
-                       goto out;
-       }
-
-       /* ir register */
-       err = rc_register_device(rc);
-       if (err)
-               goto out;
-
-       return 0;
-
-out:
-       dev->ir = NULL;
-       rc_free_device(rc);
-       kfree(ir);
-       return err;
-}
-
-int tm6000_ir_fini(struct tm6000_core *dev)
-{
-       struct tm6000_IR *ir = dev->ir;
-
-       /* skip detach on non attached board */
-
-       if (!ir)
-               return 0;
-
-       rc_unregister_device(ir->rc);
-
-       if (ir->int_urb)
-               tm6000_ir_int_stop(dev);
-
-       kfree(ir);
-       dev->ir = NULL;
-
-       return 0;
-}
diff --git a/drivers/staging/tm6000/tm6000-regs.h b/drivers/staging/tm6000/tm6000-regs.h
deleted file mode 100644 (file)
index 5375a83..0000000
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- *  tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.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 version 2
- *
- *  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.
- */
-
-/*
- * Define TV Master TM5600/TM6000/TM6010 Request codes
- */
-#define REQ_00_SET_IR_VALUE            0
-#define REQ_01_SET_WAKEUP_IRCODE       1
-#define REQ_02_GET_IR_CODE             2
-#define REQ_03_SET_GET_MCU_PIN         3
-#define REQ_04_EN_DISABLE_MCU_INT      4
-#define REQ_05_SET_GET_USBREG          5
-       /* Write: RegNum, Value, 0 */
-       /* Read : RegNum, Value, 1, RegStatus */
-#define REQ_06_SET_GET_USBREG_BIT      6
-#define REQ_07_SET_GET_AVREG           7
-       /* Write: RegNum, Value, 0 */
-       /* Read : RegNum, Value, 1, RegStatus */
-#define REQ_08_SET_GET_AVREG_BIT       8
-#define REQ_09_SET_GET_TUNER_FQ                9
-#define REQ_10_SET_TUNER_SYSTEM                10
-#define REQ_11_SET_EEPROM_ADDR         11
-#define REQ_12_SET_GET_EEPROMBYTE      12
-#define REQ_13_GET_EEPROM_SEQREAD      13
-#define REQ_14_SET_GET_I2C_WR2_RDN     14
-#define REQ_15_SET_GET_I2CBYTE         15
-       /* Write: Subaddr, Slave Addr, value, 0 */
-       /* Read : Subaddr, Slave Addr, value, 1 */
-#define REQ_16_SET_GET_I2C_WR1_RDN     16
-       /* Subaddr, Slave Addr, 0, length */
-#define REQ_17_SET_GET_I2CFP           17
-       /* Write: Slave Addr, register, value */
-       /* Read : Slave Addr, register, 2, data */
-#define REQ_20_DATA_TRANSFER           20
-#define REQ_30_I2C_WRITE               30
-#define REQ_31_I2C_READ                        31
-#define REQ_35_AFTEK_TUNER_READ                35
-#define REQ_40_GET_VERSION             40
-#define REQ_50_SET_START               50
-#define REQ_51_SET_STOP                        51
-#define REQ_52_TRANSMIT_DATA           52
-#define REQ_53_SPI_INITIAL             53
-#define REQ_54_SPI_SETSTART            54
-#define REQ_55_SPI_INOUTDATA           55
-#define REQ_56_SPI_SETSTOP             56
-
-/*
- * Define TV Master TM5600/TM6000/TM6010 GPIO lines
- */
-
-#define TM6000_GPIO_CLK                0x101
-#define TM6000_GPIO_DATA       0x100
-
-#define TM6000_GPIO_1          0x102
-#define TM6000_GPIO_2          0x103
-#define TM6000_GPIO_3          0x104
-#define TM6000_GPIO_4          0x300
-#define TM6000_GPIO_5          0x301
-#define TM6000_GPIO_6          0x304
-#define TM6000_GPIO_7          0x305
-
-/* tm6010 defines GPIO with different values */
-#define TM6010_GPIO_0      0x0102
-#define TM6010_GPIO_1      0x0103
-#define TM6010_GPIO_2      0x0104
-#define TM6010_GPIO_3      0x0105
-#define TM6010_GPIO_4      0x0106
-#define TM6010_GPIO_5      0x0107
-#define TM6010_GPIO_6      0x0300
-#define TM6010_GPIO_7      0x0301
-#define TM6010_GPIO_9      0x0305
-/*
- * Define TV Master TM5600/TM6000/TM6010 URB message codes and length
- */
-
-enum {
-       TM6000_URB_MSG_VIDEO=1,
-       TM6000_URB_MSG_AUDIO,
-       TM6000_URB_MSG_VBI,
-       TM6000_URB_MSG_PTS,
-       TM6000_URB_MSG_ERR,
-};
-
-/* Define specific TM6000 Video decoder registers */
-#define TM6000_REQ07_RD8_TEST_SEL                      0x07, 0xd8
-#define TM6000_REQ07_RD9_A_SIM_SEL                     0x07, 0xd9
-#define TM6000_REQ07_RDA_CLK_SEL                       0x07, 0xda
-#define TM6000_REQ07_RDB_OUT_SEL                       0x07, 0xdb
-#define TM6000_REQ07_RDC_NSEL_I2S                      0x07, 0xdc
-#define TM6000_REQ07_RDD_GPIO2_MDRV                    0x07, 0xdd
-#define TM6000_REQ07_RDE_GPIO1_MDRV                    0x07, 0xde
-#define TM6000_REQ07_RDF_PWDOWN_ACLK                   0x07, 0xdf
-#define TM6000_REQ07_RE0_VADC_REF_CTL                  0x07, 0xe0
-#define TM6000_REQ07_RE1_VADC_DACLIMP                  0x07, 0xe1
-#define TM6000_REQ07_RE2_VADC_STATUS_CTL               0x07, 0xe2
-#define TM6000_REQ07_RE3_VADC_INP_LPF_SEL1             0x07, 0xe3
-#define TM6000_REQ07_RE4_VADC_TARGET1                  0x07, 0xe4
-#define TM6000_REQ07_RE5_VADC_INP_LPF_SEL2             0x07, 0xe5
-#define TM6000_REQ07_RE6_VADC_TARGET2                  0x07, 0xe6
-#define TM6000_REQ07_RE7_VADC_AGAIN_CTL                        0x07, 0xe7
-#define TM6000_REQ07_RE8_VADC_PWDOWN_CTL               0x07, 0xe8
-#define TM6000_REQ07_RE9_VADC_INPUT_CTL1               0x07, 0xe9
-#define TM6000_REQ07_REA_VADC_INPUT_CTL2               0x07, 0xea
-#define TM6000_REQ07_REB_VADC_AADC_MODE                        0x07, 0xeb
-#define TM6000_REQ07_REC_VADC_AADC_LVOL                        0x07, 0xec
-#define TM6000_REQ07_RED_VADC_AADC_RVOL                        0x07, 0xed
-#define TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL         0x07, 0xee
-#define TM6000_REQ07_REF_VADC_GAIN_MAP_CTL             0x07, 0xef
-#define TM6000_REQ07_RFD_BIST_ERR_VST_LOW              0x07, 0xfd
-#define TM6000_REQ07_RFE_BIST_ERR_VST_HIGH             0x07, 0xfe
-
-/* Define TM6000/TM6010 Video decoder registers */
-#define TM6010_REQ07_R00_VIDEO_CONTROL0                        0x07, 0x00
-#define TM6010_REQ07_R01_VIDEO_CONTROL1                        0x07, 0x01
-#define TM6010_REQ07_R02_VIDEO_CONTROL2                        0x07, 0x02
-#define TM6010_REQ07_R03_YC_SEP_CONTROL                        0x07, 0x03
-#define TM6010_REQ07_R04_LUMA_HAGC_CONTROL             0x07, 0x04
-#define TM6010_REQ07_R05_NOISE_THRESHOLD               0x07, 0x05
-#define TM6010_REQ07_R06_AGC_GATE_THRESHOLD            0x07, 0x06
-#define TM6010_REQ07_R07_OUTPUT_CONTROL                        0x07, 0x07
-#define TM6010_REQ07_R08_LUMA_CONTRAST_ADJ             0x07, 0x08
-#define TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ           0x07, 0x09
-#define TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ         0x07, 0x0a
-#define TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ          0x07, 0x0b
-#define TM6010_REQ07_R0C_CHROMA_AGC_CONTROL            0x07, 0x0c
-#define TM6010_REQ07_R0D_CHROMA_KILL_LEVEL             0x07, 0x0d
-#define TM6010_REQ07_R0F_CHROMA_AUTO_POSITION          0x07, 0x0f
-#define TM6010_REQ07_R10_AGC_PEAK_NOMINAL              0x07, 0x10
-#define TM6010_REQ07_R11_AGC_PEAK_CONTROL              0x07, 0x11
-#define TM6010_REQ07_R12_AGC_GATE_STARTH               0x07, 0x12
-#define TM6010_REQ07_R13_AGC_GATE_STARTL               0x07, 0x13
-#define TM6010_REQ07_R14_AGC_GATE_WIDTH                        0x07, 0x14
-#define TM6010_REQ07_R15_AGC_BP_DELAY                  0x07, 0x15
-#define TM6010_REQ07_R16_LOCK_COUNT                    0x07, 0x16
-#define TM6010_REQ07_R17_HLOOP_MAXSTATE                        0x07, 0x17
-#define TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3         0x07, 0x18
-#define TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2         0x07, 0x19
-#define TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1         0x07, 0x1a
-#define TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0         0x07, 0x1b
-#define TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3          0x07, 0x1c
-#define TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2          0x07, 0x1d
-#define TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1          0x07, 0x1e
-#define TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0          0x07, 0x1f
-#define TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME                0x07, 0x20
-#define TM6010_REQ07_R21_HSYNC_PHASE_OFFSET            0x07, 0x21
-#define TM6010_REQ07_R22_HSYNC_PLL_START_TIME          0x07, 0x22
-#define TM6010_REQ07_R23_HSYNC_PLL_END_TIME            0x07, 0x23
-#define TM6010_REQ07_R24_HSYNC_TIP_START_TIME          0x07, 0x24
-#define TM6010_REQ07_R25_HSYNC_TIP_END_TIME            0x07, 0x25
-#define TM6010_REQ07_R26_HSYNC_RISING_EDGE_START       0x07, 0x26
-#define TM6010_REQ07_R27_HSYNC_RISING_EDGE_END         0x07, 0x27
-#define TM6010_REQ07_R28_BACKPORCH_START               0x07, 0x28
-#define TM6010_REQ07_R29_BACKPORCH_END                 0x07, 0x29
-#define TM6010_REQ07_R2A_HSYNC_FILTER_START            0x07, 0x2a
-#define TM6010_REQ07_R2B_HSYNC_FILTER_END              0x07, 0x2b
-#define TM6010_REQ07_R2C_CHROMA_BURST_START            0x07, 0x2c
-#define TM6010_REQ07_R2D_CHROMA_BURST_END              0x07, 0x2d
-#define TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART           0x07, 0x2e
-#define TM6010_REQ07_R2F_ACTIVE_VIDEO_HWIDTH           0x07, 0x2f
-#define TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART           0x07, 0x30
-#define TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT           0x07, 0x31
-#define TM6010_REQ07_R32_VSYNC_HLOCK_MIN               0x07, 0x32
-#define TM6010_REQ07_R33_VSYNC_HLOCK_MAX               0x07, 0x33
-#define TM6010_REQ07_R34_VSYNC_AGC_MIN                 0x07, 0x34
-#define TM6010_REQ07_R35_VSYNC_AGC_MAX                 0x07, 0x35
-#define TM6010_REQ07_R36_VSYNC_VBI_MIN                 0x07, 0x36
-#define TM6010_REQ07_R37_VSYNC_VBI_MAX                 0x07, 0x37
-#define TM6010_REQ07_R38_VSYNC_THRESHOLD               0x07, 0x38
-#define TM6010_REQ07_R39_VSYNC_TIME_CONSTANT           0x07, 0x39
-#define TM6010_REQ07_R3A_STATUS1                       0x07, 0x3a
-#define TM6010_REQ07_R3B_STATUS2                       0x07, 0x3b
-#define TM6010_REQ07_R3C_STATUS3                       0x07, 0x3c
-#define TM6010_REQ07_R3F_RESET                         0x07, 0x3f
-#define TM6010_REQ07_R40_TELETEXT_VBI_CODE0            0x07, 0x40
-#define TM6010_REQ07_R41_TELETEXT_VBI_CODE1            0x07, 0x41
-#define TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL           0x07, 0x42
-#define TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7           0x07, 0x43
-#define TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8           0x07, 0x44
-#define TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9           0x07, 0x45
-#define TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10          0x07, 0x46
-#define TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11          0x07, 0x47
-#define TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12          0x07, 0x48
-#define TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13          0x07, 0x49
-#define TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14          0x07, 0x4a
-#define TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15          0x07, 0x4b
-#define TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16          0x07, 0x4c
-#define TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17          0x07, 0x4d
-#define TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18          0x07, 0x4e
-#define TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19          0x07, 0x4f
-#define TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20          0x07, 0x50
-#define TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21          0x07, 0x51
-#define TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22          0x07, 0x52
-#define TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23          0x07, 0x53
-#define TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES          0x07, 0x54
-#define TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN          0x07, 0x55
-#define TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN                0x07, 0x56
-#define TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN                0x07, 0x57
-#define TM6010_REQ07_R58_VBI_CAPTION_DTO1              0x07, 0x58
-#define TM6010_REQ07_R59_VBI_CAPTION_DTO0              0x07, 0x59
-#define TM6010_REQ07_R5A_VBI_TELETEXT_DTO1             0x07, 0x5a
-#define TM6010_REQ07_R5B_VBI_TELETEXT_DTO0             0x07, 0x5b
-#define TM6010_REQ07_R5C_VBI_WSS625_DTO1               0x07, 0x5c
-#define TM6010_REQ07_R5D_VBI_WSS625_DTO0               0x07, 0x5d
-#define TM6010_REQ07_R5E_VBI_CAPTION_FRAME_START       0x07, 0x5e
-#define TM6010_REQ07_R5F_VBI_WSS625_FRAME_START                0x07, 0x5f
-#define TM6010_REQ07_R60_TELETEXT_FRAME_START          0x07, 0x60
-#define TM6010_REQ07_R61_VBI_CCDATA1                   0x07, 0x61
-#define TM6010_REQ07_R62_VBI_CCDATA2                   0x07, 0x62
-#define TM6010_REQ07_R63_VBI_WSS625_DATA1              0x07, 0x63
-#define TM6010_REQ07_R64_VBI_WSS625_DATA2              0x07, 0x64
-#define TM6010_REQ07_R65_VBI_DATA_STATUS               0x07, 0x65
-#define TM6010_REQ07_R66_VBI_CAPTION_START             0x07, 0x66
-#define TM6010_REQ07_R67_VBI_WSS625_START              0x07, 0x67
-#define TM6010_REQ07_R68_VBI_TELETEXT_START            0x07, 0x68
-#define TM6010_REQ07_R70_HSYNC_DTO_INC_STATUS3         0x07, 0x70
-#define TM6010_REQ07_R71_HSYNC_DTO_INC_STATUS2         0x07, 0x71
-#define TM6010_REQ07_R72_HSYNC_DTO_INC_STATUS1         0x07, 0x72
-#define TM6010_REQ07_R73_HSYNC_DTO_INC_STATUS0         0x07, 0x73
-#define TM6010_REQ07_R74_CHROMA_DTO_INC_STATUS3                0x07, 0x74
-#define TM6010_REQ07_R75_CHROMA_DTO_INC_STATUS2                0x07, 0x75
-#define TM6010_REQ07_R76_CHROMA_DTO_INC_STATUS1                0x07, 0x76
-#define TM6010_REQ07_R77_CHROMA_DTO_INC_STATUS0                0x07, 0x77
-#define TM6010_REQ07_R78_AGC_AGAIN_STATUS              0x07, 0x78
-#define TM6010_REQ07_R79_AGC_DGAIN_STATUS              0x07, 0x79
-#define TM6010_REQ07_R7A_CHROMA_MAG_STATUS             0x07, 0x7a
-#define TM6010_REQ07_R7B_CHROMA_GAIN_STATUS1           0x07, 0x7b
-#define TM6010_REQ07_R7C_CHROMA_GAIN_STATUS0           0x07, 0x7c
-#define TM6010_REQ07_R7D_CORDIC_FREQ_STATUS            0x07, 0x7d
-#define TM6010_REQ07_R7F_STATUS_NOISE                  0x07, 0x7f
-#define TM6010_REQ07_R80_COMB_FILTER_TRESHOLD          0x07, 0x80
-#define TM6010_REQ07_R82_COMB_FILTER_CONFIG            0x07, 0x82
-#define TM6010_REQ07_R83_CHROMA_LOCK_CONFIG            0x07, 0x83
-#define TM6010_REQ07_R84_NOISE_NTSC_C                  0x07, 0x84
-#define TM6010_REQ07_R85_NOISE_PAL_C                   0x07, 0x85
-#define TM6010_REQ07_R86_NOISE_PHASE_C                 0x07, 0x86
-#define TM6010_REQ07_R87_NOISE_PHASE_Y                 0x07, 0x87
-#define TM6010_REQ07_R8A_CHROMA_LOOPFILTER_STATE       0x07, 0x8a
-#define TM6010_REQ07_R8B_CHROMA_HRESAMPLER             0x07, 0x8b
-#define TM6010_REQ07_R8D_CPUMP_DELAY_ADJ               0x07, 0x8d
-#define TM6010_REQ07_R8E_CPUMP_ADJ                     0x07, 0x8e
-#define TM6010_REQ07_R8F_CPUMP_DELAY                   0x07, 0x8f
-
-/* Define TM6000/TM6010 Miscellaneous registers */
-#define TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE           0x07, 0xc0
-#define TM6010_REQ07_RC1_TRESHOLD                      0x07, 0xc1
-#define TM6010_REQ07_RC2_HSYNC_WIDTH                   0x07, 0xc2
-#define TM6010_REQ07_RC3_HSTART1                       0x07, 0xc3
-#define TM6010_REQ07_RC4_HSTART0                       0x07, 0xc4
-#define TM6010_REQ07_RC5_HEND1                         0x07, 0xc5
-#define TM6010_REQ07_RC6_HEND0                         0x07, 0xc6
-#define TM6010_REQ07_RC7_VSTART1                       0x07, 0xc7
-#define TM6010_REQ07_RC8_VSTART0                       0x07, 0xc8
-#define TM6010_REQ07_RC9_VEND1                         0x07, 0xc9
-#define TM6010_REQ07_RCA_VEND0                         0x07, 0xca
-#define TM6010_REQ07_RCB_DELAY                         0x07, 0xcb
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RCC_ACTIVE_VIDEO_IF               0x07, 0xcc
-#define TM6010_REQ07_RD0_USB_PERIPHERY_CONTROL         0x07, 0xd0
-#define TM6010_REQ07_RD1_ADDR_FOR_REQ1                 0x07, 0xd1
-#define TM6010_REQ07_RD2_ADDR_FOR_REQ2                 0x07, 0xd2
-#define TM6010_REQ07_RD3_ADDR_FOR_REQ3                 0x07, 0xd3
-#define TM6010_REQ07_RD4_ADDR_FOR_REQ4                 0x07, 0xd4
-#define TM6010_REQ07_RD5_POWERSAVE                     0x07, 0xd5
-#define TM6010_REQ07_RD6_ENDP_REQ1_REQ2                        0x07, 0xd6
-#define TM6010_REQ07_RD7_ENDP_REQ3_REQ4                        0x07, 0xd7
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR                            0x07, 0xd8
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_BSIZE                      0x07, 0xd9
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_WAKEUP_SEL                 0x07, 0xda
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_WAKEUP_ADD                 0x07, 0xdb
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_LEADER1                    0x07, 0xdc
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_LEADER0                    0x07, 0xdd
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_PULSE_CNT1                 0x07, 0xde
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_PULSE_CNT0                 0x07, 0xdf
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE0_DVIDEO_SOURCE                 0x07, 0xe0
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE0_DVIDEO_SOURCE_IF              0x07, 0xe1
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE2_OUT_SEL2                      0x07, 0xe2
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE3_OUT_SEL1                      0x07, 0xe3
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE4_OUT_SEL0                      0x07, 0xe4
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE5_REMOTE_WAKEUP                 0x07, 0xe5
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE7_PUB_GPIO                      0x07, 0xe7
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE8_TYPESEL_MOS_I2S               0x07, 0xe8
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE9_TYPESEL_MOS_TS                        0x07, 0xe9
-/* ONLY for TM6010 */
-#define TM6010_REQ07_REA_TYPESEL_MOS_CCIR              0x07, 0xea
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF0_BIST_CRC_RESULT0              0x07, 0xf0
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF1_BIST_CRC_RESULT1              0x07, 0xf1
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF2_BIST_CRC_RESULT2              0x07, 0xf2
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF3_BIST_CRC_RESULT3              0x07, 0xf3
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF4_BIST_ERR_VST2                 0x07, 0xf4
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF5_BIST_ERR_VST1                 0x07, 0xf5
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF6_BIST_ERR_VST0                 0x07, 0xf6
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF7_BIST                          0x07, 0xf7
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RFE_POWER_DOWN                    0x07, 0xfe
-#define TM6010_REQ07_RFF_SOFT_RESET                    0x07, 0xff
-
-/* Define TM6000/TM6010 USB registers */
-#define TM6010_REQ05_R00_MAIN_CTRL             0x05, 0x00
-#define TM6010_REQ05_R01_DEVADDR               0x05, 0x01
-#define TM6010_REQ05_R02_TEST                  0x05, 0x02
-#define TM6010_REQ05_R04_SOFN0                 0x05, 0x04
-#define TM6010_REQ05_R05_SOFN1                 0x05, 0x05
-#define TM6010_REQ05_R06_SOFTM0                        0x05, 0x06
-#define TM6010_REQ05_R07_SOFTM1                        0x05, 0x07
-#define TM6010_REQ05_R08_PHY_TEST              0x05, 0x08
-#define TM6010_REQ05_R09_VCTL                  0x05, 0x09
-#define TM6010_REQ05_R0A_VSTA                  0x05, 0x0a
-#define TM6010_REQ05_R0B_CX_CFG                        0x05, 0x0b
-#define TM6010_REQ05_R0C_ENDP0_REG0            0x05, 0x0c
-#define TM6010_REQ05_R10_GMASK                 0x05, 0x10
-#define TM6010_REQ05_R11_IMASK0                        0x05, 0x11
-#define TM6010_REQ05_R12_IMASK1                        0x05, 0x12
-#define TM6010_REQ05_R13_IMASK2                        0x05, 0x13
-#define TM6010_REQ05_R14_IMASK3                        0x05, 0x14
-#define TM6010_REQ05_R15_IMASK4                        0x05, 0x15
-#define TM6010_REQ05_R16_IMASK5                        0x05, 0x16
-#define TM6010_REQ05_R17_IMASK6                        0x05, 0x17
-#define TM6010_REQ05_R18_IMASK7                        0x05, 0x18
-#define TM6010_REQ05_R19_ZEROP0                        0x05, 0x19
-#define TM6010_REQ05_R1A_ZEROP1                        0x05, 0x1a
-#define TM6010_REQ05_R1C_FIFO_EMP0             0x05, 0x1c
-#define TM6010_REQ05_R1D_FIFO_EMP1             0x05, 0x1d
-#define TM6010_REQ05_R20_IRQ_GROUP             0x05, 0x20
-#define TM6010_REQ05_R21_IRQ_SOURCE0           0x05, 0x21
-#define TM6010_REQ05_R22_IRQ_SOURCE1           0x05, 0x22
-#define TM6010_REQ05_R23_IRQ_SOURCE2           0x05, 0x23
-#define TM6010_REQ05_R24_IRQ_SOURCE3           0x05, 0x24
-#define TM6010_REQ05_R25_IRQ_SOURCE4           0x05, 0x25
-#define TM6010_REQ05_R26_IRQ_SOURCE5           0x05, 0x26
-#define TM6010_REQ05_R27_IRQ_SOURCE6           0x05, 0x27
-#define TM6010_REQ05_R28_IRQ_SOURCE7           0x05, 0x28
-#define TM6010_REQ05_R29_SEQ_ERR0              0x05, 0x29
-#define TM6010_REQ05_R2A_SEQ_ERR1              0x05, 0x2a
-#define TM6010_REQ05_R2B_SEQ_ABORT0            0x05, 0x2b
-#define TM6010_REQ05_R2C_SEQ_ABORT1            0x05, 0x2c
-#define TM6010_REQ05_R2D_TX_ZERO0              0x05, 0x2d
-#define TM6010_REQ05_R2E_TX_ZERO1              0x05, 0x2e
-#define TM6010_REQ05_R2F_IDLE_CNT              0x05, 0x2f
-#define TM6010_REQ05_R30_FNO_P1                        0x05, 0x30
-#define TM6010_REQ05_R31_FNO_P2                        0x05, 0x31
-#define TM6010_REQ05_R32_FNO_P3                        0x05, 0x32
-#define TM6010_REQ05_R33_FNO_P4                        0x05, 0x33
-#define TM6010_REQ05_R34_FNO_P5                        0x05, 0x34
-#define TM6010_REQ05_R35_FNO_P6                        0x05, 0x35
-#define TM6010_REQ05_R36_FNO_P7                        0x05, 0x36
-#define TM6010_REQ05_R37_FNO_P8                        0x05, 0x37
-#define TM6010_REQ05_R38_FNO_P9                        0x05, 0x38
-#define TM6010_REQ05_R30_FNO_P10               0x05, 0x39
-#define TM6010_REQ05_R30_FNO_P11               0x05, 0x3a
-#define TM6010_REQ05_R30_FNO_P12               0x05, 0x3b
-#define TM6010_REQ05_R30_FNO_P13               0x05, 0x3c
-#define TM6010_REQ05_R30_FNO_P14               0x05, 0x3d
-#define TM6010_REQ05_R30_FNO_P15               0x05, 0x3e
-#define TM6010_REQ05_R40_IN_MAXPS_LOW1         0x05, 0x40
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH1                0x05, 0x41
-#define TM6010_REQ05_R42_IN_MAXPS_LOW2         0x05, 0x42
-#define TM6010_REQ05_R43_IN_MAXPS_HIGH2                0x05, 0x43
-#define TM6010_REQ05_R44_IN_MAXPS_LOW3         0x05, 0x44
-#define TM6010_REQ05_R45_IN_MAXPS_HIGH3                0x05, 0x45
-#define TM6010_REQ05_R46_IN_MAXPS_LOW4         0x05, 0x46
-#define TM6010_REQ05_R47_IN_MAXPS_HIGH4                0x05, 0x47
-#define TM6010_REQ05_R48_IN_MAXPS_LOW5         0x05, 0x48
-#define TM6010_REQ05_R49_IN_MAXPS_HIGH5                0x05, 0x49
-#define TM6010_REQ05_R4A_IN_MAXPS_LOW6         0x05, 0x4a
-#define TM6010_REQ05_R4B_IN_MAXPS_HIGH6                0x05, 0x4b
-#define TM6010_REQ05_R4C_IN_MAXPS_LOW7         0x05, 0x4c
-#define TM6010_REQ05_R4D_IN_MAXPS_HIGH7                0x05, 0x4d
-#define TM6010_REQ05_R4E_IN_MAXPS_LOW8         0x05, 0x4e
-#define TM6010_REQ05_R4F_IN_MAXPS_HIGH8                0x05, 0x4f
-#define TM6010_REQ05_R50_IN_MAXPS_LOW9         0x05, 0x50
-#define TM6010_REQ05_R51_IN_MAXPS_HIGH9                0x05, 0x51
-#define TM6010_REQ05_R40_IN_MAXPS_LOW10                0x05, 0x52
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH10       0x05, 0x53
-#define TM6010_REQ05_R40_IN_MAXPS_LOW11                0x05, 0x54
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH11       0x05, 0x55
-#define TM6010_REQ05_R40_IN_MAXPS_LOW12                0x05, 0x56
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH12       0x05, 0x57
-#define TM6010_REQ05_R40_IN_MAXPS_LOW13                0x05, 0x58
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH13       0x05, 0x59
-#define TM6010_REQ05_R40_IN_MAXPS_LOW14                0x05, 0x5a
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH14       0x05, 0x5b
-#define TM6010_REQ05_R40_IN_MAXPS_LOW15                0x05, 0x5c
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH15       0x05, 0x5d
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW1                0x05, 0x60
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH1       0x05, 0x61
-#define TM6010_REQ05_R62_OUT_MAXPS_LOW2                0x05, 0x62
-#define TM6010_REQ05_R63_OUT_MAXPS_HIGH2       0x05, 0x63
-#define TM6010_REQ05_R64_OUT_MAXPS_LOW3                0x05, 0x64
-#define TM6010_REQ05_R65_OUT_MAXPS_HIGH3       0x05, 0x65
-#define TM6010_REQ05_R66_OUT_MAXPS_LOW4                0x05, 0x66
-#define TM6010_REQ05_R67_OUT_MAXPS_HIGH4       0x05, 0x67
-#define TM6010_REQ05_R68_OUT_MAXPS_LOW5                0x05, 0x68
-#define TM6010_REQ05_R69_OUT_MAXPS_HIGH5       0x05, 0x69
-#define TM6010_REQ05_R6A_OUT_MAXPS_LOW6                0x05, 0x6a
-#define TM6010_REQ05_R6B_OUT_MAXPS_HIGH6       0x05, 0x6b
-#define TM6010_REQ05_R6C_OUT_MAXPS_LOW7                0x05, 0x6c
-#define TM6010_REQ05_R6D_OUT_MAXPS_HIGH7       0x05, 0x6d
-#define TM6010_REQ05_R6E_OUT_MAXPS_LOW8                0x05, 0x6e
-#define TM6010_REQ05_R6F_OUT_MAXPS_HIGH8       0x05, 0x6f
-#define TM6010_REQ05_R70_OUT_MAXPS_LOW9                0x05, 0x70
-#define TM6010_REQ05_R71_OUT_MAXPS_HIGH9       0x05, 0x71
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW10       0x05, 0x72
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH10      0x05, 0x73
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW11       0x05, 0x74
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH11      0x05, 0x75
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW12       0x05, 0x76
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH12      0x05, 0x77
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW13       0x05, 0x78
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH13      0x05, 0x79
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW14       0x05, 0x7a
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH14      0x05, 0x7b
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW15       0x05, 0x7c
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH15      0x05, 0x7d
-#define TM6010_REQ05_R80_FIFO0                 0x05, 0x80
-#define TM6010_REQ05_R81_FIFO1                 0x05, 0x81
-#define TM6010_REQ05_R82_FIFO2                 0x05, 0x82
-#define TM6010_REQ05_R83_FIFO3                 0x05, 0x83
-#define TM6010_REQ05_R84_FIFO4                 0x05, 0x84
-#define TM6010_REQ05_R85_FIFO5                 0x05, 0x85
-#define TM6010_REQ05_R86_FIFO6                 0x05, 0x86
-#define TM6010_REQ05_R87_FIFO7                 0x05, 0x87
-#define TM6010_REQ05_R88_FIFO8                 0x05, 0x88
-#define TM6010_REQ05_R89_FIFO9                 0x05, 0x89
-#define TM6010_REQ05_R81_FIFO10                        0x05, 0x8a
-#define TM6010_REQ05_R81_FIFO11                        0x05, 0x8b
-#define TM6010_REQ05_R81_FIFO12                        0x05, 0x8c
-#define TM6010_REQ05_R81_FIFO13                        0x05, 0x8d
-#define TM6010_REQ05_R81_FIFO14                        0x05, 0x8e
-#define TM6010_REQ05_R81_FIFO15                        0x05, 0x8f
-#define TM6010_REQ05_R90_CFG_FIFO0             0x05, 0x90
-#define TM6010_REQ05_R91_CFG_FIFO1             0x05, 0x91
-#define TM6010_REQ05_R92_CFG_FIFO2             0x05, 0x92
-#define TM6010_REQ05_R93_CFG_FIFO3             0x05, 0x93
-#define TM6010_REQ05_R94_CFG_FIFO4             0x05, 0x94
-#define TM6010_REQ05_R95_CFG_FIFO5             0x05, 0x95
-#define TM6010_REQ05_R96_CFG_FIFO6             0x05, 0x96
-#define TM6010_REQ05_R97_CFG_FIFO7             0x05, 0x97
-#define TM6010_REQ05_R98_CFG_FIFO8             0x05, 0x98
-#define TM6010_REQ05_R99_CFG_FIFO9             0x05, 0x99
-#define TM6010_REQ05_R91_CFG_FIFO10            0x05, 0x9a
-#define TM6010_REQ05_R91_CFG_FIFO11            0x05, 0x9b
-#define TM6010_REQ05_R91_CFG_FIFO12            0x05, 0x9c
-#define TM6010_REQ05_R91_CFG_FIFO13            0x05, 0x9d
-#define TM6010_REQ05_R91_CFG_FIFO14            0x05, 0x9e
-#define TM6010_REQ05_R91_CFG_FIFO15            0x05, 0x9f
-#define TM6010_REQ05_RA0_CTL_FIFO0             0x05, 0xa0
-#define TM6010_REQ05_RA1_CTL_FIFO1             0x05, 0xa1
-#define TM6010_REQ05_RA2_CTL_FIFO2             0x05, 0xa2
-#define TM6010_REQ05_RA3_CTL_FIFO3             0x05, 0xa3
-#define TM6010_REQ05_RA4_CTL_FIFO4             0x05, 0xa4
-#define TM6010_REQ05_RA5_CTL_FIFO5             0x05, 0xa5
-#define TM6010_REQ05_RA6_CTL_FIFO6             0x05, 0xa6
-#define TM6010_REQ05_RA7_CTL_FIFO7             0x05, 0xa7
-#define TM6010_REQ05_RA8_CTL_FIFO8             0x05, 0xa8
-#define TM6010_REQ05_RA9_CTL_FIFO9             0x05, 0xa9
-#define TM6010_REQ05_RA1_CTL_FIFO10            0x05, 0xaa
-#define TM6010_REQ05_RA1_CTL_FIFO11            0x05, 0xab
-#define TM6010_REQ05_RA1_CTL_FIFO12            0x05, 0xac
-#define TM6010_REQ05_RA1_CTL_FIFO13            0x05, 0xad
-#define TM6010_REQ05_RA1_CTL_FIFO14            0x05, 0xae
-#define TM6010_REQ05_RA1_CTL_FIFO15            0x05, 0xaf
-#define TM6010_REQ05_RB0_BC_LOW_FIFO0          0x05, 0xb0
-#define TM6010_REQ05_RB1_BC_LOW_FIFO1          0x05, 0xb1
-#define TM6010_REQ05_RB2_BC_LOW_FIFO2          0x05, 0xb2
-#define TM6010_REQ05_RB3_BC_LOW_FIFO3          0x05, 0xb3
-#define TM6010_REQ05_RB4_BC_LOW_FIFO4          0x05, 0xb4
-#define TM6010_REQ05_RB5_BC_LOW_FIFO5          0x05, 0xb5
-#define TM6010_REQ05_RB6_BC_LOW_FIFO6          0x05, 0xb6
-#define TM6010_REQ05_RB7_BC_LOW_FIFO7          0x05, 0xb7
-#define TM6010_REQ05_RB8_BC_LOW_FIFO8          0x05, 0xb8
-#define TM6010_REQ05_RB9_BC_LOW_FIFO9          0x05, 0xb9
-#define TM6010_REQ05_RB1_BC_LOW_FIFO10         0x05, 0xba
-#define TM6010_REQ05_RB1_BC_LOW_FIFO11         0x05, 0xbb
-#define TM6010_REQ05_RB1_BC_LOW_FIFO12         0x05, 0xbc
-#define TM6010_REQ05_RB1_BC_LOW_FIFO13         0x05, 0xbd
-#define TM6010_REQ05_RB1_BC_LOW_FIFO14         0x05, 0xbe
-#define TM6010_REQ05_RB1_BC_LOW_FIFO15         0x05, 0xbf
-#define TM6010_REQ05_RC0_DATA_FIFO0            0x05, 0xc0
-#define TM6010_REQ05_RC4_DATA_FIFO1            0x05, 0xc4
-#define TM6010_REQ05_RC8_DATA_FIFO2            0x05, 0xc8
-#define TM6010_REQ05_RCC_DATA_FIFO3            0x05, 0xcc
-#define TM6010_REQ05_RD0_DATA_FIFO4            0x05, 0xd0
-#define TM6010_REQ05_RD4_DATA_FIFO5            0x05, 0xd4
-#define TM6010_REQ05_RD8_DATA_FIFO6            0x05, 0xd8
-#define TM6010_REQ05_RDC_DATA_FIFO7            0x05, 0xdc
-#define TM6010_REQ05_RE0_DATA_FIFO8            0x05, 0xe0
-#define TM6010_REQ05_RE4_DATA_FIFO9            0x05, 0xe4
-#define TM6010_REQ05_RC4_DATA_FIFO10           0x05, 0xe8
-#define TM6010_REQ05_RC4_DATA_FIFO11           0x05, 0xec
-#define TM6010_REQ05_RC4_DATA_FIFO12           0x05, 0xf0
-#define TM6010_REQ05_RC4_DATA_FIFO13           0x05, 0xf4
-#define TM6010_REQ05_RC4_DATA_FIFO14           0x05, 0xf8
-#define TM6010_REQ05_RC4_DATA_FIFO15           0x05, 0xfc
-
-/* Define TM6010 Audio decoder registers */
-/* This core available only in TM6010 */
-#define TM6010_REQ08_R00_A_VERSION             0x08, 0x00
-#define TM6010_REQ08_R01_A_INIT                        0x08, 0x01
-#define TM6010_REQ08_R02_A_FIX_GAIN_CTRL       0x08, 0x02
-#define TM6010_REQ08_R03_A_AUTO_GAIN_CTRL      0x08, 0x03
-#define TM6010_REQ08_R04_A_SIF_AMP_CTRL                0x08, 0x04
-#define TM6010_REQ08_R05_A_STANDARD_MOD                0x08, 0x05
-#define TM6010_REQ08_R06_A_SOUND_MOD           0x08, 0x06
-#define TM6010_REQ08_R07_A_LEFT_VOL            0x08, 0x07
-#define TM6010_REQ08_R08_A_RIGHT_VOL           0x08, 0x08
-#define TM6010_REQ08_R09_A_MAIN_VOL            0x08, 0x09
-#define TM6010_REQ08_R0A_A_I2S_MOD             0x08, 0x0a
-#define TM6010_REQ08_R0B_A_ASD_THRES1          0x08, 0x0b
-#define TM6010_REQ08_R0C_A_ASD_THRES2          0x08, 0x0c
-#define TM6010_REQ08_R0D_A_AMD_THRES           0x08, 0x0d
-#define TM6010_REQ08_R0E_A_MONO_THRES1         0x08, 0x0e
-#define TM6010_REQ08_R0F_A_MONO_THRES2         0x08, 0x0f
-#define TM6010_REQ08_R10_A_MUTE_THRES1         0x08, 0x10
-#define TM6010_REQ08_R11_A_MUTE_THRES2         0x08, 0x11
-#define TM6010_REQ08_R12_A_AGC_U               0x08, 0x12
-#define TM6010_REQ08_R13_A_AGC_ERR_T           0x08, 0x13
-#define TM6010_REQ08_R14_A_AGC_GAIN_INIT       0x08, 0x14
-#define TM6010_REQ08_R15_A_AGC_STEP_THR                0x08, 0x15
-#define TM6010_REQ08_R16_A_AGC_GAIN_MAX                0x08, 0x16
-#define TM6010_REQ08_R17_A_AGC_GAIN_MIN                0x08, 0x17
-#define TM6010_REQ08_R18_A_TR_CTRL             0x08, 0x18
-#define TM6010_REQ08_R19_A_FH_2FH_GAIN         0x08, 0x19
-#define TM6010_REQ08_R1A_A_NICAM_SER_MAX       0x08, 0x1a
-#define TM6010_REQ08_R1B_A_NICAM_SER_MIN       0x08, 0x1b
-#define TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT     0x08, 0x1e
-#define TM6010_REQ08_R1F_A_TEST_INTF_SEL       0x08, 0x1f
-#define TM6010_REQ08_R20_A_TEST_PIN_SEL                0x08, 0x20
-#define TM6010_REQ08_R21_A_AGC_ERR             0x08, 0x21
-#define TM6010_REQ08_R22_A_AGC_GAIN            0x08, 0x22
-#define TM6010_REQ08_R23_A_NICAM_INFO          0x08, 0x23
-#define TM6010_REQ08_R24_A_SER                 0x08, 0x24
-#define TM6010_REQ08_R25_A_C1_AMP              0x08, 0x25
-#define TM6010_REQ08_R26_A_C2_AMP              0x08, 0x26
-#define TM6010_REQ08_R27_A_NOISE_AMP           0x08, 0x27
-#define TM6010_REQ08_R28_A_AUDIO_MODE_RES      0x08, 0x28
-
-/* Define TM6010 Video ADC registers */
-#define TM6010_REQ08_RE0_ADC_REF               0x08, 0xe0
-#define TM6010_REQ08_RE1_DAC_CLMP              0x08, 0xe1
-#define TM6010_REQ08_RE2_POWER_DOWN_CTRL1      0x08, 0xe2
-#define TM6010_REQ08_RE3_ADC_IN1_SEL           0x08, 0xe3
-#define TM6010_REQ08_RE4_ADC_IN2_SEL           0x08, 0xe4
-#define TM6010_REQ08_RE5_GAIN_PARAM            0x08, 0xe5
-#define TM6010_REQ08_RE6_POWER_DOWN_CTRL2      0x08, 0xe6
-#define TM6010_REQ08_RE7_REG_GAIN_Y            0x08, 0xe7
-#define TM6010_REQ08_RE8_REG_GAIN_C            0x08, 0xe8
-#define TM6010_REQ08_RE9_BIAS_CTRL             0x08, 0xe9
-#define TM6010_REQ08_REA_BUFF_DRV_CTRL         0x08, 0xea
-#define TM6010_REQ08_REB_SIF_GAIN_CTRL         0x08, 0xeb
-#define TM6010_REQ08_REC_REVERSE_YC_CTRL       0x08, 0xec
-#define TM6010_REQ08_RED_GAIN_SEL              0x08, 0xed
-
-/* Define TM6010 Audio ADC registers */
-#define TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG   0x08, 0xf0
-#define TM6010_REQ08_RF1_AADC_POWER_DOWN       0x08, 0xf1
-#define TM6010_REQ08_RF2_LEFT_CHANNEL_VOL      0x08, 0xf2
-#define TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL     0x08, 0xf3
diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c
deleted file mode 100644 (file)
index 8b29d73..0000000
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- *  tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- *  Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation version 2
- *
- *  This program is distributed 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/module.h>
-#include <linux/kernel.h>
-#include "tm6000.h"
-#include "tm6000-regs.h"
-
-static unsigned int tm6010_a_mode = 0;
-module_param(tm6010_a_mode, int, 0644);
-MODULE_PARM_DESC(tm6010_a_mode, "set tm6010 sif audio mode");
-
-struct tm6000_reg_settings {
-       unsigned char req;
-       unsigned char reg;
-       unsigned char value;
-};
-
-
-struct tm6000_std_settings {
-       v4l2_std_id id;
-       struct tm6000_reg_settings common[27];
-};
-
-static struct tm6000_std_settings composite_stds[] = {
-       {
-               .id = V4L2_STD_PAL_M,
-               .common = {
-                       {TM6010_REQ07_R3F_RESET, 0x01},
-                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04},
-                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
-                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
-                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
-                       {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
-                       {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
-                       {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
-                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0},
-                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
-                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
-                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
-                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
-                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88},
-                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20},
-                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61},
-                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
-                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
-                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
-                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
-
-                       {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
-                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
-                       {TM6010_REQ07_R3F_RESET, 0x00},
-                       {0, 0, 0},
-               },
-        }, {
-               .id = V4L2_STD_PAL_Nc,
-               .common = {
-                       {TM6010_REQ07_R3F_RESET, 0x01},
-                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36},
-                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
-                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
-                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
-                       {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
-                       {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
-                       {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
-                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c},
-                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
-                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
-                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
-                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
-                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
-                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
-                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
-                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
-                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
-                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
-                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
-
-                       {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
-                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
-                       {TM6010_REQ07_R3F_RESET, 0x00},
-                       {0, 0, 0},
-               },
-       }, {
-               .id = V4L2_STD_PAL,
-               .common = {
-                       {TM6010_REQ07_R3F_RESET, 0x01},
-                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32},
-                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
-                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
-                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
-                       {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
-                       {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
-                       {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
-                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50},
-                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
-                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
-                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
-                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
-                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
-                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
-                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
-                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
-                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
-                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
-                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
-
-                       {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
-                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
-                       {TM6010_REQ07_R3F_RESET, 0x00},
-                       {0, 0, 0},
-               },
-        }, {
-               .id = V4L2_STD_SECAM,
-               .common = {
-                       {TM6010_REQ07_R3F_RESET, 0x01},
-                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38},
-                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
-                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
-                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
-                       {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
-                       {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
-                       {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
-                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed},
-                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
-                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
-                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
-                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
-                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
-                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
-                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
-                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c},
-                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18},
-                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
-                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
-
-                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
-                       {TM6010_REQ07_R3F_RESET, 0x00},
-                       {0, 0, 0},
-               },
-       }, {
-               .id = V4L2_STD_NTSC,
-               .common = {
-                       {TM6010_REQ07_R3F_RESET, 0x01},
-                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00},
-                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
-                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
-                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
-                       {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
-                       {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
-                       {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2},
-                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9},
-                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
-                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
-                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
-                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
-                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88},
-                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22},
-                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61},
-                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c},
-                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
-                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
-                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
-
-                       {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd},
-                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
-                       {TM6010_REQ07_R3F_RESET, 0x00},
-                       {0, 0, 0},
-               },
-       },
-};
-
-static struct tm6000_std_settings svideo_stds[] = {
-       {
-               .id = V4L2_STD_PAL_M,
-               .common = {
-                       {TM6010_REQ07_R3F_RESET, 0x01},
-                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x05},
-                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
-                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
-                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
-                       {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
-                       {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
-                       {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
-                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0},
-                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
-                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
-                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
-                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
-                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88},
-                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22},
-                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61},
-                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
-                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
-                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
-                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
-
-                       {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
-                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
-                       {TM6010_REQ07_R3F_RESET, 0x00},
-                       {0, 0, 0},
-               },
-       }, {
-               .id = V4L2_STD_PAL_Nc,
-               .common = {
-                       {TM6010_REQ07_R3F_RESET, 0x01},
-                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x37},
-                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
-                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
-                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
-                       {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
-                       {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
-                       {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
-                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c},
-                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
-                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
-                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
-                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
-                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88},
-                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22},
-                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
-                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
-                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
-                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
-                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
-
-                       {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
-                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
-                       {TM6010_REQ07_R3F_RESET, 0x00},
-                       {0, 0, 0},
-               },
-       }, {
-               .id = V4L2_STD_PAL,
-               .common = {
-                       {TM6010_REQ07_R3F_RESET, 0x01},
-                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x33},
-                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
-                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
-                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30},
-                       {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
-                       {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
-                       {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
-                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50},
-                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
-                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
-                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
-                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
-                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
-                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a},
-                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
-                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c},
-                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
-                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52},
-                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
-
-                       {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
-                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
-                       {TM6010_REQ07_R3F_RESET, 0x00},
-                       {0, 0, 0},
-               },
-        }, {
-               .id = V4L2_STD_SECAM,
-               .common = {
-                       {TM6010_REQ07_R3F_RESET, 0x01},
-                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39},
-                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
-                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
-                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
-                       {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
-                       {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
-                       {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
-                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed},
-                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
-                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
-                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
-                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
-                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
-                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a},
-                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
-                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c},
-                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18},
-                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
-                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
-
-                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
-                       {TM6010_REQ07_R3F_RESET, 0x00},
-                       {0, 0, 0},
-               },
-       }, {
-               .id = V4L2_STD_NTSC,
-               .common = {
-                       {TM6010_REQ07_R3F_RESET, 0x01},
-                       {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x01},
-                       {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
-                       {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
-                       {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30},
-                       {TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b},
-                       {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
-                       {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
-                       {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2},
-                       {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9},
-                       {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
-                       {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
-                       {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
-                       {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
-                       {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88},
-                       {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22},
-                       {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61},
-                       {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c},
-                       {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c},
-                       {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
-                       {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F},
-
-                       {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd},
-                       {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
-                       {TM6010_REQ07_R3F_RESET, 0x00},
-                       {0, 0, 0},
-               },
-       },
-};
-
-
-static int tm6000_set_audio_std(struct tm6000_core *dev)
-{
-       uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */
-       uint8_t areg_05 = 0x01; /* Auto 4.5 = M Japan, Auto 6.5 = DK */
-       uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */
-       uint8_t nicam_flag = 0; /* No NICAM */
-
-       if (dev->radio) {
-               tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
-               tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80);
-               tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c);
-               /* set mono or stereo */
-               if (dev->amode == V4L2_TUNER_MODE_MONO)
-                       tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
-               else if (dev->amode == V4L2_TUNER_MODE_STEREO)
-                       tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x02);
-               tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18);
-               tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a);
-               tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x40);
-               tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe);
-               tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
-               tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
-               return 0;
-       }
-
-       switch (tm6010_a_mode) {
-       /* auto */
-       case 0:
-               switch (dev->norm) {
-               case V4L2_STD_NTSC_M_KR:
-                       areg_05 |= 0x00;
-                       break;
-               case V4L2_STD_NTSC_M_JP:
-                       areg_05 |= 0x40;
-                       break;
-               case V4L2_STD_NTSC_M:
-               case V4L2_STD_PAL_M:
-               case V4L2_STD_PAL_N:
-                       areg_05 |= 0x20;
-                       break;
-               case V4L2_STD_PAL_Nc:
-                       areg_05 |= 0x60;
-                       break;
-               case V4L2_STD_SECAM_L:
-                       areg_05 |= 0x00;
-                       break;
-               case V4L2_STD_DK:
-                       areg_05 |= 0x10;
-                       break;
-               }
-               break;
-       /* A2 */
-       case 1:
-               switch (dev->norm) {
-               case V4L2_STD_B:
-               case V4L2_STD_GH:
-                       areg_05 = 0x05;
-                       break;
-               case V4L2_STD_DK:
-                       areg_05 = 0x09;
-                       break;
-               }
-               break;
-       /* NICAM */
-       case 2:
-               switch (dev->norm) {
-               case V4L2_STD_B:
-               case V4L2_STD_GH:
-                       areg_05 = 0x07;
-                       break;
-               case V4L2_STD_DK:
-                       areg_05 = 0x06;
-                       break;
-               case V4L2_STD_PAL_I:
-                       areg_05 = 0x08;
-                       break;
-               case V4L2_STD_SECAM_L:
-                       areg_05 = 0x0a;
-                       areg_02 = 0x02;
-                       break;
-               }
-               nicam_flag = 1;
-               break;
-       /* other */
-       case 3:
-               switch (dev->norm) {
-               /* DK3_A2 */
-               case V4L2_STD_DK:
-                       areg_05 = 0x0b;
-                       break;
-               /* Korea */
-               case V4L2_STD_NTSC_M_KR:
-                       areg_05 = 0x04;
-                       break;
-               /* EIAJ */
-               case V4L2_STD_NTSC_M_JP:
-                       areg_05 = 0x03;
-                       break;
-               default:
-                       areg_05 = 0x02;
-                       break;
-               }
-               break;
-       }
-
-       tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
-       tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, areg_02);
-       tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
-       tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0);
-       tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, areg_05);
-       tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, areg_06);
-       tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00);
-       tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00);
-       tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08);
-       tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
-       tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20);
-       tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12);
-       tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20);
-       tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0);
-       tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80);
-       tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0);
-       tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80);
-       tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12);
-       tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe);
-       tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20);
-       tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14);
-       tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
-       tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
-       tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0);
-       tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32);
-       tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64);
-       tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20);
-       tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00);
-       tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00);
-       tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
-       tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00);
-       tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00);
-       tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
-
-       return 0;
-}
-
-void tm6000_get_std_res(struct tm6000_core *dev)
-{
-       /* Currently, those are the only supported resoltions */
-       if (dev->norm & V4L2_STD_525_60)
-               dev->height = 480;
-       else
-               dev->height = 576;
-
-       dev->width = 720;
-}
-
-static int tm6000_load_std(struct tm6000_core *dev,
-                          struct tm6000_reg_settings *set, int max_size)
-{
-       int i, rc;
-
-       /* Load board's initialization table */
-       for (i = 0; max_size; i++) {
-               if (!set[i].req)
-                       return 0;
-
-               rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value);
-               if (rc < 0) {
-                       printk(KERN_ERR "Error %i while setting "
-                              "req %d, reg %d to value %d\n",
-                              rc, set[i].req, set[i].reg, set[i].value);
-                       return rc;
-               }
-       }
-
-       return 0;
-}
-
-int tm6000_set_standard(struct tm6000_core *dev)
-{
-       int i, rc = 0;
-       u8 reg_07_fe = 0x8a;
-       u8 reg_08_f1 = 0xfc;
-       u8 reg_08_e2 = 0xf0;
-       u8 reg_08_e6 = 0x0f;
-
-       tm6000_get_std_res(dev);
-
-       if (dev->radio) {
-               /* todo */
-       }
-
-       if (dev->dev_type == TM6010) {
-               switch (dev->vinput[dev->input].vmux) {
-               case TM6000_VMUX_VIDEO_A:
-                       tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4);
-                       tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1);
-                       tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0);
-                       tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
-                       tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8);
-                       reg_07_fe |= 0x01;
-                       break;
-               case TM6000_VMUX_VIDEO_B:
-                       tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8);
-                       tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1);
-                       tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0);
-                       tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
-                       tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8);
-                       reg_07_fe |= 0x01;
-                       break;
-               case TM6000_VMUX_VIDEO_AB:
-                       tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc);
-                       tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8);
-                       reg_08_e6 = 0x00;
-                       tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2);
-                       tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0);
-                       tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
-                       tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe0);
-                       break;
-               default:
-                       break;
-               }
-               switch (dev->vinput[dev->input].amux) {
-               case TM6000_AMUX_ADC1:
-                       tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
-                               0x00, 0x0f);
-                       break;
-               case TM6000_AMUX_ADC2:
-                       tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
-                               0x08, 0x0f);
-                       break;
-               case TM6000_AMUX_SIF1:
-                       reg_08_e2 |= 0x02;
-                       reg_08_e6 = 0x08;
-                       reg_07_fe |= 0x40;
-                       reg_08_f1 |= 0x02;
-                       tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
-                       tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
-                               0x02, 0x0f);
-                       break;
-               case TM6000_AMUX_SIF2:
-                       reg_08_e2 |= 0x02;
-                       reg_08_e6 = 0x08;
-                       reg_07_fe |= 0x40;
-                       reg_08_f1 |= 0x02;
-                       tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf7);
-                       tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
-                               0x02, 0x0f);
-                       break;
-               default:
-                       break;
-               }
-               tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, reg_08_e2);
-               tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, reg_08_e6);
-               tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, reg_08_f1);
-               tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, reg_07_fe);
-       } else {
-               switch (dev->vinput[dev->input].vmux) {
-               case TM6000_VMUX_VIDEO_A:
-                       tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10);
-                       tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00);
-                       tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f);
-                       tm6000_set_reg(dev,
-                           REQ_03_SET_GET_MCU_PIN, dev->vinput[dev->input].v_gpio, 0);
-                       break;
-               case TM6000_VMUX_VIDEO_B:
-                       tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00);
-                       tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00);
-                       tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f);
-                       tm6000_set_reg(dev,
-                           REQ_03_SET_GET_MCU_PIN, dev->vinput[dev->input].v_gpio, 0);
-                       break;
-               case TM6000_VMUX_VIDEO_AB:
-                       tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10);
-                       tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x10);
-                       tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00);
-                       tm6000_set_reg(dev,
-                           REQ_03_SET_GET_MCU_PIN, dev->vinput[dev->input].v_gpio, 1);
-                       break;
-               default:
-                       break;
-               }
-               switch (dev->vinput[dev->input].amux) {
-               case TM6000_AMUX_ADC1:
-                       tm6000_set_reg_mask(dev,
-                               TM6000_REQ07_REB_VADC_AADC_MODE, 0x00, 0x0f);
-                       break;
-               case TM6000_AMUX_ADC2:
-                       tm6000_set_reg_mask(dev,
-                               TM6000_REQ07_REB_VADC_AADC_MODE, 0x04, 0x0f);
-                       break;
-               default:
-                       break;
-               }
-       }
-       if (dev->vinput[dev->input].type == TM6000_INPUT_SVIDEO) {
-               for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) {
-                       if (dev->norm & svideo_stds[i].id) {
-                               rc = tm6000_load_std(dev, svideo_stds[i].common,
-                                                    sizeof(svideo_stds[i].
-                                                           common));
-                               goto ret;
-                       }
-               }
-               return -EINVAL;
-       } else {
-               for (i = 0; i < ARRAY_SIZE(composite_stds); i++) {
-                       if (dev->norm & composite_stds[i].id) {
-                               rc = tm6000_load_std(dev,
-                                                    composite_stds[i].common,
-                                                    sizeof(composite_stds[i].
-                                                           common));
-                               goto ret;
-                       }
-               }
-               return -EINVAL;
-       }
-
-ret:
-       if (rc < 0)
-               return rc;
-
-       if ((dev->dev_type == TM6010) &&
-           ((dev->vinput[dev->input].amux == TM6000_AMUX_SIF1) ||
-           (dev->vinput[dev->input].amux == TM6000_AMUX_SIF2)))
-               tm6000_set_audio_std(dev);
-
-       msleep(40);
-
-
-       return 0;
-}
diff --git a/drivers/staging/tm6000/tm6000-usb-isoc.h b/drivers/staging/tm6000/tm6000-usb-isoc.h
deleted file mode 100644 (file)
index 084c2a8..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *  tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.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 version 2
- *
- *  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/videodev2.h>
-
-#define TM6000_URB_MSG_LEN 180
-
-struct usb_isoc_ctl {
-               /* max packet size of isoc transaction */
-       int                             max_pkt_size;
-
-               /* number of allocated urbs */
-       int                             num_bufs;
-
-               /* urb for isoc transfers */
-       struct urb                      **urb;
-
-               /* transfer buffers for isoc transfer */
-       char                            **transfer_buffer;
-
-               /* Last buffer command and region */
-       u8                              cmd;
-       int                             pos, size, pktsize;
-
-               /* Last field: ODD or EVEN? */
-       int                             vfield, field;
-
-               /* Stores incomplete commands */
-       u32                             tmp_buf;
-       int                             tmp_buf_len;
-
-               /* Stores already requested buffers */
-       struct tm6000_buffer            *buf;
-};
diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c
deleted file mode 100644 (file)
index 8d8b939..0000000
+++ /dev/null
@@ -1,1809 +0,0 @@
-/*
- *   tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
- *
- *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- *     - Fixed module load/unload
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation version 2
- *
- *  This program is distributed 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/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/random.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-ioctl.h>
-#include <media/tuner.h>
-#include <linux/interrupt.h>
-#include <linux/kthread.h>
-#include <linux/highmem.h>
-#include <linux/freezer.h>
-
-#include "tm6000-regs.h"
-#include "tm6000.h"
-
-#define BUFFER_TIMEOUT     msecs_to_jiffies(2000)  /* 2 seconds */
-
-/* Limits minimum and default number of buffers */
-#define TM6000_MIN_BUF 4
-#define TM6000_DEF_BUF 8
-
-#define TM6000_MAX_ISO_PACKETS 46      /* Max number of ISO packets */
-
-/* Declare static vars that will be used as parameters */
-static unsigned int vid_limit = 16;    /* Video memory limit, in Mb */
-static int video_nr = -1;              /* /dev/videoN, -1 for autodetect */
-static int radio_nr = -1;              /* /dev/radioN, -1 for autodetect */
-
-/* Debug level */
-int tm6000_debug;
-EXPORT_SYMBOL_GPL(tm6000_debug);
-
-static const struct v4l2_queryctrl no_ctrl = {
-       .name  = "42",
-       .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-
-/* supported controls */
-static struct v4l2_queryctrl tm6000_qctrl[] = {
-       {
-               .id            = V4L2_CID_BRIGHTNESS,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Brightness",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 1,
-               .default_value = 54,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_CONTRAST,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Contrast",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 0x1,
-               .default_value = 119,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_SATURATION,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Saturation",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 0x1,
-               .default_value = 112,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_HUE,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Hue",
-               .minimum       = -128,
-               .maximum       = 127,
-               .step          = 0x1,
-               .default_value = 0,
-               .flags         = 0,
-       },
-               /* --- audio --- */
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       }, {
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = -15,
-               .maximum       = 15,
-               .step          = 1,
-               .default_value = 0,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       }
-};
-
-static const unsigned int CTRLS = ARRAY_SIZE(tm6000_qctrl);
-static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];
-
-static struct tm6000_fmt format[] = {
-       {
-               .name     = "4:2:2, packed, YVY2",
-               .fourcc   = V4L2_PIX_FMT_YUYV,
-               .depth    = 16,
-       }, {
-               .name     = "4:2:2, packed, UYVY",
-               .fourcc   = V4L2_PIX_FMT_UYVY,
-               .depth    = 16,
-       }, {
-               .name     = "A/V + VBI mux packet",
-               .fourcc   = V4L2_PIX_FMT_TM6000,
-               .depth    = 16,
-       }
-};
-
-static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id)
-{
-       unsigned int i;
-
-       for (i = 0; i < CTRLS; i++)
-               if (tm6000_qctrl[i].id == id)
-                       return tm6000_qctrl+i;
-       return NULL;
-}
-
-/* ------------------------------------------------------------------
- *     DMA and thread functions
- * ------------------------------------------------------------------
- */
-
-#define norm_maxw(a) 720
-#define norm_maxh(a) 576
-
-#define norm_minw(a) norm_maxw(a)
-#define norm_minh(a) norm_maxh(a)
-
-/*
- * video-buf generic routine to get the next available buffer
- */
-static inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
-                              struct tm6000_buffer   **buf)
-{
-       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
-       char *outp;
-
-       if (list_empty(&dma_q->active)) {
-               dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n");
-               *buf = NULL;
-               return;
-       }
-
-       *buf = list_entry(dma_q->active.next,
-                       struct tm6000_buffer, vb.queue);
-
-       /* Cleans up buffer - Useful for testing for frame/URB loss */
-       outp = videobuf_to_vmalloc(&(*buf)->vb);
-
-       return;
-}
-
-/*
- * Announces that a buffer were filled and request the next
- */
-static inline void buffer_filled(struct tm6000_core *dev,
-                                struct tm6000_dmaqueue *dma_q,
-                                struct tm6000_buffer *buf)
-{
-       /* Advice that buffer was filled */
-       dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i);
-       buf->vb.state = VIDEOBUF_DONE;
-       buf->vb.field_count++;
-       do_gettimeofday(&buf->vb.ts);
-
-       list_del(&buf->vb.queue);
-       wake_up(&buf->vb.done);
-}
-
-const char *tm6000_msg_type[] = {
-       "unknown(0)",   /* 0 */
-       "video",        /* 1 */
-       "audio",        /* 2 */
-       "vbi",          /* 3 */
-       "pts",          /* 4 */
-       "err",          /* 5 */
-       "unknown(6)",   /* 6 */
-       "unknown(7)",   /* 7 */
-};
-
-/*
- * Identify the tm5600/6000 buffer header type and properly handles
- */
-static int copy_streams(u8 *data, unsigned long len,
-                       struct urb *urb)
-{
-       struct tm6000_dmaqueue  *dma_q = urb->context;
-       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
-       u8 *ptr = data, *endp = data+len, c;
-       unsigned long header = 0;
-       int rc = 0;
-       unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
-       struct tm6000_buffer *vbuf = NULL;
-       char *voutp = NULL;
-       unsigned int linewidth;
-
-       if (!dev->radio) {
-               /* get video buffer */
-               get_next_buf(dma_q, &vbuf);
-
-               if (!vbuf)
-                       return rc;
-               voutp = videobuf_to_vmalloc(&vbuf->vb);
-
-               if (!voutp)
-                       return 0;
-       }
-
-       for (ptr = data; ptr < endp;) {
-               if (!dev->isoc_ctl.cmd) {
-                       /* Header */
-                       if (dev->isoc_ctl.tmp_buf_len > 0) {
-                               /* from last urb or packet */
-                               header = dev->isoc_ctl.tmp_buf;
-                               if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
-                                       memcpy((u8 *)&header +
-                                               dev->isoc_ctl.tmp_buf_len,
-                                               ptr,
-                                               4 - dev->isoc_ctl.tmp_buf_len);
-                                       ptr += 4 - dev->isoc_ctl.tmp_buf_len;
-                               }
-                               dev->isoc_ctl.tmp_buf_len = 0;
-                       } else {
-                               if (ptr + 3 >= endp) {
-                                       /* have incomplete header */
-                                       dev->isoc_ctl.tmp_buf_len = endp - ptr;
-                                       memcpy(&dev->isoc_ctl.tmp_buf, ptr,
-                                               dev->isoc_ctl.tmp_buf_len);
-                                       return rc;
-                               }
-                               /* Seek for sync */
-                               for (; ptr < endp - 3; ptr++) {
-                                       if (*(ptr + 3) == 0x47)
-                                               break;
-                               }
-                               /* Get message header */
-                               header = *(unsigned long *)ptr;
-                               ptr += 4;
-                       }
-
-                       /* split the header fields */
-                       c = (header >> 24) & 0xff;
-                       size = ((header & 0x7e) << 1);
-                       if (size > 0)
-                               size -= 4;
-                       block = (header >> 7) & 0xf;
-                       field = (header >> 11) & 0x1;
-                       line  = (header >> 12) & 0x1ff;
-                       cmd   = (header >> 21) & 0x7;
-                       /* Validates haeder fields */
-                       if (size > TM6000_URB_MSG_LEN)
-                               size = TM6000_URB_MSG_LEN;
-                       pktsize = TM6000_URB_MSG_LEN;
-                       /* calculate position in buffer
-                        * and change the buffer
-                        */
-                       switch (cmd) {
-                       case TM6000_URB_MSG_VIDEO:
-                               if (!dev->radio) {
-                                       if ((dev->isoc_ctl.vfield != field) &&
-                                               (field == 1)) {
-                                       /* Announces that a new buffer
-                                        * were filled
-                                        */
-                                               buffer_filled(dev, dma_q, vbuf);
-                                               dprintk(dev, V4L2_DEBUG_ISOC,
-                                                       "new buffer filled\n");
-                                               get_next_buf(dma_q, &vbuf);
-                                               if (!vbuf)
-                                                       return rc;
-                                               voutp = videobuf_to_vmalloc(&vbuf->vb);
-                                               if (!voutp)
-                                                       return rc;
-                                               memset(voutp, 0, vbuf->vb.size);
-                                       }
-                                       linewidth = vbuf->vb.width << 1;
-                                       pos = ((line << 1) - field - 1) *
-                                       linewidth + block * TM6000_URB_MSG_LEN;
-                                       /* Don't allow to write out of the buffer */
-                                       if (pos + size > vbuf->vb.size)
-                                               cmd = TM6000_URB_MSG_ERR;
-                                       dev->isoc_ctl.vfield = field;
-                               }
-                               break;
-                       case TM6000_URB_MSG_VBI:
-                               break;
-                       case TM6000_URB_MSG_AUDIO:
-                       case TM6000_URB_MSG_PTS:
-                               size = pktsize;         /* Size is always 180 bytes */
-                               break;
-                       }
-               } else {
-                       /* Continue the last copy */
-                       cmd = dev->isoc_ctl.cmd;
-                       size = dev->isoc_ctl.size;
-                       pos = dev->isoc_ctl.pos;
-                       pktsize = dev->isoc_ctl.pktsize;
-                       field = dev->isoc_ctl.field;
-               }
-               cpysize = (endp - ptr > size) ? size : endp - ptr;
-               if (cpysize) {
-                       /* copy data in different buffers */
-                       switch (cmd) {
-                       case TM6000_URB_MSG_VIDEO:
-                               /* Fills video buffer */
-                               if (vbuf)
-                                       memcpy(&voutp[pos], ptr, cpysize);
-                               break;
-                       case TM6000_URB_MSG_AUDIO: {
-                               int i;
-                               for (i = 0; i < cpysize; i += 2)
-                                       swab16s((u16 *)(ptr + i));
-
-                               tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize);
-                               break;
-                       }
-                       case TM6000_URB_MSG_VBI:
-                               /* Need some code to copy vbi buffer */
-                               break;
-                       case TM6000_URB_MSG_PTS: {
-                               /* Need some code to copy pts */
-                               u32 pts;
-                               pts = *(u32 *)ptr;
-                               dprintk(dev, V4L2_DEBUG_ISOC, "field %d, PTS %x",
-                                       field, pts);
-                               break;
-                       }
-                       }
-               }
-               if (ptr + pktsize > endp) {
-                       /* End of URB packet, but cmd processing is not
-                        * complete. Preserve the state for a next packet
-                        */
-                       dev->isoc_ctl.pos = pos + cpysize;
-                       dev->isoc_ctl.size = size - cpysize;
-                       dev->isoc_ctl.cmd = cmd;
-                       dev->isoc_ctl.field = field;
-                       dev->isoc_ctl.pktsize = pktsize - (endp - ptr);
-                       ptr += endp - ptr;
-               } else {
-                       dev->isoc_ctl.cmd = 0;
-                       ptr += pktsize;
-               }
-       }
-       return 0;
-}
-
-/*
- * Identify the tm5600/6000 buffer header type and properly handles
- */
-static int copy_multiplexed(u8 *ptr, unsigned long len,
-                       struct urb *urb)
-{
-       struct tm6000_dmaqueue  *dma_q = urb->context;
-       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
-       unsigned int pos = dev->isoc_ctl.pos, cpysize;
-       int rc = 1;
-       struct tm6000_buffer *buf;
-       char *outp = NULL;
-
-       get_next_buf(dma_q, &buf);
-       if (buf)
-               outp = videobuf_to_vmalloc(&buf->vb);
-
-       if (!outp)
-               return 0;
-
-       while (len > 0) {
-               cpysize = min(len, buf->vb.size-pos);
-               memcpy(&outp[pos], ptr, cpysize);
-               pos += cpysize;
-               ptr += cpysize;
-               len -= cpysize;
-               if (pos >= buf->vb.size) {
-                       pos = 0;
-                       /* Announces that a new buffer were filled */
-                       buffer_filled(dev, dma_q, buf);
-                       dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
-                       get_next_buf(dma_q, &buf);
-                       if (!buf)
-                               break;
-                       outp = videobuf_to_vmalloc(&(buf->vb));
-                       if (!outp)
-                               return rc;
-                       pos = 0;
-               }
-       }
-
-       dev->isoc_ctl.pos = pos;
-       return rc;
-}
-
-static inline void print_err_status(struct tm6000_core *dev,
-                                    int packet, int status)
-{
-       char *errmsg = "Unknown";
-
-       switch (status) {
-       case -ENOENT:
-               errmsg = "unlinked synchronuously";
-               break;
-       case -ECONNRESET:
-               errmsg = "unlinked asynchronuously";
-               break;
-       case -ENOSR:
-               errmsg = "Buffer error (overrun)";
-               break;
-       case -EPIPE:
-               errmsg = "Stalled (device not responding)";
-               break;
-       case -EOVERFLOW:
-               errmsg = "Babble (bad cable?)";
-               break;
-       case -EPROTO:
-               errmsg = "Bit-stuff error (bad cable?)";
-               break;
-       case -EILSEQ:
-               errmsg = "CRC/Timeout (could be anything)";
-               break;
-       case -ETIME:
-               errmsg = "Device does not respond";
-               break;
-       }
-       if (packet < 0) {
-               dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
-                       status, errmsg);
-       } else {
-               dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n",
-                       packet, status, errmsg);
-       }
-}
-
-
-/*
- * Controls the isoc copy of each urb packet
- */
-static inline int tm6000_isoc_copy(struct urb *urb)
-{
-       struct tm6000_dmaqueue  *dma_q = urb->context;
-       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
-       int i, len = 0, rc = 1, status;
-       char *p;
-
-       if (urb->status < 0) {
-               print_err_status(dev, -1, urb->status);
-               return 0;
-       }
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               status = urb->iso_frame_desc[i].status;
-
-               if (status < 0) {
-                       print_err_status(dev, i, status);
-                       continue;
-               }
-
-               len = urb->iso_frame_desc[i].actual_length;
-
-               if (len > 0) {
-                       p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-                       if (!urb->iso_frame_desc[i].status) {
-                               if ((dev->fourcc) == V4L2_PIX_FMT_TM6000) {
-                                       rc = copy_multiplexed(p, len, urb);
-                                       if (rc <= 0)
-                                               return rc;
-                               } else {
-                                       copy_streams(p, len, urb);
-                               }
-                       }
-               }
-       }
-       return rc;
-}
-
-/* ------------------------------------------------------------------
- *     URB control
- * ------------------------------------------------------------------
- */
-
-/*
- * IRQ callback, called by URB callback
- */
-static void tm6000_irq_callback(struct urb *urb)
-{
-       struct tm6000_dmaqueue  *dma_q = urb->context;
-       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
-       int i;
-
-       if (!dev)
-               return;
-
-       spin_lock(&dev->slock);
-       tm6000_isoc_copy(urb);
-       spin_unlock(&dev->slock);
-
-       /* Reset urb buffers */
-       for (i = 0; i < urb->number_of_packets; i++) {
-               urb->iso_frame_desc[i].status = 0;
-               urb->iso_frame_desc[i].actual_length = 0;
-       }
-
-       urb->status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (urb->status)
-               tm6000_err("urb resubmit failed (error=%i)\n",
-                       urb->status);
-}
-
-/*
- * Stop and Deallocate URBs
- */
-static void tm6000_uninit_isoc(struct tm6000_core *dev)
-{
-       struct urb *urb;
-       int i;
-
-       dev->isoc_ctl.buf = NULL;
-       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-               urb = dev->isoc_ctl.urb[i];
-               if (urb) {
-                       usb_kill_urb(urb);
-                       usb_unlink_urb(urb);
-                       if (dev->isoc_ctl.transfer_buffer[i]) {
-                               usb_free_coherent(dev->udev,
-                                               urb->transfer_buffer_length,
-                                               dev->isoc_ctl.transfer_buffer[i],
-                                               urb->transfer_dma);
-                       }
-                       usb_free_urb(urb);
-                       dev->isoc_ctl.urb[i] = NULL;
-               }
-               dev->isoc_ctl.transfer_buffer[i] = NULL;
-       }
-
-       kfree(dev->isoc_ctl.urb);
-       kfree(dev->isoc_ctl.transfer_buffer);
-
-       dev->isoc_ctl.urb = NULL;
-       dev->isoc_ctl.transfer_buffer = NULL;
-       dev->isoc_ctl.num_bufs = 0;
-}
-
-/*
- * Allocate URBs and start IRQ
- */
-static int tm6000_prepare_isoc(struct tm6000_core *dev)
-{
-       struct tm6000_dmaqueue *dma_q = &dev->vidq;
-       int i, j, sb_size, pipe, size, max_packets, num_bufs = 8;
-       struct urb *urb;
-
-       /* De-allocates all pending stuff */
-       tm6000_uninit_isoc(dev);
-       /* Stop interrupt USB pipe */
-       tm6000_ir_int_stop(dev);
-
-       usb_set_interface(dev->udev,
-                         dev->isoc_in.bInterfaceNumber,
-                         dev->isoc_in.bAlternateSetting);
-
-       /* Start interrupt USB pipe */
-       tm6000_ir_int_start(dev);
-
-       pipe = usb_rcvisocpipe(dev->udev,
-                              dev->isoc_in.endp->desc.bEndpointAddress &
-                              USB_ENDPOINT_NUMBER_MASK);
-
-       size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
-
-       if (size > dev->isoc_in.maxsize)
-               size = dev->isoc_in.maxsize;
-
-       dev->isoc_ctl.max_pkt_size = size;
-
-       max_packets = TM6000_MAX_ISO_PACKETS;
-       sb_size = max_packets * size;
-
-       dev->isoc_ctl.num_bufs = num_bufs;
-
-       dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
-       if (!dev->isoc_ctl.urb) {
-               tm6000_err("cannot alloc memory for usb buffers\n");
-               return -ENOMEM;
-       }
-
-       dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs,
-                                  GFP_KERNEL);
-       if (!dev->isoc_ctl.transfer_buffer) {
-               tm6000_err("cannot allocate memory for usbtransfer\n");
-               kfree(dev->isoc_ctl.urb);
-               return -ENOMEM;
-       }
-
-       dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets"
-                   " (%d bytes) of %d bytes each to handle %u size\n",
-                   max_packets, num_bufs, sb_size,
-                   dev->isoc_in.maxsize, size);
-
-       /* allocate urbs and transfer buffers */
-       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-               urb = usb_alloc_urb(max_packets, GFP_KERNEL);
-               if (!urb) {
-                       tm6000_err("cannot alloc isoc_ctl.urb %i\n", i);
-                       tm6000_uninit_isoc(dev);
-                       usb_free_urb(urb);
-                       return -ENOMEM;
-               }
-               dev->isoc_ctl.urb[i] = urb;
-
-               dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
-                       sb_size, GFP_KERNEL, &urb->transfer_dma);
-               if (!dev->isoc_ctl.transfer_buffer[i]) {
-                       tm6000_err("unable to allocate %i bytes for transfer"
-                                       " buffer %i%s\n",
-                                       sb_size, i,
-                                       in_interrupt() ? " while in int" : "");
-                       tm6000_uninit_isoc(dev);
-                       return -ENOMEM;
-               }
-               memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
-
-               usb_fill_bulk_urb(urb, dev->udev, pipe,
-                                 dev->isoc_ctl.transfer_buffer[i], sb_size,
-                                 tm6000_irq_callback, dma_q);
-               urb->interval = dev->isoc_in.endp->desc.bInterval;
-               urb->number_of_packets = max_packets;
-               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-
-               for (j = 0; j < max_packets; j++) {
-                       urb->iso_frame_desc[j].offset = size * j;
-                       urb->iso_frame_desc[j].length = size;
-               }
-       }
-
-       return 0;
-}
-
-static int tm6000_start_thread(struct tm6000_core *dev)
-{
-       struct tm6000_dmaqueue *dma_q = &dev->vidq;
-       int i;
-
-       dma_q->frame = 0;
-       dma_q->ini_jiffies = jiffies;
-
-       init_waitqueue_head(&dma_q->wq);
-
-       /* submit urbs and enables IRQ */
-       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-               int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
-               if (rc) {
-                       tm6000_err("submit of urb %i failed (error=%i)\n", i,
-                                  rc);
-                       tm6000_uninit_isoc(dev);
-                       return rc;
-               }
-       }
-
-       return 0;
-}
-
-/* ------------------------------------------------------------------
- *     Videobuf operations
- * ------------------------------------------------------------------
- */
-
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
-{
-       struct tm6000_fh *fh = vq->priv_data;
-
-       *size = fh->fmt->depth * fh->width * fh->height >> 3;
-       if (0 == *count)
-               *count = TM6000_DEF_BUF;
-
-       if (*count < TM6000_MIN_BUF)
-               *count = TM6000_MIN_BUF;
-
-       while (*size * *count > vid_limit * 1024 * 1024)
-               (*count)--;
-
-       return 0;
-}
-
-static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf)
-{
-       struct tm6000_fh *fh = vq->priv_data;
-       struct tm6000_core   *dev = fh->dev;
-       unsigned long flags;
-
-       if (in_interrupt())
-               BUG();
-
-       /* We used to wait for the buffer to finish here, but this didn't work
-          because, as we were keeping the state as VIDEOBUF_QUEUED,
-          videobuf_queue_cancel marked it as finished for us.
-          (Also, it could wedge forever if the hardware was misconfigured.)
-
-          This should be safe; by the time we get here, the buffer isn't
-          queued anymore. If we ever start marking the buffers as
-          VIDEOBUF_ACTIVE, it won't be, though.
-       */
-       spin_lock_irqsave(&dev->slock, flags);
-       if (dev->isoc_ctl.buf == buf)
-               dev->isoc_ctl.buf = NULL;
-       spin_unlock_irqrestore(&dev->slock, flags);
-
-       videobuf_vmalloc_free(&buf->vb);
-       buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
-                                               enum v4l2_field field)
-{
-       struct tm6000_fh     *fh  = vq->priv_data;
-       struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
-       struct tm6000_core   *dev = fh->dev;
-       int rc = 0, urb_init = 0;
-
-       BUG_ON(NULL == fh->fmt);
-
-
-       /* FIXME: It assumes depth=2 */
-       /* The only currently supported format is 16 bits/pixel */
-       buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3;
-       if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
-               return -EINVAL;
-
-       if (buf->fmt       != fh->fmt    ||
-           buf->vb.width  != fh->width  ||
-           buf->vb.height != fh->height ||
-           buf->vb.field  != field) {
-               buf->fmt       = fh->fmt;
-               buf->vb.width  = fh->width;
-               buf->vb.height = fh->height;
-               buf->vb.field  = field;
-               buf->vb.state = VIDEOBUF_NEEDS_INIT;
-       }
-
-       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-               rc = videobuf_iolock(vq, &buf->vb, NULL);
-               if (rc != 0)
-                       goto fail;
-               urb_init = 1;
-       }
-
-       if (!dev->isoc_ctl.num_bufs)
-               urb_init = 1;
-
-       if (urb_init) {
-               rc = tm6000_prepare_isoc(dev);
-               if (rc < 0)
-                       goto fail;
-
-               rc = tm6000_start_thread(dev);
-               if (rc < 0)
-                       goto fail;
-
-       }
-
-       buf->vb.state = VIDEOBUF_PREPARED;
-       return 0;
-
-fail:
-       free_buffer(vq, buf);
-       return rc;
-}
-
-static void
-buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct tm6000_buffer    *buf     = container_of(vb, struct tm6000_buffer, vb);
-       struct tm6000_fh        *fh      = vq->priv_data;
-       struct tm6000_core      *dev     = fh->dev;
-       struct tm6000_dmaqueue  *vidq    = &dev->vidq;
-
-       buf->vb.state = VIDEOBUF_QUEUED;
-       list_add_tail(&buf->vb.queue, &vidq->active);
-}
-
-static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct tm6000_buffer   *buf  = container_of(vb, struct tm6000_buffer, vb);
-
-       free_buffer(vq, buf);
-}
-
-static struct videobuf_queue_ops tm6000_video_qops = {
-       .buf_setup      = buffer_setup,
-       .buf_prepare    = buffer_prepare,
-       .buf_queue      = buffer_queue,
-       .buf_release    = buffer_release,
-};
-
-/* ------------------------------------------------------------------
- *     IOCTL handling
- * ------------------------------------------------------------------
- */
-
-static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh)
-{
-       /* Is the current fh handling it? if so, that's OK */
-       if (dev->resources == fh && dev->is_res_read)
-               return true;
-
-       return false;
-}
-
-static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh)
-{
-       /* Is the current fh handling it? if so, that's OK */
-       if (dev->resources == fh)
-               return true;
-
-       return false;
-}
-
-static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh,
-                  bool is_res_read)
-{
-       /* Is the current fh handling it? if so, that's OK */
-       if (dev->resources == fh && dev->is_res_read == is_res_read)
-               return true;
-
-       /* is it free? */
-       if (dev->resources)
-               return false;
-
-       /* grab it */
-       dev->resources = fh;
-       dev->is_res_read = is_res_read;
-       dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
-       return true;
-}
-
-static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
-{
-       /* Is the current fh handling it? if so, that's OK */
-       if (dev->resources != fh)
-               return;
-
-       dev->resources = NULL;
-       dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");
-}
-
-/* ------------------------------------------------------------------
- *     IOCTL vidioc handling
- * ------------------------------------------------------------------
- */
-static int vidioc_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *cap)
-{
-       struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
-
-       strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
-       strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
-       cap->version = TM6000_VERSION;
-       cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
-                               V4L2_CAP_STREAMING     |
-                               V4L2_CAP_AUDIO         |
-                               V4L2_CAP_READWRITE;
-
-       if (dev->tuner_type != TUNER_ABSENT)
-               cap->capabilities |= V4L2_CAP_TUNER;
-
-       return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
-                                       struct v4l2_fmtdesc *f)
-{
-       if (unlikely(f->index >= ARRAY_SIZE(format)))
-               return -EINVAL;
-
-       strlcpy(f->description, format[f->index].name, sizeof(f->description));
-       f->pixelformat = format[f->index].fourcc;
-       return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
-                                       struct v4l2_format *f)
-{
-       struct tm6000_fh  *fh = priv;
-
-       f->fmt.pix.width        = fh->width;
-       f->fmt.pix.height       = fh->height;
-       f->fmt.pix.field        = fh->vb_vidq.field;
-       f->fmt.pix.pixelformat  = fh->fmt->fourcc;
-       f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * fh->fmt->depth) >> 3;
-       f->fmt.pix.sizeimage =
-               f->fmt.pix.height * f->fmt.pix.bytesperline;
-
-       return 0;
-}
-
-static struct tm6000_fmt *format_by_fourcc(unsigned int fourcc)
-{
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(format); i++)
-               if (format[i].fourcc == fourcc)
-                       return format+i;
-       return NULL;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
-                       struct v4l2_format *f)
-{
-       struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
-       struct tm6000_fmt *fmt;
-       enum v4l2_field field;
-
-       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       if (NULL == fmt) {
-               dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)"
-                               " invalid.\n", f->fmt.pix.pixelformat);
-               return -EINVAL;
-       }
-
-       field = f->fmt.pix.field;
-
-       if (field == V4L2_FIELD_ANY)
-               field = V4L2_FIELD_SEQ_TB;
-       else if (V4L2_FIELD_INTERLACED != field) {
-               dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n");
-               return -EINVAL;
-       }
-
-       tm6000_get_std_res(dev);
-
-       f->fmt.pix.width  = dev->width;
-       f->fmt.pix.height = dev->height;
-
-       f->fmt.pix.width &= ~0x01;
-
-       f->fmt.pix.field = field;
-
-       f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * fmt->depth) >> 3;
-       f->fmt.pix.sizeimage =
-               f->fmt.pix.height * f->fmt.pix.bytesperline;
-
-       return 0;
-}
-
-/*FIXME: This seems to be generic enough to be at videodev2 */
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                                       struct v4l2_format *f)
-{
-       struct tm6000_fh  *fh = priv;
-       struct tm6000_core *dev = fh->dev;
-       int ret = vidioc_try_fmt_vid_cap(file, fh, f);
-       if (ret < 0)
-               return ret;
-
-       fh->fmt           = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->width         = f->fmt.pix.width;
-       fh->height        = f->fmt.pix.height;
-       fh->vb_vidq.field = f->fmt.pix.field;
-       fh->type          = f->type;
-
-       dev->fourcc       = f->fmt.pix.pixelformat;
-
-       tm6000_set_fourcc_format(dev);
-
-       return 0;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
-                          struct v4l2_requestbuffers *p)
-{
-       struct tm6000_fh  *fh = priv;
-
-       return videobuf_reqbufs(&fh->vb_vidq, p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
-                           struct v4l2_buffer *p)
-{
-       struct tm6000_fh  *fh = priv;
-
-       return videobuf_querybuf(&fh->vb_vidq, p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       struct tm6000_fh  *fh = priv;
-
-       return videobuf_qbuf(&fh->vb_vidq, p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       struct tm6000_fh  *fh = priv;
-
-       return videobuf_dqbuf(&fh->vb_vidq, p,
-                               file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct tm6000_fh  *fh = priv;
-       struct tm6000_core *dev    = fh->dev;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       if (!res_get(dev, fh, false))
-               return -EBUSY;
-       return videobuf_streamon(&fh->vb_vidq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct tm6000_fh  *fh = priv;
-       struct tm6000_core *dev    = fh->dev;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       videobuf_streamoff(&fh->vb_vidq);
-       res_free(dev, fh);
-
-       return 0;
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
-{
-       int rc = 0;
-       struct tm6000_fh   *fh = priv;
-       struct tm6000_core *dev = fh->dev;
-
-       dev->norm = *norm;
-       rc = tm6000_init_analog_mode(dev);
-
-       fh->width  = dev->width;
-       fh->height = dev->height;
-
-       if (rc < 0)
-               return rc;
-
-       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
-
-       return 0;
-}
-
-static const char *iname[] = {
-       [TM6000_INPUT_TV] = "Television",
-       [TM6000_INPUT_COMPOSITE1] = "Composite 1",
-       [TM6000_INPUT_COMPOSITE2] = "Composite 2",
-       [TM6000_INPUT_SVIDEO] = "S-Video",
-};
-
-static int vidioc_enum_input(struct file *file, void *priv,
-                               struct v4l2_input *i)
-{
-       struct tm6000_fh   *fh = priv;
-       struct tm6000_core *dev = fh->dev;
-       unsigned int n;
-
-       n = i->index;
-       if (n >= 3)
-               return -EINVAL;
-
-       if (!dev->vinput[n].type)
-               return -EINVAL;
-
-       i->index = n;
-
-       if (dev->vinput[n].type == TM6000_INPUT_TV)
-               i->type = V4L2_INPUT_TYPE_TUNER;
-       else
-               i->type = V4L2_INPUT_TYPE_CAMERA;
-
-       strcpy(i->name, iname[dev->vinput[n].type]);
-
-       i->std = TM6000_STD;
-
-       return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
-       struct tm6000_fh   *fh = priv;
-       struct tm6000_core *dev = fh->dev;
-
-       *i = dev->input;
-
-       return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
-       struct tm6000_fh   *fh = priv;
-       struct tm6000_core *dev = fh->dev;
-       int rc = 0;
-
-       if (i >= 3)
-               return -EINVAL;
-       if (!dev->vinput[i].type)
-               return -EINVAL;
-
-       dev->input = i;
-
-       rc = vidioc_s_std(file, priv, &dev->vfd->current_norm);
-
-       return rc;
-}
-
-/* --- controls ---------------------------------------------- */
-static int vidioc_queryctrl(struct file *file, void *priv,
-                               struct v4l2_queryctrl *qc)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
-               if (qc->id && qc->id == tm6000_qctrl[i].id) {
-                       memcpy(qc, &(tm6000_qctrl[i]),
-                               sizeof(*qc));
-                       return 0;
-               }
-
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctrl)
-{
-       struct tm6000_fh  *fh = priv;
-       struct tm6000_core *dev    = fh->dev;
-       int  val;
-
-       /* FIXME: Probably, those won't work! Maybe we need shadow regs */
-       switch (ctrl->id) {
-       case V4L2_CID_CONTRAST:
-               val = tm6000_get_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0);
-               break;
-       case V4L2_CID_BRIGHTNESS:
-               val = tm6000_get_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0);
-               return 0;
-       case V4L2_CID_SATURATION:
-               val = tm6000_get_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0);
-               return 0;
-       case V4L2_CID_HUE:
-               val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0);
-               return 0;
-       case V4L2_CID_AUDIO_MUTE:
-               val = dev->ctl_mute;
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               val = dev->ctl_volume;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-
-       if (val < 0)
-               return val;
-
-       ctrl->value = val;
-
-       return 0;
-}
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctrl)
-{
-       struct tm6000_fh   *fh  = priv;
-       struct tm6000_core *dev = fh->dev;
-       u8  val = ctrl->value;
-
-       switch (ctrl->id) {
-       case V4L2_CID_CONTRAST:
-               tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
-               return 0;
-       case V4L2_CID_BRIGHTNESS:
-               tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
-               return 0;
-       case V4L2_CID_SATURATION:
-               tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
-               return 0;
-       case V4L2_CID_HUE:
-               tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
-               return 0;
-       case V4L2_CID_AUDIO_MUTE:
-               dev->ctl_mute = val;
-               tm6000_tvaudio_set_mute(dev, val);
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               dev->ctl_volume = val;
-               tm6000_set_volume(dev, val);
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-                               struct v4l2_tuner *t)
-{
-       struct tm6000_fh   *fh  = priv;
-       struct tm6000_core *dev = fh->dev;
-
-       if (unlikely(UNSET == dev->tuner_type))
-               return -EINVAL;
-       if (0 != t->index)
-               return -EINVAL;
-
-       strcpy(t->name, "Television");
-       t->type       = V4L2_TUNER_ANALOG_TV;
-       t->capability = V4L2_TUNER_CAP_NORM;
-       t->rangehigh  = 0xffffffffUL;
-       t->rxsubchans = V4L2_TUNER_SUB_STEREO;
-
-       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
-
-       t->audmode = dev->amode;
-
-       return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-                               struct v4l2_tuner *t)
-{
-       struct tm6000_fh   *fh  = priv;
-       struct tm6000_core *dev = fh->dev;
-
-       if (UNSET == dev->tuner_type)
-               return -EINVAL;
-       if (0 != t->index)
-               return -EINVAL;
-
-       dev->amode = t->audmode;
-       dprintk(dev, 3, "audio mode: %x\n", t->audmode);
-
-       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
-
-       return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
-{
-       struct tm6000_fh   *fh  = priv;
-       struct tm6000_core *dev = fh->dev;
-
-       if (unlikely(UNSET == dev->tuner_type))
-               return -EINVAL;
-
-       f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-       f->frequency = dev->freq;
-
-       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
-
-       return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
-{
-       struct tm6000_fh   *fh  = priv;
-       struct tm6000_core *dev = fh->dev;
-
-       if (unlikely(UNSET == dev->tuner_type))
-               return -EINVAL;
-       if (unlikely(f->tuner != 0))
-               return -EINVAL;
-       if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
-               return -EINVAL;
-       if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
-               return -EINVAL;
-
-       dev->freq = f->frequency;
-       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
-
-       return 0;
-}
-
-static int radio_querycap(struct file *file, void *priv,
-                                       struct v4l2_capability *cap)
-{
-       struct tm6000_fh *fh = file->private_data;
-       struct tm6000_core *dev = fh->dev;
-
-       strcpy(cap->driver, "tm6000");
-       strlcpy(cap->card, dev->name, sizeof(dev->name));
-       sprintf(cap->bus_info, "USB%04x:%04x",
-               le16_to_cpu(dev->udev->descriptor.idVendor),
-               le16_to_cpu(dev->udev->descriptor.idProduct));
-       cap->version = dev->dev_type;
-       cap->capabilities = V4L2_CAP_TUNER |
-                       V4L2_CAP_AUDIO     |
-                       V4L2_CAP_RADIO     |
-                       V4L2_CAP_READWRITE |
-                       V4L2_CAP_STREAMING;
-
-       return 0;
-}
-
-static int radio_g_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *t)
-{
-       struct tm6000_fh *fh = file->private_data;
-       struct tm6000_core *dev = fh->dev;
-
-       if (0 != t->index)
-               return -EINVAL;
-
-       memset(t, 0, sizeof(*t));
-       strcpy(t->name, "Radio");
-       t->type = V4L2_TUNER_RADIO;
-       t->rxsubchans = V4L2_TUNER_SUB_STEREO;
-
-       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
-
-       return 0;
-}
-
-static int radio_s_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *t)
-{
-       struct tm6000_fh *fh = file->private_data;
-       struct tm6000_core *dev = fh->dev;
-
-       if (0 != t->index)
-               return -EINVAL;
-
-       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
-
-       return 0;
-}
-
-static int radio_enum_input(struct file *file, void *priv,
-                                       struct v4l2_input *i)
-{
-       struct tm6000_fh *fh = priv;
-       struct tm6000_core *dev = fh->dev;
-
-       if (i->index != 0)
-               return -EINVAL;
-
-       if (!dev->rinput.type)
-               return -EINVAL;
-
-       strcpy(i->name, "Radio");
-       i->type = V4L2_INPUT_TYPE_TUNER;
-
-       return 0;
-}
-
-static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       struct tm6000_fh *fh = priv;
-       struct tm6000_core *dev = fh->dev;
-
-       if (dev->input != 5)
-               return -EINVAL;
-
-       *i = dev->input - 5;
-
-       return 0;
-}
-
-static int radio_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       memset(a, 0, sizeof(*a));
-       strcpy(a->name, "Radio");
-       return 0;
-}
-
-static int radio_s_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       return 0;
-}
-
-static int radio_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       struct tm6000_fh *fh = priv;
-       struct tm6000_core *dev = fh->dev;
-
-       if (i)
-               return -EINVAL;
-
-       if (!dev->rinput.type)
-               return -EINVAL;
-
-       dev->input = i + 5;
-
-       return 0;
-}
-
-static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
-{
-       return 0;
-}
-
-static int radio_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *c)
-{
-       const struct v4l2_queryctrl *ctrl;
-
-       if (c->id <  V4L2_CID_BASE ||
-           c->id >= V4L2_CID_LASTP1)
-               return -EINVAL;
-       if (c->id == V4L2_CID_AUDIO_MUTE) {
-               ctrl = ctrl_by_id(c->id);
-               *c = *ctrl;
-       } else
-               *c = no_ctrl;
-
-       return 0;
-}
-
-/* ------------------------------------------------------------------
-       File operations for the device
-   ------------------------------------------------------------------*/
-
-static int tm6000_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct tm6000_core *dev = video_drvdata(file);
-       struct tm6000_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       int i, rc;
-       int radio = 0;
-
-       printk(KERN_INFO "tm6000: open called (dev=%s)\n",
-               video_device_node_name(vdev));
-
-       dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n",
-               video_device_node_name(vdev));
-
-       switch (vdev->vfl_type) {
-       case VFL_TYPE_GRABBER:
-               type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               break;
-       case VFL_TYPE_VBI:
-               type = V4L2_BUF_TYPE_VBI_CAPTURE;
-               break;
-       case VFL_TYPE_RADIO:
-               radio = 1;
-               break;
-       }
-
-       /* If more than one user, mutex should be added */
-       dev->users++;
-
-       dprintk(dev, V4L2_DEBUG_OPEN, "open dev=%s type=%s users=%d\n",
-               video_device_node_name(vdev), v4l2_type_names[type],
-               dev->users);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh) {
-               dev->users--;
-               return -ENOMEM;
-       }
-
-       file->private_data = fh;
-       fh->dev      = dev;
-       fh->radio    = radio;
-       dev->radio   = radio;
-       fh->type     = type;
-       dev->fourcc  = format[0].fourcc;
-
-       fh->fmt      = format_by_fourcc(dev->fourcc);
-
-       tm6000_get_std_res(dev);
-
-       fh->width    = dev->width;
-       fh->height   = dev->height;
-
-       dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, "
-                                               "dev->vidq=0x%08lx\n",
-               (unsigned long)fh, (unsigned long)dev, (unsigned long)&dev->vidq);
-       dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
-                               "queued=%d\n", list_empty(&dev->vidq.queued));
-       dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
-                               "active=%d\n", list_empty(&dev->vidq.active));
-
-       /* initialize hardware on analog mode */
-       rc = tm6000_init_analog_mode(dev);
-       if (rc < 0)
-               return rc;
-
-       if (dev->mode != TM6000_MODE_ANALOG) {
-               /* Put all controls at a sane state */
-               for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
-                       qctl_regs[i] = tm6000_qctrl[i].default_value;
-
-               dev->mode = TM6000_MODE_ANALOG;
-       }
-
-       videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops,
-                       NULL, &dev->slock,
-                       fh->type,
-                       V4L2_FIELD_INTERLACED,
-                       sizeof(struct tm6000_buffer), fh, &dev->lock);
-
-       if (fh->radio) {
-               dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n");
-               dev->input = 5;
-               tm6000_set_audio_rinput(dev);
-               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
-               tm6000_prepare_isoc(dev);
-               tm6000_start_thread(dev);
-       }
-
-       return 0;
-}
-
-static ssize_t
-tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
-{
-       struct tm6000_fh        *fh = file->private_data;
-
-       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               if (!res_get(fh->dev, fh, true))
-                       return -EBUSY;
-
-               return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
-                                       file->f_flags & O_NONBLOCK);
-       }
-       return 0;
-}
-
-static unsigned int
-tm6000_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct tm6000_fh        *fh = file->private_data;
-       struct tm6000_buffer    *buf;
-
-       if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
-               return POLLERR;
-
-       if (!!is_res_streaming(fh->dev, fh))
-               return POLLERR;
-
-       if (!is_res_read(fh->dev, fh)) {
-               /* streaming capture */
-               if (list_empty(&fh->vb_vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vb_vidq.stream.next, struct tm6000_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               return videobuf_poll_stream(file, &fh->vb_vidq,
-                                           wait);
-       }
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE ||
-           buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-static int tm6000_release(struct file *file)
-{
-       struct tm6000_fh         *fh = file->private_data;
-       struct tm6000_core      *dev = fh->dev;
-       struct video_device    *vdev = video_devdata(file);
-
-       dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (dev=%s, users=%d)\n",
-               video_device_node_name(vdev), dev->users);
-
-       dev->users--;
-
-       res_free(dev, fh);
-       if (!dev->users) {
-               tm6000_uninit_isoc(dev);
-               videobuf_mmap_free(&fh->vb_vidq);
-       }
-
-       kfree(fh);
-
-       return 0;
-}
-
-static int tm6000_mmap(struct file *file, struct vm_area_struct * vma)
-{
-       struct tm6000_fh        *fh = file->private_data;
-       int ret;
-
-       ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
-
-       return ret;
-}
-
-static struct v4l2_file_operations tm6000_fops = {
-       .owner          = THIS_MODULE,
-       .open           = tm6000_open,
-       .release        = tm6000_release,
-       .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
-       .read           = tm6000_read,
-       .poll           = tm6000_poll,
-       .mmap           = tm6000_mmap,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap          = vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
-       .vidioc_s_std             = vidioc_s_std,
-       .vidioc_enum_input        = vidioc_enum_input,
-       .vidioc_g_input           = vidioc_g_input,
-       .vidioc_s_input           = vidioc_s_input,
-       .vidioc_queryctrl         = vidioc_queryctrl,
-       .vidioc_g_ctrl            = vidioc_g_ctrl,
-       .vidioc_s_ctrl            = vidioc_s_ctrl,
-       .vidioc_g_tuner           = vidioc_g_tuner,
-       .vidioc_s_tuner           = vidioc_s_tuner,
-       .vidioc_g_frequency       = vidioc_g_frequency,
-       .vidioc_s_frequency       = vidioc_s_frequency,
-       .vidioc_streamon          = vidioc_streamon,
-       .vidioc_streamoff         = vidioc_streamoff,
-       .vidioc_reqbufs           = vidioc_reqbufs,
-       .vidioc_querybuf          = vidioc_querybuf,
-       .vidioc_qbuf              = vidioc_qbuf,
-       .vidioc_dqbuf             = vidioc_dqbuf,
-};
-
-static struct video_device tm6000_template = {
-       .name           = "tm6000",
-       .fops           = &tm6000_fops,
-       .ioctl_ops      = &video_ioctl_ops,
-       .release        = video_device_release,
-       .tvnorms        = TM6000_STD,
-       .current_norm   = V4L2_STD_NTSC_M,
-};
-
-static const struct v4l2_file_operations radio_fops = {
-       .owner          = THIS_MODULE,
-       .open           = tm6000_open,
-       .release        = tm6000_release,
-       .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops radio_ioctl_ops = {
-       .vidioc_querycap        = radio_querycap,
-       .vidioc_g_tuner         = radio_g_tuner,
-       .vidioc_enum_input      = radio_enum_input,
-       .vidioc_g_audio         = radio_g_audio,
-       .vidioc_s_tuner         = radio_s_tuner,
-       .vidioc_s_audio         = radio_s_audio,
-       .vidioc_s_input         = radio_s_input,
-       .vidioc_s_std           = radio_s_std,
-       .vidioc_queryctrl       = radio_queryctrl,
-       .vidioc_g_input         = radio_g_input,
-       .vidioc_g_ctrl          = vidioc_g_ctrl,
-       .vidioc_s_ctrl          = vidioc_s_ctrl,
-       .vidioc_g_frequency     = vidioc_g_frequency,
-       .vidioc_s_frequency     = vidioc_s_frequency,
-};
-
-struct video_device tm6000_radio_template = {
-       .name                   = "tm6000",
-       .fops                   = &radio_fops,
-       .ioctl_ops              = &radio_ioctl_ops,
-};
-
-/* -----------------------------------------------------------------
- *     Initialization and module stuff
- * ------------------------------------------------------------------
- */
-
-static struct video_device *vdev_init(struct tm6000_core *dev,
-               const struct video_device
-               *template, const char *type_name)
-{
-       struct video_device *vfd;
-
-       vfd = video_device_alloc();
-       if (NULL == vfd)
-               return NULL;
-
-       *vfd = *template;
-       vfd->v4l2_dev = &dev->v4l2_dev;
-       vfd->release = video_device_release;
-       vfd->debug = tm6000_debug;
-       vfd->lock = &dev->lock;
-
-       snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
-
-       video_set_drvdata(vfd, dev);
-       return vfd;
-}
-
-int tm6000_v4l2_register(struct tm6000_core *dev)
-{
-       int ret = -1;
-
-       dev->vfd = vdev_init(dev, &tm6000_template, "video");
-
-       if (!dev->vfd) {
-               printk(KERN_INFO "%s: can't register video device\n",
-                      dev->name);
-               return -ENOMEM;
-       }
-
-       /* init video dma queues */
-       INIT_LIST_HEAD(&dev->vidq.active);
-       INIT_LIST_HEAD(&dev->vidq.queued);
-
-       ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
-
-       if (ret < 0) {
-               printk(KERN_INFO "%s: can't register video device\n",
-                      dev->name);
-               return ret;
-       }
-
-       printk(KERN_INFO "%s: registered device %s\n",
-              dev->name, video_device_node_name(dev->vfd));
-
-       if (dev->caps.has_radio) {
-               dev->radio_dev = vdev_init(dev, &tm6000_radio_template,
-                                                          "radio");
-               if (!dev->radio_dev) {
-                       printk(KERN_INFO "%s: can't register radio device\n",
-                              dev->name);
-                       return ret; /* FIXME release resource */
-               }
-
-               ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
-                                           radio_nr);
-               if (ret < 0) {
-                       printk(KERN_INFO "%s: can't register radio device\n",
-                              dev->name);
-                       return ret; /* FIXME release resource */
-               }
-
-               printk(KERN_INFO "%s: registered device %s\n",
-                      dev->name, video_device_node_name(dev->radio_dev));
-       }
-
-       printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
-       return ret;
-}
-
-int tm6000_v4l2_unregister(struct tm6000_core *dev)
-{
-       video_unregister_device(dev->vfd);
-
-       if (dev->radio_dev) {
-               if (video_is_registered(dev->radio_dev))
-                       video_unregister_device(dev->radio_dev);
-               else
-                       video_device_release(dev->radio_dev);
-               dev->radio_dev = NULL;
-       }
-
-       return 0;
-}
-
-int tm6000_v4l2_exit(void)
-{
-       return 0;
-}
-
-module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr, "Allow changing video device number");
-
-module_param_named(debug, tm6000_debug, int, 0444);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-module_param(vid_limit, int, 0644);
-MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
-
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h
deleted file mode 100644 (file)
index c56da62..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- *  tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
- *
- *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- *     - DVB-T support
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation version 2
- *
- *  This program is distributed 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.
- */
-
-/* Use the tm6000-hack, instead of the proper initialization code i*/
-/* #define HACK 1 */
-
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/videobuf-vmalloc.h>
-#include "tm6000-usb-isoc.h"
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <media/v4l2-device.h>
-#include <linux/version.h>
-#include <linux/dvb/frontend.h>
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dmxdev.h"
-
-#define TM6000_VERSION KERNEL_VERSION(0, 0, 2)
-
-/* Inputs */
-enum tm6000_itype {
-       TM6000_INPUT_TV = 1,
-       TM6000_INPUT_COMPOSITE1,
-       TM6000_INPUT_COMPOSITE2,
-       TM6000_INPUT_SVIDEO,
-       TM6000_INPUT_DVB,
-       TM6000_INPUT_RADIO,
-};
-
-enum tm6000_mux {
-       TM6000_VMUX_VIDEO_A = 1,
-       TM6000_VMUX_VIDEO_B,
-       TM6000_VMUX_VIDEO_AB,
-       TM6000_AMUX_ADC1,
-       TM6000_AMUX_ADC2,
-       TM6000_AMUX_SIF1,
-       TM6000_AMUX_SIF2,
-       TM6000_AMUX_I2S,
-};
-
-enum tm6000_devtype {
-       TM6000 = 0,
-       TM5600,
-       TM6010,
-};
-
-struct tm6000_input {
-       enum tm6000_itype       type;
-       enum tm6000_mux         vmux;
-       enum tm6000_mux         amux;
-       unsigned int            v_gpio;
-       unsigned int            a_gpio;
-};
-
-/* ------------------------------------------------------------------
- *     Basic structures
- * ------------------------------------------------------------------
- */
-
-struct tm6000_fmt {
-       char  *name;
-       u32   fourcc;          /* v4l2 format id */
-       int   depth;
-};
-
-/* buffer for one video frame */
-struct tm6000_buffer {
-       /* common v4l buffer stuff -- must be first */
-       struct videobuf_buffer vb;
-
-       struct tm6000_fmt      *fmt;
-};
-
-struct tm6000_dmaqueue {
-       struct list_head       active;
-       struct list_head       queued;
-
-       /* thread for generating video stream*/
-       struct task_struct         *kthread;
-       wait_queue_head_t          wq;
-       /* Counters to control fps rate */
-       int                        frame;
-       int                        ini_jiffies;
-};
-
-/* device states */
-enum tm6000_core_state {
-       DEV_INITIALIZED   = 0x01,
-       DEV_DISCONNECTED  = 0x02,
-       DEV_MISCONFIGURED = 0x04,
-};
-
-/* io methods */
-enum tm6000_io_method {
-       IO_NONE,
-       IO_READ,
-       IO_MMAP,
-};
-
-enum tm6000_mode {
-       TM6000_MODE_UNKNOWN = 0,
-       TM6000_MODE_ANALOG,
-       TM6000_MODE_DIGITAL,
-};
-
-struct tm6000_gpio {
-       int             tuner_reset;
-       int             tuner_on;
-       int             demod_reset;
-       int             demod_on;
-       int             power_led;
-       int             dvb_led;
-       int             ir;
-};
-
-struct tm6000_capabilities {
-       unsigned int    has_tuner:1;
-       unsigned int    has_tda9874:1;
-       unsigned int    has_dvb:1;
-       unsigned int    has_zl10353:1;
-       unsigned int    has_eeprom:1;
-       unsigned int    has_remote:1;
-       unsigned int    has_radio:1;
-};
-
-struct tm6000_dvb {
-       struct dvb_adapter      adapter;
-       struct dvb_demux        demux;
-       struct dvb_frontend     *frontend;
-       struct dmxdev           dmxdev;
-       unsigned int            streams;
-       struct urb              *bulk_urb;
-       struct mutex            mutex;
-};
-
-struct snd_tm6000_card {
-       struct snd_card                 *card;
-       spinlock_t                      reg_lock;
-       struct tm6000_core              *core;
-       struct snd_pcm_substream        *substream;
-
-       /* temporary data for buffer fill processing */
-       unsigned                        buf_pos;
-       unsigned                        period_pos;
-};
-
-struct tm6000_endpoint {
-       struct usb_host_endpoint        *endp;
-       __u8                            bInterfaceNumber;
-       __u8                            bAlternateSetting;
-       unsigned                        maxsize;
-};
-
-struct tm6000_core {
-       /* generic device properties */
-       char                            name[30];       /* name (including minor) of the device */
-       int                             model;          /* index in the device_data struct */
-       int                             devno;          /* marks the number of this device */
-       enum tm6000_devtype             dev_type;       /* type of device */
-       unsigned char                   eedata[256];    /* Eeprom data */
-       unsigned                        eedata_size;    /* Size of the eeprom info */
-
-       v4l2_std_id                     norm;           /* Current norm */
-       int                             width, height;  /* Selected resolution */
-
-       enum tm6000_core_state          state;
-
-       /* Device Capabilities*/
-       struct tm6000_capabilities      caps;
-
-       /* Tuner configuration */
-       int                             tuner_type;             /* type of the tuner */
-       int                             tuner_addr;             /* tuner address */
-
-       struct tm6000_gpio              gpio;
-
-       char                            *ir_codes;
-
-       __u8                            radio;
-
-       /* Demodulator configuration */
-       int                             demod_addr;     /* demodulator address */
-
-       int                             audio_bitrate;
-       /* i2c i/o */
-       struct i2c_adapter              i2c_adap;
-       struct i2c_client               i2c_client;
-
-
-       /* extension */
-       struct list_head                devlist;
-
-       /* video for linux */
-       int                             users;
-
-       /* various device info */
-       struct tm6000_fh                *resources;     /* Points to fh that is streaming */
-       bool                            is_res_read;
-
-       struct video_device             *vfd;
-       struct video_device             *radio_dev;
-       struct tm6000_dmaqueue          vidq;
-       struct v4l2_device              v4l2_dev;
-
-       int                             input;
-       struct tm6000_input             vinput[3];      /* video input */
-       struct tm6000_input             rinput;         /* radio input */
-
-       int                             freq;
-       unsigned int                    fourcc;
-
-       enum tm6000_mode                mode;
-
-       int                             ctl_mute;             /* audio */
-       int                             ctl_volume;
-       int                             amode;
-
-       /* DVB-T support */
-       struct tm6000_dvb               *dvb;
-
-       /* audio support */
-       struct snd_tm6000_card          *adev;
-       struct work_struct              wq_trigger;   /* Trigger to start/stop audio for alsa module */
-       atomic_t                        stream_started;  /* stream should be running if true */
-
-       struct tm6000_IR                *ir;
-
-       /* locks */
-       struct mutex                    lock;
-
-       /* usb transfer */
-       struct usb_device               *udev;          /* the usb device */
-
-       struct tm6000_endpoint          bulk_in, bulk_out, isoc_in, isoc_out;
-       struct tm6000_endpoint          int_in, int_out;
-
-       /* scaler!=0 if scaler is active*/
-       int                             scaler;
-
-               /* Isoc control struct */
-       struct usb_isoc_ctl          isoc_ctl;
-
-       spinlock_t                   slock;
-};
-
-enum tm6000_ops_type {
-       TM6000_AUDIO = 0x10,
-       TM6000_DVB = 0x20,
-};
-
-struct tm6000_ops {
-       struct list_head        next;
-       char                    *name;
-       enum tm6000_ops_type    type;
-       int (*init)(struct tm6000_core *);
-       int (*fini)(struct tm6000_core *);
-       int (*fillbuf)(struct tm6000_core *, char *buf, int size);
-};
-
-struct tm6000_fh {
-       struct tm6000_core           *dev;
-       unsigned int                 radio;
-
-       /* video capture */
-       struct tm6000_fmt            *fmt;
-       unsigned int                 width, height;
-       struct videobuf_queue        vb_vidq;
-
-       enum v4l2_buf_type           type;
-};
-
-#define TM6000_STD     (V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|    \
-                       V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \
-                       V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM)
-
-/* In tm6000-cards.c */
-
-int tm6000_tuner_callback(void *ptr, int component, int command, int arg);
-int tm6000_xc5000_callback(void *ptr, int component, int command, int arg);
-int tm6000_cards_setup(struct tm6000_core *dev);
-void tm6000_flash_led(struct tm6000_core *dev, u8 state);
-
-/* In tm6000-core.c */
-
-int tm6000_read_write_usb(struct tm6000_core *dev, u8 reqtype, u8 req,
-                          u16 value, u16 index, u8 *buf, u16 len);
-int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
-int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index);
-int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index);
-int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
-int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
-                                               u16 index, u16 mask);
-int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep);
-int tm6000_init(struct tm6000_core *dev);
-
-int tm6000_init_analog_mode(struct tm6000_core *dev);
-int tm6000_init_digital_mode(struct tm6000_core *dev);
-int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate);
-int tm6000_set_audio_rinput(struct tm6000_core *dev);
-int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute);
-void tm6000_set_volume(struct tm6000_core *dev, int vol);
-
-int tm6000_v4l2_register(struct tm6000_core *dev);
-int tm6000_v4l2_unregister(struct tm6000_core *dev);
-int tm6000_v4l2_exit(void);
-void tm6000_set_fourcc_format(struct tm6000_core *dev);
-
-void tm6000_remove_from_devlist(struct tm6000_core *dev);
-void tm6000_add_into_devlist(struct tm6000_core *dev);
-int tm6000_register_extension(struct tm6000_ops *ops);
-void tm6000_unregister_extension(struct tm6000_ops *ops);
-void tm6000_init_extension(struct tm6000_core *dev);
-void tm6000_close_extension(struct tm6000_core *dev);
-int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
-                       char *buf, int size);
-
-
-/* In tm6000-stds.c */
-void tm6000_get_std_res(struct tm6000_core *dev);
-int tm6000_set_standard(struct tm6000_core *dev);
-
-/* In tm6000-i2c.c */
-int tm6000_i2c_register(struct tm6000_core *dev);
-int tm6000_i2c_unregister(struct tm6000_core *dev);
-
-/* In tm6000-queue.c */
-
-int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma);
-
-int tm6000_vidioc_streamon(struct file *file, void *priv,
-                          enum v4l2_buf_type i);
-int tm6000_vidioc_streamoff(struct file *file, void *priv,
-                           enum v4l2_buf_type i);
-int tm6000_vidioc_reqbufs(struct file *file, void *priv,
-                         struct v4l2_requestbuffers *rb);
-int tm6000_vidioc_querybuf(struct file *file, void *priv,
-                          struct v4l2_buffer *b);
-int tm6000_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b);
-int tm6000_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b);
-ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count,
-                        loff_t *f_pos);
-unsigned int tm6000_v4l2_poll(struct file *file,
-                             struct poll_table_struct *wait);
-int tm6000_queue_init(struct tm6000_core *dev);
-
-/* In tm6000-alsa.c */
-/*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/
-
-/* In tm6000-input.c */
-int tm6000_ir_init(struct tm6000_core *dev);
-int tm6000_ir_fini(struct tm6000_core *dev);
-void tm6000_ir_wait(struct tm6000_core *dev, u8 state);
-int tm6000_ir_int_start(struct tm6000_core *dev);
-void tm6000_ir_int_stop(struct tm6000_core *dev);
-
-/* Debug stuff */
-
-extern int tm6000_debug;
-
-#define dprintk(dev, level, fmt, arg...) do {\
-       if (tm6000_debug & level) \
-               printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \
-                        dev->name, __FUNCTION__ , ##arg); } while (0)
-
-#define V4L2_DEBUG_REG         0x0004
-#define V4L2_DEBUG_I2C         0x0008
-#define V4L2_DEBUG_QUEUE       0x0010
-#define V4L2_DEBUG_ISOC                0x0020
-#define V4L2_DEBUG_RES_LOCK    0x0040  /* Resource locking */
-#define V4L2_DEBUG_OPEN                0x0080  /* video open/close debug */
-
-#define tm6000_err(fmt, arg...) do {\
-       printk(KERN_ERR "tm6000 %s :"fmt, \
-               __FUNCTION__ , ##arg); } while (0)
index 36db231..277e408 100644 (file)
@@ -1300,27 +1300,17 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
        return 0;
 }
 
-static int XGIfb_pan_var(struct xgifb_video_info *xgifb_info,
-                        struct fb_var_screeninfo *var)
+static int XGIfb_pan_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
+       struct xgifb_video_info *xgifb_info = info->par;
        unsigned int base;
 
        /* printk("Inside pan_var"); */
 
-       if (var->xoffset > (var->xres_virtual - var->xres)) {
-               /* printk("Pan: xo: %d xv %d xr %d\n",
-                       var->xoffset, var->xres_virtual, var->xres); */
-               return -EINVAL;
-       }
-       if (var->yoffset > (var->yres_virtual - var->yres)) {
-               /* printk("Pan: yo: %d yv %d yr %d\n",
-                       var->yoffset, var->yres_virtual, var->yres); */
-               return -EINVAL;
-       }
-       base = var->yoffset * var->xres_virtual + var->xoffset;
+       base = var->yoffset * info->var.xres_virtual + var->xoffset;
 
        /* calculate base bpp dep. */
-       switch (var->bits_per_pixel) {
+       switch (info->var.bits_per_pixel) {
        case 16:
                base >>= 1;
                break;
@@ -1615,13 +1605,12 @@ static int XGIfb_pan_display(struct fb_var_screeninfo *var,
                struct fb_info *info)
 {
        int err;
-       struct xgifb_video_info *xgifb_info = info->par;
 
        /* printk("\nInside pan_display:\n"); */
 
-       if (var->xoffset > (var->xres_virtual - var->xres))
+       if (var->xoffset > (info->var.xres_virtual - info->var.xres))
                return -EINVAL;
-       if (var->yoffset > (var->yres_virtual - var->yres))
+       if (var->yoffset > (info->var.yres_virtual - info->var.yres))
                return -EINVAL;
 
        if (var->vmode & FB_VMODE_YWRAP) {
@@ -1634,7 +1623,7 @@ static int XGIfb_pan_display(struct fb_var_screeninfo *var,
                                                > info->var.yres_virtual)
                        return -EINVAL;
        }
-       err = XGIfb_pan_var(xgifb_info, var);
+       err = XGIfb_pan_var(var, info);
        if (err < 0)
                return err;
 
index 75a39ea..a425d65 100644 (file)
@@ -378,8 +378,8 @@ static int mc68x328fb_pan_display(struct fb_var_screeninfo *var,
                    || var->xoffset)
                        return -EINVAL;
        } else {
-               if (var->xoffset + var->xres > info->var.xres_virtual ||
-                   var->yoffset + var->yres > info->var.yres_virtual)
+               if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+                   var->yoffset + info->var.yres > info->var.yres_virtual)
                        return -EINVAL;
        }
        info->var.xoffset = var->xoffset;
index 549b960..8165c55 100644 (file)
@@ -259,6 +259,15 @@ config FB_TILEBLITTING
 comment "Frame buffer hardware drivers"
        depends on FB
 
+config FB_GRVGA
+       tristate "Aeroflex Gaisler framebuffer support"
+       depends on FB && SPARC
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       ---help---
+       This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler.
+
 config FB_CIRRUS
        tristate "Cirrus Logic support"
        depends on FB && (ZORRO || PCI)
@@ -1756,9 +1765,10 @@ config FB_AU1100
 config FB_AU1200
        bool "Au1200 LCD Driver"
        depends on (FB = y) && MIPS && SOC_AU1200
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
+       select FB_SYS_FILLRECT
+       select FB_SYS_COPYAREA
+       select FB_SYS_IMAGEBLIT
+       select FB_SYS_FOPS
        help
          This is the framebuffer driver for the AMD Au1200 SOC.  It can drive
          various panels and CRTs by passing in kernel cmd line option
@@ -2027,7 +2037,7 @@ config FB_TMIO_ACCELL
 
 config FB_S3C
        tristate "Samsung S3C framebuffer support"
-       depends on FB && S3C_DEV_FB
+       depends on FB && (S3C_DEV_FB || S5P_DEV_FIMD0)
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
@@ -2110,6 +2120,22 @@ config FB_SM501
 
          If unsure, say N.
 
+config FB_SMSCUFX
+       tristate "SMSC UFX6000/7000 USB Framebuffer support"
+       depends on FB && USB
+       select FB_MODE_HELPERS
+       select FB_SYS_FILLRECT
+       select FB_SYS_COPYAREA
+       select FB_SYS_IMAGEBLIT
+       select FB_SYS_FOPS
+       select FB_DEFERRED_IO
+       ---help---
+         This is a kernel framebuffer driver for SMSC UFX USB devices.
+         Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and
+         mplayer -vo fbdev. Supports both UFX6000 (USB 2.0) and UFX7000
+         (USB 3.0) devices.
+         To compile as a module, choose M here: the module name is smscufx.
+
 config FB_UDL
        tristate "Displaylink USB Framebuffer support"
        depends on FB && USB
index 8b83129..9b9d8ff 100644 (file)
@@ -33,6 +33,7 @@ obj-$(CONFIG_FB_AMIGA)            += amifb.o c2p_planar.o
 obj-$(CONFIG_FB_ARC)              += arcfb.o
 obj-$(CONFIG_FB_CLPS711X)         += clps711xfb.o
 obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o
+obj-$(CONFIG_FB_GRVGA)            += grvga.o
 obj-$(CONFIG_FB_PM2)              += pm2fb.o
 obj-$(CONFIG_FB_PM3)             += pm3fb.o
 
@@ -127,6 +128,7 @@ obj-$(CONFIG_FB_IBM_GXT4500)          += gxt4500.o
 obj-$(CONFIG_FB_PS3)             += ps3fb.o
 obj-$(CONFIG_FB_SM501)            += sm501fb.o
 obj-$(CONFIG_FB_UDL)             += udlfb.o
+obj-$(CONFIG_FB_SMSCUFX)         += smscufx.o
 obj-$(CONFIG_FB_XILINX)           += xilinxfb.o
 obj-$(CONFIG_SH_MIPI_DSI)        += sh_mipi_dsi.o
 obj-$(CONFIG_FB_SH_MOBILE_HDMI)          += sh_mobile_hdmi.o
index 6183a57..b303f17 100644 (file)
@@ -850,9 +850,10 @@ acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
        u_int y_bottom = var->yoffset;
 
        if (!(var->vmode & FB_VMODE_YWRAP))
-               y_bottom += var->yres;
+               y_bottom += info->var.yres;
 
-       BUG_ON(y_bottom > var->yres_virtual);
+       if (y_bottom > info->var.yres_virtual)
+               return -EINVAL;
 
        acornfb_update_dma(info, var);
 
index 8686429..555dd4c 100644 (file)
@@ -908,13 +908,14 @@ static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info
        unsigned int offset;
 
        /* Calculate the offset */
-       if (var->bits_per_pixel == 0) {
-               offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2);
+       if (info->var.bits_per_pixel == 0) {
+               offset = (var->yoffset / 16) * (info->var.xres_virtual / 2)
+                      + (var->xoffset / 2);
                offset = offset >> 2;
        } else {
                offset = (var->yoffset * info->fix.line_length) +
-                        (var->xoffset * var->bits_per_pixel / 8);
-               offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 3);
+                        (var->xoffset * info->var.bits_per_pixel / 8);
+               offset = offset >> ((info->var.bits_per_pixel == 4) ? 2 : 3);
        }
 
        /* Set the offset */
index dda9206..4ac48d9 100644 (file)
@@ -39,7 +39,8 @@
                                         | FBINFO_HWACCEL_YPAN)
 
 static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-                                       struct fb_var_screeninfo *var)
+                                       struct fb_var_screeninfo *var,
+                                       struct fb_info *info)
 {
 
 }
@@ -50,14 +51,16 @@ static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
                                        | FBINFO_HWACCEL_YPAN)
 
 static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-                                    struct fb_var_screeninfo *var)
+                                    struct fb_var_screeninfo *var,
+                                    struct fb_info *info)
 {
        u32 dma2dcfg;
        u32 pixeloff;
 
-       pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
+       pixeloff = (var->xoffset * info->var.bits_per_pixel) & 0x1f;
 
-       dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
+       dma2dcfg = (info->var.xres_virtual - info->var.xres)
+                * info->var.bits_per_pixel / 8;
        dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
        lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
 
@@ -249,14 +252,14 @@ static void atmel_lcdfb_update_dma(struct fb_info *info,
        unsigned long dma_addr;
 
        dma_addr = (fix->smem_start + var->yoffset * fix->line_length
-                   + var->xoffset * var->bits_per_pixel / 8);
+                   + var->xoffset * info->var.bits_per_pixel / 8);
 
        dma_addr &= ~3UL;
 
        /* Set framebuffer DMA base address and pixel offset */
        lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
 
-       atmel_lcdfb_update_dma2d(sinfo, var);
+       atmel_lcdfb_update_dma2d(sinfo, var, info);
 }
 
 static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
index 32f8cf6..1506848 100644 (file)
@@ -845,16 +845,16 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var,
 {
         struct radeonfb_info *rinfo = info->par;
 
-        if ((var->xoffset + var->xres > var->xres_virtual)
-           || (var->yoffset + var->yres > var->yres_virtual))
-               return -EINVAL;
+       if ((var->xoffset + info->var.xres > info->var.xres_virtual)
+           || (var->yoffset + info->var.yres > info->var.yres_virtual))
+               return -EINVAL;
                 
         if (rinfo->asleep)
                return 0;
 
        radeon_fifo_wait(2);
-        OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
-                            * var->bits_per_pixel / 8) & ~7);
+       OUTREG(CRTC_OFFSET, (var->yoffset * info->fix.line_length +
+                            var->xoffset * info->var.bits_per_pixel / 8) & ~7);
         return 0;
 }
 
index 01a8fde..649cb35 100644 (file)
@@ -110,12 +110,6 @@ static struct fb_var_screeninfo au1100fb_var __devinitdata = {
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 
-static struct au1100fb_drv_info drv_info;
-
-static int nocursor = 0;
-module_param(nocursor, int, 0644);
-MODULE_PARM_DESC(nocursor, "cursor enable/disable");
-
 /* fb_blank
  * Blank the screen. Depending on the mode, the screen will be
  * activated with the backlight color, or desactivated
@@ -132,7 +126,7 @@ static int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
                        /* Turn on panel */
                        fbdev->regs->lcd_control |= LCD_CONTROL_GO;
 #ifdef CONFIG_MIPS_PB1100
-                       if (drv_info.panel_idx == 1) {
+                       if (fbdev->panel_idx == 1) {
                                au_writew(au_readw(PB1100_G_CONTROL)
                                          | (PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
                        PB1100_G_CONTROL);
@@ -147,7 +141,7 @@ static int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
                        /* Turn off panel */
                        fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
 #ifdef CONFIG_MIPS_PB1100
-                       if (drv_info.panel_idx == 1) {
+                       if (fbdev->panel_idx == 1) {
                                au_writew(au_readw(PB1100_G_CONTROL)
                                          & ~(PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
                        PB1100_G_CONTROL);
@@ -428,17 +422,6 @@ int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
        return 0;
 }
 
-/* fb_cursor
- * Used to disable cursor drawing...
- */
-int au1100fb_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
-{
-       if (nocursor)
-               return 0;
-       else
-               return -EINVAL; /* just to force soft_cursor() call */
-}
-
 static struct fb_ops au1100fb_ops =
 {
        .owner                  = THIS_MODULE,
@@ -450,13 +433,53 @@ static struct fb_ops au1100fb_ops =
        .fb_imageblit           = cfb_imageblit,
        .fb_rotate              = au1100fb_fb_rotate,
        .fb_mmap                = au1100fb_fb_mmap,
-       .fb_cursor              = au1100fb_fb_cursor,
 };
 
 
 /*-------------------------------------------------------------------------*/
 
-/* AU1100 LCD controller device driver */
+static int au1100fb_setup(struct au1100fb_device *fbdev)
+{
+       char *this_opt, *options;
+       int num_panels = ARRAY_SIZE(known_lcd_panels);
+
+       if (num_panels <= 0) {
+               print_err("No LCD panels supported by driver!");
+               return -ENODEV;
+       }
+
+       if (fb_get_options(DRIVER_NAME, &options))
+               return -ENODEV;
+       if (!options)
+               return -ENODEV;
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               /* Panel option */
+               if (!strncmp(this_opt, "panel:", 6)) {
+                       int i;
+                       this_opt += 6;
+                       for (i = 0; i < num_panels; i++) {
+                               if (!strncmp(this_opt, known_lcd_panels[i].name,
+                                            strlen(this_opt))) {
+                                       fbdev->panel = &known_lcd_panels[i];
+                                       fbdev->panel_idx = i;
+                                       break;
+                               }
+                       }
+                       if (i >= num_panels) {
+                               print_warn("Panel '%s' not supported!", this_opt);
+                               return -ENODEV;
+                       }
+               }
+               /* Unsupported option */
+               else
+                       print_warn("Unsupported option \"%s\"", this_opt);
+       }
+
+       print_info("Panel=%s", fbdev->panel->name);
+
+       return 0;
+}
 
 static int __devinit au1100fb_drv_probe(struct platform_device *dev)
 {
@@ -465,22 +488,21 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev)
        unsigned long page;
        u32 sys_clksrc;
 
-       if (!dev)
-                       return -EINVAL;
-
        /* Allocate new device private */
-       if (!(fbdev = kzalloc(sizeof(struct au1100fb_device), GFP_KERNEL))) {
+       fbdev = kzalloc(sizeof(struct au1100fb_device), GFP_KERNEL);
+       if (!fbdev) {
                print_err("fail to allocate device private record");
                return -ENOMEM;
        }
 
-       fbdev->panel = &known_lcd_panels[drv_info.panel_idx];
+       if (au1100fb_setup(fbdev))
+               goto failed;
 
        platform_set_drvdata(dev, (void *)fbdev);
 
        /* Allocate region for our registers and map them */
-       if (!(regs_res = platform_get_resource(to_platform_device(dev),
-                                       IORESOURCE_MEM, 0))) {
+       regs_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!regs_res) {
                print_err("fail to retrieve registers resource");
                return -EFAULT;
        }
@@ -500,13 +522,11 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev)
        print_dbg("Register memory map at %p", fbdev->regs);
        print_dbg("phys=0x%08x, size=%d", fbdev->regs_phys, fbdev->regs_len);
 
-
-
        /* Allocate the framebuffer to the maximum screen size * nbr of video buffers */
        fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres *
                        (fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS;
 
-       fbdev->fb_mem = dma_alloc_coherent(dev, PAGE_ALIGN(fbdev->fb_len),
+       fbdev->fb_mem = dma_alloc_coherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len),
                                        &fbdev->fb_phys, GFP_KERNEL);
        if (!fbdev->fb_mem) {
                print_err("fail to allocate frambuffer (size: %dK))",
@@ -525,7 +545,7 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev)
             page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len);
             page += PAGE_SIZE) {
 #if CONFIG_DMA_NONCOHERENT
-               SetPageReserved(virt_to_page(CAC_ADDR(page)));
+               SetPageReserved(virt_to_page(CAC_ADDR((void *)page)));
 #else
                SetPageReserved(virt_to_page(page));
 #endif
@@ -578,7 +598,8 @@ failed:
                release_mem_region(fbdev->regs_phys, fbdev->regs_len);
        }
        if (fbdev->fb_mem) {
-               dma_free_noncoherent(dev, fbdev->fb_len, fbdev->fb_mem, fbdev->fb_phys);
+               dma_free_noncoherent(&dev->dev, fbdev->fb_len, fbdev->fb_mem,
+                                    fbdev->fb_phys);
        }
        if (fbdev->info.cmap.len != 0) {
                fb_dealloc_cmap(&fbdev->info.cmap);
@@ -608,7 +629,8 @@ int au1100fb_drv_remove(struct platform_device *dev)
 
        release_mem_region(fbdev->regs_phys, fbdev->regs_len);
 
-       dma_free_coherent(dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, fbdev->fb_phys);
+       dma_free_coherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem,
+                         fbdev->fb_phys);
 
        fb_dealloc_cmap(&fbdev->info.cmap);
        kfree(fbdev->info.pseudo_palette);
@@ -675,101 +697,18 @@ static struct platform_driver au1100fb_driver = {
         .resume                = au1100fb_drv_resume,
 };
 
-/*-------------------------------------------------------------------------*/
-
-/* Kernel driver */
-
-int au1100fb_setup(char *options)
-{
-       char* this_opt;
-       int num_panels = ARRAY_SIZE(known_lcd_panels);
-       char* mode = NULL;
-       int panel_idx = 0;
-
-       if (num_panels <= 0) {
-               print_err("No LCD panels supported by driver!");
-               return -EFAULT;
-                       }
-
-       if (options) {
-               while ((this_opt = strsep(&options,",")) != NULL) {
-                       /* Panel option */
-                       if (!strncmp(this_opt, "panel:", 6)) {
-                               int i;
-                               this_opt += 6;
-                               for (i = 0; i < num_panels; i++) {
-                                       if (!strncmp(this_opt,
-                                                    known_lcd_panels[i].name,
-                                                       strlen(this_opt))) {
-                                               panel_idx = i;
-                                               break;
-                                       }
-                               }
-                               if (i >= num_panels) {
-                                       print_warn("Panel %s not supported!", this_opt);
-                               }
-                       }
-                       if (!strncmp(this_opt, "nocursor", 8)) {
-                               this_opt += 8;
-                               nocursor = 1;
-                               print_info("Cursor disabled");
-                       }
-                       /* Mode option (only option that start with digit) */
-                       else if (isdigit(this_opt[0])) {
-                               mode = kstrdup(this_opt, GFP_KERNEL);
-                               if (!mode) {
-                                       print_err("memory allocation failed");
-                                       return -ENOMEM;
-                               }
-                       }
-                       /* Unsupported option */
-                       else {
-                               print_warn("Unsupported option \"%s\"", this_opt);
-                       }
-               }
-       }
-
-       drv_info.panel_idx = panel_idx;
-       drv_info.opt_mode = mode;
-
-       print_info("Panel=%s Mode=%s",
-                       known_lcd_panels[drv_info.panel_idx].name,
-                       drv_info.opt_mode ? drv_info.opt_mode : "default");
-
-       return 0;
-}
-
-int __init au1100fb_init(void)
+static int __init au1100fb_load(void)
 {
-       char* options;
-       int ret;
-
-       print_info("" DRIVER_DESC "");
-
-       memset(&drv_info, 0, sizeof(drv_info));
-
-       if (fb_get_options(DRIVER_NAME, &options))
-               return -ENODEV;
-
-       /* Setup driver with options */
-       ret = au1100fb_setup(options);
-       if (ret < 0) {
-               print_err("Fail to setup driver");
-               return ret;
-       }
-
        return platform_driver_register(&au1100fb_driver);
 }
 
-void __exit au1100fb_cleanup(void)
+static void __exit au1100fb_unload(void)
 {
        platform_driver_unregister(&au1100fb_driver);
-
-       kfree(drv_info.opt_mode);
 }
 
-module_init(au1100fb_init);
-module_exit(au1100fb_cleanup);
+module_init(au1100fb_load);
+module_exit(au1100fb_unload);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
index 164fe2f..12d9642 100644 (file)
@@ -108,6 +108,7 @@ struct au1100fb_device {
        unsigned char*          fb_mem;         /* FrameBuffer memory map */
        size_t                  fb_len;
        dma_addr_t              fb_phys;
+       int                     panel_idx;
 };
 
 /********************************************************************/
@@ -364,11 +365,6 @@ static struct au1100fb_panel known_lcd_panels[] =
        },
 };
 
-struct au1100fb_drv_info {
-       int     panel_idx;
-       char    *opt_mode;
-};
-
 /********************************************************************/
 
 /* Inline helpers */
index 5dff32a..7200559 100644 (file)
 #include <asm/mach-au1x00/au1000.h>
 #include "au1200fb.h"
 
-#ifdef CONFIG_PM
-#include <asm/mach-au1x00/au1xxx_pm.h>
-#endif
-
-#ifndef CONFIG_FB_AU1200_DEVS
-#define CONFIG_FB_AU1200_DEVS 4
-#endif
-
 #define DRIVER_NAME "au1200fb"
 #define DRIVER_DESC "LCD controller driver for AU1200 processors"
 
-#define DEBUG 1
+#define DEBUG 0
 
 #define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
 #define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
@@ -150,7 +142,7 @@ struct au1200_lcd_iodata_t {
 
 /* Private, per-framebuffer management information (independent of the panel itself) */
 struct au1200fb_device {
-       struct fb_info fb_info;                 /* FB driver info record */
+       struct fb_info *fb_info;                /* FB driver info record */
 
        int                                     plane;
        unsigned char*          fb_mem;         /* FrameBuffer memory map */
@@ -158,7 +150,6 @@ struct au1200fb_device {
        dma_addr_t              fb_phys;
 };
 
-static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS];
 /********************************************************************/
 
 /* LCD controller restrictions */
@@ -171,10 +162,18 @@ static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS];
 /* Default number of visible screen buffer to allocate */
 #define AU1200FB_NBR_VIDEO_BUFFERS 1
 
+/* Default maximum number of fb devices to create */
+#define MAX_DEVICE_COUNT       4
+
+/* Default window configuration entry to use (see windows[]) */
+#define DEFAULT_WINDOW_INDEX   2
+
 /********************************************************************/
 
+static struct fb_info *_au1200fb_infos[MAX_DEVICE_COUNT];
 static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR;
-static int window_index = 2; /* default is zero */
+static int device_count = MAX_DEVICE_COUNT;
+static int window_index = DEFAULT_WINDOW_INDEX;        /* default is zero */
 static int panel_index = 2; /* default is zero */
 static struct window_settings *win;
 static struct panel_settings *panel;
@@ -205,12 +204,6 @@ struct window_settings {
 extern int board_au1200fb_panel_init (void);
 extern int board_au1200fb_panel_shutdown (void);
 
-#ifdef CONFIG_PM
-int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
-               au1xxx_request_t request, void *data);
-au1xxx_power_dev_t *LCD_pm_dev;
-#endif
-
 /*
  * Default window configurations
  */
@@ -652,25 +645,6 @@ static struct panel_settings known_lcd_panels[] =
 
 /********************************************************************/
 
-#ifdef CONFIG_PM
-static int set_brightness(unsigned int brightness)
-{
-       unsigned int hi1, divider;
-
-       /* limit brightness pwm duty to >= 30/1600 */
-       if (brightness < 30) {
-               brightness = 30;
-       }
-       divider = (lcd->pwmdiv & 0x3FFFF) + 1;
-       hi1 = (lcd->pwmhi >> 16) + 1;
-       hi1 = (((brightness & 0xFF) + 1) * divider >> 8);
-       lcd->pwmhi &= 0xFFFF;
-       lcd->pwmhi |= (hi1 << 16);
-
-       return brightness;
-}
-#endif /* CONFIG_PM */
-
 static int winbpp (unsigned int winctrl1)
 {
        int bits = 0;
@@ -712,8 +686,8 @@ static int fbinfo2index (struct fb_info *fb_info)
 {
        int i;
 
-       for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) {
-               if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info))
+       for (i = 0; i < device_count; ++i) {
+               if (fb_info == _au1200fb_infos[i])
                        return i;
        }
        printk("au1200fb: ERROR: fbinfo2index failed!\n");
@@ -962,7 +936,7 @@ static void au1200_setmode(struct au1200fb_device *fbdev)
        lcd->window[plane].winctrl2 = ( 0
                | LCD_WINCTRL2_CKMODE_00
                | LCD_WINCTRL2_DBM
-               | LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length)
+               | LCD_WINCTRL2_BX_N(fbdev->fb_info->fix.line_length)
                | LCD_WINCTRL2_SCX_1
                | LCD_WINCTRL2_SCY_1
                ) ;
@@ -1050,7 +1024,7 @@ static void au1200fb_update_fbinfo(struct fb_info *fbi)
 static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
        struct fb_info *fbi)
 {
-       struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
+       struct au1200fb_device *fbdev = fbi->par;
        u32 pixclock;
        int screen_size, plane;
 
@@ -1142,7 +1116,7 @@ static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
  */
 static int au1200fb_fb_set_par(struct fb_info *fbi)
 {
-       struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
+       struct au1200fb_device *fbdev = fbi->par;
 
        au1200fb_update_fbinfo(fbi);
        au1200_setmode(fbdev);
@@ -1246,11 +1220,7 @@ static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        unsigned int len;
        unsigned long start=0, off;
-       struct au1200fb_device *fbdev = (struct au1200fb_device *) info;
-
-#ifdef CONFIG_PM
-       au1xxx_pm_access(LCD_pm_dev);
-#endif
+       struct au1200fb_device *fbdev = info->par;
 
        if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
                return -EINVAL;
@@ -1461,10 +1431,6 @@ static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
        int plane;
        int val;
 
-#ifdef CONFIG_PM
-       au1xxx_pm_access(LCD_pm_dev);
-#endif
-
        plane = fbinfo2index(info);
        print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane);
 
@@ -1536,9 +1502,11 @@ static struct fb_ops au1200fb_fb_ops = {
        .fb_set_par     = au1200fb_fb_set_par,
        .fb_setcolreg   = au1200fb_fb_setcolreg,
        .fb_blank       = au1200fb_fb_blank,
-       .fb_fillrect    = cfb_fillrect,
-       .fb_copyarea    = cfb_copyarea,
-       .fb_imageblit   = cfb_imageblit,
+       .fb_fillrect    = sys_fillrect,
+       .fb_copyarea    = sys_copyarea,
+       .fb_imageblit   = sys_imageblit,
+       .fb_read        = fb_sys_read,
+       .fb_write       = fb_sys_write,
        .fb_sync        = NULL,
        .fb_ioctl       = au1200fb_ioctl,
        .fb_mmap        = au1200fb_fb_mmap,
@@ -1561,10 +1529,9 @@ static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id)
 
 static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
 {
-       struct fb_info *fbi = &fbdev->fb_info;
+       struct fb_info *fbi = fbdev->fb_info;
        int bpp;
 
-       memset(fbi, 0, sizeof(struct fb_info));
        fbi->fbops = &au1200fb_fb_ops;
 
        bpp = winbpp(win->w[fbdev->plane].mode_winctrl1);
@@ -1623,24 +1590,36 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
 
 /* AU1200 LCD controller device driver */
 
-static int au1200fb_drv_probe(struct platform_device *dev)
+static int __devinit au1200fb_drv_probe(struct platform_device *dev)
 {
        struct au1200fb_device *fbdev;
+       struct fb_info *fbi = NULL;
        unsigned long page;
-       int bpp, plane, ret;
+       int bpp, plane, ret, irq;
 
-       if (!dev)
-               return -EINVAL;
+       /* shut gcc up */
+       ret = 0;
+       fbdev = NULL;
+
+       /* Kickstart the panel */
+       au1200_setpanel(panel);
 
-       for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) {
+       for (plane = 0; plane < device_count; ++plane) {
                bpp = winbpp(win->w[plane].mode_winctrl1);
                if (win->w[plane].xres == 0)
                        win->w[plane].xres = panel->Xres;
                if (win->w[plane].yres == 0)
                        win->w[plane].yres = panel->Yres;
 
-               fbdev = &_au1200fb_devices[plane];
-               memset(fbdev, 0, sizeof(struct au1200fb_device));
+               fbi = framebuffer_alloc(sizeof(struct au1200fb_device),
+                                       &dev->dev);
+               if (!fbi)
+                       goto failed;
+
+               _au1200fb_infos[plane] = fbi;
+               fbdev = fbi->par;
+               fbdev->fb_info = fbi;
+
                fbdev->plane = plane;
 
                /* Allocate the framebuffer to the maximum screen size */
@@ -1673,30 +1652,31 @@ static int au1200fb_drv_probe(struct platform_device *dev)
                        goto failed;
 
                /* Register new framebuffer */
-               if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) {
+               ret = register_framebuffer(fbi);
+               if (ret < 0) {
                        print_err("cannot register new framebuffer");
                        goto failed;
                }
 
-               au1200fb_fb_set_par(&fbdev->fb_info);
+               au1200fb_fb_set_par(fbi);
 
 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
                if (plane == 0)
-                       if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) {
+                       if (fb_prepare_logo(fbi, FB_ROTATE_UR)) {
                                /* Start display and show logo on boot */
-                               fb_set_cmap(&fbdev->fb_info.cmap,
-                                               &fbdev->fb_info);
-
-                               fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR);
+                               fb_set_cmap(&fbi->cmap, fbi);
+                               fb_show_logo(fbi, FB_ROTATE_UR);
                        }
 #endif
        }
 
        /* Now hook interrupt too */
-       if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq,
-                         IRQF_DISABLED | IRQF_SHARED, "lcd", (void *)dev)) < 0) {
+       irq = platform_get_irq(dev, 0);
+       ret = request_irq(irq, au1200fb_handle_irq,
+                         IRQF_SHARED, "lcd", (void *)dev);
+       if (ret) {
                print_err("fail to request interrupt line %d (err: %d)",
-                         AU1200_LCD_INT, ret);
+                         irq, ret);
                goto failed;
        }
 
@@ -1705,84 +1685,108 @@ static int au1200fb_drv_probe(struct platform_device *dev)
 failed:
        /* NOTE: This only does the current plane/window that failed; others are still active */
        if (fbdev->fb_mem)
-               dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
+               dma_free_noncoherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len),
                                fbdev->fb_mem, fbdev->fb_phys);
-       if (fbdev->fb_info.cmap.len != 0)
-               fb_dealloc_cmap(&fbdev->fb_info.cmap);
-       if (fbdev->fb_info.pseudo_palette)
-               kfree(fbdev->fb_info.pseudo_palette);
+       if (fbi) {
+               if (fbi->cmap.len != 0)
+                       fb_dealloc_cmap(&fbi->cmap);
+               kfree(fbi->pseudo_palette);
+       }
        if (plane == 0)
                free_irq(AU1200_LCD_INT, (void*)dev);
        return ret;
 }
 
-static int au1200fb_drv_remove(struct platform_device *dev)
+static int __devexit au1200fb_drv_remove(struct platform_device *dev)
 {
        struct au1200fb_device *fbdev;
+       struct fb_info *fbi;
        int plane;
 
-       if (!dev)
-               return -ENODEV;
-
        /* Turn off the panel */
        au1200_setpanel(NULL);
 
-       for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane)
-       {
-               fbdev = &_au1200fb_devices[plane];
+       for (plane = 0; plane < device_count; ++plane)  {
+               fbi = _au1200fb_infos[plane];
+               fbdev = fbi->par;
 
                /* Clean up all probe data */
-               unregister_framebuffer(&fbdev->fb_info);
+               unregister_framebuffer(fbi);
                if (fbdev->fb_mem)
                        dma_free_noncoherent(&dev->dev,
                                        PAGE_ALIGN(fbdev->fb_len),
                                        fbdev->fb_mem, fbdev->fb_phys);
-               if (fbdev->fb_info.cmap.len != 0)
-                       fb_dealloc_cmap(&fbdev->fb_info.cmap);
-               if (fbdev->fb_info.pseudo_palette)
-                       kfree(fbdev->fb_info.pseudo_palette);
+               if (fbi->cmap.len != 0)
+                       fb_dealloc_cmap(&fbi->cmap);
+               kfree(fbi->pseudo_palette);
+
+               framebuffer_release(fbi);
+               _au1200fb_infos[plane] = NULL;
        }
 
-       free_irq(AU1200_LCD_INT, (void *)dev);
+       free_irq(platform_get_irq(dev, 0), (void *)dev);
 
        return 0;
 }
 
 #ifdef CONFIG_PM
-static int au1200fb_drv_suspend(struct platform_device *dev, u32 state)
+static int au1200fb_drv_suspend(struct device *dev)
 {
-       /* TODO */
+       au1200_setpanel(NULL);
+
+       lcd->outmask = 0;
+       au_sync();
+
        return 0;
 }
 
-static int au1200fb_drv_resume(struct platform_device *dev)
+static int au1200fb_drv_resume(struct device *dev)
 {
-       /* TODO */
+       struct fb_info *fbi;
+       int i;
+
+       /* Kickstart the panel */
+       au1200_setpanel(panel);
+
+       for (i = 0; i < device_count; i++) {
+               fbi = _au1200fb_infos[i];
+               au1200fb_fb_set_par(fbi);
+       }
+
        return 0;
 }
+
+static const struct dev_pm_ops au1200fb_pmops = {
+       .suspend        = au1200fb_drv_suspend,
+       .resume         = au1200fb_drv_resume,
+       .freeze         = au1200fb_drv_suspend,
+       .thaw           = au1200fb_drv_resume,
+};
+
+#define AU1200FB_PMOPS (&au1200fb_pmops)
+
+#else
+#define AU1200FB_PMOPS NULL
 #endif /* CONFIG_PM */
 
 static struct platform_driver au1200fb_driver = {
        .driver = {
-               .name           = "au1200-lcd",
-               .owner          = THIS_MODULE,
+               .name   = "au1200-lcd",
+               .owner  = THIS_MODULE,
+               .pm     = AU1200FB_PMOPS,
        },
        .probe          = au1200fb_drv_probe,
-       .remove         = au1200fb_drv_remove,
-#ifdef CONFIG_PM
-       .suspend        = au1200fb_drv_suspend,
-       .resume         = au1200fb_drv_resume,
-#endif
+       .remove         = __devexit_p(au1200fb_drv_remove),
 };
 
 /*-------------------------------------------------------------------------*/
 
 /* Kernel driver */
 
-static void au1200fb_setup(void)
+static int au1200fb_setup(void)
 {
-       charoptions = NULL;
-       char* this_opt;
+       char *options = NULL;
+       char *this_opt, *endptr;
        int num_panels = ARRAY_SIZE(known_lcd_panels);
        int panel_idx = -1;
 
@@ -1827,70 +1831,42 @@ static void au1200fb_setup(void)
                                nohwcursor = 1;
                        }
 
-                       /* Unsupported option */
-                       else {
-                               print_warn("Unsupported option \"%s\"", this_opt);
+                       else if (strncmp(this_opt, "devices:", 8) == 0) {
+                               this_opt += 8;
+                               device_count = simple_strtol(this_opt,
+                                                            &endptr, 0);
+                               if ((device_count < 0) ||
+                                   (device_count > MAX_DEVICE_COUNT))
+                                       device_count = MAX_DEVICE_COUNT;
                        }
-               }
-       }
-}
 
-#ifdef CONFIG_PM
-static int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
-               au1xxx_request_t request, void *data) {
-       int retval = -1;
-       unsigned int d = 0;
-       unsigned int brightness = 0;
-
-       if (request == AU1XXX_PM_SLEEP) {
-               board_au1200fb_panel_shutdown();
-       }
-       else if (request == AU1XXX_PM_WAKEUP) {
-               if(dev->prev_state == SLEEP_STATE)
-               {
-                       int plane;
-                       au1200_setpanel(panel);
-                       for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane)         {
-                               struct au1200fb_device *fbdev;
-                               fbdev = &_au1200fb_devices[plane];
-                               au1200fb_fb_set_par(&fbdev->fb_info);
+                       else if (strncmp(this_opt, "wincfg:", 7) == 0) {
+                               this_opt += 7;
+                               window_index = simple_strtol(this_opt,
+                                                            &endptr, 0);
+                               if ((window_index < 0) ||
+                                   (window_index >= ARRAY_SIZE(windows)))
+                                       window_index = DEFAULT_WINDOW_INDEX;
                        }
-               }
 
-               d = *((unsigned int*)data);
-               if(d <=10) brightness = 26;
-               else if(d<=20) brightness = 51;
-               else if(d<=30) brightness = 77;
-               else if(d<=40) brightness = 102;
-               else if(d<=50) brightness = 128;
-               else if(d<=60) brightness = 153;
-               else if(d<=70) brightness = 179;
-               else if(d<=80) brightness = 204;
-               else if(d<=90) brightness = 230;
-               else brightness = 255;
-               set_brightness(brightness);
-       } else if (request == AU1XXX_PM_GETSTATUS) {
-               return dev->cur_state;
-       } else if (request == AU1XXX_PM_ACCESS) {
-               if (dev->cur_state != SLEEP_STATE)
-                       return retval;
-               else {
-                       au1200_setpanel(panel);
+                       else if (strncmp(this_opt, "off", 3) == 0)
+                               return 1;
+                       /* Unsupported option */
+                       else {
+                               print_warn("Unsupported option \"%s\"", this_opt);
+                       }
                }
-       } else if (request == AU1XXX_PM_IDLE) {
-       } else if (request == AU1XXX_PM_CLEANUP) {
        }
-
-       return retval;
+       return 0;
 }
-#endif
 
 static int __init au1200fb_init(void)
 {
        print_info("" DRIVER_DESC "");
 
        /* Setup driver with options */
-       au1200fb_setup();
+       if (au1200fb_setup())
+               return -ENODEV;
 
        /* Point to the panel selected */
        panel = &known_lcd_panels[panel_index];
@@ -1899,17 +1875,6 @@ static int __init au1200fb_init(void)
        printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
        printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
 
-       /* Kickstart the panel, the framebuffers/windows come soon enough */
-       au1200_setpanel(panel);
-
-       #ifdef CONFIG_PM
-       LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL);
-       if ( LCD_pm_dev == NULL)
-               printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n");
-       else
-               printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n");
-       #endif
-
        return platform_driver_register(&au1200fb_driver);
 }
 
index 183b6f6..66bc74d 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/pm.h>
index d06886a..98e0304 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/pm.h>
index 2464b91..56720fb 100644 (file)
@@ -633,7 +633,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
                goto out7;
        }
 
-       if (request_irq(info->irq, bfin_bf54x_irq_error, IRQF_DISABLED,
+       if (request_irq(info->irq, bfin_bf54x_irq_error, 0,
                        "PPI ERROR", info) < 0) {
                printk(KERN_ERR DRIVER_NAME
                       ": unable to request PPI ERROR IRQ\n");
index 23b6c4b..c633068 100644 (file)
@@ -695,7 +695,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
                goto out7;
        }
 
-       ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED,
+       ret = request_irq(info->irq, bfin_lq035q1_irq_error, 0,
                        DRIVER_NAME" PPI ERROR", info);
        if (ret < 0) {
                dev_err(&pdev->dev, "unable to request PPI ERROR IRQ\n");
index d8de29f..d5e1267 100644 (file)
@@ -529,7 +529,7 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
                goto out7;
        }
 
-       ret = request_irq(info->irq, bfin_t350mcqb_irq_error, IRQF_DISABLED,
+       ret = request_irq(info->irq, bfin_t350mcqb_irq_error, 0,
                        "PPI ERROR", info);
        if (ret < 0) {
                printk(KERN_ERR DRIVER_NAME
index 8486f54..811dd7f 100644 (file)
@@ -481,7 +481,7 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client,
                goto out_4;
        }
 
-       if (request_irq(IRQ_PPI_ERROR, ppi_irq_error, IRQF_DISABLED,
+       if (request_irq(IRQ_PPI_ERROR, ppi_irq_error, 0,
                        "PPI ERROR", fbdev) < 0) {
                dev_err(&client->dev, "unable to request PPI ERROR IRQ\n");
                ret = -EFAULT;
index caaa27d..cb09aa1 100644 (file)
 #define CARMINEFB_DEFAULT_VIDEO_MODE   1
 
 static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
-module_param(fb_mode, uint, 444);
+module_param(fb_mode, uint, 0444);
 MODULE_PARM_DESC(fb_mode, "Initial video mode as integer.");
 
 static char *fb_mode_str;
-module_param(fb_mode_str, charp, 444);
+module_param(fb_mode_str, charp, 0444);
 MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
 
 /*
@@ -46,7 +46,7 @@ MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
  * 0b010 Display 1
  */
 static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1;
-module_param(fb_displays, int, 444);
+module_param(fb_displays, int, 0444);
 MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used");
 
 struct carmine_hw {
index 9075bea..7b2c40a 100644 (file)
@@ -550,7 +550,7 @@ static void control_set_hardware(struct fb_info_control *p, struct fb_par_contro
 
 
 /*
- * Parse user speficied options (`video=controlfb:')
+ * Parse user specified options (`video=controlfb:')
  */
 static void __init control_setup(char *options)
 {
index fcdac87..55f91d9 100644 (file)
@@ -35,6 +35,9 @@
 
 #define DRIVER_NAME "da8xx_lcdc"
 
+#define LCD_VERSION_1  1
+#define LCD_VERSION_2  2
+
 /* LCD Status Register */
 #define LCD_END_OF_FRAME1              BIT(9)
 #define LCD_END_OF_FRAME0              BIT(8)
@@ -49,7 +52,9 @@
 #define LCD_DMA_BURST_4                        0x2
 #define LCD_DMA_BURST_8                        0x3
 #define LCD_DMA_BURST_16               0x4
-#define LCD_END_OF_FRAME_INT_ENA       BIT(2)
+#define LCD_V1_END_OF_FRAME_INT_ENA    BIT(2)
+#define LCD_V2_END_OF_FRAME0_INT_ENA   BIT(8)
+#define LCD_V2_END_OF_FRAME1_INT_ENA   BIT(9)
 #define LCD_DUAL_FRAME_BUFFER_ENABLE   BIT(0)
 
 /* LCD Control Register */
 #define LCD_MONO_8BIT_MODE             BIT(9)
 #define LCD_RASTER_ORDER               BIT(8)
 #define LCD_TFT_MODE                   BIT(7)
-#define LCD_UNDERFLOW_INT_ENA          BIT(6)
-#define LCD_PL_ENABLE                  BIT(4)
+#define LCD_V1_UNDERFLOW_INT_ENA       BIT(6)
+#define LCD_V2_UNDERFLOW_INT_ENA       BIT(5)
+#define LCD_V1_PL_INT_ENA              BIT(4)
+#define LCD_V2_PL_INT_ENA              BIT(6)
 #define LCD_MONOCHROME_MODE            BIT(1)
 #define LCD_RASTER_ENABLE              BIT(0)
 #define LCD_TFT_ALT_ENABLE             BIT(23)
 #define LCD_STN_565_ENABLE             BIT(24)
+#define LCD_V2_DMA_CLK_EN              BIT(2)
+#define LCD_V2_LIDD_CLK_EN             BIT(1)
+#define LCD_V2_CORE_CLK_EN             BIT(0)
+#define LCD_V2_LPP_B10                 26
 
 /* LCD Raster Timing 2 Register */
 #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x)     ((x) << 16)
@@ -82,6 +93,7 @@
 #define LCD_INVERT_FRAME_CLOCK                 BIT(20)
 
 /* LCD Block */
+#define  LCD_PID_REG                           0x0
 #define  LCD_CTRL_REG                          0x4
 #define  LCD_STAT_REG                          0x8
 #define  LCD_RASTER_CTRL_REG                   0x28
 #define  LCD_DMA_FRM_BUF_BASE_ADDR_1_REG       0x4C
 #define  LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG    0x50
 
+/* Interrupt Registers available only in Version 2 */
+#define  LCD_RAW_STAT_REG                      0x58
+#define  LCD_MASKED_STAT_REG                   0x5c
+#define  LCD_INT_ENABLE_SET_REG                        0x60
+#define  LCD_INT_ENABLE_CLR_REG                        0x64
+#define  LCD_END_OF_INT_IND_REG                        0x68
+
+/* Clock registers available only on Version 2 */
+#define  LCD_CLK_ENABLE_REG                    0x6c
+#define  LCD_CLK_RESET_REG                     0x70
+
 #define LCD_NUM_BUFFERS        2
 
 #define WSI_TIMEOUT    50
 
 static resource_size_t da8xx_fb_reg_base;
 static struct resource *lcdc_regs;
+static unsigned int lcd_revision;
+static irq_handler_t lcdc_irq_handler;
 
 static inline unsigned int lcdc_read(unsigned int addr)
 {
@@ -240,6 +265,7 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
        u32 end;
        u32 reg_ras;
        u32 reg_dma;
+       u32 reg_int;
 
        /* init reg to clear PLM (loading mode) fields */
        reg_ras = lcdc_read(LCD_RASTER_CTRL_REG);
@@ -252,7 +278,14 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
                end      = par->dma_end;
 
                reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY);
-               reg_dma |= LCD_END_OF_FRAME_INT_ENA;
+               if (lcd_revision == LCD_VERSION_1) {
+                       reg_dma |= LCD_V1_END_OF_FRAME_INT_ENA;
+               } else {
+                       reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
+                               LCD_V2_END_OF_FRAME0_INT_ENA |
+                               LCD_V2_END_OF_FRAME1_INT_ENA;
+                       lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
+               }
                reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
 
                lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
@@ -264,7 +297,14 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
                end      = start + par->palette_sz - 1;
 
                reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
-               reg_ras |= LCD_PL_ENABLE;
+
+               if (lcd_revision == LCD_VERSION_1) {
+                       reg_ras |= LCD_V1_PL_INT_ENA;
+               } else {
+                       reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
+                               LCD_V2_PL_INT_ENA;
+                       lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
+               }
 
                lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
                lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
@@ -348,6 +388,7 @@ static void lcd_cfg_vertical_sync(int back_porch, int pulse_width,
 static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
 {
        u32 reg;
+       u32 reg_int;
 
        reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE |
                                                LCD_MONO_8BIT_MODE |
@@ -375,7 +416,13 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
        }
 
        /* enable additional interrupts here */
-       reg |= LCD_UNDERFLOW_INT_ENA;
+       if (lcd_revision == LCD_VERSION_1) {
+               reg |= LCD_V1_UNDERFLOW_INT_ENA;
+       } else {
+               reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
+                       LCD_V2_UNDERFLOW_INT_ENA;
+               lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
+       }
 
        lcdc_write(reg, LCD_RASTER_CTRL_REG);
 
@@ -413,18 +460,43 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
 
        /* Set the Panel Width */
        /* Pixels per line = (PPL + 1)*16 */
-       /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/
-       width &= 0x3f0;
+       if (lcd_revision == LCD_VERSION_1) {
+               /*
+                * 0x3F in bits 4..9 gives max horizontal resolution = 1024
+                * pixels.
+                */
+               width &= 0x3f0;
+       } else {
+               /*
+                * 0x7F in bits 4..10 gives max horizontal resolution = 2048
+                * pixels.
+                */
+               width &= 0x7f0;
+       }
+
        reg = lcdc_read(LCD_RASTER_TIMING_0_REG);
        reg &= 0xfffffc00;
-       reg |= ((width >> 4) - 1) << 4;
+       if (lcd_revision == LCD_VERSION_1) {
+               reg |= ((width >> 4) - 1) << 4;
+       } else {
+               width = (width >> 4) - 1;
+               reg |= ((width & 0x3f) << 4) | ((width & 0x40) >> 3);
+       }
        lcdc_write(reg, LCD_RASTER_TIMING_0_REG);
 
        /* Set the Panel Height */
+       /* Set bits 9:0 of Lines Per Pixel */
        reg = lcdc_read(LCD_RASTER_TIMING_1_REG);
        reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00);
        lcdc_write(reg, LCD_RASTER_TIMING_1_REG);
 
+       /* Set bit 10 of Lines Per Pixel */
+       if (lcd_revision == LCD_VERSION_2) {
+               reg = lcdc_read(LCD_RASTER_TIMING_2_REG);
+               reg |= ((height - 1) & 0x400) << 16;
+               lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
+       }
+
        /* Set the Raster Order of the Frame Buffer */
        reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8);
        if (raster_order)
@@ -511,6 +583,9 @@ static void lcd_reset(struct da8xx_fb_par *par)
        /* DMA has to be disabled */
        lcdc_write(0, LCD_DMA_CTRL_REG);
        lcdc_write(0, LCD_RASTER_CTRL_REG);
+
+       if (lcd_revision == LCD_VERSION_2)
+               lcdc_write(0, LCD_INT_ENABLE_SET_REG);
 }
 
 static void lcd_calc_clk_divider(struct da8xx_fb_par *par)
@@ -523,6 +598,11 @@ static void lcd_calc_clk_divider(struct da8xx_fb_par *par)
        /* Configure the LCD clock divisor. */
        lcdc_write(LCD_CLK_DIVISOR(div) |
                        (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG);
+
+       if (lcd_revision == LCD_VERSION_2)
+               lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN |
+                               LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG);
+
 }
 
 static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
@@ -583,7 +663,63 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
        return 0;
 }
 
-static irqreturn_t lcdc_irq_handler(int irq, void *arg)
+/* IRQ handler for version 2 of LCDC */
+static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
+{
+       struct da8xx_fb_par *par = arg;
+       u32 stat = lcdc_read(LCD_MASKED_STAT_REG);
+       u32 reg_int;
+
+       if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
+               lcd_disable_raster();
+               lcdc_write(stat, LCD_MASKED_STAT_REG);
+               lcd_enable_raster();
+       } else if (stat & LCD_PL_LOAD_DONE) {
+               /*
+                * Must disable raster before changing state of any control bit.
+                * And also must be disabled before clearing the PL loading
+                * interrupt via the following write to the status register. If
+                * this is done after then one gets multiple PL done interrupts.
+                */
+               lcd_disable_raster();
+
+               lcdc_write(stat, LCD_MASKED_STAT_REG);
+
+               /* Disable PL completion inerrupt */
+               reg_int = lcdc_read(LCD_INT_ENABLE_CLR_REG) |
+                      (LCD_V2_PL_INT_ENA);
+               lcdc_write(reg_int, LCD_INT_ENABLE_CLR_REG);
+
+               /* Setup and start data loading mode */
+               lcd_blit(LOAD_DATA, par);
+       } else {
+               lcdc_write(stat, LCD_MASKED_STAT_REG);
+
+               if (stat & LCD_END_OF_FRAME0) {
+                       lcdc_write(par->dma_start,
+                                  LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+                       lcdc_write(par->dma_end,
+                                  LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+                       par->vsync_flag = 1;
+                       wake_up_interruptible(&par->vsync_wait);
+               }
+
+               if (stat & LCD_END_OF_FRAME1) {
+                       lcdc_write(par->dma_start,
+                                  LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
+                       lcdc_write(par->dma_end,
+                                  LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
+                       par->vsync_flag = 1;
+                       wake_up_interruptible(&par->vsync_wait);
+               }
+       }
+
+       lcdc_write(0, LCD_END_OF_INT_IND_REG);
+       return IRQ_HANDLED;
+}
+
+/* IRQ handler for version 1 LCDC */
+static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
 {
        struct da8xx_fb_par *par = arg;
        u32 stat = lcdc_read(LCD_STAT_REG);
@@ -606,7 +742,7 @@ static irqreturn_t lcdc_irq_handler(int irq, void *arg)
 
                /* Disable PL completion inerrupt */
                reg_ras  = lcdc_read(LCD_RASTER_CTRL_REG);
-               reg_ras &= ~LCD_PL_ENABLE;
+               reg_ras &= ~LCD_V1_PL_INT_ENA;
                lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);
 
                /* Setup and start data loading mode */
@@ -877,8 +1013,8 @@ static int da8xx_pan_display(struct fb_var_screeninfo *var,
 
                        start   = fix->smem_start +
                                new_var.yoffset * fix->line_length +
-                               new_var.xoffset * var->bits_per_pixel / 8;
-                       end     = start + var->yres * fix->line_length - 1;
+                               new_var.xoffset * fbi->var.bits_per_pixel / 8;
+                       end     = start + fbi->var.yres * fix->line_length - 1;
                        par->dma_start  = start;
                        par->dma_end    = end;
                }
@@ -945,6 +1081,22 @@ static int __devinit fb_probe(struct platform_device *device)
        if (ret)
                goto err_clk_put;
 
+       /* Determine LCD IP Version */
+       switch (lcdc_read(LCD_PID_REG)) {
+       case 0x4C100102:
+               lcd_revision = LCD_VERSION_1;
+               break;
+       case 0x4F200800:
+               lcd_revision = LCD_VERSION_2;
+               break;
+       default:
+               dev_warn(&device->dev, "Unknown PID Reg value 0x%x, "
+                               "defaulting to LCD revision 1\n",
+                               lcdc_read(LCD_PID_REG));
+               lcd_revision = LCD_VERSION_1;
+               break;
+       }
+
        for (i = 0, lcdc_info = known_lcd_panels;
                i < ARRAY_SIZE(known_lcd_panels);
                i++, lcdc_info++) {
@@ -1085,7 +1237,13 @@ static int __devinit fb_probe(struct platform_device *device)
        }
 #endif
 
-       ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par);
+       if (lcd_revision == LCD_VERSION_1)
+               lcdc_irq_handler = lcdc_irq_handler_rev01;
+       else
+               lcdc_irq_handler = lcdc_irq_handler_rev02;
+
+       ret = request_irq(par->irq, lcdc_irq_handler, 0,
+                       DRIVER_NAME, par);
        if (ret)
                goto irq_freq;
        return 0;
index 27f2c57..60a787f 100644 (file)
@@ -624,8 +624,8 @@ static int unifb_pan_display(struct fb_var_screeninfo *var,
                    || var->xoffset)
                        return -EINVAL;
        } else {
-               if (var->xoffset + var->xres > info->var.xres_virtual ||
-                   var->yoffset + var->yres > info->var.yres_virtual)
+               if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+                   var->yoffset + info->var.yres > info->var.yres_virtual)
                        return -EINVAL;
        }
        info->var.xoffset = var->xoffset;
index 32814e8..c27e153 100644 (file)
@@ -223,8 +223,7 @@ void fb_deferred_io_cleanup(struct fb_info *info)
        int i;
 
        BUG_ON(!fbdefio);
-       cancel_delayed_work(&info->deferred_work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&info->deferred_work);
 
        /* clear out the mapping that we setup */
        for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) {
index 5aac00e..ad93629 100644 (file)
@@ -1738,8 +1738,6 @@ void fb_set_suspend(struct fb_info *info, int state)
 {
        struct fb_event event;
 
-       if (!lock_fb_info(info))
-               return;
        event.info = info;
        if (state) {
                fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
@@ -1748,7 +1746,6 @@ void fb_set_suspend(struct fb_info *info, int state)
                info->state = FBINFO_STATE_RUNNING;
                fb_notifier_call_chain(FB_EVENT_RESUME, &event);
        }
-       unlock_fb_info(info);
 }
 
 /**
index 4f57485..cef6557 100644 (file)
@@ -493,7 +493,8 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
        return num;
 }
 
-static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
+static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
+               int ver, int rev)
 {
        int xres, yres = 0, refresh, ratio, i;
 
@@ -504,7 +505,11 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
        ratio = (block[1] & 0xc0) >> 6;
        switch (ratio) {
        case 0:
-               yres = xres;
+               /* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */
+               if (ver < 1 || (ver == 1 && rev < 3))
+                       yres = xres;
+               else
+                       yres = (xres * 10)/16;
                break;
        case 1:
                yres = (xres * 3)/4;
@@ -533,12 +538,12 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
 }
 
 static int get_dst_timing(unsigned char *block,
-                         struct fb_videomode *mode)
+                         struct fb_videomode *mode, int ver, int rev)
 {
        int j, num = 0;
 
        for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
-               num += get_std_timing(block, &mode[num]);
+               num += get_std_timing(block, &mode[num], ver, rev);
 
        return num;
 }
@@ -599,6 +604,10 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
        struct fb_videomode *mode, *m;
        unsigned char *block;
        int num = 0, i, first = 1;
+       int ver, rev;
+
+       ver = edid[EDID_STRUCT_VERSION];
+       rev = edid[EDID_STRUCT_REVISION];
 
        mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
        if (mode == NULL)
@@ -632,12 +641,12 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
        DPRINTK("   Standard Timings\n");
        block = edid + STD_TIMING_DESCRIPTIONS_START;
        for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
-               num += get_std_timing(block, &mode[num]);
+               num += get_std_timing(block, &mode[num], ver, rev);
 
        block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
        for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
                if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
-                       num += get_dst_timing(block + 5, &mode[num]);
+                       num += get_dst_timing(block + 5, &mode[num], ver, rev);
        }
 
        /* Yikes, EDID data is totally useless */
index 04251ce..67afa9c 100644 (file)
@@ -399,9 +399,12 @@ static ssize_t store_fbstate(struct device *device,
 
        state = simple_strtoul(buf, &last, 0);
 
+       if (!lock_fb_info(fb_info))
+               return -ENODEV;
        console_lock();
        fb_set_suspend(fb_info, (int)state);
        console_unlock();
+       unlock_fb_info(fb_info);
 
        return count;
 }
index 0acc7d6..a16beeb 100644 (file)
 #include <linux/clk.h>
 #include <linux/uaccess.h>
 #include <linux/vmalloc.h>
-
-#include <linux/of_platform.h>
+#include <linux/spinlock.h>
 
 #include <sysdev/fsl_soc.h>
 #include <linux/fsl-diu-fb.h>
 #include "edid.h"
 
-/*
- * These parameters give default parameters
- * for video output 1024x768,
- * FIXME - change timing to proper amounts
- * hsync 31.5kHz, vsync 60Hz
- */
-static struct fb_videomode __devinitdata fsl_diu_default_mode = {
-       .refresh        = 60,
-       .xres           = 1024,
-       .yres           = 768,
-       .pixclock       = 15385,
-       .left_margin    = 160,
-       .right_margin   = 24,
-       .upper_margin   = 29,
-       .lower_margin   = 3,
-       .hsync_len      = 136,
-       .vsync_len      = 6,
-       .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-       .vmode          = FB_VMODE_NONINTERLACED
+#define FSL_AOI_NUM    6       /* 5 AOIs and one dummy AOI */
+                               /* 1 for plane 0, 2 for plane 1&2 each */
+
+/* HW cursor parameters */
+#define MAX_CURS               32
+
+/* INT_STATUS/INT_MASK field descriptions */
+#define INT_VSYNC      0x01    /* Vsync interrupt  */
+#define INT_VSYNC_WB   0x02    /* Vsync interrupt for write back operation */
+#define INT_UNDRUN     0x04    /* Under run exception interrupt */
+#define INT_PARERR     0x08    /* Display parameters error interrupt */
+#define INT_LS_BF_VS   0x10    /* Lines before vsync. interrupt */
+
+struct diu_addr {
+       void *vaddr;            /* Virtual address */
+       dma_addr_t paddr;       /* Physical address */
+       __u32 offset;
 };
 
+/*
+ * List of supported video modes
+ *
+ * The first entry is the default video mode.  The remain entries are in
+ * order if increasing resolution and frequency.  The 320x240-60 mode is
+ * the initial AOI for the second and third planes.
+ */
 static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
        {
-               .name           = "1024x768-60",
                .refresh        = 60,
                .xres           = 1024,
                .yres           = 768,
@@ -75,7 +78,132 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
                .vmode          = FB_VMODE_NONINTERLACED
        },
        {
-               .name           = "1024x768-70",
+               .refresh        = 60,
+               .xres           = 320,
+               .yres           = 240,
+               .pixclock       = 79440,
+               .left_margin    = 16,
+               .right_margin   = 16,
+               .upper_margin   = 16,
+               .lower_margin   = 5,
+               .hsync_len      = 48,
+               .vsync_len      = 1,
+               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED
+       },
+       {
+               .refresh        = 60,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = 39722,
+               .left_margin    = 48,
+               .right_margin   = 16,
+               .upper_margin   = 33,
+               .lower_margin   = 10,
+               .hsync_len      = 96,
+               .vsync_len      = 2,
+               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED
+       },
+       {
+               .refresh        = 72,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = 32052,
+               .left_margin    = 128,
+               .right_margin   = 24,
+               .upper_margin   = 28,
+               .lower_margin   = 9,
+               .hsync_len      = 40,
+               .vsync_len      = 3,
+               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED
+       },
+       {
+               .refresh        = 75,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = 31747,
+               .left_margin    = 120,
+               .right_margin   = 16,
+               .upper_margin   = 16,
+               .lower_margin   = 1,
+               .hsync_len      = 64,
+               .vsync_len      = 3,
+               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED
+       },
+       {
+               .refresh        = 90,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = 25057,
+               .left_margin    = 120,
+               .right_margin   = 32,
+               .upper_margin   = 14,
+               .lower_margin   = 25,
+               .hsync_len      = 40,
+               .vsync_len      = 14,
+               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED
+       },
+       {
+               .refresh        = 100,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = 22272,
+               .left_margin    = 48,
+               .right_margin   = 32,
+               .upper_margin   = 17,
+               .lower_margin   = 22,
+               .hsync_len      = 128,
+               .vsync_len      = 12,
+               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED
+       },
+       {
+               .refresh        = 60,
+               .xres           = 800,
+               .yres           = 480,
+               .pixclock       = 33805,
+               .left_margin    = 96,
+               .right_margin   = 24,
+               .upper_margin   = 10,
+               .lower_margin   = 3,
+               .hsync_len      = 72,
+               .vsync_len      = 7,
+               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED
+       },
+       {
+               .refresh        = 60,
+               .xres           = 800,
+               .yres           = 600,
+               .pixclock       = 25000,
+               .left_margin    = 88,
+               .right_margin   = 40,
+               .upper_margin   = 23,
+               .lower_margin   = 1,
+               .hsync_len      = 128,
+               .vsync_len      = 4,
+               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED
+       },
+       {
+               .refresh        = 60,
+               .xres           = 854,
+               .yres           = 480,
+               .pixclock       = 31518,
+               .left_margin    = 104,
+               .right_margin   = 16,
+               .upper_margin   = 13,
+               .lower_margin   = 1,
+               .hsync_len      = 88,
+               .vsync_len      = 3,
+               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED
+       },
+       {
                .refresh        = 70,
                .xres           = 1024,
                .yres           = 768,
@@ -90,7 +218,6 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
                .vmode          = FB_VMODE_NONINTERLACED
        },
        {
-               .name           = "1024x768-75",
                .refresh        = 75,
                .xres           = 1024,
                .yres           = 768,
@@ -105,7 +232,34 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
                .vmode          = FB_VMODE_NONINTERLACED
        },
        {
-               .name           = "1280x1024-60",
+               .refresh        = 60,
+               .xres           = 1280,
+               .yres           = 480,
+               .pixclock       = 18939,
+               .left_margin    = 353,
+               .right_margin   = 47,
+               .upper_margin   = 39,
+               .lower_margin   = 4,
+               .hsync_len      = 8,
+               .vsync_len      = 2,
+               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED
+       },
+       {
+               .refresh        = 60,
+               .xres           = 1280,
+               .yres           = 720,
+               .pixclock       = 13426,
+               .left_margin    = 192,
+               .right_margin   = 64,
+               .upper_margin   = 22,
+               .lower_margin   = 1,
+               .hsync_len      = 136,
+               .vsync_len      = 3,
+               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED
+       },
+       {
                .refresh        = 60,
                .xres           = 1280,
                .yres           = 1024,
@@ -120,7 +274,6 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
                .vmode          = FB_VMODE_NONINTERLACED
        },
        {
-               .name           = "1280x1024-70",
                .refresh        = 70,
                .xres           = 1280,
                .yres           = 1024,
@@ -135,7 +288,6 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
                .vmode          = FB_VMODE_NONINTERLACED
        },
        {
-               .name           = "1280x1024-75",
                .refresh        = 75,
                .xres           = 1280,
                .yres           = 1024,
@@ -150,40 +302,25 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
                .vmode          = FB_VMODE_NONINTERLACED
        },
        {
-               .name           = "320x240",            /* for AOI only */
                .refresh        = 60,
-               .xres           = 320,
-               .yres           = 240,
-               .pixclock       = 15385,
-               .left_margin    = 0,
-               .right_margin   = 0,
-               .upper_margin   = 0,
-               .lower_margin   = 0,
-               .hsync_len      = 0,
-               .vsync_len      = 0,
-               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               .vmode          = FB_VMODE_NONINTERLACED
-       },
-       {
-               .name           = "1280x480-60",
-               .refresh        = 60,
-               .xres           = 1280,
-               .yres           = 480,
-               .pixclock       = 18939,
-               .left_margin    = 353,
-               .right_margin   = 47,
-               .upper_margin   = 39,
-               .lower_margin   = 4,
-               .hsync_len      = 8,
-               .vsync_len      = 2,
+               .xres           = 1920,
+               .yres           = 1080,
+               .pixclock       = 5787,
+               .left_margin    = 328,
+               .right_margin   = 120,
+               .upper_margin   = 34,
+               .lower_margin   = 1,
+               .hsync_len      = 208,
+               .vsync_len      = 3,
                .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
                .vmode          = FB_VMODE_NONINTERLACED
        },
 };
 
-static char *fb_mode = "1024x768-32@60";
+static char *fb_mode;
 static unsigned long default_bpp = 32;
-static int monitor_port;
+static enum fsl_diu_monitor_port monitor_port;
+static char *monitor_string;
 
 #if defined(CONFIG_NOT_COHERENT_CACHE)
 static u8 *coherence_data;
@@ -201,15 +338,27 @@ struct fsl_diu_data {
        void *dummy_aoi_virt;
        unsigned int irq;
        int fb_enabled;
-       int monitor_port;
+       enum fsl_diu_monitor_port monitor_port;
+       struct diu __iomem *diu_reg;
+       spinlock_t reg_lock;
+       struct diu_addr ad;
+       struct diu_addr gamma;
+       struct diu_addr pallete;
+       struct diu_addr cursor;
+};
+
+enum mfb_index {
+       PLANE0 = 0,     /* Plane 0, only one AOI that fills the screen */
+       PLANE1_AOI0,    /* Plane 1, first AOI */
+       PLANE1_AOI1,    /* Plane 1, second AOI */
+       PLANE2_AOI0,    /* Plane 2, first AOI */
+       PLANE2_AOI1,    /* Plane 2, second AOI */
 };
 
 struct mfb_info {
-       int index;
-       int type;
+       enum mfb_index index;
        char *id;
        int registered;
-       int blank;
        unsigned long pseudo_palette[16];
        struct diu_ad *ad;
        int cursor_reset;
@@ -223,63 +372,82 @@ struct mfb_info {
 
 
 static struct mfb_info mfb_template[] = {
-       {               /* AOI 0 for plane 0 */
-       .index = 0,
-       .type = MFB_TYPE_OUTPUT,
-       .id = "Panel0",
-       .registered = 0,
-       .count = 0,
-       .x_aoi_d = 0,
-       .y_aoi_d = 0,
+       {
+               .index = PLANE0,
+               .id = "Panel0",
+               .registered = 0,
+               .count = 0,
+               .x_aoi_d = 0,
+               .y_aoi_d = 0,
        },
-       {               /* AOI 0 for plane 1 */
-       .index = 1,
-       .type = MFB_TYPE_OUTPUT,
-       .id = "Panel1 AOI0",
-       .registered = 0,
-       .g_alpha = 0xff,
-       .count = 0,
-       .x_aoi_d = 0,
-       .y_aoi_d = 0,
+       {
+               .index = PLANE1_AOI0,
+               .id = "Panel1 AOI0",
+               .registered = 0,
+               .g_alpha = 0xff,
+               .count = 0,
+               .x_aoi_d = 0,
+               .y_aoi_d = 0,
        },
-       {               /* AOI 1 for plane 1 */
-       .index = 2,
-       .type = MFB_TYPE_OUTPUT,
-       .id = "Panel1 AOI1",
-       .registered = 0,
-       .g_alpha = 0xff,
-       .count = 0,
-       .x_aoi_d = 0,
-       .y_aoi_d = 480,
+       {
+               .index = PLANE1_AOI1,
+               .id = "Panel1 AOI1",
+               .registered = 0,
+               .g_alpha = 0xff,
+               .count = 0,
+               .x_aoi_d = 0,
+               .y_aoi_d = 480,
        },
-       {               /* AOI 0 for plane 2 */
-       .index = 3,
-       .type = MFB_TYPE_OUTPUT,
-       .id = "Panel2 AOI0",
-       .registered = 0,
-       .g_alpha = 0xff,
-       .count = 0,
-       .x_aoi_d = 640,
-       .y_aoi_d = 0,
+       {
+               .index = PLANE2_AOI0,
+               .id = "Panel2 AOI0",
+               .registered = 0,
+               .g_alpha = 0xff,
+               .count = 0,
+               .x_aoi_d = 640,
+               .y_aoi_d = 0,
        },
-       {               /* AOI 1 for plane 2 */
-       .index = 4,
-       .type = MFB_TYPE_OUTPUT,
-       .id = "Panel2 AOI1",
-       .registered = 0,
-       .g_alpha = 0xff,
-       .count = 0,
-       .x_aoi_d = 640,
-       .y_aoi_d = 480,
+       {
+               .index = PLANE2_AOI1,
+               .id = "Panel2 AOI1",
+               .registered = 0,
+               .g_alpha = 0xff,
+               .count = 0,
+               .x_aoi_d = 640,
+               .y_aoi_d = 480,
        },
 };
 
-static struct diu_hw dr = {
-       .mode = MFB_MODE1,
-       .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock),
-};
+/**
+ * fsl_diu_name_to_port - convert a port name to a monitor port enum
+ *
+ * Takes the name of a monitor port ("dvi", "lvds", or "dlvds") and returns
+ * the enum fsl_diu_monitor_port that corresponds to that string.
+ *
+ * For compatibility with older versions, a number ("0", "1", or "2") is also
+ * supported.
+ *
+ * If the string is unknown, DVI is assumed.
+ *
+ * If the particular port is not supported by the platform, another port
+ * (platform-specific) is chosen instead.
+ */
+static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s)
+{
+       enum fsl_diu_monitor_port port = FSL_DIU_PORT_DVI;
+       unsigned long val;
 
-static struct diu_pool pool;
+       if (s) {
+               if (!strict_strtoul(s, 10, &val) && (val <= 2))
+                       port = (enum fsl_diu_monitor_port) val;
+               else if (strncmp(s, "lvds", 4) == 0)
+                       port = FSL_DIU_PORT_LVDS;
+               else if (strncmp(s, "dlvds", 5) == 0)
+                       port = FSL_DIU_PORT_DLVDS;
+       }
+
+       return diu_ops.valid_monitor_port(port);
+}
 
 /**
  * fsl_diu_alloc - allocate memory for the DIU
@@ -292,14 +460,9 @@ static void *fsl_diu_alloc(size_t size, phys_addr_t *phys)
 {
        void *virt;
 
-       pr_debug("size=%zu\n", size);
-
        virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO);
-       if (virt) {
+       if (virt)
                *phys = virt_to_phys(virt);
-               pr_debug("virt=%p phys=%llx\n", virt,
-                       (unsigned long long)*phys);
-       }
 
        return virt;
 }
@@ -313,8 +476,6 @@ static void *fsl_diu_alloc(size_t size, phys_addr_t *phys)
  */
 static void fsl_diu_free(void *virt, size_t size)
 {
-       pr_debug("virt=%p size=%zu\n", virt, size);
-
        if (virt && size)
                free_pages_exact(virt, size);
 }
@@ -330,82 +491,72 @@ void wr_reg_wa(u32 *reg, u32 val)
        } while (in_be32(reg) != val);
 }
 
-static int fsl_diu_enable_panel(struct fb_info *info)
+static void fsl_diu_enable_panel(struct fb_info *info)
 {
        struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
-       struct diu *hw = dr.diu_reg;
        struct diu_ad *ad = mfbi->ad;
        struct fsl_diu_data *machine_data = mfbi->parent;
-       int res = 0;
+       struct diu __iomem *hw = machine_data->diu_reg;
 
-       pr_debug("enable_panel index %d\n", mfbi->index);
-       if (mfbi->type != MFB_TYPE_OFF) {
-               switch (mfbi->index) {
-               case 0:                         /* plane 0 */
-                       if (hw->desc[0] != ad->paddr)
-                               wr_reg_wa(&hw->desc[0], ad->paddr);
-                       break;
-               case 1:                         /* plane 1 AOI 0 */
-                       cmfbi = machine_data->fsl_diu_info[2]->par;
-                       if (hw->desc[1] != ad->paddr) { /* AOI0 closed */
-                               if (cmfbi->count > 0)   /* AOI1 open */
-                                       ad->next_ad =
-                                               cpu_to_le32(cmfbi->ad->paddr);
-                               else
-                                       ad->next_ad = 0;
-                               wr_reg_wa(&hw->desc[1], ad->paddr);
-                       }
-                       break;
-               case 3:                         /* plane 2 AOI 0 */
-                       cmfbi = machine_data->fsl_diu_info[4]->par;
-                       if (hw->desc[2] != ad->paddr) { /* AOI0 closed */
-                               if (cmfbi->count > 0)   /* AOI1 open */
-                                       ad->next_ad =
-                                               cpu_to_le32(cmfbi->ad->paddr);
-                               else
-                                       ad->next_ad = 0;
-                               wr_reg_wa(&hw->desc[2], ad->paddr);
-                       }
-                       break;
-               case 2:                         /* plane 1 AOI 1 */
-                       pmfbi = machine_data->fsl_diu_info[1]->par;
-                       ad->next_ad = 0;
-                       if (hw->desc[1] == machine_data->dummy_ad->paddr)
-                               wr_reg_wa(&hw->desc[1], ad->paddr);
-                       else                                    /* AOI0 open */
-                               pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
-                       break;
-               case 4:                         /* plane 2 AOI 1 */
-                       pmfbi = machine_data->fsl_diu_info[3]->par;
-                       ad->next_ad = 0;
-                       if (hw->desc[2] == machine_data->dummy_ad->paddr)
-                               wr_reg_wa(&hw->desc[2], ad->paddr);
-                       else                            /* AOI0 was open */
-                               pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
-                       break;
-               default:
-                       res = -EINVAL;
-                       break;
+       switch (mfbi->index) {
+       case PLANE0:
+               if (hw->desc[0] != ad->paddr)
+                       wr_reg_wa(&hw->desc[0], ad->paddr);
+               break;
+       case PLANE1_AOI0:
+               cmfbi = machine_data->fsl_diu_info[2]->par;
+               if (hw->desc[1] != ad->paddr) { /* AOI0 closed */
+                       if (cmfbi->count > 0)   /* AOI1 open */
+                               ad->next_ad =
+                                       cpu_to_le32(cmfbi->ad->paddr);
+                       else
+                               ad->next_ad = 0;
+                       wr_reg_wa(&hw->desc[1], ad->paddr);
                }
-       } else
-               res = -EINVAL;
-       return res;
+               break;
+       case PLANE2_AOI0:
+               cmfbi = machine_data->fsl_diu_info[4]->par;
+               if (hw->desc[2] != ad->paddr) { /* AOI0 closed */
+                       if (cmfbi->count > 0)   /* AOI1 open */
+                               ad->next_ad =
+                                       cpu_to_le32(cmfbi->ad->paddr);
+                       else
+                               ad->next_ad = 0;
+                       wr_reg_wa(&hw->desc[2], ad->paddr);
+               }
+               break;
+       case PLANE1_AOI1:
+               pmfbi = machine_data->fsl_diu_info[1]->par;
+               ad->next_ad = 0;
+               if (hw->desc[1] == machine_data->dummy_ad->paddr)
+                       wr_reg_wa(&hw->desc[1], ad->paddr);
+               else                                    /* AOI0 open */
+                       pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
+               break;
+       case PLANE2_AOI1:
+               pmfbi = machine_data->fsl_diu_info[3]->par;
+               ad->next_ad = 0;
+               if (hw->desc[2] == machine_data->dummy_ad->paddr)
+                       wr_reg_wa(&hw->desc[2], ad->paddr);
+               else                            /* AOI0 was open */
+                       pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
+               break;
+       }
 }
 
-static int fsl_diu_disable_panel(struct fb_info *info)
+static void fsl_diu_disable_panel(struct fb_info *info)
 {
        struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
-       struct diu *hw = dr.diu_reg;
        struct diu_ad *ad = mfbi->ad;
        struct fsl_diu_data *machine_data = mfbi->parent;
-       int res = 0;
+       struct diu __iomem *hw = machine_data->diu_reg;
 
        switch (mfbi->index) {
-       case 0:                                 /* plane 0 */
+       case PLANE0:
                if (hw->desc[0] != machine_data->dummy_ad->paddr)
                        wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr);
                break;
-       case 1:                                 /* plane 1 AOI 0 */
+       case PLANE1_AOI0:
                cmfbi = machine_data->fsl_diu_info[2]->par;
                if (cmfbi->count > 0)   /* AOI1 is open */
                        wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr);
@@ -414,7 +565,7 @@ static int fsl_diu_disable_panel(struct fb_info *info)
                        wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
                                        /* close AOI 0 */
                break;
-       case 3:                                 /* plane 2 AOI 0 */
+       case PLANE2_AOI0:
                cmfbi = machine_data->fsl_diu_info[4]->par;
                if (cmfbi->count > 0)   /* AOI1 is open */
                        wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr);
@@ -423,7 +574,7 @@ static int fsl_diu_disable_panel(struct fb_info *info)
                        wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
                                        /* close AOI 0 */
                break;
-       case 2:                                 /* plane 1 AOI 1 */
+       case PLANE1_AOI1:
                pmfbi = machine_data->fsl_diu_info[1]->par;
                if (hw->desc[1] != ad->paddr) {
                                /* AOI1 is not the first in the chain */
@@ -434,7 +585,7 @@ static int fsl_diu_disable_panel(struct fb_info *info)
                        wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
                                        /* close AOI 1 */
                break;
-       case 4:                                 /* plane 2 AOI 1 */
+       case PLANE2_AOI1:
                pmfbi = machine_data->fsl_diu_info[3]->par;
                if (hw->desc[2] != ad->paddr) {
                                /* AOI1 is not the first in the chain */
@@ -445,31 +596,26 @@ static int fsl_diu_disable_panel(struct fb_info *info)
                        wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
                                /* close AOI 1 */
                break;
-       default:
-               res = -EINVAL;
-               break;
        }
-
-       return res;
 }
 
 static void enable_lcdc(struct fb_info *info)
 {
-       struct diu *hw = dr.diu_reg;
        struct mfb_info *mfbi = info->par;
        struct fsl_diu_data *machine_data = mfbi->parent;
+       struct diu __iomem *hw = machine_data->diu_reg;
 
        if (!machine_data->fb_enabled) {
-               out_be32(&hw->diu_mode, dr.mode);
+               out_be32(&hw->diu_mode, MFB_MODE1);
                machine_data->fb_enabled++;
        }
 }
 
 static void disable_lcdc(struct fb_info *info)
 {
-       struct diu *hw = dr.diu_reg;
        struct mfb_info *mfbi = info->par;
        struct fsl_diu_data *machine_data = mfbi->parent;
+       struct diu __iomem *hw = machine_data->diu_reg;
 
        if (machine_data->fb_enabled) {
                out_be32(&hw->diu_mode, 0);
@@ -482,7 +628,8 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
 {
        struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par;
        struct fsl_diu_data *machine_data = mfbi->parent;
-       int available_height, upper_aoi_bottom, index = mfbi->index;
+       int available_height, upper_aoi_bottom;
+       enum mfb_index index = mfbi->index;
        int lower_aoi_is_open, upper_aoi_is_open;
        __u32 base_plane_width, base_plane_height, upper_aoi_height;
 
@@ -494,14 +641,14 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
        if (mfbi->y_aoi_d < 0)
                mfbi->y_aoi_d = 0;
        switch (index) {
-       case 0:
+       case PLANE0:
                if (mfbi->x_aoi_d != 0)
                        mfbi->x_aoi_d = 0;
                if (mfbi->y_aoi_d != 0)
                        mfbi->y_aoi_d = 0;
                break;
-       case 1:                 /* AOI 0 */
-       case 3:
+       case PLANE1_AOI0:
+       case PLANE2_AOI0:
                lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par;
                lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0;
                if (var->xres > base_plane_width)
@@ -518,8 +665,8 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
                if ((mfbi->y_aoi_d + var->yres) > available_height)
                        mfbi->y_aoi_d = available_height - var->yres;
                break;
-       case 2:                 /* AOI 1 */
-       case 4:
+       case PLANE1_AOI1:
+       case PLANE2_AOI1:
                upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par;
                upper_aoi_height =
                                machine_data->fsl_diu_info[index-1]->var.yres;
@@ -555,9 +702,6 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
 static int fsl_diu_check_var(struct fb_var_screeninfo *var,
                                struct fb_info *info)
 {
-       pr_debug("check_var xres: %d\n", var->xres);
-       pr_debug("check_var yres: %d\n", var->yres);
-
        if (var->xres_virtual < var->xres)
                var->xres_virtual = var->xres;
        if (var->yres_virtual < var->yres)
@@ -652,7 +796,7 @@ static void set_fix(struct fb_info *info)
        struct fb_var_screeninfo *var = &info->var;
        struct mfb_info *mfbi = info->par;
 
-       strncpy(fix->id, mfbi->id, strlen(mfbi->id));
+       strncpy(fix->id, mfbi->id, sizeof(fix->id));
        fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
        fix->type = FB_TYPE_PACKED_PIXELS;
        fix->accel = FB_ACCEL_NONE;
@@ -666,45 +810,37 @@ static void update_lcdc(struct fb_info *info)
        struct fb_var_screeninfo *var = &info->var;
        struct mfb_info *mfbi = info->par;
        struct fsl_diu_data *machine_data = mfbi->parent;
-       struct diu *hw;
+       struct diu __iomem *hw;
        int i, j;
        char __iomem *cursor_base, *gamma_table_base;
 
        u32 temp;
 
-       hw = dr.diu_reg;
-
-       if (mfbi->type == MFB_TYPE_OFF) {
-               fsl_diu_disable_panel(info);
-               return;
-       }
+       hw = machine_data->diu_reg;
 
        diu_ops.set_monitor_port(machine_data->monitor_port);
-       gamma_table_base = pool.gamma.vaddr;
-       cursor_base = pool.cursor.vaddr;
+       gamma_table_base = machine_data->gamma.vaddr;
+       cursor_base = machine_data->cursor.vaddr;
        /* Prep for DIU init  - gamma table, cursor table */
 
        for (i = 0; i <= 2; i++)
-          for (j = 0; j <= 255; j++)
-             *gamma_table_base++ = j;
+               for (j = 0; j <= 255; j++)
+                       *gamma_table_base++ = j;
 
-       diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr);
+       diu_ops.set_gamma_table(machine_data->monitor_port,
+                               machine_data->gamma.vaddr);
 
-       pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw);
        disable_lcdc(info);
 
        /* Program DIU registers */
 
-       out_be32(&hw->gamma, pool.gamma.paddr);
-       out_be32(&hw->cursor, pool.cursor.paddr);
+       out_be32(&hw->gamma, machine_data->gamma.paddr);
+       out_be32(&hw->cursor, machine_data->cursor.paddr);
 
        out_be32(&hw->bgnd, 0x007F7F7F);        /* BGND */
        out_be32(&hw->bgnd_wb, 0);              /* BGND_WB */
        out_be32(&hw->disp_size, (var->yres << 16 | var->xres));
                                                /* DISP SIZE */
-       pr_debug("DIU xres: %d\n", var->xres);
-       pr_debug("DIU yres: %d\n", var->yres);
-
        out_be32(&hw->wb_size, 0); /* WB SIZE */
        out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */
 
@@ -721,15 +857,6 @@ static void update_lcdc(struct fb_info *info)
 
        out_be32(&hw->vsyn_para, temp);
 
-       pr_debug("DIU right_margin - %d\n", var->right_margin);
-       pr_debug("DIU left_margin - %d\n", var->left_margin);
-       pr_debug("DIU hsync_len - %d\n", var->hsync_len);
-       pr_debug("DIU upper_margin - %d\n", var->upper_margin);
-       pr_debug("DIU lower_margin - %d\n", var->lower_margin);
-       pr_debug("DIU vsync_len - %d\n", var->vsync_len);
-       pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para);
-       pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para);
-
        diu_ops.set_pixel_clock(var->pixclock);
 
        out_be32(&hw->syn_pol, 0);      /* SYNC SIGNALS POLARITY */
@@ -746,14 +873,9 @@ static int map_video_memory(struct fb_info *info)
        phys_addr_t phys;
        u32 smem_len = info->fix.line_length * info->var.yres_virtual;
 
-       pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual);
-       pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
-       pr_debug("info->fix.line_length  = %d\n", info->fix.line_length);
-       pr_debug("MAP_VIDEO_MEMORY: smem_len = %u\n", smem_len);
-
        info->screen_base = fsl_diu_alloc(smem_len, &phys);
        if (info->screen_base == NULL) {
-               printk(KERN_ERR "Unable to allocate fb memory\n");
+               dev_err(info->dev, "unable to allocate fb memory\n");
                return -ENOMEM;
        }
        mutex_lock(&info->mm_lock);
@@ -762,10 +884,6 @@ static int map_video_memory(struct fb_info *info)
        mutex_unlock(&info->mm_lock);
        info->screen_size = info->fix.smem_len;
 
-       pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n",
-                info->fix.smem_start, info->fix.smem_len);
-       pr_debug("screen base %p\n", info->screen_base);
-
        return 0;
 }
 
@@ -810,9 +928,9 @@ static int fsl_diu_set_par(struct fb_info *info)
        struct mfb_info *mfbi = info->par;
        struct fsl_diu_data *machine_data = mfbi->parent;
        struct diu_ad *ad = mfbi->ad;
-       struct diu *hw;
+       struct diu __iomem *hw;
 
-       hw = dr.diu_reg;
+       hw = machine_data->diu_reg;
 
        set_fix(info);
        mfbi->cursor_reset = 1;
@@ -822,18 +940,16 @@ static int fsl_diu_set_par(struct fb_info *info)
        if (len != info->fix.smem_len) {
                if (info->fix.smem_start)
                        unmap_video_memory(info);
-               pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len);
 
                /* Memory allocation for framebuffer */
                if (map_video_memory(info)) {
-                       printk(KERN_ERR "Unable to allocate fb memory 1\n");
+                       dev_err(info->dev, "unable to allocate fb memory 1\n");
                        return -ENOMEM;
                }
        }
 
-       ad->pix_fmt =
-               diu_ops.get_pixel_format(var->bits_per_pixel,
-                                        machine_data->monitor_port);
+       ad->pix_fmt = diu_ops.get_pixel_format(machine_data->monitor_port,
+                                              var->bits_per_pixel);
        ad->addr    = cpu_to_le32(info->fix.smem_start);
        ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) |
                                var->xres_virtual) | mfbi->g_alpha;
@@ -851,14 +967,14 @@ static int fsl_diu_set_par(struct fb_info *info)
        ad->ckmin_g = 255;
        ad->ckmin_b = 255;
 
-       if (mfbi->index == 0)
+       if (mfbi->index == PLANE0)
                update_lcdc(info);
        return 0;
 }
 
 static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
 {
-       return ((val<<width) + 0x7FFF - val)>>16;
+       return ((val << width) + 0x7FFF - val) >> 16;
 }
 
 /*
@@ -870,8 +986,9 @@ static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
  * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited
  * color palette.
  */
-static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green,
-                          unsigned blue, unsigned transp, struct fb_info *info)
+static int fsl_diu_setcolreg(unsigned int regno, unsigned int red,
+                            unsigned int green, unsigned int blue,
+                            unsigned int transp, struct fb_info *info)
 {
        int ret = 1;
 
@@ -906,9 +1023,6 @@ static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green,
                        ret = 0;
                }
                break;
-       case FB_VISUAL_STATIC_PSEUDOCOLOR:
-       case FB_VISUAL_PSEUDOCOLOR:
-               break;
        }
 
        return ret;
@@ -944,37 +1058,6 @@ static int fsl_diu_pan_display(struct fb_var_screeninfo *var,
        return 0;
 }
 
-/*
- * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking
- * succeeded, != 0 if un-/blanking failed.
- * blank_mode == 2: suspend vsync
- * blank_mode == 3: suspend hsync
- * blank_mode == 4: powerdown
- */
-static int fsl_diu_blank(int blank_mode, struct fb_info *info)
-{
-       struct mfb_info *mfbi = info->par;
-
-       mfbi->blank = blank_mode;
-
-       switch (blank_mode) {
-       case FB_BLANK_VSYNC_SUSPEND:
-       case FB_BLANK_HSYNC_SUSPEND:
-       /* FIXME: fixes to enable_panel and enable lcdc needed */
-       case FB_BLANK_NORMAL:
-       /*      fsl_diu_disable_panel(info);*/
-               break;
-       case FB_BLANK_POWERDOWN:
-       /*      disable_lcdc(info);     */
-               break;
-       case FB_BLANK_UNBLANK:
-       /*      fsl_diu_enable_panel(info);*/
-               break;
-       }
-
-       return 0;
-}
-
 static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
                       unsigned long arg)
 {
@@ -989,25 +1072,29 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
        if (!arg)
                return -EINVAL;
        switch (cmd) {
+       case MFB_SET_PIXFMT_OLD:
+               dev_warn(info->dev,
+                        "MFB_SET_PIXFMT value of 0x%08x is deprecated.\n",
+                        MFB_SET_PIXFMT_OLD);
        case MFB_SET_PIXFMT:
                if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt)))
                        return -EFAULT;
                ad->pix_fmt = pix_fmt;
-               pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt);
                break;
+       case MFB_GET_PIXFMT_OLD:
+               dev_warn(info->dev,
+                        "MFB_GET_PIXFMT value of 0x%08x is deprecated.\n",
+                        MFB_GET_PIXFMT_OLD);
        case MFB_GET_PIXFMT:
                pix_fmt = ad->pix_fmt;
                if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt)))
                        return -EFAULT;
-               pr_debug("get pixel format 0x%08x\n", ad->pix_fmt);
                break;
        case MFB_SET_AOID:
                if (copy_from_user(&aoi_d, buf, sizeof(aoi_d)))
                        return -EFAULT;
                mfbi->x_aoi_d = aoi_d.x_aoi_d;
                mfbi->y_aoi_d = aoi_d.y_aoi_d;
-               pr_debug("set AOI display offset of index %d to (%d,%d)\n",
-                                mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
                fsl_diu_check_var(&info->var, info);
                fsl_diu_set_aoi(info);
                break;
@@ -1016,14 +1103,11 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
                aoi_d.y_aoi_d = mfbi->y_aoi_d;
                if (copy_to_user(buf, &aoi_d, sizeof(aoi_d)))
                        return -EFAULT;
-               pr_debug("get AOI display offset of index %d (%d,%d)\n",
-                               mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
                break;
        case MFB_GET_ALPHA:
                global_alpha = mfbi->g_alpha;
                if (copy_to_user(buf, &global_alpha, sizeof(global_alpha)))
                        return -EFAULT;
-               pr_debug("get global alpha of index %d\n", mfbi->index);
                break;
        case MFB_SET_ALPHA:
                /* set panel information */
@@ -1032,7 +1116,6 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
                ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) |
                                                        (global_alpha & 0xff);
                mfbi->g_alpha = global_alpha;
-               pr_debug("set global alpha for index %d\n", mfbi->index);
                break;
        case MFB_SET_CHROMA_KEY:
                /* set panel winformation */
@@ -1060,27 +1143,9 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
                        ad->ckmin_g = ck.green_min;
                        ad->ckmin_b = ck.blue_min;
                }
-               pr_debug("set chroma key\n");
                break;
-       case FBIOGET_GWINFO:
-               if (mfbi->type == MFB_TYPE_OFF)
-                       return -ENODEV;
-               /* get graphic window information */
-               if (copy_to_user(buf, ad, sizeof(*ad)))
-                       return -EFAULT;
-               break;
-       case FBIOGET_HWCINFO:
-               pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO);
-               break;
-       case FBIOPUT_MODEINFO:
-               pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO);
-               break;
-       case FBIOGET_DISPINFO:
-               pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO);
-               break;
-
        default:
-               printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd);
+               dev_err(info->dev, "unknown ioctl command (0x%08X)\n", cmd);
                return -ENOIOCTLCMD;
        }
 
@@ -1095,22 +1160,18 @@ static int fsl_diu_open(struct fb_info *info, int user)
        int res = 0;
 
        /* free boot splash memory on first /dev/fb0 open */
-       if (!mfbi->index && diu_ops.release_bootmem)
+       if ((mfbi->index == PLANE0) && diu_ops.release_bootmem)
                diu_ops.release_bootmem();
 
        spin_lock(&diu_lock);
        mfbi->count++;
        if (mfbi->count == 1) {
-               pr_debug("open plane index %d\n", mfbi->index);
                fsl_diu_check_var(&info->var, info);
                res = fsl_diu_set_par(info);
                if (res < 0)
                        mfbi->count--;
-               else {
-                       res = fsl_diu_enable_panel(info);
-                       if (res < 0)
-                               mfbi->count--;
-               }
+               else
+                       fsl_diu_enable_panel(info);
        }
 
        spin_unlock(&diu_lock);
@@ -1126,12 +1187,9 @@ static int fsl_diu_release(struct fb_info *info, int user)
 
        spin_lock(&diu_lock);
        mfbi->count--;
-       if (mfbi->count == 0) {
-               pr_debug("release plane index %d\n", mfbi->index);
-               res = fsl_diu_disable_panel(info);
-               if (res < 0)
-                       mfbi->count++;
-       }
+       if (mfbi->count == 0)
+               fsl_diu_disable_panel(info);
+
        spin_unlock(&diu_lock);
        return res;
 }
@@ -1141,7 +1199,6 @@ static struct fb_ops fsl_diu_ops = {
        .fb_check_var = fsl_diu_check_var,
        .fb_set_par = fsl_diu_set_par,
        .fb_setcolreg = fsl_diu_setcolreg,
-       .fb_blank = fsl_diu_blank,
        .fb_pan_display = fsl_diu_pan_display,
        .fb_fillrect = cfb_fillrect,
        .fb_copyarea = cfb_copyarea,
@@ -1178,7 +1235,7 @@ static int __devinit install_fb(struct fb_info *info)
        if (init_fbinfo(info))
                return -EINVAL;
 
-       if (mfbi->index == 0) { /* plane 0 */
+       if (mfbi->index == PLANE0) {
                if (mfbi->edid_data) {
                        /* Now build modedb from EDID */
                        fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs);
@@ -1192,43 +1249,23 @@ static int __devinit install_fb(struct fb_info *info)
        } else {
                aoi_mode = init_aoi_mode;
        }
-       pr_debug("mode used = %s\n", aoi_mode);
-       rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize,
-                         &fsl_diu_default_mode, default_bpp);
-       switch (rc) {
-       case 1:
-               pr_debug("using mode specified in @mode\n");
-               break;
-       case 2:
-               pr_debug("using mode specified in @mode "
-                       "with ignored refresh rate\n");
-               break;
-       case 3:
-               pr_debug("using mode default mode\n");
-               break;
-       case 4:
-               pr_debug("using mode from list\n");
-               break;
-       default:
-               pr_debug("rc = %d\n", rc);
-               pr_debug("failed to find mode\n");
+       rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize, NULL,
+                         default_bpp);
+       if (!rc) {
                /*
                 * For plane 0 we continue and look into
                 * driver's internal modedb.
                 */
-               if (mfbi->index == 0 && mfbi->edid_data)
+               if ((mfbi->index == PLANE0) && mfbi->edid_data)
                        has_default_mode = 0;
                else
                        return -EINVAL;
-               break;
        }
 
        if (!has_default_mode) {
                rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
-                                 ARRAY_SIZE(fsl_diu_mode_db),
-                                 &fsl_diu_default_mode,
-                                 default_bpp);
-               if (rc > 0 && rc < 5)
+                       ARRAY_SIZE(fsl_diu_mode_db), NULL, default_bpp);
+               if (rc)
                        has_default_mode = 1;
        }
 
@@ -1256,33 +1293,22 @@ static int __devinit install_fb(struct fb_info *info)
                fb_videomode_to_var(&info->var, modedb);
        }
 
-       pr_debug("xres_virtual %d\n", info->var.xres_virtual);
-       pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
-
-       pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
-       pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
-
-       if (mfbi->type == MFB_TYPE_OFF)
-               mfbi->blank = FB_BLANK_NORMAL;
-       else
-               mfbi->blank = FB_BLANK_UNBLANK;
-
        if (fsl_diu_check_var(&info->var, info)) {
-               printk(KERN_ERR "fb_check_var failed");
+               dev_err(info->dev, "fsl_diu_check_var failed\n");
+               unmap_video_memory(info);
                fb_dealloc_cmap(&info->cmap);
                return -EINVAL;
        }
 
        if (register_framebuffer(info) < 0) {
-               printk(KERN_ERR "register_framebuffer failed");
+               dev_err(info->dev, "register_framebuffer failed\n");
                unmap_video_memory(info);
                fb_dealloc_cmap(&info->cmap);
                return -EINVAL;
        }
 
        mfbi->registered = 1;
-       printk(KERN_INFO "fb%d: %s fb device registered successfully.\n",
-                info->node, info->fix.id);
+       dev_info(info->dev, "%s registered successfully\n", mfbi->id);
 
        return 0;
 }
@@ -1294,7 +1320,7 @@ static void uninstall_fb(struct fb_info *info)
        if (!mfbi->registered)
                return;
 
-       if (mfbi->index == 0)
+       if (mfbi->index == PLANE0)
                kfree(mfbi->edid_data);
 
        unregister_framebuffer(info);
@@ -1307,20 +1333,20 @@ static void uninstall_fb(struct fb_info *info)
 
 static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
 {
-       struct diu *hw = dr.diu_reg;
+       struct diu __iomem *hw = dev_id;
        unsigned int status = in_be32(&hw->int_status);
 
        if (status) {
                /* This is the workaround for underrun */
                if (status & INT_UNDRUN) {
                        out_be32(&hw->diu_mode, 0);
-                       pr_debug("Err: DIU occurs underrun!\n");
                        udelay(1);
                        out_be32(&hw->diu_mode, 1);
                }
 #if defined(CONFIG_NOT_COHERENT_CACHE)
                else if (status & INT_VSYNC) {
                        unsigned int i;
+
                        for (i = 0; i < coherence_data_size;
                                i += d_cache_line_size)
                                __asm__ __volatile__ (
@@ -1333,43 +1359,38 @@ static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
        return IRQ_NONE;
 }
 
-static int request_irq_local(int irq)
+static int request_irq_local(struct fsl_diu_data *machine_data)
 {
-       unsigned long status, ints;
-       struct diu *hw;
+       struct diu __iomem *hw = machine_data->diu_reg;
+       u32 ints;
        int ret;
 
-       hw = dr.diu_reg;
-
        /* Read to clear the status */
-       status = in_be32(&hw->int_status);
+       in_be32(&hw->int_status);
 
-       ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL);
-       if (ret)
-               pr_info("Request diu IRQ failed.\n");
-       else {
+       ret = request_irq(machine_data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw);
+       if (!ret) {
                ints = INT_PARERR | INT_LS_BF_VS;
 #if !defined(CONFIG_NOT_COHERENT_CACHE)
                ints |= INT_VSYNC;
 #endif
-               if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3)
-                       ints |= INT_VSYNC_WB;
 
                /* Read to clear the status */
-               status = in_be32(&hw->int_status);
+               in_be32(&hw->int_status);
                out_be32(&hw->int_mask, ints);
        }
+
        return ret;
 }
 
-static void free_irq_local(int irq)
+static void free_irq_local(struct fsl_diu_data *machine_data)
 {
-       struct diu *hw = dr.diu_reg;
+       struct diu __iomem *hw = machine_data->diu_reg;
 
        /* Disable all LCDC interrupt */
        out_be32(&hw->int_mask, 0x1f);
 
-       free_irq(irq, NULL);
+       free_irq(machine_data->irq, NULL);
 }
 
 #ifdef CONFIG_PM
@@ -1406,49 +1427,42 @@ static int fsl_diu_resume(struct platform_device *ofdev)
 static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size,
                        u32 bytes_align)
 {
-       u32 offset, ssize;
-       u32 mask;
-       dma_addr_t paddr = 0;
+       u32 offset;
+       dma_addr_t mask;
 
-       ssize = size + bytes_align;
-       buf->vaddr = dma_alloc_coherent(dev, ssize, &paddr, GFP_DMA |
-                                                            __GFP_ZERO);
+       buf->vaddr =
+               dma_alloc_coherent(dev, size + bytes_align, &buf->paddr,
+                                  GFP_DMA | __GFP_ZERO);
        if (!buf->vaddr)
                return -ENOMEM;
 
-       buf->paddr = (__u32) paddr;
-
        mask = bytes_align - 1;
-       offset = (u32)buf->paddr & mask;
+       offset = buf->paddr & mask;
        if (offset) {
                buf->offset = bytes_align - offset;
-               buf->paddr = (u32)buf->paddr + offset;
+               buf->paddr = buf->paddr + offset;
        } else
                buf->offset = 0;
+
        return 0;
 }
 
 static void free_buf(struct device *dev, struct diu_addr *buf, u32 size,
                     u32 bytes_align)
 {
-       dma_free_coherent(dev, size + bytes_align,
-                               buf->vaddr, (buf->paddr - buf->offset));
-       return;
+       dma_free_coherent(dev, size + bytes_align, buf->vaddr,
+                         buf->paddr - buf->offset);
 }
 
 static ssize_t store_monitor(struct device *device,
        struct device_attribute *attr, const char *buf, size_t count)
 {
-       int old_monitor_port;
-       unsigned long val;
+       enum fsl_diu_monitor_port old_monitor_port;
        struct fsl_diu_data *machine_data =
                container_of(attr, struct fsl_diu_data, dev_attr);
 
-       if (strict_strtoul(buf, 10, &val))
-               return 0;
-
        old_monitor_port = machine_data->monitor_port;
-       machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val);
+       machine_data->monitor_port = fsl_diu_name_to_port(buf);
 
        if (old_monitor_port != machine_data->monitor_port) {
                /* All AOIs need adjust pixel format
@@ -1468,16 +1482,25 @@ static ssize_t show_monitor(struct device *device,
 {
        struct fsl_diu_data *machine_data =
                container_of(attr, struct fsl_diu_data, dev_attr);
-       return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
+
+       switch (machine_data->monitor_port) {
+       case FSL_DIU_PORT_DVI:
+               return sprintf(buf, "DVI\n");
+       case FSL_DIU_PORT_LVDS:
+               return sprintf(buf, "Single-link LVDS\n");
+       case FSL_DIU_PORT_DLVDS:
+               return sprintf(buf, "Dual-link LVDS\n");
+       }
+
+       return 0;
 }
 
-static int __devinit fsl_diu_probe(struct platform_device *ofdev)
+static int __devinit fsl_diu_probe(struct platform_device *pdev)
 {
-       struct device_node *np = ofdev->dev.of_node;
+       struct device_node *np = pdev->dev.of_node;
        struct mfb_info *mfbi;
-       phys_addr_t dummy_ad_addr;
+       phys_addr_t dummy_ad_addr = 0;
        int ret, i, error = 0;
-       struct resource res;
        struct fsl_diu_data *machine_data;
        int diu_mode;
 
@@ -1485,11 +1508,13 @@ static int __devinit fsl_diu_probe(struct platform_device *ofdev)
        if (!machine_data)
                return -ENOMEM;
 
+       spin_lock_init(&machine_data->reg_lock);
+
        for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
                machine_data->fsl_diu_info[i] =
-                       framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev);
+                       framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev);
                if (!machine_data->fsl_diu_info[i]) {
-                       dev_err(&ofdev->dev, "cannot allocate memory\n");
+                       dev_err(&pdev->dev, "cannot allocate memory\n");
                        ret = -ENOMEM;
                        goto error2;
                }
@@ -1497,7 +1522,7 @@ static int __devinit fsl_diu_probe(struct platform_device *ofdev)
                memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
                mfbi->parent = machine_data;
 
-               if (mfbi->index == 0) {
+               if (mfbi->index == PLANE0) {
                        const u8 *prop;
                        int len;
 
@@ -1509,60 +1534,49 @@ static int __devinit fsl_diu_probe(struct platform_device *ofdev)
                }
        }
 
-       ret = of_address_to_resource(np, 0, &res);
-       if (ret) {
-               dev_err(&ofdev->dev, "could not obtain DIU address\n");
-               goto error;
-       }
-       if (!res.start) {
-               dev_err(&ofdev->dev, "invalid DIU address\n");
-               goto error;
-       }
-       dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start);
-
-       dr.diu_reg = ioremap(res.start, sizeof(struct diu));
-       if (!dr.diu_reg) {
-               dev_err(&ofdev->dev, "Err: can't map DIU registers!\n");
+       machine_data->diu_reg = of_iomap(np, 0);
+       if (!machine_data->diu_reg) {
+               dev_err(&pdev->dev, "cannot map DIU registers\n");
                ret = -EFAULT;
                goto error2;
        }
 
-       diu_mode = in_be32(&dr.diu_reg->diu_mode);
-       if (diu_mode != MFB_MODE1)
-               out_be32(&dr.diu_reg->diu_mode, 0);     /* disable DIU */
+       diu_mode = in_be32(&machine_data->diu_reg->diu_mode);
+       if (diu_mode == MFB_MODE0)
+               out_be32(&machine_data->diu_reg->diu_mode, 0); /* disable DIU */
 
        /* Get the IRQ of the DIU */
        machine_data->irq = irq_of_parse_and_map(np, 0);
 
        if (!machine_data->irq) {
-               dev_err(&ofdev->dev, "could not get DIU IRQ\n");
+               dev_err(&pdev->dev, "could not get DIU IRQ\n");
                ret = -EINVAL;
                goto error;
        }
        machine_data->monitor_port = monitor_port;
 
        /* Area descriptor memory pool aligns to 64-bit boundary */
-       if (allocate_buf(&ofdev->dev, &pool.ad,
+       if (allocate_buf(&pdev->dev, &machine_data->ad,
                         sizeof(struct diu_ad) * FSL_AOI_NUM, 8))
                return -ENOMEM;
 
        /* Get memory for Gamma Table  - 32-byte aligned memory */
-       if (allocate_buf(&ofdev->dev, &pool.gamma, 768, 32)) {
+       if (allocate_buf(&pdev->dev, &machine_data->gamma, 768, 32)) {
                ret = -ENOMEM;
                goto error;
        }
 
        /* For performance, cursor bitmap buffer aligns to 32-byte boundary */
-       if (allocate_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
-                        32)) {
+       if (allocate_buf(&pdev->dev, &machine_data->cursor,
+                        MAX_CURS * MAX_CURS * 2, 32)) {
                ret = -ENOMEM;
                goto error;
        }
 
        i = ARRAY_SIZE(machine_data->fsl_diu_info);
-       machine_data->dummy_ad = (struct diu_ad *)
-                       ((u32)pool.ad.vaddr + pool.ad.offset) + i;
-       machine_data->dummy_ad->paddr = pool.ad.paddr +
+       machine_data->dummy_ad = (struct diu_ad *)((u32)machine_data->ad.vaddr +
+                       machine_data->ad.offset) + i;
+       machine_data->dummy_ad->paddr = machine_data->ad.paddr +
                        i * sizeof(struct diu_ad);
        machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);
        if (!machine_data->dummy_aoi_virt) {
@@ -1581,30 +1595,29 @@ static int __devinit fsl_diu_probe(struct platform_device *ofdev)
         * Let DIU display splash screen if it was pre-initialized
         * by the bootloader, set dummy area descriptor otherwise.
         */
-       if (diu_mode != MFB_MODE1)
-               out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
+       if (diu_mode == MFB_MODE0)
+               out_be32(&machine_data->diu_reg->desc[0],
+                        machine_data->dummy_ad->paddr);
 
-       out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);
-       out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);
+       out_be32(&machine_data->diu_reg->desc[1], machine_data->dummy_ad->paddr);
+       out_be32(&machine_data->diu_reg->desc[2], machine_data->dummy_ad->paddr);
 
        for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
                machine_data->fsl_diu_info[i]->fix.smem_start = 0;
                mfbi = machine_data->fsl_diu_info[i]->par;
-               mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr
-                                       + pool.ad.offset) + i;
-               mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad);
+               mfbi->ad = (struct diu_ad *)((u32)machine_data->ad.vaddr
+                                       + machine_data->ad.offset) + i;
+               mfbi->ad->paddr =
+                       machine_data->ad.paddr + i * sizeof(struct diu_ad);
                ret = install_fb(machine_data->fsl_diu_info[i]);
                if (ret) {
-                       dev_err(&ofdev->dev,
-                               "Failed to register framebuffer %d\n",
-                               i);
+                       dev_err(&pdev->dev, "could not register fb %d\n", i);
                        goto error;
                }
        }
 
-       if (request_irq_local(machine_data->irq)) {
-               dev_err(machine_data->fsl_diu_info[0]->dev,
-                       "could not request irq for diu.");
+       if (request_irq_local(machine_data)) {
+               dev_err(&pdev->dev, "could not claim irq\n");
                goto error;
        }
 
@@ -1616,29 +1629,28 @@ static int __devinit fsl_diu_probe(struct platform_device *ofdev)
        error = device_create_file(machine_data->fsl_diu_info[0]->dev,
                                  &machine_data->dev_attr);
        if (error) {
-               dev_err(machine_data->fsl_diu_info[0]->dev,
-                       "could not create sysfs %s file\n",
+               dev_err(&pdev->dev, "could not create sysfs file %s\n",
                        machine_data->dev_attr.attr.name);
        }
 
-       dev_set_drvdata(&ofdev->dev, machine_data);
+       dev_set_drvdata(&pdev->dev, machine_data);
        return 0;
 
 error:
-       for (i = ARRAY_SIZE(machine_data->fsl_diu_info);
-               i > 0; i--)
-               uninstall_fb(machine_data->fsl_diu_info[i - 1]);
-       if (pool.ad.vaddr)
-               free_buf(&ofdev->dev, &pool.ad,
+       for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
+               uninstall_fb(machine_data->fsl_diu_info[i]);
+
+       if (machine_data->ad.vaddr)
+               free_buf(&pdev->dev, &machine_data->ad,
                         sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
-       if (pool.gamma.vaddr)
-               free_buf(&ofdev->dev, &pool.gamma, 768, 32);
-       if (pool.cursor.vaddr)
-               free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
-                        32);
+       if (machine_data->gamma.vaddr)
+               free_buf(&pdev->dev, &machine_data->gamma, 768, 32);
+       if (machine_data->cursor.vaddr)
+               free_buf(&pdev->dev, &machine_data->cursor,
+                        MAX_CURS * MAX_CURS * 2, 32);
        if (machine_data->dummy_aoi_virt)
                fsl_diu_free(machine_data->dummy_aoi_virt, 64);
-       iounmap(dr.diu_reg);
+       iounmap(machine_data->diu_reg);
 
 error2:
        for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
@@ -1649,28 +1661,27 @@ error2:
        return ret;
 }
 
-
-static int fsl_diu_remove(struct platform_device *ofdev)
+static int fsl_diu_remove(struct platform_device *pdev)
 {
        struct fsl_diu_data *machine_data;
        int i;
 
-       machine_data = dev_get_drvdata(&ofdev->dev);
+       machine_data = dev_get_drvdata(&pdev->dev);
        disable_lcdc(machine_data->fsl_diu_info[0]);
-       free_irq_local(machine_data->irq);
-       for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--)
-               uninstall_fb(machine_data->fsl_diu_info[i - 1]);
-       if (pool.ad.vaddr)
-               free_buf(&ofdev->dev, &pool.ad,
+       free_irq_local(machine_data);
+       for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
+               uninstall_fb(machine_data->fsl_diu_info[i]);
+       if (machine_data->ad.vaddr)
+               free_buf(&pdev->dev, &machine_data->ad,
                         sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
-       if (pool.gamma.vaddr)
-               free_buf(&ofdev->dev, &pool.gamma, 768, 32);
-       if (pool.cursor.vaddr)
-               free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
-                        32);
+       if (machine_data->gamma.vaddr)
+               free_buf(&pdev->dev, &machine_data->gamma, 768, 32);
+       if (machine_data->cursor.vaddr)
+               free_buf(&pdev->dev, &machine_data->cursor,
+                        MAX_CURS * MAX_CURS * 2, 32);
        if (machine_data->dummy_aoi_virt)
                fsl_diu_free(machine_data->dummy_aoi_virt, 64);
-       iounmap(dr.diu_reg);
+       iounmap(machine_data->diu_reg);
        for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
                if (machine_data->fsl_diu_info[i])
                        framebuffer_release(machine_data->fsl_diu_info[i]);
@@ -1692,8 +1703,7 @@ static int __init fsl_diu_setup(char *options)
                if (!*opt)
                        continue;
                if (!strncmp(opt, "monitor=", 8)) {
-                       if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2))
-                               monitor_port = val;
+                       monitor_port = fsl_diu_name_to_port(opt + 8);
                } else if (!strncmp(opt, "bpp=", 4)) {
                        if (!strict_strtoul(opt + 4, 10, &val))
                                default_bpp = val;
@@ -1720,7 +1730,7 @@ MODULE_DEVICE_TABLE(of, fsl_diu_match);
 
 static struct platform_driver fsl_diu_driver = {
        .driver = {
-               .name = "fsl_diu",
+               .name = "fsl-diu-fb",
                .owner = THIS_MODULE,
                .of_match_table = fsl_diu_match,
        },
@@ -1746,48 +1756,54 @@ static int __init fsl_diu_init(void)
        if (fb_get_options("fslfb", &option))
                return -ENODEV;
        fsl_diu_setup(option);
+#else
+       monitor_port = fsl_diu_name_to_port(monitor_string);
 #endif
-       printk(KERN_INFO "Freescale DIU driver\n");
+       pr_info("Freescale Display Interface Unit (DIU) framebuffer driver\n");
 
 #ifdef CONFIG_NOT_COHERENT_CACHE
        np = of_find_node_by_type(NULL, "cpu");
        if (!np) {
-               printk(KERN_ERR "Err: can't find device node 'cpu'\n");
+               pr_err("fsl-diu-fb: can't find 'cpu' device node\n");
                return -ENODEV;
        }
 
        prop = of_get_property(np, "d-cache-size", NULL);
        if (prop == NULL) {
+               pr_err("fsl-diu-fb: missing 'd-cache-size' property' "
+                      "in 'cpu' node\n");
                of_node_put(np);
                return -ENODEV;
        }
 
-       /* Freescale PLRU requires 13/8 times the cache size to do a proper
-          displacement flush
+       /*
+        * Freescale PLRU requires 13/8 times the cache size to do a proper
+        * displacement flush
         */
-       coherence_data_size = *prop * 13;
+       coherence_data_size = be32_to_cpup(prop) * 13;
        coherence_data_size /= 8;
 
        prop = of_get_property(np, "d-cache-line-size", NULL);
        if (prop == NULL) {
+               pr_err("fsl-diu-fb: missing 'd-cache-line-size' property' "
+                      "in 'cpu' node\n");
                of_node_put(np);
                return -ENODEV;
        }
-       d_cache_line_size = *prop;
+       d_cache_line_size = be32_to_cpup(prop);
 
        of_node_put(np);
        coherence_data = vmalloc(coherence_data_size);
        if (!coherence_data)
                return -ENOMEM;
 #endif
+
        ret = platform_driver_register(&fsl_diu_driver);
        if (ret) {
-               printk(KERN_ERR
-                       "fsl-diu: failed to register platform driver\n");
+               pr_err("fsl-diu-fb: failed to register platform driver\n");
 #if defined(CONFIG_NOT_COHERENT_CACHE)
                vfree(coherence_data);
 #endif
-               iounmap(dr.diu_reg);
        }
        return ret;
 }
@@ -1811,8 +1827,8 @@ module_param_named(mode, fb_mode, charp, 0);
 MODULE_PARM_DESC(mode,
        "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
 module_param_named(bpp, default_bpp, ulong, 0);
-MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
-module_param_named(monitor, monitor_port, int, 0);
-MODULE_PARM_DESC(monitor,
-       "Specify the monitor port (0, 1 or 2) if supported by the platform");
+MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified in 'mode'");
+module_param_named(monitor, monitor_string, charp, 0);
+MODULE_PARM_DESC(monitor, "Specify the monitor port "
+       "(\"dvi\", \"lvds\", or \"dlvds\") if supported by the platform");
 
index d662317..223896c 100644 (file)
@@ -149,10 +149,11 @@ int g364fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 static int g364fb_pan_display(struct fb_var_screeninfo *var, 
                              struct fb_info *info)
 {
-       if (var->xoffset || var->yoffset + var->yres > var->yres_virtual)
+       if (var->xoffset ||
+           var->yoffset + info->var.yres > info->var.yres_virtual)
                return -EINVAL;
 
-       *(unsigned int *) TOP_REG = var->yoffset * var->xres;
+       *(unsigned int *) TOP_REG = var->yoffset * info->var.xres;
        return 0;
 }
 
diff --git a/drivers/video/grvga.c b/drivers/video/grvga.c
new file mode 100644 (file)
index 0000000..f37e025
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ * Driver for Aeroflex Gaisler SVGACTRL framebuffer device.
+ *
+ * 2011 (c) Aeroflex Gaisler AB
+ *
+ * Full documentation of the core can be found here:
+ * http://www.gaisler.com/products/grlib/grip.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.
+ *
+ * Contributors: Kristoffer Glembo <kristoffer@gaisler.com>
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/io.h>
+
+struct grvga_regs {
+       u32 status;             /* 0x00 */
+       u32 video_length;       /* 0x04 */
+       u32 front_porch;        /* 0x08 */
+       u32 sync_length;        /* 0x0C */
+       u32 line_length;        /* 0x10 */
+       u32 fb_pos;             /* 0x14 */
+       u32 clk_vector[4];      /* 0x18 */
+       u32 clut;               /* 0x20 */
+};
+
+struct grvga_par {
+       struct grvga_regs *regs;
+       u32 color_palette[16];  /* 16 entry pseudo palette used by fbcon in true color mode */
+       int clk_sel;
+       int fb_alloced;         /* = 1 if framebuffer is allocated in main memory */
+};
+
+
+static const struct fb_videomode grvga_modedb[] = {
+    {
+       /* 640x480 @ 60 Hz */
+       NULL, 60, 640, 480, 40000, 48, 16, 39, 11, 96, 2,
+       0, FB_VMODE_NONINTERLACED
+    }, {
+       /* 800x600 @ 60 Hz */
+       NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
+       0, FB_VMODE_NONINTERLACED
+    }, {
+       /* 800x600 @ 72 Hz */
+       NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
+       0, FB_VMODE_NONINTERLACED
+    }, {
+       /* 1024x768 @ 60 Hz */
+       NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
+       0, FB_VMODE_NONINTERLACED
+    }
+ };
+
+static struct fb_fix_screeninfo grvga_fix __initdata = {
+       .id =           "AG SVGACTRL",
+       .type =         FB_TYPE_PACKED_PIXELS,
+       .visual =       FB_VISUAL_PSEUDOCOLOR,
+       .xpanstep =     0,
+       .ypanstep =     1,
+       .ywrapstep =    0,
+       .accel =        FB_ACCEL_NONE,
+};
+
+static int grvga_check_var(struct fb_var_screeninfo *var,
+                          struct fb_info *info)
+{
+       struct grvga_par *par = info->par;
+       int i;
+
+       if (!var->xres)
+               var->xres = 1;
+       if (!var->yres)
+               var->yres = 1;
+       if (var->bits_per_pixel <= 8)
+               var->bits_per_pixel = 8;
+       else if (var->bits_per_pixel <= 16)
+               var->bits_per_pixel = 16;
+       else if (var->bits_per_pixel <= 24)
+               var->bits_per_pixel = 24;
+       else if (var->bits_per_pixel <= 32)
+               var->bits_per_pixel = 32;
+       else
+               return -EINVAL;
+
+       var->xres_virtual = var->xres;
+       var->yres_virtual = 2*var->yres;
+
+       if (info->fix.smem_len) {
+               if ((var->yres_virtual*var->xres_virtual*var->bits_per_pixel/8) > info->fix.smem_len)
+                       return -ENOMEM;
+       }
+
+       /* Which clocks that are available can be read out in these registers */
+       for (i = 0; i <= 3 ; i++) {
+               if (var->pixclock == par->regs->clk_vector[i])
+                       break;
+       }
+       if (i <= 3)
+               par->clk_sel = i;
+       else
+               return -EINVAL;
+
+       switch (info->var.bits_per_pixel) {
+       case 8:
+               var->red   = (struct fb_bitfield) {0, 8, 0};      /* offset, length, msb-right */
+               var->green = (struct fb_bitfield) {0, 8, 0};
+               var->blue  = (struct fb_bitfield) {0, 8, 0};
+               var->transp = (struct fb_bitfield) {0, 0, 0};
+               break;
+       case 16:
+               var->red   = (struct fb_bitfield) {11, 5, 0};
+               var->green = (struct fb_bitfield) {5, 6, 0};
+               var->blue  = (struct fb_bitfield) {0, 5, 0};
+               var->transp = (struct fb_bitfield) {0, 0, 0};
+               break;
+       case 24:
+       case 32:
+               var->red   = (struct fb_bitfield) {16, 8, 0};
+               var->green = (struct fb_bitfield) {8, 8, 0};
+               var->blue  = (struct fb_bitfield) {0, 8, 0};
+               var->transp = (struct fb_bitfield) {24, 8, 0};
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int grvga_set_par(struct fb_info *info)
+{
+
+       u32 func = 0;
+       struct grvga_par *par = info->par;
+
+       __raw_writel(((info->var.yres - 1) << 16) | (info->var.xres - 1),
+                    &par->regs->video_length);
+
+       __raw_writel((info->var.lower_margin << 16) | (info->var.right_margin),
+                    &par->regs->front_porch);
+
+       __raw_writel((info->var.vsync_len << 16) | (info->var.hsync_len),
+                    &par->regs->sync_length);
+
+       __raw_writel(((info->var.yres + info->var.lower_margin + info->var.upper_margin + info->var.vsync_len - 1) << 16) |
+                    (info->var.xres + info->var.right_margin + info->var.left_margin + info->var.hsync_len - 1),
+                    &par->regs->line_length);
+
+       switch (info->var.bits_per_pixel) {
+       case 8:
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+               func = 1;
+               break;
+       case 16:
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               func = 2;
+               break;
+       case 24:
+       case 32:
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               func = 3;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       __raw_writel((par->clk_sel << 6) | (func << 4) | 1,
+                    &par->regs->status);
+
+       info->fix.line_length = (info->var.xres_virtual*info->var.bits_per_pixel)/8;
+       return 0;
+}
+
+static int grvga_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
+{
+       struct grvga_par *par;
+       par = info->par;
+
+       if (regno >= 256)       /* Size of CLUT */
+               return -EINVAL;
+
+       if (info->var.grayscale) {
+               /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+               red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+       }
+
+
+
+#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
+
+       red    = CNVT_TOHW(red,   info->var.red.length);
+       green  = CNVT_TOHW(green, info->var.green.length);
+       blue   = CNVT_TOHW(blue,  info->var.blue.length);
+       transp = CNVT_TOHW(transp, info->var.transp.length);
+
+#undef CNVT_TOHW
+
+       /* In PSEUDOCOLOR we use the hardware CLUT */
+       if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+               __raw_writel((regno << 24) | (red << 16) | (green << 8) | blue,
+                            &par->regs->clut);
+
+       /* Truecolor uses the pseudo palette */
+       else if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+               u32 v;
+               if (regno >= 16)
+                       return -EINVAL;
+
+
+               v =     (red    << info->var.red.offset)   |
+                       (green  << info->var.green.offset) |
+                       (blue   << info->var.blue.offset)  |
+                       (transp << info->var.transp.offset);
+
+               ((u32 *) (info->pseudo_palette))[regno] = v;
+       }
+       return 0;
+}
+
+static int grvga_pan_display(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
+{
+       struct grvga_par *par = info->par;
+       struct fb_fix_screeninfo *fix = &info->fix;
+       u32 base_addr;
+
+       if (var->xoffset != 0)
+               return -EINVAL;
+
+       base_addr = fix->smem_start + (var->yoffset * fix->line_length);
+       base_addr &= ~3UL;
+
+       /* Set framebuffer base address  */
+       __raw_writel(base_addr,
+                    &par->regs->fb_pos);
+
+       return 0;
+}
+
+static struct fb_ops grvga_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = grvga_check_var,
+       .fb_set_par     = grvga_set_par,
+       .fb_setcolreg   = grvga_setcolreg,
+       .fb_pan_display = grvga_pan_display,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit
+};
+
+static int __init grvga_parse_custom(char *options,
+                                    struct fb_var_screeninfo *screendata)
+{
+       char *this_opt;
+       int count = 0;
+       if (!options || !*options)
+               return -1;
+
+       while ((this_opt = strsep(&options, " ")) != NULL) {
+               if (!*this_opt)
+                       continue;
+
+               switch (count) {
+               case 0:
+                       screendata->pixclock = simple_strtoul(this_opt, NULL, 0);
+                       count++;
+                       break;
+               case 1:
+                       screendata->xres = screendata->xres_virtual = simple_strtoul(this_opt, NULL, 0);
+                       count++;
+                       break;
+               case 2:
+                       screendata->right_margin = simple_strtoul(this_opt, NULL, 0);
+                       count++;
+                       break;
+               case 3:
+                       screendata->hsync_len = simple_strtoul(this_opt, NULL, 0);
+                       count++;
+                       break;
+               case 4:
+                       screendata->left_margin = simple_strtoul(this_opt, NULL, 0);
+                       count++;
+                       break;
+               case 5:
+                       screendata->yres = screendata->yres_virtual = simple_strtoul(this_opt, NULL, 0);
+                       count++;
+                       break;
+               case 6:
+                       screendata->lower_margin = simple_strtoul(this_opt, NULL, 0);
+                       count++;
+                       break;
+               case 7:
+                       screendata->vsync_len = simple_strtoul(this_opt, NULL, 0);
+                       count++;
+                       break;
+               case 8:
+                       screendata->upper_margin = simple_strtoul(this_opt, NULL, 0);
+                       count++;
+                       break;
+               case 9:
+                       screendata->bits_per_pixel = simple_strtoul(this_opt, NULL, 0);
+                       count++;
+                       break;
+               default:
+                       return -1;
+               }
+       }
+       screendata->activate  = FB_ACTIVATE_NOW;
+       screendata->vmode     = FB_VMODE_NONINTERLACED;
+       return 0;
+}
+
+static int __devinit grvga_probe(struct platform_device *dev)
+{
+       struct fb_info *info;
+       int retval = -ENOMEM;
+       unsigned long virtual_start;
+       unsigned long grvga_fix_addr = 0;
+       unsigned long physical_start = 0;
+       unsigned long grvga_mem_size = 0;
+       struct grvga_par *par = NULL;
+       char *options = NULL, *mode_opt = NULL;
+
+       info = framebuffer_alloc(sizeof(struct grvga_par), &dev->dev);
+       if (!info) {
+               dev_err(&dev->dev, "framebuffer_alloc failed\n");
+               return -ENOMEM;
+       }
+
+       /* Expecting: "grvga: modestring, [addr:<framebuffer physical address>], [size:<framebuffer size>]
+        *
+        * If modestring is custom:<custom mode string> we parse the string which then contains all videoparameters
+        * If address is left out, we allocate memory,
+        * if size is left out we only allocate enough to support the given mode.
+        */
+       if (fb_get_options("grvga", &options)) {
+               retval = -ENODEV;
+               goto err;
+       }
+
+       if (!options || !*options)
+               options =  "640x480-8@60";
+
+       while (1) {
+               char *this_opt = strsep(&options, ",");
+
+               if (!this_opt)
+                       break;
+
+               if (!strncmp(this_opt, "custom", 6)) {
+                       if (grvga_parse_custom(this_opt, &info->var) < 0) {
+                               dev_err(&dev->dev, "Failed to parse custom mode (%s).\n", this_opt);
+                               retval = -EINVAL;
+                               goto err1;
+                       }
+               } else if (!strncmp(this_opt, "addr", 4))
+                       grvga_fix_addr = simple_strtoul(this_opt + 5, NULL, 16);
+               else if (!strncmp(this_opt, "size", 4))
+                       grvga_mem_size = simple_strtoul(this_opt + 5, NULL, 0);
+               else
+                       mode_opt = this_opt;
+       }
+
+       par = info->par;
+       info->fbops = &grvga_ops;
+       info->fix = grvga_fix;
+       info->pseudo_palette = par->color_palette;
+       info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+       info->fix.smem_len = grvga_mem_size;
+
+       if (!request_mem_region(dev->resource[0].start, resource_size(&dev->resource[0]), "grlib-svgactrl regs")) {
+               dev_err(&dev->dev, "registers already mapped\n");
+               retval = -EBUSY;
+               goto err;
+       }
+
+       par->regs = of_ioremap(&dev->resource[0], 0,
+                              resource_size(&dev->resource[0]),
+                              "grlib-svgactrl regs");
+
+       if (!par->regs) {
+               dev_err(&dev->dev, "failed to map registers\n");
+               retval = -ENOMEM;
+               goto err1;
+       }
+
+       retval = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (retval < 0) {
+               dev_err(&dev->dev, "failed to allocate mem with fb_alloc_cmap\n");
+               retval = -ENOMEM;
+               goto err2;
+       }
+
+       if (mode_opt) {
+               retval = fb_find_mode(&info->var, info, mode_opt,
+                                     grvga_modedb, sizeof(grvga_modedb), &grvga_modedb[0], 8);
+               if (!retval || retval == 4) {
+                       retval = -EINVAL;
+                       goto err3;
+               }
+       }
+
+       if (!grvga_mem_size)
+               grvga_mem_size = info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel/8;
+
+       if (grvga_fix_addr) {
+               /* Got framebuffer base address from argument list */
+
+               physical_start = grvga_fix_addr;
+
+               if (!request_mem_region(physical_start, grvga_mem_size, dev->name)) {
+                       dev_err(&dev->dev, "failed to request memory region\n");
+                       retval = -ENOMEM;
+                       goto err3;
+               }
+
+               virtual_start = (unsigned long) ioremap(physical_start, grvga_mem_size);
+
+               if (!virtual_start) {
+                       dev_err(&dev->dev, "error mapping framebuffer memory\n");
+                       retval = -ENOMEM;
+                       goto err4;
+               }
+       } else {        /* Allocate frambuffer memory */
+
+               unsigned long page;
+
+               virtual_start = (unsigned long) __get_free_pages(GFP_DMA,
+                                                                get_order(grvga_mem_size));
+               if (!virtual_start) {
+                       dev_err(&dev->dev,
+                               "unable to allocate framebuffer memory (%lu bytes)\n",
+                               grvga_mem_size);
+                       retval = -ENOMEM;
+                       goto err3;
+               }
+
+               physical_start = dma_map_single(&dev->dev, (void *)virtual_start, grvga_mem_size, DMA_TO_DEVICE);
+
+               /* Set page reserved so that mmap will work. This is necessary
+                * since we'll be remapping normal memory.
+                */
+               for (page = virtual_start;
+                    page < PAGE_ALIGN(virtual_start + grvga_mem_size);
+                    page += PAGE_SIZE) {
+                       SetPageReserved(virt_to_page(page));
+               }
+
+               par->fb_alloced = 1;
+       }
+
+       memset((unsigned long *) virtual_start, 0, grvga_mem_size);
+
+       info->screen_base = (char __iomem *) virtual_start;
+       info->fix.smem_start = physical_start;
+       info->fix.smem_len   = grvga_mem_size;
+
+       dev_set_drvdata(&dev->dev, info);
+
+       dev_info(&dev->dev,
+                "Aeroflex Gaisler framebuffer device (fb%d), %dx%d-%d, using %luK of video memory @ %p\n",
+                info->node, info->var.xres, info->var.yres, info->var.bits_per_pixel,
+                grvga_mem_size >> 10, info->screen_base);
+
+       retval = register_framebuffer(info);
+       if (retval < 0) {
+               dev_err(&dev->dev, "failed to register framebuffer\n");
+               goto err4;
+       }
+
+       __raw_writel(physical_start, &par->regs->fb_pos);
+       __raw_writel(__raw_readl(&par->regs->status) | 1,  /* Enable framebuffer */
+                    &par->regs->status);
+
+       return 0;
+
+err4:
+       dev_set_drvdata(&dev->dev, NULL);
+       if (grvga_fix_addr) {
+               release_mem_region(physical_start, grvga_mem_size);
+               iounmap((void *)virtual_start);
+       } else
+               kfree((void *)virtual_start);
+err3:
+       fb_dealloc_cmap(&info->cmap);
+err2:
+       of_iounmap(&dev->resource[0], par->regs,
+                  resource_size(&dev->resource[0]));
+err1:
+       release_mem_region(dev->resource[0].start, resource_size(&dev->resource[0]));
+err:
+       framebuffer_release(info);
+
+       return retval;
+}
+
+static int __devexit grvga_remove(struct platform_device *device)
+{
+       struct fb_info *info = dev_get_drvdata(&device->dev);
+       struct grvga_par *par = info->par;
+
+       if (info) {
+               unregister_framebuffer(info);
+               fb_dealloc_cmap(&info->cmap);
+
+               of_iounmap(&device->resource[0], par->regs,
+                          resource_size(&device->resource[0]));
+               release_mem_region(device->resource[0].start, resource_size(&device->resource[0]));
+
+               if (!par->fb_alloced) {
+                       release_mem_region(info->fix.smem_start, info->fix.smem_len);
+                       iounmap(info->screen_base);
+               } else
+                       kfree((void *)info->screen_base);
+
+               framebuffer_release(info);
+               dev_set_drvdata(&device->dev, NULL);
+       }
+
+       return 0;
+}
+
+static struct of_device_id svgactrl_of_match[] = {
+       {
+               .name = "GAISLER_SVGACTRL",
+       },
+       {
+               .name = "01_063",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, svgactrl_of_match);
+
+static struct platform_driver grvga_driver = {
+       .driver = {
+               .name = "grlib-svgactrl",
+               .owner = THIS_MODULE,
+               .of_match_table = svgactrl_of_match,
+       },
+       .probe          = grvga_probe,
+       .remove         = __devexit_p(grvga_remove),
+};
+
+
+static int __init grvga_init(void)
+{
+       return platform_driver_register(&grvga_driver);
+}
+
+static void __exit grvga_exit(void)
+{
+       platform_driver_unregister(&grvga_driver);
+}
+
+module_init(grvga_init);
+module_exit(grvga_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Aeroflex Gaisler");
+MODULE_DESCRIPTION("Aeroflex Gaisler framebuffer device driver");
index 896e53d..0fad23f 100644 (file)
@@ -543,8 +543,8 @@ static int gxt4500_pan_display(struct fb_var_screeninfo *var,
 
        if (var->xoffset & 7)
                return -EINVAL;
-       if (var->xoffset + var->xres > var->xres_virtual ||
-           var->yoffset + var->yres > var->yres_virtual)
+       if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+           var->yoffset + info->var.yres > info->var.yres_virtual)
                return -EINVAL;
 
        writereg(par, REFRESH_START, (var->xoffset << 16) | var->yoffset);
index 4052718..4394389 100644 (file)
@@ -422,8 +422,8 @@ static int hgafb_pan_display(struct fb_var_screeninfo *var,
                    var->xoffset)
                        return -EINVAL;
        } else {
-               if (var->xoffset + var->xres > info->var.xres_virtual
-                || var->yoffset + var->yres > info->var.yres_virtual
+               if (var->xoffset + info->var.xres > info->var.xres_virtual
+                || var->yoffset + info->var.yres > info->var.yres_virtual
                 || var->yoffset % 8)
                        return -EINVAL;
        }
index efb2c10..8149356 100644 (file)
@@ -749,7 +749,7 @@ set_offset (struct fb_var_screeninfo *var, struct fb_info *info)
 {
        struct imstt_par *par = info->par;
        __u32 off = var->yoffset * (info->fix.line_length >> 3)
-                   + ((var->xoffset * (var->bits_per_pixel >> 3)) >> 3);
+                   + ((var->xoffset * (info->var.bits_per_pixel >> 3)) >> 3);
        write_reg_le32(par->dc_regs, SSR, off);
 }
 
index 38065cf..fbad61d 100644 (file)
@@ -390,12 +390,12 @@ int intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
        xoffset = ROUND_DOWN_TO(var->xoffset, 8);
        yoffset = var->yoffset;
 
-       if ((xoffset + var->xres > var->xres_virtual) ||
-           (yoffset + var->yres > var->yres_virtual))
+       if ((xoffset + info->var.xres > info->var.xres_virtual) ||
+           (yoffset + info->var.yres > info->var.yres_virtual))
                return -EINVAL;
 
        offset = (yoffset * dinfo->pitch) +
-                (xoffset * var->bits_per_pixel) / 8;
+                (xoffset * info->var.bits_per_pixel) / 8;
 
        offset += dinfo->fb.offset << 12;
 
index b953099..934081d 100644 (file)
@@ -23,7 +23,7 @@ static int mb862xx_i2c_wait_event(struct i2c_adapter *adap)
        u32 reg;
 
        do {
-               udelay(1);
+               udelay(10);
                reg = inreg(i2c, GC_I2C_BCR);
                if (reg & (I2C_INT | I2C_BER))
                        break;
index ee1de3e..c16ff1d 100644 (file)
@@ -278,7 +278,7 @@ static int mb862xxfb_pan(struct fb_var_screeninfo *var,
        reg = pack(var->yoffset, var->xoffset);
        outreg(disp, GC_L0WY_L0WX, reg);
 
-       reg = pack(var->yres_virtual, var->xres_virtual);
+       reg = pack(info->var.yres_virtual, info->var.xres_virtual);
        outreg(disp, GC_L0WH_L0WW, reg);
        return 0;
 }
@@ -737,7 +737,7 @@ static int __devinit of_platform_mb862xx_probe(struct platform_device *ofdev)
        if (mb862xx_gdc_init(par))
                goto io_unmap;
 
-       if (request_irq(par->irq, mb862xx_intr, IRQF_DISABLED,
+       if (request_irq(par->irq, mb862xx_intr, 0,
                        DRV_NAME, (void *)par)) {
                dev_err(dev, "Cannot request irq\n");
                goto io_unmap;
@@ -1073,7 +1073,7 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
        if (mb862xx_pci_gdc_init(par))
                goto io_unmap;
 
-       if (request_irq(par->irq, mb862xx_intr, IRQF_DISABLED | IRQF_SHARED,
+       if (request_irq(par->irq, mb862xx_intr, IRQF_SHARED,
                        DRV_NAME, (void *)par)) {
                dev_err(dev, "Cannot request irq\n");
                goto io_unmap;
index cb175fe..a9a907c 100644 (file)
@@ -491,55 +491,56 @@ EXPORT_SYMBOL(vesa_modes);
 static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
                       const struct fb_videomode *mode, unsigned int bpp)
 {
-    int err = 0;
-
-    DPRINTK("Trying mode %s %dx%d-%d@%d\n", mode->name ? mode->name : "noname",
-           mode->xres, mode->yres, bpp, mode->refresh);
-    var->xres = mode->xres;
-    var->yres = mode->yres;
-    var->xres_virtual = mode->xres;
-    var->yres_virtual = mode->yres;
-    var->xoffset = 0;
-    var->yoffset = 0;
-    var->bits_per_pixel = bpp;
-    var->activate |= FB_ACTIVATE_TEST;
-    var->pixclock = mode->pixclock;
-    var->left_margin = mode->left_margin;
-    var->right_margin = mode->right_margin;
-    var->upper_margin = mode->upper_margin;
-    var->lower_margin = mode->lower_margin;
-    var->hsync_len = mode->hsync_len;
-    var->vsync_len = mode->vsync_len;
-    var->sync = mode->sync;
-    var->vmode = mode->vmode;
-    if (info->fbops->fb_check_var)
-       err = info->fbops->fb_check_var(var, info);
-    var->activate &= ~FB_ACTIVATE_TEST;
-    return err;
+       int err = 0;
+
+       DPRINTK("Trying mode %s %dx%d-%d@%d\n",
+               mode->name ? mode->name : "noname",
+               mode->xres, mode->yres, bpp, mode->refresh);
+       var->xres = mode->xres;
+       var->yres = mode->yres;
+       var->xres_virtual = mode->xres;
+       var->yres_virtual = mode->yres;
+       var->xoffset = 0;
+       var->yoffset = 0;
+       var->bits_per_pixel = bpp;
+       var->activate |= FB_ACTIVATE_TEST;
+       var->pixclock = mode->pixclock;
+       var->left_margin = mode->left_margin;
+       var->right_margin = mode->right_margin;
+       var->upper_margin = mode->upper_margin;
+       var->lower_margin = mode->lower_margin;
+       var->hsync_len = mode->hsync_len;
+       var->vsync_len = mode->vsync_len;
+       var->sync = mode->sync;
+       var->vmode = mode->vmode;
+       if (info->fbops->fb_check_var)
+               err = info->fbops->fb_check_var(var, info);
+       var->activate &= ~FB_ACTIVATE_TEST;
+       return err;
 }
 
 /**
- *     fb_find_mode - finds a valid video mode
- *     @var: frame buffer user defined part of display
- *     @info: frame buffer info structure
- *     @mode_option: string video mode to find
- *     @db: video mode database
- *     @dbsize: size of @db
- *     @default_mode: default video mode to fall back to
- *     @default_bpp: default color depth in bits per pixel
+ *     fb_find_mode - finds a valid video mode
+ *     @var: frame buffer user defined part of display
+ *     @info: frame buffer info structure
+ *     @mode_option: string video mode to find
+ *     @db: video mode database
+ *     @dbsize: size of @db
+ *     @default_mode: default video mode to fall back to
+ *     @default_bpp: default color depth in bits per pixel
  *
- *     Finds a suitable video mode, starting with the specified mode
- *     in @mode_option with fallback to @default_mode.  If
- *     @default_mode fails, all modes in the video mode database will
- *     be tried.
+ *     Finds a suitable video mode, starting with the specified mode
+ *     in @mode_option with fallback to @default_mode.  If
+ *     @default_mode fails, all modes in the video mode database will
+ *     be tried.
  *
- *     Valid mode specifiers for @mode_option:
+ *     Valid mode specifiers for @mode_option:
  *
- *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or
- *     <name>[-<bpp>][@<refresh>]
+ *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or
+ *     <name>[-<bpp>][@<refresh>]
  *
- *     with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
- *     <name> a string.
+ *     with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
+ *     <name> a string.
  *
  *      If 'M' is present after yres (and before refresh/bpp if present),
  *      the function will compute the timings using VESA(tm) Coordinated
@@ -551,12 +552,12 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
  *
  *      1024x768MR-8@60m - Reduced blank with margins at 60Hz.
  *
- *     NOTE: The passed struct @var is _not_ cleared!  This allows you
- *     to supply values for e.g. the grayscale and accel_flags fields.
+ *     NOTE: The passed struct @var is _not_ cleared!  This allows you
+ *     to supply values for e.g. the grayscale and accel_flags fields.
  *
- *     Returns zero for failure, 1 if using specified @mode_option,
- *     2 if using specified @mode_option with an ignored refresh rate,
- *     3 if default mode is used, 4 if fall back to any valid mode.
+ *     Returns zero for failure, 1 if using specified @mode_option,
+ *     2 if using specified @mode_option with an ignored refresh rate,
+ *     3 if default mode is used, 4 if fall back to any valid mode.
  *
  */
 
@@ -566,198 +567,203 @@ int fb_find_mode(struct fb_var_screeninfo *var,
                 const struct fb_videomode *default_mode,
                 unsigned int default_bpp)
 {
-    int i;
-
-    /* Set up defaults */
-    if (!db) {
-       db = modedb;
-       dbsize = ARRAY_SIZE(modedb);
-    }
-
-    if (!default_mode)
-       default_mode = &db[0];
-
-    if (!default_bpp)
-       default_bpp = 8;
-
-    /* Did the user specify a video mode? */
-    if (!mode_option)
-       mode_option = fb_mode_option;
-    if (mode_option) {
-       const char *name = mode_option;
-       unsigned int namelen = strlen(name);
-       int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
-       unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
-       int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
-       u32 best, diff, tdiff;
-
-       for (i = namelen-1; i >= 0; i--) {
-           switch (name[i]) {
-               case '@':
-                   namelen = i;
-                   if (!refresh_specified && !bpp_specified &&
-                       !yres_specified) {
-                       refresh = simple_strtol(&name[i+1], NULL, 10);
-                       refresh_specified = 1;
-                       if (cvt || rb)
-                           cvt = 0;
-                   } else
-                       goto done;
-                   break;
-               case '-':
-                   namelen = i;
-                   if (!bpp_specified && !yres_specified) {
-                       bpp = simple_strtol(&name[i+1], NULL, 10);
-                       bpp_specified = 1;
-                       if (cvt || rb)
-                           cvt = 0;
-                   } else
-                       goto done;
-                   break;
-               case 'x':
-                   if (!yres_specified) {
-                       yres = simple_strtol(&name[i+1], NULL, 10);
-                       yres_specified = 1;
-                   } else
-                       goto done;
-                   break;
-               case '0' ... '9':
-                   break;
-               case 'M':
-                   if (!yres_specified)
-                       cvt = 1;
-                   break;
-               case 'R':
-                   if (!cvt)
-                       rb = 1;
-                   break;
-               case 'm':
-                   if (!cvt)
-                       margins = 1;
-                   break;
-               case 'i':
-                   if (!cvt)
-                       interlace = 1;
-                   break;
-               default:
-                   goto done;
-           }
-       }
-       if (i < 0 && yres_specified) {
-           xres = simple_strtol(name, NULL, 10);
-           res_specified = 1;
-       }
-done:
-       if (cvt) {
-           struct fb_videomode cvt_mode;
-           int ret;
-
-           DPRINTK("CVT mode %dx%d@%dHz%s%s%s\n", xres, yres,
-                   (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
-                   "", (margins) ? " with margins" : "", (interlace) ?
-                   " interlaced" : "");
-
-           memset(&cvt_mode, 0, sizeof(cvt_mode));
-           cvt_mode.xres = xres;
-           cvt_mode.yres = yres;
-           cvt_mode.refresh = (refresh) ? refresh : 60;
+       int i;
 
-           if (interlace)
-               cvt_mode.vmode |= FB_VMODE_INTERLACED;
-           else
-               cvt_mode.vmode &= ~FB_VMODE_INTERLACED;
+       /* Set up defaults */
+       if (!db) {
+               db = modedb;
+               dbsize = ARRAY_SIZE(modedb);
+       }
 
-           ret = fb_find_mode_cvt(&cvt_mode, margins, rb);
+       if (!default_mode)
+               default_mode = &db[0];
+
+       if (!default_bpp)
+               default_bpp = 8;
+
+       /* Did the user specify a video mode? */
+       if (!mode_option)
+               mode_option = fb_mode_option;
+       if (mode_option) {
+               const char *name = mode_option;
+               unsigned int namelen = strlen(name);
+               int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
+               unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
+               int yres_specified = 0, cvt = 0, rb = 0, interlace = 0;
+               int margins = 0;
+               u32 best, diff, tdiff;
+
+               for (i = namelen-1; i >= 0; i--) {
+                       switch (name[i]) {
+                       case '@':
+                               namelen = i;
+                               if (!refresh_specified && !bpp_specified &&
+                                   !yres_specified) {
+                                       refresh = simple_strtol(&name[i+1], NULL,
+                                                               10);
+                                       refresh_specified = 1;
+                                       if (cvt || rb)
+                                               cvt = 0;
+                               } else
+                                       goto done;
+                               break;
+                       case '-':
+                               namelen = i;
+                               if (!bpp_specified && !yres_specified) {
+                                       bpp = simple_strtol(&name[i+1], NULL,
+                                                           10);
+                                       bpp_specified = 1;
+                                       if (cvt || rb)
+                                               cvt = 0;
+                               } else
+                                       goto done;
+                               break;
+                       case 'x':
+                               if (!yres_specified) {
+                                       yres = simple_strtol(&name[i+1], NULL,
+                                                            10);
+                                       yres_specified = 1;
+                               } else
+                                       goto done;
+                               break;
+                       case '0' ... '9':
+                               break;
+                       case 'M':
+                               if (!yres_specified)
+                                       cvt = 1;
+                               break;
+                       case 'R':
+                               if (!cvt)
+                                       rb = 1;
+                               break;
+                       case 'm':
+                               if (!cvt)
+                                       margins = 1;
+                               break;
+                       case 'i':
+                               if (!cvt)
+                                       interlace = 1;
+                               break;
+                       default:
+                               goto done;
+                       }
+               }
+               if (i < 0 && yres_specified) {
+                       xres = simple_strtol(name, NULL, 10);
+                       res_specified = 1;
+               }
+done:
+               if (cvt) {
+                       struct fb_videomode cvt_mode;
+                       int ret;
+
+                       DPRINTK("CVT mode %dx%d@%dHz%s%s%s\n", xres, yres,
+                               (refresh) ? refresh : 60,
+                               (rb) ? " reduced blanking" : "",
+                               (margins) ? " with margins" : "",
+                               (interlace) ? " interlaced" : "");
+
+                       memset(&cvt_mode, 0, sizeof(cvt_mode));
+                       cvt_mode.xres = xres;
+                       cvt_mode.yres = yres;
+                       cvt_mode.refresh = (refresh) ? refresh : 60;
+
+                       if (interlace)
+                               cvt_mode.vmode |= FB_VMODE_INTERLACED;
+                       else
+                               cvt_mode.vmode &= ~FB_VMODE_INTERLACED;
+
+                       ret = fb_find_mode_cvt(&cvt_mode, margins, rb);
+
+                       if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) {
+                               DPRINTK("modedb CVT: CVT mode ok\n");
+                               return 1;
+                       }
 
-           if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) {
-               DPRINTK("modedb CVT: CVT mode ok\n");
-               return 1;
-           }
+                       DPRINTK("CVT mode invalid, getting mode from database\n");
+               }
 
-           DPRINTK("CVT mode invalid, getting mode from database\n");
-       }
+               DPRINTK("Trying specified video mode%s %ix%i\n",
+                       refresh_specified ? "" : " (ignoring refresh rate)",
+                       xres, yres);
 
-       DPRINTK("Trying specified video mode%s %ix%i\n",
-           refresh_specified ? "" : " (ignoring refresh rate)", xres, yres);
-
-       if (!refresh_specified) {
-               /*
-                * If the caller has provided a custom mode database and a
-                * valid monspecs structure, we look for the mode with the
-                * highest refresh rate.  Otherwise we play it safe it and
-                * try to find a mode with a refresh rate closest to the
-                * standard 60 Hz.
-                */
-               if (db != modedb &&
-                   info->monspecs.vfmin && info->monspecs.vfmax &&
-                   info->monspecs.hfmin && info->monspecs.hfmax &&
-                   info->monspecs.dclkmax) {
-                       refresh = 1000;
-               } else {
-                       refresh = 60;
+               if (!refresh_specified) {
+                       /*
+                        * If the caller has provided a custom mode database and
+                        * a valid monspecs structure, we look for the mode with
+                        * the highest refresh rate.  Otherwise we play it safe
+                        * it and try to find a mode with a refresh rate closest
+                        * to the standard 60 Hz.
+                        */
+                       if (db != modedb &&
+                           info->monspecs.vfmin && info->monspecs.vfmax &&
+                           info->monspecs.hfmin && info->monspecs.hfmax &&
+                           info->monspecs.dclkmax) {
+                               refresh = 1000;
+                       } else {
+                               refresh = 60;
+                       }
                }
-       }
 
-       diff = -1;
-       best = -1;
-       for (i = 0; i < dbsize; i++) {
-               if ((name_matches(db[i], name, namelen) ||
-                   (res_specified && res_matches(db[i], xres, yres))) &&
-                   !fb_try_mode(var, info, &db[i], bpp)) {
-                       if (refresh_specified && db[i].refresh == refresh) {
-                               return 1;
-                       } else {
+               diff = -1;
+               best = -1;
+               for (i = 0; i < dbsize; i++) {
+                       if ((name_matches(db[i], name, namelen) ||
+                            (res_specified && res_matches(db[i], xres, yres))) &&
+                           !fb_try_mode(var, info, &db[i], bpp)) {
+                               if (refresh_specified && db[i].refresh == refresh)
+                                       return 1;
+
                                if (abs(db[i].refresh - refresh) < diff) {
                                        diff = abs(db[i].refresh - refresh);
                                        best = i;
                                }
                        }
                }
-       }
-       if (best != -1) {
-               fb_try_mode(var, info, &db[best], bpp);
-               return (refresh_specified) ? 2 : 1;
-       }
-
-       diff = 2 * (xres + yres);
-       best = -1;
-       DPRINTK("Trying best-fit modes\n");
-       for (i = 0; i < dbsize; i++) {
-               DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres);
-               if (!fb_try_mode(var, info, &db[i], bpp)) {
-                       tdiff = abs(db[i].xres - xres) +
-                               abs(db[i].yres - yres);
-
-                       /*
-                        * Penalize modes with resolutions smaller
-                        * than requested.
-                        */
-                       if (xres > db[i].xres || yres > db[i].yres)
-                               tdiff += xres + yres;
+               if (best != -1) {
+                       fb_try_mode(var, info, &db[best], bpp);
+                       return (refresh_specified) ? 2 : 1;
+               }
 
-                       if (diff > tdiff) {
-                               diff = tdiff;
-                               best = i;
+               diff = 2 * (xres + yres);
+               best = -1;
+               DPRINTK("Trying best-fit modes\n");
+               for (i = 0; i < dbsize; i++) {
+                       DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres);
+                       if (!fb_try_mode(var, info, &db[i], bpp)) {
+                               tdiff = abs(db[i].xres - xres) +
+                                       abs(db[i].yres - yres);
+
+                               /*
+                                * Penalize modes with resolutions smaller
+                                * than requested.
+                                */
+                               if (xres > db[i].xres || yres > db[i].yres)
+                                       tdiff += xres + yres;
+
+                               if (diff > tdiff) {
+                                       diff = tdiff;
+                                       best = i;
+                               }
                        }
                }
+               if (best != -1) {
+                       fb_try_mode(var, info, &db[best], bpp);
+                       return 5;
+               }
        }
-       if (best != -1) {
-           fb_try_mode(var, info, &db[best], bpp);
-           return 5;
-       }
-    }
 
-    DPRINTK("Trying default video mode\n");
-    if (!fb_try_mode(var, info, default_mode, default_bpp))
-       return 3;
+       DPRINTK("Trying default video mode\n");
+       if (!fb_try_mode(var, info, default_mode, default_bpp))
+               return 3;
 
-    DPRINTK("Trying all modes\n");
-    for (i = 0; i < dbsize; i++)
-       if (!fb_try_mode(var, info, &db[i], default_bpp))
-           return 4;
+       DPRINTK("Trying all modes\n");
+       for (i = 0; i < dbsize; i++)
+               if (!fb_try_mode(var, info, &db[i], default_bpp))
+                       return 4;
 
-    DPRINTK("No valid mode found\n");
-    return 0;
+       DPRINTK("No valid mode found\n");
+       return 0;
 }
 
 /**
index 178b072..4527cbf 100644 (file)
@@ -715,7 +715,7 @@ static int __devinit mddi_probe(struct platform_device *pdev)
 
        mddi->int_enable = 0;
        mddi_writel(mddi->int_enable, INTEN);
-       ret = request_irq(mddi->irq, mddi_isr, IRQF_DISABLED, "mddi",
+       ret = request_irq(mddi->irq, mddi_isr, 0, "mddi",
                          &mddi->client_data);
        if (ret) {
                printk(KERN_ERR "mddi: failed to request enable irq!\n");
index 243d16f..b934477 100644 (file)
@@ -421,10 +421,11 @@ int mdp_probe(struct platform_device *pdev)
        clk = clk_get(&pdev->dev, "mdp_clk");
        if (IS_ERR(clk)) {
                printk(KERN_INFO "mdp: failed to get mdp clk");
-               return PTR_ERR(clk);
+               ret = PTR_ERR(clk);
+               goto error_get_clk;
        }
 
-       ret = request_irq(mdp->irq, mdp_isr, IRQF_DISABLED, "msm_mdp", mdp);
+       ret = request_irq(mdp->irq, mdp_isr, 0, "msm_mdp", mdp);
        if (ret)
                goto error_request_irq;
        disable_irq(mdp->irq);
@@ -495,6 +496,7 @@ int mdp_probe(struct platform_device *pdev)
 error_device_register:
        free_irq(mdp->irq, mdp);
 error_request_irq:
+error_get_clk:
        iounmap(mdp->base);
 error_get_irq:
 error_ioremap:
index 7e3a490..e3406ab 100644 (file)
@@ -382,6 +382,9 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi)
        uint32_t enabled;
        unsigned long flags;
 
+       if (mx3_fbi->txd == NULL)
+               return;
+
        spin_lock_irqsave(&mx3fb->lock, flags);
 
        enabled = sdc_fb_uninit(mx3_fbi);
@@ -986,9 +989,19 @@ static void __blank(int blank, struct fb_info *fbi)
 {
        struct mx3fb_info *mx3_fbi = fbi->par;
        struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
+       int was_blank = mx3_fbi->blank;
 
        mx3_fbi->blank = blank;
 
+       /* Attention!
+        * Do not call sdc_disable_channel() for a channel that is disabled
+        * already! This will result in a kernel NULL pointer dereference
+        * (mx3_fbi->txd is NULL). Hide the fact, that all blank modes are
+        * handled equally by this driver.
+        */
+       if (blank > FB_BLANK_UNBLANK && was_blank > FB_BLANK_UNBLANK)
+               return;
+
        switch (blank) {
        case FB_BLANK_POWERDOWN:
        case FB_BLANK_VSYNC_SUSPEND:
@@ -1062,15 +1075,15 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var,
        y_bottom = var->yoffset;
 
        if (!(var->vmode & FB_VMODE_YWRAP))
-               y_bottom += var->yres;
+               y_bottom += fbi->var.yres;
 
        if (y_bottom > fbi->var.yres_virtual)
                return -EINVAL;
 
        mutex_lock(&mx3_fbi->mutex);
 
-       offset = (var->yoffset * var->xres_virtual + var->xoffset) *
-               (var->bits_per_pixel / 8);
+       offset = var->yoffset * fbi->fix.line_length
+              + var->xoffset * (fbi->var.bits_per_pixel / 8);
        base = fbi->fix.smem_start + offset;
 
        dev_dbg(fbi->device, "Updating SDC BG buf %d address=0x%08lX\n",
index 0b2f2dd..d837d63 100644 (file)
@@ -39,6 +39,7 @@
  * the required value in the imx_fb_videomode structure.
  */
 
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
index 588527a..feea7b1 100644 (file)
@@ -1185,8 +1185,8 @@ static int neofb_pan_display(struct fb_var_screeninfo *var,
 
        DBG("neofb_update_start");
 
-       Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
-       Base *= (var->bits_per_pixel + 7) / 8;
+       Base = (var->yoffset * info->var.xres_virtual + var->xoffset) >> 2;
+       Base *= (info->var.bits_per_pixel + 7) / 8;
 
        neoUnlock();
 
index 0fff597..d1fbbd8 100644 (file)
@@ -39,7 +39,6 @@
 #include <mach/regs-clock.h>
 #include <mach/regs-ldm.h>
 #include <mach/fb.h>
-#include <mach/clkdev.h>
 
 #include "nuc900fb.h"
 
@@ -588,7 +587,7 @@ static int __devinit nuc900fb_probe(struct platform_device *pdev)
        fbinfo->flags                   = FBINFO_FLAG_DEFAULT;
        fbinfo->pseudo_palette          = &fbi->pseudo_pal;
 
-       ret = request_irq(irq, nuc900fb_irqhandler, IRQF_DISABLED,
+       ret = request_irq(irq, nuc900fb_irqhandler, 0,
                          pdev->name, fbinfo);
        if (ret) {
                dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n",
index 196fa2e..84ff232 100644 (file)
@@ -9,35 +9,6 @@ config FB_OMAP
        help
           Frame buffer driver for OMAP based boards.
 
-config FB_OMAP_LCD_VGA
-        bool "Use LCD in VGA mode"
-               depends on MACH_OMAP_3430SDP || MACH_OMAP_LDP
-               help
-                 Set LCD resolution as VGA (640 X 480).
-                 Default resolution without this option is QVGA(320 X 240).
-                 Please take a look at drivers/video/omap/lcd_ldp.c file
-                 for lcd driver code.
-choice
-       depends on FB_OMAP && MACH_OVERO
-       prompt "Screen resolution"
-       default FB_OMAP_079M3R
-       help
-         Selected desired screen resolution
-
-config FB_OMAP_031M3R
-       boolean "640 x 480 @ 60 Hz Reduced blanking"
-
-config FB_OMAP_048M3R
-       boolean "800 x 600 @ 60 Hz Reduced blanking"
-
-config FB_OMAP_079M3R
-       boolean "1024 x 768 @ 60 Hz Reduced blanking"
-
-config FB_OMAP_092M9R
-       boolean "1280 x 720 @ 60 Hz Reduced blanking"
-
-endchoice
-
 config FB_OMAP_LCDC_EXTERNAL
        bool "External LCD controller support"
        depends on FB_OMAP
index 25db556..ef78550 100644 (file)
@@ -17,7 +17,6 @@ objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o
 objs-y$(CONFIG_FB_OMAP_LCDC_BLIZZARD) += blizzard.o
 
 objs-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o
-objs-y$(CONFIG_MACH_OMAP_H4) += lcd_h4.o
 objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o
 objs-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o
 objs-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o
@@ -26,14 +25,7 @@ objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o
 objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
 objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
 
-objs-y$(CONFIG_MACH_OMAP_APOLLON) += lcd_apollon.o
-objs-y$(CONFIG_MACH_OMAP_2430SDP) += lcd_2430sdp.o
-objs-y$(CONFIG_MACH_OMAP_3430SDP) += lcd_2430sdp.o
-objs-y$(CONFIG_MACH_OMAP_LDP) += lcd_ldp.o
-objs-y$(CONFIG_MACH_OMAP3EVM) += lcd_omap3evm.o
-objs-y$(CONFIG_MACH_OMAP3_BEAGLE) += lcd_omap3beagle.o
 objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o
-objs-y$(CONFIG_MACH_OVERO) += lcd_overo.o
 objs-y$(CONFIG_MACH_HERALD) += lcd_htcherald.o
 
 omapfb-objs := $(objs-yy)
diff --git a/drivers/video/omap/lcd_2430sdp.c b/drivers/video/omap/lcd_2430sdp.c
deleted file mode 100644 (file)
index e3eccc9..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * LCD panel support for the TI 2430SDP board
- *
- * Copyright (C) 2007 MontaVista
- * Author: Hunyue Yau <hyau@mvista.com>
- *
- * Derived from drivers/video/omap/lcd-apollon.c
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/i2c/twl.h>
-
-#include <plat/mux.h>
-#include <asm/mach-types.h>
-
-#include "omapfb.h"
-
-#define SDP2430_LCD_PANEL_BACKLIGHT_GPIO       91
-#define SDP2430_LCD_PANEL_ENABLE_GPIO          154
-#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO       24
-#define SDP3430_LCD_PANEL_ENABLE_GPIO          28
-
-static unsigned backlight_gpio;
-static unsigned enable_gpio;
-
-#define LCD_PIXCLOCK_MAX               5400 /* freq 5.4 MHz */
-#define PM_RECEIVER             TWL4030_MODULE_PM_RECEIVER
-#define ENABLE_VAUX2_DEDICATED  0x09
-#define ENABLE_VAUX2_DEV_GRP    0x20
-#define ENABLE_VAUX3_DEDICATED 0x03
-#define ENABLE_VAUX3_DEV_GRP   0x20
-
-#define ENABLE_VPLL2_DEDICATED          0x05
-#define ENABLE_VPLL2_DEV_GRP            0xE0
-#define TWL4030_VPLL2_DEV_GRP           0x33
-#define TWL4030_VPLL2_DEDICATED         0x36
-
-#define t2_out(c, r, v) twl_i2c_write_u8(c, r, v)
-
-
-static int sdp2430_panel_init(struct lcd_panel *panel,
-                               struct omapfb_device *fbdev)
-{
-       if (machine_is_omap_3430sdp()) {
-               enable_gpio    = SDP3430_LCD_PANEL_ENABLE_GPIO;
-               backlight_gpio = SDP3430_LCD_PANEL_BACKLIGHT_GPIO;
-       } else {
-               enable_gpio    = SDP2430_LCD_PANEL_ENABLE_GPIO;
-               backlight_gpio = SDP2430_LCD_PANEL_BACKLIGHT_GPIO;
-       }
-
-       gpio_request(enable_gpio, "LCD enable");        /* LCD panel */
-       gpio_request(backlight_gpio, "LCD bl");         /* LCD backlight */
-       gpio_direction_output(enable_gpio, 0);
-       gpio_direction_output(backlight_gpio, 0);
-
-       return 0;
-}
-
-static void sdp2430_panel_cleanup(struct lcd_panel *panel)
-{
-       gpio_free(backlight_gpio);
-       gpio_free(enable_gpio);
-}
-
-static int sdp2430_panel_enable(struct lcd_panel *panel)
-{
-       u8 ded_val, ded_reg;
-       u8 grp_val, grp_reg;
-
-       if (machine_is_omap_3430sdp()) {
-               ded_reg = TWL4030_VAUX3_DEDICATED;
-               ded_val = ENABLE_VAUX3_DEDICATED;
-               grp_reg = TWL4030_VAUX3_DEV_GRP;
-               grp_val = ENABLE_VAUX3_DEV_GRP;
-
-               if (omap_rev() > OMAP3430_REV_ES1_0) {
-                       t2_out(PM_RECEIVER, ENABLE_VPLL2_DEDICATED,
-                                       TWL4030_VPLL2_DEDICATED);
-                       t2_out(PM_RECEIVER, ENABLE_VPLL2_DEV_GRP,
-                                       TWL4030_VPLL2_DEV_GRP);
-               }
-       } else {
-               ded_reg = TWL4030_VAUX2_DEDICATED;
-               ded_val = ENABLE_VAUX2_DEDICATED;
-               grp_reg = TWL4030_VAUX2_DEV_GRP;
-               grp_val = ENABLE_VAUX2_DEV_GRP;
-       }
-
-       gpio_set_value(enable_gpio, 1);
-       gpio_set_value(backlight_gpio, 1);
-
-       if (0 != t2_out(PM_RECEIVER, ded_val, ded_reg))
-               return -EIO;
-       if (0 != t2_out(PM_RECEIVER, grp_val, grp_reg))
-               return -EIO;
-
-       return 0;
-}
-
-static void sdp2430_panel_disable(struct lcd_panel *panel)
-{
-       gpio_set_value(enable_gpio, 0);
-       gpio_set_value(backlight_gpio, 0);
-       if (omap_rev() > OMAP3430_REV_ES1_0) {
-               t2_out(PM_RECEIVER, 0x0, TWL4030_VPLL2_DEDICATED);
-               t2_out(PM_RECEIVER, 0x0, TWL4030_VPLL2_DEV_GRP);
-               msleep(4);
-       }
-}
-
-static unsigned long sdp2430_panel_get_caps(struct lcd_panel *panel)
-{
-       return 0;
-}
-
-struct lcd_panel sdp2430_panel = {
-       .name           = "sdp2430",
-       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
-                         OMAP_LCDC_INV_HSYNC,
-
-       .bpp            = 16,
-       .data_lines     = 16,
-       .x_res          = 240,
-       .y_res          = 320,
-       .hsw            = 3,            /* hsync_len (4) - 1 */
-       .hfp            = 3,            /* right_margin (4) - 1 */
-       .hbp            = 39,           /* left_margin (40) - 1 */
-       .vsw            = 1,            /* vsync_len (2) - 1 */
-       .vfp            = 2,            /* lower_margin */
-       .vbp            = 7,            /* upper_margin (8) - 1 */
-
-       .pixel_clock    = LCD_PIXCLOCK_MAX,
-
-       .init           = sdp2430_panel_init,
-       .cleanup        = sdp2430_panel_cleanup,
-       .enable         = sdp2430_panel_enable,
-       .disable        = sdp2430_panel_disable,
-       .get_caps       = sdp2430_panel_get_caps,
-};
-
-static int sdp2430_panel_probe(struct platform_device *pdev)
-{
-       omapfb_register_panel(&sdp2430_panel);
-       return 0;
-}
-
-static int sdp2430_panel_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
-static int sdp2430_panel_suspend(struct platform_device *pdev,
-                                       pm_message_t mesg)
-{
-       return 0;
-}
-
-static int sdp2430_panel_resume(struct platform_device *pdev)
-{
-       return 0;
-}
-
-struct platform_driver sdp2430_panel_driver = {
-       .probe          = sdp2430_panel_probe,
-       .remove         = sdp2430_panel_remove,
-       .suspend        = sdp2430_panel_suspend,
-       .resume         = sdp2430_panel_resume,
-       .driver         = {
-               .name   = "sdp2430_lcd",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init sdp2430_panel_drv_init(void)
-{
-       return platform_driver_register(&sdp2430_panel_driver);
-}
-
-static void __exit sdp2430_panel_drv_exit(void)
-{
-       platform_driver_unregister(&sdp2430_panel_driver);
-}
-
-module_init(sdp2430_panel_drv_init);
-module_exit(sdp2430_panel_drv_exit);
diff --git a/drivers/video/omap/lcd_apollon.c b/drivers/video/omap/lcd_apollon.c
deleted file mode 100644 (file)
index 4b24f54..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * LCD panel support for the Samsung OMAP2 Apollon board
- *
- * Copyright (C) 2005,2006 Samsung Electronics
- * Author: Kyungmin Park <kyungmin.park@samsung.com>
- *
- * Derived from drivers/video/omap/lcd-h4.c
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <asm/gpio.h>
-
-#include "omapfb.h"
-
-/* #define USE_35INCH_LCD 1 */
-
-static int apollon_panel_init(struct lcd_panel *panel,
-                               struct omapfb_device *fbdev)
-{
-       return 0;
-}
-
-static void apollon_panel_cleanup(struct lcd_panel *panel)
-{
-}
-
-static int apollon_panel_enable(struct lcd_panel *panel)
-{
-       return 0;
-}
-
-static void apollon_panel_disable(struct lcd_panel *panel)
-{
-}
-
-static unsigned long apollon_panel_get_caps(struct lcd_panel *panel)
-{
-       return 0;
-}
-
-struct lcd_panel apollon_panel = {
-       .name           = "apollon",
-       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
-                         OMAP_LCDC_INV_HSYNC,
-
-       .bpp            = 16,
-       .data_lines     = 18,
-#ifdef USE_35INCH_LCD
-       .x_res          = 240,
-       .y_res          = 320,
-       .hsw            = 2,
-       .hfp            = 3,
-       .hbp            = 9,
-       .vsw            = 4,
-       .vfp            = 3,
-       .vbp            = 5,
-#else
-       .x_res          = 480,
-       .y_res          = 272,
-       .hsw            = 41,
-       .hfp            = 2,
-       .hbp            = 2,
-       .vsw            = 10,
-       .vfp            = 2,
-       .vbp            = 2,
-#endif
-       .pixel_clock    = 6250,
-
-       .init           = apollon_panel_init,
-       .cleanup        = apollon_panel_cleanup,
-       .enable         = apollon_panel_enable,
-       .disable        = apollon_panel_disable,
-       .get_caps       = apollon_panel_get_caps,
-};
-
-static int apollon_panel_probe(struct platform_device *pdev)
-{
-       omapfb_register_panel(&apollon_panel);
-       return 0;
-}
-
-static int apollon_panel_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
-static int apollon_panel_suspend(struct platform_device *pdev,
-                                 pm_message_t mesg)
-{
-       return 0;
-}
-
-static int apollon_panel_resume(struct platform_device *pdev)
-{
-       return 0;
-}
-
-struct platform_driver apollon_panel_driver = {
-       .probe          = apollon_panel_probe,
-       .remove         = apollon_panel_remove,
-       .suspend        = apollon_panel_suspend,
-       .resume         = apollon_panel_resume,
-       .driver         = {
-               .name   = "apollon_lcd",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init apollon_panel_drv_init(void)
-{
-       return platform_driver_register(&apollon_panel_driver);
-}
-
-static void __exit apollon_panel_drv_exit(void)
-{
-       platform_driver_unregister(&apollon_panel_driver);
-}
-
-module_init(apollon_panel_drv_init);
-module_exit(apollon_panel_drv_exit);
diff --git a/drivers/video/omap/lcd_h4.c b/drivers/video/omap/lcd_h4.c
deleted file mode 100644 (file)
index 03a06a9..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * LCD panel support for the TI OMAP H4 board
- *
- * Copyright (C) 2004 Nokia Corporation
- * Author: Imre Deak <imre.deak@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include "omapfb.h"
-
-static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
-{
-       return 0;
-}
-
-static void h4_panel_cleanup(struct lcd_panel *panel)
-{
-}
-
-static int h4_panel_enable(struct lcd_panel *panel)
-{
-       return 0;
-}
-
-static void h4_panel_disable(struct lcd_panel *panel)
-{
-}
-
-static unsigned long h4_panel_get_caps(struct lcd_panel *panel)
-{
-       return 0;
-}
-
-static struct lcd_panel h4_panel = {
-       .name           = "h4",
-       .config         = OMAP_LCDC_PANEL_TFT,
-
-       .bpp            = 16,
-       .data_lines     = 16,
-       .x_res          = 240,
-       .y_res          = 320,
-       .pixel_clock    = 6250,
-       .hsw            = 15,
-       .hfp            = 15,
-       .hbp            = 60,
-       .vsw            = 1,
-       .vfp            = 1,
-       .vbp            = 1,
-
-       .init           = h4_panel_init,
-       .cleanup        = h4_panel_cleanup,
-       .enable         = h4_panel_enable,
-       .disable        = h4_panel_disable,
-       .get_caps       = h4_panel_get_caps,
-};
-
-static int h4_panel_probe(struct platform_device *pdev)
-{
-       omapfb_register_panel(&h4_panel);
-       return 0;
-}
-
-static int h4_panel_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
-static int h4_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
-{
-       return 0;
-}
-
-static int h4_panel_resume(struct platform_device *pdev)
-{
-       return 0;
-}
-
-static struct platform_driver h4_panel_driver = {
-       .probe          = h4_panel_probe,
-       .remove         = h4_panel_remove,
-       .suspend        = h4_panel_suspend,
-       .resume         = h4_panel_resume,
-       .driver         = {
-               .name   = "lcd_h4",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init h4_panel_drv_init(void)
-{
-       return platform_driver_register(&h4_panel_driver);
-}
-
-static void __exit h4_panel_drv_cleanup(void)
-{
-       platform_driver_unregister(&h4_panel_driver);
-}
-
-module_init(h4_panel_drv_init);
-module_exit(h4_panel_drv_cleanup);
-
diff --git a/drivers/video/omap/lcd_ldp.c b/drivers/video/omap/lcd_ldp.c
deleted file mode 100644 (file)
index 0624664..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * LCD panel support for the TI LDP board
- *
- * Copyright (C) 2007 WindRiver
- * Author: Stanley Miao <stanley.miao@windriver.com>
- *
- * Derived from drivers/video/omap/lcd-2430sdp.c
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/i2c/twl.h>
-
-#include <asm/gpio.h>
-#include <plat/mux.h>
-#include <asm/mach-types.h>
-
-#include "omapfb.h"
-
-#define LCD_PANEL_BACKLIGHT_GPIO       (15 + OMAP_MAX_GPIO_LINES)
-#define LCD_PANEL_ENABLE_GPIO          (7 + OMAP_MAX_GPIO_LINES)
-
-#define LCD_PANEL_RESET_GPIO           55
-#define LCD_PANEL_QVGA_GPIO            56
-
-#ifdef CONFIG_FB_OMAP_LCD_VGA
-#define LCD_XRES               480
-#define LCD_YRES               640
-#define LCD_PIXCLOCK_MAX       41700
-#else
-#define LCD_XRES               240
-#define LCD_YRES               320
-#define LCD_PIXCLOCK_MAX       185186
-#endif
-
-#define PM_RECEIVER             TWL4030_MODULE_PM_RECEIVER
-#define ENABLE_VAUX2_DEDICATED  0x09
-#define ENABLE_VAUX2_DEV_GRP    0x20
-#define ENABLE_VAUX3_DEDICATED 0x03
-#define ENABLE_VAUX3_DEV_GRP   0x20
-
-#define ENABLE_VPLL2_DEDICATED          0x05
-#define ENABLE_VPLL2_DEV_GRP            0xE0
-#define TWL4030_VPLL2_DEV_GRP           0x33
-#define TWL4030_VPLL2_DEDICATED         0x36
-
-#define t2_out(c, r, v) twl_i2c_write_u8(c, r, v)
-
-
-static int ldp_panel_init(struct lcd_panel *panel,
-                               struct omapfb_device *fbdev)
-{
-       gpio_request(LCD_PANEL_RESET_GPIO, "lcd reset");
-       gpio_request(LCD_PANEL_QVGA_GPIO, "lcd qvga");
-       gpio_request(LCD_PANEL_ENABLE_GPIO, "lcd panel");
-       gpio_request(LCD_PANEL_BACKLIGHT_GPIO, "lcd backlight");
-
-       gpio_direction_output(LCD_PANEL_QVGA_GPIO, 0);
-       gpio_direction_output(LCD_PANEL_RESET_GPIO, 0);
-       gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 0);
-       gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 0);
-
-#ifdef CONFIG_FB_OMAP_LCD_VGA
-       gpio_set_value(LCD_PANEL_QVGA_GPIO, 0);
-#else
-       gpio_set_value(LCD_PANEL_QVGA_GPIO, 1);
-#endif
-       gpio_set_value(LCD_PANEL_RESET_GPIO, 1);
-
-       return 0;
-}
-
-static void ldp_panel_cleanup(struct lcd_panel *panel)
-{
-       gpio_free(LCD_PANEL_BACKLIGHT_GPIO);
-       gpio_free(LCD_PANEL_ENABLE_GPIO);
-       gpio_free(LCD_PANEL_QVGA_GPIO);
-       gpio_free(LCD_PANEL_RESET_GPIO);
-}
-
-static int ldp_panel_enable(struct lcd_panel *panel)
-{
-       if (0 != t2_out(PM_RECEIVER, ENABLE_VPLL2_DEDICATED,
-                       TWL4030_VPLL2_DEDICATED))
-               return -EIO;
-       if (0 != t2_out(PM_RECEIVER, ENABLE_VPLL2_DEV_GRP,
-                       TWL4030_VPLL2_DEV_GRP))
-               return -EIO;
-
-       gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 1);
-       gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 1);
-
-       if (0 != t2_out(PM_RECEIVER, ENABLE_VAUX3_DEDICATED,
-                               TWL4030_VAUX3_DEDICATED))
-               return -EIO;
-       if (0 != t2_out(PM_RECEIVER, ENABLE_VAUX3_DEV_GRP,
-                               TWL4030_VAUX3_DEV_GRP))
-               return -EIO;
-
-       return 0;
-}
-
-static void ldp_panel_disable(struct lcd_panel *panel)
-{
-       gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 0);
-       gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 0);
-
-       t2_out(PM_RECEIVER, 0x0, TWL4030_VPLL2_DEDICATED);
-       t2_out(PM_RECEIVER, 0x0, TWL4030_VPLL2_DEV_GRP);
-       msleep(4);
-}
-
-static unsigned long ldp_panel_get_caps(struct lcd_panel *panel)
-{
-       return 0;
-}
-
-struct lcd_panel ldp_panel = {
-       .name           = "ldp",
-       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
-                         OMAP_LCDC_INV_HSYNC,
-
-       .bpp            = 16,
-       .data_lines     = 18,
-       .x_res          = LCD_XRES,
-       .y_res          = LCD_YRES,
-       .hsw            = 3,            /* hsync_len (4) - 1 */
-       .hfp            = 3,            /* right_margin (4) - 1 */
-       .hbp            = 39,           /* left_margin (40) - 1 */
-       .vsw            = 1,            /* vsync_len (2) - 1 */
-       .vfp            = 2,            /* lower_margin */
-       .vbp            = 7,            /* upper_margin (8) - 1 */
-
-       .pixel_clock    = LCD_PIXCLOCK_MAX,
-
-       .init           = ldp_panel_init,
-       .cleanup        = ldp_panel_cleanup,
-       .enable         = ldp_panel_enable,
-       .disable        = ldp_panel_disable,
-       .get_caps       = ldp_panel_get_caps,
-};
-
-static int ldp_panel_probe(struct platform_device *pdev)
-{
-       omapfb_register_panel(&ldp_panel);
-       return 0;
-}
-
-static int ldp_panel_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
-static int ldp_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
-{
-       return 0;
-}
-
-static int ldp_panel_resume(struct platform_device *pdev)
-{
-       return 0;
-}
-
-struct platform_driver ldp_panel_driver = {
-       .probe          = ldp_panel_probe,
-       .remove         = ldp_panel_remove,
-       .suspend        = ldp_panel_suspend,
-       .resume         = ldp_panel_resume,
-       .driver         = {
-               .name   = "ldp_lcd",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init ldp_panel_drv_init(void)
-{
-       return platform_driver_register(&ldp_panel_driver);
-}
-
-static void __exit ldp_panel_drv_exit(void)
-{
-       platform_driver_unregister(&ldp_panel_driver);
-}
-
-module_init(ldp_panel_drv_init);
-module_exit(ldp_panel_drv_exit);
diff --git a/drivers/video/omap/lcd_omap3beagle.c b/drivers/video/omap/lcd_omap3beagle.c
deleted file mode 100644 (file)
index d7c6c3e..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * LCD panel support for the TI OMAP3 Beagle board
- *
- * Author: Koen Kooi <koen@openembedded.org>
- *
- * Derived from drivers/video/omap/lcd-omap3evm.c
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/i2c/twl.h>
-
-#include <asm/mach-types.h>
-
-#include "omapfb.h"
-
-#define LCD_PANEL_ENABLE_GPIO       170
-
-static int omap3beagle_panel_init(struct lcd_panel *panel,
-                               struct omapfb_device *fbdev)
-{
-       gpio_request(LCD_PANEL_ENABLE_GPIO, "LCD enable");
-       return 0;
-}
-
-static void omap3beagle_panel_cleanup(struct lcd_panel *panel)
-{
-       gpio_free(LCD_PANEL_ENABLE_GPIO);
-}
-
-static int omap3beagle_panel_enable(struct lcd_panel *panel)
-{
-       gpio_set_value(LCD_PANEL_ENABLE_GPIO, 1);
-       return 0;
-}
-
-static void omap3beagle_panel_disable(struct lcd_panel *panel)
-{
-       gpio_set_value(LCD_PANEL_ENABLE_GPIO, 0);
-}
-
-static unsigned long omap3beagle_panel_get_caps(struct lcd_panel *panel)
-{
-       return 0;
-}
-
-struct lcd_panel omap3beagle_panel = {
-       .name           = "omap3beagle",
-       .config         = OMAP_LCDC_PANEL_TFT,
-
-       .bpp            = 16,
-       .data_lines     = 24,
-       .x_res          = 1024,
-       .y_res          = 768,
-       .hsw            = 3,            /* hsync_len (4) - 1 */
-       .hfp            = 3,            /* right_margin (4) - 1 */
-       .hbp            = 39,           /* left_margin (40) - 1 */
-       .vsw            = 1,            /* vsync_len (2) - 1 */
-       .vfp            = 2,            /* lower_margin */
-       .vbp            = 7,            /* upper_margin (8) - 1 */
-
-       .pixel_clock    = 64000,
-
-       .init           = omap3beagle_panel_init,
-       .cleanup        = omap3beagle_panel_cleanup,
-       .enable         = omap3beagle_panel_enable,
-       .disable        = omap3beagle_panel_disable,
-       .get_caps       = omap3beagle_panel_get_caps,
-};
-
-static int omap3beagle_panel_probe(struct platform_device *pdev)
-{
-       omapfb_register_panel(&omap3beagle_panel);
-       return 0;
-}
-
-static int omap3beagle_panel_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
-static int omap3beagle_panel_suspend(struct platform_device *pdev,
-                                  pm_message_t mesg)
-{
-       return 0;
-}
-
-static int omap3beagle_panel_resume(struct platform_device *pdev)
-{
-       return 0;
-}
-
-struct platform_driver omap3beagle_panel_driver = {
-       .probe          = omap3beagle_panel_probe,
-       .remove         = omap3beagle_panel_remove,
-       .suspend        = omap3beagle_panel_suspend,
-       .resume         = omap3beagle_panel_resume,
-       .driver         = {
-               .name   = "omap3beagle_lcd",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init omap3beagle_panel_drv_init(void)
-{
-       return platform_driver_register(&omap3beagle_panel_driver);
-}
-
-static void __exit omap3beagle_panel_drv_exit(void)
-{
-       platform_driver_unregister(&omap3beagle_panel_driver);
-}
-
-module_init(omap3beagle_panel_drv_init);
-module_exit(omap3beagle_panel_drv_exit);
diff --git a/drivers/video/omap/lcd_omap3evm.c b/drivers/video/omap/lcd_omap3evm.c
deleted file mode 100644 (file)
index 06840da..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * LCD panel support for the TI OMAP3 EVM board
- *
- * Author: Steve Sakoman <steve@sakoman.com>
- *
- * Derived from drivers/video/omap/lcd-apollon.c
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/i2c/twl.h>
-
-#include <plat/mux.h>
-#include <asm/mach-types.h>
-
-#include "omapfb.h"
-
-#define LCD_PANEL_ENABLE_GPIO       153
-#define LCD_PANEL_LR                2
-#define LCD_PANEL_UD                3
-#define LCD_PANEL_INI               152
-#define LCD_PANEL_QVGA              154
-#define LCD_PANEL_RESB              155
-
-#define ENABLE_VDAC_DEDICATED  0x03
-#define ENABLE_VDAC_DEV_GRP    0x20
-#define ENABLE_VPLL2_DEDICATED 0x05
-#define ENABLE_VPLL2_DEV_GRP   0xE0
-
-#define TWL_LED_LEDEN          0x00
-#define TWL_PWMA_PWMAON                0x00
-#define TWL_PWMA_PWMAOFF       0x01
-
-static unsigned int bklight_level;
-
-static int omap3evm_panel_init(struct lcd_panel *panel,
-                               struct omapfb_device *fbdev)
-{
-       gpio_request(LCD_PANEL_LR, "LCD lr");
-       gpio_request(LCD_PANEL_UD, "LCD ud");
-       gpio_request(LCD_PANEL_INI, "LCD ini");
-       gpio_request(LCD_PANEL_RESB, "LCD resb");
-       gpio_request(LCD_PANEL_QVGA, "LCD qvga");
-
-       gpio_direction_output(LCD_PANEL_RESB, 1);
-       gpio_direction_output(LCD_PANEL_INI, 1);
-       gpio_direction_output(LCD_PANEL_QVGA, 0);
-       gpio_direction_output(LCD_PANEL_LR, 1);
-       gpio_direction_output(LCD_PANEL_UD, 1);
-
-       twl_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN);
-       twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON);
-       twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF);
-       bklight_level = 100;
-
-       return 0;
-}
-
-static void omap3evm_panel_cleanup(struct lcd_panel *panel)
-{
-       gpio_free(LCD_PANEL_QVGA);
-       gpio_free(LCD_PANEL_RESB);
-       gpio_free(LCD_PANEL_INI);
-       gpio_free(LCD_PANEL_UD);
-       gpio_free(LCD_PANEL_LR);
-}
-
-static int omap3evm_panel_enable(struct lcd_panel *panel)
-{
-       gpio_set_value(LCD_PANEL_ENABLE_GPIO, 0);
-       return 0;
-}
-
-static void omap3evm_panel_disable(struct lcd_panel *panel)
-{
-       gpio_set_value(LCD_PANEL_ENABLE_GPIO, 1);
-}
-
-static unsigned long omap3evm_panel_get_caps(struct lcd_panel *panel)
-{
-       return 0;
-}
-
-static int omap3evm_bklight_setlevel(struct lcd_panel *panel,
-                                               unsigned int level)
-{
-       u8 c;
-       if ((level >= 0) && (level <= 100)) {
-               c = (125 * (100 - level)) / 100 + 2;
-               twl_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF);
-               bklight_level = level;
-       }
-       return 0;
-}
-
-static unsigned int omap3evm_bklight_getlevel(struct lcd_panel *panel)
-{
-       return bklight_level;
-}
-
-static unsigned int omap3evm_bklight_getmaxlevel(struct lcd_panel *panel)
-{
-       return 100;
-}
-
-struct lcd_panel omap3evm_panel = {
-       .name           = "omap3evm",
-       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
-                         OMAP_LCDC_INV_HSYNC,
-
-       .bpp            = 16,
-       .data_lines     = 18,
-       .x_res          = 480,
-       .y_res          = 640,
-       .hsw            = 3,            /* hsync_len (4) - 1 */
-       .hfp            = 3,            /* right_margin (4) - 1 */
-       .hbp            = 39,           /* left_margin (40) - 1 */
-       .vsw            = 1,            /* vsync_len (2) - 1 */
-       .vfp            = 2,            /* lower_margin */
-       .vbp            = 7,            /* upper_margin (8) - 1 */
-
-       .pixel_clock    = 26000,
-
-       .init           = omap3evm_panel_init,
-       .cleanup        = omap3evm_panel_cleanup,
-       .enable         = omap3evm_panel_enable,
-       .disable        = omap3evm_panel_disable,
-       .get_caps       = omap3evm_panel_get_caps,
-       .set_bklight_level      = omap3evm_bklight_setlevel,
-       .get_bklight_level      = omap3evm_bklight_getlevel,
-       .get_bklight_max        = omap3evm_bklight_getmaxlevel,
-};
-
-static int omap3evm_panel_probe(struct platform_device *pdev)
-{
-       omapfb_register_panel(&omap3evm_panel);
-       return 0;
-}
-
-static int omap3evm_panel_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
-static int omap3evm_panel_suspend(struct platform_device *pdev,
-                                  pm_message_t mesg)
-{
-       return 0;
-}
-
-static int omap3evm_panel_resume(struct platform_device *pdev)
-{
-       return 0;
-}
-
-struct platform_driver omap3evm_panel_driver = {
-       .probe          = omap3evm_panel_probe,
-       .remove         = omap3evm_panel_remove,
-       .suspend        = omap3evm_panel_suspend,
-       .resume         = omap3evm_panel_resume,
-       .driver         = {
-               .name   = "omap3evm_lcd",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init omap3evm_panel_drv_init(void)
-{
-       return platform_driver_register(&omap3evm_panel_driver);
-}
-
-static void __exit omap3evm_panel_drv_exit(void)
-{
-       platform_driver_unregister(&omap3evm_panel_driver);
-}
-
-module_init(omap3evm_panel_drv_init);
-module_exit(omap3evm_panel_drv_exit);
diff --git a/drivers/video/omap/lcd_overo.c b/drivers/video/omap/lcd_overo.c
deleted file mode 100644 (file)
index b8fd5b2..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * LCD panel support for the Gumstix Overo
- *
- * Author: Steve Sakoman <steve@sakoman.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/i2c/twl.h>
-
-#include <asm/gpio.h>
-#include <plat/mux.h>
-#include <asm/mach-types.h>
-
-#include "omapfb.h"
-
-#define LCD_ENABLE       144
-
-static int overo_panel_init(struct lcd_panel *panel,
-                               struct omapfb_device *fbdev)
-{
-       if ((gpio_request(LCD_ENABLE, "LCD_ENABLE") == 0) &&
-           (gpio_direction_output(LCD_ENABLE, 1) == 0))
-               gpio_export(LCD_ENABLE, 0);
-       else
-               printk(KERN_ERR "could not obtain gpio for LCD_ENABLE\n");
-
-       return 0;
-}
-
-static void overo_panel_cleanup(struct lcd_panel *panel)
-{
-       gpio_free(LCD_ENABLE);
-}
-
-static int overo_panel_enable(struct lcd_panel *panel)
-{
-       gpio_set_value(LCD_ENABLE, 1);
-       return 0;
-}
-
-static void overo_panel_disable(struct lcd_panel *panel)
-{
-       gpio_set_value(LCD_ENABLE, 0);
-}
-
-static unsigned long overo_panel_get_caps(struct lcd_panel *panel)
-{
-       return 0;
-}
-
-struct lcd_panel overo_panel = {
-       .name           = "overo",
-       .config         = OMAP_LCDC_PANEL_TFT,
-       .bpp            = 16,
-       .data_lines     = 24,
-
-#if defined CONFIG_FB_OMAP_031M3R
-
-       /* 640 x 480 @ 60 Hz  Reduced blanking VESA CVT 0.31M3-R */
-       .x_res          = 640,
-       .y_res          = 480,
-       .hfp            = 48,
-       .hsw            = 32,
-       .hbp            = 80,
-       .vfp            = 3,
-       .vsw            = 4,
-       .vbp            = 7,
-       .pixel_clock    = 23500,
-
-#elif defined CONFIG_FB_OMAP_048M3R
-
-       /* 800 x 600 @ 60 Hz  Reduced blanking VESA CVT 0.48M3-R */
-       .x_res          = 800,
-       .y_res          = 600,
-       .hfp            = 48,
-       .hsw            = 32,
-       .hbp            = 80,
-       .vfp            = 3,
-       .vsw            = 4,
-       .vbp            = 11,
-       .pixel_clock    = 35500,
-
-#elif defined CONFIG_FB_OMAP_079M3R
-
-       /* 1024 x 768 @ 60 Hz  Reduced blanking VESA CVT 0.79M3-R */
-       .x_res          = 1024,
-       .y_res          = 768,
-       .hfp            = 48,
-       .hsw            = 32,
-       .hbp            = 80,
-       .vfp            = 3,
-       .vsw            = 4,
-       .vbp            = 15,
-       .pixel_clock    = 56000,
-
-#elif defined CONFIG_FB_OMAP_092M9R
-
-       /* 1280 x 720 @ 60 Hz  Reduced blanking VESA CVT 0.92M9-R */
-       .x_res          = 1280,
-       .y_res          = 720,
-       .hfp            = 48,
-       .hsw            = 32,
-       .hbp            = 80,
-       .vfp            = 3,
-       .vsw            = 5,
-       .vbp            = 13,
-       .pixel_clock    = 64000,
-
-#else
-
-       /* use 640 x 480 if no config option */
-       /* 640 x 480 @ 60 Hz  Reduced blanking VESA CVT 0.31M3-R */
-       .x_res          = 640,
-       .y_res          = 480,
-       .hfp            = 48,
-       .hsw            = 32,
-       .hbp            = 80,
-       .vfp            = 3,
-       .vsw            = 4,
-       .vbp            = 7,
-       .pixel_clock    = 23500,
-
-#endif
-
-       .init           = overo_panel_init,
-       .cleanup        = overo_panel_cleanup,
-       .enable         = overo_panel_enable,
-       .disable        = overo_panel_disable,
-       .get_caps       = overo_panel_get_caps,
-};
-
-static int overo_panel_probe(struct platform_device *pdev)
-{
-       omapfb_register_panel(&overo_panel);
-       return 0;
-}
-
-static int overo_panel_remove(struct platform_device *pdev)
-{
-       /* omapfb does not have unregister_panel */
-       return 0;
-}
-
-static struct platform_driver overo_panel_driver = {
-       .probe          = overo_panel_probe,
-       .remove         = overo_panel_remove,
-       .driver         = {
-               .name   = "overo_lcd",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init overo_panel_drv_init(void)
-{
-       return platform_driver_register(&overo_panel_driver);
-}
-
-static void __exit overo_panel_drv_exit(void)
-{
-       platform_driver_unregister(&overo_panel_driver);
-}
-
-module_init(overo_panel_drv_init);
-module_exit(overo_panel_drv_exit);
index 609a280..8d8e1fe 100644 (file)
@@ -10,6 +10,13 @@ config PANEL_GENERIC_DPI
          Supports LCD Panel used in TI SDP3430 and EVM boards,
          OMAP3517 EVM boards and CM-T35.
 
+config PANEL_DVI
+       tristate "DVI output"
+       depends on OMAP2_DSS_DPI
+       help
+         Driver for external monitors, connected via DVI. The driver uses i2c
+         to read EDID information from the monitor.
+
 config PANEL_LGPHILIPS_LB035Q02
        tristate "LG.Philips LB035Q02 LCD Panel"
        depends on OMAP2_DSS_DPI && SPI
@@ -19,20 +26,30 @@ config PANEL_LGPHILIPS_LB035Q02
 config PANEL_SHARP_LS037V7DW01
         tristate "Sharp LS037V7DW01 LCD Panel"
         depends on OMAP2_DSS_DPI
-        select BACKLIGHT_CLASS_DEVICE
+        depends on BACKLIGHT_CLASS_DEVICE
         help
           LCD Panel used in TI's SDP3430 and EVM boards
 
 config PANEL_NEC_NL8048HL11_01B
        tristate "NEC NL8048HL11-01B Panel"
        depends on OMAP2_DSS_DPI
+       depends on SPI
+       depends on BACKLIGHT_CLASS_DEVICE
        help
                This NEC NL8048HL11-01B panel is TFT LCD
                used in the Zoom2/3/3630 sdp boards.
 
+config PANEL_PICODLP
+       tristate "TI PICO DLP mini-projector"
+       depends on OMAP2_DSS && I2C
+       help
+               A mini-projector used in TI's SDP4430 and EVM boards
+               For more info please visit http://www.dlp.com/projector/
+
 config PANEL_TAAL
         tristate "Taal DSI Panel"
         depends on OMAP2_DSS_DSI
+        depends on BACKLIGHT_CLASS_DEVICE
         help
           Taal DSI command mode panel from TPO.
 
@@ -45,7 +62,14 @@ config PANEL_TPO_TD043MTEA1
 config PANEL_ACX565AKM
        tristate "ACX565AKM Panel"
        depends on OMAP2_DSS_SDI && SPI
-       select BACKLIGHT_CLASS_DEVICE
+       depends on BACKLIGHT_CLASS_DEVICE
        help
          This is the LCD panel used on Nokia N900
+
+config PANEL_N8X0
+       tristate "N8X0 Panel"
+       depends on OMAP2_DSS_RFBI && SPI
+       depends on BACKLIGHT_CLASS_DEVICE
+       help
+         This is the LCD panel used on Nokia N8x0
 endmenu
index 0f601ab..fbfafc6 100644 (file)
@@ -1,8 +1,11 @@
 obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o
+obj-$(CONFIG_PANEL_DVI) += panel-dvi.o
 obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
 obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
 obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o
 
 obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
+obj-$(CONFIG_PANEL_PICODLP) +=  panel-picodlp.o
 obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
 obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o
+obj-$(CONFIG_PANEL_N8X0) += panel-n8x0.o
diff --git a/drivers/video/omap2/displays/panel-dvi.c b/drivers/video/omap2/displays/panel-dvi.c
new file mode 100644 (file)
index 0000000..03eb14a
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * DVI output support
+ *
+ * Copyright (C) 2011 Texas Instruments Inc
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <video/omapdss.h>
+#include <linux/i2c.h>
+#include <drm/drm_edid.h>
+
+#include <video/omap-panel-dvi.h>
+
+static const struct omap_video_timings panel_dvi_default_timings = {
+       .x_res          = 640,
+       .y_res          = 480,
+
+       .pixel_clock    = 23500,
+
+       .hfp            = 48,
+       .hsw            = 32,
+       .hbp            = 80,
+
+       .vfp            = 3,
+       .vsw            = 4,
+       .vbp            = 7,
+};
+
+struct panel_drv_data {
+       struct omap_dss_device *dssdev;
+
+       struct mutex lock;
+};
+
+static inline struct panel_dvi_platform_data
+*get_pdata(const struct omap_dss_device *dssdev)
+{
+       return dssdev->data;
+}
+
+static int panel_dvi_power_on(struct omap_dss_device *dssdev)
+{
+       struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
+       int r;
+
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
+       r = omapdss_dpi_display_enable(dssdev);
+       if (r)
+               goto err0;
+
+       if (pdata->platform_enable) {
+               r = pdata->platform_enable(dssdev);
+               if (r)
+                       goto err1;
+       }
+
+       return 0;
+err1:
+       omapdss_dpi_display_disable(dssdev);
+err0:
+       return r;
+}
+
+static void panel_dvi_power_off(struct omap_dss_device *dssdev)
+{
+       struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return;
+
+       if (pdata->platform_disable)
+               pdata->platform_disable(dssdev);
+
+       omapdss_dpi_display_disable(dssdev);
+}
+
+static int panel_dvi_probe(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata;
+
+       ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
+       if (!ddata)
+               return -ENOMEM;
+
+       dssdev->panel.timings = panel_dvi_default_timings;
+       dssdev->panel.config = OMAP_DSS_LCD_TFT;
+
+       ddata->dssdev = dssdev;
+       mutex_init(&ddata->lock);
+
+       dev_set_drvdata(&dssdev->dev, ddata);
+
+       return 0;
+}
+
+static void __exit panel_dvi_remove(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+
+       mutex_lock(&ddata->lock);
+
+       dev_set_drvdata(&dssdev->dev, NULL);
+
+       mutex_unlock(&ddata->lock);
+
+       kfree(ddata);
+}
+
+static int panel_dvi_enable(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+       int r;
+
+       mutex_lock(&ddata->lock);
+
+       r = panel_dvi_power_on(dssdev);
+       if (r == 0)
+               dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+       mutex_unlock(&ddata->lock);
+
+       return r;
+}
+
+static void panel_dvi_disable(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+
+       mutex_lock(&ddata->lock);
+
+       panel_dvi_power_off(dssdev);
+
+       dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+       mutex_unlock(&ddata->lock);
+}
+
+static int panel_dvi_suspend(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+
+       mutex_lock(&ddata->lock);
+
+       panel_dvi_power_off(dssdev);
+
+       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+       mutex_unlock(&ddata->lock);
+
+       return 0;
+}
+
+static int panel_dvi_resume(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+       int r;
+
+       mutex_lock(&ddata->lock);
+
+       r = panel_dvi_power_on(dssdev);
+       if (r == 0)
+               dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+       mutex_unlock(&ddata->lock);
+
+       return r;
+}
+
+static void panel_dvi_set_timings(struct omap_dss_device *dssdev,
+               struct omap_video_timings *timings)
+{
+       struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+
+       mutex_lock(&ddata->lock);
+       dpi_set_timings(dssdev, timings);
+       mutex_unlock(&ddata->lock);
+}
+
+static void panel_dvi_get_timings(struct omap_dss_device *dssdev,
+               struct omap_video_timings *timings)
+{
+       struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+
+       mutex_lock(&ddata->lock);
+       *timings = dssdev->panel.timings;
+       mutex_unlock(&ddata->lock);
+}
+
+static int panel_dvi_check_timings(struct omap_dss_device *dssdev,
+               struct omap_video_timings *timings)
+{
+       struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+       int r;
+
+       mutex_lock(&ddata->lock);
+       r = dpi_check_timings(dssdev, timings);
+       mutex_unlock(&ddata->lock);
+
+       return r;
+}
+
+
+static int panel_dvi_ddc_read(struct i2c_adapter *adapter,
+               unsigned char *buf, u16 count, u8 offset)
+{
+       int r, retries;
+
+       for (retries = 3; retries > 0; retries--) {
+               struct i2c_msg msgs[] = {
+                       {
+                               .addr   = DDC_ADDR,
+                               .flags  = 0,
+                               .len    = 1,
+                               .buf    = &offset,
+                       }, {
+                               .addr   = DDC_ADDR,
+                               .flags  = I2C_M_RD,
+                               .len    = count,
+                               .buf    = buf,
+                       }
+               };
+
+               r = i2c_transfer(adapter, msgs, 2);
+               if (r == 2)
+                       return 0;
+
+               if (r != -EAGAIN)
+                       break;
+       }
+
+       return r < 0 ? r : -EIO;
+}
+
+static int panel_dvi_read_edid(struct omap_dss_device *dssdev,
+               u8 *edid, int len)
+{
+       struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+       struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
+       struct i2c_adapter *adapter;
+       int r, l, bytes_read;
+
+       mutex_lock(&ddata->lock);
+
+       if (pdata->i2c_bus_num == 0) {
+               r = -ENODEV;
+               goto err;
+       }
+
+       adapter = i2c_get_adapter(pdata->i2c_bus_num);
+       if (!adapter) {
+               dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
+                               pdata->i2c_bus_num);
+               r = -EINVAL;
+               goto err;
+       }
+
+       l = min(EDID_LENGTH, len);
+       r = panel_dvi_ddc_read(adapter, edid, l, 0);
+       if (r)
+               goto err;
+
+       bytes_read = l;
+
+       /* if there are extensions, read second block */
+       if (len > EDID_LENGTH && edid[0x7e] > 0) {
+               l = min(EDID_LENGTH, len - EDID_LENGTH);
+
+               r = panel_dvi_ddc_read(adapter, edid + EDID_LENGTH,
+                               l, EDID_LENGTH);
+               if (r)
+                       goto err;
+
+               bytes_read += l;
+       }
+
+       mutex_unlock(&ddata->lock);
+
+       return bytes_read;
+
+err:
+       mutex_unlock(&ddata->lock);
+       return r;
+}
+
+static bool panel_dvi_detect(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
+       struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
+       struct i2c_adapter *adapter;
+       unsigned char out;
+       int r;
+
+       mutex_lock(&ddata->lock);
+
+       if (pdata->i2c_bus_num == 0)
+               goto out;
+
+       adapter = i2c_get_adapter(pdata->i2c_bus_num);
+       if (!adapter)
+               goto out;
+
+       r = panel_dvi_ddc_read(adapter, &out, 1, 0);
+
+       mutex_unlock(&ddata->lock);
+
+       return r == 0;
+
+out:
+       mutex_unlock(&ddata->lock);
+       return true;
+}
+
+static struct omap_dss_driver panel_dvi_driver = {
+       .probe          = panel_dvi_probe,
+       .remove         = __exit_p(panel_dvi_remove),
+
+       .enable         = panel_dvi_enable,
+       .disable        = panel_dvi_disable,
+       .suspend        = panel_dvi_suspend,
+       .resume         = panel_dvi_resume,
+
+       .set_timings    = panel_dvi_set_timings,
+       .get_timings    = panel_dvi_get_timings,
+       .check_timings  = panel_dvi_check_timings,
+
+       .read_edid      = panel_dvi_read_edid,
+       .detect         = panel_dvi_detect,
+
+       .driver         = {
+               .name   = "dvi",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init panel_dvi_init(void)
+{
+       return omap_dss_register_driver(&panel_dvi_driver);
+}
+
+static void __exit panel_dvi_exit(void)
+{
+       omap_dss_unregister_driver(&panel_dvi_driver);
+}
+
+module_init(panel_dvi_init);
+module_exit(panel_dvi_exit);
+MODULE_LICENSE("GPL");
index 9c90f75..519c47d 100644 (file)
@@ -58,30 +58,6 @@ struct panel_config {
 
 /* Panel configurations */
 static struct panel_config generic_dpi_panels[] = {
-       /* Generic Panel */
-       {
-               {
-                       .x_res          = 640,
-                       .y_res          = 480,
-
-                       .pixel_clock    = 23500,
-
-                       .hfp            = 48,
-                       .hsw            = 32,
-                       .hbp            = 80,
-
-                       .vfp            = 3,
-                       .vsw            = 4,
-                       .vbp            = 7,
-               },
-               .acbi                   = 0x0,
-               .acb                    = 0x0,
-               .config                 = OMAP_DSS_LCD_TFT,
-               .power_on_delay         = 0,
-               .power_off_delay        = 0,
-               .name                   = "generic",
-       },
-
        /* Sharp LQ043T1DG01 */
        {
                {
@@ -232,6 +208,95 @@ static struct panel_config generic_dpi_panels[] = {
                .power_off_delay        = 0,
                .name                   = "powertip_ph480272t",
        },
+
+       /* Innolux AT070TN83 */
+       {
+               {
+                       .x_res          = 800,
+                       .y_res          = 480,
+
+                       .pixel_clock    = 40000,
+
+                       .hsw            = 48,
+                       .hfp            = 1,
+                       .hbp            = 1,
+
+                       .vsw            = 3,
+                       .vfp            = 12,
+                       .vbp            = 25,
+               },
+               .acbi                   = 0x0,
+               .acb                    = 0x28,
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                         OMAP_DSS_LCD_IHS,
+               .power_on_delay         = 0,
+               .power_off_delay        = 0,
+               .name                   = "innolux_at070tn83",
+       },
+
+       /* NEC NL2432DR22-11B */
+       {
+               {
+                       .x_res          = 240,
+                       .y_res          = 320,
+
+                       .pixel_clock    = 5400,
+
+                       .hsw            = 3,
+                       .hfp            = 3,
+                       .hbp            = 39,
+
+                       .vsw            = 1,
+                       .vfp            = 2,
+                       .vbp            = 7,
+               },
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                               OMAP_DSS_LCD_IHS,
+               .name                   = "nec_nl2432dr22-11b",
+       },
+
+       /* Unknown panel used in OMAP H4 */
+       {
+               {
+                       .x_res          = 240,
+                       .y_res          = 320,
+
+                       .pixel_clock    = 6250,
+
+                       .hsw            = 15,
+                       .hfp            = 15,
+                       .hbp            = 60,
+
+                       .vsw            = 1,
+                       .vfp            = 1,
+                       .vbp            = 1,
+               },
+               .config                 = OMAP_DSS_LCD_TFT,
+
+               .name                   = "h4",
+       },
+
+       /* Unknown panel used in Samsung OMAP2 Apollon */
+       {
+               {
+                       .x_res          = 480,
+                       .y_res          = 272,
+
+                       .pixel_clock    = 6250,
+
+                       .hsw            = 41,
+                       .hfp            = 2,
+                       .hbp            = 2,
+
+                       .vsw            = 10,
+                       .vfp            = 2,
+                       .vbp            = 2,
+               },
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                               OMAP_DSS_LCD_IHS,
+
+               .name                   = "apollon",
+       },
 };
 
 struct panel_drv_data {
diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c
new file mode 100644 (file)
index 0000000..150e8ba
--- /dev/null
@@ -0,0 +1,747 @@
+/* #define DEBUG */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-n8x0.h>
+
+#define BLIZZARD_REV_CODE                      0x00
+#define BLIZZARD_CONFIG                        0x02
+#define BLIZZARD_PLL_DIV                       0x04
+#define BLIZZARD_PLL_LOCK_RANGE                0x06
+#define BLIZZARD_PLL_CLOCK_SYNTH_0             0x08
+#define BLIZZARD_PLL_CLOCK_SYNTH_1             0x0a
+#define BLIZZARD_PLL_MODE                      0x0c
+#define BLIZZARD_CLK_SRC                       0x0e
+#define BLIZZARD_MEM_BANK0_ACTIVATE            0x10
+#define BLIZZARD_MEM_BANK0_STATUS              0x14
+#define BLIZZARD_PANEL_CONFIGURATION           0x28
+#define BLIZZARD_HDISP                         0x2a
+#define BLIZZARD_HNDP                          0x2c
+#define BLIZZARD_VDISP0                        0x2e
+#define BLIZZARD_VDISP1                        0x30
+#define BLIZZARD_VNDP                          0x32
+#define BLIZZARD_HSW                           0x34
+#define BLIZZARD_VSW                           0x38
+#define BLIZZARD_DISPLAY_MODE                  0x68
+#define BLIZZARD_INPUT_WIN_X_START_0           0x6c
+#define BLIZZARD_DATA_SOURCE_SELECT            0x8e
+#define BLIZZARD_DISP_MEM_DATA_PORT            0x90
+#define BLIZZARD_DISP_MEM_READ_ADDR0           0x92
+#define BLIZZARD_POWER_SAVE                    0xE6
+#define BLIZZARD_NDISP_CTRL_STATUS             0xE8
+
+/* Data source select */
+/* For S1D13745 */
+#define BLIZZARD_SRC_WRITE_LCD_BACKGROUND      0x00
+#define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE     0x01
+#define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE      0x04
+#define BLIZZARD_SRC_DISABLE_OVERLAY           0x05
+/* For S1D13744 */
+#define BLIZZARD_SRC_WRITE_LCD                 0x00
+#define BLIZZARD_SRC_BLT_LCD                   0x06
+
+#define BLIZZARD_COLOR_RGB565                  0x01
+#define BLIZZARD_COLOR_YUV420                  0x09
+
+#define BLIZZARD_VERSION_S1D13745              0x01    /* Hailstorm */
+#define BLIZZARD_VERSION_S1D13744              0x02    /* Blizzard */
+
+#define MIPID_CMD_READ_DISP_ID         0x04
+#define MIPID_CMD_READ_RED             0x06
+#define MIPID_CMD_READ_GREEN           0x07
+#define MIPID_CMD_READ_BLUE            0x08
+#define MIPID_CMD_READ_DISP_STATUS     0x09
+#define MIPID_CMD_RDDSDR               0x0F
+#define MIPID_CMD_SLEEP_IN             0x10
+#define MIPID_CMD_SLEEP_OUT            0x11
+#define MIPID_CMD_DISP_OFF             0x28
+#define MIPID_CMD_DISP_ON              0x29
+
+static struct panel_drv_data {
+       struct mutex lock;
+
+       struct omap_dss_device *dssdev;
+       struct spi_device *spidev;
+       struct backlight_device *bldev;
+
+       int blizzard_ver;
+} s_drv_data;
+
+
+static inline
+struct panel_n8x0_data *get_board_data(const struct omap_dss_device *dssdev)
+{
+       return dssdev->data;
+}
+
+static inline
+struct panel_drv_data *get_drv_data(const struct omap_dss_device *dssdev)
+{
+       return &s_drv_data;
+}
+
+
+static inline void blizzard_cmd(u8 cmd)
+{
+       omap_rfbi_write_command(&cmd, 1);
+}
+
+static inline void blizzard_write(u8 cmd, const u8 *buf, int len)
+{
+       omap_rfbi_write_command(&cmd, 1);
+       omap_rfbi_write_data(buf, len);
+}
+
+static inline void blizzard_read(u8 cmd, u8 *buf, int len)
+{
+       omap_rfbi_write_command(&cmd, 1);
+       omap_rfbi_read_data(buf, len);
+}
+
+static u8 blizzard_read_reg(u8 cmd)
+{
+       u8 data;
+       blizzard_read(cmd, &data, 1);
+       return data;
+}
+
+static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev,
+               int x, int y, int w, int h)
+{
+       struct panel_drv_data *ddata = get_drv_data(dssdev);
+       u8 tmp[18];
+       int x_end, y_end;
+
+       x_end = x + w - 1;
+       y_end = y + h - 1;
+
+       tmp[0] = x;
+       tmp[1] = x >> 8;
+       tmp[2] = y;
+       tmp[3] = y >> 8;
+       tmp[4] = x_end;
+       tmp[5] = x_end >> 8;
+       tmp[6] = y_end;
+       tmp[7] = y_end >> 8;
+
+       /* scaling? */
+       tmp[8] = x;
+       tmp[9] = x >> 8;
+       tmp[10] = y;
+       tmp[11] = y >> 8;
+       tmp[12] = x_end;
+       tmp[13] = x_end >> 8;
+       tmp[14] = y_end;
+       tmp[15] = y_end >> 8;
+
+       tmp[16] = BLIZZARD_COLOR_RGB565;
+
+       if (ddata->blizzard_ver == BLIZZARD_VERSION_S1D13745)
+               tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND;
+       else
+               tmp[17] = ddata->blizzard_ver == BLIZZARD_VERSION_S1D13744 ?
+                       BLIZZARD_SRC_WRITE_LCD :
+                       BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE;
+
+       omap_rfbi_configure(dssdev, 16, 8);
+
+       blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18);
+
+       omap_rfbi_configure(dssdev, 16, 16);
+}
+
+static void mipid_transfer(struct spi_device *spi, int cmd, const u8 *wbuf,
+               int wlen, u8 *rbuf, int rlen)
+{
+       struct spi_message      m;
+       struct spi_transfer     *x, xfer[4];
+       u16                     w;
+       int                     r;
+
+       spi_message_init(&m);
+
+       memset(xfer, 0, sizeof(xfer));
+       x = &xfer[0];
+
+       cmd &=  0xff;
+       x->tx_buf               = &cmd;
+       x->bits_per_word        = 9;
+       x->len                  = 2;
+       spi_message_add_tail(x, &m);
+
+       if (wlen) {
+               x++;
+               x->tx_buf               = wbuf;
+               x->len                  = wlen;
+               x->bits_per_word        = 9;
+               spi_message_add_tail(x, &m);
+       }
+
+       if (rlen) {
+               x++;
+               x->rx_buf       = &w;
+               x->len          = 1;
+               spi_message_add_tail(x, &m);
+
+               if (rlen > 1) {
+                       /* Arrange for the extra clock before the first
+                        * data bit.
+                        */
+                       x->bits_per_word = 9;
+                       x->len           = 2;
+
+                       x++;
+                       x->rx_buf        = &rbuf[1];
+                       x->len           = rlen - 1;
+                       spi_message_add_tail(x, &m);
+               }
+       }
+
+       r = spi_sync(spi, &m);
+       if (r < 0)
+               dev_dbg(&spi->dev, "spi_sync %d\n", r);
+
+       if (rlen)
+               rbuf[0] = w & 0xff;
+}
+
+static inline void mipid_cmd(struct spi_device *spi, int cmd)
+{
+       mipid_transfer(spi, cmd, NULL, 0, NULL, 0);
+}
+
+static inline void mipid_write(struct spi_device *spi,
+               int reg, const u8 *buf, int len)
+{
+       mipid_transfer(spi, reg, buf, len, NULL, 0);
+}
+
+static inline void mipid_read(struct spi_device *spi,
+               int reg, u8 *buf, int len)
+{
+       mipid_transfer(spi, reg, NULL, 0, buf, len);
+}
+
+static void set_data_lines(struct spi_device *spi, int data_lines)
+{
+       u16 par;
+
+       switch (data_lines) {
+       case 16:
+               par = 0x150;
+               break;
+       case 18:
+               par = 0x160;
+               break;
+       case 24:
+               par = 0x170;
+               break;
+       }
+
+       mipid_write(spi, 0x3a, (u8 *)&par, 2);
+}
+
+static void send_init_string(struct spi_device *spi)
+{
+       u16 initpar[] = { 0x0102, 0x0100, 0x0100 };
+       mipid_write(spi, 0xc2, (u8 *)initpar, sizeof(initpar));
+}
+
+static void send_display_on(struct spi_device *spi)
+{
+       mipid_cmd(spi, MIPID_CMD_DISP_ON);
+}
+
+static void send_display_off(struct spi_device *spi)
+{
+       mipid_cmd(spi, MIPID_CMD_DISP_OFF);
+}
+
+static void send_sleep_out(struct spi_device *spi)
+{
+       mipid_cmd(spi, MIPID_CMD_SLEEP_OUT);
+       msleep(120);
+}
+
+static void send_sleep_in(struct spi_device *spi)
+{
+       mipid_cmd(spi, MIPID_CMD_SLEEP_IN);
+       msleep(50);
+}
+
+static int n8x0_panel_power_on(struct omap_dss_device *dssdev)
+{
+       int r;
+       struct panel_n8x0_data *bdata = get_board_data(dssdev);
+       struct panel_drv_data *ddata = get_drv_data(dssdev);
+       struct spi_device *spi = ddata->spidev;
+       u8 rev, conf;
+       u8 display_id[3];
+       const char *panel_name;
+
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
+       gpio_direction_output(bdata->ctrl_pwrdown, 1);
+
+       if (bdata->platform_enable) {
+               r = bdata->platform_enable(dssdev);
+               if (r)
+                       goto err_plat_en;
+       }
+
+       r = omapdss_rfbi_display_enable(dssdev);
+       if (r)
+               goto err_rfbi_en;
+
+       rev = blizzard_read_reg(BLIZZARD_REV_CODE);
+       conf = blizzard_read_reg(BLIZZARD_CONFIG);
+
+       switch (rev & 0xfc) {
+       case 0x9c:
+               ddata->blizzard_ver = BLIZZARD_VERSION_S1D13744;
+               dev_info(&dssdev->dev, "s1d13744 LCD controller rev %d "
+                       "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
+               break;
+       case 0xa4:
+               ddata->blizzard_ver = BLIZZARD_VERSION_S1D13745;
+               dev_info(&dssdev->dev, "s1d13745 LCD controller rev %d "
+                       "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
+               break;
+       default:
+               dev_err(&dssdev->dev, "invalid s1d1374x revision %02x\n", rev);
+               r = -ENODEV;
+               goto err_inv_chip;
+       }
+
+       /* panel */
+
+       gpio_direction_output(bdata->panel_reset, 1);
+
+       mipid_read(spi, MIPID_CMD_READ_DISP_ID, display_id, 3);
+       dev_dbg(&spi->dev, "MIPI display ID: %02x%02x%02x\n",
+                       display_id[0], display_id[1], display_id[2]);
+
+       switch (display_id[0]) {
+       case 0x45:
+               panel_name = "lph8923";
+               break;
+       case 0x83:
+               panel_name = "ls041y3";
+               break;
+       default:
+               dev_err(&dssdev->dev, "invalid display ID 0x%x\n",
+                               display_id[0]);
+               r = -ENODEV;
+               goto err_inv_panel;
+       }
+
+       dev_info(&dssdev->dev, "%s rev %02x LCD detected\n",
+                       panel_name, display_id[1]);
+
+       send_sleep_out(spi);
+       send_init_string(spi);
+       set_data_lines(spi, 24);
+       send_display_on(spi);
+
+       return 0;
+
+err_inv_panel:
+       /*
+        * HACK: we should turn off the panel here, but there is some problem
+        * with the initialization sequence, and we fail to init the panel if we
+        * have turned it off
+        */
+       /* gpio_direction_output(bdata->panel_reset, 0); */
+err_inv_chip:
+       omapdss_rfbi_display_disable(dssdev);
+err_rfbi_en:
+       if (bdata->platform_disable)
+               bdata->platform_disable(dssdev);
+err_plat_en:
+       gpio_direction_output(bdata->ctrl_pwrdown, 0);
+       return r;
+}
+
+static void n8x0_panel_power_off(struct omap_dss_device *dssdev)
+{
+       struct panel_n8x0_data *bdata = get_board_data(dssdev);
+       struct panel_drv_data *ddata = get_drv_data(dssdev);
+       struct spi_device *spi = ddata->spidev;
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return;
+
+       send_display_off(spi);
+       send_sleep_in(spi);
+
+       if (bdata->platform_disable)
+               bdata->platform_disable(dssdev);
+
+       /*
+        * HACK: we should turn off the panel here, but there is some problem
+        * with the initialization sequence, and we fail to init the panel if we
+        * have turned it off
+        */
+       /* gpio_direction_output(bdata->panel_reset, 0); */
+       gpio_direction_output(bdata->ctrl_pwrdown, 0);
+       omapdss_rfbi_display_disable(dssdev);
+}
+
+static const struct rfbi_timings n8x0_panel_timings = {
+       .cs_on_time     = 0,
+
+       .we_on_time     = 9000,
+       .we_off_time    = 18000,
+       .we_cycle_time  = 36000,
+
+       .re_on_time     = 9000,
+       .re_off_time    = 27000,
+       .re_cycle_time  = 36000,
+
+       .access_time    = 27000,
+       .cs_off_time    = 36000,
+
+       .cs_pulse_width = 0,
+};
+
+static int n8x0_bl_update_status(struct backlight_device *dev)
+{
+       struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
+       struct panel_n8x0_data *bdata = get_board_data(dssdev);
+       struct panel_drv_data *ddata = get_drv_data(dssdev);
+       int r;
+       int level;
+
+       mutex_lock(&ddata->lock);
+
+       if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
+                       dev->props.power == FB_BLANK_UNBLANK)
+               level = dev->props.brightness;
+       else
+               level = 0;
+
+       dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
+
+       if (!bdata->set_backlight)
+               r = -EINVAL;
+       else
+               r = bdata->set_backlight(dssdev, level);
+
+       mutex_unlock(&ddata->lock);
+
+       return r;
+}
+
+static int n8x0_bl_get_intensity(struct backlight_device *dev)
+{
+       if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
+                       dev->props.power == FB_BLANK_UNBLANK)
+               return dev->props.brightness;
+
+       return 0;
+}
+
+static const struct backlight_ops n8x0_bl_ops = {
+       .get_brightness = n8x0_bl_get_intensity,
+       .update_status  = n8x0_bl_update_status,
+};
+
+static int n8x0_panel_probe(struct omap_dss_device *dssdev)
+{
+       struct panel_n8x0_data *bdata = get_board_data(dssdev);
+       struct panel_drv_data *ddata;
+       struct backlight_device *bldev;
+       struct backlight_properties props;
+       int r;
+
+       dev_dbg(&dssdev->dev, "probe\n");
+
+       if (!bdata)
+               return -EINVAL;
+
+       s_drv_data.dssdev = dssdev;
+
+       ddata = &s_drv_data;
+
+       mutex_init(&ddata->lock);
+
+       dssdev->panel.config = OMAP_DSS_LCD_TFT;
+       dssdev->panel.timings.x_res = 800;
+       dssdev->panel.timings.y_res = 480;
+       dssdev->ctrl.pixel_size = 16;
+       dssdev->ctrl.rfbi_timings = n8x0_panel_timings;
+
+       memset(&props, 0, sizeof(props));
+       props.max_brightness = 127;
+       props.type = BACKLIGHT_PLATFORM;
+       bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev,
+                       dssdev, &n8x0_bl_ops, &props);
+       if (IS_ERR(bldev)) {
+               r = PTR_ERR(bldev);
+               dev_err(&dssdev->dev, "register backlight failed\n");
+               return r;
+       }
+
+       ddata->bldev = bldev;
+
+       bldev->props.fb_blank = FB_BLANK_UNBLANK;
+       bldev->props.power = FB_BLANK_UNBLANK;
+       bldev->props.brightness = 127;
+
+       n8x0_bl_update_status(bldev);
+
+       return 0;
+}
+
+static void n8x0_panel_remove(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata = get_drv_data(dssdev);
+       struct backlight_device *bldev;
+
+       dev_dbg(&dssdev->dev, "remove\n");
+
+       bldev = ddata->bldev;
+       bldev->props.power = FB_BLANK_POWERDOWN;
+       n8x0_bl_update_status(bldev);
+       backlight_device_unregister(bldev);
+
+       dev_set_drvdata(&dssdev->dev, NULL);
+}
+
+static int n8x0_panel_enable(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata = get_drv_data(dssdev);
+       int r;
+
+       dev_dbg(&dssdev->dev, "enable\n");
+
+       mutex_lock(&ddata->lock);
+
+       rfbi_bus_lock();
+
+       r = n8x0_panel_power_on(dssdev);
+
+       rfbi_bus_unlock();
+
+       if (r) {
+               mutex_unlock(&ddata->lock);
+               return r;
+       }
+
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+       mutex_unlock(&ddata->lock);
+
+       return 0;
+}
+
+static void n8x0_panel_disable(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata = get_drv_data(dssdev);
+
+       dev_dbg(&dssdev->dev, "disable\n");
+
+       mutex_lock(&ddata->lock);
+
+       rfbi_bus_lock();
+
+       n8x0_panel_power_off(dssdev);
+
+       rfbi_bus_unlock();
+
+       dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+       mutex_unlock(&ddata->lock);
+}
+
+static int n8x0_panel_suspend(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata = get_drv_data(dssdev);
+
+       dev_dbg(&dssdev->dev, "suspend\n");
+
+       mutex_lock(&ddata->lock);
+
+       rfbi_bus_lock();
+
+       n8x0_panel_power_off(dssdev);
+
+       rfbi_bus_unlock();
+
+       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+       mutex_unlock(&ddata->lock);
+
+       return 0;
+}
+
+static int n8x0_panel_resume(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata = get_drv_data(dssdev);
+       int r;
+
+       dev_dbg(&dssdev->dev, "resume\n");
+
+       mutex_lock(&ddata->lock);
+
+       rfbi_bus_lock();
+
+       r = n8x0_panel_power_on(dssdev);
+
+       rfbi_bus_unlock();
+
+       if (r) {
+               mutex_unlock(&ddata->lock);
+               return r;
+       }
+
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+       mutex_unlock(&ddata->lock);
+
+       return 0;
+}
+
+static void n8x0_panel_get_timings(struct omap_dss_device *dssdev,
+               struct omap_video_timings *timings)
+{
+       *timings = dssdev->panel.timings;
+}
+
+static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev,
+               u16 *xres, u16 *yres)
+{
+       *xres = dssdev->panel.timings.x_res;
+       *yres = dssdev->panel.timings.y_res;
+}
+
+static void update_done(void *data)
+{
+       rfbi_bus_unlock();
+}
+
+static int n8x0_panel_update(struct omap_dss_device *dssdev,
+               u16 x, u16 y, u16 w, u16 h)
+{
+       struct panel_drv_data *ddata = get_drv_data(dssdev);
+
+       dev_dbg(&dssdev->dev, "update\n");
+
+       mutex_lock(&ddata->lock);
+       rfbi_bus_lock();
+
+       omap_rfbi_prepare_update(dssdev, &x, &y, &w, &h);
+
+       blizzard_ctrl_setup_update(dssdev, x, y, w, h);
+
+       omap_rfbi_update(dssdev, x, y, w, h, update_done, NULL);
+
+       mutex_unlock(&ddata->lock);
+
+       return 0;
+}
+
+static int n8x0_panel_sync(struct omap_dss_device *dssdev)
+{
+       struct panel_drv_data *ddata = get_drv_data(dssdev);
+
+       dev_dbg(&dssdev->dev, "sync\n");
+
+       mutex_lock(&ddata->lock);
+       rfbi_bus_lock();
+       rfbi_bus_unlock();
+       mutex_unlock(&ddata->lock);
+
+       return 0;
+}
+
+static struct omap_dss_driver n8x0_panel_driver = {
+       .probe          = n8x0_panel_probe,
+       .remove         = n8x0_panel_remove,
+
+       .enable         = n8x0_panel_enable,
+       .disable        = n8x0_panel_disable,
+       .suspend        = n8x0_panel_suspend,
+       .resume         = n8x0_panel_resume,
+
+       .update         = n8x0_panel_update,
+       .sync           = n8x0_panel_sync,
+
+       .get_resolution = n8x0_panel_get_resolution,
+       .get_recommended_bpp = omapdss_default_get_recommended_bpp,
+
+       .get_timings    = n8x0_panel_get_timings,
+
+       .driver         = {
+               .name   = "n8x0_panel",
+               .owner  = THIS_MODULE,
+       },
+};
+
+/* PANEL */
+
+static int mipid_spi_probe(struct spi_device *spi)
+{
+       dev_dbg(&spi->dev, "mipid_spi_probe\n");
+
+       spi->mode = SPI_MODE_0;
+
+       s_drv_data.spidev = spi;
+
+       return 0;
+}
+
+static int mipid_spi_remove(struct spi_device *spi)
+{
+       dev_dbg(&spi->dev, "mipid_spi_remove\n");
+       return 0;
+}
+
+static struct spi_driver mipid_spi_driver = {
+       .driver = {
+               .name   = "lcd_mipid",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = mipid_spi_probe,
+       .remove = __devexit_p(mipid_spi_remove),
+};
+
+static int __init n8x0_panel_drv_init(void)
+{
+       int r;
+
+       r = spi_register_driver(&mipid_spi_driver);
+       if (r) {
+               pr_err("n8x0_panel: spi driver registration failed\n");
+               return r;
+       }
+
+       r = omap_dss_register_driver(&n8x0_panel_driver);
+       if (r) {
+               pr_err("n8x0_panel: dss driver registration failed\n");
+               spi_unregister_driver(&mipid_spi_driver);
+               return r;
+       }
+
+       return 0;
+}
+
+static void __exit n8x0_panel_drv_exit(void)
+{
+       spi_unregister_driver(&mipid_spi_driver);
+
+       omap_dss_unregister_driver(&n8x0_panel_driver);
+}
+
+module_init(n8x0_panel_drv_init);
+module_exit(n8x0_panel_drv_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c
new file mode 100644 (file)
index 0000000..98ebdad
--- /dev/null
@@ -0,0 +1,594 @@
+/*
+ * picodlp panel driver
+ * picodlp_i2c_driver: i2c_client driver
+ *
+ * Copyright (C) 2009-2011 Texas Instruments
+ * Author: Mythri P K <mythripk@ti.com>
+ * Mayuresh Janorkar <mayur@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-picodlp.h>
+
+#include "panel-picodlp.h"
+
+struct picodlp_data {
+       struct mutex lock;
+       struct i2c_client *picodlp_i2c_client;
+};
+
+static struct i2c_board_info picodlp_i2c_board_info = {
+       I2C_BOARD_INFO("picodlp_i2c_driver", 0x1b),
+};
+
+struct picodlp_i2c_data {
+       struct mutex xfer_lock;
+};
+
+static struct i2c_device_id picodlp_i2c_id[] = {
+       { "picodlp_i2c_driver", 0 },
+};
+
+struct picodlp_i2c_command {
+       u8 reg;
+       u32 value;
+};
+
+static struct omap_video_timings pico_ls_timings = {
+       .x_res          = 864,
+       .y_res          = 480,
+       .hsw            = 7,
+       .hfp            = 11,
+       .hbp            = 7,
+
+       .pixel_clock    = 19200,
+
+       .vsw            = 2,
+       .vfp            = 3,
+       .vbp            = 14,
+};
+
+static inline struct picodlp_panel_data
+               *get_panel_data(const struct omap_dss_device *dssdev)
+{
+       return (struct picodlp_panel_data *) dssdev->data;
+}
+
+static u32 picodlp_i2c_read(struct i2c_client *client, u8 reg)
+{
+       u8 read_cmd[] = {READ_REG_SELECT, reg}, data[4];
+       struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client);
+       struct i2c_msg msg[2];
+
+       mutex_lock(&picodlp_i2c_data->xfer_lock);
+
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = 2;
+       msg[0].buf = read_cmd;
+
+       msg[1].addr = client->addr;
+       msg[1].flags = I2C_M_RD;
+       msg[1].len = 4;
+       msg[1].buf = data;
+
+       i2c_transfer(client->adapter, msg, 2);
+       mutex_unlock(&picodlp_i2c_data->xfer_lock);
+       return (data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24));
+}
+
+static int picodlp_i2c_write_block(struct i2c_client *client,
+                                       u8 *data, int len)
+{
+       struct i2c_msg msg;
+       int i, r, msg_count = 1;
+
+       struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client);
+
+       if (len < 1 || len > 32) {
+               dev_err(&client->dev,
+                       "too long syn_write_block len %d\n", len);
+               return -EIO;
+       }
+       mutex_lock(&picodlp_i2c_data->xfer_lock);
+
+       msg.addr = client->addr;
+       msg.flags = 0;
+       msg.len = len;
+       msg.buf = data;
+       r = i2c_transfer(client->adapter, &msg, msg_count);
+       mutex_unlock(&picodlp_i2c_data->xfer_lock);
+
+       /*
+        * i2c_transfer returns:
+        * number of messages sent in case of success
+        * a negative error number in case of failure
+        */
+       if (r != msg_count)
+               goto err;
+
+       /* In case of success */
+       for (i = 0; i < len; i++)
+               dev_dbg(&client->dev,
+                       "addr %x bw 0x%02x[%d]: 0x%02x\n",
+                       client->addr, data[0] + i, i, data[i]);
+
+       return 0;
+err:
+       dev_err(&client->dev, "picodlp_i2c_write error\n");
+       return r;
+}
+
+static int picodlp_i2c_write(struct i2c_client *client, u8 reg, u32 value)
+{
+       u8 data[5];
+       int i;
+
+       data[0] = reg;
+       for (i = 1; i < 5; i++)
+               data[i] = (value >> (32 - (i) * 8)) & 0xFF;
+
+       return picodlp_i2c_write_block(client, data, 5);
+}
+
+static int picodlp_i2c_write_array(struct i2c_client *client,
+                       const struct picodlp_i2c_command commands[],
+                       int count)
+{
+       int i, r = 0;
+       for (i = 0; i < count; i++) {
+               r = picodlp_i2c_write(client, commands[i].reg,
+                                               commands[i].value);
+               if (r)
+                       return r;
+       }
+       return r;
+}
+
+static int picodlp_wait_for_dma_done(struct i2c_client *client)
+{
+       u8 trial = 100;
+
+       do {
+               msleep(1);
+               if (!trial--)
+                       return -ETIMEDOUT;
+       } while (picodlp_i2c_read(client, MAIN_STATUS) & DMA_STATUS);
+
+       return 0;
+}
+
+/**
+ * picodlp_i2c_init:   i2c_initialization routine
+ * client:     i2c_client for communication
+ *
+ * return
+ *             0       : Success, no error
+ *     error code      : Failure
+ */
+static int picodlp_i2c_init(struct i2c_client *client)
+{
+       int r;
+       static const struct picodlp_i2c_command init_cmd_set1[] = {
+               {SOFT_RESET, 1},
+               {DMD_PARK_TRIGGER, 1},
+               {MISC_REG, 5},
+               {SEQ_CONTROL, 0},
+               {SEQ_VECTOR, 0x100},
+               {DMD_BLOCK_COUNT, 7},
+               {DMD_VCC_CONTROL, 0x109},
+               {DMD_PARK_PULSE_COUNT, 0xA},
+               {DMD_PARK_PULSE_WIDTH, 0xB},
+               {DMD_PARK_DELAY, 0x2ED},
+               {DMD_SHADOW_ENABLE, 0},
+               {FLASH_OPCODE, 0xB},
+               {FLASH_DUMMY_BYTES, 1},
+               {FLASH_ADDR_BYTES, 3},
+               {PBC_CONTROL, 0},
+               {FLASH_START_ADDR, CMT_LUT_0_START_ADDR},
+               {FLASH_READ_BYTES, CMT_LUT_0_SIZE},
+               {CMT_SPLASH_LUT_START_ADDR, 0},
+               {CMT_SPLASH_LUT_DEST_SELECT, CMT_LUT_ALL},
+               {PBC_CONTROL, 1},
+       };
+
+       static const struct picodlp_i2c_command init_cmd_set2[] = {
+               {PBC_CONTROL, 0},
+               {CMT_SPLASH_LUT_DEST_SELECT, 0},
+               {PBC_CONTROL, 0},
+               {FLASH_START_ADDR, SEQUENCE_0_START_ADDR},
+               {FLASH_READ_BYTES, SEQUENCE_0_SIZE},
+               {SEQ_RESET_LUT_START_ADDR, 0},
+               {SEQ_RESET_LUT_DEST_SELECT, SEQ_SEQ_LUT},
+               {PBC_CONTROL, 1},
+       };
+
+       static const struct picodlp_i2c_command init_cmd_set3[] = {
+               {PBC_CONTROL, 0},
+               {SEQ_RESET_LUT_DEST_SELECT, 0},
+               {PBC_CONTROL, 0},
+               {FLASH_START_ADDR, DRC_TABLE_0_START_ADDR},
+               {FLASH_READ_BYTES, DRC_TABLE_0_SIZE},
+               {SEQ_RESET_LUT_START_ADDR, 0},
+               {SEQ_RESET_LUT_DEST_SELECT, SEQ_DRC_LUT_ALL},
+               {PBC_CONTROL, 1},
+       };
+
+       static const struct picodlp_i2c_command init_cmd_set4[] = {
+               {PBC_CONTROL, 0},
+               {SEQ_RESET_LUT_DEST_SELECT, 0},
+               {SDC_ENABLE, 1},
+               {AGC_CTRL, 7},
+               {CCA_C1A, 0x100},
+               {CCA_C1B, 0x0},
+               {CCA_C1C, 0x0},
+               {CCA_C2A, 0x0},
+               {CCA_C2B, 0x100},
+               {CCA_C2C, 0x0},
+               {CCA_C3A, 0x0},
+               {CCA_C3B, 0x0},
+               {CCA_C3C, 0x100},
+               {CCA_C7A, 0x100},
+               {CCA_C7B, 0x100},
+               {CCA_C7C, 0x100},
+               {CCA_ENABLE, 1},
+               {CPU_IF_MODE, 1},
+               {SHORT_FLIP, 1},
+               {CURTAIN_CONTROL, 0},
+               {DMD_PARK_TRIGGER, 0},
+               {R_DRIVE_CURRENT, 0x298},
+               {G_DRIVE_CURRENT, 0x298},
+               {B_DRIVE_CURRENT, 0x298},
+               {RGB_DRIVER_ENABLE, 7},
+               {SEQ_CONTROL, 0},
+               {ACTGEN_CONTROL, 0x10},
+               {SEQUENCE_MODE, SEQ_LOCK},
+               {DATA_FORMAT, RGB888},
+               {INPUT_RESOLUTION, WVGA_864_LANDSCAPE},
+               {INPUT_SOURCE, PARALLEL_RGB},
+               {CPU_IF_SYNC_METHOD, 1},
+               {SEQ_CONTROL, 1}
+       };
+
+       r = picodlp_i2c_write_array(client, init_cmd_set1,
+                                               ARRAY_SIZE(init_cmd_set1));
+       if (r)
+               return r;
+
+       r = picodlp_wait_for_dma_done(client);
+       if (r)
+               return r;
+
+       r = picodlp_i2c_write_array(client, init_cmd_set2,
+                                       ARRAY_SIZE(init_cmd_set2));
+       if (r)
+               return r;
+
+       r = picodlp_wait_for_dma_done(client);
+       if (r)
+               return r;
+
+       r = picodlp_i2c_write_array(client, init_cmd_set3,
+                                       ARRAY_SIZE(init_cmd_set3));
+       if (r)
+               return r;
+
+       r = picodlp_wait_for_dma_done(client);
+       if (r)
+               return r;
+
+       r = picodlp_i2c_write_array(client, init_cmd_set4,
+                                       ARRAY_SIZE(init_cmd_set4));
+       if (r)
+               return r;
+
+       return 0;
+}
+
+static int picodlp_i2c_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct picodlp_i2c_data *picodlp_i2c_data;
+
+       picodlp_i2c_data = kzalloc(sizeof(struct picodlp_i2c_data), GFP_KERNEL);
+
+       if (!picodlp_i2c_data)
+               return -ENOMEM;
+
+       mutex_init(&picodlp_i2c_data->xfer_lock);
+       i2c_set_clientdata(client, picodlp_i2c_data);
+
+       return 0;
+}
+
+static int picodlp_i2c_remove(struct i2c_client *client)
+{
+       struct picodlp_i2c_data *picodlp_i2c_data =
+                                       i2c_get_clientdata(client);
+       kfree(picodlp_i2c_data);
+       return 0;
+}
+
+static struct i2c_driver picodlp_i2c_driver = {
+       .driver = {
+               .name   = "picodlp_i2c_driver",
+       },
+       .probe          = picodlp_i2c_probe,
+       .remove         = picodlp_i2c_remove,
+       .id_table       = picodlp_i2c_id,
+};
+
+static int picodlp_panel_power_on(struct omap_dss_device *dssdev)
+{
+       int r, trial = 100;
+       struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
+       struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev);
+
+       if (dssdev->platform_enable) {
+               r = dssdev->platform_enable(dssdev);
+               if (r)
+                       return r;
+       }
+
+       gpio_set_value(picodlp_pdata->pwrgood_gpio, 0);
+       msleep(1);
+       gpio_set_value(picodlp_pdata->pwrgood_gpio, 1);
+
+       while (!gpio_get_value(picodlp_pdata->emu_done_gpio)) {
+               if (!trial--) {
+                       dev_err(&dssdev->dev, "emu_done signal not"
+                                               " going high\n");
+                       return -ETIMEDOUT;
+               }
+               msleep(5);
+       }
+       /*
+        * As per dpp2600 programming guide,
+        * it is required to sleep for 1000ms after emu_done signal goes high
+        * then only i2c commands can be successfully sent to dpp2600
+        */
+       msleep(1000);
+       r = omapdss_dpi_display_enable(dssdev);
+       if (r) {
+               dev_err(&dssdev->dev, "failed to enable DPI\n");
+               goto err1;
+       }
+
+       r = picodlp_i2c_init(picod->picodlp_i2c_client);
+       if (r)
+               goto err;
+
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+       return r;
+err:
+       omapdss_dpi_display_disable(dssdev);
+err1:
+       if (dssdev->platform_disable)
+               dssdev->platform_disable(dssdev);
+
+       return r;
+}
+
+static void picodlp_panel_power_off(struct omap_dss_device *dssdev)
+{
+       struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev);
+
+       omapdss_dpi_display_disable(dssdev);
+
+       gpio_set_value(picodlp_pdata->emu_done_gpio, 0);
+       gpio_set_value(picodlp_pdata->pwrgood_gpio, 0);
+
+       if (dssdev->platform_disable)
+               dssdev->platform_disable(dssdev);
+}
+
+static int picodlp_panel_probe(struct omap_dss_device *dssdev)
+{
+       struct picodlp_data *picod;
+       struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev);
+       struct i2c_adapter *adapter;
+       struct i2c_client *picodlp_i2c_client;
+       int r = 0, picodlp_adapter_id;
+
+       dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_ONOFF |
+                               OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IVS;
+       dssdev->panel.acb = 0x0;
+       dssdev->panel.timings = pico_ls_timings;
+
+       picod =  kzalloc(sizeof(struct picodlp_data), GFP_KERNEL);
+       if (!picod)
+               return -ENOMEM;
+
+       mutex_init(&picod->lock);
+
+       picodlp_adapter_id = picodlp_pdata->picodlp_adapter_id;
+
+       adapter = i2c_get_adapter(picodlp_adapter_id);
+       if (!adapter) {
+               dev_err(&dssdev->dev, "can't get i2c adapter\n");
+               r = -ENODEV;
+               goto err;
+       }
+
+       picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info);
+       if (!picodlp_i2c_client) {
+               dev_err(&dssdev->dev, "can't add i2c device::"
+                                        " picodlp_i2c_client is NULL\n");
+               r = -ENODEV;
+               goto err;
+       }
+
+       picod->picodlp_i2c_client = picodlp_i2c_client;
+
+       dev_set_drvdata(&dssdev->dev, picod);
+       return r;
+err:
+       kfree(picod);
+       return r;
+}
+
+static void picodlp_panel_remove(struct omap_dss_device *dssdev)
+{
+       struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
+
+       i2c_unregister_device(picod->picodlp_i2c_client);
+       dev_set_drvdata(&dssdev->dev, NULL);
+       dev_dbg(&dssdev->dev, "removing picodlp panel\n");
+
+       kfree(picod);
+}
+
+static int picodlp_panel_enable(struct omap_dss_device *dssdev)
+{
+       struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
+       int r;
+
+       dev_dbg(&dssdev->dev, "enabling picodlp panel\n");
+
+       mutex_lock(&picod->lock);
+       if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+               mutex_unlock(&picod->lock);
+               return -EINVAL;
+       }
+
+       r = picodlp_panel_power_on(dssdev);
+       mutex_unlock(&picod->lock);
+
+       return r;
+}
+
+static void picodlp_panel_disable(struct omap_dss_device *dssdev)
+{
+       struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
+
+       mutex_lock(&picod->lock);
+       /* Turn off DLP Power */
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               picodlp_panel_power_off(dssdev);
+
+       dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+       mutex_unlock(&picod->lock);
+
+       dev_dbg(&dssdev->dev, "disabling picodlp panel\n");
+}
+
+static int picodlp_panel_suspend(struct omap_dss_device *dssdev)
+{
+       struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
+
+       mutex_lock(&picod->lock);
+       /* Turn off DLP Power */
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
+               mutex_unlock(&picod->lock);
+               dev_err(&dssdev->dev, "unable to suspend picodlp panel,"
+                                       " panel is not ACTIVE\n");
+               return -EINVAL;
+       }
+
+       picodlp_panel_power_off(dssdev);
+
+       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+       mutex_unlock(&picod->lock);
+
+       dev_dbg(&dssdev->dev, "suspending picodlp panel\n");
+       return 0;
+}
+
+static int picodlp_panel_resume(struct omap_dss_device *dssdev)
+{
+       struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
+       int r;
+
+       mutex_lock(&picod->lock);
+       if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
+               mutex_unlock(&picod->lock);
+               dev_err(&dssdev->dev, "unable to resume picodlp panel,"
+                       " panel is not ACTIVE\n");
+               return -EINVAL;
+       }
+
+       r = picodlp_panel_power_on(dssdev);
+       mutex_unlock(&picod->lock);
+       dev_dbg(&dssdev->dev, "resuming picodlp panel\n");
+       return r;
+}
+
+static void picodlp_get_resolution(struct omap_dss_device *dssdev,
+                                       u16 *xres, u16 *yres)
+{
+       *xres = dssdev->panel.timings.x_res;
+       *yres = dssdev->panel.timings.y_res;
+}
+
+static struct omap_dss_driver picodlp_driver = {
+       .probe          = picodlp_panel_probe,
+       .remove         = picodlp_panel_remove,
+
+       .enable         = picodlp_panel_enable,
+       .disable        = picodlp_panel_disable,
+
+       .get_resolution = picodlp_get_resolution,
+
+       .suspend        = picodlp_panel_suspend,
+       .resume         = picodlp_panel_resume,
+
+       .driver         = {
+               .name   = "picodlp_panel",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init picodlp_init(void)
+{
+       int r = 0;
+
+       r = i2c_add_driver(&picodlp_i2c_driver);
+       if (r) {
+               printk(KERN_WARNING "picodlp_i2c_driver" \
+                       " registration failed\n");
+               return r;
+       }
+
+       r = omap_dss_register_driver(&picodlp_driver);
+       if (r)
+               i2c_del_driver(&picodlp_i2c_driver);
+
+       return r;
+}
+
+static void __exit picodlp_exit(void)
+{
+       i2c_del_driver(&picodlp_i2c_driver);
+       omap_dss_unregister_driver(&picodlp_driver);
+}
+
+module_init(picodlp_init);
+module_exit(picodlp_exit);
+
+MODULE_AUTHOR("Mythri P K <mythripk@ti.com>");
+MODULE_DESCRIPTION("picodlp driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-picodlp.h b/drivers/video/omap2/displays/panel-picodlp.h
new file mode 100644 (file)
index 0000000..a34b431
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * Header file required by picodlp panel driver
+ *
+ * Copyright (C) 2009-2011 Texas Instruments
+ * Author: Mythri P K <mythripk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __OMAP2_DISPLAY_PANEL_PICODLP_H
+#define __OMAP2_DISPLAY_PANEL_PICODLP_H
+
+/* Commands used for configuring picodlp panel */
+
+#define MAIN_STATUS                    0x03
+#define PBC_CONTROL                    0x08
+#define INPUT_SOURCE                   0x0B
+#define INPUT_RESOLUTION               0x0C
+#define DATA_FORMAT                    0x0D
+#define IMG_ROTATION                   0x0E
+#define LONG_FLIP                      0x0F
+#define SHORT_FLIP                     0x10
+#define TEST_PAT_SELECT                        0x11
+#define R_DRIVE_CURRENT                        0x12
+#define G_DRIVE_CURRENT                        0x13
+#define B_DRIVE_CURRENT                        0x14
+#define READ_REG_SELECT                        0x15
+#define RGB_DRIVER_ENABLE              0x16
+
+#define CPU_IF_MODE                    0x18
+#define FRAME_RATE                     0x19
+#define CPU_IF_SYNC_METHOD             0x1A
+#define CPU_IF_SOF                     0x1B
+#define CPU_IF_EOF                     0x1C
+#define CPU_IF_SLEEP                   0x1D
+
+#define SEQUENCE_MODE                  0x1E
+#define SOFT_RESET                     0x1F
+#define FRONT_END_RESET                        0x21
+#define AUTO_PWR_ENABLE                        0x22
+
+#define VSYNC_LINE_DELAY               0x23
+#define CPU_PI_HORIZ_START             0x24
+#define CPU_PI_VERT_START              0x25
+#define CPU_PI_HORIZ_WIDTH             0x26
+#define CPU_PI_VERT_HEIGHT             0x27
+
+#define PIXEL_MASK_CROP                        0x28
+#define CROP_FIRST_LINE                        0x29
+#define CROP_LAST_LINE                 0x2A
+#define CROP_FIRST_PIXEL               0x2B
+#define CROP_LAST_PIXEL                        0x2C
+#define DMD_PARK_TRIGGER               0x2D
+
+#define MISC_REG                       0x30
+
+/* AGC registers */
+#define AGC_CTRL                       0x50
+#define AGC_CLIPPED_PIXS               0x55
+#define AGC_BRIGHT_PIXS                        0x56
+#define AGC_BG_PIXS                    0x57
+#define AGC_SAFETY_MARGIN              0x17
+
+/* Color Coordinate Adjustment registers */
+#define CCA_ENABLE             0x5E
+#define CCA_C1A                        0x5F
+#define CCA_C1B                        0x60
+#define CCA_C1C                        0x61
+#define CCA_C2A                        0x62
+#define CCA_C2B                        0x63
+#define CCA_C2C                        0x64
+#define CCA_C3A                        0x65
+#define CCA_C3B                        0x66
+#define CCA_C3C                        0x67
+#define CCA_C7A                        0x71
+#define CCA_C7B                        0x72
+#define CCA_C7C                        0x73
+
+/**
+ * DLP Pico Processor 2600 comes with flash
+ * We can do DMA operations from flash for accessing Look Up Tables
+ */
+#define DMA_STATUS                     0x100
+#define FLASH_ADDR_BYTES               0x74
+#define FLASH_DUMMY_BYTES              0x75
+#define FLASH_WRITE_BYTES              0x76
+#define FLASH_READ_BYTES               0x77
+#define FLASH_OPCODE                   0x78
+#define FLASH_START_ADDR               0x79
+#define FLASH_DUMMY2                   0x7A
+#define FLASH_WRITE_DATA               0x7B
+
+#define TEMPORAL_DITH_DISABLE          0x7E
+#define SEQ_CONTROL                    0x82
+#define SEQ_VECTOR                     0x83
+
+/* DMD is Digital Micromirror Device */
+#define DMD_BLOCK_COUNT                        0x84
+#define DMD_VCC_CONTROL                        0x86
+#define DMD_PARK_PULSE_COUNT           0x87
+#define DMD_PARK_PULSE_WIDTH           0x88
+#define DMD_PARK_DELAY                 0x89
+#define DMD_SHADOW_ENABLE              0x8E
+#define SEQ_STATUS                     0x8F
+#define FLASH_CLOCK_CONTROL            0x98
+#define DMD_PARK                       0x2D
+
+#define SDRAM_BIST_ENABLE              0x46
+#define DDR_DRIVER_STRENGTH            0x9A
+#define SDC_ENABLE                     0x9D
+#define SDC_BUFF_SWAP_DISABLE          0xA3
+#define CURTAIN_CONTROL                        0xA6
+#define DDR_BUS_SWAP_ENABLE            0xA7
+#define DMD_TRC_ENABLE                 0xA8
+#define DMD_BUS_SWAP_ENABLE            0xA9
+
+#define ACTGEN_ENABLE                  0xAE
+#define ACTGEN_CONTROL                 0xAF
+#define ACTGEN_HORIZ_BP                        0xB0
+#define ACTGEN_VERT_BP                 0xB1
+
+/* Look Up Table access */
+#define CMT_SPLASH_LUT_START_ADDR      0xFA
+#define CMT_SPLASH_LUT_DEST_SELECT     0xFB
+#define CMT_SPLASH_LUT_DATA            0xFC
+#define SEQ_RESET_LUT_START_ADDR       0xFD
+#define SEQ_RESET_LUT_DEST_SELECT      0xFE
+#define SEQ_RESET_LUT_DATA             0xFF
+
+/* Input source definitions */
+#define PARALLEL_RGB           0
+#define INT_TEST_PATTERN       1
+#define SPLASH_SCREEN          2
+#define CPU_INTF               3
+#define BT656                  4
+
+/* Standard input resolution definitions */
+#define QWVGA_LANDSCAPE                3       /* (427h*240v) */
+#define WVGA_864_LANDSCAPE     21      /* (864h*480v) */
+#define WVGA_DMD_OPTICAL_TEST  35      /* (608h*684v) */
+
+/* Standard data format definitions */
+#define RGB565                 0
+#define RGB666                 1
+#define RGB888                 2
+
+/* Test Pattern definitions */
+#define TPG_CHECKERBOARD       0
+#define TPG_BLACK              1
+#define TPG_WHITE              2
+#define TPG_RED                        3
+#define TPG_BLUE               4
+#define TPG_GREEN              5
+#define TPG_VLINES_BLACK       6
+#define TPG_HLINES_BLACK       7
+#define TPG_VLINES_ALT         8
+#define TPG_HLINES_ALT         9
+#define TPG_DIAG_LINES         10
+#define TPG_GREYRAMP_VERT      11
+#define TPG_GREYRAMP_HORIZ     12
+#define TPG_ANSI_CHECKERBOARD  13
+
+/* sequence mode definitions */
+#define SEQ_FREE_RUN           0
+#define SEQ_LOCK               1
+
+/* curtain color definitions */
+#define CURTAIN_BLACK          0
+#define CURTAIN_RED            1
+#define CURTAIN_GREEN          2
+#define CURTAIN_BLUE           3
+#define CURTAIN_YELLOW         4
+#define CURTAIN_MAGENTA                5
+#define CURTAIN_CYAN           6
+#define CURTAIN_WHITE          7
+
+/* LUT definitions */
+#define CMT_LUT_NONE           0
+#define CMT_LUT_GREEN          1
+#define CMT_LUT_RED            2
+#define CMT_LUT_BLUE           3
+#define CMT_LUT_ALL            4
+#define SPLASH_LUT             5
+
+#define SEQ_LUT_NONE           0
+#define SEQ_DRC_LUT_0          1
+#define SEQ_DRC_LUT_1          2
+#define SEQ_DRC_LUT_2          3
+#define SEQ_DRC_LUT_3          4
+#define SEQ_SEQ_LUT            5
+#define SEQ_DRC_LUT_ALL                6
+#define WPC_PROGRAM_LUT                7
+
+#define BITSTREAM_START_ADDR           0x00000000
+#define BITSTREAM_SIZE                 0x00040000
+
+#define WPC_FW_0_START_ADDR            0x00040000
+#define WPC_FW_0_SIZE                  0x00000ce8
+
+#define SEQUENCE_0_START_ADDR          0x00044000
+#define SEQUENCE_0_SIZE                        0x00001000
+
+#define SEQUENCE_1_START_ADDR          0x00045000
+#define SEQUENCE_1_SIZE                        0x00000d10
+
+#define SEQUENCE_2_START_ADDR          0x00046000
+#define SEQUENCE_2_SIZE                        0x00000d10
+
+#define SEQUENCE_3_START_ADDR          0x00047000
+#define SEQUENCE_3_SIZE                        0x00000d10
+
+#define SEQUENCE_4_START_ADDR          0x00048000
+#define SEQUENCE_4_SIZE                        0x00000d10
+
+#define SEQUENCE_5_START_ADDR          0x00049000
+#define SEQUENCE_5_SIZE                        0x00000d10
+
+#define SEQUENCE_6_START_ADDR          0x0004a000
+#define SEQUENCE_6_SIZE                        0x00000d10
+
+#define CMT_LUT_0_START_ADDR           0x0004b200
+#define CMT_LUT_0_SIZE                 0x00000600
+
+#define CMT_LUT_1_START_ADDR           0x0004b800
+#define CMT_LUT_1_SIZE                 0x00000600
+
+#define CMT_LUT_2_START_ADDR           0x0004be00
+#define CMT_LUT_2_SIZE                 0x00000600
+
+#define CMT_LUT_3_START_ADDR           0x0004c400
+#define CMT_LUT_3_SIZE                 0x00000600
+
+#define CMT_LUT_4_START_ADDR           0x0004ca00
+#define CMT_LUT_4_SIZE                 0x00000600
+
+#define CMT_LUT_5_START_ADDR           0x0004d000
+#define CMT_LUT_5_SIZE                 0x00000600
+
+#define CMT_LUT_6_START_ADDR           0x0004d600
+#define CMT_LUT_6_SIZE                 0x00000600
+
+#define DRC_TABLE_0_START_ADDR         0x0004dc00
+#define DRC_TABLE_0_SIZE               0x00000100
+
+#define SPLASH_0_START_ADDR            0x0004dd00
+#define SPLASH_0_SIZE                  0x00032280
+
+#define SEQUENCE_7_START_ADDR          0x00080000
+#define SEQUENCE_7_SIZE                        0x00000d10
+
+#define SEQUENCE_8_START_ADDR          0x00081800
+#define SEQUENCE_8_SIZE                        0x00000d10
+
+#define SEQUENCE_9_START_ADDR          0x00083000
+#define SEQUENCE_9_SIZE                        0x00000d10
+
+#define CMT_LUT_7_START_ADDR           0x0008e000
+#define CMT_LUT_7_SIZE                 0x00000600
+
+#define CMT_LUT_8_START_ADDR           0x0008e800
+#define CMT_LUT_8_SIZE                 0x00000600
+
+#define CMT_LUT_9_START_ADDR           0x0008f000
+#define CMT_LUT_9_SIZE                 0x00000600
+
+#define SPLASH_1_START_ADDR            0x0009a000
+#define SPLASH_1_SIZE                  0x00032280
+
+#define SPLASH_2_START_ADDR            0x000cd000
+#define SPLASH_2_SIZE                  0x00032280
+
+#define SPLASH_3_START_ADDR            0x00100000
+#define SPLASH_3_SIZE                  0x00032280
+
+#define OPT_SPLASH_0_START_ADDR                0x00134000
+#define OPT_SPLASH_0_SIZE              0x000cb100
+
+#endif
index 4e888ac..80c3f6a 100644 (file)
 
 #include <video/omapdss.h>
 #include <video/omap-panel-nokia-dsi.h>
+#include <video/mipi_display.h>
 
 /* DSI Virtual channel. Hardcoded for now. */
 #define TCH 0
 
 #define DCS_READ_NUM_ERRORS    0x05
-#define DCS_READ_POWER_MODE    0x0a
-#define DCS_READ_MADCTL                0x0b
-#define DCS_READ_PIXEL_FORMAT  0x0c
-#define DCS_RDDSDR             0x0f
-#define DCS_SLEEP_IN           0x10
-#define DCS_SLEEP_OUT          0x11
-#define DCS_DISPLAY_OFF                0x28
-#define DCS_DISPLAY_ON         0x29
-#define DCS_COLUMN_ADDR                0x2a
-#define DCS_PAGE_ADDR          0x2b
-#define DCS_MEMORY_WRITE       0x2c
-#define DCS_TEAR_OFF           0x34
-#define DCS_TEAR_ON            0x35
-#define DCS_MEM_ACC_CTRL       0x36
-#define DCS_PIXEL_FORMAT       0x3a
 #define DCS_BRIGHTNESS         0x51
 #define DCS_CTRL_DISPLAY       0x53
 #define DCS_WRITE_CABC         0x55
@@ -222,8 +208,6 @@ struct taal_data {
 
        struct delayed_work te_timeout_work;
 
-       bool use_dsi_bl;
-
        bool cabc_broken;
        unsigned cabc_mode;
 
@@ -302,7 +286,7 @@ static int taal_sleep_in(struct taal_data *td)
 
        hw_guard_wait(td);
 
-       cmd = DCS_SLEEP_IN;
+       cmd = MIPI_DCS_ENTER_SLEEP_MODE;
        r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, &cmd, 1);
        if (r)
                return r;
@@ -321,7 +305,7 @@ static int taal_sleep_out(struct taal_data *td)
 
        hw_guard_wait(td);
 
-       r = taal_dcs_write_0(td, DCS_SLEEP_OUT);
+       r = taal_dcs_write_0(td, MIPI_DCS_EXIT_SLEEP_MODE);
        if (r)
                return r;
 
@@ -356,7 +340,7 @@ static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror)
        u8 mode;
        int b5, b6, b7;
 
-       r = taal_dcs_read_1(td, DCS_READ_MADCTL, &mode);
+       r = taal_dcs_read_1(td, MIPI_DCS_GET_ADDRESS_MODE, &mode);
        if (r)
                return r;
 
@@ -390,7 +374,7 @@ static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror)
        mode &= ~((1<<7) | (1<<6) | (1<<5));
        mode |= (b7 << 7) | (b6 << 6) | (b5 << 5);
 
-       return taal_dcs_write_1(td, DCS_MEM_ACC_CTRL, mode);
+       return taal_dcs_write_1(td, MIPI_DCS_SET_ADDRESS_MODE, mode);
 }
 
 static int taal_set_update_window(struct taal_data *td,
@@ -403,7 +387,7 @@ static int taal_set_update_window(struct taal_data *td,
        u16 y2 = y + h - 1;
 
        u8 buf[5];
-       buf[0] = DCS_COLUMN_ADDR;
+       buf[0] = MIPI_DCS_SET_COLUMN_ADDRESS;
        buf[1] = (x1 >> 8) & 0xff;
        buf[2] = (x1 >> 0) & 0xff;
        buf[3] = (x2 >> 8) & 0xff;
@@ -413,7 +397,7 @@ static int taal_set_update_window(struct taal_data *td,
        if (r)
                return r;
 
-       buf[0] = DCS_PAGE_ADDR;
+       buf[0] = MIPI_DCS_SET_PAGE_ADDRESS;
        buf[1] = (y1 >> 8) & 0xff;
        buf[2] = (y1 >> 0) & 0xff;
        buf[3] = (y2 >> 8) & 0xff;
@@ -555,7 +539,6 @@ static int taal_bl_update_status(struct backlight_device *dev)
 {
        struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-       struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
        int r;
        int level;
 
@@ -569,23 +552,16 @@ static int taal_bl_update_status(struct backlight_device *dev)
 
        mutex_lock(&td->lock);
 
-       if (td->use_dsi_bl) {
-               if (td->enabled) {
-                       dsi_bus_lock(dssdev);
+       if (td->enabled) {
+               dsi_bus_lock(dssdev);
 
-                       r = taal_wake_up(dssdev);
-                       if (!r)
-                               r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
+               r = taal_wake_up(dssdev);
+               if (!r)
+                       r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
 
-                       dsi_bus_unlock(dssdev);
-               } else {
-                       r = 0;
-               }
+               dsi_bus_unlock(dssdev);
        } else {
-               if (!panel_data->set_backlight)
-                       r = -EINVAL;
-               else
-                       r = panel_data->set_backlight(dssdev, level);
+               r = 0;
        }
 
        mutex_unlock(&td->lock);
@@ -964,7 +940,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
 {
        struct backlight_properties props;
        struct taal_data *td;
-       struct backlight_device *bldev;
+       struct backlight_device *bldev = NULL;
        struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
        struct panel_config *panel_config = NULL;
        int r, i;
@@ -990,7 +966,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
 
        dssdev->panel.config = OMAP_DSS_LCD_TFT;
        dssdev->panel.timings = panel_config->timings;
-       dssdev->ctrl.pixel_size = 24;
+       dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;
 
        td = kzalloc(sizeof(*td), GFP_KERNEL);
        if (!td) {
@@ -1025,35 +1001,26 @@ static int taal_probe(struct omap_dss_device *dssdev)
 
        taal_hw_reset(dssdev);
 
-       /* if no platform set_backlight() defined, presume DSI backlight
-        * control */
-       memset(&props, 0, sizeof(struct backlight_properties));
-       if (!panel_data->set_backlight)
-               td->use_dsi_bl = true;
-
-       if (td->use_dsi_bl)
+       if (panel_data->use_dsi_backlight) {
+               memset(&props, 0, sizeof(struct backlight_properties));
                props.max_brightness = 255;
-       else
-               props.max_brightness = 127;
-
-       props.type = BACKLIGHT_RAW;
-       bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev,
-                                       dssdev, &taal_bl_ops, &props);
-       if (IS_ERR(bldev)) {
-               r = PTR_ERR(bldev);
-               goto err_bl;
-       }
 
-       td->bldev = bldev;
+               props.type = BACKLIGHT_RAW;
+               bldev = backlight_device_register(dev_name(&dssdev->dev),
+                               &dssdev->dev, dssdev, &taal_bl_ops, &props);
+               if (IS_ERR(bldev)) {
+                       r = PTR_ERR(bldev);
+                       goto err_bl;
+               }
+
+               td->bldev = bldev;
 
-       bldev->props.fb_blank = FB_BLANK_UNBLANK;
-       bldev->props.power = FB_BLANK_UNBLANK;
-       if (td->use_dsi_bl)
+               bldev->props.fb_blank = FB_BLANK_UNBLANK;
+               bldev->props.power = FB_BLANK_UNBLANK;
                bldev->props.brightness = 255;
-       else
-               bldev->props.brightness = 127;
 
-       taal_bl_update_status(bldev);
+               taal_bl_update_status(bldev);
+       }
 
        if (panel_data->use_ext_te) {
                int gpio = panel_data->ext_te_gpio;
@@ -1067,7 +1034,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
                gpio_direction_input(gpio);
 
                r = request_irq(gpio_to_irq(gpio), taal_te_isr,
-                               IRQF_DISABLED | IRQF_TRIGGER_RISING,
+                               IRQF_TRIGGER_RISING,
                                "taal vsync", dssdev);
 
                if (r) {
@@ -1111,7 +1078,8 @@ err_irq:
        if (panel_data->use_ext_te)
                gpio_free(panel_data->ext_te_gpio);
 err_gpio:
-       backlight_device_unregister(bldev);
+       if (bldev != NULL)
+               backlight_device_unregister(bldev);
 err_bl:
        destroy_workqueue(td->workqueue);
 err_wq:
@@ -1140,9 +1108,11 @@ static void __exit taal_remove(struct omap_dss_device *dssdev)
        }
 
        bldev = td->bldev;
-       bldev->props.power = FB_BLANK_POWERDOWN;
-       taal_bl_update_status(bldev);
-       backlight_device_unregister(bldev);
+       if (bldev != NULL) {
+               bldev->props.power = FB_BLANK_POWERDOWN;
+               taal_bl_update_status(bldev);
+               backlight_device_unregister(bldev);
+       }
 
        taal_cancel_ulps_work(dssdev);
        taal_cancel_esd_work(dssdev);
@@ -1195,7 +1165,8 @@ static int taal_power_on(struct omap_dss_device *dssdev)
        if (r)
                goto err;
 
-       r = taal_dcs_write_1(td, DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
+       r = taal_dcs_write_1(td, MIPI_DCS_SET_PIXEL_FORMAT,
+               MIPI_DCS_PIXEL_FMT_24BIT);
        if (r)
                goto err;
 
@@ -1209,7 +1180,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
                        goto err;
        }
 
-       r = taal_dcs_write_0(td, DCS_DISPLAY_ON);
+       r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_ON);
        if (r)
                goto err;
 
@@ -1246,7 +1217,7 @@ static void taal_power_off(struct omap_dss_device *dssdev)
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
        int r;
 
-       r = taal_dcs_write_0(td, DCS_DISPLAY_OFF);
+       r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_OFF);
        if (!r)
                r = taal_sleep_in(td);
 
@@ -1529,9 +1500,9 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
        int r;
 
        if (enable)
-               r = taal_dcs_write_1(td, DCS_TEAR_ON, 0);
+               r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0);
        else
-               r = taal_dcs_write_0(td, DCS_TEAR_OFF);
+               r = taal_dcs_write_0(td, MIPI_DCS_SET_TEAR_OFF);
 
        if (!panel_data->use_ext_te)
                omapdss_dsi_enable_te(dssdev, enable);
@@ -1851,7 +1822,7 @@ static void taal_esd_work(struct work_struct *work)
                goto err;
        }
 
-       r = taal_dcs_read_1(td, DCS_RDDSDR, &state1);
+       r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state1);
        if (r) {
                dev_err(&dssdev->dev, "failed to read Taal status\n");
                goto err;
@@ -1864,7 +1835,7 @@ static void taal_esd_work(struct work_struct *work)
                goto err;
        }
 
-       r = taal_dcs_read_1(td, DCS_RDDSDR, &state2);
+       r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state2);
        if (r) {
                dev_err(&dssdev->dev, "failed to read Taal status\n");
                goto err;
@@ -1880,7 +1851,7 @@ static void taal_esd_work(struct work_struct *work)
        /* Self-diagnostics result is also shown on TE GPIO line. We need
         * to re-enable TE after self diagnostics */
        if (td->te_enabled && panel_data->use_ext_te) {
-               r = taal_dcs_write_1(td, DCS_TEAR_ON, 0);
+               r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0);
                if (r)
                        goto err;
        }
index 0d12524..7be7c06 100644 (file)
@@ -1,5 +1,5 @@
 menuconfig OMAP2_DSS
-        tristate "OMAP2+ Display Subsystem support (EXPERIMENTAL)"
+        tristate "OMAP2+ Display Subsystem support"
         depends on ARCH_OMAP2PLUS
         help
          OMAP2+ Display Subsystem support.
index 10d9d3b..bd34ac5 100644 (file)
@@ -6,4 +6,4 @@ omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
 omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
 omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
 omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \
-                                   hdmi_omap4_panel.o
+                                   hdmi_panel.o ti_hdmi_4xxx_ip.o
index 76821fe..86ec12e 100644 (file)
@@ -144,6 +144,10 @@ static int dss_initialize_debugfs(void)
 #ifdef CONFIG_OMAP2_DSS_VENC
        debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
                        &venc_dump_regs, &dss_debug_fops);
+#endif
+#ifdef CONFIG_OMAP4_DSS_HDMI
+       debugfs_create_file("hdmi", S_IRUGO, dss_debugfs_dir,
+                       &hdmi_dump_regs, &dss_debug_fops);
 #endif
        return 0;
 }
index 0f3961a..6892cfd 100644 (file)
@@ -106,7 +106,7 @@ static struct {
        int irq;
        struct clk *dss_clk;
 
-       u32     fifo_size[3];
+       u32     fifo_size[MAX_DSS_OVERLAYS];
 
        spinlock_t irq_lock;
        u32 irq_error_mask;
@@ -171,172 +171,98 @@ static int dispc_get_ctx_loss_count(void)
 
 static void dispc_save_context(void)
 {
-       int i;
+       int i, j;
 
        DSSDBG("dispc_save_context\n");
 
        SR(IRQENABLE);
        SR(CONTROL);
        SR(CONFIG);
-       SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD));
-       SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT));
-       SR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD));
-       SR(TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT));
        SR(LINE_NUMBER);
-       SR(TIMING_H(OMAP_DSS_CHANNEL_LCD));
-       SR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
-       SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
-       SR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
-       if (dss_has_feature(FEAT_GLOBAL_ALPHA))
+       if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
+                       dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
                SR(GLOBAL_ALPHA);
-       SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
-       SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                SR(CONTROL2);
-               SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2));
-               SR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2));
-               SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD2));
-               SR(TIMING_H(OMAP_DSS_CHANNEL_LCD2));
-               SR(TIMING_V(OMAP_DSS_CHANNEL_LCD2));
-               SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD2));
-               SR(DIVISORo(OMAP_DSS_CHANNEL_LCD2));
                SR(CONFIG2);
        }
 
-       SR(OVL_BA0(OMAP_DSS_GFX));
-       SR(OVL_BA1(OMAP_DSS_GFX));
-       SR(OVL_POSITION(OMAP_DSS_GFX));
-       SR(OVL_SIZE(OMAP_DSS_GFX));
-       SR(OVL_ATTRIBUTES(OMAP_DSS_GFX));
-       SR(OVL_FIFO_THRESHOLD(OMAP_DSS_GFX));
-       SR(OVL_ROW_INC(OMAP_DSS_GFX));
-       SR(OVL_PIXEL_INC(OMAP_DSS_GFX));
-       SR(OVL_WINDOW_SKIP(OMAP_DSS_GFX));
-       SR(OVL_TABLE_BA(OMAP_DSS_GFX));
+       for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
+               SR(DEFAULT_COLOR(i));
+               SR(TRANS_COLOR(i));
+               SR(SIZE_MGR(i));
+               if (i == OMAP_DSS_CHANNEL_DIGIT)
+                       continue;
+               SR(TIMING_H(i));
+               SR(TIMING_V(i));
+               SR(POL_FREQ(i));
+               SR(DIVISORo(i));
 
-       SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD));
-       SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
-       SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
+               SR(DATA_CYCLE1(i));
+               SR(DATA_CYCLE2(i));
+               SR(DATA_CYCLE3(i));
 
-       if (dss_has_feature(FEAT_CPR)) {
-               SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
-               SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
-               SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
-       }
-       if (dss_has_feature(FEAT_MGR_LCD2)) {
                if (dss_has_feature(FEAT_CPR)) {
-                       SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
-                       SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
-                       SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+                       SR(CPR_COEF_R(i));
+                       SR(CPR_COEF_G(i));
+                       SR(CPR_COEF_B(i));
                }
-
-               SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
-               SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
-               SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
        }
 
-       if (dss_has_feature(FEAT_PRELOAD))
-               SR(OVL_PRELOAD(OMAP_DSS_GFX));
-
-       /* VID1 */
-       SR(OVL_BA0(OMAP_DSS_VIDEO1));
-       SR(OVL_BA1(OMAP_DSS_VIDEO1));
-       SR(OVL_POSITION(OMAP_DSS_VIDEO1));
-       SR(OVL_SIZE(OMAP_DSS_VIDEO1));
-       SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
-       SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
-       SR(OVL_ROW_INC(OMAP_DSS_VIDEO1));
-       SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
-       SR(OVL_FIR(OMAP_DSS_VIDEO1));
-       SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
-       SR(OVL_ACCU0(OMAP_DSS_VIDEO1));
-       SR(OVL_ACCU1(OMAP_DSS_VIDEO1));
-
-       for (i = 0; i < 8; i++)
-               SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i));
-
-       for (i = 0; i < 8; i++)
-               SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i));
-
-       for (i = 0; i < 5; i++)
-               SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
-
-       if (dss_has_feature(FEAT_FIR_COEF_V)) {
-               for (i = 0; i < 8; i++)
-                       SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
-       }
-
-       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
-               SR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
-               SR(OVL_BA1_UV(OMAP_DSS_VIDEO1));
-               SR(OVL_FIR2(OMAP_DSS_VIDEO1));
-               SR(OVL_ACCU2_0(OMAP_DSS_VIDEO1));
-               SR(OVL_ACCU2_1(OMAP_DSS_VIDEO1));
-
-               for (i = 0; i < 8; i++)
-                       SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i));
-
-               for (i = 0; i < 8; i++)
-                       SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i));
-
-               for (i = 0; i < 8; i++)
-                       SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i));
-       }
-       if (dss_has_feature(FEAT_ATTR2))
-               SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
-
-       if (dss_has_feature(FEAT_PRELOAD))
-               SR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
-
-       /* VID2 */
-       SR(OVL_BA0(OMAP_DSS_VIDEO2));
-       SR(OVL_BA1(OMAP_DSS_VIDEO2));
-       SR(OVL_POSITION(OMAP_DSS_VIDEO2));
-       SR(OVL_SIZE(OMAP_DSS_VIDEO2));
-       SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
-       SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
-       SR(OVL_ROW_INC(OMAP_DSS_VIDEO2));
-       SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
-       SR(OVL_FIR(OMAP_DSS_VIDEO2));
-       SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
-       SR(OVL_ACCU0(OMAP_DSS_VIDEO2));
-       SR(OVL_ACCU1(OMAP_DSS_VIDEO2));
+       for (i = 0; i < dss_feat_get_num_ovls(); i++) {
+               SR(OVL_BA0(i));
+               SR(OVL_BA1(i));
+               SR(OVL_POSITION(i));
+               SR(OVL_SIZE(i));
+               SR(OVL_ATTRIBUTES(i));
+               SR(OVL_FIFO_THRESHOLD(i));
+               SR(OVL_ROW_INC(i));
+               SR(OVL_PIXEL_INC(i));
+               if (dss_has_feature(FEAT_PRELOAD))
+                       SR(OVL_PRELOAD(i));
+               if (i == OMAP_DSS_GFX) {
+                       SR(OVL_WINDOW_SKIP(i));
+                       SR(OVL_TABLE_BA(i));
+                       continue;
+               }
+               SR(OVL_FIR(i));
+               SR(OVL_PICTURE_SIZE(i));
+               SR(OVL_ACCU0(i));
+               SR(OVL_ACCU1(i));
 
-       for (i = 0; i < 8; i++)
-               SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i));
+               for (j = 0; j < 8; j++)
+                       SR(OVL_FIR_COEF_H(i, j));
 
-       for (i = 0; i < 8; i++)
-               SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i));
+               for (j = 0; j < 8; j++)
+                       SR(OVL_FIR_COEF_HV(i, j));
 
-       for (i = 0; i < 5; i++)
-               SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
+               for (j = 0; j < 5; j++)
+                       SR(OVL_CONV_COEF(i, j));
 
-       if (dss_has_feature(FEAT_FIR_COEF_V)) {
-               for (i = 0; i < 8; i++)
-                       SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
-       }
+               if (dss_has_feature(FEAT_FIR_COEF_V)) {
+                       for (j = 0; j < 8; j++)
+                               SR(OVL_FIR_COEF_V(i, j));
+               }
 
-       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
-               SR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
-               SR(OVL_BA1_UV(OMAP_DSS_VIDEO2));
-               SR(OVL_FIR2(OMAP_DSS_VIDEO2));
-               SR(OVL_ACCU2_0(OMAP_DSS_VIDEO2));
-               SR(OVL_ACCU2_1(OMAP_DSS_VIDEO2));
+               if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+                       SR(OVL_BA0_UV(i));
+                       SR(OVL_BA1_UV(i));
+                       SR(OVL_FIR2(i));
+                       SR(OVL_ACCU2_0(i));
+                       SR(OVL_ACCU2_1(i));
 
-               for (i = 0; i < 8; i++)
-                       SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i));
+                       for (j = 0; j < 8; j++)
+                               SR(OVL_FIR_COEF_H2(i, j));
 
-               for (i = 0; i < 8; i++)
-                       SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i));
+                       for (j = 0; j < 8; j++)
+                               SR(OVL_FIR_COEF_HV2(i, j));
 
-               for (i = 0; i < 8; i++)
-                       SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i));
+                       for (j = 0; j < 8; j++)
+                               SR(OVL_FIR_COEF_V2(i, j));
+               }
+               if (dss_has_feature(FEAT_ATTR2))
+                       SR(OVL_ATTRIBUTES2(i));
        }
-       if (dss_has_feature(FEAT_ATTR2))
-               SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
-
-       if (dss_has_feature(FEAT_PRELOAD))
-               SR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
 
        if (dss_has_feature(FEAT_CORE_CLK_DIV))
                SR(DIVISOR);
@@ -349,7 +275,7 @@ static void dispc_save_context(void)
 
 static void dispc_restore_context(void)
 {
-       int i, ctx;
+       int i, j, ctx;
 
        DSSDBG("dispc_restore_context\n");
 
@@ -367,165 +293,89 @@ static void dispc_restore_context(void)
        /*RR(IRQENABLE);*/
        /*RR(CONTROL);*/
        RR(CONFIG);
-       RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD));
-       RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT));
-       RR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD));
-       RR(TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT));
        RR(LINE_NUMBER);
-       RR(TIMING_H(OMAP_DSS_CHANNEL_LCD));
-       RR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
-       RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
-       RR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
-       if (dss_has_feature(FEAT_GLOBAL_ALPHA))
+       if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
+                       dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
                RR(GLOBAL_ALPHA);
-       RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
-       RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
-       if (dss_has_feature(FEAT_MGR_LCD2)) {
-               RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2));
-               RR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2));
-               RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD2));
-               RR(TIMING_H(OMAP_DSS_CHANNEL_LCD2));
-               RR(TIMING_V(OMAP_DSS_CHANNEL_LCD2));
-               RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD2));
-               RR(DIVISORo(OMAP_DSS_CHANNEL_LCD2));
+       if (dss_has_feature(FEAT_MGR_LCD2))
                RR(CONFIG2);
-       }
-
-       RR(OVL_BA0(OMAP_DSS_GFX));
-       RR(OVL_BA1(OMAP_DSS_GFX));
-       RR(OVL_POSITION(OMAP_DSS_GFX));
-       RR(OVL_SIZE(OMAP_DSS_GFX));
-       RR(OVL_ATTRIBUTES(OMAP_DSS_GFX));
-       RR(OVL_FIFO_THRESHOLD(OMAP_DSS_GFX));
-       RR(OVL_ROW_INC(OMAP_DSS_GFX));
-       RR(OVL_PIXEL_INC(OMAP_DSS_GFX));
-       RR(OVL_WINDOW_SKIP(OMAP_DSS_GFX));
-       RR(OVL_TABLE_BA(OMAP_DSS_GFX));
-
 
-       RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD));
-       RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
-       RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
+       for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
+               RR(DEFAULT_COLOR(i));
+               RR(TRANS_COLOR(i));
+               RR(SIZE_MGR(i));
+               if (i == OMAP_DSS_CHANNEL_DIGIT)
+                       continue;
+               RR(TIMING_H(i));
+               RR(TIMING_V(i));
+               RR(POL_FREQ(i));
+               RR(DIVISORo(i));
 
-       if (dss_has_feature(FEAT_CPR)) {
-               RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
-               RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
-               RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
-       }
-       if (dss_has_feature(FEAT_MGR_LCD2)) {
-               RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
-               RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
-               RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
+               RR(DATA_CYCLE1(i));
+               RR(DATA_CYCLE2(i));
+               RR(DATA_CYCLE3(i));
 
                if (dss_has_feature(FEAT_CPR)) {
-                       RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
-                       RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
-                       RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+                       RR(CPR_COEF_R(i));
+                       RR(CPR_COEF_G(i));
+                       RR(CPR_COEF_B(i));
                }
        }
 
-       if (dss_has_feature(FEAT_PRELOAD))
-               RR(OVL_PRELOAD(OMAP_DSS_GFX));
-
-       /* VID1 */
-       RR(OVL_BA0(OMAP_DSS_VIDEO1));
-       RR(OVL_BA1(OMAP_DSS_VIDEO1));
-       RR(OVL_POSITION(OMAP_DSS_VIDEO1));
-       RR(OVL_SIZE(OMAP_DSS_VIDEO1));
-       RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
-       RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
-       RR(OVL_ROW_INC(OMAP_DSS_VIDEO1));
-       RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
-       RR(OVL_FIR(OMAP_DSS_VIDEO1));
-       RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
-       RR(OVL_ACCU0(OMAP_DSS_VIDEO1));
-       RR(OVL_ACCU1(OMAP_DSS_VIDEO1));
-
-       for (i = 0; i < 8; i++)
-               RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i));
-
-       for (i = 0; i < 8; i++)
-               RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i));
-
-       for (i = 0; i < 5; i++)
-               RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
-
-       if (dss_has_feature(FEAT_FIR_COEF_V)) {
-               for (i = 0; i < 8; i++)
-                       RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
-       }
-
-       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
-               RR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
-               RR(OVL_BA1_UV(OMAP_DSS_VIDEO1));
-               RR(OVL_FIR2(OMAP_DSS_VIDEO1));
-               RR(OVL_ACCU2_0(OMAP_DSS_VIDEO1));
-               RR(OVL_ACCU2_1(OMAP_DSS_VIDEO1));
-
-               for (i = 0; i < 8; i++)
-                       RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i));
-
-               for (i = 0; i < 8; i++)
-                       RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i));
-
-               for (i = 0; i < 8; i++)
-                       RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i));
-       }
-       if (dss_has_feature(FEAT_ATTR2))
-               RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
-
-       if (dss_has_feature(FEAT_PRELOAD))
-               RR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
-
-       /* VID2 */
-       RR(OVL_BA0(OMAP_DSS_VIDEO2));
-       RR(OVL_BA1(OMAP_DSS_VIDEO2));
-       RR(OVL_POSITION(OMAP_DSS_VIDEO2));
-       RR(OVL_SIZE(OMAP_DSS_VIDEO2));
-       RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
-       RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
-       RR(OVL_ROW_INC(OMAP_DSS_VIDEO2));
-       RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
-       RR(OVL_FIR(OMAP_DSS_VIDEO2));
-       RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
-       RR(OVL_ACCU0(OMAP_DSS_VIDEO2));
-       RR(OVL_ACCU1(OMAP_DSS_VIDEO2));
+       for (i = 0; i < dss_feat_get_num_ovls(); i++) {
+               RR(OVL_BA0(i));
+               RR(OVL_BA1(i));
+               RR(OVL_POSITION(i));
+               RR(OVL_SIZE(i));
+               RR(OVL_ATTRIBUTES(i));
+               RR(OVL_FIFO_THRESHOLD(i));
+               RR(OVL_ROW_INC(i));
+               RR(OVL_PIXEL_INC(i));
+               if (dss_has_feature(FEAT_PRELOAD))
+                       RR(OVL_PRELOAD(i));
+               if (i == OMAP_DSS_GFX) {
+                       RR(OVL_WINDOW_SKIP(i));
+                       RR(OVL_TABLE_BA(i));
+                       continue;
+               }
+               RR(OVL_FIR(i));
+               RR(OVL_PICTURE_SIZE(i));
+               RR(OVL_ACCU0(i));
+               RR(OVL_ACCU1(i));
 
-       for (i = 0; i < 8; i++)
-               RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i));
+               for (j = 0; j < 8; j++)
+                       RR(OVL_FIR_COEF_H(i, j));
 
-       for (i = 0; i < 8; i++)
-               RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i));
+               for (j = 0; j < 8; j++)
+                       RR(OVL_FIR_COEF_HV(i, j));
 
-       for (i = 0; i < 5; i++)
-               RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
+               for (j = 0; j < 5; j++)
+                       RR(OVL_CONV_COEF(i, j));
 
-       if (dss_has_feature(FEAT_FIR_COEF_V)) {
-               for (i = 0; i < 8; i++)
-                       RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
-       }
+               if (dss_has_feature(FEAT_FIR_COEF_V)) {
+                       for (j = 0; j < 8; j++)
+                               RR(OVL_FIR_COEF_V(i, j));
+               }
 
-       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
-               RR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
-               RR(OVL_BA1_UV(OMAP_DSS_VIDEO2));
-               RR(OVL_FIR2(OMAP_DSS_VIDEO2));
-               RR(OVL_ACCU2_0(OMAP_DSS_VIDEO2));
-               RR(OVL_ACCU2_1(OMAP_DSS_VIDEO2));
+               if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+                       RR(OVL_BA0_UV(i));
+                       RR(OVL_BA1_UV(i));
+                       RR(OVL_FIR2(i));
+                       RR(OVL_ACCU2_0(i));
+                       RR(OVL_ACCU2_1(i));
 
-               for (i = 0; i < 8; i++)
-                       RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i));
+                       for (j = 0; j < 8; j++)
+                               RR(OVL_FIR_COEF_H2(i, j));
 
-               for (i = 0; i < 8; i++)
-                       RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i));
+                       for (j = 0; j < 8; j++)
+                               RR(OVL_FIR_COEF_HV2(i, j));
 
-               for (i = 0; i < 8; i++)
-                       RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i));
+                       for (j = 0; j < 8; j++)
+                               RR(OVL_FIR_COEF_V2(i, j));
+               }
+               if (dss_has_feature(FEAT_ATTR2))
+                       RR(OVL_ATTRIBUTES2(i));
        }
-       if (dss_has_feature(FEAT_ATTR2))
-               RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
-
-       if (dss_has_feature(FEAT_PRELOAD))
-               RR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
 
        if (dss_has_feature(FEAT_CORE_CLK_DIV))
                RR(DIVISOR);
@@ -570,13 +420,28 @@ void dispc_runtime_put(void)
        WARN_ON(r < 0);
 }
 
+static inline bool dispc_mgr_is_lcd(enum omap_channel channel)
+{
+       if (channel == OMAP_DSS_CHANNEL_LCD ||
+                       channel == OMAP_DSS_CHANNEL_LCD2)
+               return true;
+       else
+               return false;
+}
+
+static struct omap_dss_device *dispc_mgr_get_device(enum omap_channel channel)
+{
+       struct omap_overlay_manager *mgr =
+               omap_dss_get_overlay_manager(channel);
 
-bool dispc_go_busy(enum omap_channel channel)
+       return mgr ? mgr->device : NULL;
+}
+
+bool dispc_mgr_go_busy(enum omap_channel channel)
 {
        int bit;
 
-       if (channel == OMAP_DSS_CHANNEL_LCD ||
-                       channel == OMAP_DSS_CHANNEL_LCD2)
+       if (dispc_mgr_is_lcd(channel))
                bit = 5; /* GOLCD */
        else
                bit = 6; /* GODIGIT */
@@ -587,13 +452,12 @@ bool dispc_go_busy(enum omap_channel channel)
                return REG_GET(DISPC_CONTROL, bit, bit) == 1;
 }
 
-void dispc_go(enum omap_channel channel)
+void dispc_mgr_go(enum omap_channel channel)
 {
        int bit;
        bool enable_bit, go_bit;
 
-       if (channel == OMAP_DSS_CHANNEL_LCD ||
-                       channel == OMAP_DSS_CHANNEL_LCD2)
+       if (dispc_mgr_is_lcd(channel))
                bit = 0; /* LCDENABLE */
        else
                bit = 1; /* DIGITALENABLE */
@@ -607,8 +471,7 @@ void dispc_go(enum omap_channel channel)
        if (!enable_bit)
                return;
 
-       if (channel == OMAP_DSS_CHANNEL_LCD ||
-                       channel == OMAP_DSS_CHANNEL_LCD2)
+       if (dispc_mgr_is_lcd(channel))
                bit = 5; /* GOLCD */
        else
                bit = 6; /* GODIGIT */
@@ -632,43 +495,44 @@ void dispc_go(enum omap_channel channel)
                REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
 }
 
-static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
+static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value)
 {
        dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
 }
 
-static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
+static void dispc_ovl_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
 {
        dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value);
 }
 
-static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
+static void dispc_ovl_write_firv_reg(enum omap_plane plane, int reg, u32 value)
 {
        dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value);
 }
 
-static void _dispc_write_firh2_reg(enum omap_plane plane, int reg, u32 value)
+static void dispc_ovl_write_firh2_reg(enum omap_plane plane, int reg, u32 value)
 {
        BUG_ON(plane == OMAP_DSS_GFX);
 
        dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value);
 }
 
-static void _dispc_write_firhv2_reg(enum omap_plane plane, int reg, u32 value)
+static void dispc_ovl_write_firhv2_reg(enum omap_plane plane, int reg,
+               u32 value)
 {
        BUG_ON(plane == OMAP_DSS_GFX);
 
        dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
 }
 
-static void _dispc_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
+static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
 {
        BUG_ON(plane == OMAP_DSS_GFX);
 
        dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
 }
 
-static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
+static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup,
                                  int vscaleup, int five_taps,
                                  enum omap_color_component color_comp)
 {
@@ -769,11 +633,11 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
                        | FLD_VAL(v_coef[i].vc2, 31, 24);
 
                if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
-                       _dispc_write_firh_reg(plane, i, h);
-                       _dispc_write_firhv_reg(plane, i, hv);
+                       dispc_ovl_write_firh_reg(plane, i, h);
+                       dispc_ovl_write_firhv_reg(plane, i, hv);
                } else {
-                       _dispc_write_firh2_reg(plane, i, h);
-                       _dispc_write_firhv2_reg(plane, i, hv);
+                       dispc_ovl_write_firh2_reg(plane, i, h);
+                       dispc_ovl_write_firhv2_reg(plane, i, hv);
                }
 
        }
@@ -784,15 +648,16 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
                        v = FLD_VAL(v_coef[i].vc00, 7, 0)
                                | FLD_VAL(v_coef[i].vc22, 15, 8);
                        if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
-                               _dispc_write_firv_reg(plane, i, v);
+                               dispc_ovl_write_firv_reg(plane, i, v);
                        else
-                               _dispc_write_firv2_reg(plane, i, v);
+                               dispc_ovl_write_firv2_reg(plane, i, v);
                }
        }
 }
 
 static void _dispc_setup_color_conv_coef(void)
 {
+       int i;
        const struct color_conv_coef {
                int  ry,  rcr,  rcb,   gy,  gcr,  gcb,   by,  bcr,  bcb;
                int  full_range;
@@ -806,65 +671,54 @@ static void _dispc_setup_color_conv_coef(void)
 
        ct = &ctbl_bt601_5;
 
-       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0),
-               CVAL(ct->rcr, ct->ry));
-       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1),
-               CVAL(ct->gy,  ct->rcb));
-       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2),
-               CVAL(ct->gcb, ct->gcr));
-       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3),
-               CVAL(ct->bcr, ct->by));
-       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4),
-               CVAL(0, ct->bcb));
-
-       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0),
-               CVAL(ct->rcr, ct->ry));
-       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1),
-               CVAL(ct->gy, ct->rcb));
-       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2),
-               CVAL(ct->gcb, ct->gcr));
-       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3),
-               CVAL(ct->bcr, ct->by));
-       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4),
-               CVAL(0, ct->bcb));
+       for (i = 1; i < dss_feat_get_num_ovls(); i++) {
+               dispc_write_reg(DISPC_OVL_CONV_COEF(i, 0),
+                       CVAL(ct->rcr, ct->ry));
+               dispc_write_reg(DISPC_OVL_CONV_COEF(i, 1),
+                       CVAL(ct->gy,  ct->rcb));
+               dispc_write_reg(DISPC_OVL_CONV_COEF(i, 2),
+                       CVAL(ct->gcb, ct->gcr));
+               dispc_write_reg(DISPC_OVL_CONV_COEF(i, 3),
+                       CVAL(ct->bcr, ct->by));
+               dispc_write_reg(DISPC_OVL_CONV_COEF(i, 4),
+                       CVAL(0, ct->bcb));
 
-#undef CVAL
+               REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), ct->full_range,
+                       11, 11);
+       }
 
-       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1),
-               ct->full_range, 11, 11);
-       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2),
-               ct->full_range, 11, 11);
+#undef CVAL
 }
 
 
-static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
+static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr)
 {
        dispc_write_reg(DISPC_OVL_BA0(plane), paddr);
 }
 
-static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
+static void dispc_ovl_set_ba1(enum omap_plane plane, u32 paddr)
 {
        dispc_write_reg(DISPC_OVL_BA1(plane), paddr);
 }
 
-static void _dispc_set_plane_ba0_uv(enum omap_plane plane, u32 paddr)
+static void dispc_ovl_set_ba0_uv(enum omap_plane plane, u32 paddr)
 {
        dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr);
 }
 
-static void _dispc_set_plane_ba1_uv(enum omap_plane plane, u32 paddr)
+static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr)
 {
        dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
 }
 
-static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
+static void dispc_ovl_set_pos(enum omap_plane plane, int x, int y)
 {
        u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
 
        dispc_write_reg(DISPC_OVL_POSITION(plane), val);
 }
 
-static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
+static void dispc_ovl_set_pic_size(enum omap_plane plane, int width, int height)
 {
        u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
 
@@ -874,7 +728,7 @@ static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
                dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
 }
 
-static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
+static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height)
 {
        u32 val;
 
@@ -885,44 +739,61 @@ static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
        dispc_write_reg(DISPC_OVL_SIZE(plane), val);
 }
 
-static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable)
+static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder)
 {
-       if (!dss_has_feature(FEAT_PRE_MULT_ALPHA))
+       struct omap_overlay *ovl = omap_dss_get_overlay(plane);
+
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
                return;
 
-       if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
-               plane == OMAP_DSS_VIDEO1)
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
+}
+
+static void dispc_ovl_enable_zorder_planes(void)
+{
+       int i;
+
+       if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
                return;
 
-       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
+       for (i = 0; i < dss_feat_get_num_ovls(); i++)
+               REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
 }
 
-static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
+static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable)
 {
-       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
+       struct omap_overlay *ovl = omap_dss_get_overlay(plane);
+
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
                return;
 
-       if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
-               plane == OMAP_DSS_VIDEO1)
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
+}
+
+static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
+{
+       static const unsigned shifts[] = { 0, 8, 16, 24, };
+       int shift;
+       struct omap_overlay *ovl = omap_dss_get_overlay(plane);
+
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
                return;
 
-       if (plane == OMAP_DSS_GFX)
-               REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
-       else if (plane == OMAP_DSS_VIDEO2)
-               REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16);
+       shift = shifts[plane];
+       REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift);
 }
 
-static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
+static void dispc_ovl_set_pix_inc(enum omap_plane plane, s32 inc)
 {
        dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc);
 }
 
-static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
+static void dispc_ovl_set_row_inc(enum omap_plane plane, s32 inc)
 {
        dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc);
 }
 
-static void _dispc_set_color_mode(enum omap_plane plane,
+static void dispc_ovl_set_color_mode(enum omap_plane plane,
                enum omap_color_mode color_mode)
 {
        u32 m = 0;
@@ -1003,7 +874,7 @@ static void _dispc_set_color_mode(enum omap_plane plane,
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
 }
 
-void dispc_set_channel_out(enum omap_plane plane,
+static void dispc_ovl_set_channel_out(enum omap_plane plane,
                enum omap_channel channel)
 {
        int shift;
@@ -1016,6 +887,7 @@ void dispc_set_channel_out(enum omap_plane plane,
                break;
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
+       case OMAP_DSS_VIDEO3:
                shift = 16;
                break;
        default:
@@ -1050,24 +922,13 @@ void dispc_set_channel_out(enum omap_plane plane,
        dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
 }
 
-static void dispc_set_burst_size(enum omap_plane plane,
+static void dispc_ovl_set_burst_size(enum omap_plane plane,
                enum omap_burst_size burst_size)
 {
+       static const unsigned shifts[] = { 6, 14, 14, 14, };
        int shift;
 
-       switch (plane) {
-       case OMAP_DSS_GFX:
-               shift = 6;
-               break;
-       case OMAP_DSS_VIDEO1:
-       case OMAP_DSS_VIDEO2:
-               shift = 14;
-               break;
-       default:
-               BUG();
-               return;
-       }
-
+       shift = shifts[plane];
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift);
 }
 
@@ -1078,10 +939,10 @@ static void dispc_configure_burst_sizes(void)
 
        /* Configure burst size always to maximum size */
        for (i = 0; i < omap_dss_get_num_overlays(); ++i)
-               dispc_set_burst_size(i, burst_size);
+               dispc_ovl_set_burst_size(i, burst_size);
 }
 
-u32 dispc_get_burst_size(enum omap_plane plane)
+u32 dispc_ovl_get_burst_size(enum omap_plane plane)
 {
        unsigned unit = dss_feat_get_burst_size_unit();
        /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
@@ -1102,7 +963,7 @@ void dispc_enable_gamma_table(bool enable)
        REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
 }
 
-void dispc_enable_cpr(enum omap_channel channel, bool enable)
+void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
 {
        u16 reg;
 
@@ -1116,12 +977,12 @@ void dispc_enable_cpr(enum omap_channel channel, bool enable)
        REG_FLD_MOD(reg, enable, 15, 15);
 }
 
-void dispc_set_cpr_coef(enum omap_channel channel,
+void dispc_mgr_set_cpr_coef(enum omap_channel channel,
                struct omap_dss_cpr_coefs *coefs)
 {
        u32 coef_r, coef_g, coef_b;
 
-       if (channel != OMAP_DSS_CHANNEL_LCD && channel != OMAP_DSS_CHANNEL_LCD2)
+       if (!dispc_mgr_is_lcd(channel))
                return;
 
        coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
@@ -1136,7 +997,7 @@ void dispc_set_cpr_coef(enum omap_channel channel,
        dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b);
 }
 
-static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
+static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable)
 {
        u32 val;
 
@@ -1147,19 +1008,16 @@ static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
        dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
 }
 
-void dispc_enable_replication(enum omap_plane plane, bool enable)
+static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable)
 {
-       int bit;
-
-       if (plane == OMAP_DSS_GFX)
-               bit = 5;
-       else
-               bit = 10;
+       static const unsigned shifts[] = { 5, 10, 10, 10 };
+       int shift;
 
-       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
+       shift = shifts[plane];
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
 }
 
-void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
+void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
 {
        u32 val;
        BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
@@ -1186,19 +1044,20 @@ static void dispc_read_plane_fifo_sizes(void)
 
        dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
 
-       for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
+       for (plane = 0; plane < dss_feat_get_num_ovls(); ++plane) {
                size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end);
                size *= unit;
                dispc.fifo_size[plane] = size;
        }
 }
 
-u32 dispc_get_plane_fifo_size(enum omap_plane plane)
+u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
 {
        return dispc.fifo_size[plane];
 }
 
-void dispc_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
+static void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low,
+               u32 high)
 {
        u8 hi_start, hi_end, lo_start, lo_end;
        u32 unit;
@@ -1233,7 +1092,7 @@ void dispc_enable_fifomerge(bool enable)
        REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
 }
 
-static void _dispc_set_fir(enum omap_plane plane,
+static void dispc_ovl_set_fir(enum omap_plane plane,
                                int hinc, int vinc,
                                enum omap_color_component color_comp)
 {
@@ -1256,7 +1115,7 @@ static void _dispc_set_fir(enum omap_plane plane,
        }
 }
 
-static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
+static void dispc_ovl_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
 {
        u32 val;
        u8 hor_start, hor_end, vert_start, vert_end;
@@ -1270,7 +1129,7 @@ static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
        dispc_write_reg(DISPC_OVL_ACCU0(plane), val);
 }
 
-static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
+static void dispc_ovl_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
 {
        u32 val;
        u8 hor_start, hor_end, vert_start, vert_end;
@@ -1284,7 +1143,8 @@ static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
        dispc_write_reg(DISPC_OVL_ACCU1(plane), val);
 }
 
-static void _dispc_set_vid_accu2_0(enum omap_plane plane, int haccu, int vaccu)
+static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane, int haccu,
+               int vaccu)
 {
        u32 val;
 
@@ -1292,7 +1152,8 @@ static void _dispc_set_vid_accu2_0(enum omap_plane plane, int haccu, int vaccu)
        dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val);
 }
 
-static void _dispc_set_vid_accu2_1(enum omap_plane plane, int haccu, int vaccu)
+static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane, int haccu,
+               int vaccu)
 {
        u32 val;
 
@@ -1300,7 +1161,7 @@ static void _dispc_set_vid_accu2_1(enum omap_plane plane, int haccu, int vaccu)
        dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val);
 }
 
-static void _dispc_set_scale_param(enum omap_plane plane,
+static void dispc_ovl_set_scale_param(enum omap_plane plane,
                u16 orig_width, u16 orig_height,
                u16 out_width, u16 out_height,
                bool five_taps, u8 rotation,
@@ -1312,15 +1173,16 @@ static void _dispc_set_scale_param(enum omap_plane plane,
        hscaleup = orig_width <= out_width;
        vscaleup = orig_height <= out_height;
 
-       _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps, color_comp);
+       dispc_ovl_set_scale_coef(plane, hscaleup, vscaleup, five_taps,
+                       color_comp);
 
        fir_hinc = 1024 * orig_width / out_width;
        fir_vinc = 1024 * orig_height / out_height;
 
-       _dispc_set_fir(plane, fir_hinc, fir_vinc, color_comp);
+       dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
 }
 
-static void _dispc_set_scaling_common(enum omap_plane plane,
+static void dispc_ovl_set_scaling_common(enum omap_plane plane,
                u16 orig_width, u16 orig_height,
                u16 out_width, u16 out_height,
                bool ilace, bool five_taps,
@@ -1331,7 +1193,7 @@ static void _dispc_set_scaling_common(enum omap_plane plane,
        int accu1 = 0;
        u32 l;
 
-       _dispc_set_scale_param(plane, orig_width, orig_height,
+       dispc_ovl_set_scale_param(plane, orig_width, orig_height,
                                out_width, out_height, five_taps,
                                rotation, DISPC_COLOR_COMPONENT_RGB_Y);
        l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
@@ -1370,11 +1232,11 @@ static void _dispc_set_scaling_common(enum omap_plane plane,
                }
        }
 
-       _dispc_set_vid_accu0(plane, 0, accu0);
-       _dispc_set_vid_accu1(plane, 0, accu1);
+       dispc_ovl_set_vid_accu0(plane, 0, accu0);
+       dispc_ovl_set_vid_accu1(plane, 0, accu1);
 }
 
-static void _dispc_set_scaling_uv(enum omap_plane plane,
+static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
                u16 orig_width, u16 orig_height,
                u16 out_width, u16 out_height,
                bool ilace, bool five_taps,
@@ -1422,7 +1284,7 @@ static void _dispc_set_scaling_uv(enum omap_plane plane,
        if (out_height != orig_height)
                scale_y = true;
 
-       _dispc_set_scale_param(plane, orig_width, orig_height,
+       dispc_ovl_set_scale_param(plane, orig_width, orig_height,
                        out_width, out_height, five_taps,
                                rotation, DISPC_COLOR_COMPONENT_UV);
 
@@ -1433,11 +1295,11 @@ static void _dispc_set_scaling_uv(enum omap_plane plane,
        /* set V scaling */
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
 
-       _dispc_set_vid_accu2_0(plane, 0x80, 0);
-       _dispc_set_vid_accu2_1(plane, 0x80, 0);
+       dispc_ovl_set_vid_accu2_0(plane, 0x80, 0);
+       dispc_ovl_set_vid_accu2_1(plane, 0x80, 0);
 }
 
-static void _dispc_set_scaling(enum omap_plane plane,
+static void dispc_ovl_set_scaling(enum omap_plane plane,
                u16 orig_width, u16 orig_height,
                u16 out_width, u16 out_height,
                bool ilace, bool five_taps,
@@ -1446,14 +1308,14 @@ static void _dispc_set_scaling(enum omap_plane plane,
 {
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       _dispc_set_scaling_common(plane,
+       dispc_ovl_set_scaling_common(plane,
                        orig_width, orig_height,
                        out_width, out_height,
                        ilace, five_taps,
                        fieldmode, color_mode,
                        rotation);
 
-       _dispc_set_scaling_uv(plane,
+       dispc_ovl_set_scaling_uv(plane,
                orig_width, orig_height,
                out_width, out_height,
                ilace, five_taps,
@@ -1461,7 +1323,7 @@ static void _dispc_set_scaling(enum omap_plane plane,
                rotation);
 }
 
-static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
+static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
                bool mirroring, enum omap_color_mode color_mode)
 {
        bool row_repeat = false;
@@ -1789,12 +1651,11 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width,
                enum omap_color_mode color_mode)
 {
        u32 fclk = 0;
-       /* FIXME venc pclk? */
-       u64 tmp, pclk = dispc_pclk_rate(channel);
+       u64 tmp, pclk = dispc_mgr_pclk_rate(channel);
 
        if (height > out_height) {
-               /* FIXME get real display PPL */
-               unsigned int ppl = 800;
+               struct omap_dss_device *dssdev = dispc_mgr_get_device(channel);
+               unsigned int ppl = dssdev->panel.timings.x_res;
 
                tmp = pclk * height * out_width;
                do_div(tmp, 2 * out_height * ppl);
@@ -1846,114 +1707,120 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width,
        else
                vf = 1;
 
-       /* FIXME venc pclk? */
-       return dispc_pclk_rate(channel) * vf * hf;
+       return dispc_mgr_pclk_rate(channel) * vf * hf;
 }
 
-int dispc_setup_plane(enum omap_plane plane,
-               u32 paddr, u16 screen_width,
-               u16 pos_x, u16 pos_y,
-               u16 width, u16 height,
+static int dispc_ovl_calc_scaling(enum omap_plane plane,
+               enum omap_channel channel, u16 width, u16 height,
                u16 out_width, u16 out_height,
-               enum omap_color_mode color_mode,
-               bool ilace,
-               enum omap_dss_rotation_type rotation_type,
-               u8 rotation, bool mirror,
-               u8 global_alpha, u8 pre_mult_alpha,
-               enum omap_channel channel, u32 puv_addr)
-{
-       const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
-       bool five_taps = 0;
-       bool fieldmode = 0;
-       int cconv = 0;
-       unsigned offset0, offset1;
-       s32 row_inc;
-       s32 pix_inc;
-       u16 frame_height = height;
-       unsigned int field_offset = 0;
+               enum omap_color_mode color_mode, bool *five_taps)
+{
+       struct omap_overlay *ovl = omap_dss_get_overlay(plane);
+       const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
+       unsigned long fclk = 0;
 
-       DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
-              "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
-              plane, paddr, screen_width, pos_x, pos_y,
-              width, height,
-              out_width, out_height,
-              ilace, color_mode,
-              rotation, mirror, channel);
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
+               if (width != out_width || height != out_height)
+                       return -EINVAL;
+               else
+                       return 0;
+       }
 
-       if (paddr == 0)
+       if (out_width < width / maxdownscale ||
+                       out_width > width * 8)
                return -EINVAL;
 
-       if (ilace && height == out_height)
-               fieldmode = 1;
+       if (out_height < height / maxdownscale ||
+                       out_height > height * 8)
+               return -EINVAL;
 
-       if (ilace) {
-               if (fieldmode)
-                       height /= 2;
-               pos_y /= 2;
-               out_height /= 2;
+       /* Must use 5-tap filter? */
+       *five_taps = height > out_height * 2;
 
-               DSSDBG("adjusting for ilace: height %d, pos_y %d, "
-                               "out_height %d\n",
-                               height, pos_y, out_height);
+       if (!*five_taps) {
+               fclk = calc_fclk(channel, width, height, out_width,
+                               out_height);
+
+               /* Try 5-tap filter if 3-tap fclk is too high */
+               if (cpu_is_omap34xx() && height > out_height &&
+                               fclk > dispc_fclk_rate())
+                       *five_taps = true;
        }
 
-       if (!dss_feat_color_mode_supported(plane, color_mode))
+       if (width > (2048 >> *five_taps)) {
+               DSSERR("failed to set up scaling, fclk too low\n");
                return -EINVAL;
+       }
 
-       if (plane == OMAP_DSS_GFX) {
-               if (width != out_width || height != out_height)
-                       return -EINVAL;
-       } else {
-               /* video plane */
+       if (*five_taps)
+               fclk = calc_fclk_five_taps(channel, width, height,
+                               out_width, out_height, color_mode);
 
-               unsigned long fclk = 0;
+       DSSDBG("required fclk rate = %lu Hz\n", fclk);
+       DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
 
-               if (out_width < width / maxdownscale ||
-                  out_width > width * 8)
-                       return -EINVAL;
+       if (!fclk || fclk > dispc_fclk_rate()) {
+               DSSERR("failed to set up scaling, "
+                       "required fclk rate = %lu Hz, "
+                       "current fclk rate = %lu Hz\n",
+                       fclk, dispc_fclk_rate());
+               return -EINVAL;
+       }
 
-               if (out_height < height / maxdownscale ||
-                  out_height > height * 8)
-                       return -EINVAL;
+       return 0;
+}
 
-               if (color_mode == OMAP_DSS_COLOR_YUV2 ||
-                       color_mode == OMAP_DSS_COLOR_UYVY ||
-                       color_mode == OMAP_DSS_COLOR_NV12)
-                       cconv = 1;
+int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
+               bool ilace, enum omap_channel channel, bool replication,
+               u32 fifo_low, u32 fifo_high)
+{
+       struct omap_overlay *ovl = omap_dss_get_overlay(plane);
+       bool five_taps = false;
+       bool fieldmode = 0;
+       int r, cconv = 0;
+       unsigned offset0, offset1;
+       s32 row_inc;
+       s32 pix_inc;
+       u16 frame_height = oi->height;
+       unsigned int field_offset = 0;
 
-               /* Must use 5-tap filter? */
-               five_taps = height > out_height * 2;
+       DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
+               "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d "
+               "fifo_low %d fifo high %d\n", plane, oi->paddr, oi->p_uv_addr,
+               oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
+               oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
+               oi->mirror, ilace, channel, replication, fifo_low, fifo_high);
 
-               if (!five_taps) {
-                       fclk = calc_fclk(channel, width, height, out_width,
-                                       out_height);
+       if (oi->paddr == 0)
+               return -EINVAL;
 
-                       /* Try 5-tap filter if 3-tap fclk is too high */
-                       if (cpu_is_omap34xx() && height > out_height &&
-                                       fclk > dispc_fclk_rate())
-                               five_taps = true;
-               }
+       if (ilace && oi->height == oi->out_height)
+               fieldmode = 1;
 
-               if (width > (2048 >> five_taps)) {
-                       DSSERR("failed to set up scaling, fclk too low\n");
-                       return -EINVAL;
-               }
+       if (ilace) {
+               if (fieldmode)
+                       oi->height /= 2;
+               oi->pos_y /= 2;
+               oi->out_height /= 2;
 
-               if (five_taps)
-                       fclk = calc_fclk_five_taps(channel, width, height,
-                                       out_width, out_height, color_mode);
+               DSSDBG("adjusting for ilace: height %d, pos_y %d, "
+                               "out_height %d\n",
+                               oi->height, oi->pos_y, oi->out_height);
+       }
 
-               DSSDBG("required fclk rate = %lu Hz\n", fclk);
-               DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
+       if (!dss_feat_color_mode_supported(plane, oi->color_mode))
+               return -EINVAL;
 
-               if (!fclk || fclk > dispc_fclk_rate()) {
-                       DSSERR("failed to set up scaling, "
-                                       "required fclk rate = %lu Hz, "
-                                       "current fclk rate = %lu Hz\n",
-                                       fclk, dispc_fclk_rate());
-                       return -EINVAL;
-               }
-       }
+       r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height,
+                       oi->out_width, oi->out_height, oi->color_mode,
+                       &five_taps);
+       if (r)
+               return r;
+
+       if (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
+                       oi->color_mode == OMAP_DSS_COLOR_UYVY ||
+                       oi->color_mode == OMAP_DSS_COLOR_NV12)
+               cconv = 1;
 
        if (ilace && !fieldmode) {
                /*
@@ -1963,69 +1830,76 @@ int dispc_setup_plane(enum omap_plane plane,
                 * so the integer part must be added to the base address of the
                 * bottom field.
                 */
-               if (!height || height == out_height)
+               if (!oi->height || oi->height == oi->out_height)
                        field_offset = 0;
                else
-                       field_offset = height / out_height / 2;
+                       field_offset = oi->height / oi->out_height / 2;
        }
 
        /* Fields are independent but interleaved in memory. */
        if (fieldmode)
                field_offset = 1;
 
-       if (rotation_type == OMAP_DSS_ROT_DMA)
-               calc_dma_rotation_offset(rotation, mirror,
-                               screen_width, width, frame_height, color_mode,
-                               fieldmode, field_offset,
+       if (oi->rotation_type == OMAP_DSS_ROT_DMA)
+               calc_dma_rotation_offset(oi->rotation, oi->mirror,
+                               oi->screen_width, oi->width, frame_height,
+                               oi->color_mode, fieldmode, field_offset,
                                &offset0, &offset1, &row_inc, &pix_inc);
        else
-               calc_vrfb_rotation_offset(rotation, mirror,
-                               screen_width, width, frame_height, color_mode,
-                               fieldmode, field_offset,
+               calc_vrfb_rotation_offset(oi->rotation, oi->mirror,
+                               oi->screen_width, oi->width, frame_height,
+                               oi->color_mode, fieldmode, field_offset,
                                &offset0, &offset1, &row_inc, &pix_inc);
 
        DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
                        offset0, offset1, row_inc, pix_inc);
 
-       _dispc_set_color_mode(plane, color_mode);
+       dispc_ovl_set_color_mode(plane, oi->color_mode);
 
-       _dispc_set_plane_ba0(plane, paddr + offset0);
-       _dispc_set_plane_ba1(plane, paddr + offset1);
+       dispc_ovl_set_ba0(plane, oi->paddr + offset0);
+       dispc_ovl_set_ba1(plane, oi->paddr + offset1);
 
-       if (OMAP_DSS_COLOR_NV12 == color_mode) {
-               _dispc_set_plane_ba0_uv(plane, puv_addr + offset0);
-               _dispc_set_plane_ba1_uv(plane, puv_addr + offset1);
+       if (OMAP_DSS_COLOR_NV12 == oi->color_mode) {
+               dispc_ovl_set_ba0_uv(plane, oi->p_uv_addr + offset0);
+               dispc_ovl_set_ba1_uv(plane, oi->p_uv_addr + offset1);
        }
 
 
-       _dispc_set_row_inc(plane, row_inc);
-       _dispc_set_pix_inc(plane, pix_inc);
+       dispc_ovl_set_row_inc(plane, row_inc);
+       dispc_ovl_set_pix_inc(plane, pix_inc);
 
-       DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height,
-                       out_width, out_height);
+       DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width,
+                       oi->height, oi->out_width, oi->out_height);
 
-       _dispc_set_plane_pos(plane, pos_x, pos_y);
+       dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y);
 
-       _dispc_set_pic_size(plane, width, height);
+       dispc_ovl_set_pic_size(plane, oi->width, oi->height);
 
-       if (plane != OMAP_DSS_GFX) {
-               _dispc_set_scaling(plane, width, height,
-                                  out_width, out_height,
+       if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) {
+               dispc_ovl_set_scaling(plane, oi->width, oi->height,
+                                  oi->out_width, oi->out_height,
                                   ilace, five_taps, fieldmode,
-                                  color_mode, rotation);
-               _dispc_set_vid_size(plane, out_width, out_height);
-               _dispc_set_vid_color_conv(plane, cconv);
+                                  oi->color_mode, oi->rotation);
+               dispc_ovl_set_vid_size(plane, oi->out_width, oi->out_height);
+               dispc_ovl_set_vid_color_conv(plane, cconv);
        }
 
-       _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
+       dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror,
+                       oi->color_mode);
+
+       dispc_ovl_set_zorder(plane, oi->zorder);
+       dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha);
+       dispc_ovl_setup_global_alpha(plane, oi->global_alpha);
 
-       _dispc_set_pre_mult_alpha(plane, pre_mult_alpha);
-       _dispc_setup_global_alpha(plane, global_alpha);
+       dispc_ovl_set_channel_out(plane, channel);
+
+       dispc_ovl_enable_replication(plane, replication);
+       dispc_ovl_set_fifo_threshold(plane, fifo_low, fifo_high);
 
        return 0;
 }
 
-int dispc_enable_plane(enum omap_plane plane, bool enable)
+int dispc_ovl_enable(enum omap_plane plane, bool enable)
 {
        DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
 
@@ -2048,7 +1922,7 @@ static void _enable_lcd_out(enum omap_channel channel, bool enable)
                REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
 }
 
-static void dispc_enable_lcd_out(enum omap_channel channel, bool enable)
+static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable)
 {
        struct completion frame_done_completion;
        bool is_on;
@@ -2095,14 +1969,19 @@ static void _enable_digit_out(bool enable)
        REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
 }
 
-static void dispc_enable_digit_out(bool enable)
+static void dispc_mgr_enable_digit_out(bool enable)
 {
        struct completion frame_done_completion;
-       int r;
+       enum dss_hdmi_venc_clk_source_select src;
+       int r, i;
+       u32 irq_mask;
+       int num_irqs;
 
        if (REG_GET(DISPC_CONTROL, 1, 1) == enable)
                return;
 
+       src = dss_get_hdmi_venc_clk_source();
+
        if (enable) {
                unsigned long flags;
                /* When we enable digit output, we'll get an extra digit
@@ -2119,43 +1998,47 @@ static void dispc_enable_digit_out(bool enable)
         * wait for the extra sync losts */
        init_completion(&frame_done_completion);
 
+       if (src == DSS_HDMI_M_PCLK && enable == false) {
+               irq_mask = DISPC_IRQ_FRAMEDONETV;
+               num_irqs = 1;
+       } else {
+               irq_mask = DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD;
+               /* XXX I understand from TRM that we should only wait for the
+                * current field to complete. But it seems we have to wait for
+                * both fields */
+               num_irqs = 2;
+       }
+
        r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion,
-                       DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
+                       irq_mask);
        if (r)
-               DSSERR("failed to register EVSYNC isr\n");
+               DSSERR("failed to register %x isr\n", irq_mask);
 
        _enable_digit_out(enable);
 
-       /* XXX I understand from TRM that we should only wait for the
-        * current field to complete. But it seems we have to wait
-        * for both fields */
-       if (!wait_for_completion_timeout(&frame_done_completion,
-                               msecs_to_jiffies(100)))
-               DSSERR("timeout waiting for EVSYNC\n");
-
-       if (!wait_for_completion_timeout(&frame_done_completion,
-                               msecs_to_jiffies(100)))
-               DSSERR("timeout waiting for EVSYNC\n");
+       for (i = 0; i < num_irqs; ++i) {
+               if (!wait_for_completion_timeout(&frame_done_completion,
+                                       msecs_to_jiffies(100)))
+                       DSSERR("timeout waiting for digit out to %s\n",
+                                       enable ? "start" : "stop");
+       }
 
-       r = omap_dispc_unregister_isr(dispc_disable_isr,
-                       &frame_done_completion,
-                       DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
+       r = omap_dispc_unregister_isr(dispc_disable_isr, &frame_done_completion,
+                       irq_mask);
        if (r)
-               DSSERR("failed to unregister EVSYNC isr\n");
+               DSSERR("failed to unregister %x isr\n", irq_mask);
 
        if (enable) {
                unsigned long flags;
                spin_lock_irqsave(&dispc.irq_lock, flags);
-               dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
-               if (dss_has_feature(FEAT_MGR_LCD2))
-                       dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
+               dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST_DIGIT;
                dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
                _omap_dispc_set_irqs();
                spin_unlock_irqrestore(&dispc.irq_lock, flags);
        }
 }
 
-bool dispc_is_channel_enabled(enum omap_channel channel)
+bool dispc_mgr_is_enabled(enum omap_channel channel)
 {
        if (channel == OMAP_DSS_CHANNEL_LCD)
                return !!REG_GET(DISPC_CONTROL, 0, 0);
@@ -2167,13 +2050,12 @@ bool dispc_is_channel_enabled(enum omap_channel channel)
                BUG();
 }
 
-void dispc_enable_channel(enum omap_channel channel, bool enable)
+void dispc_mgr_enable(enum omap_channel channel, bool enable)
 {
-       if (channel == OMAP_DSS_CHANNEL_LCD ||
-                       channel == OMAP_DSS_CHANNEL_LCD2)
-               dispc_enable_lcd_out(channel, enable);
+       if (dispc_mgr_is_lcd(channel))
+               dispc_mgr_enable_lcd_out(channel, enable);
        else if (channel == OMAP_DSS_CHANNEL_DIGIT)
-               dispc_enable_digit_out(enable);
+               dispc_mgr_enable_digit_out(enable);
        else
                BUG();
 }
@@ -2202,7 +2084,7 @@ void dispc_pck_free_enable(bool enable)
        REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
 }
 
-void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable)
+void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable)
 {
        if (channel == OMAP_DSS_CHANNEL_LCD2)
                REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16);
@@ -2211,7 +2093,7 @@ void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable)
 }
 
 
-void dispc_set_lcd_display_type(enum omap_channel channel,
+void dispc_mgr_set_lcd_display_type(enum omap_channel channel,
                enum omap_lcd_display_type type)
 {
        int mode;
@@ -2242,12 +2124,12 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode)
 }
 
 
-void dispc_set_default_color(enum omap_channel channel, u32 color)
+void dispc_mgr_set_default_color(enum omap_channel channel, u32 color)
 {
        dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
 }
 
-u32 dispc_get_default_color(enum omap_channel channel)
+u32 dispc_mgr_get_default_color(enum omap_channel channel)
 {
        u32 l;
 
@@ -2260,7 +2142,7 @@ u32 dispc_get_default_color(enum omap_channel channel)
        return l;
 }
 
-void dispc_set_trans_key(enum omap_channel ch,
+void dispc_mgr_set_trans_key(enum omap_channel ch,
                enum omap_dss_trans_key_type type,
                u32 trans_key)
 {
@@ -2274,7 +2156,7 @@ void dispc_set_trans_key(enum omap_channel ch,
        dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
 }
 
-void dispc_get_trans_key(enum omap_channel ch,
+void dispc_mgr_get_trans_key(enum omap_channel ch,
                enum omap_dss_trans_key_type *type,
                u32 *trans_key)
 {
@@ -2293,7 +2175,7 @@ void dispc_get_trans_key(enum omap_channel ch,
                *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch));
 }
 
-void dispc_enable_trans_key(enum omap_channel ch, bool enable)
+void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
 {
        if (ch == OMAP_DSS_CHANNEL_LCD)
                REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
@@ -2302,39 +2184,36 @@ void dispc_enable_trans_key(enum omap_channel ch, bool enable)
        else /* OMAP_DSS_CHANNEL_LCD2 */
                REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10);
 }
-void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
+
+void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable)
 {
-       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
+       if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
                return;
 
        if (ch == OMAP_DSS_CHANNEL_LCD)
                REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
                REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
-       else /* OMAP_DSS_CHANNEL_LCD2 */
-               REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18);
 }
-bool dispc_alpha_blending_enabled(enum omap_channel ch)
+
+bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch)
 {
        bool enabled;
 
-       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
+       if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
                return false;
 
        if (ch == OMAP_DSS_CHANNEL_LCD)
                enabled = REG_GET(DISPC_CONFIG, 18, 18);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
                enabled = REG_GET(DISPC_CONFIG, 19, 19);
-       else if (ch == OMAP_DSS_CHANNEL_LCD2)
-               enabled = REG_GET(DISPC_CONFIG2, 18, 18);
        else
                BUG();
 
        return enabled;
 }
 
-
-bool dispc_trans_key_enabled(enum omap_channel ch)
+bool dispc_mgr_trans_key_enabled(enum omap_channel ch)
 {
        bool enabled;
 
@@ -2351,7 +2230,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
 }
 
 
-void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
+void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
 {
        int code;
 
@@ -2379,46 +2258,41 @@ void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
                REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
 }
 
-void dispc_set_parallel_interface_mode(enum omap_channel channel,
-               enum omap_parallel_interface_mode mode)
+void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode)
 {
        u32 l;
-       int stallmode;
-       int gpout0 = 1;
-       int gpout1;
+       int gpout0, gpout1;
 
        switch (mode) {
-       case OMAP_DSS_PARALLELMODE_BYPASS:
-               stallmode = 0;
-               gpout1 = 1;
+       case DSS_IO_PAD_MODE_RESET:
+               gpout0 = 0;
+               gpout1 = 0;
                break;
-
-       case OMAP_DSS_PARALLELMODE_RFBI:
-               stallmode = 1;
+       case DSS_IO_PAD_MODE_RFBI:
+               gpout0 = 1;
                gpout1 = 0;
                break;
-
-       case OMAP_DSS_PARALLELMODE_DSI:
-               stallmode = 1;
+       case DSS_IO_PAD_MODE_BYPASS:
+               gpout0 = 1;
                gpout1 = 1;
                break;
-
        default:
                BUG();
                return;
        }
 
-       if (channel == OMAP_DSS_CHANNEL_LCD2) {
-               l = dispc_read_reg(DISPC_CONTROL2);
-               l = FLD_MOD(l, stallmode, 11, 11);
-               dispc_write_reg(DISPC_CONTROL2, l);
-       } else {
-               l = dispc_read_reg(DISPC_CONTROL);
-               l = FLD_MOD(l, stallmode, 11, 11);
-               l = FLD_MOD(l, gpout0, 15, 15);
-               l = FLD_MOD(l, gpout1, 16, 16);
-               dispc_write_reg(DISPC_CONTROL, l);
-       }
+       l = dispc_read_reg(DISPC_CONTROL);
+       l = FLD_MOD(l, gpout0, 15, 15);
+       l = FLD_MOD(l, gpout1, 16, 16);
+       dispc_write_reg(DISPC_CONTROL, l);
+}
+
+void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable)
+{
+       if (channel == OMAP_DSS_CHANNEL_LCD2)
+               REG_FLD_MOD(DISPC_CONTROL2, enable, 11, 11);
+       else
+               REG_FLD_MOD(DISPC_CONTROL, enable, 11, 11);
 }
 
 static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
@@ -2452,7 +2326,7 @@ bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
                        timings->vfp, timings->vbp);
 }
 
-static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw,
+static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
                int hfp, int hbp, int vsw, int vfp, int vbp)
 {
        u32 timing_h, timing_v;
@@ -2476,7 +2350,7 @@ static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw,
 }
 
 /* change name to mode? */
-void dispc_set_lcd_timings(enum omap_channel channel,
+void dispc_mgr_set_lcd_timings(enum omap_channel channel,
                struct omap_video_timings *timings)
 {
        unsigned xtot, ytot;
@@ -2487,11 +2361,11 @@ void dispc_set_lcd_timings(enum omap_channel channel,
                                timings->vfp, timings->vbp))
                BUG();
 
-       _dispc_set_lcd_timings(channel, timings->hsw, timings->hfp,
+       _dispc_mgr_set_lcd_timings(channel, timings->hsw, timings->hfp,
                        timings->hbp, timings->vsw, timings->vfp,
                        timings->vbp);
 
-       dispc_set_lcd_size(channel, timings->x_res, timings->y_res);
+       dispc_mgr_set_lcd_size(channel, timings->x_res, timings->y_res);
 
        xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
        ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
@@ -2509,17 +2383,17 @@ void dispc_set_lcd_timings(enum omap_channel channel,
        DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
 }
 
-static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
+static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
                u16 pck_div)
 {
        BUG_ON(lck_div < 1);
-       BUG_ON(pck_div < 2);
+       BUG_ON(pck_div < 1);
 
        dispc_write_reg(DISPC_DIVISORo(channel),
                        FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
 }
 
-static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div,
+static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
                int *pck_div)
 {
        u32 l;
@@ -2552,7 +2426,7 @@ unsigned long dispc_fclk_rate(void)
        return r;
 }
 
-unsigned long dispc_lclk_rate(enum omap_channel channel)
+unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
 {
        struct platform_device *dsidev;
        int lcd;
@@ -2582,19 +2456,34 @@ unsigned long dispc_lclk_rate(enum omap_channel channel)
        return r / lcd;
 }
 
-unsigned long dispc_pclk_rate(enum omap_channel channel)
+unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
 {
-       int pcd;
        unsigned long r;
-       u32 l;
 
-       l = dispc_read_reg(DISPC_DIVISORo(channel));
+       if (dispc_mgr_is_lcd(channel)) {
+               int pcd;
+               u32 l;
 
-       pcd = FLD_GET(l, 7, 0);
+               l = dispc_read_reg(DISPC_DIVISORo(channel));
 
-       r = dispc_lclk_rate(channel);
+               pcd = FLD_GET(l, 7, 0);
 
-       return r / pcd;
+               r = dispc_mgr_lclk_rate(channel);
+
+               return r / pcd;
+       } else {
+               struct omap_dss_device *dssdev =
+                       dispc_mgr_get_device(channel);
+
+               switch (dssdev->type) {
+               case OMAP_DISPLAY_TYPE_VENC:
+                       return venc_get_pixel_clock();
+               case OMAP_DISPLAY_TYPE_HDMI:
+                       return hdmi_get_pixel_clock();
+               default:
+                       BUG();
+               }
+       }
 }
 
 void dispc_dump_clocks(struct seq_file *s)
@@ -2631,12 +2520,12 @@ void dispc_dump_clocks(struct seq_file *s)
                dss_get_generic_clk_source_name(lcd_clk_src),
                dss_feat_get_clk_source_name(lcd_clk_src));
 
-       dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd);
+       dispc_mgr_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd);
 
        seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
-                       dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd);
+                       dispc_mgr_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd);
        seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
-                       dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd);
+                       dispc_mgr_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd);
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                seq_printf(s, "- LCD2 -\n");
 
@@ -2646,12 +2535,12 @@ void dispc_dump_clocks(struct seq_file *s)
                        dss_get_generic_clk_source_name(lcd_clk_src),
                        dss_feat_get_clk_source_name(lcd_clk_src));
 
-               dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd);
+               dispc_mgr_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd);
 
                seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
-                               dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd);
+                               dispc_mgr_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd);
                seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
-                               dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd);
+                               dispc_mgr_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd);
        }
 
        dispc_runtime_put();
@@ -2692,6 +2581,10 @@ void dispc_dump_irqs(struct seq_file *s)
        PIS(VID1_END_WIN);
        PIS(VID2_FIFO_UNDERFLOW);
        PIS(VID2_END_WIN);
+       if (dss_feat_get_num_ovls() > 3) {
+               PIS(VID3_FIFO_UNDERFLOW);
+               PIS(VID3_END_WIN);
+       }
        PIS(SYNC_LOST);
        PIS(SYNC_LOST_DIGIT);
        PIS(WAKEUP);
@@ -2707,11 +2600,26 @@ void dispc_dump_irqs(struct seq_file *s)
 
 void dispc_dump_regs(struct seq_file *s)
 {
+       int i, j;
+       const char *mgr_names[] = {
+               [OMAP_DSS_CHANNEL_LCD]          = "LCD",
+               [OMAP_DSS_CHANNEL_DIGIT]        = "TV",
+               [OMAP_DSS_CHANNEL_LCD2]         = "LCD2",
+       };
+       const char *ovl_names[] = {
+               [OMAP_DSS_GFX]          = "GFX",
+               [OMAP_DSS_VIDEO1]       = "VID1",
+               [OMAP_DSS_VIDEO2]       = "VID2",
+               [OMAP_DSS_VIDEO3]       = "VID3",
+       };
+       const char **p_names;
+
 #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
 
        if (dispc_runtime_get())
                return;
 
+       /* DISPC common registers */
        DUMPREG(DISPC_REVISION);
        DUMPREG(DISPC_SYSCONFIG);
        DUMPREG(DISPC_SYSSTATUS);
@@ -2720,247 +2628,139 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_CONTROL);
        DUMPREG(DISPC_CONFIG);
        DUMPREG(DISPC_CAPABLE);
-       DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT));
-       DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT));
        DUMPREG(DISPC_LINE_STATUS);
        DUMPREG(DISPC_LINE_NUMBER);
-       DUMPREG(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD));
-       if (dss_has_feature(FEAT_GLOBAL_ALPHA))
+       if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
+                       dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
                DUMPREG(DISPC_GLOBAL_ALPHA);
-       DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
-       DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                DUMPREG(DISPC_CONTROL2);
                DUMPREG(DISPC_CONFIG2);
-               DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2));
-               DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2));
-               DUMPREG(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD2));
-               DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD2));
-               DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD2));
-               DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD2));
-               DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD2));
-       }
-
-       DUMPREG(DISPC_OVL_BA0(OMAP_DSS_GFX));
-       DUMPREG(DISPC_OVL_BA1(OMAP_DSS_GFX));
-       DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_GFX));
-       DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_GFX));
-       DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_GFX));
-       DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_GFX));
-       DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_GFX));
-       DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_GFX));
-       DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_GFX));
-       DUMPREG(DISPC_OVL_WINDOW_SKIP(OMAP_DSS_GFX));
-       DUMPREG(DISPC_OVL_TABLE_BA(OMAP_DSS_GFX));
-
-       DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
-
-       if (dss_has_feature(FEAT_CPR)) {
-               DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
-               DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
-               DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
        }
-       if (dss_has_feature(FEAT_MGR_LCD2)) {
-               DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
-               DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
-               DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
+
+#undef DUMPREG
+
+#define DISPC_REG(i, name) name(i)
+#define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
+       48 - strlen(#r) - strlen(p_names[i]), " ", \
+       dispc_read_reg(DISPC_REG(i, r)))
+
+       p_names = mgr_names;
+
+       /* DISPC channel specific registers */
+       for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
+               DUMPREG(i, DISPC_DEFAULT_COLOR);
+               DUMPREG(i, DISPC_TRANS_COLOR);
+               DUMPREG(i, DISPC_SIZE_MGR);
+
+               if (i == OMAP_DSS_CHANNEL_DIGIT)
+                       continue;
+
+               DUMPREG(i, DISPC_DEFAULT_COLOR);
+               DUMPREG(i, DISPC_TRANS_COLOR);
+               DUMPREG(i, DISPC_TIMING_H);
+               DUMPREG(i, DISPC_TIMING_V);
+               DUMPREG(i, DISPC_POL_FREQ);
+               DUMPREG(i, DISPC_DIVISORo);
+               DUMPREG(i, DISPC_SIZE_MGR);
+
+               DUMPREG(i, DISPC_DATA_CYCLE1);
+               DUMPREG(i, DISPC_DATA_CYCLE2);
+               DUMPREG(i, DISPC_DATA_CYCLE3);
 
                if (dss_has_feature(FEAT_CPR)) {
-                       DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
-                       DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
-                       DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+                       DUMPREG(i, DISPC_CPR_COEF_R);
+                       DUMPREG(i, DISPC_CPR_COEF_G);
+                       DUMPREG(i, DISPC_CPR_COEF_B);
+               }
+       }
+
+       p_names = ovl_names;
+
+       for (i = 0; i < dss_feat_get_num_ovls(); i++) {
+               DUMPREG(i, DISPC_OVL_BA0);
+               DUMPREG(i, DISPC_OVL_BA1);
+               DUMPREG(i, DISPC_OVL_POSITION);
+               DUMPREG(i, DISPC_OVL_SIZE);
+               DUMPREG(i, DISPC_OVL_ATTRIBUTES);
+               DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
+               DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
+               DUMPREG(i, DISPC_OVL_ROW_INC);
+               DUMPREG(i, DISPC_OVL_PIXEL_INC);
+               if (dss_has_feature(FEAT_PRELOAD))
+                       DUMPREG(i, DISPC_OVL_PRELOAD);
+
+               if (i == OMAP_DSS_GFX) {
+                       DUMPREG(i, DISPC_OVL_WINDOW_SKIP);
+                       DUMPREG(i, DISPC_OVL_TABLE_BA);
+                       continue;
+               }
+
+               DUMPREG(i, DISPC_OVL_FIR);
+               DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
+               DUMPREG(i, DISPC_OVL_ACCU0);
+               DUMPREG(i, DISPC_OVL_ACCU1);
+               if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+                       DUMPREG(i, DISPC_OVL_BA0_UV);
+                       DUMPREG(i, DISPC_OVL_BA1_UV);
+                       DUMPREG(i, DISPC_OVL_FIR2);
+                       DUMPREG(i, DISPC_OVL_ACCU2_0);
+                       DUMPREG(i, DISPC_OVL_ACCU2_1);
                }
+               if (dss_has_feature(FEAT_ATTR2))
+                       DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
+               if (dss_has_feature(FEAT_PRELOAD))
+                       DUMPREG(i, DISPC_OVL_PRELOAD);
        }
 
-       if (dss_has_feature(FEAT_PRELOAD))
-               DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX));
-
-       DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO1));
-
-       DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO2));
-       DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO2));
-       DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO2));
-       DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO2));
-       DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
-       DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
-       DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO2));
-       DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO2));
-       DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
-       DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO2));
-       DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
-       DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO2));
-       DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO2));
-
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 0));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 1));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 2));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 3));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 4));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 5));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 6));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 7));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 0));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 1));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 2));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 3));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 4));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 5));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 6));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 7));
-       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0));
-       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1));
-       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2));
-       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3));
-       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4));
-       if (dss_has_feature(FEAT_FIR_COEF_V)) {
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7));
-       }
-
-       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
-               DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1));
-               DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO1));
-               DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO1));
-               DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO1));
-               DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO1));
-
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 0));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 1));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 2));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 3));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 4));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 5));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 6));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 7));
-
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 0));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 1));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 2));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 3));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 4));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 5));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 6));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 7));
-
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 0));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 1));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 2));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 3));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 4));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 5));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 6));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 7));
-       }
-       if (dss_has_feature(FEAT_ATTR2))
-               DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
-
-
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 0));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 1));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 2));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 3));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 4));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 5));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 6));
-       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 7));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 0));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 1));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 2));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 3));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 4));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 5));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 6));
-       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 7));
-       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0));
-       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1));
-       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2));
-       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3));
-       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4));
-
-       if (dss_has_feature(FEAT_FIR_COEF_V)) {
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6));
-               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7));
-       }
-
-       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
-               DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2));
-               DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO2));
-               DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO2));
-               DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO2));
-               DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO2));
-
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 0));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 1));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 2));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 3));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 4));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 5));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 6));
-               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 7));
-
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 0));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 1));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 2));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 3));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 4));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 5));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 6));
-               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 7));
-
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 0));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 1));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 2));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 3));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 4));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 5));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 6));
-               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 7));
-       }
-       if (dss_has_feature(FEAT_ATTR2))
-               DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
-
-       if (dss_has_feature(FEAT_PRELOAD)) {
-               DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1));
-               DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2));
+#undef DISPC_REG
+#undef DUMPREG
+
+#define DISPC_REG(plane, name, i) name(plane, i)
+#define DUMPREG(plane, name, i) \
+       seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
+       46 - strlen(#name) - strlen(p_names[plane]), " ", \
+       dispc_read_reg(DISPC_REG(plane, name, i)))
+
+       /* Video pipeline coefficient registers */
+
+       /* start from OMAP_DSS_VIDEO1 */
+       for (i = 1; i < dss_feat_get_num_ovls(); i++) {
+               for (j = 0; j < 8; j++)
+                       DUMPREG(i, DISPC_OVL_FIR_COEF_H, j);
+
+               for (j = 0; j < 8; j++)
+                       DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j);
+
+               for (j = 0; j < 5; j++)
+                       DUMPREG(i, DISPC_OVL_CONV_COEF, j);
+
+               if (dss_has_feature(FEAT_FIR_COEF_V)) {
+                       for (j = 0; j < 8; j++)
+                               DUMPREG(i, DISPC_OVL_FIR_COEF_V, j);
+               }
+
+               if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+                       for (j = 0; j < 8; j++)
+                               DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j);
+
+                       for (j = 0; j < 8; j++)
+                               DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j);
+
+                       for (j = 0; j < 8; j++)
+                               DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j);
+               }
        }
 
        dispc_runtime_put();
+
+#undef DISPC_REG
 #undef DUMPREG
 }
 
-static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf,
-               bool ieo, bool ipc, bool ihs, bool ivs, u8 acbi, u8 acb)
+static void _dispc_mgr_set_pol_freq(enum omap_channel channel, bool onoff,
+               bool rf, bool ieo, bool ipc, bool ihs, bool ivs, u8 acbi,
+               u8 acb)
 {
        u32 l = 0;
 
@@ -2979,10 +2779,10 @@ static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf,
        dispc_write_reg(DISPC_POL_FREQ(channel), l);
 }
 
-void dispc_set_pol_freq(enum omap_channel channel,
+void dispc_mgr_set_pol_freq(enum omap_channel channel,
                enum omap_panel_config config, u8 acbi, u8 acb)
 {
-       _dispc_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0,
+       _dispc_mgr_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0,
                        (config & OMAP_DSS_LCD_RF) != 0,
                        (config & OMAP_DSS_LCD_IEO) != 0,
                        (config & OMAP_DSS_LCD_IPC) != 0,
@@ -2995,11 +2795,17 @@ void dispc_set_pol_freq(enum omap_channel channel,
 void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
                struct dispc_clock_info *cinfo)
 {
-       u16 pcd_min = is_tft ? 2 : 3;
+       u16 pcd_min, pcd_max;
        unsigned long best_pck;
        u16 best_ld, cur_ld;
        u16 best_pd, cur_pd;
 
+       pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
+       pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
+
+       if (!is_tft)
+               pcd_min = 3;
+
        best_pck = 0;
        best_ld = 0;
        best_pd = 0;
@@ -3007,7 +2813,7 @@ void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
        for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
                unsigned long lck = fck / cur_ld;
 
-               for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) {
+               for (cur_pd = pcd_min; cur_pd <= pcd_max; ++cur_pd) {
                        unsigned long pck = lck / cur_pd;
                        long old_delta = abs(best_pck - req_pck);
                        long new_delta = abs(pck - req_pck);
@@ -3042,7 +2848,7 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
 {
        if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
                return -EINVAL;
-       if (cinfo->pck_div < 2 || cinfo->pck_div > 255)
+       if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
                return -EINVAL;
 
        cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
@@ -3051,18 +2857,18 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
        return 0;
 }
 
-int dispc_set_clock_div(enum omap_channel channel,
+int dispc_mgr_set_clock_div(enum omap_channel channel,
                struct dispc_clock_info *cinfo)
 {
        DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
        DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
 
-       dispc_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
+       dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
 
        return 0;
 }
 
-int dispc_get_clock_div(enum omap_channel channel,
+int dispc_mgr_get_clock_div(enum omap_channel channel,
                struct dispc_clock_info *cinfo)
 {
        unsigned long fck;
@@ -3207,6 +3013,8 @@ static void print_irq_status(u32 status)
        PIS(OCP_ERR);
        PIS(VID1_FIFO_UNDERFLOW);
        PIS(VID2_FIFO_UNDERFLOW);
+       if (dss_feat_get_num_ovls() > 3)
+               PIS(VID3_FIFO_UNDERFLOW);
        PIS(SYNC_LOST);
        PIS(SYNC_LOST_DIGIT);
        if (dss_has_feature(FEAT_MGR_LCD2))
@@ -3300,178 +3108,72 @@ static void dispc_error_worker(struct work_struct *work)
        int i;
        u32 errors;
        unsigned long flags;
+       static const unsigned fifo_underflow_bits[] = {
+               DISPC_IRQ_GFX_FIFO_UNDERFLOW,
+               DISPC_IRQ_VID1_FIFO_UNDERFLOW,
+               DISPC_IRQ_VID2_FIFO_UNDERFLOW,
+               DISPC_IRQ_VID3_FIFO_UNDERFLOW,
+       };
+
+       static const unsigned sync_lost_bits[] = {
+               DISPC_IRQ_SYNC_LOST,
+               DISPC_IRQ_SYNC_LOST_DIGIT,
+               DISPC_IRQ_SYNC_LOST2,
+       };
 
        spin_lock_irqsave(&dispc.irq_lock, flags);
        errors = dispc.error_irqs;
        dispc.error_irqs = 0;
        spin_unlock_irqrestore(&dispc.irq_lock, flags);
 
-       if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) {
-               DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n");
-               for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
-                       struct omap_overlay *ovl;
-                       ovl = omap_dss_get_overlay(i);
-
-                       if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
-                               continue;
-
-                       if (ovl->id == 0) {
-                               dispc_enable_plane(ovl->id, 0);
-                               dispc_go(ovl->manager->id);
-                               mdelay(50);
-                               break;
-                       }
-               }
-       }
-
-       if (errors & DISPC_IRQ_VID1_FIFO_UNDERFLOW) {
-               DSSERR("VID1_FIFO_UNDERFLOW, disabling VID1\n");
-               for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
-                       struct omap_overlay *ovl;
-                       ovl = omap_dss_get_overlay(i);
-
-                       if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
-                               continue;
-
-                       if (ovl->id == 1) {
-                               dispc_enable_plane(ovl->id, 0);
-                               dispc_go(ovl->manager->id);
-                               mdelay(50);
-                               break;
-                       }
-               }
-       }
-
-       if (errors & DISPC_IRQ_VID2_FIFO_UNDERFLOW) {
-               DSSERR("VID2_FIFO_UNDERFLOW, disabling VID2\n");
-               for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
-                       struct omap_overlay *ovl;
-                       ovl = omap_dss_get_overlay(i);
-
-                       if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
-                               continue;
+       dispc_runtime_get();
 
-                       if (ovl->id == 2) {
-                               dispc_enable_plane(ovl->id, 0);
-                               dispc_go(ovl->manager->id);
-                               mdelay(50);
-                               break;
-                       }
-               }
-       }
-
-       if (errors & DISPC_IRQ_SYNC_LOST) {
-               struct omap_overlay_manager *manager = NULL;
-               bool enable = false;
+       for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+               struct omap_overlay *ovl;
+               unsigned bit;
 
-               DSSERR("SYNC_LOST, disabling LCD\n");
+               ovl = omap_dss_get_overlay(i);
+               bit = fifo_underflow_bits[i];
 
-               for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
-                       struct omap_overlay_manager *mgr;
-                       mgr = omap_dss_get_overlay_manager(i);
-
-                       if (mgr->id == OMAP_DSS_CHANNEL_LCD) {
-                               manager = mgr;
-                               enable = mgr->device->state ==
-                                               OMAP_DSS_DISPLAY_ACTIVE;
-                               mgr->device->driver->disable(mgr->device);
-                               break;
-                       }
-               }
-
-               if (manager) {
-                       struct omap_dss_device *dssdev = manager->device;
-                       for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
-                               struct omap_overlay *ovl;
-                               ovl = omap_dss_get_overlay(i);
-
-                               if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
-                                       continue;
-
-                               if (ovl->id != 0 && ovl->manager == manager)
-                                       dispc_enable_plane(ovl->id, 0);
-                       }
-
-                       dispc_go(manager->id);
+               if (bit & errors) {
+                       DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
+                                       ovl->name);
+                       dispc_ovl_enable(ovl->id, false);
+                       dispc_mgr_go(ovl->manager->id);
                        mdelay(50);
-                       if (enable)
-                               dssdev->driver->enable(dssdev);
                }
        }
 
-       if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) {
-               struct omap_overlay_manager *manager = NULL;
-               bool enable = false;
+       for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
+               struct omap_overlay_manager *mgr;
+               unsigned bit;
 
-               DSSERR("SYNC_LOST_DIGIT, disabling TV\n");
+               mgr = omap_dss_get_overlay_manager(i);
+               bit = sync_lost_bits[i];
 
-               for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
-                       struct omap_overlay_manager *mgr;
-                       mgr = omap_dss_get_overlay_manager(i);
+               if (bit & errors) {
+                       struct omap_dss_device *dssdev = mgr->device;
+                       bool enable;
 
-                       if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) {
-                               manager = mgr;
-                               enable = mgr->device->state ==
-                                               OMAP_DSS_DISPLAY_ACTIVE;
-                               mgr->device->driver->disable(mgr->device);
-                               break;
-                       }
-               }
+                       DSSERR("SYNC_LOST on channel %s, restarting the output "
+                                       "with video overlays disabled\n",
+                                       mgr->name);
 
-               if (manager) {
-                       struct omap_dss_device *dssdev = manager->device;
-                       for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
-                               struct omap_overlay *ovl;
-                               ovl = omap_dss_get_overlay(i);
-
-                               if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
-                                       continue;
-
-                               if (ovl->id != 0 && ovl->manager == manager)
-                                       dispc_enable_plane(ovl->id, 0);
-                       }
+                       enable = dssdev->state == OMAP_DSS_DISPLAY_ACTIVE;
+                       dssdev->driver->disable(dssdev);
 
-                       dispc_go(manager->id);
-                       mdelay(50);
-                       if (enable)
-                               dssdev->driver->enable(dssdev);
-               }
-       }
-
-       if (errors & DISPC_IRQ_SYNC_LOST2) {
-               struct omap_overlay_manager *manager = NULL;
-               bool enable = false;
-
-               DSSERR("SYNC_LOST for LCD2, disabling LCD2\n");
-
-               for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
-                       struct omap_overlay_manager *mgr;
-                       mgr = omap_dss_get_overlay_manager(i);
-
-                       if (mgr->id == OMAP_DSS_CHANNEL_LCD2) {
-                               manager = mgr;
-                               enable = mgr->device->state ==
-                                               OMAP_DSS_DISPLAY_ACTIVE;
-                               mgr->device->driver->disable(mgr->device);
-                               break;
-                       }
-               }
-
-               if (manager) {
-                       struct omap_dss_device *dssdev = manager->device;
                        for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
                                struct omap_overlay *ovl;
                                ovl = omap_dss_get_overlay(i);
 
-                               if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
-                                       continue;
-
-                               if (ovl->id != 0 && ovl->manager == manager)
-                                       dispc_enable_plane(ovl->id, 0);
+                               if (ovl->id != OMAP_DSS_GFX &&
+                                               ovl->manager == mgr)
+                                       dispc_ovl_enable(ovl->id, false);
                        }
 
-                       dispc_go(manager->id);
+                       dispc_mgr_go(mgr->id);
                        mdelay(50);
+
                        if (enable)
                                dssdev->driver->enable(dssdev);
                }
@@ -3482,9 +3184,7 @@ static void dispc_error_worker(struct work_struct *work)
                for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
                        struct omap_overlay_manager *mgr;
                        mgr = omap_dss_get_overlay_manager(i);
-
-                       if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
-                               mgr->device->driver->disable(mgr->device);
+                       mgr->device->driver->disable(mgr->device);
                }
        }
 
@@ -3492,6 +3192,8 @@ static void dispc_error_worker(struct work_struct *work)
        dispc.irq_error_mask |= errors;
        _omap_dispc_set_irqs();
        spin_unlock_irqrestore(&dispc.irq_lock, flags);
+
+       dispc_runtime_put();
 }
 
 int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
@@ -3586,6 +3288,8 @@ static void _omap_dispc_initialize_irq(void)
        dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
        if (dss_has_feature(FEAT_MGR_LCD2))
                dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
+       if (dss_feat_get_num_ovls() > 3)
+               dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
 
        /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
         * so clear it */
@@ -3635,6 +3339,8 @@ static void _omap_dispc_initial_config(void)
        dispc_read_plane_fifo_sizes();
 
        dispc_configure_burst_sizes();
+
+       dispc_ovl_enable_zorder_planes();
 }
 
 /* DISPC HW IP initialisation */
@@ -3734,7 +3440,6 @@ static int omap_dispchw_remove(struct platform_device *pdev)
 static int dispc_runtime_suspend(struct device *dev)
 {
        dispc_save_context();
-       clk_disable(dispc.dss_clk);
        dss_runtime_put();
 
        return 0;
@@ -3748,7 +3453,6 @@ static int dispc_runtime_resume(struct device *dev)
        if (r < 0)
                return r;
 
-       clk_enable(dispc.dss_clk);
        dispc_restore_context();
 
        return 0;
index 6c9ee0a..c06efc3 100644 (file)
@@ -291,6 +291,8 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
                return 0x00BC;
        case OMAP_DSS_VIDEO2:
                return 0x014C;
+       case OMAP_DSS_VIDEO3:
+               return 0x0300;
        default:
                BUG();
        }
@@ -304,6 +306,8 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0000;
+       case OMAP_DSS_VIDEO3:
+               return 0x0008;
        default:
                BUG();
        }
@@ -316,6 +320,8 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0004;
+       case OMAP_DSS_VIDEO3:
+               return 0x000C;
        default:
                BUG();
        }
@@ -330,6 +336,8 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
                return 0x0544;
        case OMAP_DSS_VIDEO2:
                return 0x04BC;
+       case OMAP_DSS_VIDEO3:
+               return 0x0310;
        default:
                BUG();
        }
@@ -344,6 +352,8 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
                return 0x0548;
        case OMAP_DSS_VIDEO2:
                return 0x04C0;
+       case OMAP_DSS_VIDEO3:
+               return 0x0314;
        default:
                BUG();
        }
@@ -356,6 +366,8 @@ static inline u16 DISPC_POS_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0008;
+       case OMAP_DSS_VIDEO3:
+               return 0x009C;
        default:
                BUG();
        }
@@ -368,6 +380,8 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x000C;
+       case OMAP_DSS_VIDEO3:
+               return 0x00A8;
        default:
                BUG();
        }
@@ -381,6 +395,8 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0010;
+       case OMAP_DSS_VIDEO3:
+               return 0x0070;
        default:
                BUG();
        }
@@ -395,6 +411,8 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
                return 0x0568;
        case OMAP_DSS_VIDEO2:
                return 0x04DC;
+       case OMAP_DSS_VIDEO3:
+               return 0x032C;
        default:
                BUG();
        }
@@ -408,6 +426,8 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0014;
+       case OMAP_DSS_VIDEO3:
+               return 0x008C;
        default:
                BUG();
        }
@@ -421,6 +441,8 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0018;
+       case OMAP_DSS_VIDEO3:
+               return 0x0088;
        default:
                BUG();
        }
@@ -434,6 +456,8 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x001C;
+       case OMAP_DSS_VIDEO3:
+               return 0x00A4;
        default:
                BUG();
        }
@@ -447,6 +471,8 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0020;
+       case OMAP_DSS_VIDEO3:
+               return 0x0098;
        default:
                BUG();
        }
@@ -459,6 +485,7 @@ static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane)
                return 0x0034;
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
+       case OMAP_DSS_VIDEO3:
                BUG();
        default:
                BUG();
@@ -472,6 +499,7 @@ static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane)
                return 0x0038;
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
+       case OMAP_DSS_VIDEO3:
                BUG();
        default:
                BUG();
@@ -486,6 +514,8 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0024;
+       case OMAP_DSS_VIDEO3:
+               return 0x0090;
        default:
                BUG();
        }
@@ -500,6 +530,8 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
                return 0x0580;
        case OMAP_DSS_VIDEO2:
                return 0x055C;
+       case OMAP_DSS_VIDEO3:
+               return 0x0424;
        default:
                BUG();
        }
@@ -513,6 +545,8 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0028;
+       case OMAP_DSS_VIDEO3:
+               return 0x0094;
        default:
                BUG();
        }
@@ -527,6 +561,8 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x002C;
+       case OMAP_DSS_VIDEO3:
+               return 0x0000;
        default:
                BUG();
        }
@@ -541,6 +577,8 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
                return 0x0584;
        case OMAP_DSS_VIDEO2:
                return 0x0560;
+       case OMAP_DSS_VIDEO3:
+               return 0x0428;
        default:
                BUG();
        }
@@ -554,6 +592,8 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0030;
+       case OMAP_DSS_VIDEO3:
+               return 0x0004;
        default:
                BUG();
        }
@@ -568,6 +608,8 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
                return 0x0588;
        case OMAP_DSS_VIDEO2:
                return 0x0564;
+       case OMAP_DSS_VIDEO3:
+               return 0x042C;
        default:
                BUG();
        }
@@ -582,6 +624,8 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0034 + i * 0x8;
+       case OMAP_DSS_VIDEO3:
+               return 0x0010 + i * 0x8;
        default:
                BUG();
        }
@@ -597,6 +641,8 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
                return 0x058C + i * 0x8;
        case OMAP_DSS_VIDEO2:
                return 0x0568 + i * 0x8;
+       case OMAP_DSS_VIDEO3:
+               return 0x0430 + i * 0x8;
        default:
                BUG();
        }
@@ -611,6 +657,8 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0038 + i * 0x8;
+       case OMAP_DSS_VIDEO3:
+               return 0x0014 + i * 0x8;
        default:
                BUG();
        }
@@ -626,6 +674,8 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
                return 0x0590 + i * 8;
        case OMAP_DSS_VIDEO2:
                return 0x056C + i * 0x8;
+       case OMAP_DSS_VIDEO3:
+               return 0x0434 + i * 0x8;
        default:
                BUG();
        }
@@ -639,6 +689,7 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
                BUG();
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
+       case OMAP_DSS_VIDEO3:
                return 0x0074 + i * 0x4;
        default:
                BUG();
@@ -655,6 +706,8 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
                return 0x0124 + i * 0x4;
        case OMAP_DSS_VIDEO2:
                return 0x00B4 + i * 0x4;
+       case OMAP_DSS_VIDEO3:
+               return 0x0050 + i * 0x4;
        default:
                BUG();
        }
@@ -670,6 +723,8 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
                return 0x05CC + i * 0x4;
        case OMAP_DSS_VIDEO2:
                return 0x05A8 + i * 0x4;
+       case OMAP_DSS_VIDEO3:
+               return 0x0470 + i * 0x4;
        default:
                BUG();
        }
@@ -684,6 +739,8 @@ static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane)
                return 0x0174;
        case OMAP_DSS_VIDEO2:
                return 0x00E8;
+       case OMAP_DSS_VIDEO3:
+               return 0x00A0;
        default:
                BUG();
        }
index 94495e4..be331dc 100644 (file)
@@ -45,14 +45,13 @@ static ssize_t display_enabled_store(struct device *dev,
                const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       int r, enabled;
+       int r;
+       bool enabled;
 
-       r = kstrtoint(buf, 0, &enabled);
+       r = strtobool(buf, &enabled);
        if (r)
                return r;
 
-       enabled = !!enabled;
-
        if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
                if (enabled) {
                        r = dssdev->driver->enable(dssdev);
@@ -79,17 +78,16 @@ static ssize_t display_tear_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       int te, r;
+       int r;
+       bool te;
 
        if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
                return -ENOENT;
 
-       r = kstrtoint(buf, 0, &te);
+       r = strtobool(buf, &te);
        if (r)
                return r;
 
-       te = !!te;
-
        r = dssdev->driver->enable_te(dssdev, te);
        if (r)
                return r;
@@ -195,17 +193,16 @@ static ssize_t display_mirror_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       int mirror, r;
+       int r;
+       bool mirror;
 
        if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
                return -ENOENT;
 
-       r = kstrtoint(buf, 0, &mirror);
+       r = strtobool(buf, &mirror);
        if (r)
                return r;
 
-       mirror = !!mirror;
-
        r = dssdev->driver->set_mirror(dssdev, mirror);
        if (r)
                return r;
@@ -302,11 +299,15 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
                        return 16;
 
        case OMAP_DISPLAY_TYPE_DBI:
-       case OMAP_DISPLAY_TYPE_DSI:
                if (dssdev->ctrl.pixel_size == 24)
                        return 24;
                else
                        return 16;
+       case OMAP_DISPLAY_TYPE_DSI:
+               if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16)
+                       return 24;
+               else
+                       return 16;
        case OMAP_DISPLAY_TYPE_VENC:
        case OMAP_DISPLAY_TYPE_SDI:
        case OMAP_DISPLAY_TYPE_HDMI:
@@ -342,9 +343,11 @@ bool dss_use_replication(struct omap_dss_device *dssdev,
                bpp = 24;
                break;
        case OMAP_DISPLAY_TYPE_DBI:
-       case OMAP_DISPLAY_TYPE_DSI:
                bpp = dssdev->ctrl.pixel_size;
                break;
+       case OMAP_DISPLAY_TYPE_DSI:
+               bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+               break;
        default:
                BUG();
        }
index f053b18..483888a 100644 (file)
@@ -82,9 +82,11 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
 
        dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
 
-       r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
-       if (r)
+       r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo);
+       if (r) {
+               dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
                return r;
+       }
 
        *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
        *lck_div = dispc_cinfo.lck_div;
@@ -109,7 +111,7 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft,
        if (r)
                return r;
 
-       r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
+       r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo);
        if (r)
                return r;
 
@@ -129,7 +131,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
        bool is_tft;
        int r = 0;
 
-       dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
+       dispc_mgr_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
                        dssdev->panel.acbi, dssdev->panel.acb);
 
        is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
@@ -153,7 +155,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
                t->pixel_clock = pck;
        }
 
-       dispc_set_lcd_timings(dssdev->manager->id, t);
+       dispc_mgr_set_lcd_timings(dssdev->manager->id, t);
 
        return 0;
 }
@@ -164,11 +166,12 @@ static void dpi_basic_init(struct omap_dss_device *dssdev)
 
        is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
 
-       dispc_set_parallel_interface_mode(dssdev->manager->id,
-                       OMAP_DSS_PARALLELMODE_BYPASS);
-       dispc_set_lcd_display_type(dssdev->manager->id, is_tft ?
+       dispc_mgr_set_io_pad_mode(DSS_IO_PAD_MODE_BYPASS);
+       dispc_mgr_enable_stallmode(dssdev->manager->id, false);
+
+       dispc_mgr_set_lcd_display_type(dssdev->manager->id, is_tft ?
                        OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN);
-       dispc_set_tft_data_lines(dssdev->manager->id,
+       dispc_mgr_set_tft_data_lines(dssdev->manager->id,
                        dssdev->phy.dpi.data_lines);
 }
 
@@ -176,6 +179,11 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
 {
        int r;
 
+       if (dssdev->manager == NULL) {
+               DSSERR("failed to enable display: no manager\n");
+               return -ENODEV;
+       }
+
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
@@ -277,7 +285,7 @@ void dpi_set_timings(struct omap_dss_device *dssdev,
                }
 
                dpi_set_mode(dssdev);
-               dispc_go(dssdev->manager->id);
+               dispc_mgr_go(dssdev->manager->id);
 
                dispc_runtime_put();
                dss_runtime_put();
index 7adbbeb..43c04a9 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/pm_runtime.h>
 
 #include <video/omapdss.h>
+#include <video/mipi_display.h>
 #include <plat/clock.h>
 
 #include "dss.h"
@@ -131,7 +132,7 @@ struct dsi_reg { u16 idx; };
 #define DSI_IRQ_TA_TIMEOUT     (1 << 20)
 #define DSI_IRQ_ERROR_MASK \
        (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
-       DSI_IRQ_TA_TIMEOUT)
+       DSI_IRQ_TA_TIMEOUT | DSI_IRQ_SYNC_LOST)
 #define DSI_IRQ_CHANNEL_MASK   0xf
 
 /* Virtual channel interrupts */
@@ -198,18 +199,6 @@ struct dsi_reg { u16 idx; };
         DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \
         DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5)
 
-#define DSI_DT_DCS_SHORT_WRITE_0       0x05
-#define DSI_DT_DCS_SHORT_WRITE_1       0x15
-#define DSI_DT_DCS_READ                        0x06
-#define DSI_DT_SET_MAX_RET_PKG_SIZE    0x37
-#define DSI_DT_NULL_PACKET             0x09
-#define DSI_DT_DCS_LONG_WRITE          0x39
-
-#define DSI_DT_RX_ACK_WITH_ERR         0x02
-#define DSI_DT_RX_DCS_LONG_READ                0x1c
-#define DSI_DT_RX_SHORT_READ_1         0x21
-#define DSI_DT_RX_SHORT_READ_2         0x22
-
 typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
 
 #define DSI_MAX_NR_ISRS                2
@@ -228,9 +217,9 @@ enum fifo_size {
        DSI_FIFO_SIZE_128       = 4,
 };
 
-enum dsi_vc_mode {
-       DSI_VC_MODE_L4 = 0,
-       DSI_VC_MODE_VP,
+enum dsi_vc_source {
+       DSI_VC_SOURCE_L4 = 0,
+       DSI_VC_SOURCE_VP,
 };
 
 enum dsi_lane {
@@ -274,7 +263,8 @@ struct dsi_data {
        struct clk *dss_clk;
        struct clk *sys_clk;
 
-       void (*dsi_mux_pads)(bool enable);
+       int (*enable_pads)(int dsi_id, unsigned lane_mask);
+       void (*disable_pads)(int dsi_id, unsigned lane_mask);
 
        struct dsi_clock_info current_cinfo;
 
@@ -282,7 +272,7 @@ struct dsi_data {
        struct regulator *vdds_dsi_reg;
 
        struct {
-               enum dsi_vc_mode mode;
+               enum dsi_vc_source source;
                struct omap_dss_device *dssdev;
                enum fifo_size fifo_size;
                int vc_id;
@@ -368,14 +358,9 @@ struct platform_device *dsi_get_dsidev_from_id(int module)
        return dsi_pdev_map[module];
 }
 
-static int dsi_get_dsidev_id(struct platform_device *dsidev)
+static inline int dsi_get_dsidev_id(struct platform_device *dsidev)
 {
-       /* TEMP: Pass 0 as the dsi module index till the time the dsi platform
-        * device names aren't changed to the form "omapdss_dsi.0",
-        * "omapdss_dsi.1" and so on */
-       BUG_ON(dsidev->id != -1);
-
-       return 0;
+       return dsidev->id;
 }
 
 static inline void dsi_write_reg(struct platform_device *dsidev,
@@ -437,6 +422,21 @@ static inline int wait_for_bit_change(struct platform_device *dsidev,
        return value;
 }
 
+u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
+{
+       switch (fmt) {
+       case OMAP_DSS_DSI_FMT_RGB888:
+       case OMAP_DSS_DSI_FMT_RGB666:
+               return 24;
+       case OMAP_DSS_DSI_FMT_RGB666_PACKED:
+               return 18;
+       case OMAP_DSS_DSI_FMT_RGB565:
+               return 16;
+       default:
+               BUG();
+       }
+}
+
 #ifdef DEBUG
 static void dsi_perf_mark_setup(struct platform_device *dsidev)
 {
@@ -453,6 +453,7 @@ static void dsi_perf_mark_start(struct platform_device *dsidev)
 static void dsi_perf_show(struct platform_device *dsidev, const char *name)
 {
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct omap_dss_device *dssdev = dsi->update_region.device;
        ktime_t t, setup_time, trans_time;
        u32 total_bytes;
        u32 setup_us, trans_us, total_us;
@@ -476,7 +477,7 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name)
 
        total_bytes = dsi->update_region.w *
                dsi->update_region.h *
-               dsi->update_region.device->ctrl.pixel_size / 8;
+               dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
 
        printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
                        "%u bytes, %u kbytes/sec\n",
@@ -1287,7 +1288,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
                 * with DSS_SYS_CLK source also */
                cinfo->highfreq = 0;
        } else {
-               cinfo->clkin = dispc_pclk_rate(dssdev->manager->id);
+               cinfo->clkin = dispc_mgr_pclk_rate(dssdev->manager->id);
 
                if (cinfo->clkin < 32000000)
                        cinfo->highfreq = 0;
@@ -2360,6 +2361,24 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
        return 0;
 }
 
+static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev)
+{
+       unsigned lanes = 0;
+
+       if (dssdev->phy.dsi.clk_lane != 0)
+               lanes |= 1 << (dssdev->phy.dsi.clk_lane - 1);
+       if (dssdev->phy.dsi.data1_lane != 0)
+               lanes |= 1 << (dssdev->phy.dsi.data1_lane - 1);
+       if (dssdev->phy.dsi.data2_lane != 0)
+               lanes |= 1 << (dssdev->phy.dsi.data2_lane - 1);
+       if (dssdev->phy.dsi.data3_lane != 0)
+               lanes |= 1 << (dssdev->phy.dsi.data3_lane - 1);
+       if (dssdev->phy.dsi.data4_lane != 0)
+               lanes |= 1 << (dssdev->phy.dsi.data4_lane - 1);
+
+       return lanes;
+}
+
 static int dsi_cio_init(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -2370,8 +2389,9 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
 
        DSSDBGF();
 
-       if (dsi->dsi_mux_pads)
-               dsi->dsi_mux_pads(true);
+       r = dsi->enable_pads(dsidev->id, dsi_get_lane_mask(dssdev));
+       if (r)
+               return r;
 
        dsi_enable_scp_clk(dsidev);
 
@@ -2452,6 +2472,12 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
 
        dsi_cio_timings(dsidev);
 
+       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+               /* DDR_CLK_ALWAYS_ON */
+               REG_FLD_MOD(dsidev, DSI_CLK_CTRL,
+                       dssdev->panel.dsi_vm_data.ddr_clk_always_on, 13, 13);
+       }
+
        dsi->ulps_enabled = false;
 
        DSSDBG("CIO init done\n");
@@ -2467,19 +2493,21 @@ err_cio_pwr:
                dsi_cio_disable_lane_override(dsidev);
 err_scp_clk_dom:
        dsi_disable_scp_clk(dsidev);
-       if (dsi->dsi_mux_pads)
-               dsi->dsi_mux_pads(false);
+       dsi->disable_pads(dsidev->id, dsi_get_lane_mask(dssdev));
        return r;
 }
 
-static void dsi_cio_uninit(struct platform_device *dsidev)
+static void dsi_cio_uninit(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
+       /* DDR_CLK_ALWAYS_ON */
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13);
+
        dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
        dsi_disable_scp_clk(dsidev);
-       if (dsi->dsi_mux_pads)
-               dsi->dsi_mux_pads(false);
+       dsi->disable_pads(dsidev->id, dsi_get_lane_mask(dssdev));
 }
 
 static void dsi_config_tx_fifo(struct platform_device *dsidev,
@@ -2669,10 +2697,10 @@ static int dsi_sync_vc(struct platform_device *dsidev, int channel)
        if (!dsi_vc_is_enabled(dsidev, channel))
                return 0;
 
-       switch (dsi->vc[channel].mode) {
-       case DSI_VC_MODE_VP:
+       switch (dsi->vc[channel].source) {
+       case DSI_VC_SOURCE_VP:
                return dsi_sync_vc_vp(dsidev, channel);
-       case DSI_VC_MODE_L4:
+       case DSI_VC_SOURCE_L4:
                return dsi_sync_vc_l4(dsidev, channel);
        default:
                BUG();
@@ -2726,43 +2754,12 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
        dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);
 }
 
-static int dsi_vc_config_l4(struct platform_device *dsidev, int channel)
+static int dsi_vc_config_source(struct platform_device *dsidev, int channel,
+               enum dsi_vc_source source)
 {
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
-       if (dsi->vc[channel].mode == DSI_VC_MODE_L4)
-               return 0;
-
-       DSSDBGF("%d", channel);
-
-       dsi_sync_vc(dsidev, channel);
-
-       dsi_vc_enable(dsidev, channel, 0);
-
-       /* VC_BUSY */
-       if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
-               DSSERR("vc(%d) busy when trying to config for L4\n", channel);
-               return -EIO;
-       }
-
-       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
-
-       /* DCS_CMD_ENABLE */
-       if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC))
-               REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 30, 30);
-
-       dsi_vc_enable(dsidev, channel, 1);
-
-       dsi->vc[channel].mode = DSI_VC_MODE_L4;
-
-       return 0;
-}
-
-static int dsi_vc_config_vp(struct platform_device *dsidev, int channel)
-{
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-
-       if (dsi->vc[channel].mode == DSI_VC_MODE_VP)
+       if (dsi->vc[channel].source == source)
                return 0;
 
        DSSDBGF("%d", channel);
@@ -2777,21 +2774,22 @@ static int dsi_vc_config_vp(struct platform_device *dsidev, int channel)
                return -EIO;
        }
 
-       /* SOURCE, 1 = video port */
-       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 1, 1);
+       /* SOURCE, 0 = L4, 1 = video port */
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), source, 1, 1);
 
        /* DCS_CMD_ENABLE */
-       if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC))
-               REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 30, 30);
+       if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
+               bool enable = source == DSI_VC_SOURCE_VP;
+               REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 30, 30);
+       }
 
        dsi_vc_enable(dsidev, channel, 1);
 
-       dsi->vc[channel].mode = DSI_VC_MODE_VP;
+       dsi->vc[channel].source = source;
 
        return 0;
 }
 
-
 void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
                bool enable)
 {
@@ -2810,6 +2808,10 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
        dsi_if_enable(dsidev, 1);
 
        dsi_force_tx_stop_mode_io(dsidev);
+
+       /* start the DDR clock by sending a NULL packet */
+       if (dssdev->panel.dsi_vm_data.ddr_clk_always_on && enable)
+               dsi_vc_send_null(dssdev, channel);
 }
 EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
 
@@ -2873,16 +2875,16 @@ static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev,
                val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
                DSSERR("\trawval %#08x\n", val);
                dt = FLD_GET(val, 5, 0);
-               if (dt == DSI_DT_RX_ACK_WITH_ERR) {
+               if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) {
                        u16 err = FLD_GET(val, 23, 8);
                        dsi_show_rx_ack_with_err(err);
-               } else if (dt == DSI_DT_RX_SHORT_READ_1) {
+               } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE) {
                        DSSERR("\tDCS short response, 1 byte: %#x\n",
                                        FLD_GET(val, 23, 8));
-               } else if (dt == DSI_DT_RX_SHORT_READ_2) {
+               } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE) {
                        DSSERR("\tDCS short response, 2 byte: %#x\n",
                                        FLD_GET(val, 23, 8));
-               } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
+               } else if (dt == MIPI_DSI_RX_DCS_LONG_READ_RESPONSE) {
                        DSSERR("\tDCS long response, len %d\n",
                                        FLD_GET(val, 23, 8));
                        dsi_vc_flush_long_data(dsidev, channel);
@@ -3007,7 +3009,7 @@ static int dsi_vc_send_long(struct platform_device *dsidev, int channel,
                return -EINVAL;
        }
 
-       dsi_vc_config_l4(dsidev, channel);
+       dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4);
 
        dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc);
 
@@ -3066,7 +3068,7 @@ static int dsi_vc_send_short(struct platform_device *dsidev, int channel,
                                channel,
                                data_type, data & 0xff, (data >> 8) & 0xff);
 
-       dsi_vc_config_l4(dsidev, channel);
+       dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4);
 
        if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) {
                DSSERR("ERROR FIFO FULL, aborting transfer\n");
@@ -3085,44 +3087,66 @@ static int dsi_vc_send_short(struct platform_device *dsidev, int channel,
 int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       u8 nullpkg[] = {0, 0, 0, 0};
 
-       return dsi_vc_send_long(dsidev, channel, DSI_DT_NULL_PACKET, nullpkg,
-               4, 0);
+       return dsi_vc_send_long(dsidev, channel, MIPI_DSI_NULL_PACKET, NULL,
+               0, 0);
 }
 EXPORT_SYMBOL(dsi_vc_send_null);
 
-int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
-               u8 *data, int len)
+static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev,
+               int channel, u8 *data, int len, enum dss_dsi_content_type type)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        int r;
 
-       BUG_ON(len == 0);
-
-       if (len == 1) {
-               r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_0,
-                               data[0], 0);
+       if (len == 0) {
+               BUG_ON(type == DSS_DSI_CONTENT_DCS);
+               r = dsi_vc_send_short(dsidev, channel,
+                               MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM, 0, 0);
+       } else if (len == 1) {
+               r = dsi_vc_send_short(dsidev, channel,
+                               type == DSS_DSI_CONTENT_GENERIC ?
+                               MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM :
+                               MIPI_DSI_DCS_SHORT_WRITE, data[0], 0);
        } else if (len == 2) {
-               r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_1,
+               r = dsi_vc_send_short(dsidev, channel,
+                               type == DSS_DSI_CONTENT_GENERIC ?
+                               MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM :
+                               MIPI_DSI_DCS_SHORT_WRITE_PARAM,
                                data[0] | (data[1] << 8), 0);
        } else {
-               /* 0x39 = DCS Long Write */
-               r = dsi_vc_send_long(dsidev, channel, DSI_DT_DCS_LONG_WRITE,
-                               data, len, 0);
+               r = dsi_vc_send_long(dsidev, channel,
+                               type == DSS_DSI_CONTENT_GENERIC ?
+                               MIPI_DSI_GENERIC_LONG_WRITE :
+                               MIPI_DSI_DCS_LONG_WRITE, data, len, 0);
        }
 
        return r;
 }
+
+int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
+               u8 *data, int len)
+{
+       return dsi_vc_write_nosync_common(dssdev, channel, data, len,
+                       DSS_DSI_CONTENT_DCS);
+}
 EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
 
-int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
-               int len)
+int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel,
+               u8 *data, int len)
+{
+       return dsi_vc_write_nosync_common(dssdev, channel, data, len,
+                       DSS_DSI_CONTENT_GENERIC);
+}
+EXPORT_SYMBOL(dsi_vc_generic_write_nosync);
+
+static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel,
+               u8 *data, int len, enum dss_dsi_content_type type)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        int r;
 
-       r = dsi_vc_dcs_write_nosync(dssdev, channel, data, len);
+       r = dsi_vc_write_nosync_common(dssdev, channel, data, len, type);
        if (r)
                goto err;
 
@@ -3140,18 +3164,39 @@ int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
 
        return 0;
 err:
-       DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n",
+       DSSERR("dsi_vc_write_common(ch %d, cmd 0x%02x, len %d) failed\n",
                        channel, data[0], len);
        return r;
 }
+
+int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
+               int len)
+{
+       return dsi_vc_write_common(dssdev, channel, data, len,
+                       DSS_DSI_CONTENT_DCS);
+}
 EXPORT_SYMBOL(dsi_vc_dcs_write);
 
+int dsi_vc_generic_write(struct omap_dss_device *dssdev, int channel, u8 *data,
+               int len)
+{
+       return dsi_vc_write_common(dssdev, channel, data, len,
+                       DSS_DSI_CONTENT_GENERIC);
+}
+EXPORT_SYMBOL(dsi_vc_generic_write);
+
 int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd)
 {
        return dsi_vc_dcs_write(dssdev, channel, &dcs_cmd, 1);
 }
 EXPORT_SYMBOL(dsi_vc_dcs_write_0);
 
+int dsi_vc_generic_write_0(struct omap_dss_device *dssdev, int channel)
+{
+       return dsi_vc_generic_write(dssdev, channel, NULL, 0);
+}
+EXPORT_SYMBOL(dsi_vc_generic_write_0);
+
 int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
                u8 param)
 {
@@ -3162,25 +3207,87 @@ int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
 }
 EXPORT_SYMBOL(dsi_vc_dcs_write_1);
 
-int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
-               u8 *buf, int buflen)
+int dsi_vc_generic_write_1(struct omap_dss_device *dssdev, int channel,
+               u8 param)
+{
+       return dsi_vc_generic_write(dssdev, channel, &param, 1);
+}
+EXPORT_SYMBOL(dsi_vc_generic_write_1);
+
+int dsi_vc_generic_write_2(struct omap_dss_device *dssdev, int channel,
+               u8 param1, u8 param2)
+{
+       u8 buf[2];
+       buf[0] = param1;
+       buf[1] = param2;
+       return dsi_vc_generic_write(dssdev, channel, buf, 2);
+}
+EXPORT_SYMBOL(dsi_vc_generic_write_2);
+
+static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev,
+               int channel, u8 dcs_cmd)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       u32 val;
-       u8 dt;
        int r;
 
        if (dsi->debug_read)
-               DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %x)\n", channel, dcs_cmd);
+               DSSDBG("dsi_vc_dcs_send_read_request(ch%d, dcs_cmd %x)\n",
+                       channel, dcs_cmd);
 
-       r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_READ, dcs_cmd, 0);
-       if (r)
-               goto err;
+       r = dsi_vc_send_short(dsidev, channel, MIPI_DSI_DCS_READ, dcs_cmd, 0);
+       if (r) {
+               DSSERR("dsi_vc_dcs_send_read_request(ch %d, cmd 0x%02x)"
+                       " failed\n", channel, dcs_cmd);
+               return r;
+       }
 
-       r = dsi_vc_send_bta_sync(dssdev, channel);
-       if (r)
-               goto err;
+       return 0;
+}
+
+static int dsi_vc_generic_send_read_request(struct omap_dss_device *dssdev,
+               int channel, u8 *reqdata, int reqlen)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       u16 data;
+       u8 data_type;
+       int r;
+
+       if (dsi->debug_read)
+               DSSDBG("dsi_vc_generic_send_read_request(ch %d, reqlen %d)\n",
+                       channel, reqlen);
+
+       if (reqlen == 0) {
+               data_type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;
+               data = 0;
+       } else if (reqlen == 1) {
+               data_type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
+               data = reqdata[0];
+       } else if (reqlen == 2) {
+               data_type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;
+               data = reqdata[0] | (reqdata[1] << 8);
+       } else {
+               BUG();
+       }
+
+       r = dsi_vc_send_short(dsidev, channel, data_type, data, 0);
+       if (r) {
+               DSSERR("dsi_vc_generic_send_read_request(ch %d, reqlen %d)"
+                       " failed\n", channel, reqlen);
+               return r;
+       }
+
+       return 0;
+}
+
+static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel,
+               u8 *buf, int buflen, enum dss_dsi_content_type type)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       u32 val;
+       u8 dt;
+       int r;
 
        /* RX_FIFO_NOT_EMPTY */
        if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) {
@@ -3193,16 +3300,20 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
        if (dsi->debug_read)
                DSSDBG("\theader: %08x\n", val);
        dt = FLD_GET(val, 5, 0);
-       if (dt == DSI_DT_RX_ACK_WITH_ERR) {
+       if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) {
                u16 err = FLD_GET(val, 23, 8);
                dsi_show_rx_ack_with_err(err);
                r = -EIO;
                goto err;
 
-       } else if (dt == DSI_DT_RX_SHORT_READ_1) {
+       } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
+                       MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE :
+                       MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE)) {
                u8 data = FLD_GET(val, 15, 8);
                if (dsi->debug_read)
-                       DSSDBG("\tDCS short response, 1 byte: %02x\n", data);
+                       DSSDBG("\t%s short response, 1 byte: %02x\n",
+                               type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
+                               "DCS", data);
 
                if (buflen < 1) {
                        r = -EIO;
@@ -3212,10 +3323,14 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
                buf[0] = data;
 
                return 1;
-       } else if (dt == DSI_DT_RX_SHORT_READ_2) {
+       } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
+                       MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE :
+                       MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE)) {
                u16 data = FLD_GET(val, 23, 8);
                if (dsi->debug_read)
-                       DSSDBG("\tDCS short response, 2 byte: %04x\n", data);
+                       DSSDBG("\t%s short response, 2 byte: %04x\n",
+                               type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
+                               "DCS", data);
 
                if (buflen < 2) {
                        r = -EIO;
@@ -3226,11 +3341,15 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
                buf[1] = (data >> 8) & 0xff;
 
                return 2;
-       } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
+       } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
+                       MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE :
+                       MIPI_DSI_RX_DCS_LONG_READ_RESPONSE)) {
                int w;
                int len = FLD_GET(val, 23, 8);
                if (dsi->debug_read)
-                       DSSDBG("\tDCS long response, len %d\n", len);
+                       DSSDBG("\t%s long response, len %d\n",
+                               type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
+                               "DCS", len);
 
                if (len > buflen) {
                        r = -EIO;
@@ -3266,58 +3385,126 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
 
        BUG();
 err:
-       DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n",
-                       channel, dcs_cmd);
+       DSSERR("dsi_vc_read_rx_fifo(ch %d type %s) failed\n", channel,
+               type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : "DCS");
+
        return r;
+}
 
+int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *buf, int buflen)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       int r;
+
+       r = dsi_vc_dcs_send_read_request(dssdev, channel, dcs_cmd);
+       if (r)
+               goto err;
+
+       r = dsi_vc_send_bta_sync(dssdev, channel);
+       if (r)
+               goto err;
+
+       r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen,
+               DSS_DSI_CONTENT_DCS);
+       if (r < 0)
+               goto err;
+
+       if (r != buflen) {
+               r = -EIO;
+               goto err;
+       }
+
+       return 0;
+err:
+       DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n", channel, dcs_cmd);
+       return r;
 }
 EXPORT_SYMBOL(dsi_vc_dcs_read);
 
-int dsi_vc_dcs_read_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
-               u8 *data)
+static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel,
+               u8 *reqdata, int reqlen, u8 *buf, int buflen)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        int r;
 
-       r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, data, 1);
+       r = dsi_vc_generic_send_read_request(dssdev, channel, reqdata, reqlen);
+       if (r)
+               return r;
+
+       r = dsi_vc_send_bta_sync(dssdev, channel);
+       if (r)
+               return r;
 
+       r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen,
+               DSS_DSI_CONTENT_GENERIC);
        if (r < 0)
                return r;
 
-       if (r != 1)
-               return -EIO;
+       if (r != buflen) {
+               r = -EIO;
+               return r;
+       }
 
        return 0;
 }
-EXPORT_SYMBOL(dsi_vc_dcs_read_1);
 
-int dsi_vc_dcs_read_2(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
-               u8 *data1, u8 *data2)
+int dsi_vc_generic_read_0(struct omap_dss_device *dssdev, int channel, u8 *buf,
+               int buflen)
 {
-       u8 buf[2];
        int r;
 
-       r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, buf, 2);
+       r = dsi_vc_generic_read(dssdev, channel, NULL, 0, buf, buflen);
+       if (r) {
+               DSSERR("dsi_vc_generic_read_0(ch %d) failed\n", channel);
+               return r;
+       }
 
-       if (r < 0)
+       return 0;
+}
+EXPORT_SYMBOL(dsi_vc_generic_read_0);
+
+int dsi_vc_generic_read_1(struct omap_dss_device *dssdev, int channel, u8 param,
+               u8 *buf, int buflen)
+{
+       int r;
+
+       r = dsi_vc_generic_read(dssdev, channel, &param, 1, buf, buflen);
+       if (r) {
+               DSSERR("dsi_vc_generic_read_1(ch %d) failed\n", channel);
                return r;
+       }
 
-       if (r != 2)
-               return -EIO;
+       return 0;
+}
+EXPORT_SYMBOL(dsi_vc_generic_read_1);
 
-       *data1 = buf[0];
-       *data2 = buf[1];
+int dsi_vc_generic_read_2(struct omap_dss_device *dssdev, int channel,
+               u8 param1, u8 param2, u8 *buf, int buflen)
+{
+       int r;
+       u8 reqdata[2];
+
+       reqdata[0] = param1;
+       reqdata[1] = param2;
+
+       r = dsi_vc_generic_read(dssdev, channel, reqdata, 2, buf, buflen);
+       if (r) {
+               DSSERR("dsi_vc_generic_read_2(ch %d) failed\n", channel);
+               return r;
+       }
 
        return 0;
 }
-EXPORT_SYMBOL(dsi_vc_dcs_read_2);
+EXPORT_SYMBOL(dsi_vc_generic_read_2);
 
 int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
                u16 len)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
 
-       return dsi_vc_send_short(dsidev, channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
-                       len, 0);
+       return dsi_vc_send_short(dsidev, channel,
+                       MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0);
 }
 EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
 
@@ -3508,6 +3695,75 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev,
                        ticks, x4 ? " x4" : "", x16 ? " x16" : "",
                        (total_ticks * 1000) / (fck / 1000 / 1000));
 }
+
+static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       int num_line_buffers;
+
+       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+               int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+               unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
+               struct omap_video_timings *timings = &dssdev->panel.timings;
+               /*
+                * Don't use line buffers if width is greater than the video
+                * port's line buffer size
+                */
+               if (line_buf_size <= timings->x_res * bpp / 8)
+                       num_line_buffers = 0;
+               else
+                       num_line_buffers = 2;
+       } else {
+               /* Use maximum number of line buffers in command mode */
+               num_line_buffers = 2;
+       }
+
+       /* LINE_BUFFER */
+       REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12);
+}
+
+static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       int de_pol = dssdev->panel.dsi_vm_data.vp_de_pol;
+       int hsync_pol = dssdev->panel.dsi_vm_data.vp_hsync_pol;
+       int vsync_pol = dssdev->panel.dsi_vm_data.vp_vsync_pol;
+       bool vsync_end = dssdev->panel.dsi_vm_data.vp_vsync_end;
+       bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end;
+       u32 r;
+
+       r = dsi_read_reg(dsidev, DSI_CTRL);
+       r = FLD_MOD(r, de_pol, 9, 9);           /* VP_DE_POL */
+       r = FLD_MOD(r, hsync_pol, 10, 10);      /* VP_HSYNC_POL */
+       r = FLD_MOD(r, vsync_pol, 11, 11);      /* VP_VSYNC_POL */
+       r = FLD_MOD(r, 1, 15, 15);              /* VP_VSYNC_START */
+       r = FLD_MOD(r, vsync_end, 16, 16);      /* VP_VSYNC_END */
+       r = FLD_MOD(r, 1, 17, 17);              /* VP_HSYNC_START */
+       r = FLD_MOD(r, hsync_end, 18, 18);      /* VP_HSYNC_END */
+       dsi_write_reg(dsidev, DSI_CTRL, r);
+}
+
+static void dsi_config_blanking_modes(struct omap_dss_device *dssdev)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       int blanking_mode = dssdev->panel.dsi_vm_data.blanking_mode;
+       int hfp_blanking_mode = dssdev->panel.dsi_vm_data.hfp_blanking_mode;
+       int hbp_blanking_mode = dssdev->panel.dsi_vm_data.hbp_blanking_mode;
+       int hsa_blanking_mode = dssdev->panel.dsi_vm_data.hsa_blanking_mode;
+       u32 r;
+
+       /*
+        * 0 = TX FIFO packets sent or LPS in corresponding blanking periods
+        * 1 = Long blanking packets are sent in corresponding blanking periods
+        */
+       r = dsi_read_reg(dsidev, DSI_CTRL);
+       r = FLD_MOD(r, blanking_mode, 20, 20);          /* BLANKING_MODE */
+       r = FLD_MOD(r, hfp_blanking_mode, 21, 21);      /* HFP_BLANKING */
+       r = FLD_MOD(r, hbp_blanking_mode, 22, 22);      /* HBP_BLANKING */
+       r = FLD_MOD(r, hsa_blanking_mode, 23, 23);      /* HSA_BLANKING */
+       dsi_write_reg(dsidev, DSI_CTRL, r);
+}
+
 static int dsi_proto_config(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -3530,7 +3786,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
        dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
        dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
 
-       switch (dssdev->ctrl.pixel_size) {
+       switch (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt)) {
        case 16:
                buswidth = 0;
                break;
@@ -3551,7 +3807,6 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
        r = FLD_MOD(r, 1, 4, 4);        /* VP_CLK_RATIO, always 1, see errata*/
        r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */
        r = FLD_MOD(r, 0, 8, 8);        /* VP_CLK_POL */
-       r = FLD_MOD(r, 2, 13, 12);      /* LINE_BUFFER, 2 lines */
        r = FLD_MOD(r, 1, 14, 14);      /* TRIGGER_RESET_MODE */
        r = FLD_MOD(r, 1, 19, 19);      /* EOT_ENABLE */
        if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
@@ -3562,6 +3817,13 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
 
        dsi_write_reg(dsidev, DSI_CTRL, r);
 
+       dsi_config_vp_num_line_buffers(dssdev);
+
+       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+               dsi_config_vp_sync_events(dssdev);
+               dsi_config_blanking_modes(dssdev);
+       }
+
        dsi_vc_initial_config(dsidev, 0);
        dsi_vc_initial_config(dsidev, 1);
        dsi_vc_initial_config(dsidev, 2);
@@ -3580,6 +3842,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
        unsigned ddr_clk_pre, ddr_clk_post;
        unsigned enter_hs_mode_lat, exit_hs_mode_lat;
        unsigned ths_eot;
+       int ndl = dsi_get_num_data_lanes_dssdev(dssdev);
        u32 r;
 
        r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
@@ -3602,7 +3865,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
        /* min 60ns + 52*UI */
        tclk_post = ns2ddr(dsidev, 60) + 26;
 
-       ths_eot = DIV_ROUND_UP(4, dsi_get_num_data_lanes_dssdev(dssdev));
+       ths_eot = DIV_ROUND_UP(4, ndl);
 
        ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
                        4);
@@ -3632,162 +3895,114 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
 
        DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
                        enter_hs_mode_lat, exit_hs_mode_lat);
-}
-
-
-#define DSI_DECL_VARS \
-       int __dsi_cb = 0; u32 __dsi_cv = 0;
 
-#define DSI_FLUSH(dsidev, ch) \
-       if (__dsi_cb > 0) { \
-               /*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \
-               dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
-               __dsi_cb = __dsi_cv = 0; \
+        if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+               /* TODO: Implement a video mode check_timings function */
+               int hsa = dssdev->panel.dsi_vm_data.hsa;
+               int hfp = dssdev->panel.dsi_vm_data.hfp;
+               int hbp = dssdev->panel.dsi_vm_data.hbp;
+               int vsa = dssdev->panel.dsi_vm_data.vsa;
+               int vfp = dssdev->panel.dsi_vm_data.vfp;
+               int vbp = dssdev->panel.dsi_vm_data.vbp;
+               int window_sync = dssdev->panel.dsi_vm_data.window_sync;
+               bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end;
+               struct omap_video_timings *timings = &dssdev->panel.timings;
+               int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+               int tl, t_he, width_bytes;
+
+               t_he = hsync_end ?
+                       ((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0;
+
+               width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8);
+
+               /* TL = t_HS + HSA + t_HE + HFP + ceil((WC + 6) / NDL) + HBP */
+               tl = DIV_ROUND_UP(4, ndl) + (hsync_end ? hsa : 0) + t_he + hfp +
+                       DIV_ROUND_UP(width_bytes + 6, ndl) + hbp;
+
+               DSSDBG("HBP: %d, HFP: %d, HSA: %d, TL: %d TXBYTECLKHS\n", hbp,
+                       hfp, hsync_end ? hsa : 0, tl);
+               DSSDBG("VBP: %d, VFP: %d, VSA: %d, VACT: %d lines\n", vbp, vfp,
+                       vsa, timings->y_res);
+
+               r = dsi_read_reg(dsidev, DSI_VM_TIMING1);
+               r = FLD_MOD(r, hbp, 11, 0);     /* HBP */
+               r = FLD_MOD(r, hfp, 23, 12);    /* HFP */
+               r = FLD_MOD(r, hsync_end ? hsa : 0, 31, 24);    /* HSA */
+               dsi_write_reg(dsidev, DSI_VM_TIMING1, r);
+
+               r = dsi_read_reg(dsidev, DSI_VM_TIMING2);
+               r = FLD_MOD(r, vbp, 7, 0);      /* VBP */
+               r = FLD_MOD(r, vfp, 15, 8);     /* VFP */
+               r = FLD_MOD(r, vsa, 23, 16);    /* VSA */
+               r = FLD_MOD(r, window_sync, 27, 24);    /* WINDOW_SYNC */
+               dsi_write_reg(dsidev, DSI_VM_TIMING2, r);
+
+               r = dsi_read_reg(dsidev, DSI_VM_TIMING3);
+               r = FLD_MOD(r, timings->y_res, 14, 0);  /* VACT */
+               r = FLD_MOD(r, tl, 31, 16);             /* TL */
+               dsi_write_reg(dsidev, DSI_VM_TIMING3, r);
        }
+}
 
-#define DSI_PUSH(dsidev, ch, data) \
-       do { \
-               __dsi_cv |= (data) << (__dsi_cb * 8); \
-               /*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \
-               if (++__dsi_cb > 3) \
-                       DSI_FLUSH(dsidev, ch); \
-       } while (0)
-
-static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
-                       int x, int y, int w, int h)
+int dsi_video_mode_enable(struct omap_dss_device *dssdev, int channel)
 {
-       /* Note: supports only 24bit colors in 32bit container */
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       int first = 1;
-       int fifo_stalls = 0;
-       int max_dsi_packet_size;
-       int max_data_per_packet;
-       int max_pixels_per_packet;
-       int pixels_left;
-       int bytespp = dssdev->ctrl.pixel_size / 8;
-       int scr_width;
-       u32 __iomem *data;
-       int start_offset;
-       int horiz_inc;
-       int current_x;
-       struct omap_overlay *ovl;
-
-       debug_irq = 0;
-
-       DSSDBG("dsi_update_screen_l4 (%d,%d %dx%d)\n",
-                       x, y, w, h);
+       int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+       u8 data_type;
+       u16 word_count;
 
-       ovl = dssdev->manager->overlays[0];
-
-       if (ovl->info.color_mode != OMAP_DSS_COLOR_RGB24U)
-               return -EINVAL;
-
-       if (dssdev->ctrl.pixel_size != 24)
-               return -EINVAL;
-
-       scr_width = ovl->info.screen_width;
-       data = ovl->info.vaddr;
-
-       start_offset = scr_width * y + x;
-       horiz_inc = scr_width - w;
-       current_x = x;
-
-       /* We need header(4) + DCSCMD(1) + pixels(numpix*bytespp) bytes
-        * in fifo */
-
-       /* When using CPU, max long packet size is TX buffer size */
-       max_dsi_packet_size = dsi->vc[0].fifo_size * 32 * 4;
-
-       /* we seem to get better perf if we divide the tx fifo to half,
-          and while the other half is being sent, we fill the other half
-          max_dsi_packet_size /= 2; */
-
-       max_data_per_packet = max_dsi_packet_size - 4 - 1;
-
-       max_pixels_per_packet = max_data_per_packet / bytespp;
-
-       DSSDBG("max_pixels_per_packet %d\n", max_pixels_per_packet);
-
-       pixels_left = w * h;
+       switch (dssdev->panel.dsi_pix_fmt) {
+       case OMAP_DSS_DSI_FMT_RGB888:
+               data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
+               break;
+       case OMAP_DSS_DSI_FMT_RGB666:
+               data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
+               break;
+       case OMAP_DSS_DSI_FMT_RGB666_PACKED:
+               data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18;
+               break;
+       case OMAP_DSS_DSI_FMT_RGB565:
+               data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
+               break;
+       default:
+               BUG();
+       };
 
-       DSSDBG("total pixels %d\n", pixels_left);
+       dsi_if_enable(dsidev, false);
+       dsi_vc_enable(dsidev, channel, false);
 
-       data += start_offset;
+       /* MODE, 1 = video mode */
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4);
 
-       while (pixels_left > 0) {
-               /* 0x2c = write_memory_start */
-               /* 0x3c = write_memory_continue */
-               u8 dcs_cmd = first ? 0x2c : 0x3c;
-               int pixels;
-               DSI_DECL_VARS;
-               first = 0;
+       word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8);
 
-#if 1
-               /* using fifo not empty */
-               /* TX_FIFO_NOT_EMPTY */
-               while (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(0)), 5, 5)) {
-                       fifo_stalls++;
-                       if (fifo_stalls > 0xfffff) {
-                               DSSERR("fifo stalls overflow, pixels left %d\n",
-                                               pixels_left);
-                               dsi_if_enable(dsidev, 0);
-                               return -EIO;
-                       }
-                       udelay(1);
-               }
-#elif 1
-               /* using fifo emptiness */
-               while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 <
-                               max_dsi_packet_size) {
-                       fifo_stalls++;
-                       if (fifo_stalls > 0xfffff) {
-                               DSSERR("fifo stalls overflow, pixels left %d\n",
-                                              pixels_left);
-                               dsi_if_enable(dsidev, 0);
-                               return -EIO;
-                       }
-               }
-#else
-               while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS,
-                               7, 0) + 1) * 4 == 0) {
-                       fifo_stalls++;
-                       if (fifo_stalls > 0xfffff) {
-                               DSSERR("fifo stalls overflow, pixels left %d\n",
-                                              pixels_left);
-                               dsi_if_enable(dsidev, 0);
-                               return -EIO;
-                       }
-               }
-#endif
-               pixels = min(max_pixels_per_packet, pixels_left);
+       dsi_vc_write_long_header(dsidev, channel, data_type, word_count, 0);
 
-               pixels_left -= pixels;
+       dsi_vc_enable(dsidev, channel, true);
+       dsi_if_enable(dsidev, true);
 
-               dsi_vc_write_long_header(dsidev, 0, DSI_DT_DCS_LONG_WRITE,
-                               1 + pixels * bytespp, 0);
+       dssdev->manager->enable(dssdev->manager);
 
-               DSI_PUSH(dsidev, 0, dcs_cmd);
+       return 0;
+}
+EXPORT_SYMBOL(dsi_video_mode_enable);
 
-               while (pixels-- > 0) {
-                       u32 pix = __raw_readl(data++);
+void dsi_video_mode_disable(struct omap_dss_device *dssdev, int channel)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
 
-                       DSI_PUSH(dsidev, 0, (pix >> 16) & 0xff);
-                       DSI_PUSH(dsidev, 0, (pix >> 8) & 0xff);
-                       DSI_PUSH(dsidev, 0, (pix >> 0) & 0xff);
+       dsi_if_enable(dsidev, false);
+       dsi_vc_enable(dsidev, channel, false);
 
-                       current_x++;
-                       if (current_x == x+w) {
-                               current_x = x;
-                               data += horiz_inc;
-                       }
-               }
+       /* MODE, 0 = command mode */
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4);
 
-               DSI_FLUSH(dsidev, 0);
-       }
+       dsi_vc_enable(dsidev, channel, true);
+       dsi_if_enable(dsidev, true);
 
-       return 0;
+       dssdev->manager->disable(dssdev->manager);
 }
+EXPORT_SYMBOL(dsi_video_mode_disable);
 
 static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
                u16 x, u16 y, u16 w, u16 h)
@@ -3808,9 +4023,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
        DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
                        x, y, w, h);
 
-       dsi_vc_config_vp(dsidev, channel);
+       dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP);
 
-       bytespp = dssdev->ctrl.pixel_size / 8;
+       bytespp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
        bytespl = w * bytespp;
        bytespf = bytespl * h;
 
@@ -3831,7 +4046,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
        l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
        dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
 
-       dsi_vc_write_long_header(dsidev, channel, DSI_DT_DCS_LONG_WRITE,
+       dsi_vc_write_long_header(dsidev, channel, MIPI_DSI_DCS_LONG_WRITE,
                packet_len, 0);
 
        if (dsi->te_enabled)
@@ -3956,11 +4171,9 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
 
        dsi_perf_mark_setup(dsidev);
 
-       if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
-               dss_setup_partial_planes(dssdev, x, y, w, h,
-                               enlarge_update_area);
-               dispc_set_lcd_size(dssdev->manager->id, *w, *h);
-       }
+       dss_setup_partial_planes(dssdev, x, y, w, h,
+                       enlarge_update_area);
+       dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h);
 
        return 0;
 }
@@ -3982,27 +4195,16 @@ int omap_dsi_update(struct omap_dss_device *dssdev,
         * see rather obscure HW error happening, as DSS halts. */
        BUG_ON(x % 2 == 1);
 
-       if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
-               dsi->framedone_callback = callback;
-               dsi->framedone_data = data;
-
-               dsi->update_region.x = x;
-               dsi->update_region.y = y;
-               dsi->update_region.w = w;
-               dsi->update_region.h = h;
-               dsi->update_region.device = dssdev;
-
-               dsi_update_screen_dispc(dssdev, x, y, w, h);
-       } else {
-               int r;
+       dsi->framedone_callback = callback;
+       dsi->framedone_data = data;
 
-               r = dsi_update_screen_l4(dssdev, x, y, w, h);
-               if (r)
-                       return r;
+       dsi->update_region.x = x;
+       dsi->update_region.y = y;
+       dsi->update_region.w = w;
+       dsi->update_region.h = h;
+       dsi->update_region.device = dssdev;
 
-               dsi_perf_show(dsidev, "L4");
-               callback(0, data);
-       }
+       dsi_update_screen_dispc(dssdev, x, y, w, h);
 
        return 0;
 }
@@ -4013,28 +4215,9 @@ EXPORT_SYMBOL(omap_dsi_update);
 static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 {
        int r;
-       u32 irq;
-
-       irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ?
-               DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2;
 
-       r = omap_dispc_register_isr(dsi_framedone_irq_callback, (void *) dssdev,
-                       irq);
-       if (r) {
-               DSSERR("can't get FRAMEDONE irq\n");
-               return r;
-       }
-
-       dispc_set_lcd_display_type(dssdev->manager->id,
-                       OMAP_DSS_LCD_DISPLAY_TFT);
-
-       dispc_set_parallel_interface_mode(dssdev->manager->id,
-                       OMAP_DSS_PARALLELMODE_DSI);
-       dispc_enable_fifohandcheck(dssdev->manager->id, 1);
-
-       dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size);
-
-       {
+       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
+               u32 irq;
                struct omap_video_timings timings = {
                        .hsw            = 1,
                        .hfp            = 1,
@@ -4044,21 +4227,46 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
                        .vbp            = 0,
                };
 
-               dispc_set_lcd_timings(dssdev->manager->id, &timings);
+               irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ?
+                       DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2;
+
+               r = omap_dispc_register_isr(dsi_framedone_irq_callback,
+                       (void *) dssdev, irq);
+               if (r) {
+                       DSSERR("can't get FRAMEDONE irq\n");
+                       return r;
+               }
+
+               dispc_mgr_enable_stallmode(dssdev->manager->id, true);
+               dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 1);
+
+               dispc_mgr_set_lcd_timings(dssdev->manager->id, &timings);
+       } else {
+               dispc_mgr_enable_stallmode(dssdev->manager->id, false);
+               dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 0);
+
+               dispc_mgr_set_lcd_timings(dssdev->manager->id,
+                       &dssdev->panel.timings);
        }
 
+               dispc_mgr_set_lcd_display_type(dssdev->manager->id,
+                       OMAP_DSS_LCD_DISPLAY_TFT);
+               dispc_mgr_set_tft_data_lines(dssdev->manager->id,
+                       dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt));
        return 0;
 }
 
 static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
 {
-       u32 irq;
+       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
+               u32 irq;
 
-       irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ?
-               DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2;
+               irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ?
+                       DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2;
 
-       omap_dispc_unregister_isr(dsi_framedone_irq_callback, (void *) dssdev,
-                       irq);
+               omap_dispc_unregister_isr(dsi_framedone_irq_callback,
+                       (void *) dssdev, irq);
+       }
 }
 
 static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
@@ -4106,7 +4314,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
                return r;
        }
 
-       r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
+       r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo);
        if (r) {
                DSSERR("Failed to set dispc clocks\n");
                return r;
@@ -4166,10 +4374,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
 
        return 0;
 err3:
-       dsi_cio_uninit(dsidev);
+       dsi_cio_uninit(dssdev);
 err2:
        dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
        dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK);
+       dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
+
 err1:
        dsi_pll_uninit(dsidev, true);
 err0:
@@ -4195,7 +4405,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
 
        dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
        dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK);
-       dsi_cio_uninit(dsidev);
+       dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
+       dsi_cio_uninit(dssdev);
        dsi_pll_uninit(dsidev, disconnect_lanes);
 }
 
@@ -4211,6 +4422,12 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
 
        mutex_lock(&dsi->lock);
 
+       if (dssdev->manager == NULL) {
+               DSSERR("failed to enable display: no manager\n");
+               r = -ENODEV;
+               goto err_start_dev;
+       }
+
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
@@ -4307,9 +4524,10 @@ int dsi_init_display(struct omap_dss_device *dssdev)
 
        DSSDBG("DSI init\n");
 
-       /* XXX these should be figured out dynamically */
-       dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
-               OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
+       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
+               dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
+                       OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
+       }
 
        if (dsi->vdds_dsi_reg == NULL) {
                struct regulator *vdds_dsi;
@@ -4435,10 +4653,7 @@ static int dsi_get_clocks(struct platform_device *dsidev)
 
        dsi->dss_clk = clk;
 
-       if (cpu_is_omap34xx() || cpu_is_omap3630())
-               clk = clk_get(&dsidev->dev, "dss2_alwon_fck");
-       else
-               clk = clk_get(&dsidev->dev, "sys_clk");
+       clk = clk_get(&dsidev->dev, "sys_clk");
        if (IS_ERR(clk)) {
                DSSERR("can't get sys_clk\n");
                clk_put(dsi->dss_clk);
@@ -4462,7 +4677,7 @@ static void dsi_put_clocks(struct platform_device *dsidev)
 }
 
 /* DSI1 HW IP initialisation */
-static int omap_dsi1hw_probe(struct platform_device *dsidev)
+static int omap_dsihw_probe(struct platform_device *dsidev)
 {
        struct omap_display_platform_data *dss_plat_data;
        struct omap_dss_board_info *board_info;
@@ -4483,7 +4698,8 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev)
 
        dss_plat_data = dsidev->dev.platform_data;
        board_info = dss_plat_data->board_data;
-       dsi->dsi_mux_pads = board_info->dsi_mux_pads;
+       dsi->enable_pads = board_info->dsi_enable_pads;
+       dsi->disable_pads = board_info->dsi_disable_pads;
 
        spin_lock_init(&dsi->irq_lock);
        spin_lock_init(&dsi->errors_lock);
@@ -4539,7 +4755,7 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev)
 
        /* DSI VCs initialization */
        for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
-               dsi->vc[i].mode = DSI_VC_MODE_L4;
+               dsi->vc[i].source = DSI_VC_SOURCE_L4;
                dsi->vc[i].dssdev = NULL;
                dsi->vc[i].vc_id = 0;
        }
@@ -4572,7 +4788,7 @@ err_alloc:
        return r;
 }
 
-static int omap_dsi1hw_remove(struct platform_device *dsidev)
+static int omap_dsihw_remove(struct platform_device *dsidev)
 {
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
@@ -4602,10 +4818,6 @@ static int omap_dsi1hw_remove(struct platform_device *dsidev)
 
 static int dsi_runtime_suspend(struct device *dev)
 {
-       struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev));
-
-       clk_disable(dsi->dss_clk);
-
        dispc_runtime_put();
        dss_runtime_put();
 
@@ -4614,7 +4826,6 @@ static int dsi_runtime_suspend(struct device *dev)
 
 static int dsi_runtime_resume(struct device *dev)
 {
-       struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev));
        int r;
 
        r = dss_runtime_get();
@@ -4625,8 +4836,6 @@ static int dsi_runtime_resume(struct device *dev)
        if (r)
                goto err_get_dispc;
 
-       clk_enable(dsi->dss_clk);
-
        return 0;
 
 err_get_dispc:
@@ -4640,11 +4849,11 @@ static const struct dev_pm_ops dsi_pm_ops = {
        .runtime_resume = dsi_runtime_resume,
 };
 
-static struct platform_driver omap_dsi1hw_driver = {
-       .probe          = omap_dsi1hw_probe,
-       .remove         = omap_dsi1hw_remove,
+static struct platform_driver omap_dsihw_driver = {
+       .probe          = omap_dsihw_probe,
+       .remove         = omap_dsihw_remove,
        .driver         = {
-               .name   = "omapdss_dsi1",
+               .name   = "omapdss_dsi",
                .owner  = THIS_MODULE,
                .pm     = &dsi_pm_ops,
        },
@@ -4652,10 +4861,10 @@ static struct platform_driver omap_dsi1hw_driver = {
 
 int dsi_init_platform_driver(void)
 {
-       return platform_driver_register(&omap_dsi1hw_driver);
+       return platform_driver_register(&omap_dsihw_driver);
 }
 
 void dsi_uninit_platform_driver(void)
 {
-       return platform_driver_unregister(&omap_dsi1hw_driver);
+       return platform_driver_unregister(&omap_dsihw_driver);
 }
index 0f9c3a6..3e09726 100644 (file)
@@ -639,6 +639,17 @@ void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi)
        REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */
 }
 
+enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
+{
+       enum omap_display_type displays;
+
+       displays = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
+       if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0)
+               return DSS_VENC_TV_CLK;
+
+       return REG_GET(DSS_CONTROL, 15, 15);
+}
+
 static int dss_get_clocks(void)
 {
        struct clk *clk;
@@ -691,11 +702,6 @@ static void dss_put_clocks(void)
        clk_put(dss.dss_clk);
 }
 
-struct clk *dss_get_ick(void)
-{
-       return clk_get(&dss.pdev->dev, "ick");
-}
-
 int dss_runtime_get(void)
 {
        int r;
@@ -824,13 +830,11 @@ static int omap_dsshw_remove(struct platform_device *pdev)
 static int dss_runtime_suspend(struct device *dev)
 {
        dss_save_context();
-       clk_disable(dss.dss_clk);
        return 0;
 }
 
 static int dss_runtime_resume(struct device *dev)
 {
-       clk_enable(dss.dss_clk);
        dss_restore_context();
        return 0;
 }
index 9c94b11..6308fc5 100644 (file)
@@ -97,10 +97,10 @@ extern unsigned int dss_debug;
 #define FLD_MOD(orig, val, start, end) \
        (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
 
-enum omap_parallel_interface_mode {
-       OMAP_DSS_PARALLELMODE_BYPASS,           /* MIPI DPI */
-       OMAP_DSS_PARALLELMODE_RFBI,             /* MIPI DBI */
-       OMAP_DSS_PARALLELMODE_DSI,
+enum dss_io_pad_mode {
+       DSS_IO_PAD_MODE_RESET,
+       DSS_IO_PAD_MODE_RFBI,
+       DSS_IO_PAD_MODE_BYPASS,
 };
 
 enum dss_hdmi_venc_clk_source_select {
@@ -108,6 +108,11 @@ enum dss_hdmi_venc_clk_source_select {
        DSS_HDMI_M_PCLK = 1,
 };
 
+enum dss_dsi_content_type {
+       DSS_DSI_CONTENT_DCS,
+       DSS_DSI_CONTENT_GENERIC,
+};
+
 struct dss_clock_info {
        /* rates that we get with dividers below */
        unsigned long fck;
@@ -150,16 +155,6 @@ struct dsi_clock_info {
        bool use_sys_clk;
 };
 
-/* HDMI PLL structure */
-struct hdmi_pll_info {
-       u16 regn;
-       u16 regm;
-       u32 regmf;
-       u16 regm2;
-       u16 regsd;
-       u16 dcofreq;
-};
-
 struct seq_file;
 struct platform_device;
 
@@ -209,9 +204,8 @@ void dss_uninit_platform_driver(void);
 int dss_runtime_get(void);
 void dss_runtime_put(void);
 
-struct clk *dss_get_ick(void);
-
 void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
+enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
 const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
 void dss_dump_clocks(struct seq_file *s);
 
@@ -279,6 +273,8 @@ void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
 
 int dsi_init_display(struct omap_dss_device *display);
 void dsi_irq_handler(void);
+u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
+
 unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
 int dsi_pll_set_clock_div(struct platform_device *dsidev,
                struct dsi_clock_info *cinfo);
@@ -309,6 +305,11 @@ static inline int dsi_runtime_get(struct platform_device *dsidev)
 static inline void dsi_runtime_put(struct platform_device *dsidev)
 {
 }
+static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
+{
+       WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__);
+       return 0;
+}
 static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
 {
        WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
@@ -385,90 +386,71 @@ void dispc_disable_sidle(void);
 void dispc_lcd_enable_signal_polarity(bool act_high);
 void dispc_lcd_enable_signal(bool enable);
 void dispc_pck_free_enable(bool enable);
-void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable);
-
-void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height);
 void dispc_set_digit_size(u16 width, u16 height);
-u32 dispc_get_plane_fifo_size(enum omap_plane plane);
-void dispc_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
 void dispc_enable_fifomerge(bool enable);
-u32 dispc_get_burst_size(enum omap_plane plane);
-void dispc_enable_cpr(enum omap_channel channel, bool enable);
-void dispc_set_cpr_coef(enum omap_channel channel,
-               struct omap_dss_cpr_coefs *coefs);
-
-void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
-void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
-void dispc_set_plane_pos(enum omap_plane plane, u16 x, u16 y);
-void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height);
-void dispc_set_channel_out(enum omap_plane plane,
-               enum omap_channel channel_out);
-
 void dispc_enable_gamma_table(bool enable);
-int dispc_setup_plane(enum omap_plane plane,
-                     u32 paddr, u16 screen_width,
-                     u16 pos_x, u16 pos_y,
-                     u16 width, u16 height,
-                     u16 out_width, u16 out_height,
-                     enum omap_color_mode color_mode,
-                     bool ilace,
-                     enum omap_dss_rotation_type rotation_type,
-                     u8 rotation, bool mirror,
-                     u8 global_alpha, u8 pre_mult_alpha,
-                     enum omap_channel channel,
-                     u32 puv_addr);
-
-bool dispc_go_busy(enum omap_channel channel);
-void dispc_go(enum omap_channel channel);
-void dispc_enable_channel(enum omap_channel channel, bool enable);
-bool dispc_is_channel_enabled(enum omap_channel channel);
-int dispc_enable_plane(enum omap_plane plane, bool enable);
-void dispc_enable_replication(enum omap_plane plane, bool enable);
-
-void dispc_set_parallel_interface_mode(enum omap_channel channel,
-               enum omap_parallel_interface_mode mode);
-void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines);
-void dispc_set_lcd_display_type(enum omap_channel channel,
-               enum omap_lcd_display_type type);
 void dispc_set_loadmode(enum omap_dss_load_mode mode);
 
-void dispc_set_default_color(enum omap_channel channel, u32 color);
-u32 dispc_get_default_color(enum omap_channel channel);
-void dispc_set_trans_key(enum omap_channel ch,
-               enum omap_dss_trans_key_type type,
-               u32 trans_key);
-void dispc_get_trans_key(enum omap_channel ch,
-               enum omap_dss_trans_key_type *type,
-               u32 *trans_key);
-void dispc_enable_trans_key(enum omap_channel ch, bool enable);
-void dispc_enable_alpha_blending(enum omap_channel ch, bool enable);
-bool dispc_trans_key_enabled(enum omap_channel ch);
-bool dispc_alpha_blending_enabled(enum omap_channel ch);
-
 bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
-void dispc_set_lcd_timings(enum omap_channel channel,
-               struct omap_video_timings *timings);
 unsigned long dispc_fclk_rate(void);
-unsigned long dispc_lclk_rate(enum omap_channel channel);
-unsigned long dispc_pclk_rate(enum omap_channel channel);
-void dispc_set_pol_freq(enum omap_channel channel,
-               enum omap_panel_config config, u8 acbi, u8 acb);
 void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
                struct dispc_clock_info *cinfo);
 int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
                struct dispc_clock_info *cinfo);
-int dispc_set_clock_div(enum omap_channel channel,
+
+
+u32 dispc_ovl_get_fifo_size(enum omap_plane plane);
+u32 dispc_ovl_get_burst_size(enum omap_plane plane);
+int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
+               bool ilace, enum omap_channel channel, bool replication,
+               u32 fifo_low, u32 fifo_high);
+int dispc_ovl_enable(enum omap_plane plane, bool enable);
+
+
+void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable);
+void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height);
+void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable);
+void dispc_mgr_set_cpr_coef(enum omap_channel channel,
+               struct omap_dss_cpr_coefs *coefs);
+bool dispc_mgr_go_busy(enum omap_channel channel);
+void dispc_mgr_go(enum omap_channel channel);
+void dispc_mgr_enable(enum omap_channel channel, bool enable);
+bool dispc_mgr_is_channel_enabled(enum omap_channel channel);
+void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode);
+void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable);
+void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines);
+void dispc_mgr_set_lcd_display_type(enum omap_channel channel,
+               enum omap_lcd_display_type type);
+void dispc_mgr_set_default_color(enum omap_channel channel, u32 color);
+u32 dispc_mgr_get_default_color(enum omap_channel channel);
+void dispc_mgr_set_trans_key(enum omap_channel ch,
+               enum omap_dss_trans_key_type type,
+               u32 trans_key);
+void dispc_mgr_get_trans_key(enum omap_channel ch,
+               enum omap_dss_trans_key_type *type,
+               u32 *trans_key);
+void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable);
+void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable);
+bool dispc_mgr_trans_key_enabled(enum omap_channel ch);
+bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch);
+void dispc_mgr_set_lcd_timings(enum omap_channel channel,
+               struct omap_video_timings *timings);
+void dispc_mgr_set_pol_freq(enum omap_channel channel,
+               enum omap_panel_config config, u8 acbi, u8 acb);
+unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);
+unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);
+int dispc_mgr_set_clock_div(enum omap_channel channel,
                struct dispc_clock_info *cinfo);
-int dispc_get_clock_div(enum omap_channel channel,
+int dispc_mgr_get_clock_div(enum omap_channel channel,
                struct dispc_clock_info *cinfo);
 
-
 /* VENC */
 #ifdef CONFIG_OMAP2_DSS_VENC
 int venc_init_platform_driver(void);
 void venc_uninit_platform_driver(void);
 void venc_dump_regs(struct seq_file *s);
 int venc_init_display(struct omap_dss_device *display);
+unsigned long venc_get_pixel_clock(void);
 #else
 static inline int venc_init_platform_driver(void)
 {
@@ -477,6 +459,11 @@ static inline int venc_init_platform_driver(void)
 static inline void venc_uninit_platform_driver(void)
 {
 }
+static inline unsigned long venc_get_pixel_clock(void)
+{
+       WARN("%s: VENC not compiled in, returning pclk as 0\n", __func__);
+       return 0;
+}
 #endif
 
 /* HDMI */
@@ -484,6 +471,8 @@ static inline void venc_uninit_platform_driver(void)
 int hdmi_init_platform_driver(void);
 void hdmi_uninit_platform_driver(void);
 int hdmi_init_display(struct omap_dss_device *dssdev);
+unsigned long hdmi_get_pixel_clock(void);
+void hdmi_dump_regs(struct seq_file *s);
 #else
 static inline int hdmi_init_display(struct omap_dss_device *dssdev)
 {
@@ -496,12 +485,19 @@ static inline int hdmi_init_platform_driver(void)
 static inline void hdmi_uninit_platform_driver(void)
 {
 }
+static inline unsigned long hdmi_get_pixel_clock(void)
+{
+       WARN("%s: HDMI not compiled in, returning pclk as 0\n", __func__);
+       return 0;
+}
 #endif
 int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev);
 void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev);
 int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
                                        struct omap_video_timings *timings);
+int omapdss_hdmi_read_edid(u8 *buf, int len);
+bool omapdss_hdmi_detect(void);
 int hdmi_panel_init(void);
 void hdmi_panel_exit(void);
 
index b415c4e..b402699 100644 (file)
@@ -47,6 +47,7 @@ struct omap_dss_features {
        const int num_ovls;
        const enum omap_display_type *supported_displays;
        const enum omap_color_mode *supported_color_modes;
+       const enum omap_overlay_caps *overlay_caps;
        const char * const *clksrc_names;
        const struct dss_param_range *dss_params;
 
@@ -209,6 +210,68 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = {
        OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
        OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
        OMAP_DSS_COLOR_RGBX32,
+
+       /* OMAP_DSS_VIDEO3 */
+       OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+       OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+       OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+       OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+       OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+       OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+       OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+       OMAP_DSS_COLOR_RGBX32,
+};
+
+static const enum omap_overlay_caps omap2_dss_overlay_caps[] = {
+       /* OMAP_DSS_GFX */
+       0,
+
+       /* OMAP_DSS_VIDEO1 */
+       OMAP_DSS_OVL_CAP_SCALE,
+
+       /* OMAP_DSS_VIDEO2 */
+       OMAP_DSS_OVL_CAP_SCALE,
+};
+
+static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = {
+       /* OMAP_DSS_GFX */
+       OMAP_DSS_OVL_CAP_GLOBAL_ALPHA,
+
+       /* OMAP_DSS_VIDEO1 */
+       OMAP_DSS_OVL_CAP_SCALE,
+
+       /* OMAP_DSS_VIDEO2 */
+       OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA,
+};
+
+static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = {
+       /* OMAP_DSS_GFX */
+       OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA,
+
+       /* OMAP_DSS_VIDEO1 */
+       OMAP_DSS_OVL_CAP_SCALE,
+
+       /* OMAP_DSS_VIDEO2 */
+       OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
+               OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA,
+};
+
+static const enum omap_overlay_caps omap4_dss_overlay_caps[] = {
+       /* OMAP_DSS_GFX */
+       OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
+               OMAP_DSS_OVL_CAP_ZORDER,
+
+       /* OMAP_DSS_VIDEO1 */
+       OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
+               OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER,
+
+       /* OMAP_DSS_VIDEO2 */
+       OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
+               OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER,
+
+       /* OMAP_DSS_VIDEO3 */
+       OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
+               OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER,
 };
 
 static const char * const omap2_dss_clk_source_names[] = {
@@ -233,32 +296,38 @@ static const char * const omap4_dss_clk_source_names[] = {
 
 static const struct dss_param_range omap2_dss_param_range[] = {
        [FEAT_PARAM_DSS_FCK]                    = { 0, 173000000 },
+       [FEAT_PARAM_DSS_PCD]                    = { 2, 255 },
        [FEAT_PARAM_DSIPLL_REGN]                = { 0, 0 },
        [FEAT_PARAM_DSIPLL_REGM]                = { 0, 0 },
        [FEAT_PARAM_DSIPLL_REGM_DISPC]          = { 0, 0 },
        [FEAT_PARAM_DSIPLL_REGM_DSI]            = { 0, 0 },
        [FEAT_PARAM_DSIPLL_FINT]                = { 0, 0 },
        [FEAT_PARAM_DSIPLL_LPDIV]               = { 0, 0 },
+       [FEAT_PARAM_DOWNSCALE]                  = { 1, 2 },
 };
 
 static const struct dss_param_range omap3_dss_param_range[] = {
        [FEAT_PARAM_DSS_FCK]                    = { 0, 173000000 },
+       [FEAT_PARAM_DSS_PCD]                    = { 1, 255 },
        [FEAT_PARAM_DSIPLL_REGN]                = { 0, (1 << 7) - 1 },
        [FEAT_PARAM_DSIPLL_REGM]                = { 0, (1 << 11) - 1 },
        [FEAT_PARAM_DSIPLL_REGM_DISPC]          = { 0, (1 << 4) - 1 },
        [FEAT_PARAM_DSIPLL_REGM_DSI]            = { 0, (1 << 4) - 1 },
        [FEAT_PARAM_DSIPLL_FINT]                = { 750000, 2100000 },
        [FEAT_PARAM_DSIPLL_LPDIV]               = { 1, (1 << 13) - 1},
+       [FEAT_PARAM_DOWNSCALE]                  = { 1, 4 },
 };
 
 static const struct dss_param_range omap4_dss_param_range[] = {
        [FEAT_PARAM_DSS_FCK]                    = { 0, 186000000 },
+       [FEAT_PARAM_DSS_PCD]                    = { 1, 255 },
        [FEAT_PARAM_DSIPLL_REGN]                = { 0, (1 << 8) - 1 },
        [FEAT_PARAM_DSIPLL_REGM]                = { 0, (1 << 12) - 1 },
        [FEAT_PARAM_DSIPLL_REGM_DISPC]          = { 0, (1 << 5) - 1 },
        [FEAT_PARAM_DSIPLL_REGM_DSI]            = { 0, (1 << 5) - 1 },
        [FEAT_PARAM_DSIPLL_FINT]                = { 500000, 2500000 },
        [FEAT_PARAM_DSIPLL_LPDIV]               = { 0, (1 << 13) - 1 },
+       [FEAT_PARAM_DOWNSCALE]                  = { 1, 4 },
 };
 
 /* OMAP2 DSS Features */
@@ -275,6 +344,7 @@ static const struct omap_dss_features omap2_dss_features = {
        .num_ovls = 3,
        .supported_displays = omap2_dss_supported_displays,
        .supported_color_modes = omap2_dss_supported_color_modes,
+       .overlay_caps = omap2_dss_overlay_caps,
        .clksrc_names = omap2_dss_clk_source_names,
        .dss_params = omap2_dss_param_range,
        .buffer_size_unit = 1,
@@ -287,18 +357,19 @@ static const struct omap_dss_features omap3430_dss_features = {
        .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
 
        .has_feature    =
-               FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
+               FEAT_LCDENABLEPOL |
                FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
                FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
                FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF |
                FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC |
                FEAT_VENC_REQUIRES_TV_DAC_CLK | FEAT_CPR | FEAT_PRELOAD |
-               FEAT_FIR_COEF_V,
+               FEAT_FIR_COEF_V | FEAT_ALPHA_FIXED_ZORDER,
 
        .num_mgrs = 2,
        .num_ovls = 3,
        .supported_displays = omap3430_dss_supported_displays,
        .supported_color_modes = omap3_dss_supported_color_modes,
+       .overlay_caps = omap3430_dss_overlay_caps,
        .clksrc_names = omap3_dss_clk_source_names,
        .dss_params = omap3_dss_param_range,
        .buffer_size_unit = 1,
@@ -310,18 +381,19 @@ static const struct omap_dss_features omap3630_dss_features = {
        .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
 
        .has_feature    =
-               FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
+               FEAT_LCDENABLEPOL |
                FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
-               FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
+               FEAT_FUNCGATED |
                FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
                FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG |
                FEAT_DSI_PLL_FREQSEL | FEAT_CPR | FEAT_PRELOAD |
-               FEAT_FIR_COEF_V,
+               FEAT_FIR_COEF_V | FEAT_ALPHA_FIXED_ZORDER,
 
        .num_mgrs = 2,
        .num_ovls = 3,
        .supported_displays = omap3630_dss_supported_displays,
        .supported_color_modes = omap3_dss_supported_color_modes,
+       .overlay_caps = omap3630_dss_overlay_caps,
        .clksrc_names = omap3_dss_clk_source_names,
        .dss_params = omap3_dss_param_range,
        .buffer_size_unit = 1,
@@ -335,17 +407,18 @@ static const struct omap_dss_features omap4430_es1_0_dss_features  = {
        .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
 
        .has_feature    =
-               FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
-               FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
+               FEAT_MGR_LCD2 |
                FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
                FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
                FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 |
-               FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V,
+               FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V |
+               FEAT_ALPHA_FREE_ZORDER,
 
        .num_mgrs = 3,
-       .num_ovls = 3,
+       .num_ovls = 4,
        .supported_displays = omap4_dss_supported_displays,
        .supported_color_modes = omap4_dss_supported_color_modes,
+       .overlay_caps = omap4_dss_overlay_caps,
        .clksrc_names = omap4_dss_clk_source_names,
        .dss_params = omap4_dss_param_range,
        .buffer_size_unit = 16,
@@ -358,24 +431,50 @@ static const struct omap_dss_features omap4_dss_features = {
        .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
 
        .has_feature    =
-               FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
-               FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
+               FEAT_MGR_LCD2 |
                FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
                FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
                FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE |
                FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | FEAT_CPR |
-               FEAT_PRELOAD | FEAT_FIR_COEF_V,
+               FEAT_PRELOAD | FEAT_FIR_COEF_V | FEAT_ALPHA_FREE_ZORDER,
 
        .num_mgrs = 3,
-       .num_ovls = 3,
+       .num_ovls = 4,
        .supported_displays = omap4_dss_supported_displays,
        .supported_color_modes = omap4_dss_supported_color_modes,
+       .overlay_caps = omap4_dss_overlay_caps,
        .clksrc_names = omap4_dss_clk_source_names,
        .dss_params = omap4_dss_param_range,
        .buffer_size_unit = 16,
        .burst_size_unit = 16,
 };
 
+#if defined(CONFIG_OMAP4_DSS_HDMI)
+/* HDMI OMAP4 Functions*/
+static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
+
+       .video_configure        =       ti_hdmi_4xxx_basic_configure,
+       .phy_enable             =       ti_hdmi_4xxx_phy_enable,
+       .phy_disable            =       ti_hdmi_4xxx_phy_disable,
+       .read_edid              =       ti_hdmi_4xxx_read_edid,
+       .detect                 =       ti_hdmi_4xxx_detect,
+       .pll_enable             =       ti_hdmi_4xxx_pll_enable,
+       .pll_disable            =       ti_hdmi_4xxx_pll_disable,
+       .video_enable           =       ti_hdmi_4xxx_wp_video_start,
+       .dump_wrapper           =       ti_hdmi_4xxx_wp_dump,
+       .dump_core              =       ti_hdmi_4xxx_core_dump,
+       .dump_pll               =       ti_hdmi_4xxx_pll_dump,
+       .dump_phy               =       ti_hdmi_4xxx_phy_dump,
+
+};
+
+void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data)
+{
+       if (cpu_is_omap44xx())
+               ip_data->ops = &omap4_hdmi_functions;
+}
+#endif
+
 /* Functions returning values related to a DSS feature */
 int dss_feat_get_num_mgrs(void)
 {
@@ -407,6 +506,11 @@ enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
        return omap_current_dss_features->supported_color_modes[plane];
 }
 
+enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane)
+{
+       return omap_current_dss_features->overlay_caps[plane];
+}
+
 bool dss_feat_color_mode_supported(enum omap_plane plane,
                enum omap_color_mode color_mode)
 {
index b7398cb..6a6c05d 100644 (file)
 #ifndef __OMAP2_DSS_FEATURES_H
 #define __OMAP2_DSS_FEATURES_H
 
+#if defined(CONFIG_OMAP4_DSS_HDMI)
+#include "ti_hdmi.h"
+#endif
+
 #define MAX_DSS_MANAGERS       3
-#define MAX_DSS_OVERLAYS       3
+#define MAX_DSS_OVERLAYS       4
 #define MAX_DSS_LCD_MANAGERS   2
 #define MAX_NUM_DSI            2
 
 /* DSS has feature id */
 enum dss_feat_id {
-       FEAT_GLOBAL_ALPHA               = 1 << 0,
-       FEAT_GLOBAL_ALPHA_VID1          = 1 << 1,
-       FEAT_PRE_MULT_ALPHA             = 1 << 2,
        FEAT_LCDENABLEPOL               = 1 << 3,
        FEAT_LCDENABLESIGNAL            = 1 << 4,
        FEAT_PCKFREEENABLE              = 1 << 5,
@@ -55,6 +56,8 @@ enum dss_feat_id {
        FEAT_CPR                        = 1 << 23,
        FEAT_PRELOAD                    = 1 << 24,
        FEAT_FIR_COEF_V                 = 1 << 25,
+       FEAT_ALPHA_FIXED_ZORDER         = 1 << 26,
+       FEAT_ALPHA_FREE_ZORDER          = 1 << 27,
 };
 
 /* DSS register field id */
@@ -75,12 +78,14 @@ enum dss_feat_reg_field {
 
 enum dss_range_param {
        FEAT_PARAM_DSS_FCK,
+       FEAT_PARAM_DSS_PCD,
        FEAT_PARAM_DSIPLL_REGN,
        FEAT_PARAM_DSIPLL_REGM,
        FEAT_PARAM_DSIPLL_REGM_DISPC,
        FEAT_PARAM_DSIPLL_REGM_DSI,
        FEAT_PARAM_DSIPLL_FINT,
        FEAT_PARAM_DSIPLL_LPDIV,
+       FEAT_PARAM_DOWNSCALE,
 };
 
 /* DSS Feature Functions */
@@ -90,6 +95,7 @@ unsigned long dss_feat_get_param_min(enum dss_range_param param);
 unsigned long dss_feat_get_param_max(enum dss_range_param param);
 enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
 enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
+enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane);
 bool dss_feat_color_mode_supported(enum omap_plane plane,
                enum omap_color_mode color_mode);
 const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id);
@@ -100,4 +106,7 @@ u32 dss_feat_get_burst_size_unit(void);             /* in bytes */
 bool dss_has_feature(enum dss_feat_id id);
 void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
 void dss_features_init(void);
+#if defined(CONFIG_OMAP4_DSS_HDMI)
+void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data);
+#endif
 #endif
index 256f27a..3262f0f 100644 (file)
        defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
+#include "ti_hdmi_4xxx_ip.h"
 #endif
 
+#include "ti_hdmi.h"
 #include "dss.h"
-#include "hdmi.h"
 #include "dss_features.h"
 
+#define HDMI_WP                        0x0
+#define HDMI_CORE_SYS          0x400
+#define HDMI_CORE_AV           0x900
+#define HDMI_PLLCTRL           0x200
+#define HDMI_PHY               0x300
+
+/* HDMI EDID Length move this */
+#define HDMI_EDID_MAX_LENGTH                   256
+#define EDID_TIMING_DESCRIPTOR_SIZE            0x12
+#define EDID_DESCRIPTOR_BLOCK0_ADDRESS         0x36
+#define EDID_DESCRIPTOR_BLOCK1_ADDRESS         0x80
+#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR     4
+#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR     4
+
+#define OMAP_HDMI_TIMINGS_NB                   34
+
+#define HDMI_DEFAULT_REGN 16
+#define HDMI_DEFAULT_REGM2 1
+
 static struct {
        struct mutex lock;
        struct omap_display_platform_data *pdata;
        struct platform_device *pdev;
-       void __iomem *base_wp;  /* HDMI wrapper */
+       struct hdmi_ip_data ip_data;
        int code;
        int mode;
-       u8 edid[HDMI_EDID_MAX_LENGTH];
-       u8 edid_set;
-       bool custom_set;
-       struct hdmi_config cfg;
 
        struct clk *sys_clk;
-       struct clk *hdmi_clk;
 } hdmi;
 
 /*
@@ -144,30 +159,6 @@ static const int code_vesa[85] = {
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, 27, 28, -1, 33};
 
-static const u8 edid_header[8] = {0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0};
-
-static inline void hdmi_write_reg(const struct hdmi_reg idx, u32 val)
-{
-       __raw_writel(val, hdmi.base_wp + idx.idx);
-}
-
-static inline u32 hdmi_read_reg(const struct hdmi_reg idx)
-{
-       return __raw_readl(hdmi.base_wp + idx.idx);
-}
-
-static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx,
-                               int b2, int b1, u32 val)
-{
-       u32 t = 0;
-       while (val != REG_GET(idx, b2, b1)) {
-               udelay(1);
-               if (t++ > 10000)
-                       return !val;
-       }
-       return val;
-}
-
 static int hdmi_runtime_get(void)
 {
        int r;
@@ -193,304 +184,7 @@ int hdmi_init_display(struct omap_dss_device *dssdev)
 {
        DSSDBG("init_display\n");
 
-       return 0;
-}
-
-static int hdmi_pll_init(enum hdmi_clk_refsel refsel, int dcofreq,
-               struct hdmi_pll_info *fmt, u16 sd)
-{
-       u32 r;
-
-       /* PLL start always use manual mode */
-       REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
-
-       r = hdmi_read_reg(PLLCTRL_CFG1);
-       r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
-       r = FLD_MOD(r, fmt->regn, 8, 1);  /* CFG1_PLL_REGN */
-
-       hdmi_write_reg(PLLCTRL_CFG1, r);
-
-       r = hdmi_read_reg(PLLCTRL_CFG2);
-
-       r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
-       r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
-       r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
-
-       if (dcofreq) {
-               /* divider programming for frequency beyond 1000Mhz */
-               REG_FLD_MOD(PLLCTRL_CFG3, sd, 17, 10);
-               r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
-       } else {
-               r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
-       }
-
-       hdmi_write_reg(PLLCTRL_CFG2, r);
-
-       r = hdmi_read_reg(PLLCTRL_CFG4);
-       r = FLD_MOD(r, fmt->regm2, 24, 18);
-       r = FLD_MOD(r, fmt->regmf, 17, 0);
-
-       hdmi_write_reg(PLLCTRL_CFG4, r);
-
-       /* go now */
-       REG_FLD_MOD(PLLCTRL_PLL_GO, 0x1, 0, 0);
-
-       /* wait for bit change */
-       if (hdmi_wait_for_bit_change(PLLCTRL_PLL_GO, 0, 0, 1) != 1) {
-               DSSERR("PLL GO bit not set\n");
-               return -ETIMEDOUT;
-       }
-
-       /* Wait till the lock bit is set in PLL status */
-       if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
-               DSSWARN("cannot lock PLL\n");
-               DSSWARN("CFG1 0x%x\n",
-                       hdmi_read_reg(PLLCTRL_CFG1));
-               DSSWARN("CFG2 0x%x\n",
-                       hdmi_read_reg(PLLCTRL_CFG2));
-               DSSWARN("CFG4 0x%x\n",
-                       hdmi_read_reg(PLLCTRL_CFG4));
-               return -ETIMEDOUT;
-       }
-
-       DSSDBG("PLL locked!\n");
-
-       return 0;
-}
-
-/* PHY_PWR_CMD */
-static int hdmi_set_phy_pwr(enum hdmi_phy_pwr val)
-{
-       /* Command for power control of HDMI PHY */
-       REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 7, 6);
-
-       /* Status of the power control of HDMI PHY */
-       if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 5, 4, val) != val) {
-               DSSERR("Failed to set PHY power mode to %d\n", val);
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-/* PLL_PWR_CMD */
-static int hdmi_set_pll_pwr(enum hdmi_pll_pwr val)
-{
-       /* Command for power control of HDMI PLL */
-       REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 3, 2);
-
-       /* wait till PHY_PWR_STATUS is set */
-       if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 1, 0, val) != val) {
-               DSSERR("Failed to set PHY_PWR_STATUS\n");
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-static int hdmi_pll_reset(void)
-{
-       /* SYSRESET  controlled by power FSM */
-       REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 3, 3);
-
-       /* READ 0x0 reset is in progress */
-       if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 0, 0, 1) != 1) {
-               DSSERR("Failed to sysreset PLL\n");
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-static int hdmi_phy_init(void)
-{
-       u16 r = 0;
-
-       r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_LDOON);
-       if (r)
-               return r;
-
-       r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_TXON);
-       if (r)
-               return r;
-
-       /*
-        * Read address 0 in order to get the SCP reset done completed
-        * Dummy access performed to make sure reset is done
-        */
-       hdmi_read_reg(HDMI_TXPHY_TX_CTRL);
-
-       /*
-        * Write to phy address 0 to configure the clock
-        * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
-        */
-       REG_FLD_MOD(HDMI_TXPHY_TX_CTRL, 0x1, 31, 30);
-
-       /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
-       hdmi_write_reg(HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
-
-       /* Setup max LDO voltage */
-       REG_FLD_MOD(HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
-
-       /* Write to phy address 3 to change the polarity control */
-       REG_FLD_MOD(HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);
-
-       return 0;
-}
-
-static int hdmi_pll_program(struct hdmi_pll_info *fmt)
-{
-       u16 r = 0;
-       enum hdmi_clk_refsel refsel;
-
-       r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
-       if (r)
-               return r;
-
-       r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
-       if (r)
-               return r;
-
-       r = hdmi_pll_reset();
-       if (r)
-               return r;
-
-       refsel = HDMI_REFSEL_SYSCLK;
-
-       r = hdmi_pll_init(refsel, fmt->dcofreq, fmt, fmt->regsd);
-       if (r)
-               return r;
-
-       return 0;
-}
-
-static void hdmi_phy_off(void)
-{
-       hdmi_set_phy_pwr(HDMI_PHYPWRCMD_OFF);
-}
-
-static int hdmi_core_ddc_edid(u8 *pedid, int ext)
-{
-       u32 i, j;
-       char checksum = 0;
-       u32 offset = 0;
-
-       /* Turn on CLK for DDC */
-       REG_FLD_MOD(HDMI_CORE_AV_DPD, 0x7, 2, 0);
-
-       /*
-        * SW HACK : Without the Delay DDC(i2c bus) reads 0 values /
-        * right shifted values( The behavior is not consistent and seen only
-        * with some TV's)
-        */
-       usleep_range(800, 1000);
-
-       if (!ext) {
-               /* Clk SCL Devices */
-               REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0xA, 3, 0);
-
-               /* HDMI_CORE_DDC_STATUS_IN_PROG */
-               if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS,
-                                               4, 4, 0) != 0) {
-                       DSSERR("Failed to program DDC\n");
-                       return -ETIMEDOUT;
-               }
-
-               /* Clear FIFO */
-               REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x9, 3, 0);
-
-               /* HDMI_CORE_DDC_STATUS_IN_PROG */
-               if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS,
-                                               4, 4, 0) != 0) {
-                       DSSERR("Failed to program DDC\n");
-                       return -ETIMEDOUT;
-               }
-
-       } else {
-               if (ext % 2 != 0)
-                       offset = 0x80;
-       }
-
-       /* Load Segment Address Register */
-       REG_FLD_MOD(HDMI_CORE_DDC_SEGM, ext/2, 7, 0);
-
-       /* Load Slave Address Register */
-       REG_FLD_MOD(HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1);
-
-       /* Load Offset Address Register */
-       REG_FLD_MOD(HDMI_CORE_DDC_OFFSET, offset, 7, 0);
-
-       /* Load Byte Count */
-       REG_FLD_MOD(HDMI_CORE_DDC_COUNT1, 0x80, 7, 0);
-       REG_FLD_MOD(HDMI_CORE_DDC_COUNT2, 0x0, 1, 0);
-
-       /* Set DDC_CMD */
-       if (ext)
-               REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x4, 3, 0);
-       else
-               REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x2, 3, 0);
-
-       /* HDMI_CORE_DDC_STATUS_BUS_LOW */
-       if (REG_GET(HDMI_CORE_DDC_STATUS, 6, 6) == 1) {
-               DSSWARN("I2C Bus Low?\n");
-               return -EIO;
-       }
-       /* HDMI_CORE_DDC_STATUS_NO_ACK */
-       if (REG_GET(HDMI_CORE_DDC_STATUS, 5, 5) == 1) {
-               DSSWARN("I2C No Ack\n");
-               return -EIO;
-       }
-
-       i = ext * 128;
-       j = 0;
-       while (((REG_GET(HDMI_CORE_DDC_STATUS, 4, 4) == 1) ||
-                       (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0)) &&
-                       j < 128) {
-
-               if (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0) {
-                       /* FIFO not empty */
-                       pedid[i++] = REG_GET(HDMI_CORE_DDC_DATA, 7, 0);
-                       j++;
-               }
-       }
-
-       for (j = 0; j < 128; j++)
-               checksum += pedid[j];
-
-       if (checksum != 0) {
-               DSSERR("E-EDID checksum failed!!\n");
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int read_edid(u8 *pedid, u16 max_length)
-{
-       int r = 0, n = 0, i = 0;
-       int max_ext_blocks = (max_length / 128) - 1;
-
-       r = hdmi_core_ddc_edid(pedid, 0);
-       if (r) {
-               return r;
-       } else {
-               n = pedid[0x7e];
-
-               /*
-                * README: need to comply with max_length set by the caller.
-                * Better implementation should be to allocate necessary
-                * memory to store EDID according to nb_block field found
-                * in first block
-                */
-               if (n > max_ext_blocks)
-                       n = max_ext_blocks;
-
-               for (i = 1; i <= n; i++) {
-                       r = hdmi_core_ddc_edid(pedid, i);
-                       if (r)
-                               return r;
-               }
-       }
+       dss_init_hdmi_ip_ops(&hdmi.ip_data);
        return 0;
 }
 
@@ -518,7 +212,7 @@ static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
 {
        int i = 0, code = -1, temp_vsync = 0, temp_hsync = 0;
        int timing_vsync = 0, timing_hsync = 0;
-       struct omap_video_timings temp;
+       struct hdmi_video_timings temp;
        struct hdmi_cm cm = {-1};
        DSSDBG("hdmi_get_code\n");
 
@@ -556,500 +250,6 @@ static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
        return cm;
 }
 
-static void get_horz_vert_timing_info(int current_descriptor_addrs, u8 *edid ,
-               struct omap_video_timings *timings)
-{
-       /* X and Y resolution */
-       timings->x_res = (((edid[current_descriptor_addrs + 4] & 0xF0) << 4) |
-                        edid[current_descriptor_addrs + 2]);
-       timings->y_res = (((edid[current_descriptor_addrs + 7] & 0xF0) << 4) |
-                        edid[current_descriptor_addrs + 5]);
-
-       timings->pixel_clock = ((edid[current_descriptor_addrs + 1] << 8) |
-                               edid[current_descriptor_addrs]);
-
-       timings->pixel_clock = 10 * timings->pixel_clock;
-
-       /* HORIZONTAL FRONT PORCH */
-       timings->hfp = edid[current_descriptor_addrs + 8] |
-                       ((edid[current_descriptor_addrs + 11] & 0xc0) << 2);
-       /* HORIZONTAL SYNC WIDTH */
-       timings->hsw = edid[current_descriptor_addrs + 9] |
-                       ((edid[current_descriptor_addrs + 11] & 0x30) << 4);
-       /* HORIZONTAL BACK PORCH */
-       timings->hbp = (((edid[current_descriptor_addrs + 4] & 0x0F) << 8) |
-                       edid[current_descriptor_addrs + 3]) -
-                       (timings->hfp + timings->hsw);
-       /* VERTICAL FRONT PORCH */
-       timings->vfp = ((edid[current_descriptor_addrs + 10] & 0xF0) >> 4) |
-                       ((edid[current_descriptor_addrs + 11] & 0x0f) << 2);
-       /* VERTICAL SYNC WIDTH */
-       timings->vsw = (edid[current_descriptor_addrs + 10] & 0x0F) |
-                       ((edid[current_descriptor_addrs + 11] & 0x03) << 4);
-       /* VERTICAL BACK PORCH */
-       timings->vbp = (((edid[current_descriptor_addrs + 7] & 0x0F) << 8) |
-                       edid[current_descriptor_addrs + 6]) -
-                       (timings->vfp + timings->vsw);
-
-}
-
-/* Description : This function gets the resolution information from EDID */
-static void get_edid_timing_data(u8 *edid)
-{
-       u8 count;
-       u16 current_descriptor_addrs;
-       struct hdmi_cm cm;
-       struct omap_video_timings edid_timings;
-
-       /* search block 0, there are 4 DTDs arranged in priority order */
-       for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) {
-               current_descriptor_addrs =
-                       EDID_DESCRIPTOR_BLOCK0_ADDRESS +
-                       count * EDID_TIMING_DESCRIPTOR_SIZE;
-               get_horz_vert_timing_info(current_descriptor_addrs,
-                               edid, &edid_timings);
-               cm = hdmi_get_code(&edid_timings);
-               DSSDBG("Block0[%d] value matches code = %d , mode = %d\n",
-                       count, cm.code, cm.mode);
-               if (cm.code == -1) {
-                       continue;
-               } else {
-                       hdmi.code = cm.code;
-                       hdmi.mode = cm.mode;
-                       DSSDBG("code = %d , mode = %d\n",
-                               hdmi.code, hdmi.mode);
-                       return;
-               }
-       }
-       if (edid[0x7e] != 0x00) {
-               for (count = 0; count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR;
-                       count++) {
-                       current_descriptor_addrs =
-                       EDID_DESCRIPTOR_BLOCK1_ADDRESS +
-                       count * EDID_TIMING_DESCRIPTOR_SIZE;
-                       get_horz_vert_timing_info(current_descriptor_addrs,
-                                               edid, &edid_timings);
-                       cm = hdmi_get_code(&edid_timings);
-                       DSSDBG("Block1[%d] value matches code = %d, mode = %d",
-                               count, cm.code, cm.mode);
-                       if (cm.code == -1) {
-                               continue;
-                       } else {
-                               hdmi.code = cm.code;
-                               hdmi.mode = cm.mode;
-                               DSSDBG("code = %d , mode = %d\n",
-                                       hdmi.code, hdmi.mode);
-                               return;
-                       }
-               }
-       }
-
-       DSSINFO("no valid timing found , falling back to VGA\n");
-       hdmi.code = 4; /* setting default value of 640 480 VGA */
-       hdmi.mode = HDMI_DVI;
-}
-
-static void hdmi_read_edid(struct omap_video_timings *dp)
-{
-       int ret = 0, code;
-
-       memset(hdmi.edid, 0, HDMI_EDID_MAX_LENGTH);
-
-       if (!hdmi.edid_set)
-               ret = read_edid(hdmi.edid, HDMI_EDID_MAX_LENGTH);
-
-       if (!ret) {
-               if (!memcmp(hdmi.edid, edid_header, sizeof(edid_header))) {
-                       /* search for timings of default resolution */
-                       get_edid_timing_data(hdmi.edid);
-                       hdmi.edid_set = true;
-               }
-       } else {
-               DSSWARN("failed to read E-EDID\n");
-       }
-
-       if (!hdmi.edid_set) {
-               DSSINFO("fallback to VGA\n");
-               hdmi.code = 4; /* setting default value of 640 480 VGA */
-               hdmi.mode = HDMI_DVI;
-       }
-
-       code = get_timings_index();
-
-       *dp = cea_vesa_timings[code].timings;
-}
-
-static void hdmi_core_init(struct hdmi_core_video_config *video_cfg,
-                       struct hdmi_core_infoframe_avi *avi_cfg,
-                       struct hdmi_core_packet_enable_repeat *repeat_cfg)
-{
-       DSSDBG("Enter hdmi_core_init\n");
-
-       /* video core */
-       video_cfg->ip_bus_width = HDMI_INPUT_8BIT;
-       video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT;
-       video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE;
-       video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE;
-       video_cfg->hdmi_dvi = HDMI_DVI;
-       video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK;
-
-       /* info frame */
-       avi_cfg->db1_format = 0;
-       avi_cfg->db1_active_info = 0;
-       avi_cfg->db1_bar_info_dv = 0;
-       avi_cfg->db1_scan_info = 0;
-       avi_cfg->db2_colorimetry = 0;
-       avi_cfg->db2_aspect_ratio = 0;
-       avi_cfg->db2_active_fmt_ar = 0;
-       avi_cfg->db3_itc = 0;
-       avi_cfg->db3_ec = 0;
-       avi_cfg->db3_q_range = 0;
-       avi_cfg->db3_nup_scaling = 0;
-       avi_cfg->db4_videocode = 0;
-       avi_cfg->db5_pixel_repeat = 0;
-       avi_cfg->db6_7_line_eoftop = 0 ;
-       avi_cfg->db8_9_line_sofbottom = 0;
-       avi_cfg->db10_11_pixel_eofleft = 0;
-       avi_cfg->db12_13_pixel_sofright = 0;
-
-       /* packet enable and repeat */
-       repeat_cfg->audio_pkt = 0;
-       repeat_cfg->audio_pkt_repeat = 0;
-       repeat_cfg->avi_infoframe = 0;
-       repeat_cfg->avi_infoframe_repeat = 0;
-       repeat_cfg->gen_cntrl_pkt = 0;
-       repeat_cfg->gen_cntrl_pkt_repeat = 0;
-       repeat_cfg->generic_pkt = 0;
-       repeat_cfg->generic_pkt_repeat = 0;
-}
-
-static void hdmi_core_powerdown_disable(void)
-{
-       DSSDBG("Enter hdmi_core_powerdown_disable\n");
-       REG_FLD_MOD(HDMI_CORE_CTRL1, 0x0, 0, 0);
-}
-
-static void hdmi_core_swreset_release(void)
-{
-       DSSDBG("Enter hdmi_core_swreset_release\n");
-       REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x0, 0, 0);
-}
-
-static void hdmi_core_swreset_assert(void)
-{
-       DSSDBG("Enter hdmi_core_swreset_assert\n");
-       REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x1, 0, 0);
-}
-
-/* DSS_HDMI_CORE_VIDEO_CONFIG */
-static void hdmi_core_video_config(struct hdmi_core_video_config *cfg)
-{
-       u32 r = 0;
-
-       /* sys_ctrl1 default configuration not tunable */
-       r = hdmi_read_reg(HDMI_CORE_CTRL1);
-       r = FLD_MOD(r, HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC, 5, 5);
-       r = FLD_MOD(r, HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC, 4, 4);
-       r = FLD_MOD(r, HDMI_CORE_CTRL1_BSEL_24BITBUS, 2, 2);
-       r = FLD_MOD(r, HDMI_CORE_CTRL1_EDGE_RISINGEDGE, 1, 1);
-       hdmi_write_reg(HDMI_CORE_CTRL1, r);
-
-       REG_FLD_MOD(HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6);
-
-       /* Vid_Mode */
-       r = hdmi_read_reg(HDMI_CORE_SYS_VID_MODE);
-
-       /* dither truncation configuration */
-       if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) {
-               r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6);
-               r = FLD_MOD(r, 1, 5, 5);
-       } else {
-               r = FLD_MOD(r, cfg->op_dither_truc, 7, 6);
-               r = FLD_MOD(r, 0, 5, 5);
-       }
-       hdmi_write_reg(HDMI_CORE_SYS_VID_MODE, r);
-
-       /* HDMI_Ctrl */
-       r = hdmi_read_reg(HDMI_CORE_AV_HDMI_CTRL);
-       r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6);
-       r = FLD_MOD(r, cfg->pkt_mode, 5, 3);
-       r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0);
-       hdmi_write_reg(HDMI_CORE_AV_HDMI_CTRL, r);
-
-       /* TMDS_CTRL */
-       REG_FLD_MOD(HDMI_CORE_SYS_TMDS_CTRL,
-               cfg->tclk_sel_clkmult, 6, 5);
-}
-
-static void hdmi_core_aux_infoframe_avi_config(
-               struct hdmi_core_infoframe_avi info_avi)
-{
-       u32 val;
-       char sum = 0, checksum = 0;
-
-       sum += 0x82 + 0x002 + 0x00D;
-       hdmi_write_reg(HDMI_CORE_AV_AVI_TYPE, 0x082);
-       hdmi_write_reg(HDMI_CORE_AV_AVI_VERS, 0x002);
-       hdmi_write_reg(HDMI_CORE_AV_AVI_LEN, 0x00D);
-
-       val = (info_avi.db1_format << 5) |
-               (info_avi.db1_active_info << 4) |
-               (info_avi.db1_bar_info_dv << 2) |
-               (info_avi.db1_scan_info);
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(0), val);
-       sum += val;
-
-       val = (info_avi.db2_colorimetry << 6) |
-               (info_avi.db2_aspect_ratio << 4) |
-               (info_avi.db2_active_fmt_ar);
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(1), val);
-       sum += val;
-
-       val = (info_avi.db3_itc << 7) |
-               (info_avi.db3_ec << 4) |
-               (info_avi.db3_q_range << 2) |
-               (info_avi.db3_nup_scaling);
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(2), val);
-       sum += val;
-
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(3), info_avi.db4_videocode);
-       sum += info_avi.db4_videocode;
-
-       val = info_avi.db5_pixel_repeat;
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(4), val);
-       sum += val;
-
-       val = info_avi.db6_7_line_eoftop & 0x00FF;
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(5), val);
-       sum += val;
-
-       val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF);
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(6), val);
-       sum += val;
-
-       val = info_avi.db8_9_line_sofbottom & 0x00FF;
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(7), val);
-       sum += val;
-
-       val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF);
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(8), val);
-       sum += val;
-
-       val = info_avi.db10_11_pixel_eofleft & 0x00FF;
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(9), val);
-       sum += val;
-
-       val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF);
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(10), val);
-       sum += val;
-
-       val = info_avi.db12_13_pixel_sofright & 0x00FF;
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(11), val);
-       sum += val;
-
-       val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF);
-       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(12), val);
-       sum += val;
-
-       checksum = 0x100 - sum;
-       hdmi_write_reg(HDMI_CORE_AV_AVI_CHSUM, checksum);
-}
-
-static void hdmi_core_av_packet_config(
-               struct hdmi_core_packet_enable_repeat repeat_cfg)
-{
-       /* enable/repeat the infoframe */
-       hdmi_write_reg(HDMI_CORE_AV_PB_CTRL1,
-               (repeat_cfg.audio_pkt << 5) |
-               (repeat_cfg.audio_pkt_repeat << 4) |
-               (repeat_cfg.avi_infoframe << 1) |
-               (repeat_cfg.avi_infoframe_repeat));
-
-       /* enable/repeat the packet */
-       hdmi_write_reg(HDMI_CORE_AV_PB_CTRL2,
-               (repeat_cfg.gen_cntrl_pkt << 3) |
-               (repeat_cfg.gen_cntrl_pkt_repeat << 2) |
-               (repeat_cfg.generic_pkt << 1) |
-               (repeat_cfg.generic_pkt_repeat));
-}
-
-static void hdmi_wp_init(struct omap_video_timings *timings,
-                       struct hdmi_video_format *video_fmt,
-                       struct hdmi_video_interface *video_int)
-{
-       DSSDBG("Enter hdmi_wp_init\n");
-
-       timings->hbp = 0;
-       timings->hfp = 0;
-       timings->hsw = 0;
-       timings->vbp = 0;
-       timings->vfp = 0;
-       timings->vsw = 0;
-
-       video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
-       video_fmt->y_res = 0;
-       video_fmt->x_res = 0;
-
-       video_int->vsp = 0;
-       video_int->hsp = 0;
-
-       video_int->interlacing = 0;
-       video_int->tm = 0; /* HDMI_TIMING_SLAVE */
-
-}
-
-static void hdmi_wp_video_start(bool start)
-{
-       REG_FLD_MOD(HDMI_WP_VIDEO_CFG, start, 31, 31);
-}
-
-static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt,
-       struct omap_video_timings *timings, struct hdmi_config *param)
-{
-       DSSDBG("Enter hdmi_wp_video_init_format\n");
-
-       video_fmt->y_res = param->timings.timings.y_res;
-       video_fmt->x_res = param->timings.timings.x_res;
-
-       timings->hbp = param->timings.timings.hbp;
-       timings->hfp = param->timings.timings.hfp;
-       timings->hsw = param->timings.timings.hsw;
-       timings->vbp = param->timings.timings.vbp;
-       timings->vfp = param->timings.timings.vfp;
-       timings->vsw = param->timings.timings.vsw;
-}
-
-static void hdmi_wp_video_config_format(
-               struct hdmi_video_format *video_fmt)
-{
-       u32 l = 0;
-
-       REG_FLD_MOD(HDMI_WP_VIDEO_CFG, video_fmt->packing_mode, 10, 8);
-
-       l |= FLD_VAL(video_fmt->y_res, 31, 16);
-       l |= FLD_VAL(video_fmt->x_res, 15, 0);
-       hdmi_write_reg(HDMI_WP_VIDEO_SIZE, l);
-}
-
-static void hdmi_wp_video_config_interface(
-               struct hdmi_video_interface *video_int)
-{
-       u32 r;
-       DSSDBG("Enter hdmi_wp_video_config_interface\n");
-
-       r = hdmi_read_reg(HDMI_WP_VIDEO_CFG);
-       r = FLD_MOD(r, video_int->vsp, 7, 7);
-       r = FLD_MOD(r, video_int->hsp, 6, 6);
-       r = FLD_MOD(r, video_int->interlacing, 3, 3);
-       r = FLD_MOD(r, video_int->tm, 1, 0);
-       hdmi_write_reg(HDMI_WP_VIDEO_CFG, r);
-}
-
-static void hdmi_wp_video_config_timing(
-               struct omap_video_timings *timings)
-{
-       u32 timing_h = 0;
-       u32 timing_v = 0;
-
-       DSSDBG("Enter hdmi_wp_video_config_timing\n");
-
-       timing_h |= FLD_VAL(timings->hbp, 31, 20);
-       timing_h |= FLD_VAL(timings->hfp, 19, 8);
-       timing_h |= FLD_VAL(timings->hsw, 7, 0);
-       hdmi_write_reg(HDMI_WP_VIDEO_TIMING_H, timing_h);
-
-       timing_v |= FLD_VAL(timings->vbp, 31, 20);
-       timing_v |= FLD_VAL(timings->vfp, 19, 8);
-       timing_v |= FLD_VAL(timings->vsw, 7, 0);
-       hdmi_write_reg(HDMI_WP_VIDEO_TIMING_V, timing_v);
-}
-
-static void hdmi_basic_configure(struct hdmi_config *cfg)
-{
-       /* HDMI */
-       struct omap_video_timings video_timing;
-       struct hdmi_video_format video_format;
-       struct hdmi_video_interface video_interface;
-       /* HDMI core */
-       struct hdmi_core_infoframe_avi avi_cfg;
-       struct hdmi_core_video_config v_core_cfg;
-       struct hdmi_core_packet_enable_repeat repeat_cfg;
-
-       hdmi_wp_init(&video_timing, &video_format,
-               &video_interface);
-
-       hdmi_core_init(&v_core_cfg,
-               &avi_cfg,
-               &repeat_cfg);
-
-       hdmi_wp_video_init_format(&video_format,
-                       &video_timing, cfg);
-
-       hdmi_wp_video_config_timing(&video_timing);
-
-       /* video config */
-       video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422;
-
-       hdmi_wp_video_config_format(&video_format);
-
-       video_interface.vsp = cfg->timings.vsync_pol;
-       video_interface.hsp = cfg->timings.hsync_pol;
-       video_interface.interlacing = cfg->interlace;
-       video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */
-
-       hdmi_wp_video_config_interface(&video_interface);
-
-       /*
-        * configure core video part
-        * set software reset in the core
-        */
-       hdmi_core_swreset_assert();
-
-       /* power down off */
-       hdmi_core_powerdown_disable();
-
-       v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL;
-       v_core_cfg.hdmi_dvi = cfg->cm.mode;
-
-       hdmi_core_video_config(&v_core_cfg);
-
-       /* release software reset in the core */
-       hdmi_core_swreset_release();
-
-       /*
-        * configure packet
-        * info frame video see doc CEA861-D page 65
-        */
-       avi_cfg.db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB;
-       avi_cfg.db1_active_info =
-               HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF;
-       avi_cfg.db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO;
-       avi_cfg.db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0;
-       avi_cfg.db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO;
-       avi_cfg.db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO;
-       avi_cfg.db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME;
-       avi_cfg.db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO;
-       avi_cfg.db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601;
-       avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT;
-       avi_cfg.db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO;
-       avi_cfg.db4_videocode = cfg->cm.code;
-       avi_cfg.db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO;
-       avi_cfg.db6_7_line_eoftop = 0;
-       avi_cfg.db8_9_line_sofbottom = 0;
-       avi_cfg.db10_11_pixel_eofleft = 0;
-       avi_cfg.db12_13_pixel_sofright = 0;
-
-       hdmi_core_aux_infoframe_avi_config(avi_cfg);
-
-       /* enable/repeat the infoframe */
-       repeat_cfg.avi_infoframe = HDMI_PACKETENABLE;
-       repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON;
-       /* wakeup */
-       repeat_cfg.audio_pkt = HDMI_PACKETENABLE;
-       repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON;
-       hdmi_core_av_packet_config(repeat_cfg);
-}
-
 static void update_hdmi_timings(struct hdmi_config *cfg,
                struct omap_video_timings *timings, int code)
 {
@@ -1066,6 +266,12 @@ static void update_hdmi_timings(struct hdmi_config *cfg,
        cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol;
 }
 
+unsigned long hdmi_get_pixel_clock(void)
+{
+       /* HDMI Pixel Clock in Mhz */
+       return hdmi.ip_data.cfg.timings.timings.pixel_clock * 10000;
+}
+
 static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
                struct hdmi_pll_info *pi)
 {
@@ -1077,15 +283,23 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
         * Input clock is predivided by N + 1
         * out put of which is reference clk
         */
-       pi->regn = dssdev->clocks.hdmi.regn;
-       refclk = clkin / (pi->regn + 1);
+       if (dssdev->clocks.hdmi.regn == 0)
+               pi->regn = HDMI_DEFAULT_REGN;
+       else
+               pi->regn = dssdev->clocks.hdmi.regn;
+
+       refclk = clkin / pi->regn;
 
        /*
         * multiplier is pixel_clk/ref_clk
         * Multiplying by 100 to avoid fractional part removal
         */
        pi->regm = (phy * 100 / (refclk)) / 100;
-       pi->regm2 = dssdev->clocks.hdmi.regm2;
+
+       if (dssdev->clocks.hdmi.regm2 == 0)
+               pi->regm2 = HDMI_DEFAULT_REGM2;
+       else
+               pi->regm2 = dssdev->clocks.hdmi.regm2;
 
        /*
         * fractional multiplier is remainder of the difference between
@@ -1100,7 +314,10 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
         * is greater than 1000MHz
         */
        pi->dcofreq = phy > 1000 * 100;
-       pi->regsd = ((pi->regm * clkin / 10) / ((pi->regn + 1) * 250) + 5) / 10;
+       pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
+
+       /* Set the reference clock to sysclk reference */
+       pi->refsel = HDMI_REFSEL_SYSCLK;
 
        DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
        DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
@@ -1109,7 +326,6 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
 static int hdmi_power_on(struct omap_dss_device *dssdev)
 {
        int r, code = 0;
-       struct hdmi_pll_info pll_data;
        struct omap_video_timings *p;
        unsigned long phy;
 
@@ -1117,7 +333,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
        if (r)
                return r;
 
-       dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
+       dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0);
 
        p = &dssdev->panel.timings;
 
@@ -1125,36 +341,31 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
                dssdev->panel.timings.x_res,
                dssdev->panel.timings.y_res);
 
-       if (!hdmi.custom_set) {
-               DSSDBG("Read EDID as no EDID is not set on poweron\n");
-               hdmi_read_edid(p);
-       }
        code = get_timings_index();
-       dssdev->panel.timings = cea_vesa_timings[code].timings;
-       update_hdmi_timings(&hdmi.cfg, p, code);
+       update_hdmi_timings(&hdmi.ip_data.cfg, p, code);
 
        phy = p->pixel_clock;
 
-       hdmi_compute_pll(dssdev, phy, &pll_data);
+       hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);
 
-       hdmi_wp_video_start(0);
+       hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0);
 
-       /* config the PLL and PHY first */
-       r = hdmi_pll_program(&pll_data);
+       /* config the PLL and PHY hdmi_set_pll_pwrfirst */
+       r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data);
        if (r) {
                DSSDBG("Failed to lock PLL\n");
                goto err;
        }
 
-       r = hdmi_phy_init();
+       r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data);
        if (r) {
                DSSDBG("Failed to start PHY\n");
                goto err;
        }
 
-       hdmi.cfg.cm.mode = hdmi.mode;
-       hdmi.cfg.cm.code = hdmi.code;
-       hdmi_basic_configure(&hdmi.cfg);
+       hdmi.ip_data.cfg.cm.mode = hdmi.mode;
+       hdmi.ip_data.cfg.cm.code = hdmi.code;
+       hdmi.ip_data.ops->video_configure(&hdmi.ip_data);
 
        /* Make selection of HDMI in DSS */
        dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
@@ -1174,9 +385,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
        dispc_set_digit_size(dssdev->panel.timings.x_res,
                        dssdev->panel.timings.y_res);
 
-       dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 1);
+       hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1);
 
-       hdmi_wp_video_start(1);
+       dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 1);
 
        return 0;
 err:
@@ -1186,14 +397,12 @@ err:
 
 static void hdmi_power_off(struct omap_dss_device *dssdev)
 {
-       dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
+       dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0);
 
-       hdmi_wp_video_start(0);
-       hdmi_phy_off();
-       hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
+       hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0);
+       hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
+       hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
        hdmi_runtime_put();
-
-       hdmi.edid_set = 0;
 }
 
 int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
@@ -1203,7 +412,6 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
 
        cm = hdmi_get_code(timings);
        if (cm.code == -1) {
-               DSSERR("Invalid timing entered\n");
                return -EINVAL;
        }
 
@@ -1215,12 +423,69 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
 {
        struct hdmi_cm cm;
 
-       hdmi.custom_set = 1;
        cm = hdmi_get_code(&dssdev->panel.timings);
        hdmi.code = cm.code;
        hdmi.mode = cm.mode;
-       omapdss_hdmi_display_enable(dssdev);
-       hdmi.custom_set = 0;
+
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+               int r;
+
+               hdmi_power_off(dssdev);
+
+               r = hdmi_power_on(dssdev);
+               if (r)
+                       DSSERR("failed to power on device\n");
+       }
+}
+
+void hdmi_dump_regs(struct seq_file *s)
+{
+       mutex_lock(&hdmi.lock);
+
+       if (hdmi_runtime_get())
+               return;
+
+       hdmi.ip_data.ops->dump_wrapper(&hdmi.ip_data, s);
+       hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s);
+       hdmi.ip_data.ops->dump_phy(&hdmi.ip_data, s);
+       hdmi.ip_data.ops->dump_core(&hdmi.ip_data, s);
+
+       hdmi_runtime_put();
+       mutex_unlock(&hdmi.lock);
+}
+
+int omapdss_hdmi_read_edid(u8 *buf, int len)
+{
+       int r;
+
+       mutex_lock(&hdmi.lock);
+
+       r = hdmi_runtime_get();
+       BUG_ON(r);
+
+       r = hdmi.ip_data.ops->read_edid(&hdmi.ip_data, buf, len);
+
+       hdmi_runtime_put();
+       mutex_unlock(&hdmi.lock);
+
+       return r;
+}
+
+bool omapdss_hdmi_detect(void)
+{
+       int r;
+
+       mutex_lock(&hdmi.lock);
+
+       r = hdmi_runtime_get();
+       BUG_ON(r);
+
+       r = hdmi.ip_data.ops->detect(&hdmi.ip_data);
+
+       hdmi_runtime_put();
+       mutex_unlock(&hdmi.lock);
+
+       return r == 1;
 }
 
 int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
@@ -1231,6 +496,12 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
 
        mutex_lock(&hdmi.lock);
 
+       if (dssdev->manager == NULL) {
+               DSSERR("failed to enable display: no manager\n");
+               r = -ENODEV;
+               goto err0;
+       }
+
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
@@ -1282,219 +553,9 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
 
 #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
        defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-static void hdmi_wp_audio_config_format(
-               struct hdmi_audio_format *aud_fmt)
-{
-       u32 r;
-
-       DSSDBG("Enter hdmi_wp_audio_config_format\n");
-
-       r = hdmi_read_reg(HDMI_WP_AUDIO_CFG);
-       r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
-       r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
-       r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
-       r = FLD_MOD(r, aud_fmt->type, 4, 4);
-       r = FLD_MOD(r, aud_fmt->justification, 3, 3);
-       r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
-       r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
-       r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
-       hdmi_write_reg(HDMI_WP_AUDIO_CFG, r);
-}
-
-static void hdmi_wp_audio_config_dma(struct hdmi_audio_dma *aud_dma)
-{
-       u32 r;
-
-       DSSDBG("Enter hdmi_wp_audio_config_dma\n");
-
-       r = hdmi_read_reg(HDMI_WP_AUDIO_CFG2);
-       r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
-       r = FLD_MOD(r, aud_dma->block_size, 7, 0);
-       hdmi_write_reg(HDMI_WP_AUDIO_CFG2, r);
-
-       r = hdmi_read_reg(HDMI_WP_AUDIO_CTRL);
-       r = FLD_MOD(r, aud_dma->mode, 9, 9);
-       r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
-       hdmi_write_reg(HDMI_WP_AUDIO_CTRL, r);
-}
-
-static void hdmi_core_audio_config(struct hdmi_core_audio_config *cfg)
-{
-       u32 r;
-
-       /* audio clock recovery parameters */
-       r = hdmi_read_reg(HDMI_CORE_AV_ACR_CTRL);
-       r = FLD_MOD(r, cfg->use_mclk, 2, 2);
-       r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1);
-       r = FLD_MOD(r, cfg->cts_mode, 0, 0);
-       hdmi_write_reg(HDMI_CORE_AV_ACR_CTRL, r);
-
-       REG_FLD_MOD(HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0);
-       REG_FLD_MOD(HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0);
-       REG_FLD_MOD(HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0);
-
-       if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) {
-               REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0);
-               REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0);
-               REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0);
-       } else {
-               /*
-                * HDMI IP uses this configuration to divide the MCLK to
-                * update CTS value.
-                */
-               REG_FLD_MOD(HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0);
-
-               /* Configure clock for audio packets */
-               REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_1,
-                       cfg->aud_par_busclk, 7, 0);
-               REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_2,
-                       (cfg->aud_par_busclk >> 8), 7, 0);
-               REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_3,
-                       (cfg->aud_par_busclk >> 16), 7, 0);
-       }
-
-       /* Override of SPDIF sample frequency with value in I2S_CHST4 */
-       REG_FLD_MOD(HDMI_CORE_AV_SPDIF_CTRL, cfg->fs_override, 1, 1);
-
-       /* I2S parameters */
-       REG_FLD_MOD(HDMI_CORE_AV_I2S_CHST4, cfg->freq_sample, 3, 0);
-
-       r = hdmi_read_reg(HDMI_CORE_AV_I2S_IN_CTRL);
-       r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7);
-       r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6);
-       r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5);
-       r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4);
-       r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3);
-       r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2);
-       r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1);
-       r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0);
-       hdmi_write_reg(HDMI_CORE_AV_I2S_IN_CTRL, r);
-
-       r = hdmi_read_reg(HDMI_CORE_AV_I2S_CHST5);
-       r = FLD_MOD(r, cfg->freq_sample, 7, 4);
-       r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1);
-       r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0);
-       hdmi_write_reg(HDMI_CORE_AV_I2S_CHST5, r);
-
-       REG_FLD_MOD(HDMI_CORE_AV_I2S_IN_LEN, cfg->i2s_cfg.in_length_bits, 3, 0);
-
-       /* Audio channels and mode parameters */
-       REG_FLD_MOD(HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1);
-       r = hdmi_read_reg(HDMI_CORE_AV_AUD_MODE);
-       r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4);
-       r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3);
-       r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2);
-       r = FLD_MOD(r, cfg->en_spdif, 1, 1);
-       hdmi_write_reg(HDMI_CORE_AV_AUD_MODE, r);
-}
-
-static void hdmi_core_audio_infoframe_config(
-               struct hdmi_core_infoframe_audio *info_aud)
-{
-       u8 val;
-       u8 sum = 0, checksum = 0;
-
-       /*
-        * Set audio info frame type, version and length as
-        * described in HDMI 1.4a Section 8.2.2 specification.
-        * Checksum calculation is defined in Section 5.3.5.
-        */
-       hdmi_write_reg(HDMI_CORE_AV_AUDIO_TYPE, 0x84);
-       hdmi_write_reg(HDMI_CORE_AV_AUDIO_VERS, 0x01);
-       hdmi_write_reg(HDMI_CORE_AV_AUDIO_LEN, 0x0a);
-       sum += 0x84 + 0x001 + 0x00a;
-
-       val = (info_aud->db1_coding_type << 4)
-                       | (info_aud->db1_channel_count - 1);
-       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(0), val);
-       sum += val;
-
-       val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size;
-       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(1), val);
-       sum += val;
-
-       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(2), 0x00);
-
-       val = info_aud->db4_channel_alloc;
-       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(3), val);
-       sum += val;
-
-       val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3);
-       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(4), val);
-       sum += val;
-
-       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(5), 0x00);
-       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(6), 0x00);
-       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(7), 0x00);
-       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(8), 0x00);
-       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(9), 0x00);
 
-       checksum = 0x100 - sum;
-       hdmi_write_reg(HDMI_CORE_AV_AUDIO_CHSUM, checksum);
-
-       /*
-        * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing
-        * is available.
-        */
-}
-
-static int hdmi_config_audio_acr(u32 sample_freq, u32 *n, u32 *cts)
-{
-       u32 r;
-       u32 deep_color = 0;
-       u32 pclk = hdmi.cfg.timings.timings.pixel_clock;
-
-       if (n == NULL || cts == NULL)
-               return -EINVAL;
-       /*
-        * Obtain current deep color configuration. This needed
-        * to calculate the TMDS clock based on the pixel clock.
-        */
-       r = REG_GET(HDMI_WP_VIDEO_CFG, 1, 0);
-       switch (r) {
-       case 1: /* No deep color selected */
-               deep_color = 100;
-               break;
-       case 2: /* 10-bit deep color selected */
-               deep_color = 125;
-               break;
-       case 3: /* 12-bit deep color selected */
-               deep_color = 150;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (sample_freq) {
-       case 32000:
-               if ((deep_color == 125) && ((pclk == 54054)
-                               || (pclk == 74250)))
-                       *n = 8192;
-               else
-                       *n = 4096;
-               break;
-       case 44100:
-               *n = 6272;
-               break;
-       case 48000:
-               if ((deep_color == 125) && ((pclk == 54054)
-                               || (pclk == 74250)))
-                       *n = 8192;
-               else
-                       *n = 6144;
-               break;
-       default:
-               *n = 0;
-               return -EINVAL;
-       }
-
-       /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
-       *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
-
-       return 0;
-}
-
-static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
+static int hdmi_audio_hw_params(struct hdmi_ip_data *ip_data,
+                                       struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *params,
                                    struct snd_soc_dai *dai)
 {
@@ -1548,7 +609,7 @@ static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       err = hdmi_config_audio_acr(params_rate(params), &n, &cts);
+       err = hdmi_config_audio_acr(ip_data, params_rate(params), &n, &cts);
        if (err < 0)
                return err;
 
@@ -1564,8 +625,8 @@ static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
        audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
        audio_dma.fifo_threshold = 0x20; /* in number of samples */
 
-       hdmi_wp_audio_config_dma(&audio_dma);
-       hdmi_wp_audio_config_format(&audio_format);
+       hdmi_wp_audio_config_dma(ip_data, &audio_dma);
+       hdmi_wp_audio_config_format(ip_data, &audio_format);
 
        /*
         * I2S config
@@ -1609,7 +670,7 @@ static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
        /* Use parallel audio interface */
        core_cfg.en_parallel_aud_input = true;
 
-       hdmi_core_audio_config(&core_cfg);
+       hdmi_core_audio_config(ip_data, &core_cfg);
 
        /*
         * Configure packet
@@ -1623,36 +684,10 @@ static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
        aud_if_cfg.db5_downmix_inh = false;
        aud_if_cfg.db5_lsv = 0;
 
-       hdmi_core_audio_infoframe_config(&aud_if_cfg);
+       hdmi_core_audio_infoframe_config(ip_data, &aud_if_cfg);
        return 0;
 }
 
-static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd,
-                                 struct snd_soc_dai *dai)
-{
-       int err = 0;
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 1, 0, 0);
-               REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 31, 31);
-               REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 30, 30);
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 0, 0, 0);
-               REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 30, 30);
-               REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 31, 31);
-               break;
-       default:
-               err = -EINVAL;
-       }
-       return err;
-}
-
 static int hdmi_audio_startup(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *dai)
 {
@@ -1698,15 +733,6 @@ static int hdmi_get_clocks(struct platform_device *pdev)
 
        hdmi.sys_clk = clk;
 
-       clk = clk_get(&pdev->dev, "dss_48mhz_clk");
-       if (IS_ERR(clk)) {
-               DSSERR("can't get hdmi_clk\n");
-               clk_put(hdmi.sys_clk);
-               return PTR_ERR(clk);
-       }
-
-       hdmi.hdmi_clk = clk;
-
        return 0;
 }
 
@@ -1714,8 +740,6 @@ static void hdmi_put_clocks(void)
 {
        if (hdmi.sys_clk)
                clk_put(hdmi.sys_clk);
-       if (hdmi.hdmi_clk)
-               clk_put(hdmi.hdmi_clk);
 }
 
 /* HDMI HW IP initialisation */
@@ -1736,20 +760,26 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
        }
 
        /* Base address taken from platform */
-       hdmi.base_wp = ioremap(hdmi_mem->start, resource_size(hdmi_mem));
-       if (!hdmi.base_wp) {
+       hdmi.ip_data.base_wp = ioremap(hdmi_mem->start,
+                                               resource_size(hdmi_mem));
+       if (!hdmi.ip_data.base_wp) {
                DSSERR("can't ioremap WP\n");
                return -ENOMEM;
        }
 
        r = hdmi_get_clocks(pdev);
        if (r) {
-               iounmap(hdmi.base_wp);
+               iounmap(hdmi.ip_data.base_wp);
                return r;
        }
 
        pm_runtime_enable(&pdev->dev);
 
+       hdmi.ip_data.core_sys_offset = HDMI_CORE_SYS;
+       hdmi.ip_data.core_av_offset = HDMI_CORE_AV;
+       hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
+       hdmi.ip_data.phy_offset = HDMI_PHY;
+
        hdmi_panel_init();
 
 #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
@@ -1779,14 +809,13 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev)
 
        hdmi_put_clocks();
 
-       iounmap(hdmi.base_wp);
+       iounmap(hdmi.ip_data.base_wp);
 
        return 0;
 }
 
 static int hdmi_runtime_suspend(struct device *dev)
 {
-       clk_disable(hdmi.hdmi_clk);
        clk_disable(hdmi.sys_clk);
 
        dispc_runtime_put();
@@ -1809,7 +838,6 @@ static int hdmi_runtime_resume(struct device *dev)
 
 
        clk_enable(hdmi.sys_clk);
-       clk_enable(hdmi.hdmi_clk);
 
        return 0;
 
diff --git a/drivers/video/omap2/dss/hdmi.h b/drivers/video/omap2/dss/hdmi.h
deleted file mode 100644 (file)
index c885f9c..0000000
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- * hdmi.h
- *
- * HDMI driver definition for TI OMAP4 processors.
- *
- * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _OMAP4_DSS_HDMI_H_
-#define _OMAP4_DSS_HDMI_H_
-
-#include <linux/string.h>
-#include <video/omapdss.h>
-
-#define HDMI_WP                0x0
-#define HDMI_CORE_SYS          0x400
-#define HDMI_CORE_AV           0x900
-#define HDMI_PLLCTRL           0x200
-#define HDMI_PHY               0x300
-
-struct hdmi_reg { u16 idx; };
-
-#define HDMI_REG(idx)                  ((const struct hdmi_reg) { idx })
-
-/* HDMI Wrapper */
-#define HDMI_WP_REG(idx)                       HDMI_REG(HDMI_WP + idx)
-
-#define HDMI_WP_REVISION                       HDMI_WP_REG(0x0)
-#define HDMI_WP_SYSCONFIG                      HDMI_WP_REG(0x10)
-#define HDMI_WP_IRQSTATUS_RAW                  HDMI_WP_REG(0x24)
-#define HDMI_WP_IRQSTATUS                      HDMI_WP_REG(0x28)
-#define HDMI_WP_PWR_CTRL                       HDMI_WP_REG(0x40)
-#define HDMI_WP_IRQENABLE_SET                  HDMI_WP_REG(0x2C)
-#define HDMI_WP_VIDEO_CFG                      HDMI_WP_REG(0x50)
-#define HDMI_WP_VIDEO_SIZE                     HDMI_WP_REG(0x60)
-#define HDMI_WP_VIDEO_TIMING_H                 HDMI_WP_REG(0x68)
-#define HDMI_WP_VIDEO_TIMING_V                 HDMI_WP_REG(0x6C)
-#define HDMI_WP_WP_CLK                         HDMI_WP_REG(0x70)
-#define HDMI_WP_AUDIO_CFG                      HDMI_WP_REG(0x80)
-#define HDMI_WP_AUDIO_CFG2                     HDMI_WP_REG(0x84)
-#define HDMI_WP_AUDIO_CTRL                     HDMI_WP_REG(0x88)
-#define HDMI_WP_AUDIO_DATA                     HDMI_WP_REG(0x8C)
-
-/* HDMI IP Core System */
-#define HDMI_CORE_SYS_REG(idx)                 HDMI_REG(HDMI_CORE_SYS + idx)
-
-#define HDMI_CORE_SYS_VND_IDL                  HDMI_CORE_SYS_REG(0x0)
-#define HDMI_CORE_SYS_DEV_IDL                  HDMI_CORE_SYS_REG(0x8)
-#define HDMI_CORE_SYS_DEV_IDH                  HDMI_CORE_SYS_REG(0xC)
-#define HDMI_CORE_SYS_DEV_REV                  HDMI_CORE_SYS_REG(0x10)
-#define HDMI_CORE_SYS_SRST                     HDMI_CORE_SYS_REG(0x14)
-#define HDMI_CORE_CTRL1                        HDMI_CORE_SYS_REG(0x20)
-#define HDMI_CORE_SYS_SYS_STAT                 HDMI_CORE_SYS_REG(0x24)
-#define HDMI_CORE_SYS_VID_ACEN                 HDMI_CORE_SYS_REG(0x124)
-#define HDMI_CORE_SYS_VID_MODE                 HDMI_CORE_SYS_REG(0x128)
-#define HDMI_CORE_SYS_INTR_STATE               HDMI_CORE_SYS_REG(0x1C0)
-#define HDMI_CORE_SYS_INTR1                    HDMI_CORE_SYS_REG(0x1C4)
-#define HDMI_CORE_SYS_INTR2                    HDMI_CORE_SYS_REG(0x1C8)
-#define HDMI_CORE_SYS_INTR3                    HDMI_CORE_SYS_REG(0x1CC)
-#define HDMI_CORE_SYS_INTR4                    HDMI_CORE_SYS_REG(0x1D0)
-#define HDMI_CORE_SYS_UMASK1                   HDMI_CORE_SYS_REG(0x1D4)
-#define HDMI_CORE_SYS_TMDS_CTRL                HDMI_CORE_SYS_REG(0x208)
-#define HDMI_CORE_SYS_DE_DLY                   HDMI_CORE_SYS_REG(0xC8)
-#define HDMI_CORE_SYS_DE_CTRL                  HDMI_CORE_SYS_REG(0xCC)
-#define HDMI_CORE_SYS_DE_TOP                   HDMI_CORE_SYS_REG(0xD0)
-#define HDMI_CORE_SYS_DE_CNTL                  HDMI_CORE_SYS_REG(0xD8)
-#define HDMI_CORE_SYS_DE_CNTH                  HDMI_CORE_SYS_REG(0xDC)
-#define HDMI_CORE_SYS_DE_LINL                  HDMI_CORE_SYS_REG(0xE0)
-#define HDMI_CORE_SYS_DE_LINH_1                HDMI_CORE_SYS_REG(0xE4)
-#define HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC        0x1
-#define HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC        0x1
-#define HDMI_CORE_CTRL1_BSEL_24BITBUS          0x1
-#define HDMI_CORE_CTRL1_EDGE_RISINGEDGE        0x1
-
-/* HDMI DDC E-DID */
-#define HDMI_CORE_DDC_CMD                      HDMI_CORE_SYS_REG(0x3CC)
-#define HDMI_CORE_DDC_STATUS                   HDMI_CORE_SYS_REG(0x3C8)
-#define HDMI_CORE_DDC_ADDR                     HDMI_CORE_SYS_REG(0x3B4)
-#define HDMI_CORE_DDC_OFFSET                   HDMI_CORE_SYS_REG(0x3BC)
-#define HDMI_CORE_DDC_COUNT1                   HDMI_CORE_SYS_REG(0x3C0)
-#define HDMI_CORE_DDC_COUNT2                   HDMI_CORE_SYS_REG(0x3C4)
-#define HDMI_CORE_DDC_DATA                     HDMI_CORE_SYS_REG(0x3D0)
-#define HDMI_CORE_DDC_SEGM                     HDMI_CORE_SYS_REG(0x3B8)
-
-/* HDMI IP Core Audio Video */
-#define HDMI_CORE_AV_REG(idx)                  HDMI_REG(HDMI_CORE_AV + idx)
-
-#define HDMI_CORE_AV_HDMI_CTRL                 HDMI_CORE_AV_REG(0xBC)
-#define HDMI_CORE_AV_DPD                       HDMI_CORE_AV_REG(0xF4)
-#define HDMI_CORE_AV_PB_CTRL1                  HDMI_CORE_AV_REG(0xF8)
-#define HDMI_CORE_AV_PB_CTRL2                  HDMI_CORE_AV_REG(0xFC)
-#define HDMI_CORE_AV_AVI_TYPE                  HDMI_CORE_AV_REG(0x100)
-#define HDMI_CORE_AV_AVI_VERS                  HDMI_CORE_AV_REG(0x104)
-#define HDMI_CORE_AV_AVI_LEN                   HDMI_CORE_AV_REG(0x108)
-#define HDMI_CORE_AV_AVI_CHSUM                 HDMI_CORE_AV_REG(0x10C)
-#define HDMI_CORE_AV_AVI_DBYTE(n)              HDMI_CORE_AV_REG(n * 4 + 0x110)
-#define HDMI_CORE_AV_AVI_DBYTE_NELEMS          HDMI_CORE_AV_REG(15)
-#define HDMI_CORE_AV_SPD_DBYTE                 HDMI_CORE_AV_REG(0x190)
-#define HDMI_CORE_AV_SPD_DBYTE_NELEMS          HDMI_CORE_AV_REG(27)
-#define HDMI_CORE_AV_AUD_DBYTE(n)              HDMI_CORE_AV_REG(n * 4 + 0x210)
-#define HDMI_CORE_AV_AUD_DBYTE_NELEMS          HDMI_CORE_AV_REG(10)
-#define HDMI_CORE_AV_MPEG_DBYTE                HDMI_CORE_AV_REG(0x290)
-#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS         HDMI_CORE_AV_REG(27)
-#define HDMI_CORE_AV_GEN_DBYTE                 HDMI_CORE_AV_REG(0x300)
-#define HDMI_CORE_AV_GEN_DBYTE_NELEMS          HDMI_CORE_AV_REG(31)
-#define HDMI_CORE_AV_GEN2_DBYTE                HDMI_CORE_AV_REG(0x380)
-#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS         HDMI_CORE_AV_REG(31)
-#define HDMI_CORE_AV_ACR_CTRL                  HDMI_CORE_AV_REG(0x4)
-#define HDMI_CORE_AV_FREQ_SVAL                 HDMI_CORE_AV_REG(0x8)
-#define HDMI_CORE_AV_N_SVAL1                   HDMI_CORE_AV_REG(0xC)
-#define HDMI_CORE_AV_N_SVAL2                   HDMI_CORE_AV_REG(0x10)
-#define HDMI_CORE_AV_N_SVAL3                   HDMI_CORE_AV_REG(0x14)
-#define HDMI_CORE_AV_CTS_SVAL1                 HDMI_CORE_AV_REG(0x18)
-#define HDMI_CORE_AV_CTS_SVAL2                 HDMI_CORE_AV_REG(0x1C)
-#define HDMI_CORE_AV_CTS_SVAL3                 HDMI_CORE_AV_REG(0x20)
-#define HDMI_CORE_AV_CTS_HVAL1                 HDMI_CORE_AV_REG(0x24)
-#define HDMI_CORE_AV_CTS_HVAL2                 HDMI_CORE_AV_REG(0x28)
-#define HDMI_CORE_AV_CTS_HVAL3                 HDMI_CORE_AV_REG(0x2C)
-#define HDMI_CORE_AV_AUD_MODE                  HDMI_CORE_AV_REG(0x50)
-#define HDMI_CORE_AV_SPDIF_CTRL                HDMI_CORE_AV_REG(0x54)
-#define HDMI_CORE_AV_HW_SPDIF_FS               HDMI_CORE_AV_REG(0x60)
-#define HDMI_CORE_AV_SWAP_I2S                  HDMI_CORE_AV_REG(0x64)
-#define HDMI_CORE_AV_SPDIF_ERTH                HDMI_CORE_AV_REG(0x6C)
-#define HDMI_CORE_AV_I2S_IN_MAP                HDMI_CORE_AV_REG(0x70)
-#define HDMI_CORE_AV_I2S_IN_CTRL               HDMI_CORE_AV_REG(0x74)
-#define HDMI_CORE_AV_I2S_CHST0                 HDMI_CORE_AV_REG(0x78)
-#define HDMI_CORE_AV_I2S_CHST1                 HDMI_CORE_AV_REG(0x7C)
-#define HDMI_CORE_AV_I2S_CHST2                 HDMI_CORE_AV_REG(0x80)
-#define HDMI_CORE_AV_I2S_CHST4                 HDMI_CORE_AV_REG(0x84)
-#define HDMI_CORE_AV_I2S_CHST5                 HDMI_CORE_AV_REG(0x88)
-#define HDMI_CORE_AV_ASRC                      HDMI_CORE_AV_REG(0x8C)
-#define HDMI_CORE_AV_I2S_IN_LEN                HDMI_CORE_AV_REG(0x90)
-#define HDMI_CORE_AV_HDMI_CTRL                 HDMI_CORE_AV_REG(0xBC)
-#define HDMI_CORE_AV_AUDO_TXSTAT               HDMI_CORE_AV_REG(0xC0)
-#define HDMI_CORE_AV_AUD_PAR_BUSCLK_1          HDMI_CORE_AV_REG(0xCC)
-#define HDMI_CORE_AV_AUD_PAR_BUSCLK_2          HDMI_CORE_AV_REG(0xD0)
-#define HDMI_CORE_AV_AUD_PAR_BUSCLK_3          HDMI_CORE_AV_REG(0xD4)
-#define HDMI_CORE_AV_TEST_TXCTRL               HDMI_CORE_AV_REG(0xF0)
-#define HDMI_CORE_AV_DPD                       HDMI_CORE_AV_REG(0xF4)
-#define HDMI_CORE_AV_PB_CTRL1                  HDMI_CORE_AV_REG(0xF8)
-#define HDMI_CORE_AV_PB_CTRL2                  HDMI_CORE_AV_REG(0xFC)
-#define HDMI_CORE_AV_AVI_TYPE                  HDMI_CORE_AV_REG(0x100)
-#define HDMI_CORE_AV_AVI_VERS                  HDMI_CORE_AV_REG(0x104)
-#define HDMI_CORE_AV_AVI_LEN                   HDMI_CORE_AV_REG(0x108)
-#define HDMI_CORE_AV_AVI_CHSUM                 HDMI_CORE_AV_REG(0x10C)
-#define HDMI_CORE_AV_SPD_TYPE                  HDMI_CORE_AV_REG(0x180)
-#define HDMI_CORE_AV_SPD_VERS                  HDMI_CORE_AV_REG(0x184)
-#define HDMI_CORE_AV_SPD_LEN                   HDMI_CORE_AV_REG(0x188)
-#define HDMI_CORE_AV_SPD_CHSUM                 HDMI_CORE_AV_REG(0x18C)
-#define HDMI_CORE_AV_AUDIO_TYPE                HDMI_CORE_AV_REG(0x200)
-#define HDMI_CORE_AV_AUDIO_VERS                HDMI_CORE_AV_REG(0x204)
-#define HDMI_CORE_AV_AUDIO_LEN                 HDMI_CORE_AV_REG(0x208)
-#define HDMI_CORE_AV_AUDIO_CHSUM               HDMI_CORE_AV_REG(0x20C)
-#define HDMI_CORE_AV_MPEG_TYPE                 HDMI_CORE_AV_REG(0x280)
-#define HDMI_CORE_AV_MPEG_VERS                 HDMI_CORE_AV_REG(0x284)
-#define HDMI_CORE_AV_MPEG_LEN                  HDMI_CORE_AV_REG(0x288)
-#define HDMI_CORE_AV_MPEG_CHSUM                HDMI_CORE_AV_REG(0x28C)
-#define HDMI_CORE_AV_CP_BYTE1                  HDMI_CORE_AV_REG(0x37C)
-#define HDMI_CORE_AV_CEC_ADDR_ID               HDMI_CORE_AV_REG(0x3FC)
-#define HDMI_CORE_AV_SPD_DBYTE_ELSIZE          0x4
-#define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE         0x4
-#define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE         0x4
-#define HDMI_CORE_AV_GEN_DBYTE_ELSIZE          0x4
-
-/* PLL */
-#define HDMI_PLL_REG(idx)                      HDMI_REG(HDMI_PLLCTRL + idx)
-
-#define PLLCTRL_PLL_CONTROL                    HDMI_PLL_REG(0x0)
-#define PLLCTRL_PLL_STATUS                     HDMI_PLL_REG(0x4)
-#define PLLCTRL_PLL_GO                         HDMI_PLL_REG(0x8)
-#define PLLCTRL_CFG1                           HDMI_PLL_REG(0xC)
-#define PLLCTRL_CFG2                           HDMI_PLL_REG(0x10)
-#define PLLCTRL_CFG3                           HDMI_PLL_REG(0x14)
-#define PLLCTRL_CFG4                           HDMI_PLL_REG(0x20)
-
-/* HDMI PHY */
-#define HDMI_PHY_REG(idx)                      HDMI_REG(HDMI_PHY + idx)
-
-#define HDMI_TXPHY_TX_CTRL                     HDMI_PHY_REG(0x0)
-#define HDMI_TXPHY_DIGITAL_CTRL                HDMI_PHY_REG(0x4)
-#define HDMI_TXPHY_POWER_CTRL                  HDMI_PHY_REG(0x8)
-#define HDMI_TXPHY_PAD_CFG_CTRL                HDMI_PHY_REG(0xC)
-
-/* HDMI EDID Length  */
-#define HDMI_EDID_MAX_LENGTH                   256
-#define EDID_TIMING_DESCRIPTOR_SIZE            0x12
-#define EDID_DESCRIPTOR_BLOCK0_ADDRESS         0x36
-#define EDID_DESCRIPTOR_BLOCK1_ADDRESS         0x80
-#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR     4
-#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR     4
-
-#define OMAP_HDMI_TIMINGS_NB                   34
-
-#define REG_FLD_MOD(idx, val, start, end) \
-       hdmi_write_reg(idx, FLD_MOD(hdmi_read_reg(idx), val, start, end))
-#define REG_GET(idx, start, end) \
-       FLD_GET(hdmi_read_reg(idx), start, end)
-
-/* HDMI timing structure */
-struct hdmi_timings {
-       struct omap_video_timings timings;
-       int vsync_pol;
-       int hsync_pol;
-};
-
-enum hdmi_phy_pwr {
-       HDMI_PHYPWRCMD_OFF = 0,
-       HDMI_PHYPWRCMD_LDOON = 1,
-       HDMI_PHYPWRCMD_TXON = 2
-};
-
-enum hdmi_pll_pwr {
-       HDMI_PLLPWRCMD_ALLOFF = 0,
-       HDMI_PLLPWRCMD_PLLONLY = 1,
-       HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2,
-       HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3
-};
-
-enum hdmi_clk_refsel {
-       HDMI_REFSEL_PCLK = 0,
-       HDMI_REFSEL_REF1 = 1,
-       HDMI_REFSEL_REF2 = 2,
-       HDMI_REFSEL_SYSCLK = 3
-};
-
-enum hdmi_core_inputbus_width {
-       HDMI_INPUT_8BIT = 0,
-       HDMI_INPUT_10BIT = 1,
-       HDMI_INPUT_12BIT = 2
-};
-
-enum hdmi_core_dither_trunc {
-       HDMI_OUTPUTTRUNCATION_8BIT = 0,
-       HDMI_OUTPUTTRUNCATION_10BIT = 1,
-       HDMI_OUTPUTTRUNCATION_12BIT = 2,
-       HDMI_OUTPUTDITHER_8BIT = 3,
-       HDMI_OUTPUTDITHER_10BIT = 4,
-       HDMI_OUTPUTDITHER_12BIT = 5
-};
-
-enum hdmi_core_deepcolor_ed {
-       HDMI_DEEPCOLORPACKECTDISABLE = 0,
-       HDMI_DEEPCOLORPACKECTENABLE = 1
-};
-
-enum hdmi_core_packet_mode {
-       HDMI_PACKETMODERESERVEDVALUE = 0,
-       HDMI_PACKETMODE24BITPERPIXEL = 4,
-       HDMI_PACKETMODE30BITPERPIXEL = 5,
-       HDMI_PACKETMODE36BITPERPIXEL = 6,
-       HDMI_PACKETMODE48BITPERPIXEL = 7
-};
-
-enum hdmi_core_hdmi_dvi {
-       HDMI_DVI = 0,
-       HDMI_HDMI = 1
-};
-
-enum hdmi_core_tclkselclkmult {
-       HDMI_FPLL05IDCK = 0,
-       HDMI_FPLL10IDCK = 1,
-       HDMI_FPLL20IDCK = 2,
-       HDMI_FPLL40IDCK = 3
-};
-
-enum hdmi_core_packet_ctrl {
-       HDMI_PACKETENABLE = 1,
-       HDMI_PACKETDISABLE = 0,
-       HDMI_PACKETREPEATON = 1,
-       HDMI_PACKETREPEATOFF = 0
-};
-
-/* INFOFRAME_AVI_ and INFOFRAME_AUDIO_ definitions */
-enum hdmi_core_infoframe {
-       HDMI_INFOFRAME_AVI_DB1Y_RGB = 0,
-       HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1,
-       HDMI_INFOFRAME_AVI_DB1Y_YUV444 = 2,
-       HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF = 0,
-       HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_ON =  1,
-       HDMI_INFOFRAME_AVI_DB1B_NO = 0,
-       HDMI_INFOFRAME_AVI_DB1B_VERT = 1,
-       HDMI_INFOFRAME_AVI_DB1B_HORI = 2,
-       HDMI_INFOFRAME_AVI_DB1B_VERTHORI = 3,
-       HDMI_INFOFRAME_AVI_DB1S_0 = 0,
-       HDMI_INFOFRAME_AVI_DB1S_1 = 1,
-       HDMI_INFOFRAME_AVI_DB1S_2 = 2,
-       HDMI_INFOFRAME_AVI_DB2C_NO = 0,
-       HDMI_INFOFRAME_AVI_DB2C_ITU601 = 1,
-       HDMI_INFOFRAME_AVI_DB2C_ITU709 = 2,
-       HDMI_INFOFRAME_AVI_DB2C_EC_EXTENDED = 3,
-       HDMI_INFOFRAME_AVI_DB2M_NO = 0,
-       HDMI_INFOFRAME_AVI_DB2M_43 = 1,
-       HDMI_INFOFRAME_AVI_DB2M_169 = 2,
-       HDMI_INFOFRAME_AVI_DB2R_SAME = 8,
-       HDMI_INFOFRAME_AVI_DB2R_43 = 9,
-       HDMI_INFOFRAME_AVI_DB2R_169 = 10,
-       HDMI_INFOFRAME_AVI_DB2R_149 = 11,
-       HDMI_INFOFRAME_AVI_DB3ITC_NO = 0,
-       HDMI_INFOFRAME_AVI_DB3ITC_YES = 1,
-       HDMI_INFOFRAME_AVI_DB3EC_XVYUV601 = 0,
-       HDMI_INFOFRAME_AVI_DB3EC_XVYUV709 = 1,
-       HDMI_INFOFRAME_AVI_DB3Q_DEFAULT = 0,
-       HDMI_INFOFRAME_AVI_DB3Q_LR = 1,
-       HDMI_INFOFRAME_AVI_DB3Q_FR = 2,
-       HDMI_INFOFRAME_AVI_DB3SC_NO = 0,
-       HDMI_INFOFRAME_AVI_DB3SC_HORI = 1,
-       HDMI_INFOFRAME_AVI_DB3SC_VERT = 2,
-       HDMI_INFOFRAME_AVI_DB3SC_HORIVERT = 3,
-       HDMI_INFOFRAME_AVI_DB5PR_NO = 0,
-       HDMI_INFOFRAME_AVI_DB5PR_2 = 1,
-       HDMI_INFOFRAME_AVI_DB5PR_3 = 2,
-       HDMI_INFOFRAME_AVI_DB5PR_4 = 3,
-       HDMI_INFOFRAME_AVI_DB5PR_5 = 4,
-       HDMI_INFOFRAME_AVI_DB5PR_6 = 5,
-       HDMI_INFOFRAME_AVI_DB5PR_7 = 6,
-       HDMI_INFOFRAME_AVI_DB5PR_8 = 7,
-       HDMI_INFOFRAME_AVI_DB5PR_9 = 8,
-       HDMI_INFOFRAME_AVI_DB5PR_10 = 9,
-       HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM = 0,
-       HDMI_INFOFRAME_AUDIO_DB1CT_IEC60958 = 1,
-       HDMI_INFOFRAME_AUDIO_DB1CT_AC3 = 2,
-       HDMI_INFOFRAME_AUDIO_DB1CT_MPEG1 = 3,
-       HDMI_INFOFRAME_AUDIO_DB1CT_MP3 = 4,
-       HDMI_INFOFRAME_AUDIO_DB1CT_MPEG2_MULTICH = 5,
-       HDMI_INFOFRAME_AUDIO_DB1CT_AAC = 6,
-       HDMI_INFOFRAME_AUDIO_DB1CT_DTS = 7,
-       HDMI_INFOFRAME_AUDIO_DB1CT_ATRAC = 8,
-       HDMI_INFOFRAME_AUDIO_DB1CT_ONEBIT = 9,
-       HDMI_INFOFRAME_AUDIO_DB1CT_DOLBY_DIGITAL_PLUS = 10,
-       HDMI_INFOFRAME_AUDIO_DB1CT_DTS_HD = 11,
-       HDMI_INFOFRAME_AUDIO_DB1CT_MAT = 12,
-       HDMI_INFOFRAME_AUDIO_DB1CT_DST = 13,
-       HDMI_INFOFRAME_AUDIO_DB1CT_WMA_PRO = 14,
-       HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM = 0,
-       HDMI_INFOFRAME_AUDIO_DB2SF_32000 = 1,
-       HDMI_INFOFRAME_AUDIO_DB2SF_44100 = 2,
-       HDMI_INFOFRAME_AUDIO_DB2SF_48000 = 3,
-       HDMI_INFOFRAME_AUDIO_DB2SF_88200 = 4,
-       HDMI_INFOFRAME_AUDIO_DB2SF_96000 = 5,
-       HDMI_INFOFRAME_AUDIO_DB2SF_176400 = 6,
-       HDMI_INFOFRAME_AUDIO_DB2SF_192000 = 7,
-       HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM = 0,
-       HDMI_INFOFRAME_AUDIO_DB2SS_16BIT = 1,
-       HDMI_INFOFRAME_AUDIO_DB2SS_20BIT = 2,
-       HDMI_INFOFRAME_AUDIO_DB2SS_24BIT = 3,
-       HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PERMITTED = 0,
-       HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PROHIBITED = 1
-};
-
-enum hdmi_packing_mode {
-       HDMI_PACK_10b_RGB_YUV444 = 0,
-       HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
-       HDMI_PACK_20b_YUV422 = 2,
-       HDMI_PACK_ALREADYPACKED = 7
-};
-
-enum hdmi_core_audio_sample_freq {
-       HDMI_AUDIO_FS_32000 = 0x3,
-       HDMI_AUDIO_FS_44100 = 0x0,
-       HDMI_AUDIO_FS_48000 = 0x2,
-       HDMI_AUDIO_FS_88200 = 0x8,
-       HDMI_AUDIO_FS_96000 = 0xA,
-       HDMI_AUDIO_FS_176400 = 0xC,
-       HDMI_AUDIO_FS_192000 = 0xE,
-       HDMI_AUDIO_FS_NOT_INDICATED = 0x1
-};
-
-enum hdmi_core_audio_layout {
-       HDMI_AUDIO_LAYOUT_2CH = 0,
-       HDMI_AUDIO_LAYOUT_8CH = 1
-};
-
-enum hdmi_core_cts_mode {
-       HDMI_AUDIO_CTS_MODE_HW = 0,
-       HDMI_AUDIO_CTS_MODE_SW = 1
-};
-
-enum hdmi_stereo_channels {
-       HDMI_AUDIO_STEREO_NOCHANNELS = 0,
-       HDMI_AUDIO_STEREO_ONECHANNEL = 1,
-       HDMI_AUDIO_STEREO_TWOCHANNELS = 2,
-       HDMI_AUDIO_STEREO_THREECHANNELS = 3,
-       HDMI_AUDIO_STEREO_FOURCHANNELS = 4
-};
-
-enum hdmi_audio_type {
-       HDMI_AUDIO_TYPE_LPCM = 0,
-       HDMI_AUDIO_TYPE_IEC = 1
-};
-
-enum hdmi_audio_justify {
-       HDMI_AUDIO_JUSTIFY_LEFT = 0,
-       HDMI_AUDIO_JUSTIFY_RIGHT = 1
-};
-
-enum hdmi_audio_sample_order {
-       HDMI_AUDIO_SAMPLE_RIGHT_FIRST = 0,
-       HDMI_AUDIO_SAMPLE_LEFT_FIRST = 1
-};
-
-enum hdmi_audio_samples_perword {
-       HDMI_AUDIO_ONEWORD_ONESAMPLE = 0,
-       HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1
-};
-
-enum hdmi_audio_sample_size {
-       HDMI_AUDIO_SAMPLE_16BITS = 0,
-       HDMI_AUDIO_SAMPLE_24BITS = 1
-};
-
-enum hdmi_audio_transf_mode {
-       HDMI_AUDIO_TRANSF_DMA = 0,
-       HDMI_AUDIO_TRANSF_IRQ = 1
-};
-
-enum hdmi_audio_blk_strt_end_sig {
-       HDMI_AUDIO_BLOCK_SIG_STARTEND_ON = 0,
-       HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF = 1
-};
-
-enum hdmi_audio_i2s_config {
-       HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT = 0,
-       HDMI_AUDIO_I2S_WS_POLARIT_YLOW_IS_RIGHT = 1,
-       HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0,
-       HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1,
-       HDMI_AUDIO_I2S_MAX_WORD_20BITS = 0,
-       HDMI_AUDIO_I2S_MAX_WORD_24BITS = 1,
-       HDMI_AUDIO_I2S_CHST_WORD_NOT_SPECIFIED = 0,
-       HDMI_AUDIO_I2S_CHST_WORD_16_BITS = 1,
-       HDMI_AUDIO_I2S_CHST_WORD_17_BITS = 6,
-       HDMI_AUDIO_I2S_CHST_WORD_18_BITS = 2,
-       HDMI_AUDIO_I2S_CHST_WORD_19_BITS = 4,
-       HDMI_AUDIO_I2S_CHST_WORD_20_BITS_20MAX = 5,
-       HDMI_AUDIO_I2S_CHST_WORD_20_BITS_24MAX = 1,
-       HDMI_AUDIO_I2S_CHST_WORD_21_BITS = 6,
-       HDMI_AUDIO_I2S_CHST_WORD_22_BITS = 2,
-       HDMI_AUDIO_I2S_CHST_WORD_23_BITS = 4,
-       HDMI_AUDIO_I2S_CHST_WORD_24_BITS = 5,
-       HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0,
-       HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1,
-       HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0,
-       HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_NA = 0,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_16 = 2,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_17 = 12,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_18 = 4,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_19 = 8,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_20 = 10,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_21 = 13,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_22 = 5,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_23 = 9,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_24 = 11,
-       HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0,
-       HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1,
-       HDMI_AUDIO_I2S_SD0_EN = 1,
-       HDMI_AUDIO_I2S_SD1_EN = 1 << 1,
-       HDMI_AUDIO_I2S_SD2_EN = 1 << 2,
-       HDMI_AUDIO_I2S_SD3_EN = 1 << 3,
-};
-
-enum hdmi_audio_mclk_mode {
-       HDMI_AUDIO_MCLK_128FS = 0,
-       HDMI_AUDIO_MCLK_256FS = 1,
-       HDMI_AUDIO_MCLK_384FS = 2,
-       HDMI_AUDIO_MCLK_512FS = 3,
-       HDMI_AUDIO_MCLK_768FS = 4,
-       HDMI_AUDIO_MCLK_1024FS = 5,
-       HDMI_AUDIO_MCLK_1152FS = 6,
-       HDMI_AUDIO_MCLK_192FS = 7
-};
-
-struct hdmi_core_video_config {
-       enum hdmi_core_inputbus_width   ip_bus_width;
-       enum hdmi_core_dither_trunc     op_dither_truc;
-       enum hdmi_core_deepcolor_ed     deep_color_pkt;
-       enum hdmi_core_packet_mode      pkt_mode;
-       enum hdmi_core_hdmi_dvi         hdmi_dvi;
-       enum hdmi_core_tclkselclkmult   tclk_sel_clkmult;
-};
-
-/*
- * Refer to section 8.2 in HDMI 1.3 specification for
- * details about infoframe databytes
- */
-struct hdmi_core_infoframe_avi {
-       u8      db1_format;
-               /* Y0, Y1 rgb,yCbCr */
-       u8      db1_active_info;
-               /* A0  Active information Present */
-       u8      db1_bar_info_dv;
-               /* B0, B1 Bar info data valid */
-       u8      db1_scan_info;
-               /* S0, S1 scan information */
-       u8      db2_colorimetry;
-               /* C0, C1 colorimetry */
-       u8      db2_aspect_ratio;
-               /* M0, M1 Aspect ratio (4:3, 16:9) */
-       u8      db2_active_fmt_ar;
-               /* R0...R3 Active format aspect ratio */
-       u8      db3_itc;
-               /* ITC IT content. */
-       u8      db3_ec;
-               /* EC0, EC1, EC2 Extended colorimetry */
-       u8      db3_q_range;
-               /* Q1, Q0 Quantization range */
-       u8      db3_nup_scaling;
-               /* SC1, SC0 Non-uniform picture scaling */
-       u8      db4_videocode;
-               /* VIC0..6 Video format identification */
-       u8      db5_pixel_repeat;
-               /* PR0..PR3 Pixel repetition factor */
-       u16     db6_7_line_eoftop;
-               /* Line number end of top bar */
-       u16     db8_9_line_sofbottom;
-               /* Line number start of bottom bar */
-       u16     db10_11_pixel_eofleft;
-               /* Pixel number end of left bar */
-       u16     db12_13_pixel_sofright;
-               /* Pixel number start of right bar */
-};
-/*
- * Refer to section 8.2 in HDMI 1.3 specification for
- * details about infoframe databytes
- */
-struct hdmi_core_infoframe_audio {
-       u8 db1_coding_type;
-       u8 db1_channel_count;
-       u8 db2_sample_freq;
-       u8 db2_sample_size;
-       u8 db4_channel_alloc;
-       bool db5_downmix_inh;
-       u8 db5_lsv;     /* Level shift values for downmix */
-};
-
-struct hdmi_core_packet_enable_repeat {
-       u32     audio_pkt;
-       u32     audio_pkt_repeat;
-       u32     avi_infoframe;
-       u32     avi_infoframe_repeat;
-       u32     gen_cntrl_pkt;
-       u32     gen_cntrl_pkt_repeat;
-       u32     generic_pkt;
-       u32     generic_pkt_repeat;
-};
-
-struct hdmi_video_format {
-       enum hdmi_packing_mode  packing_mode;
-       u32                     y_res;  /* Line per panel */
-       u32                     x_res;  /* pixel per line */
-};
-
-struct hdmi_video_interface {
-       int     vsp;    /* Vsync polarity */
-       int     hsp;    /* Hsync polarity */
-       int     interlacing;
-       int     tm;     /* Timing mode */
-};
-
-struct hdmi_cm {
-       int     code;
-       int     mode;
-};
-
-struct hdmi_config {
-       struct hdmi_timings timings;
-       u16     interlace;
-       struct hdmi_cm cm;
-};
-
-struct hdmi_audio_format {
-       enum hdmi_stereo_channels               stereo_channels;
-       u8                                      active_chnnls_msk;
-       enum hdmi_audio_type                    type;
-       enum hdmi_audio_justify                 justification;
-       enum hdmi_audio_sample_order            sample_order;
-       enum hdmi_audio_samples_perword         samples_per_word;
-       enum hdmi_audio_sample_size             sample_size;
-       enum hdmi_audio_blk_strt_end_sig        en_sig_blk_strt_end;
-};
-
-struct hdmi_audio_dma {
-       u8                              transfer_size;
-       u8                              block_size;
-       enum hdmi_audio_transf_mode     mode;
-       u16                             fifo_threshold;
-};
-
-struct hdmi_core_audio_i2s_config {
-       u8 word_max_length;
-       u8 word_length;
-       u8 in_length_bits;
-       u8 justification;
-       u8 en_high_bitrate_aud;
-       u8 sck_edge_mode;
-       u8 cbit_order;
-       u8 vbit;
-       u8 ws_polarity;
-       u8 direction;
-       u8 shift;
-       u8 active_sds;
-};
-
-struct hdmi_core_audio_config {
-       struct hdmi_core_audio_i2s_config       i2s_cfg;
-       enum hdmi_core_audio_sample_freq        freq_sample;
-       bool                                    fs_override;
-       u32                                     n;
-       u32                                     cts;
-       u32                                     aud_par_busclk;
-       enum hdmi_core_audio_layout             layout;
-       enum hdmi_core_cts_mode                 cts_mode;
-       bool                                    use_mclk;
-       enum hdmi_audio_mclk_mode               mclk_mode;
-       bool                                    en_acr_pkt;
-       bool                                    en_dsd_audio;
-       bool                                    en_parallel_aud_input;
-       bool                                    en_spdif;
-};
-#endif
diff --git a/drivers/video/omap2/dss/hdmi_omap4_panel.c b/drivers/video/omap2/dss/hdmi_omap4_panel.c
deleted file mode 100644 (file)
index 7d4f2bd..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * hdmi_omap4_panel.c
- *
- * HDMI library support functions for TI OMAP4 processors.
- *
- * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
- * Authors:    Mythri P k <mythripk@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
-#include <linux/module.h>
-#include <video/omapdss.h>
-
-#include "dss.h"
-
-static struct {
-       struct mutex hdmi_lock;
-} hdmi;
-
-
-static int hdmi_panel_probe(struct omap_dss_device *dssdev)
-{
-       DSSDBG("ENTER hdmi_panel_probe\n");
-
-       dssdev->panel.config = OMAP_DSS_LCD_TFT |
-                       OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS;
-
-       /*
-        * Initialize the timings to 640 * 480
-        * This is only for framebuffer update not for TV timing setting
-        * Setting TV timing will be done only on enable
-        */
-       dssdev->panel.timings.x_res = 640;
-       dssdev->panel.timings.y_res = 480;
-
-       DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n",
-               dssdev->panel.timings.x_res,
-               dssdev->panel.timings.y_res);
-       return 0;
-}
-
-static void hdmi_panel_remove(struct omap_dss_device *dssdev)
-{
-
-}
-
-static int hdmi_panel_enable(struct omap_dss_device *dssdev)
-{
-       int r = 0;
-       DSSDBG("ENTER hdmi_panel_enable\n");
-
-       mutex_lock(&hdmi.hdmi_lock);
-
-       if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
-               r = -EINVAL;
-               goto err;
-       }
-
-       r = omapdss_hdmi_display_enable(dssdev);
-       if (r) {
-               DSSERR("failed to power on\n");
-               goto err;
-       }
-
-       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
-err:
-       mutex_unlock(&hdmi.hdmi_lock);
-
-       return r;
-}
-
-static void hdmi_panel_disable(struct omap_dss_device *dssdev)
-{
-       mutex_lock(&hdmi.hdmi_lock);
-
-       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
-               omapdss_hdmi_display_disable(dssdev);
-
-       dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-
-       mutex_unlock(&hdmi.hdmi_lock);
-}
-
-static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
-{
-       int r = 0;
-
-       mutex_lock(&hdmi.hdmi_lock);
-
-       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
-               r = -EINVAL;
-               goto err;
-       }
-
-       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
-
-       omapdss_hdmi_display_disable(dssdev);
-
-err:
-       mutex_unlock(&hdmi.hdmi_lock);
-
-       return r;
-}
-
-static int hdmi_panel_resume(struct omap_dss_device *dssdev)
-{
-       int r = 0;
-
-       mutex_lock(&hdmi.hdmi_lock);
-
-       if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
-               r = -EINVAL;
-               goto err;
-       }
-
-       r = omapdss_hdmi_display_enable(dssdev);
-       if (r) {
-               DSSERR("failed to power on\n");
-               goto err;
-       }
-
-       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
-err:
-       mutex_unlock(&hdmi.hdmi_lock);
-
-       return r;
-}
-
-static void hdmi_get_timings(struct omap_dss_device *dssdev,
-                       struct omap_video_timings *timings)
-{
-       mutex_lock(&hdmi.hdmi_lock);
-
-       *timings = dssdev->panel.timings;
-
-       mutex_unlock(&hdmi.hdmi_lock);
-}
-
-static void hdmi_set_timings(struct omap_dss_device *dssdev,
-                       struct omap_video_timings *timings)
-{
-       DSSDBG("hdmi_set_timings\n");
-
-       mutex_lock(&hdmi.hdmi_lock);
-
-       dssdev->panel.timings = *timings;
-
-       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
-               /* turn the hdmi off and on to get new timings to use */
-               omapdss_hdmi_display_disable(dssdev);
-               omapdss_hdmi_display_set_timing(dssdev);
-       }
-
-       mutex_unlock(&hdmi.hdmi_lock);
-}
-
-static int hdmi_check_timings(struct omap_dss_device *dssdev,
-                       struct omap_video_timings *timings)
-{
-       int r = 0;
-
-       DSSDBG("hdmi_check_timings\n");
-
-       mutex_lock(&hdmi.hdmi_lock);
-
-       r = omapdss_hdmi_display_check_timing(dssdev, timings);
-       if (r) {
-               DSSERR("Timing cannot be applied\n");
-               goto err;
-       }
-err:
-       mutex_unlock(&hdmi.hdmi_lock);
-       return r;
-}
-
-static struct omap_dss_driver hdmi_driver = {
-       .probe          = hdmi_panel_probe,
-       .remove         = hdmi_panel_remove,
-       .enable         = hdmi_panel_enable,
-       .disable        = hdmi_panel_disable,
-       .suspend        = hdmi_panel_suspend,
-       .resume         = hdmi_panel_resume,
-       .get_timings    = hdmi_get_timings,
-       .set_timings    = hdmi_set_timings,
-       .check_timings  = hdmi_check_timings,
-       .driver                 = {
-               .name   = "hdmi_panel",
-               .owner  = THIS_MODULE,
-       },
-};
-
-int hdmi_panel_init(void)
-{
-       mutex_init(&hdmi.hdmi_lock);
-
-       omap_dss_register_driver(&hdmi_driver);
-
-       return 0;
-}
-
-void hdmi_panel_exit(void)
-{
-       omap_dss_unregister_driver(&hdmi_driver);
-
-}
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c
new file mode 100644 (file)
index 0000000..533d5dc
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * hdmi_panel.c
+ *
+ * HDMI library support functions for TI OMAP4 processors.
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Authors:    Mythri P k <mythripk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <video/omapdss.h>
+#include <linux/slab.h>
+
+#include "dss.h"
+
+static struct {
+       struct mutex hdmi_lock;
+} hdmi;
+
+
+static int hdmi_panel_probe(struct omap_dss_device *dssdev)
+{
+       DSSDBG("ENTER hdmi_panel_probe\n");
+
+       dssdev->panel.config = OMAP_DSS_LCD_TFT |
+                       OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS;
+
+       dssdev->panel.timings = (struct omap_video_timings){640, 480, 25175, 96, 16, 48, 2 , 11, 31};
+
+       DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n",
+               dssdev->panel.timings.x_res,
+               dssdev->panel.timings.y_res);
+       return 0;
+}
+
+static void hdmi_panel_remove(struct omap_dss_device *dssdev)
+{
+
+}
+
+static int hdmi_panel_enable(struct omap_dss_device *dssdev)
+{
+       int r = 0;
+       DSSDBG("ENTER hdmi_panel_enable\n");
+
+       mutex_lock(&hdmi.hdmi_lock);
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+               r = -EINVAL;
+               goto err;
+       }
+
+       r = omapdss_hdmi_display_enable(dssdev);
+       if (r) {
+               DSSERR("failed to power on\n");
+               goto err;
+       }
+
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+err:
+       mutex_unlock(&hdmi.hdmi_lock);
+
+       return r;
+}
+
+static void hdmi_panel_disable(struct omap_dss_device *dssdev)
+{
+       mutex_lock(&hdmi.hdmi_lock);
+
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               omapdss_hdmi_display_disable(dssdev);
+
+       dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+       mutex_unlock(&hdmi.hdmi_lock);
+}
+
+static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
+{
+       int r = 0;
+
+       mutex_lock(&hdmi.hdmi_lock);
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
+               r = -EINVAL;
+               goto err;
+       }
+
+       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+       omapdss_hdmi_display_disable(dssdev);
+
+err:
+       mutex_unlock(&hdmi.hdmi_lock);
+
+       return r;
+}
+
+static int hdmi_panel_resume(struct omap_dss_device *dssdev)
+{
+       int r = 0;
+
+       mutex_lock(&hdmi.hdmi_lock);
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
+               r = -EINVAL;
+               goto err;
+       }
+
+       r = omapdss_hdmi_display_enable(dssdev);
+       if (r) {
+               DSSERR("failed to power on\n");
+               goto err;
+       }
+
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+err:
+       mutex_unlock(&hdmi.hdmi_lock);
+
+       return r;
+}
+
+static void hdmi_get_timings(struct omap_dss_device *dssdev,
+                       struct omap_video_timings *timings)
+{
+       mutex_lock(&hdmi.hdmi_lock);
+
+       *timings = dssdev->panel.timings;
+
+       mutex_unlock(&hdmi.hdmi_lock);
+}
+
+static void hdmi_set_timings(struct omap_dss_device *dssdev,
+                       struct omap_video_timings *timings)
+{
+       DSSDBG("hdmi_set_timings\n");
+
+       mutex_lock(&hdmi.hdmi_lock);
+
+       dssdev->panel.timings = *timings;
+       omapdss_hdmi_display_set_timing(dssdev);
+
+       mutex_unlock(&hdmi.hdmi_lock);
+}
+
+static int hdmi_check_timings(struct omap_dss_device *dssdev,
+                       struct omap_video_timings *timings)
+{
+       int r = 0;
+
+       DSSDBG("hdmi_check_timings\n");
+
+       mutex_lock(&hdmi.hdmi_lock);
+
+       r = omapdss_hdmi_display_check_timing(dssdev, timings);
+
+       mutex_unlock(&hdmi.hdmi_lock);
+       return r;
+}
+
+static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len)
+{
+       int r;
+
+       mutex_lock(&hdmi.hdmi_lock);
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
+               r = omapdss_hdmi_display_enable(dssdev);
+               if (r)
+                       goto err;
+       }
+
+       r = omapdss_hdmi_read_edid(buf, len);
+
+       if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
+                       dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
+               omapdss_hdmi_display_disable(dssdev);
+err:
+       mutex_unlock(&hdmi.hdmi_lock);
+
+       return r;
+}
+
+static bool hdmi_detect(struct omap_dss_device *dssdev)
+{
+       int r;
+
+       mutex_lock(&hdmi.hdmi_lock);
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
+               r = omapdss_hdmi_display_enable(dssdev);
+               if (r)
+                       goto err;
+       }
+
+       r = omapdss_hdmi_detect();
+
+       if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
+                       dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
+               omapdss_hdmi_display_disable(dssdev);
+err:
+       mutex_unlock(&hdmi.hdmi_lock);
+
+       return r;
+}
+
+static struct omap_dss_driver hdmi_driver = {
+       .probe          = hdmi_panel_probe,
+       .remove         = hdmi_panel_remove,
+       .enable         = hdmi_panel_enable,
+       .disable        = hdmi_panel_disable,
+       .suspend        = hdmi_panel_suspend,
+       .resume         = hdmi_panel_resume,
+       .get_timings    = hdmi_get_timings,
+       .set_timings    = hdmi_set_timings,
+       .check_timings  = hdmi_check_timings,
+       .read_edid      = hdmi_read_edid,
+       .detect         = hdmi_detect,
+       .driver                 = {
+               .name   = "hdmi_panel",
+               .owner  = THIS_MODULE,
+       },
+};
+
+int hdmi_panel_init(void)
+{
+       mutex_init(&hdmi.hdmi_lock);
+
+       omap_dss_register_driver(&hdmi_driver);
+
+       return 0;
+}
+
+void hdmi_panel_exit(void)
+{
+       omap_dss_unregister_driver(&hdmi_driver);
+
+}
index 13d72d5..6e63845 100644 (file)
@@ -106,7 +106,7 @@ put_device:
 static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
                                          char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.default_color);
+       return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.default_color);
 }
 
 static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
@@ -116,8 +116,9 @@ static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
        u32 color;
        int r;
 
-       if (sscanf(buf, "%d", &color) != 1)
-               return -EINVAL;
+       r = kstrtouint(buf, 0, &color);
+       if (r)
+               return r;
 
        mgr->get_manager_info(mgr, &info);
 
@@ -184,7 +185,7 @@ static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
 static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
                                            char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_key);
+       return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.trans_key);
 }
 
 static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
@@ -194,8 +195,9 @@ static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
        u32 key_value;
        int r;
 
-       if (sscanf(buf, "%d", &key_value) != 1)
-               return -EINVAL;
+       r = kstrtouint(buf, 0, &key_value);
+       if (r)
+               return r;
 
        mgr->get_manager_info(mgr, &info);
 
@@ -222,15 +224,16 @@ static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
                                               const char *buf, size_t size)
 {
        struct omap_overlay_manager_info info;
-       int enable;
+       bool enable;
        int r;
 
-       if (sscanf(buf, "%d", &enable) != 1)
-               return -EINVAL;
+       r = strtobool(buf, &enable);
+       if (r)
+               return r;
 
        mgr->get_manager_info(mgr, &info);
 
-       info.trans_enabled = enable ? true : false;
+       info.trans_enabled = enable;
 
        r = mgr->set_manager_info(mgr, &info);
        if (r)
@@ -246,7 +249,10 @@ static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
 static ssize_t manager_alpha_blending_enabled_show(
                struct omap_overlay_manager *mgr, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.alpha_enabled);
+       WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+               mgr->info.partial_alpha_enabled);
 }
 
 static ssize_t manager_alpha_blending_enabled_store(
@@ -254,15 +260,18 @@ static ssize_t manager_alpha_blending_enabled_store(
                const char *buf, size_t size)
 {
        struct omap_overlay_manager_info info;
-       int enable;
+       bool enable;
        int r;
 
-       if (sscanf(buf, "%d", &enable) != 1)
-               return -EINVAL;
+       WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
+
+       r = strtobool(buf, &enable);
+       if (r)
+               return r;
 
        mgr->get_manager_info(mgr, &info);
 
-       info.alpha_enabled = enable ? true : false;
+       info.partial_alpha_enabled = enable;
 
        r = mgr->set_manager_info(mgr, &info);
        if (r)
@@ -285,19 +294,16 @@ static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
                const char *buf, size_t size)
 {
        struct omap_overlay_manager_info info;
-       int v;
        int r;
        bool enable;
 
        if (!dss_has_feature(FEAT_CPR))
                return -ENODEV;
 
-       r = kstrtoint(buf, 0, &v);
+       r = strtobool(buf, &enable);
        if (r)
                return r;
 
-       enable = !!v;
-
        mgr->get_manager_info(mgr, &info);
 
        if (info.cpr_enable == enable)
@@ -586,6 +592,13 @@ static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
                return -EINVAL;
        }
 
+       /*
+        * Don't allow currently enabled displays to have the overlay manager
+        * pulled out from underneath them
+        */
+       if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED)
+               return -EINVAL;
+
        mgr->device->manager = NULL;
        mgr->device = NULL;
        mgr->device_changed = true;
@@ -801,7 +814,7 @@ static int configure_overlay(enum omap_plane plane)
 {
        struct overlay_cache_data *c;
        struct manager_cache_data *mc;
-       struct omap_overlay_info *oi;
+       struct omap_overlay_info *oi, new_oi;
        struct omap_overlay_manager_info *mi;
        u16 outw, outh;
        u16 x, y, w, h;
@@ -815,7 +828,7 @@ static int configure_overlay(enum omap_plane plane)
        oi = &c->info;
 
        if (!c->enabled) {
-               dispc_enable_plane(plane, 0);
+               dispc_ovl_enable(plane, 0);
                return 0;
        }
 
@@ -843,7 +856,7 @@ static int configure_overlay(enum omap_plane plane)
                /* If the overlay is outside the update region, disable it */
                if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
                                        x, y, outw, outh)) {
-                       dispc_enable_plane(plane, 0);
+                       dispc_ovl_enable(plane, 0);
                        return 0;
                }
 
@@ -921,34 +934,27 @@ static int configure_overlay(enum omap_plane plane)
                }
        }
 
-       r = dispc_setup_plane(plane,
-                       paddr,
-                       oi->screen_width,
-                       x, y,
-                       w, h,
-                       outw, outh,
-                       oi->color_mode,
-                       c->ilace,
-                       oi->rotation_type,
-                       oi->rotation,
-                       oi->mirror,
-                       oi->global_alpha,
-                       oi->pre_mult_alpha,
-                       c->channel,
-                       oi->p_uv_addr);
+       new_oi = *oi;
+
+       /* update new_oi members which could have been possibly updated */
+       new_oi.pos_x = x;
+       new_oi.pos_y = y;
+       new_oi.width = w;
+       new_oi.height = h;
+       new_oi.out_width = outw;
+       new_oi.out_height = outh;
+       new_oi.paddr = paddr;
 
+       r = dispc_ovl_setup(plane, &new_oi, c->ilace, c->channel,
+               c->replication, c->fifo_low, c->fifo_high);
        if (r) {
                /* this shouldn't happen */
-               DSSERR("dispc_setup_plane failed for ovl %d\n", plane);
-               dispc_enable_plane(plane, 0);
+               DSSERR("dispc_ovl_setup failed for ovl %d\n", plane);
+               dispc_ovl_enable(plane, 0);
                return r;
        }
 
-       dispc_enable_replication(plane, c->replication);
-
-       dispc_set_fifo_threshold(plane, c->fifo_low, c->fifo_high);
-
-       dispc_enable_plane(plane, 1);
+       dispc_ovl_enable(plane, 1);
 
        return 0;
 }
@@ -962,13 +968,13 @@ static void configure_manager(enum omap_channel channel)
        /* picking info from the cache */
        mi = &dss_cache.manager_cache[channel].info;
 
-       dispc_set_default_color(channel, mi->default_color);
-       dispc_set_trans_key(channel, mi->trans_key_type, mi->trans_key);
-       dispc_enable_trans_key(channel, mi->trans_enabled);
-       dispc_enable_alpha_blending(channel, mi->alpha_enabled);
+       dispc_mgr_set_default_color(channel, mi->default_color);
+       dispc_mgr_set_trans_key(channel, mi->trans_key_type, mi->trans_key);
+       dispc_mgr_enable_trans_key(channel, mi->trans_enabled);
+       dispc_mgr_enable_alpha_fixed_zorder(channel, mi->partial_alpha_enabled);
        if (dss_has_feature(FEAT_CPR)) {
-               dispc_enable_cpr(channel, mi->cpr_enable);
-               dispc_set_cpr_coef(channel, &mi->cpr_coefs);
+               dispc_mgr_enable_cpr(channel, mi->cpr_enable);
+               dispc_mgr_set_cpr_coef(channel, &mi->cpr_coefs);
        }
 }
 
@@ -992,7 +998,7 @@ static int configure_dispc(void)
        busy = false;
 
        for (i = 0; i < num_mgrs; i++) {
-               mgr_busy[i] = dispc_go_busy(i);
+               mgr_busy[i] = dispc_mgr_go_busy(i);
                mgr_go[i] = false;
        }
 
@@ -1053,7 +1059,7 @@ static int configure_dispc(void)
                 * always be turned off after frame, and new settings will be
                 * taken in to use at next update */
                if (!mc->manual_update)
-                       dispc_go(i);
+                       dispc_mgr_go(i);
        }
 
        if (busy)
@@ -1258,7 +1264,7 @@ static void dss_apply_irq_handler(void *data, u32 mask)
        u32 irq_mask;
 
        for (i = 0; i < num_mgrs; i++)
-               mgr_busy[i] = dispc_go_busy(i);
+               mgr_busy[i] = dispc_mgr_go_busy(i);
 
        spin_lock(&dss_cache.lock);
 
@@ -1280,7 +1286,7 @@ static void dss_apply_irq_handler(void *data, u32 mask)
 
        /* re-read busy flags */
        for (i = 0; i < num_mgrs; i++)
-               mgr_busy[i] = dispc_go_busy(i);
+               mgr_busy[i] = dispc_mgr_go_busy(i);
 
        /* keep running as long as there are busy managers, so that
         * we can collect overlay-applied information */
@@ -1326,11 +1332,13 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
                ovl = omap_dss_get_overlay(i);
 
-               if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
-                       continue;
-
                oc = &dss_cache.overlay_cache[ovl->id];
 
+               if (ovl->manager_changed) {
+                       ovl->manager_changed = false;
+                       ovl->info_dirty  = true;
+               }
+
                if (!overlay_enabled(ovl)) {
                        if (oc->enabled) {
                                oc->enabled = false;
@@ -1375,9 +1383,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
        list_for_each_entry(mgr, &manager_list, list) {
                struct omap_dss_device *dssdev;
 
-               if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
-                       continue;
-
                mc = &dss_cache.manager_cache[mgr->id];
 
                if (mgr->device_changed) {
@@ -1423,9 +1428,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
                ovl = omap_dss_get_overlay(i);
 
-               if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
-                       continue;
-
                oc = &dss_cache.overlay_cache[ovl->id];
 
                if (!oc->enabled)
@@ -1433,11 +1435,11 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
                dssdev = ovl->manager->device;
 
-               size = dispc_get_plane_fifo_size(ovl->id);
+               size = dispc_ovl_get_fifo_size(ovl->id);
                if (use_fifomerge)
                        size *= 3;
 
-               burst_size = dispc_get_burst_size(ovl->id);
+               burst_size = dispc_ovl_get_burst_size(ovl->id);
 
                switch (dssdev->type) {
                case OMAP_DISPLAY_TYPE_DPI:
@@ -1484,12 +1486,17 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
 static int dss_check_manager(struct omap_overlay_manager *mgr)
 {
-       /* OMAP supports only graphics source transparency color key and alpha
-        * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */
-
-       if (mgr->info.alpha_enabled && mgr->info.trans_enabled &&
-                       mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST)
-               return -EINVAL;
+       if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
+               /*
+                * OMAP3 supports only graphics source transparency color key
+                * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
+                * Alpha Mode
+                */
+               if (mgr->info.partial_alpha_enabled && mgr->info.trans_enabled
+                       && mgr->info.trans_key_type !=
+                               OMAP_DSS_COLOR_KEY_GFX_DST)
+                       return -EINVAL;
+       }
 
        return 0;
 }
@@ -1522,13 +1529,13 @@ static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
 
 static int dss_mgr_enable(struct omap_overlay_manager *mgr)
 {
-       dispc_enable_channel(mgr->id, 1);
+       dispc_mgr_enable(mgr->id, 1);
        return 0;
 }
 
 static int dss_mgr_disable(struct omap_overlay_manager *mgr)
 {
-       dispc_enable_channel(mgr->id, 0);
+       dispc_mgr_enable(mgr->id, 0);
        return 0;
 }
 
@@ -1580,7 +1587,7 @@ int dss_init_overlay_managers(struct platform_device *pdev)
                mgr->enable = &dss_mgr_enable;
                mgr->disable = &dss_mgr_disable;
 
-               mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
+               mgr->caps = 0;
                mgr->supported_displays =
                        dss_feat_get_supported_displays(mgr->id);
 
@@ -1597,42 +1604,6 @@ int dss_init_overlay_managers(struct platform_device *pdev)
                }
        }
 
-#ifdef L4_EXAMPLE
-       {
-               int omap_dss_mgr_apply_l4(struct omap_overlay_manager *mgr)
-               {
-                       DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name);
-
-                       return 0;
-               }
-
-               struct omap_overlay_manager *mgr;
-               mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
-
-               BUG_ON(mgr == NULL);
-
-               mgr->name = "l4";
-               mgr->supported_displays =
-                       OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI;
-
-               mgr->set_device = &omap_dss_set_device;
-               mgr->unset_device = &omap_dss_unset_device;
-               mgr->apply = &omap_dss_mgr_apply_l4;
-               mgr->set_manager_info = &omap_dss_mgr_set_info;
-               mgr->get_manager_info = &omap_dss_mgr_get_info;
-
-               dss_overlay_setup_l4_manager(mgr);
-
-               omap_dss_add_overlay_manager(mgr);
-
-               r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
-                               &pdev->dev.kobj, "managerl4");
-
-               if (r)
-                       DSSERR("failed to create sysfs file\n");
-       }
-#endif
-
        return 0;
 }
 
index c84380c..ab8e40e 100644 (file)
@@ -211,16 +211,17 @@ static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
 static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
                size_t size)
 {
-       int r, enable;
+       int r;
+       bool enable;
        struct omap_overlay_info info;
 
        ovl->get_overlay_info(ovl, &info);
 
-       r = kstrtoint(buf, 0, &enable);
+       r = strtobool(buf, &enable);
        if (r)
                return r;
 
-       info.enabled = !!enable;
+       info.enabled = enable;
 
        r = ovl->set_overlay_info(ovl, &info);
        if (r)
@@ -248,7 +249,7 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
        u8 alpha;
        struct omap_overlay_info info;
 
-       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
                return -ENODEV;
 
        r = kstrtou8(buf, 0, &alpha);
@@ -257,14 +258,7 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
 
        ovl->get_overlay_info(ovl, &info);
 
-       /* Video1 plane does not support global alpha
-        * to always make it 255 completely opaque
-        */
-       if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
-                       ovl->id == OMAP_DSS_VIDEO1)
-               info.global_alpha = 255;
-       else
-               info.global_alpha = alpha;
+       info.global_alpha = alpha;
 
        r = ovl->set_overlay_info(ovl, &info);
        if (r)
@@ -293,20 +287,52 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
        u8 alpha;
        struct omap_overlay_info info;
 
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
+               return -ENODEV;
+
        r = kstrtou8(buf, 0, &alpha);
        if (r)
                return r;
 
        ovl->get_overlay_info(ovl, &info);
 
-       /* only GFX and Video2 plane support pre alpha multiplied
-        * set zero for Video1 plane
-        */
-       if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
-               ovl->id == OMAP_DSS_VIDEO1)
-               info.pre_mult_alpha = 0;
-       else
-               info.pre_mult_alpha = alpha;
+       info.pre_mult_alpha = alpha;
+
+       r = ovl->set_overlay_info(ovl, &info);
+       if (r)
+               return r;
+
+       if (ovl->manager) {
+               r = ovl->manager->apply(ovl->manager);
+               if (r)
+                       return r;
+       }
+
+       return size;
+}
+
+static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.zorder);
+}
+
+static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
+               const char *buf, size_t size)
+{
+       int r;
+       u8 zorder;
+       struct omap_overlay_info info;
+
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+               return -ENODEV;
+
+       r = kstrtou8(buf, 0, &zorder);
+       if (r)
+               return r;
+
+       ovl->get_overlay_info(ovl, &info);
+
+       info.zorder = zorder;
 
        r = ovl->set_overlay_info(ovl, &info);
        if (r)
@@ -347,6 +373,8 @@ static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
 static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
                overlay_pre_mult_alpha_show,
                overlay_pre_mult_alpha_store);
+static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
+               overlay_zorder_show, overlay_zorder_store);
 
 static struct attribute *overlay_sysfs_attrs[] = {
        &overlay_attr_name.attr,
@@ -358,6 +386,7 @@ static struct attribute *overlay_sysfs_attrs[] = {
        &overlay_attr_enabled.attr,
        &overlay_attr_global_alpha.attr,
        &overlay_attr_pre_mult_alpha.attr,
+       &overlay_attr_zorder.attr,
        NULL
 };
 
@@ -407,6 +436,7 @@ int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
        struct omap_overlay_info *info;
        u16 outw, outh;
        u16 dw, dh;
+       int i;
 
        if (!dssdev)
                return 0;
@@ -462,6 +492,31 @@ int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
                return -EINVAL;
        }
 
+       if (ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) {
+               if (info->zorder < 0 || info->zorder > 3) {
+                       DSSERR("zorder out of range: %d\n",
+                               info->zorder);
+                       return -EINVAL;
+               }
+               /*
+                * Check that zorder doesn't match with zorder of any other
+                * overlay which is enabled and is also connected to the same
+                * manager
+                */
+               for (i = 0; i < omap_dss_get_num_overlays(); i++) {
+                       struct omap_overlay *tmp_ovl = omap_dss_get_overlay(i);
+
+                       if (tmp_ovl->id != ovl->id &&
+                                       tmp_ovl->manager == ovl->manager &&
+                                       tmp_ovl->info.enabled == true &&
+                                       tmp_ovl->info.zorder == info->zorder) {
+                               DSSERR("%s and %s have same zorder: %d\n",
+                                       ovl->name, tmp_ovl->name, info->zorder);
+                               return -EINVAL;
+                       }
+               }
+       }
+
        return 0;
 }
 
@@ -516,6 +571,7 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
        }
 
        ovl->manager = mgr;
+       ovl->manager_changed = true;
 
        /* XXX: When there is an overlay on a DSI manual update display, and
         * the overlay is first disabled, then moved to tv, and enabled, we
@@ -529,15 +585,12 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
         * Userspace workaround for this is to update the LCD after disabling
         * the overlay, but before moving the overlay to TV.
         */
-       dispc_set_channel_out(ovl->id, mgr->id);
 
        return 0;
 }
 
 static int omap_dss_unset_manager(struct omap_overlay *ovl)
 {
-       int r;
-
        if (!ovl->manager) {
                DSSERR("failed to detach overlay: manager not set\n");
                return -EINVAL;
@@ -548,11 +601,8 @@ static int omap_dss_unset_manager(struct omap_overlay *ovl)
                return -EINVAL;
        }
 
-       r = ovl->wait_for_go(ovl);
-       if (r)
-               return r;
-
        ovl->manager = NULL;
+       ovl->manager_changed = true;
 
        return 0;
 }
@@ -618,22 +668,29 @@ void dss_init_overlays(struct platform_device *pdev)
                case 0:
                        ovl->name = "gfx";
                        ovl->id = OMAP_DSS_GFX;
-                       ovl->caps = OMAP_DSS_OVL_CAP_DISPC;
                        ovl->info.global_alpha = 255;
+                       ovl->info.zorder = 0;
                        break;
                case 1:
                        ovl->name = "vid1";
                        ovl->id = OMAP_DSS_VIDEO1;
-                       ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
-                               OMAP_DSS_OVL_CAP_DISPC;
                        ovl->info.global_alpha = 255;
+                       ovl->info.zorder =
+                               dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
                        break;
                case 2:
                        ovl->name = "vid2";
                        ovl->id = OMAP_DSS_VIDEO2;
-                       ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
-                               OMAP_DSS_OVL_CAP_DISPC;
                        ovl->info.global_alpha = 255;
+                       ovl->info.zorder =
+                               dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
+                       break;
+               case 3:
+                       ovl->name = "vid3";
+                       ovl->id = OMAP_DSS_VIDEO3;
+                       ovl->info.global_alpha = 255;
+                       ovl->info.zorder =
+                               dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
                        break;
                }
 
@@ -643,6 +700,7 @@ void dss_init_overlays(struct platform_device *pdev)
                ovl->get_overlay_info = &dss_ovl_get_overlay_info;
                ovl->wait_for_go = &dss_ovl_wait_for_go;
 
+               ovl->caps = dss_feat_get_overlay_caps(ovl->id);
                ovl->supported_modes =
                        dss_feat_get_supported_color_modes(ovl->id);
 
index 39f4c59..1bd3703 100644 (file)
@@ -309,9 +309,9 @@ static void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
 
        DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
 
-       dispc_set_lcd_size(dssdev->manager->id, width, height);
+       dispc_mgr_set_lcd_size(dssdev->manager->id, width, height);
 
-       dispc_enable_channel(dssdev->manager->id, true);
+       dispc_mgr_enable(dssdev->manager->id, true);
 
        rfbi.framedone_callback = callback;
        rfbi.framedone_callback_data = data;
@@ -783,10 +783,8 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
        if (*w == 0 || *h == 0)
                return -EINVAL;
 
-       if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
-               dss_setup_partial_planes(dssdev, x, y, w, h, true);
-               dispc_set_lcd_size(dssdev->manager->id, *w, *h);
-       }
+       dss_setup_partial_planes(dssdev, x, y, w, h, true);
+       dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h);
 
        return 0;
 }
@@ -796,22 +794,7 @@ int omap_rfbi_update(struct omap_dss_device *dssdev,
                u16 x, u16 y, u16 w, u16 h,
                void (*callback)(void *), void *data)
 {
-       if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
-               rfbi_transfer_area(dssdev, w, h, callback, data);
-       } else {
-               struct omap_overlay *ovl;
-               void __iomem *addr;
-               int scr_width;
-
-               ovl = dssdev->manager->overlays[0];
-               scr_width = ovl->info.screen_width;
-               addr = ovl->info.vaddr;
-
-               omap_rfbi_write_pixels(addr, scr_width, x, y, w, h);
-
-               callback(data);
-       }
-
+       rfbi_transfer_area(dssdev, w, h, callback, data);
        return 0;
 }
 EXPORT_SYMBOL(omap_rfbi_update);
@@ -860,6 +843,11 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 {
        int r;
 
+       if (dssdev->manager == NULL) {
+               DSSERR("failed to enable display: no manager\n");
+               return -ENODEV;
+       }
+
        r = rfbi_runtime_get();
        if (r)
                return r;
@@ -877,13 +865,13 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
                goto err1;
        }
 
-       dispc_set_lcd_display_type(dssdev->manager->id,
+       dispc_mgr_set_lcd_display_type(dssdev->manager->id,
                        OMAP_DSS_LCD_DISPLAY_TFT);
 
-       dispc_set_parallel_interface_mode(dssdev->manager->id,
-                       OMAP_DSS_PARALLELMODE_RFBI);
+       dispc_mgr_set_io_pad_mode(DSS_IO_PAD_MODE_RFBI);
+       dispc_mgr_enable_stallmode(dssdev->manager->id, true);
 
-       dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size);
+       dispc_mgr_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size);
 
        rfbi_configure(dssdev->phy.rfbi.channel,
                               dssdev->ctrl.pixel_size,
@@ -952,10 +940,7 @@ static int omap_rfbihw_probe(struct platform_device *pdev)
 
        msleep(10);
 
-       if (cpu_is_omap24xx() || cpu_is_omap34xx() || cpu_is_omap3630())
-               clk = dss_get_ick();
-       else
-               clk = clk_get(&pdev->dev, "ick");
+       clk = clk_get(&pdev->dev, "ick");
        if (IS_ERR(clk)) {
                DSSERR("can't get ick\n");
                r = PTR_ERR(clk);
index 3a688c8..695dc04 100644 (file)
@@ -35,13 +35,13 @@ static struct {
 static void sdi_basic_init(struct omap_dss_device *dssdev)
 
 {
-       dispc_set_parallel_interface_mode(dssdev->manager->id,
-                       OMAP_DSS_PARALLELMODE_BYPASS);
+       dispc_mgr_set_io_pad_mode(DSS_IO_PAD_MODE_BYPASS);
+       dispc_mgr_enable_stallmode(dssdev->manager->id, false);
 
-       dispc_set_lcd_display_type(dssdev->manager->id,
+       dispc_mgr_set_lcd_display_type(dssdev->manager->id,
                        OMAP_DSS_LCD_DISPLAY_TFT);
 
-       dispc_set_tft_data_lines(dssdev->manager->id, 24);
+       dispc_mgr_set_tft_data_lines(dssdev->manager->id, 24);
        dispc_lcd_enable_signal_polarity(1);
 }
 
@@ -55,6 +55,11 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        unsigned long pck;
        int r;
 
+       if (dssdev->manager == NULL) {
+               DSSERR("failed to enable display: no manager\n");
+               return -ENODEV;
+       }
+
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
@@ -78,7 +83,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        /* 15.5.9.1.2 */
        dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF;
 
-       dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
+       dispc_mgr_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
                        dssdev->panel.acbi, dssdev->panel.acb);
 
        r = dss_calc_clock_div(1, t->pixel_clock * 1000,
@@ -101,13 +106,13 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        }
 
 
-       dispc_set_lcd_timings(dssdev->manager->id, t);
+       dispc_mgr_set_lcd_timings(dssdev->manager->id, t);
 
        r = dss_set_clock_div(&dss_cinfo);
        if (r)
                goto err_set_dss_clock_div;
 
-       r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
+       r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo);
        if (r)
                goto err_set_dispc_clock_div;
 
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h
new file mode 100644 (file)
index 0000000..2c3443d
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * ti_hdmi.h
+ *
+ * HDMI driver definition for TI OMAP4, DM81xx, DM38xx  Processor.
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TI_HDMI_H
+#define _TI_HDMI_H
+
+struct hdmi_ip_data;
+
+enum hdmi_pll_pwr {
+       HDMI_PLLPWRCMD_ALLOFF = 0,
+       HDMI_PLLPWRCMD_PLLONLY = 1,
+       HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2,
+       HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3
+};
+
+enum hdmi_core_hdmi_dvi {
+       HDMI_DVI = 0,
+       HDMI_HDMI = 1
+};
+
+enum hdmi_clk_refsel {
+       HDMI_REFSEL_PCLK = 0,
+       HDMI_REFSEL_REF1 = 1,
+       HDMI_REFSEL_REF2 = 2,
+       HDMI_REFSEL_SYSCLK = 3
+};
+
+struct hdmi_video_timings {
+       u16 x_res;
+       u16 y_res;
+       /* Unit: KHz */
+       u32 pixel_clock;
+       u16 hsw;
+       u16 hfp;
+       u16 hbp;
+       u16 vsw;
+       u16 vfp;
+       u16 vbp;
+};
+
+/* HDMI timing structure */
+struct hdmi_timings {
+       struct hdmi_video_timings timings;
+       int vsync_pol;
+       int hsync_pol;
+};
+
+struct hdmi_cm {
+       int     code;
+       int     mode;
+};
+
+struct hdmi_config {
+       struct hdmi_timings timings;
+       u16     interlace;
+       struct hdmi_cm cm;
+};
+
+/* HDMI PLL structure */
+struct hdmi_pll_info {
+       u16 regn;
+       u16 regm;
+       u32 regmf;
+       u16 regm2;
+       u16 regsd;
+       u16 dcofreq;
+       enum hdmi_clk_refsel refsel;
+};
+
+struct ti_hdmi_ip_ops {
+
+       void (*video_configure)(struct hdmi_ip_data *ip_data);
+
+       int (*phy_enable)(struct hdmi_ip_data *ip_data);
+
+       void (*phy_disable)(struct hdmi_ip_data *ip_data);
+
+       int (*read_edid)(struct hdmi_ip_data *ip_data, u8 *edid, int len);
+
+       bool (*detect)(struct hdmi_ip_data *ip_data);
+
+       int (*pll_enable)(struct hdmi_ip_data *ip_data);
+
+       void (*pll_disable)(struct hdmi_ip_data *ip_data);
+
+       void (*video_enable)(struct hdmi_ip_data *ip_data, bool start);
+
+       void (*dump_wrapper)(struct hdmi_ip_data *ip_data, struct seq_file *s);
+
+       void (*dump_core)(struct hdmi_ip_data *ip_data, struct seq_file *s);
+
+       void (*dump_pll)(struct hdmi_ip_data *ip_data, struct seq_file *s);
+
+       void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s);
+
+};
+
+struct hdmi_ip_data {
+       void __iomem    *base_wp;       /* HDMI wrapper */
+       unsigned long   core_sys_offset;
+       unsigned long   core_av_offset;
+       unsigned long   pll_offset;
+       unsigned long   phy_offset;
+       const struct ti_hdmi_ip_ops *ops;
+       struct hdmi_config cfg;
+       struct hdmi_pll_info pll_data;
+};
+int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data);
+void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data);
+int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len);
+bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data);
+void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start);
+int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data);
+void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data);
+void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data);
+void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
+void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
+void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
+void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
+
+#endif
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
new file mode 100644 (file)
index 0000000..e1a6ce5
--- /dev/null
@@ -0,0 +1,1239 @@
+/*
+ * ti_hdmi_4xxx_ip.c
+ *
+ * HDMI TI81xx, TI38xx, TI OMAP4 etc IP driver Library
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Authors: Yong Zhi
+ *     Mythri pk <mythripk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/seq_file.h>
+
+#include "ti_hdmi_4xxx_ip.h"
+#include "dss.h"
+
+static inline void hdmi_write_reg(void __iomem *base_addr,
+                               const u16 idx, u32 val)
+{
+       __raw_writel(val, base_addr + idx);
+}
+
+static inline u32 hdmi_read_reg(void __iomem *base_addr,
+                               const u16 idx)
+{
+       return __raw_readl(base_addr + idx);
+}
+
+static inline void __iomem *hdmi_wp_base(struct hdmi_ip_data *ip_data)
+{
+       return ip_data->base_wp;
+}
+
+static inline void __iomem *hdmi_phy_base(struct hdmi_ip_data *ip_data)
+{
+       return ip_data->base_wp + ip_data->phy_offset;
+}
+
+static inline void __iomem *hdmi_pll_base(struct hdmi_ip_data *ip_data)
+{
+       return ip_data->base_wp + ip_data->pll_offset;
+}
+
+static inline void __iomem *hdmi_av_base(struct hdmi_ip_data *ip_data)
+{
+       return ip_data->base_wp + ip_data->core_av_offset;
+}
+
+static inline void __iomem *hdmi_core_sys_base(struct hdmi_ip_data *ip_data)
+{
+       return ip_data->base_wp + ip_data->core_sys_offset;
+}
+
+static inline int hdmi_wait_for_bit_change(void __iomem *base_addr,
+                               const u16 idx,
+                               int b2, int b1, u32 val)
+{
+       u32 t = 0;
+       while (val != REG_GET(base_addr, idx, b2, b1)) {
+               udelay(1);
+               if (t++ > 10000)
+                       return !val;
+       }
+       return val;
+}
+
+static int hdmi_pll_init(struct hdmi_ip_data *ip_data)
+{
+       u32 r;
+       void __iomem *pll_base = hdmi_pll_base(ip_data);
+       struct hdmi_pll_info *fmt = &ip_data->pll_data;
+
+       /* PLL start always use manual mode */
+       REG_FLD_MOD(pll_base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
+
+       r = hdmi_read_reg(pll_base, PLLCTRL_CFG1);
+       r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
+       r = FLD_MOD(r, fmt->regn - 1, 8, 1);  /* CFG1_PLL_REGN */
+
+       hdmi_write_reg(pll_base, PLLCTRL_CFG1, r);
+
+       r = hdmi_read_reg(pll_base, PLLCTRL_CFG2);
+
+       r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
+       r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
+       r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
+       r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */
+
+       if (fmt->dcofreq) {
+               /* divider programming for frequency beyond 1000Mhz */
+               REG_FLD_MOD(pll_base, PLLCTRL_CFG3, fmt->regsd, 17, 10);
+               r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
+       } else {
+               r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
+       }
+
+       hdmi_write_reg(pll_base, PLLCTRL_CFG2, r);
+
+       r = hdmi_read_reg(pll_base, PLLCTRL_CFG4);
+       r = FLD_MOD(r, fmt->regm2, 24, 18);
+       r = FLD_MOD(r, fmt->regmf, 17, 0);
+
+       hdmi_write_reg(pll_base, PLLCTRL_CFG4, r);
+
+       /* go now */
+       REG_FLD_MOD(pll_base, PLLCTRL_PLL_GO, 0x1, 0, 0);
+
+       /* wait for bit change */
+       if (hdmi_wait_for_bit_change(pll_base, PLLCTRL_PLL_GO,
+                                                       0, 0, 1) != 1) {
+               pr_err("PLL GO bit not set\n");
+               return -ETIMEDOUT;
+       }
+
+       /* Wait till the lock bit is set in PLL status */
+       if (hdmi_wait_for_bit_change(pll_base,
+                               PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
+               pr_err("cannot lock PLL\n");
+               pr_err("CFG1 0x%x\n",
+                       hdmi_read_reg(pll_base, PLLCTRL_CFG1));
+               pr_err("CFG2 0x%x\n",
+                       hdmi_read_reg(pll_base, PLLCTRL_CFG2));
+               pr_err("CFG4 0x%x\n",
+                       hdmi_read_reg(pll_base, PLLCTRL_CFG4));
+               return -ETIMEDOUT;
+       }
+
+       pr_debug("PLL locked!\n");
+
+       return 0;
+}
+
+/* PHY_PWR_CMD */
+static int hdmi_set_phy_pwr(struct hdmi_ip_data *ip_data, enum hdmi_phy_pwr val)
+{
+       /* Command for power control of HDMI PHY */
+       REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_PWR_CTRL, val, 7, 6);
+
+       /* Status of the power control of HDMI PHY */
+       if (hdmi_wait_for_bit_change(hdmi_wp_base(ip_data),
+                               HDMI_WP_PWR_CTRL, 5, 4, val) != val) {
+               pr_err("Failed to set PHY power mode to %d\n", val);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+/* PLL_PWR_CMD */
+static int hdmi_set_pll_pwr(struct hdmi_ip_data *ip_data, enum hdmi_pll_pwr val)
+{
+       /* Command for power control of HDMI PLL */
+       REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_PWR_CTRL, val, 3, 2);
+
+       /* wait till PHY_PWR_STATUS is set */
+       if (hdmi_wait_for_bit_change(hdmi_wp_base(ip_data), HDMI_WP_PWR_CTRL,
+                                               1, 0, val) != val) {
+               pr_err("Failed to set PLL_PWR_STATUS\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int hdmi_pll_reset(struct hdmi_ip_data *ip_data)
+{
+       /* SYSRESET  controlled by power FSM */
+       REG_FLD_MOD(hdmi_pll_base(ip_data), PLLCTRL_PLL_CONTROL, 0x0, 3, 3);
+
+       /* READ 0x0 reset is in progress */
+       if (hdmi_wait_for_bit_change(hdmi_pll_base(ip_data),
+                               PLLCTRL_PLL_STATUS, 0, 0, 1) != 1) {
+               pr_err("Failed to sysreset PLL\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data)
+{
+       u16 r = 0;
+
+       r = hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF);
+       if (r)
+               return r;
+
+       r = hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
+       if (r)
+               return r;
+
+       r = hdmi_pll_reset(ip_data);
+       if (r)
+               return r;
+
+       r = hdmi_pll_init(ip_data);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data)
+{
+       hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF);
+}
+
+int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data)
+{
+       u16 r = 0;
+       void __iomem *phy_base = hdmi_phy_base(ip_data);
+
+       r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON);
+       if (r)
+               return r;
+
+       r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON);
+       if (r)
+               return r;
+
+       /*
+        * Read address 0 in order to get the SCP reset done completed
+        * Dummy access performed to make sure reset is done
+        */
+       hdmi_read_reg(phy_base, HDMI_TXPHY_TX_CTRL);
+
+       /*
+        * Write to phy address 0 to configure the clock
+        * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
+        */
+       REG_FLD_MOD(phy_base, HDMI_TXPHY_TX_CTRL, 0x1, 31, 30);
+
+       /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
+       hdmi_write_reg(phy_base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
+
+       /* Setup max LDO voltage */
+       REG_FLD_MOD(phy_base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
+
+       /* Write to phy address 3 to change the polarity control */
+       REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);
+
+       return 0;
+}
+
+void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data)
+{
+       hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
+}
+
+static int hdmi_core_ddc_init(struct hdmi_ip_data *ip_data)
+{
+       void __iomem *base = hdmi_core_sys_base(ip_data);
+
+       /* Turn on CLK for DDC */
+       REG_FLD_MOD(base, HDMI_CORE_AV_DPD, 0x7, 2, 0);
+
+       /* IN_PROG */
+       if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 1) {
+               /* Abort transaction */
+               REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xf, 3, 0);
+               /* IN_PROG */
+               if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
+                                       4, 4, 0) != 0) {
+                       DSSERR("Timeout aborting DDC transaction\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       /* Clk SCL Devices */
+       REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xA, 3, 0);
+
+       /* HDMI_CORE_DDC_STATUS_IN_PROG */
+       if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
+                               4, 4, 0) != 0) {
+               DSSERR("Timeout starting SCL clock\n");
+               return -ETIMEDOUT;
+       }
+
+       /* Clear FIFO */
+       REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x9, 3, 0);
+
+       /* HDMI_CORE_DDC_STATUS_IN_PROG */
+       if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
+                               4, 4, 0) != 0) {
+               DSSERR("Timeout clearing DDC fifo\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int hdmi_core_ddc_edid(struct hdmi_ip_data *ip_data,
+               u8 *pedid, int ext)
+{
+       void __iomem *base = hdmi_core_sys_base(ip_data);
+       u32 i;
+       char checksum;
+       u32 offset = 0;
+
+       /* HDMI_CORE_DDC_STATUS_IN_PROG */
+       if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
+                               4, 4, 0) != 0) {
+               DSSERR("Timeout waiting DDC to be ready\n");
+               return -ETIMEDOUT;
+       }
+
+       if (ext % 2 != 0)
+               offset = 0x80;
+
+       /* Load Segment Address Register */
+       REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, ext / 2, 7, 0);
+
+       /* Load Slave Address Register */
+       REG_FLD_MOD(base, HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1);
+
+       /* Load Offset Address Register */
+       REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, offset, 7, 0);
+
+       /* Load Byte Count */
+       REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, 0x80, 7, 0);
+       REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT2, 0x0, 1, 0);
+
+       /* Set DDC_CMD */
+       if (ext)
+               REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x4, 3, 0);
+       else
+               REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x2, 3, 0);
+
+       /* HDMI_CORE_DDC_STATUS_BUS_LOW */
+       if (REG_GET(base, HDMI_CORE_DDC_STATUS, 6, 6) == 1) {
+               pr_err("I2C Bus Low?\n");
+               return -EIO;
+       }
+       /* HDMI_CORE_DDC_STATUS_NO_ACK */
+       if (REG_GET(base, HDMI_CORE_DDC_STATUS, 5, 5) == 1) {
+               pr_err("I2C No Ack\n");
+               return -EIO;
+       }
+
+       for (i = 0; i < 0x80; ++i) {
+               int t;
+
+               /* IN_PROG */
+               if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 0) {
+                       DSSERR("operation stopped when reading edid\n");
+                       return -EIO;
+               }
+
+               t = 0;
+               /* FIFO_EMPTY */
+               while (REG_GET(base, HDMI_CORE_DDC_STATUS, 2, 2) == 1) {
+                       if (t++ > 10000) {
+                               DSSERR("timeout reading edid\n");
+                               return -ETIMEDOUT;
+                       }
+                       udelay(1);
+               }
+
+               pedid[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0);
+       }
+
+       checksum = 0;
+       for (i = 0; i < 0x80; ++i)
+               checksum += pedid[i];
+
+       if (checksum != 0) {
+               pr_err("E-EDID checksum failed!!\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data,
+                               u8 *edid, int len)
+{
+       int r, l;
+
+       if (len < 128)
+               return -EINVAL;
+
+       r = hdmi_core_ddc_init(ip_data);
+       if (r)
+               return r;
+
+       r = hdmi_core_ddc_edid(ip_data, edid, 0);
+       if (r)
+               return r;
+
+       l = 128;
+
+       if (len >= 128 * 2 && edid[0x7e] > 0) {
+               r = hdmi_core_ddc_edid(ip_data, edid + 0x80, 1);
+               if (r)
+                       return r;
+               l += 128;
+       }
+
+       return l;
+}
+
+bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data)
+{
+       int r;
+
+       void __iomem *base = hdmi_core_sys_base(ip_data);
+
+       /* HPD */
+       r = REG_GET(base, HDMI_CORE_SYS_SYS_STAT, 1, 1);
+
+       return r == 1;
+}
+
+static void hdmi_core_init(struct hdmi_core_video_config *video_cfg,
+                       struct hdmi_core_infoframe_avi *avi_cfg,
+                       struct hdmi_core_packet_enable_repeat *repeat_cfg)
+{
+       pr_debug("Enter hdmi_core_init\n");
+
+       /* video core */
+       video_cfg->ip_bus_width = HDMI_INPUT_8BIT;
+       video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT;
+       video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE;
+       video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE;
+       video_cfg->hdmi_dvi = HDMI_DVI;
+       video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK;
+
+       /* info frame */
+       avi_cfg->db1_format = 0;
+       avi_cfg->db1_active_info = 0;
+       avi_cfg->db1_bar_info_dv = 0;
+       avi_cfg->db1_scan_info = 0;
+       avi_cfg->db2_colorimetry = 0;
+       avi_cfg->db2_aspect_ratio = 0;
+       avi_cfg->db2_active_fmt_ar = 0;
+       avi_cfg->db3_itc = 0;
+       avi_cfg->db3_ec = 0;
+       avi_cfg->db3_q_range = 0;
+       avi_cfg->db3_nup_scaling = 0;
+       avi_cfg->db4_videocode = 0;
+       avi_cfg->db5_pixel_repeat = 0;
+       avi_cfg->db6_7_line_eoftop = 0 ;
+       avi_cfg->db8_9_line_sofbottom = 0;
+       avi_cfg->db10_11_pixel_eofleft = 0;
+       avi_cfg->db12_13_pixel_sofright = 0;
+
+       /* packet enable and repeat */
+       repeat_cfg->audio_pkt = 0;
+       repeat_cfg->audio_pkt_repeat = 0;
+       repeat_cfg->avi_infoframe = 0;
+       repeat_cfg->avi_infoframe_repeat = 0;
+       repeat_cfg->gen_cntrl_pkt = 0;
+       repeat_cfg->gen_cntrl_pkt_repeat = 0;
+       repeat_cfg->generic_pkt = 0;
+       repeat_cfg->generic_pkt_repeat = 0;
+}
+
+static void hdmi_core_powerdown_disable(struct hdmi_ip_data *ip_data)
+{
+       pr_debug("Enter hdmi_core_powerdown_disable\n");
+       REG_FLD_MOD(hdmi_core_sys_base(ip_data), HDMI_CORE_CTRL1, 0x0, 0, 0);
+}
+
+static void hdmi_core_swreset_release(struct hdmi_ip_data *ip_data)
+{
+       pr_debug("Enter hdmi_core_swreset_release\n");
+       REG_FLD_MOD(hdmi_core_sys_base(ip_data), HDMI_CORE_SYS_SRST, 0x0, 0, 0);
+}
+
+static void hdmi_core_swreset_assert(struct hdmi_ip_data *ip_data)
+{
+       pr_debug("Enter hdmi_core_swreset_assert\n");
+       REG_FLD_MOD(hdmi_core_sys_base(ip_data), HDMI_CORE_SYS_SRST, 0x1, 0, 0);
+}
+
+/* HDMI_CORE_VIDEO_CONFIG */
+static void hdmi_core_video_config(struct hdmi_ip_data *ip_data,
+                               struct hdmi_core_video_config *cfg)
+{
+       u32 r = 0;
+       void __iomem *core_sys_base = hdmi_core_sys_base(ip_data);
+
+       /* sys_ctrl1 default configuration not tunable */
+       r = hdmi_read_reg(core_sys_base, HDMI_CORE_CTRL1);
+       r = FLD_MOD(r, HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC, 5, 5);
+       r = FLD_MOD(r, HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC, 4, 4);
+       r = FLD_MOD(r, HDMI_CORE_CTRL1_BSEL_24BITBUS, 2, 2);
+       r = FLD_MOD(r, HDMI_CORE_CTRL1_EDGE_RISINGEDGE, 1, 1);
+       hdmi_write_reg(core_sys_base, HDMI_CORE_CTRL1, r);
+
+       REG_FLD_MOD(core_sys_base,
+                       HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6);
+
+       /* Vid_Mode */
+       r = hdmi_read_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE);
+
+       /* dither truncation configuration */
+       if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) {
+               r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6);
+               r = FLD_MOD(r, 1, 5, 5);
+       } else {
+               r = FLD_MOD(r, cfg->op_dither_truc, 7, 6);
+               r = FLD_MOD(r, 0, 5, 5);
+       }
+       hdmi_write_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE, r);
+
+       /* HDMI_Ctrl */
+       r = hdmi_read_reg(hdmi_av_base(ip_data), HDMI_CORE_AV_HDMI_CTRL);
+       r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6);
+       r = FLD_MOD(r, cfg->pkt_mode, 5, 3);
+       r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0);
+       hdmi_write_reg(hdmi_av_base(ip_data), HDMI_CORE_AV_HDMI_CTRL, r);
+
+       /* TMDS_CTRL */
+       REG_FLD_MOD(core_sys_base,
+                       HDMI_CORE_SYS_TMDS_CTRL, cfg->tclk_sel_clkmult, 6, 5);
+}
+
+static void hdmi_core_aux_infoframe_avi_config(struct hdmi_ip_data *ip_data,
+               struct hdmi_core_infoframe_avi info_avi)
+{
+       u32 val;
+       char sum = 0, checksum = 0;
+       void __iomem *av_base = hdmi_av_base(ip_data);
+
+       sum += 0x82 + 0x002 + 0x00D;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_TYPE, 0x082);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_VERS, 0x002);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_LEN, 0x00D);
+
+       val = (info_avi.db1_format << 5) |
+               (info_avi.db1_active_info << 4) |
+               (info_avi.db1_bar_info_dv << 2) |
+               (info_avi.db1_scan_info);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(0), val);
+       sum += val;
+
+       val = (info_avi.db2_colorimetry << 6) |
+               (info_avi.db2_aspect_ratio << 4) |
+               (info_avi.db2_active_fmt_ar);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(1), val);
+       sum += val;
+
+       val = (info_avi.db3_itc << 7) |
+               (info_avi.db3_ec << 4) |
+               (info_avi.db3_q_range << 2) |
+               (info_avi.db3_nup_scaling);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(2), val);
+       sum += val;
+
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(3),
+                                       info_avi.db4_videocode);
+       sum += info_avi.db4_videocode;
+
+       val = info_avi.db5_pixel_repeat;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(4), val);
+       sum += val;
+
+       val = info_avi.db6_7_line_eoftop & 0x00FF;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(5), val);
+       sum += val;
+
+       val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(6), val);
+       sum += val;
+
+       val = info_avi.db8_9_line_sofbottom & 0x00FF;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(7), val);
+       sum += val;
+
+       val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(8), val);
+       sum += val;
+
+       val = info_avi.db10_11_pixel_eofleft & 0x00FF;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(9), val);
+       sum += val;
+
+       val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(10), val);
+       sum += val;
+
+       val = info_avi.db12_13_pixel_sofright & 0x00FF;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(11), val);
+       sum += val;
+
+       val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(12), val);
+       sum += val;
+
+       checksum = 0x100 - sum;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_CHSUM, checksum);
+}
+
+static void hdmi_core_av_packet_config(struct hdmi_ip_data *ip_data,
+               struct hdmi_core_packet_enable_repeat repeat_cfg)
+{
+       /* enable/repeat the infoframe */
+       hdmi_write_reg(hdmi_av_base(ip_data), HDMI_CORE_AV_PB_CTRL1,
+               (repeat_cfg.audio_pkt << 5) |
+               (repeat_cfg.audio_pkt_repeat << 4) |
+               (repeat_cfg.avi_infoframe << 1) |
+               (repeat_cfg.avi_infoframe_repeat));
+
+       /* enable/repeat the packet */
+       hdmi_write_reg(hdmi_av_base(ip_data), HDMI_CORE_AV_PB_CTRL2,
+               (repeat_cfg.gen_cntrl_pkt << 3) |
+               (repeat_cfg.gen_cntrl_pkt_repeat << 2) |
+               (repeat_cfg.generic_pkt << 1) |
+               (repeat_cfg.generic_pkt_repeat));
+}
+
+static void hdmi_wp_init(struct omap_video_timings *timings,
+                       struct hdmi_video_format *video_fmt,
+                       struct hdmi_video_interface *video_int)
+{
+       pr_debug("Enter hdmi_wp_init\n");
+
+       timings->hbp = 0;
+       timings->hfp = 0;
+       timings->hsw = 0;
+       timings->vbp = 0;
+       timings->vfp = 0;
+       timings->vsw = 0;
+
+       video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
+       video_fmt->y_res = 0;
+       video_fmt->x_res = 0;
+
+       video_int->vsp = 0;
+       video_int->hsp = 0;
+
+       video_int->interlacing = 0;
+       video_int->tm = 0; /* HDMI_TIMING_SLAVE */
+
+}
+
+void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start)
+{
+       REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, start, 31, 31);
+}
+
+static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt,
+       struct omap_video_timings *timings, struct hdmi_config *param)
+{
+       pr_debug("Enter hdmi_wp_video_init_format\n");
+
+       video_fmt->y_res = param->timings.timings.y_res;
+       video_fmt->x_res = param->timings.timings.x_res;
+
+       timings->hbp = param->timings.timings.hbp;
+       timings->hfp = param->timings.timings.hfp;
+       timings->hsw = param->timings.timings.hsw;
+       timings->vbp = param->timings.timings.vbp;
+       timings->vfp = param->timings.timings.vfp;
+       timings->vsw = param->timings.timings.vsw;
+}
+
+static void hdmi_wp_video_config_format(struct hdmi_ip_data *ip_data,
+               struct hdmi_video_format *video_fmt)
+{
+       u32 l = 0;
+
+       REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG,
+                       video_fmt->packing_mode, 10, 8);
+
+       l |= FLD_VAL(video_fmt->y_res, 31, 16);
+       l |= FLD_VAL(video_fmt->x_res, 15, 0);
+       hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_SIZE, l);
+}
+
+static void hdmi_wp_video_config_interface(struct hdmi_ip_data *ip_data,
+               struct hdmi_video_interface *video_int)
+{
+       u32 r;
+       pr_debug("Enter hdmi_wp_video_config_interface\n");
+
+       r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG);
+       r = FLD_MOD(r, video_int->vsp, 7, 7);
+       r = FLD_MOD(r, video_int->hsp, 6, 6);
+       r = FLD_MOD(r, video_int->interlacing, 3, 3);
+       r = FLD_MOD(r, video_int->tm, 1, 0);
+       hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, r);
+}
+
+static void hdmi_wp_video_config_timing(struct hdmi_ip_data *ip_data,
+               struct omap_video_timings *timings)
+{
+       u32 timing_h = 0;
+       u32 timing_v = 0;
+
+       pr_debug("Enter hdmi_wp_video_config_timing\n");
+
+       timing_h |= FLD_VAL(timings->hbp, 31, 20);
+       timing_h |= FLD_VAL(timings->hfp, 19, 8);
+       timing_h |= FLD_VAL(timings->hsw, 7, 0);
+       hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_TIMING_H, timing_h);
+
+       timing_v |= FLD_VAL(timings->vbp, 31, 20);
+       timing_v |= FLD_VAL(timings->vfp, 19, 8);
+       timing_v |= FLD_VAL(timings->vsw, 7, 0);
+       hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_TIMING_V, timing_v);
+}
+
+void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data)
+{
+       /* HDMI */
+       struct omap_video_timings video_timing;
+       struct hdmi_video_format video_format;
+       struct hdmi_video_interface video_interface;
+       /* HDMI core */
+       struct hdmi_core_infoframe_avi avi_cfg;
+       struct hdmi_core_video_config v_core_cfg;
+       struct hdmi_core_packet_enable_repeat repeat_cfg;
+       struct hdmi_config *cfg = &ip_data->cfg;
+
+       hdmi_wp_init(&video_timing, &video_format,
+               &video_interface);
+
+       hdmi_core_init(&v_core_cfg,
+               &avi_cfg,
+               &repeat_cfg);
+
+       hdmi_wp_video_init_format(&video_format, &video_timing, cfg);
+
+       hdmi_wp_video_config_timing(ip_data, &video_timing);
+
+       /* video config */
+       video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422;
+
+       hdmi_wp_video_config_format(ip_data, &video_format);
+
+       video_interface.vsp = cfg->timings.vsync_pol;
+       video_interface.hsp = cfg->timings.hsync_pol;
+       video_interface.interlacing = cfg->interlace;
+       video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */
+
+       hdmi_wp_video_config_interface(ip_data, &video_interface);
+
+       /*
+        * configure core video part
+        * set software reset in the core
+        */
+       hdmi_core_swreset_assert(ip_data);
+
+       /* power down off */
+       hdmi_core_powerdown_disable(ip_data);
+
+       v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL;
+       v_core_cfg.hdmi_dvi = cfg->cm.mode;
+
+       hdmi_core_video_config(ip_data, &v_core_cfg);
+
+       /* release software reset in the core */
+       hdmi_core_swreset_release(ip_data);
+
+       /*
+        * configure packet
+        * info frame video see doc CEA861-D page 65
+        */
+       avi_cfg.db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB;
+       avi_cfg.db1_active_info =
+               HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF;
+       avi_cfg.db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO;
+       avi_cfg.db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0;
+       avi_cfg.db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO;
+       avi_cfg.db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO;
+       avi_cfg.db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME;
+       avi_cfg.db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO;
+       avi_cfg.db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601;
+       avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT;
+       avi_cfg.db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO;
+       avi_cfg.db4_videocode = cfg->cm.code;
+       avi_cfg.db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO;
+       avi_cfg.db6_7_line_eoftop = 0;
+       avi_cfg.db8_9_line_sofbottom = 0;
+       avi_cfg.db10_11_pixel_eofleft = 0;
+       avi_cfg.db12_13_pixel_sofright = 0;
+
+       hdmi_core_aux_infoframe_avi_config(ip_data, avi_cfg);
+
+       /* enable/repeat the infoframe */
+       repeat_cfg.avi_infoframe = HDMI_PACKETENABLE;
+       repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON;
+       /* wakeup */
+       repeat_cfg.audio_pkt = HDMI_PACKETENABLE;
+       repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON;
+       hdmi_core_av_packet_config(ip_data, repeat_cfg);
+}
+
+void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
+{
+#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r,\
+               hdmi_read_reg(hdmi_wp_base(ip_data), r))
+
+       DUMPREG(HDMI_WP_REVISION);
+       DUMPREG(HDMI_WP_SYSCONFIG);
+       DUMPREG(HDMI_WP_IRQSTATUS_RAW);
+       DUMPREG(HDMI_WP_IRQSTATUS);
+       DUMPREG(HDMI_WP_PWR_CTRL);
+       DUMPREG(HDMI_WP_IRQENABLE_SET);
+       DUMPREG(HDMI_WP_VIDEO_CFG);
+       DUMPREG(HDMI_WP_VIDEO_SIZE);
+       DUMPREG(HDMI_WP_VIDEO_TIMING_H);
+       DUMPREG(HDMI_WP_VIDEO_TIMING_V);
+       DUMPREG(HDMI_WP_WP_CLK);
+       DUMPREG(HDMI_WP_AUDIO_CFG);
+       DUMPREG(HDMI_WP_AUDIO_CFG2);
+       DUMPREG(HDMI_WP_AUDIO_CTRL);
+       DUMPREG(HDMI_WP_AUDIO_DATA);
+}
+
+void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
+{
+#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
+               hdmi_read_reg(hdmi_pll_base(ip_data), r))
+
+       DUMPPLL(PLLCTRL_PLL_CONTROL);
+       DUMPPLL(PLLCTRL_PLL_STATUS);
+       DUMPPLL(PLLCTRL_PLL_GO);
+       DUMPPLL(PLLCTRL_CFG1);
+       DUMPPLL(PLLCTRL_CFG2);
+       DUMPPLL(PLLCTRL_CFG3);
+       DUMPPLL(PLLCTRL_CFG4);
+}
+
+void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
+{
+       int i;
+
+#define CORE_REG(i, name) name(i)
+#define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\
+               hdmi_read_reg(hdmi_pll_base(ip_data), r))
+#define DUMPCOREAV(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \
+               (i < 10) ? 32 - strlen(#r) : 31 - strlen(#r), " ", \
+               hdmi_read_reg(hdmi_pll_base(ip_data), CORE_REG(i, r)))
+
+       DUMPCORE(HDMI_CORE_SYS_VND_IDL);
+       DUMPCORE(HDMI_CORE_SYS_DEV_IDL);
+       DUMPCORE(HDMI_CORE_SYS_DEV_IDH);
+       DUMPCORE(HDMI_CORE_SYS_DEV_REV);
+       DUMPCORE(HDMI_CORE_SYS_SRST);
+       DUMPCORE(HDMI_CORE_CTRL1);
+       DUMPCORE(HDMI_CORE_SYS_SYS_STAT);
+       DUMPCORE(HDMI_CORE_SYS_VID_ACEN);
+       DUMPCORE(HDMI_CORE_SYS_VID_MODE);
+       DUMPCORE(HDMI_CORE_SYS_INTR_STATE);
+       DUMPCORE(HDMI_CORE_SYS_INTR1);
+       DUMPCORE(HDMI_CORE_SYS_INTR2);
+       DUMPCORE(HDMI_CORE_SYS_INTR3);
+       DUMPCORE(HDMI_CORE_SYS_INTR4);
+       DUMPCORE(HDMI_CORE_SYS_UMASK1);
+       DUMPCORE(HDMI_CORE_SYS_TMDS_CTRL);
+       DUMPCORE(HDMI_CORE_SYS_DE_DLY);
+       DUMPCORE(HDMI_CORE_SYS_DE_CTRL);
+       DUMPCORE(HDMI_CORE_SYS_DE_TOP);
+       DUMPCORE(HDMI_CORE_SYS_DE_CNTL);
+       DUMPCORE(HDMI_CORE_SYS_DE_CNTH);
+       DUMPCORE(HDMI_CORE_SYS_DE_LINL);
+       DUMPCORE(HDMI_CORE_SYS_DE_LINH_1);
+
+       DUMPCORE(HDMI_CORE_DDC_CMD);
+       DUMPCORE(HDMI_CORE_DDC_STATUS);
+       DUMPCORE(HDMI_CORE_DDC_ADDR);
+       DUMPCORE(HDMI_CORE_DDC_OFFSET);
+       DUMPCORE(HDMI_CORE_DDC_COUNT1);
+       DUMPCORE(HDMI_CORE_DDC_COUNT2);
+       DUMPCORE(HDMI_CORE_DDC_DATA);
+       DUMPCORE(HDMI_CORE_DDC_SEGM);
+
+       DUMPCORE(HDMI_CORE_AV_HDMI_CTRL);
+       DUMPCORE(HDMI_CORE_AV_DPD);
+       DUMPCORE(HDMI_CORE_AV_PB_CTRL1);
+       DUMPCORE(HDMI_CORE_AV_PB_CTRL2);
+       DUMPCORE(HDMI_CORE_AV_AVI_TYPE);
+       DUMPCORE(HDMI_CORE_AV_AVI_VERS);
+       DUMPCORE(HDMI_CORE_AV_AVI_LEN);
+       DUMPCORE(HDMI_CORE_AV_AVI_CHSUM);
+
+       for (i = 0; i < HDMI_CORE_AV_AVI_DBYTE_NELEMS; i++)
+               DUMPCOREAV(i, HDMI_CORE_AV_AVI_DBYTE);
+
+       for (i = 0; i < HDMI_CORE_AV_SPD_DBYTE_NELEMS; i++)
+               DUMPCOREAV(i, HDMI_CORE_AV_SPD_DBYTE);
+
+       for (i = 0; i < HDMI_CORE_AV_AUD_DBYTE_NELEMS; i++)
+               DUMPCOREAV(i, HDMI_CORE_AV_AUD_DBYTE);
+
+       for (i = 0; i < HDMI_CORE_AV_MPEG_DBYTE_NELEMS; i++)
+               DUMPCOREAV(i, HDMI_CORE_AV_MPEG_DBYTE);
+
+       for (i = 0; i < HDMI_CORE_AV_GEN_DBYTE_NELEMS; i++)
+               DUMPCOREAV(i, HDMI_CORE_AV_GEN_DBYTE);
+
+       for (i = 0; i < HDMI_CORE_AV_GEN2_DBYTE_NELEMS; i++)
+               DUMPCOREAV(i, HDMI_CORE_AV_GEN2_DBYTE);
+
+       DUMPCORE(HDMI_CORE_AV_ACR_CTRL);
+       DUMPCORE(HDMI_CORE_AV_FREQ_SVAL);
+       DUMPCORE(HDMI_CORE_AV_N_SVAL1);
+       DUMPCORE(HDMI_CORE_AV_N_SVAL2);
+       DUMPCORE(HDMI_CORE_AV_N_SVAL3);
+       DUMPCORE(HDMI_CORE_AV_CTS_SVAL1);
+       DUMPCORE(HDMI_CORE_AV_CTS_SVAL2);
+       DUMPCORE(HDMI_CORE_AV_CTS_SVAL3);
+       DUMPCORE(HDMI_CORE_AV_CTS_HVAL1);
+       DUMPCORE(HDMI_CORE_AV_CTS_HVAL2);
+       DUMPCORE(HDMI_CORE_AV_CTS_HVAL3);
+       DUMPCORE(HDMI_CORE_AV_AUD_MODE);
+       DUMPCORE(HDMI_CORE_AV_SPDIF_CTRL);
+       DUMPCORE(HDMI_CORE_AV_HW_SPDIF_FS);
+       DUMPCORE(HDMI_CORE_AV_SWAP_I2S);
+       DUMPCORE(HDMI_CORE_AV_SPDIF_ERTH);
+       DUMPCORE(HDMI_CORE_AV_I2S_IN_MAP);
+       DUMPCORE(HDMI_CORE_AV_I2S_IN_CTRL);
+       DUMPCORE(HDMI_CORE_AV_I2S_CHST0);
+       DUMPCORE(HDMI_CORE_AV_I2S_CHST1);
+       DUMPCORE(HDMI_CORE_AV_I2S_CHST2);
+       DUMPCORE(HDMI_CORE_AV_I2S_CHST4);
+       DUMPCORE(HDMI_CORE_AV_I2S_CHST5);
+       DUMPCORE(HDMI_CORE_AV_ASRC);
+       DUMPCORE(HDMI_CORE_AV_I2S_IN_LEN);
+       DUMPCORE(HDMI_CORE_AV_HDMI_CTRL);
+       DUMPCORE(HDMI_CORE_AV_AUDO_TXSTAT);
+       DUMPCORE(HDMI_CORE_AV_AUD_PAR_BUSCLK_1);
+       DUMPCORE(HDMI_CORE_AV_AUD_PAR_BUSCLK_2);
+       DUMPCORE(HDMI_CORE_AV_AUD_PAR_BUSCLK_3);
+       DUMPCORE(HDMI_CORE_AV_TEST_TXCTRL);
+       DUMPCORE(HDMI_CORE_AV_DPD);
+       DUMPCORE(HDMI_CORE_AV_PB_CTRL1);
+       DUMPCORE(HDMI_CORE_AV_PB_CTRL2);
+       DUMPCORE(HDMI_CORE_AV_AVI_TYPE);
+       DUMPCORE(HDMI_CORE_AV_AVI_VERS);
+       DUMPCORE(HDMI_CORE_AV_AVI_LEN);
+       DUMPCORE(HDMI_CORE_AV_AVI_CHSUM);
+       DUMPCORE(HDMI_CORE_AV_SPD_TYPE);
+       DUMPCORE(HDMI_CORE_AV_SPD_VERS);
+       DUMPCORE(HDMI_CORE_AV_SPD_LEN);
+       DUMPCORE(HDMI_CORE_AV_SPD_CHSUM);
+       DUMPCORE(HDMI_CORE_AV_AUDIO_TYPE);
+       DUMPCORE(HDMI_CORE_AV_AUDIO_VERS);
+       DUMPCORE(HDMI_CORE_AV_AUDIO_LEN);
+       DUMPCORE(HDMI_CORE_AV_AUDIO_CHSUM);
+       DUMPCORE(HDMI_CORE_AV_MPEG_TYPE);
+       DUMPCORE(HDMI_CORE_AV_MPEG_VERS);
+       DUMPCORE(HDMI_CORE_AV_MPEG_LEN);
+       DUMPCORE(HDMI_CORE_AV_MPEG_CHSUM);
+       DUMPCORE(HDMI_CORE_AV_CP_BYTE1);
+       DUMPCORE(HDMI_CORE_AV_CEC_ADDR_ID);
+}
+
+void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
+{
+#define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\
+               hdmi_read_reg(hdmi_phy_base(ip_data), r))
+
+       DUMPPHY(HDMI_TXPHY_TX_CTRL);
+       DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL);
+       DUMPPHY(HDMI_TXPHY_POWER_CTRL);
+       DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL);
+}
+
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data,
+                                       struct hdmi_audio_format *aud_fmt)
+{
+       u32 r;
+
+       DSSDBG("Enter hdmi_wp_audio_config_format\n");
+
+       r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG);
+       r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
+       r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
+       r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
+       r = FLD_MOD(r, aud_fmt->type, 4, 4);
+       r = FLD_MOD(r, aud_fmt->justification, 3, 3);
+       r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
+       r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
+       r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
+       hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG, r);
+}
+
+void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data,
+                                       struct hdmi_audio_dma *aud_dma)
+{
+       u32 r;
+
+       DSSDBG("Enter hdmi_wp_audio_config_dma\n");
+
+       r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG2);
+       r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
+       r = FLD_MOD(r, aud_dma->block_size, 7, 0);
+       hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG2, r);
+
+       r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL);
+       r = FLD_MOD(r, aud_dma->mode, 9, 9);
+       r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
+       hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL, r);
+}
+
+void hdmi_core_audio_config(struct hdmi_ip_data *ip_data,
+                                       struct hdmi_core_audio_config *cfg)
+{
+       u32 r;
+       void __iomem *av_base = hdmi_av_base(ip_data);
+
+       /* audio clock recovery parameters */
+       r = hdmi_read_reg(av_base, HDMI_CORE_AV_ACR_CTRL);
+       r = FLD_MOD(r, cfg->use_mclk, 2, 2);
+       r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1);
+       r = FLD_MOD(r, cfg->cts_mode, 0, 0);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_ACR_CTRL, r);
+
+       REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0);
+       REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0);
+       REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0);
+
+       if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) {
+               REG_FLD_MOD(av_base, HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0);
+               REG_FLD_MOD(av_base,
+                               HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0);
+               REG_FLD_MOD(av_base,
+                               HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0);
+       } else {
+               /*
+                * HDMI IP uses this configuration to divide the MCLK to
+                * update CTS value.
+                */
+               REG_FLD_MOD(av_base,
+                               HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0);
+
+               /* Configure clock for audio packets */
+               REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_1,
+                               cfg->aud_par_busclk, 7, 0);
+               REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_2,
+                               (cfg->aud_par_busclk >> 8), 7, 0);
+               REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_3,
+                               (cfg->aud_par_busclk >> 16), 7, 0);
+       }
+
+       /* Override of SPDIF sample frequency with value in I2S_CHST4 */
+       REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL,
+                                               cfg->fs_override, 1, 1);
+
+       /* I2S parameters */
+       REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_CHST4,
+                                               cfg->freq_sample, 3, 0);
+
+       r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL);
+       r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7);
+       r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6);
+       r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5);
+       r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4);
+       r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3);
+       r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2);
+       r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1);
+       r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL, r);
+
+       r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_CHST5);
+       r = FLD_MOD(r, cfg->freq_sample, 7, 4);
+       r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1);
+       r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5, r);
+
+       REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_IN_LEN,
+                       cfg->i2s_cfg.in_length_bits, 3, 0);
+
+       /* Audio channels and mode parameters */
+       REG_FLD_MOD(av_base, HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1);
+       r = hdmi_read_reg(av_base, HDMI_CORE_AV_AUD_MODE);
+       r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4);
+       r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3);
+       r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2);
+       r = FLD_MOD(r, cfg->en_spdif, 1, 1);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r);
+}
+
+void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
+               struct hdmi_core_infoframe_audio *info_aud)
+{
+       u8 val;
+       u8 sum = 0, checksum = 0;
+       void __iomem *av_base = hdmi_av_base(ip_data);
+
+       /*
+        * Set audio info frame type, version and length as
+        * described in HDMI 1.4a Section 8.2.2 specification.
+        * Checksum calculation is defined in Section 5.3.5.
+        */
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_TYPE, 0x84);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_VERS, 0x01);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_LEN, 0x0a);
+       sum += 0x84 + 0x001 + 0x00a;
+
+       val = (info_aud->db1_coding_type << 4)
+                       | (info_aud->db1_channel_count - 1);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0), val);
+       sum += val;
+
+       val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1), val);
+       sum += val;
+
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), 0x00);
+
+       val = info_aud->db4_channel_alloc;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), val);
+       sum += val;
+
+       val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4), val);
+       sum += val;
+
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(5), 0x00);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(6), 0x00);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(7), 0x00);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(8), 0x00);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(9), 0x00);
+
+       checksum = 0x100 - sum;
+       hdmi_write_reg(av_base,
+                                       HDMI_CORE_AV_AUDIO_CHSUM, checksum);
+
+       /*
+        * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing
+        * is available.
+        */
+}
+
+int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data,
+                               u32 sample_freq, u32 *n, u32 *cts)
+{
+       u32 r;
+       u32 deep_color = 0;
+       u32 pclk = ip_data->cfg.timings.timings.pixel_clock;
+
+       if (n == NULL || cts == NULL)
+               return -EINVAL;
+       /*
+        * Obtain current deep color configuration. This needed
+        * to calculate the TMDS clock based on the pixel clock.
+        */
+       r = REG_GET(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, 1, 0);
+       switch (r) {
+       case 1: /* No deep color selected */
+               deep_color = 100;
+               break;
+       case 2: /* 10-bit deep color selected */
+               deep_color = 125;
+               break;
+       case 3: /* 12-bit deep color selected */
+               deep_color = 150;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (sample_freq) {
+       case 32000:
+               if ((deep_color == 125) && ((pclk == 54054)
+                               || (pclk == 74250)))
+                       *n = 8192;
+               else
+                       *n = 4096;
+               break;
+       case 44100:
+               *n = 6272;
+               break;
+       case 48000:
+               if ((deep_color == 125) && ((pclk == 54054)
+                               || (pclk == 74250)))
+                       *n = 8192;
+               else
+                       *n = 6144;
+               break;
+       default:
+               *n = 0;
+               return -EINVAL;
+       }
+
+       /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
+       *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
+
+       return 0;
+}
+
+int hdmi_audio_trigger(struct hdmi_ip_data *ip_data,
+                               struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       int err = 0;
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               REG_FLD_MOD(hdmi_av_base(ip_data),
+                                       HDMI_CORE_AV_AUD_MODE, 1, 0, 0);
+               REG_FLD_MOD(hdmi_wp_base(ip_data),
+                                       HDMI_WP_AUDIO_CTRL, 1, 31, 31);
+               REG_FLD_MOD(hdmi_wp_base(ip_data),
+                                       HDMI_WP_AUDIO_CTRL, 1, 30, 30);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               REG_FLD_MOD(hdmi_av_base(ip_data),
+                                       HDMI_CORE_AV_AUD_MODE, 0, 0, 0);
+               REG_FLD_MOD(hdmi_wp_base(ip_data),
+                                       HDMI_WP_AUDIO_CTRL, 0, 30, 30);
+               REG_FLD_MOD(hdmi_wp_base(ip_data),
+                                       HDMI_WP_AUDIO_CTRL, 0, 31, 31);
+               break;
+       default:
+               err = -EINVAL;
+       }
+       return err;
+}
+#endif
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h
new file mode 100644 (file)
index 0000000..2040956
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * ti_hdmi_4xxx_ip.h
+ *
+ * HDMI header definition for DM81xx, DM38xx, TI OMAP4 etc processors.
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _HDMI_TI_4xxx_H_
+#define _HDMI_TI_4xxx_H_
+
+#include <linux/string.h>
+#include <video/omapdss.h>
+#include "ti_hdmi.h"
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#endif
+
+/* HDMI Wrapper */
+
+#define HDMI_WP_REVISION                       0x0
+#define HDMI_WP_SYSCONFIG                      0x10
+#define HDMI_WP_IRQSTATUS_RAW                  0x24
+#define HDMI_WP_IRQSTATUS                      0x28
+#define HDMI_WP_PWR_CTRL                       0x40
+#define HDMI_WP_IRQENABLE_SET                  0x2C
+#define HDMI_WP_VIDEO_CFG                      0x50
+#define HDMI_WP_VIDEO_SIZE                     0x60
+#define HDMI_WP_VIDEO_TIMING_H                 0x68
+#define HDMI_WP_VIDEO_TIMING_V                 0x6C
+#define HDMI_WP_WP_CLK                         0x70
+#define HDMI_WP_AUDIO_CFG                      0x80
+#define HDMI_WP_AUDIO_CFG2                     0x84
+#define HDMI_WP_AUDIO_CTRL                     0x88
+#define HDMI_WP_AUDIO_DATA                     0x8C
+
+/* HDMI IP Core System */
+
+#define HDMI_CORE_SYS_VND_IDL                  0x0
+#define HDMI_CORE_SYS_DEV_IDL                  0x8
+#define HDMI_CORE_SYS_DEV_IDH                  0xC
+#define HDMI_CORE_SYS_DEV_REV                  0x10
+#define HDMI_CORE_SYS_SRST                     0x14
+#define HDMI_CORE_CTRL1                                0x20
+#define HDMI_CORE_SYS_SYS_STAT                 0x24
+#define HDMI_CORE_SYS_VID_ACEN                 0x124
+#define HDMI_CORE_SYS_VID_MODE                 0x128
+#define HDMI_CORE_SYS_INTR_STATE               0x1C0
+#define HDMI_CORE_SYS_INTR1                    0x1C4
+#define HDMI_CORE_SYS_INTR2                    0x1C8
+#define HDMI_CORE_SYS_INTR3                    0x1CC
+#define HDMI_CORE_SYS_INTR4                    0x1D0
+#define HDMI_CORE_SYS_UMASK1                   0x1D4
+#define HDMI_CORE_SYS_TMDS_CTRL                        0x208
+#define HDMI_CORE_SYS_DE_DLY                   0xC8
+#define HDMI_CORE_SYS_DE_CTRL                  0xCC
+#define HDMI_CORE_SYS_DE_TOP                   0xD0
+#define HDMI_CORE_SYS_DE_CNTL                  0xD8
+#define HDMI_CORE_SYS_DE_CNTH                  0xDC
+#define HDMI_CORE_SYS_DE_LINL                  0xE0
+#define HDMI_CORE_SYS_DE_LINH_1                        0xE4
+#define HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC        0x1
+#define HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC        0x1
+#define HDMI_CORE_CTRL1_BSEL_24BITBUS          0x1
+#define HDMI_CORE_CTRL1_EDGE_RISINGEDGE        0x1
+
+/* HDMI DDC E-DID */
+#define HDMI_CORE_DDC_CMD                      0x3CC
+#define HDMI_CORE_DDC_STATUS                   0x3C8
+#define HDMI_CORE_DDC_ADDR                     0x3B4
+#define HDMI_CORE_DDC_OFFSET                   0x3BC
+#define HDMI_CORE_DDC_COUNT1                   0x3C0
+#define HDMI_CORE_DDC_COUNT2                   0x3C4
+#define HDMI_CORE_DDC_DATA                     0x3D0
+#define HDMI_CORE_DDC_SEGM                     0x3B8
+
+/* HDMI IP Core Audio Video */
+
+#define HDMI_CORE_AV_HDMI_CTRL                 0xBC
+#define HDMI_CORE_AV_DPD                       0xF4
+#define HDMI_CORE_AV_PB_CTRL1                  0xF8
+#define HDMI_CORE_AV_PB_CTRL2                  0xFC
+#define HDMI_CORE_AV_AVI_TYPE                  0x100
+#define HDMI_CORE_AV_AVI_VERS                  0x104
+#define HDMI_CORE_AV_AVI_LEN                   0x108
+#define HDMI_CORE_AV_AVI_CHSUM                 0x10C
+#define HDMI_CORE_AV_AVI_DBYTE(n)              (n * 4 + 0x110)
+#define HDMI_CORE_AV_AVI_DBYTE_NELEMS          15
+#define HDMI_CORE_AV_SPD_DBYTE(n)              (n * 4 + 0x190)
+#define HDMI_CORE_AV_SPD_DBYTE_NELEMS          27
+#define HDMI_CORE_AV_AUD_DBYTE(n)              (n * 4 + 0x210)
+#define HDMI_CORE_AV_AUD_DBYTE_NELEMS          10
+#define HDMI_CORE_AV_MPEG_DBYTE(n)             (n * 4 + 0x290)
+#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS         27
+#define HDMI_CORE_AV_GEN_DBYTE(n)              (n * 4 + 0x300)
+#define HDMI_CORE_AV_GEN_DBYTE_NELEMS          31
+#define HDMI_CORE_AV_GEN2_DBYTE(n)             (n * 4 + 0x380)
+#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS         31
+#define HDMI_CORE_AV_ACR_CTRL                  0x4
+#define HDMI_CORE_AV_FREQ_SVAL                 0x8
+#define HDMI_CORE_AV_N_SVAL1                   0xC
+#define HDMI_CORE_AV_N_SVAL2                   0x10
+#define HDMI_CORE_AV_N_SVAL3                   0x14
+#define HDMI_CORE_AV_CTS_SVAL1                 0x18
+#define HDMI_CORE_AV_CTS_SVAL2                 0x1C
+#define HDMI_CORE_AV_CTS_SVAL3                 0x20
+#define HDMI_CORE_AV_CTS_HVAL1                 0x24
+#define HDMI_CORE_AV_CTS_HVAL2                 0x28
+#define HDMI_CORE_AV_CTS_HVAL3                 0x2C
+#define HDMI_CORE_AV_AUD_MODE                  0x50
+#define HDMI_CORE_AV_SPDIF_CTRL                        0x54
+#define HDMI_CORE_AV_HW_SPDIF_FS               0x60
+#define HDMI_CORE_AV_SWAP_I2S                  0x64
+#define HDMI_CORE_AV_SPDIF_ERTH                        0x6C
+#define HDMI_CORE_AV_I2S_IN_MAP                        0x70
+#define HDMI_CORE_AV_I2S_IN_CTRL               0x74
+#define HDMI_CORE_AV_I2S_CHST0                 0x78
+#define HDMI_CORE_AV_I2S_CHST1                 0x7C
+#define HDMI_CORE_AV_I2S_CHST2                 0x80
+#define HDMI_CORE_AV_I2S_CHST4                 0x84
+#define HDMI_CORE_AV_I2S_CHST5                 0x88
+#define HDMI_CORE_AV_ASRC                      0x8C
+#define HDMI_CORE_AV_I2S_IN_LEN                        0x90
+#define HDMI_CORE_AV_HDMI_CTRL                 0xBC
+#define HDMI_CORE_AV_AUDO_TXSTAT               0xC0
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_1          0xCC
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_2          0xD0
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_3          0xD4
+#define HDMI_CORE_AV_TEST_TXCTRL               0xF0
+#define HDMI_CORE_AV_DPD                       0xF4
+#define HDMI_CORE_AV_PB_CTRL1                  0xF8
+#define HDMI_CORE_AV_PB_CTRL2                  0xFC
+#define HDMI_CORE_AV_AVI_TYPE                  0x100
+#define HDMI_CORE_AV_AVI_VERS                  0x104
+#define HDMI_CORE_AV_AVI_LEN                   0x108
+#define HDMI_CORE_AV_AVI_CHSUM                 0x10C
+#define HDMI_CORE_AV_SPD_TYPE                  0x180
+#define HDMI_CORE_AV_SPD_VERS                  0x184
+#define HDMI_CORE_AV_SPD_LEN                   0x188
+#define HDMI_CORE_AV_SPD_CHSUM                 0x18C
+#define HDMI_CORE_AV_AUDIO_TYPE                        0x200
+#define HDMI_CORE_AV_AUDIO_VERS                        0x204
+#define HDMI_CORE_AV_AUDIO_LEN                 0x208
+#define HDMI_CORE_AV_AUDIO_CHSUM               0x20C
+#define HDMI_CORE_AV_MPEG_TYPE                 0x280
+#define HDMI_CORE_AV_MPEG_VERS                 0x284
+#define HDMI_CORE_AV_MPEG_LEN                  0x288
+#define HDMI_CORE_AV_MPEG_CHSUM                        0x28C
+#define HDMI_CORE_AV_CP_BYTE1                  0x37C
+#define HDMI_CORE_AV_CEC_ADDR_ID               0x3FC
+#define HDMI_CORE_AV_SPD_DBYTE_ELSIZE          0x4
+#define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE         0x4
+#define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE         0x4
+#define HDMI_CORE_AV_GEN_DBYTE_ELSIZE          0x4
+
+/* PLL */
+
+#define PLLCTRL_PLL_CONTROL                    0x0
+#define PLLCTRL_PLL_STATUS                     0x4
+#define PLLCTRL_PLL_GO                         0x8
+#define PLLCTRL_CFG1                           0xC
+#define PLLCTRL_CFG2                           0x10
+#define PLLCTRL_CFG3                           0x14
+#define PLLCTRL_CFG4                           0x20
+
+/* HDMI PHY */
+
+#define HDMI_TXPHY_TX_CTRL                     0x0
+#define HDMI_TXPHY_DIGITAL_CTRL                        0x4
+#define HDMI_TXPHY_POWER_CTRL                  0x8
+#define HDMI_TXPHY_PAD_CFG_CTRL                        0xC
+
+#define REG_FLD_MOD(base, idx, val, start, end) \
+       hdmi_write_reg(base, idx, FLD_MOD(hdmi_read_reg(base, idx),\
+                                                       val, start, end))
+#define REG_GET(base, idx, start, end) \
+       FLD_GET(hdmi_read_reg(base, idx), start, end)
+
+enum hdmi_phy_pwr {
+       HDMI_PHYPWRCMD_OFF = 0,
+       HDMI_PHYPWRCMD_LDOON = 1,
+       HDMI_PHYPWRCMD_TXON = 2
+};
+
+enum hdmi_core_inputbus_width {
+       HDMI_INPUT_8BIT = 0,
+       HDMI_INPUT_10BIT = 1,
+       HDMI_INPUT_12BIT = 2
+};
+
+enum hdmi_core_dither_trunc {
+       HDMI_OUTPUTTRUNCATION_8BIT = 0,
+       HDMI_OUTPUTTRUNCATION_10BIT = 1,
+       HDMI_OUTPUTTRUNCATION_12BIT = 2,
+       HDMI_OUTPUTDITHER_8BIT = 3,
+       HDMI_OUTPUTDITHER_10BIT = 4,
+       HDMI_OUTPUTDITHER_12BIT = 5
+};
+
+enum hdmi_core_deepcolor_ed {
+       HDMI_DEEPCOLORPACKECTDISABLE = 0,
+       HDMI_DEEPCOLORPACKECTENABLE = 1
+};
+
+enum hdmi_core_packet_mode {
+       HDMI_PACKETMODERESERVEDVALUE = 0,
+       HDMI_PACKETMODE24BITPERPIXEL = 4,
+       HDMI_PACKETMODE30BITPERPIXEL = 5,
+       HDMI_PACKETMODE36BITPERPIXEL = 6,
+       HDMI_PACKETMODE48BITPERPIXEL = 7
+};
+
+enum hdmi_core_tclkselclkmult {
+       HDMI_FPLL05IDCK = 0,
+       HDMI_FPLL10IDCK = 1,
+       HDMI_FPLL20IDCK = 2,
+       HDMI_FPLL40IDCK = 3
+};
+
+enum hdmi_core_packet_ctrl {
+       HDMI_PACKETENABLE = 1,
+       HDMI_PACKETDISABLE = 0,
+       HDMI_PACKETREPEATON = 1,
+       HDMI_PACKETREPEATOFF = 0
+};
+
+/* INFOFRAME_AVI_ and INFOFRAME_AUDIO_ definitions */
+enum hdmi_core_infoframe {
+       HDMI_INFOFRAME_AVI_DB1Y_RGB = 0,
+       HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1,
+       HDMI_INFOFRAME_AVI_DB1Y_YUV444 = 2,
+       HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF = 0,
+       HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_ON =  1,
+       HDMI_INFOFRAME_AVI_DB1B_NO = 0,
+       HDMI_INFOFRAME_AVI_DB1B_VERT = 1,
+       HDMI_INFOFRAME_AVI_DB1B_HORI = 2,
+       HDMI_INFOFRAME_AVI_DB1B_VERTHORI = 3,
+       HDMI_INFOFRAME_AVI_DB1S_0 = 0,
+       HDMI_INFOFRAME_AVI_DB1S_1 = 1,
+       HDMI_INFOFRAME_AVI_DB1S_2 = 2,
+       HDMI_INFOFRAME_AVI_DB2C_NO = 0,
+       HDMI_INFOFRAME_AVI_DB2C_ITU601 = 1,
+       HDMI_INFOFRAME_AVI_DB2C_ITU709 = 2,
+       HDMI_INFOFRAME_AVI_DB2C_EC_EXTENDED = 3,
+       HDMI_INFOFRAME_AVI_DB2M_NO = 0,
+       HDMI_INFOFRAME_AVI_DB2M_43 = 1,
+       HDMI_INFOFRAME_AVI_DB2M_169 = 2,
+       HDMI_INFOFRAME_AVI_DB2R_SAME = 8,
+       HDMI_INFOFRAME_AVI_DB2R_43 = 9,
+       HDMI_INFOFRAME_AVI_DB2R_169 = 10,
+       HDMI_INFOFRAME_AVI_DB2R_149 = 11,
+       HDMI_INFOFRAME_AVI_DB3ITC_NO = 0,
+       HDMI_INFOFRAME_AVI_DB3ITC_YES = 1,
+       HDMI_INFOFRAME_AVI_DB3EC_XVYUV601 = 0,
+       HDMI_INFOFRAME_AVI_DB3EC_XVYUV709 = 1,
+       HDMI_INFOFRAME_AVI_DB3Q_DEFAULT = 0,
+       HDMI_INFOFRAME_AVI_DB3Q_LR = 1,
+       HDMI_INFOFRAME_AVI_DB3Q_FR = 2,
+       HDMI_INFOFRAME_AVI_DB3SC_NO = 0,
+       HDMI_INFOFRAME_AVI_DB3SC_HORI = 1,
+       HDMI_INFOFRAME_AVI_DB3SC_VERT = 2,
+       HDMI_INFOFRAME_AVI_DB3SC_HORIVERT = 3,
+       HDMI_INFOFRAME_AVI_DB5PR_NO = 0,
+       HDMI_INFOFRAME_AVI_DB5PR_2 = 1,
+       HDMI_INFOFRAME_AVI_DB5PR_3 = 2,
+       HDMI_INFOFRAME_AVI_DB5PR_4 = 3,
+       HDMI_INFOFRAME_AVI_DB5PR_5 = 4,
+       HDMI_INFOFRAME_AVI_DB5PR_6 = 5,
+       HDMI_INFOFRAME_AVI_DB5PR_7 = 6,
+       HDMI_INFOFRAME_AVI_DB5PR_8 = 7,
+       HDMI_INFOFRAME_AVI_DB5PR_9 = 8,
+       HDMI_INFOFRAME_AVI_DB5PR_10 = 9,
+       HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM = 0,
+       HDMI_INFOFRAME_AUDIO_DB1CT_IEC60958 = 1,
+       HDMI_INFOFRAME_AUDIO_DB1CT_AC3 = 2,
+       HDMI_INFOFRAME_AUDIO_DB1CT_MPEG1 = 3,
+       HDMI_INFOFRAME_AUDIO_DB1CT_MP3 = 4,
+       HDMI_INFOFRAME_AUDIO_DB1CT_MPEG2_MULTICH = 5,
+       HDMI_INFOFRAME_AUDIO_DB1CT_AAC = 6,
+       HDMI_INFOFRAME_AUDIO_DB1CT_DTS = 7,
+       HDMI_INFOFRAME_AUDIO_DB1CT_ATRAC = 8,
+       HDMI_INFOFRAME_AUDIO_DB1CT_ONEBIT = 9,
+       HDMI_INFOFRAME_AUDIO_DB1CT_DOLBY_DIGITAL_PLUS = 10,
+       HDMI_INFOFRAME_AUDIO_DB1CT_DTS_HD = 11,
+       HDMI_INFOFRAME_AUDIO_DB1CT_MAT = 12,
+       HDMI_INFOFRAME_AUDIO_DB1CT_DST = 13,
+       HDMI_INFOFRAME_AUDIO_DB1CT_WMA_PRO = 14,
+       HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM = 0,
+       HDMI_INFOFRAME_AUDIO_DB2SF_32000 = 1,
+       HDMI_INFOFRAME_AUDIO_DB2SF_44100 = 2,
+       HDMI_INFOFRAME_AUDIO_DB2SF_48000 = 3,
+       HDMI_INFOFRAME_AUDIO_DB2SF_88200 = 4,
+       HDMI_INFOFRAME_AUDIO_DB2SF_96000 = 5,
+       HDMI_INFOFRAME_AUDIO_DB2SF_176400 = 6,
+       HDMI_INFOFRAME_AUDIO_DB2SF_192000 = 7,
+       HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM = 0,
+       HDMI_INFOFRAME_AUDIO_DB2SS_16BIT = 1,
+       HDMI_INFOFRAME_AUDIO_DB2SS_20BIT = 2,
+       HDMI_INFOFRAME_AUDIO_DB2SS_24BIT = 3,
+       HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PERMITTED = 0,
+       HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PROHIBITED = 1
+};
+
+enum hdmi_packing_mode {
+       HDMI_PACK_10b_RGB_YUV444 = 0,
+       HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
+       HDMI_PACK_20b_YUV422 = 2,
+       HDMI_PACK_ALREADYPACKED = 7
+};
+
+enum hdmi_core_audio_sample_freq {
+       HDMI_AUDIO_FS_32000 = 0x3,
+       HDMI_AUDIO_FS_44100 = 0x0,
+       HDMI_AUDIO_FS_48000 = 0x2,
+       HDMI_AUDIO_FS_88200 = 0x8,
+       HDMI_AUDIO_FS_96000 = 0xA,
+       HDMI_AUDIO_FS_176400 = 0xC,
+       HDMI_AUDIO_FS_192000 = 0xE,
+       HDMI_AUDIO_FS_NOT_INDICATED = 0x1
+};
+
+enum hdmi_core_audio_layout {
+       HDMI_AUDIO_LAYOUT_2CH = 0,
+       HDMI_AUDIO_LAYOUT_8CH = 1
+};
+
+enum hdmi_core_cts_mode {
+       HDMI_AUDIO_CTS_MODE_HW = 0,
+       HDMI_AUDIO_CTS_MODE_SW = 1
+};
+
+enum hdmi_stereo_channels {
+       HDMI_AUDIO_STEREO_NOCHANNELS = 0,
+       HDMI_AUDIO_STEREO_ONECHANNEL = 1,
+       HDMI_AUDIO_STEREO_TWOCHANNELS = 2,
+       HDMI_AUDIO_STEREO_THREECHANNELS = 3,
+       HDMI_AUDIO_STEREO_FOURCHANNELS = 4
+};
+
+enum hdmi_audio_type {
+       HDMI_AUDIO_TYPE_LPCM = 0,
+       HDMI_AUDIO_TYPE_IEC = 1
+};
+
+enum hdmi_audio_justify {
+       HDMI_AUDIO_JUSTIFY_LEFT = 0,
+       HDMI_AUDIO_JUSTIFY_RIGHT = 1
+};
+
+enum hdmi_audio_sample_order {
+       HDMI_AUDIO_SAMPLE_RIGHT_FIRST = 0,
+       HDMI_AUDIO_SAMPLE_LEFT_FIRST = 1
+};
+
+enum hdmi_audio_samples_perword {
+       HDMI_AUDIO_ONEWORD_ONESAMPLE = 0,
+       HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1
+};
+
+enum hdmi_audio_sample_size {
+       HDMI_AUDIO_SAMPLE_16BITS = 0,
+       HDMI_AUDIO_SAMPLE_24BITS = 1
+};
+
+enum hdmi_audio_transf_mode {
+       HDMI_AUDIO_TRANSF_DMA = 0,
+       HDMI_AUDIO_TRANSF_IRQ = 1
+};
+
+enum hdmi_audio_blk_strt_end_sig {
+       HDMI_AUDIO_BLOCK_SIG_STARTEND_ON = 0,
+       HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF = 1
+};
+
+enum hdmi_audio_i2s_config {
+       HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT = 0,
+       HDMI_AUDIO_I2S_WS_POLARIT_YLOW_IS_RIGHT = 1,
+       HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0,
+       HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1,
+       HDMI_AUDIO_I2S_MAX_WORD_20BITS = 0,
+       HDMI_AUDIO_I2S_MAX_WORD_24BITS = 1,
+       HDMI_AUDIO_I2S_CHST_WORD_NOT_SPECIFIED = 0,
+       HDMI_AUDIO_I2S_CHST_WORD_16_BITS = 1,
+       HDMI_AUDIO_I2S_CHST_WORD_17_BITS = 6,
+       HDMI_AUDIO_I2S_CHST_WORD_18_BITS = 2,
+       HDMI_AUDIO_I2S_CHST_WORD_19_BITS = 4,
+       HDMI_AUDIO_I2S_CHST_WORD_20_BITS_20MAX = 5,
+       HDMI_AUDIO_I2S_CHST_WORD_20_BITS_24MAX = 1,
+       HDMI_AUDIO_I2S_CHST_WORD_21_BITS = 6,
+       HDMI_AUDIO_I2S_CHST_WORD_22_BITS = 2,
+       HDMI_AUDIO_I2S_CHST_WORD_23_BITS = 4,
+       HDMI_AUDIO_I2S_CHST_WORD_24_BITS = 5,
+       HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0,
+       HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1,
+       HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0,
+       HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_NA = 0,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_16 = 2,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_17 = 12,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_18 = 4,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_19 = 8,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_20 = 10,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_21 = 13,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_22 = 5,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_23 = 9,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_24 = 11,
+       HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0,
+       HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1,
+       HDMI_AUDIO_I2S_SD0_EN = 1,
+       HDMI_AUDIO_I2S_SD1_EN = 1 << 1,
+       HDMI_AUDIO_I2S_SD2_EN = 1 << 2,
+       HDMI_AUDIO_I2S_SD3_EN = 1 << 3,
+};
+
+enum hdmi_audio_mclk_mode {
+       HDMI_AUDIO_MCLK_128FS = 0,
+       HDMI_AUDIO_MCLK_256FS = 1,
+       HDMI_AUDIO_MCLK_384FS = 2,
+       HDMI_AUDIO_MCLK_512FS = 3,
+       HDMI_AUDIO_MCLK_768FS = 4,
+       HDMI_AUDIO_MCLK_1024FS = 5,
+       HDMI_AUDIO_MCLK_1152FS = 6,
+       HDMI_AUDIO_MCLK_192FS = 7
+};
+
+struct hdmi_core_video_config {
+       enum hdmi_core_inputbus_width   ip_bus_width;
+       enum hdmi_core_dither_trunc     op_dither_truc;
+       enum hdmi_core_deepcolor_ed     deep_color_pkt;
+       enum hdmi_core_packet_mode      pkt_mode;
+       enum hdmi_core_hdmi_dvi         hdmi_dvi;
+       enum hdmi_core_tclkselclkmult   tclk_sel_clkmult;
+};
+
+/*
+ * Refer to section 8.2 in HDMI 1.3 specification for
+ * details about infoframe databytes
+ */
+struct hdmi_core_infoframe_avi {
+       /* Y0, Y1 rgb,yCbCr */
+       u8      db1_format;
+       /* A0  Active information Present */
+       u8      db1_active_info;
+       /* B0, B1 Bar info data valid */
+       u8      db1_bar_info_dv;
+       /* S0, S1 scan information */
+       u8      db1_scan_info;
+       /* C0, C1 colorimetry */
+       u8      db2_colorimetry;
+       /* M0, M1 Aspect ratio (4:3, 16:9) */
+       u8      db2_aspect_ratio;
+       /* R0...R3 Active format aspect ratio */
+       u8      db2_active_fmt_ar;
+       /* ITC IT content. */
+       u8      db3_itc;
+       /* EC0, EC1, EC2 Extended colorimetry */
+       u8      db3_ec;
+       /* Q1, Q0 Quantization range */
+       u8      db3_q_range;
+       /* SC1, SC0 Non-uniform picture scaling */
+       u8      db3_nup_scaling;
+       /* VIC0..6 Video format identification */
+       u8      db4_videocode;
+       /* PR0..PR3 Pixel repetition factor */
+       u8      db5_pixel_repeat;
+       /* Line number end of top bar */
+       u16     db6_7_line_eoftop;
+       /* Line number start of bottom bar */
+       u16     db8_9_line_sofbottom;
+       /* Pixel number end of left bar */
+       u16     db10_11_pixel_eofleft;
+       /* Pixel number start of right bar */
+       u16     db12_13_pixel_sofright;
+};
+/*
+ * Refer to section 8.2 in HDMI 1.3 specification for
+ * details about infoframe databytes
+ */
+struct hdmi_core_infoframe_audio {
+       u8 db1_coding_type;
+       u8 db1_channel_count;
+       u8 db2_sample_freq;
+       u8 db2_sample_size;
+       u8 db4_channel_alloc;
+       bool db5_downmix_inh;
+       u8 db5_lsv;     /* Level shift values for downmix */
+};
+
+struct hdmi_core_packet_enable_repeat {
+       u32     audio_pkt;
+       u32     audio_pkt_repeat;
+       u32     avi_infoframe;
+       u32     avi_infoframe_repeat;
+       u32     gen_cntrl_pkt;
+       u32     gen_cntrl_pkt_repeat;
+       u32     generic_pkt;
+       u32     generic_pkt_repeat;
+};
+
+struct hdmi_video_format {
+       enum hdmi_packing_mode  packing_mode;
+       u32                     y_res;  /* Line per panel */
+       u32                     x_res;  /* pixel per line */
+};
+
+struct hdmi_video_interface {
+       int     vsp;    /* Vsync polarity */
+       int     hsp;    /* Hsync polarity */
+       int     interlacing;
+       int     tm;     /* Timing mode */
+};
+
+struct hdmi_audio_format {
+       enum hdmi_stereo_channels               stereo_channels;
+       u8                                      active_chnnls_msk;
+       enum hdmi_audio_type                    type;
+       enum hdmi_audio_justify                 justification;
+       enum hdmi_audio_sample_order            sample_order;
+       enum hdmi_audio_samples_perword         samples_per_word;
+       enum hdmi_audio_sample_size             sample_size;
+       enum hdmi_audio_blk_strt_end_sig        en_sig_blk_strt_end;
+};
+
+struct hdmi_audio_dma {
+       u8                              transfer_size;
+       u8                              block_size;
+       enum hdmi_audio_transf_mode     mode;
+       u16                             fifo_threshold;
+};
+
+struct hdmi_core_audio_i2s_config {
+       u8 word_max_length;
+       u8 word_length;
+       u8 in_length_bits;
+       u8 justification;
+       u8 en_high_bitrate_aud;
+       u8 sck_edge_mode;
+       u8 cbit_order;
+       u8 vbit;
+       u8 ws_polarity;
+       u8 direction;
+       u8 shift;
+       u8 active_sds;
+};
+
+struct hdmi_core_audio_config {
+       struct hdmi_core_audio_i2s_config       i2s_cfg;
+       enum hdmi_core_audio_sample_freq        freq_sample;
+       bool                                    fs_override;
+       u32                                     n;
+       u32                                     cts;
+       u32                                     aud_par_busclk;
+       enum hdmi_core_audio_layout             layout;
+       enum hdmi_core_cts_mode                 cts_mode;
+       bool                                    use_mclk;
+       enum hdmi_audio_mclk_mode               mclk_mode;
+       bool                                    en_acr_pkt;
+       bool                                    en_dsd_audio;
+       bool                                    en_parallel_aud_input;
+       bool                                    en_spdif;
+};
+
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+int hdmi_audio_trigger(struct hdmi_ip_data *ip_data,
+                               struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai);
+int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data,
+                               u32 sample_freq, u32 *n, u32 *cts);
+void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
+               struct hdmi_core_infoframe_audio *info_aud);
+void hdmi_core_audio_config(struct hdmi_ip_data *ip_data,
+                                       struct hdmi_core_audio_config *cfg);
+void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data,
+                                       struct hdmi_audio_dma *aud_dma);
+void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data,
+                                       struct hdmi_audio_format *aud_fmt);
+#endif
+#endif
index 173c664..7533458 100644 (file)
@@ -295,7 +295,6 @@ static struct {
        u32 wss_data;
        struct regulator *vdda_dac_reg;
 
-       struct clk      *tv_clk;
        struct clk      *tv_dac_clk;
 } venc;
 
@@ -464,9 +463,11 @@ static void venc_power_off(struct omap_dss_device *dssdev)
        regulator_disable(venc.vdda_dac_reg);
 }
 
-
-
-
+unsigned long venc_get_pixel_clock(void)
+{
+       /* VENC Pixel Clock in Mhz */
+       return 13500000;
+}
 
 /* driver */
 static int venc_panel_probe(struct omap_dss_device *dssdev)
@@ -732,22 +733,10 @@ static int venc_get_clocks(struct platform_device *pdev)
 {
        struct clk *clk;
 
-       clk = clk_get(&pdev->dev, "fck");
-       if (IS_ERR(clk)) {
-               DSSERR("can't get fck\n");
-               return PTR_ERR(clk);
-       }
-
-       venc.tv_clk = clk;
-
        if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
-               if (cpu_is_omap34xx() || cpu_is_omap3630())
-                       clk = clk_get(&pdev->dev, "dss_96m_fck");
-               else
-                       clk = clk_get(&pdev->dev, "tv_dac_clk");
+               clk = clk_get(&pdev->dev, "tv_dac_clk");
                if (IS_ERR(clk)) {
                        DSSERR("can't get tv_dac_clk\n");
-                       clk_put(venc.tv_clk);
                        return PTR_ERR(clk);
                }
        } else {
@@ -761,8 +750,6 @@ static int venc_get_clocks(struct platform_device *pdev)
 
 static void venc_put_clocks(void)
 {
-       if (venc.tv_clk)
-               clk_put(venc.tv_clk);
        if (venc.tv_dac_clk)
                clk_put(venc.tv_dac_clk);
 }
@@ -838,7 +825,6 @@ static int venc_runtime_suspend(struct device *dev)
 {
        if (venc.tv_dac_clk)
                clk_disable(venc.tv_dac_clk);
-       clk_disable(venc.tv_clk);
 
        dispc_runtime_put();
        dss_runtime_put();
@@ -858,7 +844,6 @@ static int venc_runtime_resume(struct device *dev)
        if (r < 0)
                goto err_get_dispc;
 
-       clk_enable(venc.tv_clk);
        if (venc.tv_dac_clk)
                clk_enable(venc.tv_dac_clk);
 
index aa33386..83d3fe7 100644 (file)
@@ -1,5 +1,5 @@
 menuconfig FB_OMAP2
-        tristate "OMAP2+ frame buffer support (EXPERIMENTAL)"
+        tristate "OMAP2+ frame buffer support"
         depends on FB && OMAP2_DSS
 
        select OMAP2_VRAM
index 602b71a..70aa47d 100644 (file)
@@ -808,19 +808,15 @@ static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var,
 static void omapfb_calc_addr(const struct omapfb_info *ofbi,
                             const struct fb_var_screeninfo *var,
                             const struct fb_fix_screeninfo *fix,
-                            int rotation, u32 *paddr, void __iomem **vaddr)
+                            int rotation, u32 *paddr)
 {
        u32 data_start_p;
-       void __iomem *data_start_v;
        int offset;
 
-       if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
+       if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
                data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
-               data_start_v = NULL;
-       } else {
+       else
                data_start_p = omapfb_get_region_paddr(ofbi);
-               data_start_v = omapfb_get_region_vaddr(ofbi);
-       }
 
        if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
                offset = calc_rotation_offset_vrfb(var, fix, rotation);
@@ -828,16 +824,14 @@ static void omapfb_calc_addr(const struct omapfb_info *ofbi,
                offset = calc_rotation_offset_dma(var, fix, rotation);
 
        data_start_p += offset;
-       data_start_v += offset;
 
        if (offset)
                DBG("offset %d, %d = %d\n",
                    var->xoffset, var->yoffset, offset);
 
-       DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
+       DBG("paddr %x\n", data_start_p);
 
        *paddr = data_start_p;
-       *vaddr = data_start_v;
 }
 
 /* setup overlay according to the fb */
@@ -850,7 +844,6 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
        struct fb_fix_screeninfo *fix = &fbi->fix;
        enum omap_color_mode mode = 0;
        u32 data_start_p = 0;
-       void __iomem *data_start_v = NULL;
        struct omap_overlay_info info;
        int xres, yres;
        int screen_width;
@@ -880,8 +873,7 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
        }
 
        if (ofbi->region->size)
-               omapfb_calc_addr(ofbi, var, fix, rotation,
-                                &data_start_p, &data_start_v);
+               omapfb_calc_addr(ofbi, var, fix, rotation, &data_start_p);
 
        r = fb_mode_to_dss_mode(var, &mode);
        if (r) {
@@ -910,7 +902,6 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
                mirror = ofbi->mirror;
 
        info.paddr = data_start_p;
-       info.vaddr = data_start_v;
        info.screen_width = screen_width;
        info.width = xres;
        info.height = yres;
@@ -2276,6 +2267,87 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
        return r;
 }
 
+static void fb_videomode_to_omap_timings(struct fb_videomode *m,
+               struct omap_video_timings *t)
+{
+       t->x_res = m->xres;
+       t->y_res = m->yres;
+       t->pixel_clock = PICOS2KHZ(m->pixclock);
+       t->hsw = m->hsync_len;
+       t->hfp = m->right_margin;
+       t->hbp = m->left_margin;
+       t->vsw = m->vsync_len;
+       t->vfp = m->lower_margin;
+       t->vbp = m->upper_margin;
+}
+
+static int omapfb_find_best_mode(struct omap_dss_device *display,
+               struct omap_video_timings *timings)
+{
+       struct fb_monspecs *specs;
+       u8 *edid;
+       int r, i, best_xres, best_idx, len;
+
+       if (!display->driver->read_edid)
+               return -ENODEV;
+
+       len = 0x80 * 2;
+       edid = kmalloc(len, GFP_KERNEL);
+
+       r = display->driver->read_edid(display, edid, len);
+       if (r < 0)
+               goto err1;
+
+       specs = kzalloc(sizeof(*specs), GFP_KERNEL);
+
+       fb_edid_to_monspecs(edid, specs);
+
+       if (edid[126] > 0)
+               fb_edid_add_monspecs(edid + 0x80, specs);
+
+       best_xres = 0;
+       best_idx = -1;
+
+       for (i = 0; i < specs->modedb_len; ++i) {
+               struct fb_videomode *m;
+               struct omap_video_timings t;
+
+               m = &specs->modedb[i];
+
+               if (m->pixclock == 0)
+                       continue;
+
+               /* skip repeated pixel modes */
+               if (m->xres == 2880 || m->xres == 1440)
+                       continue;
+
+               fb_videomode_to_omap_timings(m, &t);
+
+               r = display->driver->check_timings(display, &t);
+               if (r == 0 && best_xres < m->xres) {
+                       best_xres = m->xres;
+                       best_idx = i;
+               }
+       }
+
+       if (best_xres == 0) {
+               r = -ENOENT;
+               goto err2;
+       }
+
+       fb_videomode_to_omap_timings(&specs->modedb[best_idx], timings);
+
+       r = 0;
+
+err2:
+       fb_destroy_modedb(specs->modedb);
+       kfree(specs);
+err1:
+       kfree(edid);
+
+       return r;
+}
+
 static int omapfb_init_display(struct omapfb2_device *fbdev,
                struct omap_dss_device *dssdev)
 {
@@ -2373,8 +2445,10 @@ static int omapfb_probe(struct platform_device *pdev)
                omap_dss_get_device(dssdev);
 
                if (!dssdev->driver) {
-                       dev_err(&pdev->dev, "no driver for display\n");
-                       r = -ENODEV;
+                       dev_warn(&pdev->dev, "no driver for display: %s\n",
+                               dssdev->name);
+                       omap_dss_put_device(dssdev);
+                       continue;
                }
 
                d = &fbdev->displays[fbdev->num_displays++];
@@ -2402,9 +2476,27 @@ static int omapfb_probe(struct platform_device *pdev)
        for (i = 0; i < fbdev->num_managers; i++)
                fbdev->managers[i] = omap_dss_get_overlay_manager(i);
 
+       /* gfx overlay should be the default one. find a display
+        * connected to that, and use it as default display */
+       ovl = omap_dss_get_overlay(0);
+       if (ovl->manager && ovl->manager->device) {
+               def_display = ovl->manager->device;
+       } else {
+               dev_warn(&pdev->dev, "cannot find default display\n");
+               def_display = NULL;
+       }
+
        if (def_mode && strlen(def_mode) > 0) {
                if (omapfb_parse_def_modes(fbdev))
                        dev_warn(&pdev->dev, "cannot parse default modes\n");
+       } else if (def_display && def_display->driver->set_timings &&
+                       def_display->driver->check_timings) {
+               struct omap_video_timings t;
+
+               r = omapfb_find_best_mode(def_display, &t);
+
+               if (r == 0)
+                       def_display->driver->set_timings(def_display, &t);
        }
 
        r = omapfb_create_framebuffers(fbdev);
@@ -2421,16 +2513,6 @@ static int omapfb_probe(struct platform_device *pdev)
 
        DBG("mgr->apply'ed\n");
 
-       /* gfx overlay should be the default one. find a display
-        * connected to that, and use it as default display */
-       ovl = omap_dss_get_overlay(0);
-       if (ovl->manager && ovl->manager->device) {
-               def_display = ovl->manager->device;
-       } else {
-               dev_warn(&pdev->dev, "cannot find default display\n");
-               def_display = NULL;
-       }
-
        if (def_display) {
                r = omapfb_init_display(fbdev, def_display);
                if (r) {
index 153bf1a..1694d51 100644 (file)
@@ -104,16 +104,14 @@ static ssize_t store_mirror(struct device *dev,
 {
        struct fb_info *fbi = dev_get_drvdata(dev);
        struct omapfb_info *ofbi = FB2OFB(fbi);
-       int mirror;
+       bool mirror;
        int r;
        struct fb_var_screeninfo new_var;
 
-       r = kstrtoint(buf, 0, &mirror);
+       r = strtobool(buf, &mirror);
        if (r)
                return r;
 
-       mirror = !!mirror;
-
        if (!lock_fb_info(fbi))
                return -ENODEV;
 
index f27ae16..ae3caa6 100644 (file)
@@ -490,7 +490,7 @@ static int platinum_var_to_par(struct fb_var_screeninfo *var,
 
 
 /* 
- * Parse user speficied options (`video=platinumfb:')
+ * Parse user specified options (`video=platinumfb:')
  */
 static int __init platinumfb_setup(char *options)
 {
@@ -683,7 +683,7 @@ static struct platform_driver platinum_driver =
                .of_match_table = platinumfb_match,
        },
        .probe          = platinumfb_probe,
-       .remove         = platinumfb_remove,
+       .remove         = __devexit_p(platinumfb_remove),
 };
 
 static int __init platinumfb_init(void)
index 27f93aa..dc7bfa9 100644 (file)
@@ -973,8 +973,8 @@ static int pm2fb_pan_display(struct fb_var_screeninfo *var,
 {
        struct pm2fb_par *p = info->par;
        u32 base;
-       u32 depth = (var->bits_per_pixel + 7) & ~7;
-       u32 xres = (var->xres + 31) & ~31;
+       u32 depth = (info->var.bits_per_pixel + 7) & ~7;
+       u32 xres = (info->var.xres + 31) & ~31;
 
        depth = (depth > 32) ? 32 : depth;
        base = to3264(var->yoffset * xres + var->xoffset, depth, 1);
@@ -1773,7 +1773,7 @@ MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
 
 #ifndef MODULE
 /**
- * Parse user speficied options.
+ * Parse user specified options.
  *
  * This is, comma-separated options following `video=pm2fb:'.
  */
index 6666f45..6632ee5 100644 (file)
@@ -1147,9 +1147,9 @@ static int pm3fb_pan_display(struct fb_var_screeninfo *var,
                                 struct fb_info *info)
 {
        struct pm3_par *par = info->par;
-       const u32 xres = (var->xres + 31) & ~31;
+       const u32 xres = (info->var.xres + 31) & ~31;
 
-       par->base = pm3fb_shift_bpp(var->bits_per_pixel,
+       par->base = pm3fb_shift_bpp(info->var.bits_per_pixel,
                                        (var->yoffset * xres)
                                        + var->xoffset);
        PM3_WAIT(par, 1);
@@ -1525,7 +1525,7 @@ static int __init pm3fb_setup(char *options)
 {
        char *this_opt;
 
-       /* Parse user speficied options (`video=pm3fb:') */
+       /* Parse user specified options (`video=pm3fb:') */
        if (!options || !*options)
                return 0;
 
index 65560a1..213fbbc 100644 (file)
@@ -1082,7 +1082,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        }
 
        retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt,
-                            IRQF_DISABLED, DEVICE_NAME, &dev->core);
+                            0, DEVICE_NAME, &dev->core);
        if (retval) {
                dev_err(&dev->core, "%s: request_irq failed %d\n", __func__,
                        retval);
index 0283c70..1ed8b36 100644 (file)
@@ -31,8 +31,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
-
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/miscdevice.h>
@@ -678,7 +676,7 @@ pxa3xx_gcu_probe(struct platform_device *dev)
        }
 
        ret = request_irq(irq, pxa3xx_gcu_handle_irq,
-                         IRQF_DISABLED, DRV_NAME, priv);
+                         0, DRV_NAME, priv);
        if (ret) {
                dev_err(&dev->dev, "request_irq failed\n");
                ret = -EBUSY;
index 0f4e8c9..e89778f 100644 (file)
@@ -2191,7 +2191,7 @@ static int __devinit pxafb_probe(struct platform_device *dev)
                goto failed_free_mem;
        }
 
-       ret = request_irq(irq, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi);
+       ret = request_irq(irq, pxafb_handle_irq, 0, "LCD", fbi);
        if (ret) {
                dev_err(&dev->dev, "request_irq failed: %d\n", ret);
                ret = -EBUSY;
index 4aecf21..0753b1c 100644 (file)
@@ -81,6 +81,7 @@ struct s3c_fb;
  * @palette: Address of palette memory, or 0 if none.
  * @has_prtcon: Set if has PRTCON register.
  * @has_shadowcon: Set if has SHADOWCON register.
+ * @has_clksel: Set if VIDCON0 register has CLKSEL bit.
  */
 struct s3c_fb_variant {
        unsigned int    is_2443:1;
@@ -98,6 +99,7 @@ struct s3c_fb_variant {
 
        unsigned int    has_prtcon:1;
        unsigned int    has_shadowcon:1;
+       unsigned int    has_clksel:1;
 };
 
 /**
@@ -186,6 +188,7 @@ struct s3c_fb_vsync {
  * @dev: The device that we bound to, for printing, etc.
  * @regs_res: The resource we claimed for the IO registers.
  * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
+ * @lcd_clk: The clk (sclk) feeding pixclk.
  * @regs: The mapped hardware registers.
  * @variant: Variant information for this hardware.
  * @enabled: A bitmask of enabled hardware windows.
@@ -200,6 +203,7 @@ struct s3c_fb {
        struct device           *dev;
        struct resource         *regs_res;
        struct clk              *bus_clk;
+       struct clk              *lcd_clk;
        void __iomem            *regs;
        struct s3c_fb_variant    variant;
 
@@ -336,10 +340,15 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
  */
 static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
 {
-       unsigned long clk = clk_get_rate(sfb->bus_clk);
+       unsigned long clk;
        unsigned long long tmp;
        unsigned int result;
 
+       if (sfb->variant.has_clksel)
+               clk = clk_get_rate(sfb->bus_clk);
+       else
+               clk = clk_get_rate(sfb->lcd_clk);
+
        tmp = (unsigned long long)clk;
        tmp *= pixclk;
 
@@ -883,7 +892,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
                }
        }
        /* Offset in bytes to the end of the displayed area */
-       end_boff = start_boff + var->yres * info->fix.line_length;
+       end_boff = start_boff + info->var.yres * info->fix.line_length;
 
        /* Temporarily turn off per-vsync update from shadow registers until
         * both start and end addresses are updated to prevent corruption */
@@ -1354,13 +1363,24 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
 
        clk_enable(sfb->bus_clk);
 
+       if (!sfb->variant.has_clksel) {
+               sfb->lcd_clk = clk_get(dev, "sclk_fimd");
+               if (IS_ERR(sfb->lcd_clk)) {
+                       dev_err(dev, "failed to get lcd clock\n");
+                       ret = PTR_ERR(sfb->lcd_clk);
+                       goto err_bus_clk;
+               }
+
+               clk_enable(sfb->lcd_clk);
+       }
+
        pm_runtime_enable(sfb->dev);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(dev, "failed to find registers\n");
                ret = -ENOENT;
-               goto err_clk;
+               goto err_lcd_clk;
        }
 
        sfb->regs_res = request_mem_region(res->start, resource_size(res),
@@ -1368,7 +1388,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
        if (!sfb->regs_res) {
                dev_err(dev, "failed to claim register region\n");
                ret = -ENOENT;
-               goto err_clk;
+               goto err_lcd_clk;
        }
 
        sfb->regs = ioremap(res->start, resource_size(res));
@@ -1450,7 +1470,13 @@ err_ioremap:
 err_req_region:
        release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
 
-err_clk:
+err_lcd_clk:
+       if (!sfb->variant.has_clksel) {
+               clk_disable(sfb->lcd_clk);
+               clk_put(sfb->lcd_clk);
+       }
+
+err_bus_clk:
        clk_disable(sfb->bus_clk);
        clk_put(sfb->bus_clk);
 
@@ -1481,6 +1507,11 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
 
        iounmap(sfb->regs);
 
+       if (!sfb->variant.has_clksel) {
+               clk_disable(sfb->lcd_clk);
+               clk_put(sfb->lcd_clk);
+       }
+
        clk_disable(sfb->bus_clk);
        clk_put(sfb->bus_clk);
 
@@ -1510,6 +1541,9 @@ static int s3c_fb_suspend(struct device *dev)
                s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
        }
 
+       if (!sfb->variant.has_clksel)
+               clk_disable(sfb->lcd_clk);
+
        clk_disable(sfb->bus_clk);
        return 0;
 }
@@ -1524,6 +1558,9 @@ static int s3c_fb_resume(struct device *dev)
 
        clk_enable(sfb->bus_clk);
 
+       if (!sfb->variant.has_clksel)
+               clk_enable(sfb->lcd_clk);
+
        /* setup gpio and output polarity controls */
        pd->setup_gpio();
        writel(pd->vidcon1, sfb->regs + VIDCON1);
@@ -1569,6 +1606,9 @@ static int s3c_fb_runtime_suspend(struct device *dev)
                s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
        }
 
+       if (!sfb->variant.has_clksel)
+               clk_disable(sfb->lcd_clk);
+
        clk_disable(sfb->bus_clk);
        return 0;
 }
@@ -1583,6 +1623,9 @@ static int s3c_fb_runtime_resume(struct device *dev)
 
        clk_enable(sfb->bus_clk);
 
+       if (!sfb->variant.has_clksel)
+               clk_enable(sfb->lcd_clk);
+
        /* setup gpio and output polarity controls */
        pd->setup_gpio();
        writel(pd->vidcon1, sfb->regs + VIDCON1);
@@ -1755,6 +1798,7 @@ static struct s3c_fb_driverdata s3c_fb_data_64xx = {
                },
 
                .has_prtcon     = 1,
+               .has_clksel     = 1,
        },
        .win[0] = &s3c_fb_data_64xx_wins[0],
        .win[1] = &s3c_fb_data_64xx_wins[1],
@@ -1785,6 +1829,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
                },
 
                .has_prtcon     = 1,
+               .has_clksel     = 1,
        },
        .win[0] = &s3c_fb_data_s5p_wins[0],
        .win[1] = &s3c_fb_data_s5p_wins[1],
@@ -1794,6 +1839,37 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
 };
 
 static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
+       .variant = {
+               .nr_windows     = 5,
+               .vidtcon        = VIDTCON0,
+               .wincon         = WINCON(0),
+               .winmap         = WINxMAP(0),
+               .keycon         = WKEYCON,
+               .osd            = VIDOSD_BASE,
+               .osd_stride     = 16,
+               .buf_start      = VIDW_BUF_START(0),
+               .buf_size       = VIDW_BUF_SIZE(0),
+               .buf_end        = VIDW_BUF_END(0),
+
+               .palette = {
+                       [0] = 0x2400,
+                       [1] = 0x2800,
+                       [2] = 0x2c00,
+                       [3] = 0x3000,
+                       [4] = 0x3400,
+               },
+
+               .has_shadowcon  = 1,
+               .has_clksel     = 1,
+       },
+       .win[0] = &s3c_fb_data_s5p_wins[0],
+       .win[1] = &s3c_fb_data_s5p_wins[1],
+       .win[2] = &s3c_fb_data_s5p_wins[2],
+       .win[3] = &s3c_fb_data_s5p_wins[3],
+       .win[4] = &s3c_fb_data_s5p_wins[4],
+};
+
+static struct s3c_fb_driverdata s3c_fb_data_exynos4 = {
        .variant = {
                .nr_windows     = 5,
                .vidtcon        = VIDTCON0,
@@ -1843,6 +1919,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
                        [0] = 0x400,
                        [1] = 0x800,
                },
+               .has_clksel     = 1,
        },
        .win[0] = &(struct s3c_fb_win_variant) {
                .palette_sz     = 256,
@@ -1859,6 +1936,30 @@ static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
        },
 };
 
+static struct s3c_fb_driverdata s3c_fb_data_s5p64x0 = {
+       .variant = {
+               .nr_windows     = 3,
+               .vidtcon        = VIDTCON0,
+               .wincon         = WINCON(0),
+               .winmap         = WINxMAP(0),
+               .keycon         = WKEYCON,
+               .osd            = VIDOSD_BASE,
+               .osd_stride     = 16,
+               .buf_start      = VIDW_BUF_START(0),
+               .buf_size       = VIDW_BUF_SIZE(0),
+               .buf_end        = VIDW_BUF_END(0),
+
+               .palette = {
+                       [0] = 0x2400,
+                       [1] = 0x2800,
+                       [2] = 0x2c00,
+               },
+       },
+       .win[0] = &s3c_fb_data_s5p_wins[0],
+       .win[1] = &s3c_fb_data_s5p_wins[1],
+       .win[2] = &s3c_fb_data_s5p_wins[2],
+};
+
 static struct platform_device_id s3c_fb_driver_ids[] = {
        {
                .name           = "s3c-fb",
@@ -1869,9 +1970,15 @@ static struct platform_device_id s3c_fb_driver_ids[] = {
        }, {
                .name           = "s5pv210-fb",
                .driver_data    = (unsigned long)&s3c_fb_data_s5pv210,
+       }, {
+               .name           = "exynos4-fb",
+               .driver_data    = (unsigned long)&s3c_fb_data_exynos4,
        }, {
                .name           = "s3c2443-fb",
                .driver_data    = (unsigned long)&s3c_fb_data_s3c2443,
+       }, {
+               .name           = "s5p64x0-fb",
+               .driver_data    = (unsigned long)&s3c_fb_data_s5p64x0,
        },
        {},
 };
index 0aa1376..ee4c0df 100644 (file)
@@ -767,7 +767,6 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
 static int s3c2410fb_cpufreq_transition(struct notifier_block *nb,
                                        unsigned long val, void *data)
 {
-       struct cpufreq_freqs *freqs = data;
        struct s3c2410fb_info *info;
        struct fb_info *fbinfo;
        long delta_f;
@@ -911,7 +910,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
        for (i = 0; i < 256; i++)
                info->palette_buffer[i] = PALETTE_BUFF_CLEAR;
 
-       ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);
+       ret = request_irq(irq, s3c2410fb_irq, 0, pdev->name, info);
        if (ret) {
                dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
                ret = -EBUSY;
index 4ca5d0c..946a949 100644 (file)
@@ -1019,12 +1019,13 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
        unsigned int offset;
 
        /* Calculate the offset */
-       if (var->bits_per_pixel == 0) {
-               offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2);
+       if (info->var.bits_per_pixel == 0) {
+               offset = (var->yoffset / 16) * (info->var.xres_virtual / 2)
+                      + (var->xoffset / 2);
                offset = offset >> 2;
        } else {
                offset = (var->yoffset * info->fix.line_length) +
-                        (var->xoffset * var->bits_per_pixel / 8);
+                        (var->xoffset * info->var.bits_per_pixel / 8);
                offset = offset >> 2;
        }
 
@@ -1504,7 +1505,7 @@ static struct pci_driver s3fb_pci_driver = {
        .resume         = s3_pci_resume,
 };
 
-/* Parse user speficied options */
+/* Parse user specified options */
 
 #ifndef MODULE
 static int  __init s3fb_setup(char *options)
index e8b76d6..98d55d0 100644 (file)
@@ -1457,8 +1457,7 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
        if (ret)
                goto failed;
 
-       ret = request_irq(irq, sa1100fb_handle_irq, IRQF_DISABLED,
-                         "LCD", fbi);
+       ret = request_irq(irq, sa1100fb_handle_irq, 0, "LCD", fbi);
        if (ret) {
                printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
                goto failed;
index 4de541c..beb4950 100644 (file)
@@ -1477,15 +1477,9 @@ static void savagefb_set_par_int(struct savagefb_par  *par, struct savage_reg *r
        vgaHWProtect(par, 0);
 }
 
-static void savagefb_update_start(struct savagefb_par      *par,
-                                 struct fb_var_screeninfo *var)
+static void savagefb_update_start(struct savagefb_par *par, int base)
 {
-       int base;
-
-       base = ((var->yoffset * var->xres_virtual + (var->xoffset & ~1))
-               * ((var->bits_per_pixel+7) / 8)) >> 2;
-
-       /* now program the start address registers */
+       /* program the start address registers */
        vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par);
        vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par);
        vga_out8(0x3d4, 0x69, par);
@@ -1550,8 +1544,12 @@ static int savagefb_pan_display(struct fb_var_screeninfo *var,
                                struct fb_info           *info)
 {
        struct savagefb_par *par = info->par;
+       int base;
+
+       base = (var->yoffset * info->fix.line_length
+            + (var->xoffset & ~1) * ((info->var.bits_per_pixel+7) / 8)) >> 2;
 
-       savagefb_update_start(par, var);
+       savagefb_update_start(par, base);
        return 0;
 }
 
index 7d54e2c..647ba98 100644 (file)
@@ -1111,6 +1111,7 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate,
 static void sh_hdmi_edid_work_fn(struct work_struct *work)
 {
        struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work);
+       struct fb_info *info;
        struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
        struct sh_mobile_lcdc_chan *ch;
        int ret;
@@ -1123,8 +1124,9 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
 
        mutex_lock(&hdmi->mutex);
 
+       info = hdmi->info;
+
        if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
-               struct fb_info *info = hdmi->info;
                unsigned long parent_rate = 0, hdmi_rate;
 
                ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
@@ -1148,42 +1150,45 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
 
                ch = info->par;
 
-               console_lock();
+               if (lock_fb_info(info)) {
+                       console_lock();
 
-               /* HDMI plug in */
-               if (!sh_hdmi_must_reconfigure(hdmi) &&
-                   info->state == FBINFO_STATE_RUNNING) {
-                       /*
-                        * First activation with the default monitor - just turn
-                        * on, if we run a resume here, the logo disappears
-                        */
-                       if (lock_fb_info(info)) {
+                       /* HDMI plug in */
+                       if (!sh_hdmi_must_reconfigure(hdmi) &&
+                           info->state == FBINFO_STATE_RUNNING) {
+                               /*
+                                * First activation with the default monitor - just turn
+                                * on, if we run a resume here, the logo disappears
+                                */
                                info->var.width = hdmi->var.width;
                                info->var.height = hdmi->var.height;
                                sh_hdmi_display_on(hdmi, info);
-                               unlock_fb_info(info);
+                       } else {
+                               /* New monitor or have to wake up */
+                               fb_set_suspend(info, 0);
                        }
-               } else {
-                       /* New monitor or have to wake up */
-                       fb_set_suspend(info, 0);
-               }
 
-               console_unlock();
+                       console_unlock();
+                       unlock_fb_info(info);
+               }
        } else {
                ret = 0;
-               if (!hdmi->info)
+               if (!info)
                        goto out;
 
                hdmi->monspec.modedb_len = 0;
                fb_destroy_modedb(hdmi->monspec.modedb);
                hdmi->monspec.modedb = NULL;
 
-               console_lock();
+               if (lock_fb_info(info)) {
+                       console_lock();
 
-               /* HDMI disconnect */
-               fb_set_suspend(hdmi->info, 1);
+                       /* HDMI disconnect */
+                       fb_set_suspend(info, 1);
 
-               console_unlock();
+                       console_unlock();
+                       unlock_fb_info(info);
+               }
        }
 
 out:
index b048417..3a41c01 100644 (file)
 #include <linux/backlight.h>
 #include <linux/gpio.h>
 #include <video/sh_mobile_lcdc.h>
+#include <video/sh_mobile_meram.h>
 #include <linux/atomic.h>
 
 #include "sh_mobile_lcdcfb.h"
-#include "sh_mobile_meram.h"
 
 #define SIDE_B_OFFSET 0x1000
 #define MIRROR_OFFSET 0x2000
 
-/* shared registers */
-#define _LDDCKR 0x410
-#define _LDDCKSTPR 0x414
-#define _LDINTR 0x468
-#define _LDSR 0x46c
-#define _LDCNT1R 0x470
-#define _LDCNT2R 0x474
-#define _LDRCNTR 0x478
-#define _LDDDSR 0x47c
-#define _LDDWD0R 0x800
-#define _LDDRDR 0x840
-#define _LDDWAR 0x900
-#define _LDDRAR 0x904
-
-/* shared registers and their order for context save/restore */
-static int lcdc_shared_regs[] = {
-       _LDDCKR,
-       _LDDCKSTPR,
-       _LDINTR,
-       _LDDDSR,
-       _LDCNT1R,
-       _LDCNT2R,
-};
-#define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs)
-
 #define MAX_XRES 1920
 #define MAX_YRES 1080
 
@@ -98,22 +73,6 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
        [LDPMR] = 0x63c,
 };
 
-#define START_LCDC     0x00000001
-#define LCDC_RESET     0x00000100
-#define DISPLAY_BEU    0x00000008
-#define LCDC_ENABLE    0x00000001
-#define LDINTR_FE      0x00000400
-#define LDINTR_VSE     0x00000200
-#define LDINTR_VEE     0x00000100
-#define LDINTR_FS      0x00000004
-#define LDINTR_VSS     0x00000002
-#define LDINTR_VES     0x00000001
-#define LDRCNTR_SRS    0x00020000
-#define LDRCNTR_SRC    0x00010000
-#define LDRCNTR_MRS    0x00000002
-#define LDRCNTR_MRC    0x00000001
-#define LDSR_MRS       0x00000100
-
 static const struct fb_videomode default_720p = {
        .name = "HDMI 720p",
        .xres = 1280,
@@ -141,7 +100,6 @@ struct sh_mobile_lcdc_priv {
        unsigned long lddckr;
        struct sh_mobile_lcdc_chan ch[2];
        struct notifier_block notifier;
-       unsigned long saved_shared_regs[NR_SHARED_REGS];
        int started;
        int forced_bpp; /* 2 channel LCDC must share bpp setting */
        struct sh_mobile_meram_info *meram_dev;
@@ -218,33 +176,36 @@ static void lcdc_sys_write_index(void *handle, unsigned long data)
 {
        struct sh_mobile_lcdc_chan *ch = handle;
 
-       lcdc_write(ch->lcdc, _LDDWD0R, data | 0x10000000);
-       lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
-       lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
-       lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
+       lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT);
+       lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
+       lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
+                  (lcdc_chan_is_sublcd(ch) ? 2 : 0));
+       lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
 }
 
 static void lcdc_sys_write_data(void *handle, unsigned long data)
 {
        struct sh_mobile_lcdc_chan *ch = handle;
 
-       lcdc_write(ch->lcdc, _LDDWD0R, data | 0x11000000);
-       lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
-       lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
-       lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
+       lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT | LDDWDxR_RSW);
+       lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
+       lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
+                  (lcdc_chan_is_sublcd(ch) ? 2 : 0));
+       lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
 }
 
 static unsigned long lcdc_sys_read_data(void *handle)
 {
        struct sh_mobile_lcdc_chan *ch = handle;
 
-       lcdc_write(ch->lcdc, _LDDRDR, 0x01000000);
-       lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
-       lcdc_write(ch->lcdc, _LDDRAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
+       lcdc_write(ch->lcdc, _LDDRDR, LDDRDR_RSR);
+       lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
+       lcdc_write(ch->lcdc, _LDDRAR, LDDRAR_RA |
+                  (lcdc_chan_is_sublcd(ch) ? 2 : 0));
        udelay(1);
-       lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
+       lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
 
-       return lcdc_read(ch->lcdc, _LDDRDR) & 0x3ffff;
+       return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK;
 }
 
 struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
@@ -256,18 +217,22 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
 static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
 {
        if (atomic_inc_and_test(&priv->hw_usecnt)) {
-               pm_runtime_get_sync(priv->dev);
                if (priv->dot_clk)
                        clk_enable(priv->dot_clk);
+               pm_runtime_get_sync(priv->dev);
+               if (priv->meram_dev && priv->meram_dev->pdev)
+                       pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
        }
 }
 
 static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
 {
        if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
+               if (priv->meram_dev && priv->meram_dev->pdev)
+                       pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
+               pm_runtime_put(priv->dev);
                if (priv->dot_clk)
                        clk_disable(priv->dot_clk);
-               pm_runtime_put(priv->dev);
        }
 }
 
@@ -319,13 +284,13 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
                if (bcfg->start_transfer)
                        bcfg->start_transfer(bcfg->board_data, ch,
                                             &sh_mobile_lcdc_sys_bus_ops);
-               lcdc_write_chan(ch, LDSM2R, 1);
+               lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
                dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
        } else {
                if (bcfg->start_transfer)
                        bcfg->start_transfer(bcfg->board_data, ch,
                                             &sh_mobile_lcdc_sys_bus_ops);
-               lcdc_write_chan(ch, LDSM2R, 1);
+               lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
        }
 }
 
@@ -341,22 +306,16 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
 {
        struct sh_mobile_lcdc_priv *priv = data;
        struct sh_mobile_lcdc_chan *ch;
-       unsigned long tmp;
        unsigned long ldintr;
        int is_sub;
        int k;
 
-       /* acknowledge interrupt */
-       ldintr = tmp = lcdc_read(priv, _LDINTR);
-       /*
-        * disable further VSYNC End IRQs, preserve all other enabled IRQs,
-        * write 0 to bits 0-6 to ack all triggered IRQs.
-        */
-       tmp &= 0xffffff00 & ~LDINTR_VEE;
-       lcdc_write(priv, _LDINTR, tmp);
+       /* Acknowledge interrupts and disable further VSYNC End IRQs. */
+       ldintr = lcdc_read(priv, _LDINTR);
+       lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);
 
        /* figure out if this interrupt is for main or sub lcd */
-       is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0;
+       is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
 
        /* wake up channel and disable clocks */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
@@ -365,7 +324,7 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
                if (!ch->enabled)
                        continue;
 
-               /* Frame Start */
+               /* Frame End */
                if (ldintr & LDINTR_FS) {
                        if (is_sub == lcdc_chan_is_sublcd(ch)) {
                                ch->frame_end = 1;
@@ -391,16 +350,17 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
 
        /* start or stop the lcdc */
        if (start)
-               lcdc_write(priv, _LDCNT2R, tmp | START_LCDC);
+               lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO);
        else
-               lcdc_write(priv, _LDCNT2R, tmp & ~START_LCDC);
+               lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO);
 
        /* wait until power is applied/stopped on all channels */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
                if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)
                        while (1) {
-                               tmp = lcdc_read_chan(&priv->ch[k], LDPMR) & 3;
-                               if (start && tmp == 3)
+                               tmp = lcdc_read_chan(&priv->ch[k], LDPMR)
+                                   & LDPMR_LPS;
+                               if (start && tmp == LDPMR_LPS)
                                        break;
                                if (!start && tmp == 0)
                                        break;
@@ -418,13 +378,13 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
        u32 tmp;
 
        tmp = ch->ldmt1r_value;
-       tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28;
-       tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27;
-       tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0;
-       tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0;
-       tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0;
-       tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0;
-       tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0;
+       tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;
+       tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;
+       tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
+       tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
+       tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
+       tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
+       tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
        lcdc_write_chan(ch, LDMT1R, tmp);
 
        /* setup SYS bus */
@@ -463,242 +423,239 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
        lcdc_write_chan(ch, LDHAJR, tmp);
 }
 
-static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
+/*
+ * __sh_mobile_lcdc_start - Configure and tart the LCDC
+ * @priv: LCDC device
+ *
+ * Configure all enabled channels and start the LCDC device. All external
+ * devices (clocks, MERAM, panels, ...) are not touched by this function.
+ */
+static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 {
        struct sh_mobile_lcdc_chan *ch;
-       struct sh_mobile_lcdc_board_cfg *board_cfg;
        unsigned long tmp;
        int bpp = 0;
-       unsigned long ldddsr;
-       int k, m, ret;
+       int k, m;
 
-       /* enable clocks before accessing the hardware */
-       for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
-               if (priv->ch[k].enabled) {
-                       sh_mobile_lcdc_clk_on(priv);
-                       if (!bpp)
-                               bpp = priv->ch[k].info->var.bits_per_pixel;
-               }
-       }
-
-       /* reset */
-       lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET);
-       lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0);
-
-       /* enable LCDC channels */
-       tmp = lcdc_read(priv, _LDCNT2R);
-       tmp |= priv->ch[0].enabled;
-       tmp |= priv->ch[1].enabled;
-       lcdc_write(priv, _LDCNT2R, tmp);
-
-       /* read data from external memory, avoid using the BEU for now */
-       lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU);
+       /* Enable LCDC channels. Read data from external memory, avoid using the
+        * BEU for now.
+        */
+       lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled);
 
-       /* stop the lcdc first */
+       /* Stop the LCDC first and disable all interrupts. */
        sh_mobile_lcdc_start_stop(priv, 0);
+       lcdc_write(priv, _LDINTR, 0);
 
-       /* configure clocks */
+       /* Configure power supply, dot clocks and start them. */
        tmp = priv->lddckr;
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
                ch = &priv->ch[k];
-
-               if (!priv->ch[k].enabled)
+               if (!ch->enabled)
                        continue;
 
+               if (!bpp)
+                       bpp = ch->info->var.bits_per_pixel;
+
+               /* Power supply */
+               lcdc_write_chan(ch, LDPMR, 0);
+
                m = ch->cfg.clock_divider;
                if (!m)
                        continue;
 
-               if (m == 1)
-                       m = 1 << 6;
-               tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
-
-               /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */
+               /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
+                * denominator.
+                */
                lcdc_write_chan(ch, LDDCKPAT1R, 0);
                lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);
+
+               if (m == 1)
+                       m = LDDCKR_MOSEL;
+               tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
        }
 
        lcdc_write(priv, _LDDCKR, tmp);
-
-       /* start dotclock again */
        lcdc_write(priv, _LDDCKSTPR, 0);
        lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
 
-       /* interrupts are disabled to begin with */
-       lcdc_write(priv, _LDINTR, 0);
-
+       /* Setup geometry, format, frame buffer memory and operation mode. */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
                ch = &priv->ch[k];
-
                if (!ch->enabled)
                        continue;
 
                sh_mobile_lcdc_geometry(ch);
 
-               /* power supply */
-               lcdc_write_chan(ch, LDPMR, 0);
-
-               board_cfg = &ch->cfg.board_cfg;
-               if (board_cfg->setup_sys) {
-                       ret = board_cfg->setup_sys(board_cfg->board_data,
-                                               ch, &sh_mobile_lcdc_sys_bus_ops);
-                       if (ret)
-                               return ret;
-               }
-       }
-
-       /* word and long word swap */
-       ldddsr = lcdc_read(priv, _LDDDSR);
-       if  (priv->ch[0].info->var.nonstd)
-               lcdc_write(priv, _LDDDSR, ldddsr | 7);
-       else {
-               switch (bpp) {
-               case 16:
-                       lcdc_write(priv, _LDDDSR, ldddsr | 6);
-                       break;
-               case 24:
-                       lcdc_write(priv, _LDDDSR, ldddsr | 7);
-                       break;
-               case 32:
-                       lcdc_write(priv, _LDDDSR, ldddsr | 4);
-                       break;
-               }
-       }
-
-       for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
-               unsigned long base_addr_y;
-               unsigned long base_addr_c = 0;
-               int pitch;
-               ch = &priv->ch[k];
-
-               if (!priv->ch[k].enabled)
-                       continue;
-
-               /* set bpp format in PKF[4:0] */
-               tmp = lcdc_read_chan(ch, LDDFR);
-               tmp &= ~0x0003031f;
                if (ch->info->var.nonstd) {
-                       tmp |= (ch->info->var.nonstd << 16);
+                       tmp = (ch->info->var.nonstd << 16);
                        switch (ch->info->var.bits_per_pixel) {
                        case 12:
+                               tmp |= LDDFR_YF_420;
                                break;
                        case 16:
-                               tmp |= (0x1 << 8);
+                               tmp |= LDDFR_YF_422;
                                break;
                        case 24:
-                               tmp |= (0x2 << 8);
+                       default:
+                               tmp |= LDDFR_YF_444;
                                break;
                        }
                } else {
                        switch (ch->info->var.bits_per_pixel) {
                        case 16:
-                               tmp |= 0x03;
+                               tmp = LDDFR_PKF_RGB16;
                                break;
                        case 24:
-                               tmp |= 0x0b;
+                               tmp = LDDFR_PKF_RGB24;
                                break;
                        case 32:
+                       default:
+                               tmp = LDDFR_PKF_ARGB32;
                                break;
                        }
                }
+
                lcdc_write_chan(ch, LDDFR, tmp);
+               lcdc_write_chan(ch, LDMLSR, ch->pitch);
+               lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
+               if (ch->info->var.nonstd)
+                       lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
 
-               base_addr_y = ch->info->fix.smem_start;
-               base_addr_c = base_addr_y +
-                               ch->info->var.xres *
-                               ch->info->var.yres_virtual;
-               pitch = ch->info->fix.line_length;
+               /* When using deferred I/O mode, configure the LCDC for one-shot
+                * operation and enable the frame end interrupt. Otherwise use
+                * continuous read mode.
+                */
+               if (ch->ldmt1r_value & LDMT1R_IFM &&
+                   ch->cfg.sys_bus_cfg.deferred_io_msec) {
+                       lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
+                       lcdc_write(priv, _LDINTR, LDINTR_FE);
+               } else {
+                       lcdc_write_chan(ch, LDSM1R, 0);
+               }
+       }
 
-               /* test if we can enable meram */
-               if (ch->cfg.meram_cfg && priv->meram_dev &&
-                               priv->meram_dev->ops) {
-                       struct sh_mobile_meram_cfg *cfg;
-                       struct sh_mobile_meram_info *mdev;
-                       unsigned long icb_addr_y, icb_addr_c;
-                       int icb_pitch;
-                       int pf;
+       /* Word and long word swap. */
+       if  (priv->ch[0].info->var.nonstd)
+               tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
+       else {
+               switch (bpp) {
+               case 16:
+                       tmp = LDDDSR_LS | LDDDSR_WS;
+                       break;
+               case 24:
+                       tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
+                       break;
+               case 32:
+               default:
+                       tmp = LDDDSR_LS;
+                       break;
+               }
+       }
+       lcdc_write(priv, _LDDDSR, tmp);
 
-                       cfg = ch->cfg.meram_cfg;
-                       mdev = priv->meram_dev;
-                       /* we need to de-init configured ICBs before we
-                        * we can re-initialize them.
-                        */
-                       if (ch->meram_enabled)
-                               mdev->ops->meram_unregister(mdev, cfg);
+       /* Enable the display output. */
+       lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
+       sh_mobile_lcdc_start_stop(priv, 1);
+       priv->started = 1;
+}
 
-                       ch->meram_enabled = 0;
+static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
+{
+       struct sh_mobile_meram_info *mdev = priv->meram_dev;
+       struct sh_mobile_lcdc_board_cfg *board_cfg;
+       struct sh_mobile_lcdc_chan *ch;
+       unsigned long tmp;
+       int ret;
+       int k;
 
-                       if (ch->info->var.nonstd) {
-                               if (ch->info->var.bits_per_pixel == 24)
-                                       pf = SH_MOBILE_MERAM_PF_NV24;
-                               else
-                                       pf = SH_MOBILE_MERAM_PF_NV;
-                       } else {
-                               pf = SH_MOBILE_MERAM_PF_RGB;
-                       }
+       /* enable clocks before accessing the hardware */
+       for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+               if (priv->ch[k].enabled)
+                       sh_mobile_lcdc_clk_on(priv);
+       }
 
-                       ret = mdev->ops->meram_register(mdev, cfg, pitch,
-                                               ch->info->var.yres,
-                                               pf,
-                                               base_addr_y,
-                                               base_addr_c,
-                                               &icb_addr_y,
-                                               &icb_addr_c,
-                                               &icb_pitch);
-                       if (!ret)  {
-                               /* set LDSA1R value */
-                               base_addr_y = icb_addr_y;
-                               pitch = icb_pitch;
-
-                               /* set LDSA2R value if required */
-                               if (base_addr_c)
-                                       base_addr_c = icb_addr_c;
-
-                               ch->meram_enabled = 1;
-                       }
-               }
+       /* reset */
+       lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR);
+       lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
 
-               /* point out our frame buffer */
-               lcdc_write_chan(ch, LDSA1R, base_addr_y);
-               if (ch->info->var.nonstd)
-                       lcdc_write_chan(ch, LDSA2R, base_addr_c);
+       for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+               ch = &priv->ch[k];
 
-               /* set line size */
-               lcdc_write_chan(ch, LDMLSR, pitch);
+               if (!ch->enabled)
+                       continue;
 
-               /* setup deferred io if SYS bus */
-               tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
-               if (ch->ldmt1r_value & (1 << 12) && tmp) {
-                       ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
-                       ch->defio.delay = msecs_to_jiffies(tmp);
-                       ch->info->fbdefio = &ch->defio;
-                       fb_deferred_io_init(ch->info);
+               board_cfg = &ch->cfg.board_cfg;
+               if (board_cfg->setup_sys) {
+                       ret = board_cfg->setup_sys(board_cfg->board_data, ch,
+                                                  &sh_mobile_lcdc_sys_bus_ops);
+                       if (ret)
+                               return ret;
+               }
+       }
 
-                       /* one-shot mode */
-                       lcdc_write_chan(ch, LDSM1R, 1);
+       /* Compute frame buffer base address and pitch for each channel. */
+       for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+               struct sh_mobile_meram_cfg *cfg;
+               int pixelformat;
 
-                       /* enable "Frame End Interrupt Enable" bit */
-                       lcdc_write(priv, _LDINTR, LDINTR_FE);
+               ch = &priv->ch[k];
+               if (!ch->enabled)
+                       continue;
 
-               } else {
-                       /* continuous read mode */
-                       lcdc_write_chan(ch, LDSM1R, 0);
+               ch->base_addr_y = ch->info->fix.smem_start;
+               ch->base_addr_c = ch->base_addr_y
+                               + ch->info->var.xres
+                               * ch->info->var.yres_virtual;
+               ch->pitch = ch->info->fix.line_length;
+
+               /* Enable MERAM if possible. */
+               cfg = ch->cfg.meram_cfg;
+               if (mdev == NULL || mdev->ops == NULL || cfg == NULL)
+                       continue;
+
+               /* we need to de-init configured ICBs before we can
+                * re-initialize them.
+                */
+               if (ch->meram_enabled) {
+                       mdev->ops->meram_unregister(mdev, cfg);
+                       ch->meram_enabled = 0;
                }
+
+               if (!ch->info->var.nonstd)
+                       pixelformat = SH_MOBILE_MERAM_PF_RGB;
+               else if (ch->info->var.bits_per_pixel == 24)
+                       pixelformat = SH_MOBILE_MERAM_PF_NV24;
+               else
+                       pixelformat = SH_MOBILE_MERAM_PF_NV;
+
+               ret = mdev->ops->meram_register(mdev, cfg, ch->pitch,
+                                       ch->info->var.yres, pixelformat,
+                                       ch->base_addr_y, ch->base_addr_c,
+                                       &ch->base_addr_y, &ch->base_addr_c,
+                                       &ch->pitch);
+               if (!ret)
+                       ch->meram_enabled = 1;
        }
 
-       /* display output */
-       lcdc_write(priv, _LDCNT1R, LCDC_ENABLE);
+       /* Start the LCDC. */
+       __sh_mobile_lcdc_start(priv);
 
-       /* start the lcdc */
-       sh_mobile_lcdc_start_stop(priv, 1);
-       priv->started = 1;
-
-       /* tell the board code to enable the panel */
+       /* Setup deferred I/O, tell the board code to enable the panels, and
+        * turn backlight on.
+        */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
                ch = &priv->ch[k];
                if (!ch->enabled)
                        continue;
 
+               tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
+               if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {
+                       ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
+                       ch->defio.delay = msecs_to_jiffies(tmp);
+                       ch->info->fbdefio = &ch->defio;
+                       fb_deferred_io_init(ch->info);
+               }
+
                board_cfg = &ch->cfg.board_cfg;
                if (board_cfg->display_on && try_module_get(board_cfg->owner)) {
                        board_cfg->display_on(board_cfg->board_data, ch->info);
@@ -776,42 +733,42 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
 
 static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
 {
-       int ifm, miftyp;
-
-       switch (ch->cfg.interface_type) {
-       case RGB8: ifm = 0; miftyp = 0; break;
-       case RGB9: ifm = 0; miftyp = 4; break;
-       case RGB12A: ifm = 0; miftyp = 5; break;
-       case RGB12B: ifm = 0; miftyp = 6; break;
-       case RGB16: ifm = 0; miftyp = 7; break;
-       case RGB18: ifm = 0; miftyp = 10; break;
-       case RGB24: ifm = 0; miftyp = 11; break;
-       case SYS8A: ifm = 1; miftyp = 0; break;
-       case SYS8B: ifm = 1; miftyp = 1; break;
-       case SYS8C: ifm = 1; miftyp = 2; break;
-       case SYS8D: ifm = 1; miftyp = 3; break;
-       case SYS9: ifm = 1; miftyp = 4; break;
-       case SYS12: ifm = 1; miftyp = 5; break;
-       case SYS16A: ifm = 1; miftyp = 7; break;
-       case SYS16B: ifm = 1; miftyp = 8; break;
-       case SYS16C: ifm = 1; miftyp = 9; break;
-       case SYS18: ifm = 1; miftyp = 10; break;
-       case SYS24: ifm = 1; miftyp = 11; break;
-       default: goto bad;
+       int interface_type = ch->cfg.interface_type;
+
+       switch (interface_type) {
+       case RGB8:
+       case RGB9:
+       case RGB12A:
+       case RGB12B:
+       case RGB16:
+       case RGB18:
+       case RGB24:
+       case SYS8A:
+       case SYS8B:
+       case SYS8C:
+       case SYS8D:
+       case SYS9:
+       case SYS12:
+       case SYS16A:
+       case SYS16B:
+       case SYS16C:
+       case SYS18:
+       case SYS24:
+               break;
+       default:
+               return -EINVAL;
        }
 
        /* SUBLCD only supports SYS interface */
        if (lcdc_chan_is_sublcd(ch)) {
-               if (ifm == 0)
-                       goto bad;
-               else
-                       ifm = 0;
+               if (!(interface_type & LDMT1R_IFM))
+                       return -EINVAL;
+
+               interface_type &= ~LDMT1R_IFM;
        }
 
-       ch->ldmt1r_value = (ifm << 12) | miftyp;
+       ch->ldmt1r_value = interface_type;
        return 0;
- bad:
-       return -EINVAL;
 }
 
 static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
@@ -819,18 +776,24 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
                                       struct sh_mobile_lcdc_priv *priv)
 {
        char *str;
-       int icksel;
 
        switch (clock_source) {
-       case LCDC_CLK_BUS: str = "bus_clk"; icksel = 0; break;
-       case LCDC_CLK_PERIPHERAL: str = "peripheral_clk"; icksel = 1; break;
-       case LCDC_CLK_EXTERNAL: str = NULL; icksel = 2; break;
+       case LCDC_CLK_BUS:
+               str = "bus_clk";
+               priv->lddckr = LDDCKR_ICKSEL_BUS;
+               break;
+       case LCDC_CLK_PERIPHERAL:
+               str = "peripheral_clk";
+               priv->lddckr = LDDCKR_ICKSEL_MIPI;
+               break;
+       case LCDC_CLK_EXTERNAL:
+               str = NULL;
+               priv->lddckr = LDDCKR_ICKSEL_HDMI;
+               break;
        default:
                return -EINVAL;
        }
 
-       priv->lddckr = icksel << 16;
-
        if (str) {
                priv->dot_clk = clk_get(&pdev->dev, str);
                if (IS_ERR(priv->dot_clk)) {
@@ -914,12 +877,12 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
        unsigned long base_addr_y, base_addr_c;
        unsigned long c_offset;
 
-       if (!var->nonstd)
-               new_pan_offset = (var->yoffset * info->fix.line_length) +
-                       (var->xoffset * (info->var.bits_per_pixel / 8));
+       if (!info->var.nonstd)
+               new_pan_offset = var->yoffset * info->fix.line_length
+                              + var->xoffset * (info->var.bits_per_pixel / 8);
        else
-               new_pan_offset = (var->yoffset * info->fix.line_length) +
-                       (var->xoffset);
+               new_pan_offset = var->yoffset * info->fix.line_length
+                              + var->xoffset;
 
        if (new_pan_offset == ch->pan_offset)
                return 0;       /* No change, do nothing */
@@ -928,44 +891,40 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
 
        /* Set the source address for the next refresh */
        base_addr_y = ch->dma_handle + new_pan_offset;
-       if (var->nonstd) {
+       if (info->var.nonstd) {
                /* Set y offset */
-               c_offset = (var->yoffset *
-                       info->fix.line_length *
-                       (info->var.bits_per_pixel - 8)) / 8;
-               base_addr_c = ch->dma_handle + var->xres * var->yres_virtual +
-                       c_offset;
+               c_offset = var->yoffset * info->fix.line_length
+                        * (info->var.bits_per_pixel - 8) / 8;
+               base_addr_c = ch->dma_handle
+                           + info->var.xres * info->var.yres_virtual
+                           + c_offset;
                /* Set x offset */
                if (info->var.bits_per_pixel == 24)
                        base_addr_c += 2 * var->xoffset;
                else
                        base_addr_c += var->xoffset;
-       } else
-               base_addr_c = 0;
+       }
 
-       if (!ch->meram_enabled) {
-               lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
-               if (base_addr_c)
-                       lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
-       } else {
+       if (ch->meram_enabled) {
                struct sh_mobile_meram_cfg *cfg;
                struct sh_mobile_meram_info *mdev;
-               unsigned long icb_addr_y, icb_addr_c;
                int ret;
 
                cfg = ch->cfg.meram_cfg;
                mdev = priv->meram_dev;
                ret = mdev->ops->meram_update(mdev, cfg,
                                        base_addr_y, base_addr_c,
-                                       &icb_addr_y, &icb_addr_c);
+                                       &base_addr_y, &base_addr_c);
                if (ret)
                        return ret;
+       }
 
-               lcdc_write_chan_mirror(ch, LDSA1R, icb_addr_y);
-               if (icb_addr_c)
-                       lcdc_write_chan_mirror(ch, LDSA2R, icb_addr_c);
+       ch->base_addr_y = base_addr_y;
+       ch->base_addr_c = base_addr_c;
 
-       }
+       lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
+       if (info->var.nonstd)
+               lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
 
        if (lcdc_chan_is_sublcd(ch))
                lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
@@ -985,9 +944,11 @@ static int sh_mobile_wait_for_vsync(struct fb_info *info)
        unsigned long ldintr;
        int ret;
 
-       /* Enable VSync End interrupt */
+       /* Enable VSync End interrupt and be careful not to acknowledge any
+        * pending interrupt.
+        */
        ldintr = lcdc_read(ch->lcdc, _LDINTR);
-       ldintr |= LDINTR_VEE;
+       ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
        lcdc_write(ch->lcdc, _LDINTR, ldintr);
 
        ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
@@ -1037,11 +998,6 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
                /* Couldn't reconfigure, hopefully, can continue as before */
                return;
 
-       if (info->var.nonstd)
-               info->fix.line_length = mode1.xres;
-       else
-               info->fix.line_length = mode1.xres * (ch->cfg.bpp / 8);
-
        /*
         * fb_set_var() calls the notifier change internally, only if
         * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
@@ -1094,30 +1050,126 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
 {
        struct sh_mobile_lcdc_chan *ch = info->par;
        struct sh_mobile_lcdc_priv *p = ch->lcdc;
+       unsigned int best_dist = (unsigned int)-1;
+       unsigned int best_xres = 0;
+       unsigned int best_yres = 0;
+       unsigned int i;
 
-       if (var->xres > MAX_XRES || var->yres > MAX_YRES ||
-           var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) {
-               dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %lukHz!\n",
-                        var->left_margin, var->xres, var->right_margin, var->hsync_len,
-                        var->upper_margin, var->yres, var->lower_margin, var->vsync_len,
-                        PICOS2KHZ(var->pixclock));
+       if (var->xres > MAX_XRES || var->yres > MAX_YRES)
                return -EINVAL;
+
+       /* If board code provides us with a list of available modes, make sure
+        * we use one of them. Find the mode closest to the requested one. The
+        * distance between two modes is defined as the size of the
+        * non-overlapping parts of the two rectangles.
+        */
+       for (i = 0; i < ch->cfg.num_cfg; ++i) {
+               const struct fb_videomode *mode = &ch->cfg.lcd_cfg[i];
+               unsigned int dist;
+
+               /* We can only round up. */
+               if (var->xres > mode->xres || var->yres > mode->yres)
+                       continue;
+
+               dist = var->xres * var->yres + mode->xres * mode->yres
+                    - 2 * min(var->xres, mode->xres)
+                        * min(var->yres, mode->yres);
+
+               if (dist < best_dist) {
+                       best_xres = mode->xres;
+                       best_yres = mode->yres;
+                       best_dist = dist;
+               }
+       }
+
+       /* If no available mode can be used, return an error. */
+       if (ch->cfg.num_cfg != 0) {
+               if (best_dist == (unsigned int)-1)
+                       return -EINVAL;
+
+               var->xres = best_xres;
+               var->yres = best_yres;
        }
 
+       /* Make sure the virtual resolution is at least as big as the visible
+        * resolution.
+        */
+       if (var->xres_virtual < var->xres)
+               var->xres_virtual = var->xres;
+       if (var->yres_virtual < var->yres)
+               var->yres_virtual = var->yres;
+
+       if (var->bits_per_pixel <= 16) {                /* RGB 565 */
+               var->bits_per_pixel = 16;
+               var->red.offset = 11;
+               var->red.length = 5;
+               var->green.offset = 5;
+               var->green.length = 6;
+               var->blue.offset = 0;
+               var->blue.length = 5;
+               var->transp.offset = 0;
+               var->transp.length = 0;
+       } else if (var->bits_per_pixel <= 24) {         /* RGB 888 */
+               var->bits_per_pixel = 24;
+               var->red.offset = 16;
+               var->red.length = 8;
+               var->green.offset = 8;
+               var->green.length = 8;
+               var->blue.offset = 0;
+               var->blue.length = 8;
+               var->transp.offset = 0;
+               var->transp.length = 0;
+       } else if (var->bits_per_pixel <= 32) {         /* RGBA 888 */
+               var->bits_per_pixel = 32;
+               var->red.offset = 16;
+               var->red.length = 8;
+               var->green.offset = 8;
+               var->green.length = 8;
+               var->blue.offset = 0;
+               var->blue.length = 8;
+               var->transp.offset = 24;
+               var->transp.length = 8;
+       } else
+               return -EINVAL;
+
+       var->red.msb_right = 0;
+       var->green.msb_right = 0;
+       var->blue.msb_right = 0;
+       var->transp.msb_right = 0;
+
+       /* Make sure we don't exceed our allocated memory. */
+       if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
+           info->fix.smem_len)
+               return -EINVAL;
+
        /* only accept the forced_bpp for dual channel configurations */
        if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel)
                return -EINVAL;
 
-       switch (var->bits_per_pixel) {
-       case 16: /* PKF[4:0] = 00011 - RGB 565 */
-       case 24: /* PKF[4:0] = 01011 - RGB 888 */
-       case 32: /* PKF[4:0] = 00000 - RGBA 888 */
-               break;
-       default:
-               return -EINVAL;
+       return 0;
+}
+
+static int sh_mobile_set_par(struct fb_info *info)
+{
+       struct sh_mobile_lcdc_chan *ch = info->par;
+       u32 line_length = info->fix.line_length;
+       int ret;
+
+       sh_mobile_lcdc_stop(ch->lcdc);
+
+       if (info->var.nonstd)
+               info->fix.line_length = info->var.xres;
+       else
+               info->fix.line_length = info->var.xres
+                                     * info->var.bits_per_pixel / 8;
+
+       ret = sh_mobile_lcdc_start(ch->lcdc);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
+               info->fix.line_length = line_length;
        }
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -1177,6 +1229,7 @@ static struct fb_ops sh_mobile_lcdc_ops = {
        .fb_open        = sh_mobile_open,
        .fb_release     = sh_mobile_release,
        .fb_check_var   = sh_mobile_check_var,
+       .fb_set_par     = sh_mobile_set_par,
 };
 
 static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
@@ -1238,66 +1291,6 @@ static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
        backlight_device_unregister(bdev);
 }
 
-static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp,
-                                  int nonstd)
-{
-       if (nonstd) {
-               switch (bpp) {
-               case 12:
-               case 16:
-               case 24:
-                       var->bits_per_pixel = bpp;
-                       var->nonstd = nonstd;
-                       return 0;
-               default:
-                       return -EINVAL;
-               }
-       }
-
-       switch (bpp) {
-       case 16: /* PKF[4:0] = 00011 - RGB 565 */
-               var->red.offset = 11;
-               var->red.length = 5;
-               var->green.offset = 5;
-               var->green.length = 6;
-               var->blue.offset = 0;
-               var->blue.length = 5;
-               var->transp.offset = 0;
-               var->transp.length = 0;
-               break;
-
-       case 24: /* PKF[4:0] = 01011 - RGB 888 */
-               var->red.offset = 16;
-               var->red.length = 8;
-               var->green.offset = 8;
-               var->green.length = 8;
-               var->blue.offset = 0;
-               var->blue.length = 8;
-               var->transp.offset = 0;
-               var->transp.length = 0;
-               break;
-
-       case 32: /* PKF[4:0] = 00000 - RGBA 888 */
-               var->red.offset = 16;
-               var->red.length = 8;
-               var->green.offset = 8;
-               var->green.length = 8;
-               var->blue.offset = 0;
-               var->blue.length = 8;
-               var->transp.offset = 24;
-               var->transp.length = 8;
-               break;
-       default:
-               return -EINVAL;
-       }
-       var->bits_per_pixel = bpp;
-       var->red.msb_right = 0;
-       var->green.msb_right = 0;
-       var->blue.msb_right = 0;
-       var->transp.msb_right = 0;
-       return 0;
-}
-
 static int sh_mobile_lcdc_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -1316,47 +1309,20 @@ static int sh_mobile_lcdc_resume(struct device *dev)
 static int sh_mobile_lcdc_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev);
-       struct sh_mobile_lcdc_chan *ch;
-       int k, n;
-
-       /* save per-channel registers */
-       for (k = 0; k < ARRAY_SIZE(p->ch); k++) {
-               ch = &p->ch[k];
-               if (!ch->enabled)
-                       continue;
-               for (n = 0; n < NR_CH_REGS; n++)
-                       ch->saved_ch_regs[n] = lcdc_read_chan(ch, n);
-       }
-
-       /* save shared registers */
-       for (n = 0; n < NR_SHARED_REGS; n++)
-               p->saved_shared_regs[n] = lcdc_read(p, lcdc_shared_regs[n]);
+       struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
 
        /* turn off LCDC hardware */
-       lcdc_write(p, _LDCNT1R, 0);
+       lcdc_write(priv, _LDCNT1R, 0);
+
        return 0;
 }
 
 static int sh_mobile_lcdc_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev);
-       struct sh_mobile_lcdc_chan *ch;
-       int k, n;
-
-       /* restore per-channel registers */
-       for (k = 0; k < ARRAY_SIZE(p->ch); k++) {
-               ch = &p->ch[k];
-               if (!ch->enabled)
-                       continue;
-               for (n = 0; n < NR_CH_REGS; n++)
-                       lcdc_write_chan(ch, n, ch->saved_ch_regs[n]);
-       }
+       struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
 
-       /* restore shared registers */
-       for (n = 0; n < NR_SHARED_REGS; n++)
-               lcdc_write(p, lcdc_shared_regs[n], p->saved_shared_regs[n]);
+       __sh_mobile_lcdc_start(priv);
 
        return 0;
 }
@@ -1408,17 +1374,187 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
        return NOTIFY_OK;
 }
 
-static int sh_mobile_lcdc_remove(struct platform_device *pdev);
+static int sh_mobile_lcdc_remove(struct platform_device *pdev)
+{
+       struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
+       struct fb_info *info;
+       int i;
 
-static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
+       fb_unregister_client(&priv->notifier);
+
+       for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
+               if (priv->ch[i].info && priv->ch[i].info->dev)
+                       unregister_framebuffer(priv->ch[i].info);
+
+       sh_mobile_lcdc_stop(priv);
+
+       for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
+               info = priv->ch[i].info;
+
+               if (!info || !info->device)
+                       continue;
+
+               if (priv->ch[i].sglist)
+                       vfree(priv->ch[i].sglist);
+
+               if (info->screen_base)
+                       dma_free_coherent(&pdev->dev, info->fix.smem_len,
+                                         info->screen_base,
+                                         priv->ch[i].dma_handle);
+               fb_dealloc_cmap(&info->cmap);
+               framebuffer_release(info);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
+               if (priv->ch[i].bl)
+                       sh_mobile_lcdc_bl_remove(priv->ch[i].bl);
+       }
+
+       if (priv->dot_clk)
+               clk_put(priv->dot_clk);
+
+       if (priv->dev)
+               pm_runtime_disable(priv->dev);
+
+       if (priv->base)
+               iounmap(priv->base);
+
+       if (priv->irq)
+               free_irq(priv->irq, priv);
+       kfree(priv);
+       return 0;
+}
+
+static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
+                                                struct device *dev)
 {
+       struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
+       const struct fb_videomode *max_mode;
+       const struct fb_videomode *mode;
+       struct fb_var_screeninfo *var;
        struct fb_info *info;
-       struct sh_mobile_lcdc_priv *priv;
+       unsigned int max_size;
+       int num_cfg;
+       void *buf;
+       int ret;
+       int i;
+
+       mutex_init(&ch->open_lock);
+
+       /* Allocate the frame buffer device. */
+       ch->info = framebuffer_alloc(0, dev);
+       if (!ch->info) {
+               dev_err(dev, "unable to allocate fb_info\n");
+               return -ENOMEM;
+       }
+
+       info = ch->info;
+       info->fbops = &sh_mobile_lcdc_ops;
+       info->par = ch;
+       info->pseudo_palette = &ch->pseudo_palette;
+       info->flags = FBINFO_FLAG_DEFAULT;
+
+       /* Iterate through the modes to validate them and find the highest
+        * resolution.
+        */
+       max_mode = NULL;
+       max_size = 0;
+
+       for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) {
+               unsigned int size = mode->yres * mode->xres;
+
+               /* NV12 buffers must have even number of lines */
+               if ((cfg->nonstd) && cfg->bpp == 12 &&
+                               (mode->yres & 0x1)) {
+                       dev_err(dev, "yres must be multiple of 2 for YCbCr420 "
+                               "mode.\n");
+                       return -EINVAL;
+               }
+
+               if (size > max_size) {
+                       max_mode = mode;
+                       max_size = size;
+               }
+       }
+
+       if (!max_size)
+               max_size = MAX_XRES * MAX_YRES;
+       else
+               dev_dbg(dev, "Found largest videomode %ux%u\n",
+                       max_mode->xres, max_mode->yres);
+
+       /* Initialize fixed screen information. Restrict pan to 2 lines steps
+        * for NV12.
+        */
+       info->fix = sh_mobile_lcdc_fix;
+       info->fix.smem_len = max_size * 2 * cfg->bpp / 8;
+       if (cfg->nonstd && cfg->bpp == 12)
+               info->fix.ypanstep = 2;
+
+       /* Create the mode list. */
+       if (cfg->lcd_cfg == NULL) {
+               mode = &default_720p;
+               num_cfg = 1;
+       } else {
+               mode = cfg->lcd_cfg;
+               num_cfg = cfg->num_cfg;
+       }
+
+       fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
+
+       /* Initialize variable screen information using the first mode as
+        * default. The default Y virtual resolution is twice the panel size to
+        * allow for double-buffering.
+        */
+       var = &info->var;
+       fb_videomode_to_var(var, mode);
+       var->bits_per_pixel = cfg->bpp;
+       var->width = cfg->lcd_size_cfg.width;
+       var->height = cfg->lcd_size_cfg.height;
+       var->yres_virtual = var->yres * 2;
+       var->activate = FB_ACTIVATE_NOW;
+
+       ret = sh_mobile_check_var(var, info);
+       if (ret)
+               return ret;
+
+       /* Allocate frame buffer memory and color map. */
+       buf = dma_alloc_coherent(dev, info->fix.smem_len, &ch->dma_handle,
+                                GFP_KERNEL);
+       if (!buf) {
+               dev_err(dev, "unable to allocate buffer\n");
+               return -ENOMEM;
+       }
+
+       ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
+       if (ret < 0) {
+               dev_err(dev, "unable to allocate cmap\n");
+               dma_free_coherent(dev, info->fix.smem_len,
+                                 buf, ch->dma_handle);
+               return ret;
+       }
+
+       info->fix.smem_start = ch->dma_handle;
+       if (var->nonstd)
+               info->fix.line_length = var->xres;
+       else
+               info->fix.line_length = var->xres * (cfg->bpp / 8);
+
+       info->screen_base = buf;
+       info->device = dev;
+       ch->display_var = *var;
+
+       return 0;
+}
+
+static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
+{
        struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
+       struct sh_mobile_lcdc_priv *priv;
        struct resource *res;
+       int num_channels;
        int error;
-       void *buf;
-       int i, j;
+       int i;
 
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data defined\n");
@@ -1440,7 +1576,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, priv);
 
-       error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED,
+       error = request_irq(i, sh_mobile_lcdc_irq, 0,
                            dev_name(&pdev->dev), priv);
        if (error) {
                dev_err(&pdev->dev, "unable to request irq\n");
@@ -1450,9 +1586,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
        priv->irq = i;
        atomic_set(&priv->hw_usecnt, -1);
 
-       j = 0;
-       for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) {
-               struct sh_mobile_lcdc_chan *ch = priv->ch + j;
+       for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {
+               struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
 
                ch->lcdc = priv;
                memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i]));
@@ -1472,26 +1607,26 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 
                switch (pdata->ch[i].chan) {
                case LCDC_CHAN_MAINLCD:
-                       ch->enabled = 1 << 1;
+                       ch->enabled = LDCNT2R_ME;
                        ch->reg_offs = lcdc_offs_mainlcd;
-                       j++;
+                       num_channels++;
                        break;
                case LCDC_CHAN_SUBLCD:
-                       ch->enabled = 1 << 2;
+                       ch->enabled = LDCNT2R_SE;
                        ch->reg_offs = lcdc_offs_sublcd;
-                       j++;
+                       num_channels++;
                        break;
                }
        }
 
-       if (!j) {
+       if (!num_channels) {
                dev_err(&pdev->dev, "no channels defined\n");
                error = -EINVAL;
                goto err1;
        }
 
        /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */
-       if (j == 2)
+       if (num_channels == 2)
                priv->forced_bpp = pdata->ch[0].bpp;
 
        priv->base = ioremap_nocache(res->start, resource_size(res));
@@ -1506,125 +1641,23 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 
        priv->meram_dev = pdata->meram_dev;
 
-       for (i = 0; i < j; i++) {
-               struct fb_var_screeninfo *var;
-               const struct fb_videomode *lcd_cfg, *max_cfg = NULL;
+       for (i = 0; i < num_channels; i++) {
                struct sh_mobile_lcdc_chan *ch = priv->ch + i;
-               struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
-               const struct fb_videomode *mode = cfg->lcd_cfg;
-               unsigned long max_size = 0;
-               int k;
-               int num_cfg;
-
-               ch->info = framebuffer_alloc(0, &pdev->dev);
-               if (!ch->info) {
-                       dev_err(&pdev->dev, "unable to allocate fb_info\n");
-                       error = -ENOMEM;
-                       break;
-               }
-
-               info = ch->info;
-               var = &info->var;
-               info->fbops = &sh_mobile_lcdc_ops;
-               info->par = ch;
-
-               mutex_init(&ch->open_lock);
-
-               for (k = 0, lcd_cfg = mode;
-                    k < cfg->num_cfg && lcd_cfg;
-                    k++, lcd_cfg++) {
-                       unsigned long size = lcd_cfg->yres * lcd_cfg->xres;
-                       /* NV12 buffers must have even number of lines */
-                       if ((cfg->nonstd) && cfg->bpp == 12 &&
-                                       (lcd_cfg->yres & 0x1)) {
-                               dev_err(&pdev->dev, "yres must be multiple of 2"
-                                               " for YCbCr420 mode.\n");
-                               error = -EINVAL;
-                               goto err1;
-                       }
-
-                       if (size > max_size) {
-                               max_cfg = lcd_cfg;
-                               max_size = size;
-                       }
-               }
-
-               if (!mode)
-                       max_size = MAX_XRES * MAX_YRES;
-               else if (max_cfg)
-                       dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n",
-                               max_cfg->xres, max_cfg->yres);
 
-               info->fix = sh_mobile_lcdc_fix;
-               info->fix.smem_len = max_size * 2 * cfg->bpp / 8;
-
-                /* Only pan in 2 line steps for NV12 */
-               if (cfg->nonstd && cfg->bpp == 12)
-                       info->fix.ypanstep = 2;
-
-               if (!mode) {
-                       mode = &default_720p;
-                       num_cfg = 1;
-               } else {
-                       num_cfg = cfg->num_cfg;
-               }
-
-               fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
-
-               fb_videomode_to_var(var, mode);
-               var->width = cfg->lcd_size_cfg.width;
-               var->height = cfg->lcd_size_cfg.height;
-               /* Default Y virtual resolution is 2x panel size */
-               var->yres_virtual = var->yres * 2;
-               var->activate = FB_ACTIVATE_NOW;
-
-               error = sh_mobile_lcdc_set_bpp(var, cfg->bpp, cfg->nonstd);
+               error = sh_mobile_lcdc_channel_init(ch, &pdev->dev);
                if (error)
-                       break;
-
-               buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len,
-                                        &ch->dma_handle, GFP_KERNEL);
-               if (!buf) {
-                       dev_err(&pdev->dev, "unable to allocate buffer\n");
-                       error = -ENOMEM;
-                       break;
-               }
-
-               info->pseudo_palette = &ch->pseudo_palette;
-               info->flags = FBINFO_FLAG_DEFAULT;
-
-               error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
-               if (error < 0) {
-                       dev_err(&pdev->dev, "unable to allocate cmap\n");
-                       dma_free_coherent(&pdev->dev, info->fix.smem_len,
-                                         buf, ch->dma_handle);
-                       break;
-               }
-
-               info->fix.smem_start = ch->dma_handle;
-               if (var->nonstd)
-                       info->fix.line_length = var->xres;
-               else
-                       info->fix.line_length = var->xres * (cfg->bpp / 8);
-
-               info->screen_base = buf;
-               info->device = &pdev->dev;
-               ch->display_var = *var;
+                       goto err1;
        }
 
-       if (error)
-               goto err1;
-
        error = sh_mobile_lcdc_start(priv);
        if (error) {
                dev_err(&pdev->dev, "unable to start hardware\n");
                goto err1;
        }
 
-       for (i = 0; i < j; i++) {
+       for (i = 0; i < num_channels; i++) {
                struct sh_mobile_lcdc_chan *ch = priv->ch + i;
-
-               info = ch->info;
+               struct fb_info *info = ch->info;
 
                if (info->fbdefio) {
                        ch->sglist = vmalloc(sizeof(struct scatterlist) *
@@ -1665,57 +1698,6 @@ err1:
        return error;
 }
 
-static int sh_mobile_lcdc_remove(struct platform_device *pdev)
-{
-       struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
-       struct fb_info *info;
-       int i;
-
-       fb_unregister_client(&priv->notifier);
-
-       for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
-               if (priv->ch[i].info && priv->ch[i].info->dev)
-                       unregister_framebuffer(priv->ch[i].info);
-
-       sh_mobile_lcdc_stop(priv);
-
-       for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
-               info = priv->ch[i].info;
-
-               if (!info || !info->device)
-                       continue;
-
-               if (priv->ch[i].sglist)
-                       vfree(priv->ch[i].sglist);
-
-               if (info->screen_base)
-                       dma_free_coherent(&pdev->dev, info->fix.smem_len,
-                                         info->screen_base,
-                                         priv->ch[i].dma_handle);
-               fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
-
-       for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
-               if (priv->ch[i].bl)
-                       sh_mobile_lcdc_bl_remove(priv->ch[i].bl);
-       }
-
-       if (priv->dot_clk)
-               clk_put(priv->dot_clk);
-
-       if (priv->dev)
-               pm_runtime_disable(priv->dev);
-
-       if (priv->base)
-               iounmap(priv->base);
-
-       if (priv->irq)
-               free_irq(priv->irq, priv);
-       kfree(priv);
-       return 0;
-}
-
 static struct platform_driver sh_mobile_lcdc_driver = {
        .driver         = {
                .name           = "sh_mobile_lcdc_fb",
index aeed668..a58a0f3 100644 (file)
@@ -18,6 +18,13 @@ struct sh_mobile_lcdc_priv;
 struct fb_info;
 struct backlight_device;
 
+/*
+ * struct sh_mobile_lcdc_chan - LCDC display channel
+ *
+ * @base_addr_y: Frame buffer viewport base address (luma component)
+ * @base_addr_c: Frame buffer viewport base address (chroma component)
+ * @pitch: Frame buffer line pitch
+ */
 struct sh_mobile_lcdc_chan {
        struct sh_mobile_lcdc_priv *lcdc;
        unsigned long *reg_offs;
@@ -25,7 +32,6 @@ struct sh_mobile_lcdc_chan {
        unsigned long enabled; /* ME and SE in LDCNT2R */
        struct sh_mobile_lcdc_chan_cfg cfg;
        u32 pseudo_palette[PALETTE_NR];
-       unsigned long saved_ch_regs[NR_CH_REGS];
        struct fb_info *info;
        struct backlight_device *bl;
        dma_addr_t dma_handle;
@@ -40,6 +46,10 @@ struct sh_mobile_lcdc_chan {
        int blank_status;
        struct mutex open_lock;         /* protects the use counter */
        int meram_enabled;
+
+       unsigned long base_addr_y;
+       unsigned long base_addr_c;
+       unsigned int pitch;
 };
 
 #endif
index cc7d732..4d63490 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/pm_runtime.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
-
-#include "sh_mobile_meram.h"
+#include <video/sh_mobile_meram.h>
 
 /* meram registers */
-#define MExxCTL 0x0
-#define MExxBSIZE 0x4
-#define MExxMNCF 0x8
-#define MExxSARA 0x10
-#define MExxSARB 0x14
-#define MExxSBSIZE 0x18
-
-#define MERAM_MExxCTL_VAL(ctl, next_icb, addr) \
-       ((ctl) | (((next_icb) & 0x1f) << 11) | (((addr) & 0x7ff) << 16))
-#define        MERAM_MExxBSIZE_VAL(a, b, c) \
-       (((a) << 28) | ((b) << 16) | (c))
-
-#define MEVCR1 0x4
-#define MEACTS 0x10
-#define MEQSEL1 0x40
-#define MEQSEL2 0x44
+#define MEVCR1                 0x4
+#define MEVCR1_RST             (1 << 31)
+#define MEVCR1_WD              (1 << 30)
+#define MEVCR1_AMD1            (1 << 29)
+#define MEVCR1_AMD0            (1 << 28)
+#define MEQSEL1                        0x40
+#define MEQSEL2                        0x44
+
+#define MExxCTL                        0x400
+#define MExxCTL_BV             (1 << 31)
+#define MExxCTL_BSZ_SHIFT      28
+#define MExxCTL_MSAR_MASK      (0x7ff << MExxCTL_MSAR_SHIFT)
+#define MExxCTL_MSAR_SHIFT     16
+#define MExxCTL_NXT_MASK       (0x1f << MExxCTL_NXT_SHIFT)
+#define MExxCTL_NXT_SHIFT      11
+#define MExxCTL_WD1            (1 << 10)
+#define MExxCTL_WD0            (1 << 9)
+#define MExxCTL_WS             (1 << 8)
+#define MExxCTL_CB             (1 << 7)
+#define MExxCTL_WBF            (1 << 6)
+#define MExxCTL_WF             (1 << 5)
+#define MExxCTL_RF             (1 << 4)
+#define MExxCTL_CM             (1 << 3)
+#define MExxCTL_MD_READ                (1 << 0)
+#define MExxCTL_MD_WRITE       (2 << 0)
+#define MExxCTL_MD_ICB_WB      (3 << 0)
+#define MExxCTL_MD_ICB         (4 << 0)
+#define MExxCTL_MD_FB          (7 << 0)
+#define MExxCTL_MD_MASK                (7 << 0)
+#define MExxBSIZE              0x404
+#define MExxBSIZE_RCNT_SHIFT   28
+#define MExxBSIZE_YSZM1_SHIFT  16
+#define MExxBSIZE_XSZM1_SHIFT  0
+#define MExxMNCF               0x408
+#define MExxMNCF_KWBNM_SHIFT   28
+#define MExxMNCF_KRBNM_SHIFT   24
+#define MExxMNCF_BNM_SHIFT     16
+#define MExxMNCF_XBV           (1 << 15)
+#define MExxMNCF_CPL_YCBCR444  (1 << 12)
+#define MExxMNCF_CPL_YCBCR420  (2 << 12)
+#define MExxMNCF_CPL_YCBCR422  (3 << 12)
+#define MExxMNCF_CPL_MSK       (3 << 12)
+#define MExxMNCF_BL            (1 << 2)
+#define MExxMNCF_LNM_SHIFT     0
+#define MExxSARA               0x410
+#define MExxSARB               0x414
+#define MExxSBSIZE             0x418
+#define MExxSBSIZE_HDV         (1 << 31)
+#define MExxSBSIZE_HSZ16       (0 << 28)
+#define MExxSBSIZE_HSZ32       (1 << 28)
+#define MExxSBSIZE_HSZ64       (2 << 28)
+#define MExxSBSIZE_HSZ128      (3 << 28)
+#define MExxSBSIZE_SBSIZZ_SHIFT        0
+
+#define MERAM_MExxCTL_VAL(next, addr)  \
+       ((((next) << MExxCTL_NXT_SHIFT) & MExxCTL_NXT_MASK) | \
+        (((addr) << MExxCTL_MSAR_SHIFT) & MExxCTL_MSAR_MASK))
+#define        MERAM_MExxBSIZE_VAL(rcnt, yszm1, xszm1) \
+       (((rcnt) << MExxBSIZE_RCNT_SHIFT) | \
+        ((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \
+        ((xszm1) << MExxBSIZE_XSZM1_SHIFT))
+
+#define SH_MOBILE_MERAM_ICB_NUM                32
+
+static unsigned long common_regs[] = {
+       MEVCR1,
+       MEQSEL1,
+       MEQSEL2,
+};
+#define CMN_REGS_SIZE ARRAY_SIZE(common_regs)
+
+static unsigned long icb_regs[] = {
+       MExxCTL,
+       MExxBSIZE,
+       MExxMNCF,
+       MExxSARA,
+       MExxSARB,
+       MExxSBSIZE,
+};
+#define ICB_REGS_SIZE ARRAY_SIZE(icb_regs)
+
+struct sh_mobile_meram_priv {
+       void __iomem    *base;
+       struct mutex    lock;
+       unsigned long   used_icb;
+       int             used_meram_cache_regions;
+       unsigned long   used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
+       unsigned long   cmn_saved_regs[CMN_REGS_SIZE];
+       unsigned long   icb_saved_regs[ICB_REGS_SIZE * SH_MOBILE_MERAM_ICB_NUM];
+};
 
 /* settings */
 #define MERAM_SEC_LINE 15
  * MERAM/ICB access functions
  */
 
-#define MERAM_ICB_OFFSET(base, idx, off)       \
-       ((base) + (0x400 + ((idx) * 0x20) + (off)))
+#define MERAM_ICB_OFFSET(base, idx, off)       ((base) + (off) + (idx) * 0x20)
 
 static inline void meram_write_icb(void __iomem *base, int idx, int off,
        unsigned long val)
@@ -280,17 +353,18 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
        /*
         * Set MERAM for framebuffer
         *
-        * 0x70f:  WD = 0x3, WS=0x1, CM=0x1, MD=FB mode
         * we also chain the cache_icb and the marker_icb.
         * we also split the allocated MERAM buffer between two ICBs.
         */
        meram_write_icb(priv->base, icb->cache_icb, MExxCTL,
-                       MERAM_MExxCTL_VAL(0x70f, icb->marker_icb,
-                                         icb->meram_offset));
+                       MERAM_MExxCTL_VAL(icb->marker_icb, icb->meram_offset) |
+                       MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
+                       MExxCTL_MD_FB);
        meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
-                       MERAM_MExxCTL_VAL(0x70f, icb->cache_icb,
-                                         icb->meram_offset +
-                                         icb->meram_size / 2));
+                       MERAM_MExxCTL_VAL(icb->cache_icb, icb->meram_offset +
+                                         icb->meram_size / 2) |
+                       MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
+                       MExxCTL_MD_FB);
 
        return 0;
 }
@@ -299,8 +373,10 @@ static void meram_deinit(struct sh_mobile_meram_priv *priv,
                        struct sh_mobile_meram_icb *icb)
 {
        /* disable ICB */
-       meram_write_icb(priv->base, icb->cache_icb,  MExxCTL, 0);
-       meram_write_icb(priv->base, icb->marker_icb, MExxCTL, 0);
+       meram_write_icb(priv->base, icb->cache_icb,  MExxCTL,
+                       MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
+       meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
+                       MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
        icb->cache_unit = 0;
 }
 
@@ -337,24 +413,22 @@ static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
                xres, yres, (!pixelformat) ? "yuv" : "rgb",
                base_addr_y, base_addr_c);
 
-       mutex_lock(&priv->lock);
-
        /* we can't handle wider than 8192px */
        if (xres > 8192) {
                dev_err(&pdev->dev, "width exceeding the limit (> 8192).");
-               error = -EINVAL;
-               goto err;
-       }
-
-       if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
-               dev_err(&pdev->dev, "no more ICB available.");
-               error = -EINVAL;
-               goto err;
+               return -EINVAL;
        }
 
        /* do we have at least one ICB config? */
        if (cfg->icb[0].marker_icb < 0 || cfg->icb[0].cache_icb < 0) {
                dev_err(&pdev->dev, "at least one ICB is required.");
+               return -EINVAL;
+       }
+
+       mutex_lock(&priv->lock);
+
+       if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
+               dev_err(&pdev->dev, "no more ICB available.");
                error = -EINVAL;
                goto err;
        }
@@ -460,6 +534,57 @@ static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata,
        return 0;
 }
 
+static int sh_mobile_meram_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+       int k, j;
+
+       for (k = 0; k < CMN_REGS_SIZE; k++)
+               priv->cmn_saved_regs[k] = meram_read_reg(priv->base,
+                       common_regs[k]);
+
+       for (j = 0; j < 32; j++) {
+               if (!test_bit(j, &priv->used_icb))
+                       continue;
+               for (k = 0; k < ICB_REGS_SIZE; k++) {
+                       priv->icb_saved_regs[j * ICB_REGS_SIZE + k] =
+                               meram_read_icb(priv->base, j, icb_regs[k]);
+                       /* Reset ICB on resume */
+                       if (icb_regs[k] == MExxCTL)
+                               priv->icb_saved_regs[j * ICB_REGS_SIZE + k] |=
+                                       MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF;
+               }
+       }
+       return 0;
+}
+
+static int sh_mobile_meram_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+       int k, j;
+
+       for (j = 0; j < 32; j++) {
+               if (!test_bit(j, &priv->used_icb))
+                       continue;
+               for (k = 0; k < ICB_REGS_SIZE; k++) {
+                       meram_write_icb(priv->base, j, icb_regs[k],
+                       priv->icb_saved_regs[j * ICB_REGS_SIZE + k]);
+               }
+       }
+
+       for (k = 0; k < CMN_REGS_SIZE; k++)
+               meram_write_reg(priv->base, common_regs[k],
+                       priv->cmn_saved_regs[k]);
+       return 0;
+}
+
+static const struct dev_pm_ops sh_mobile_meram_dev_pm_ops = {
+       .runtime_suspend = sh_mobile_meram_runtime_suspend,
+       .runtime_resume = sh_mobile_meram_runtime_resume,
+};
+
 static struct sh_mobile_meram_ops sh_mobile_meram_ops = {
        .module                 = THIS_MODULE,
        .meram_register         = sh_mobile_meram_register,
@@ -513,7 +638,9 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
 
        /* initialize ICB addressing mode */
        if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1)
-               meram_write_reg(priv->base, MEVCR1, 1 << 29);
+               meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1);
+
+       pm_runtime_enable(&pdev->dev);
 
        dev_info(&pdev->dev, "sh_mobile_meram initialized.");
 
@@ -530,6 +657,8 @@ static int sh_mobile_meram_remove(struct platform_device *pdev)
 {
        struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
 
+       pm_runtime_disable(&pdev->dev);
+
        if (priv->base)
                iounmap(priv->base);
 
@@ -544,6 +673,7 @@ static struct platform_driver sh_mobile_meram_driver = {
        .driver = {
                .name           = "sh_mobile_meram",
                .owner          = THIS_MODULE,
+               .pm             = &sh_mobile_meram_dev_pm_ops,
        },
        .probe          = sh_mobile_meram_probe,
        .remove         = sh_mobile_meram_remove,
diff --git a/drivers/video/sh_mobile_meram.h b/drivers/video/sh_mobile_meram.h
deleted file mode 100644 (file)
index 82c54fb..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __sh_mobile_meram_h__
-#define __sh_mobile_meram_h__
-
-#include <linux/mutex.h>
-#include <video/sh_mobile_meram.h>
-
-/*
- * MERAM private
- */
-
-#define MERAM_ICB_Y 0x1
-#define MERAM_ICB_C 0x2
-
-/* MERAM cache size */
-#define SH_MOBILE_MERAM_ICB_NUM                32
-
-#define SH_MOBILE_MERAM_CACHE_OFFSET(p)        ((p) >> 16)
-#define SH_MOBILE_MERAM_CACHE_SIZE(p)  ((p) & 0xffff)
-
-struct sh_mobile_meram_priv {
-       void __iomem    *base;
-       struct mutex    lock;
-       unsigned long   used_icb;
-       int             used_meram_cache_regions;
-       unsigned long   used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
-};
-
-int sh_mobile_meram_alloc_icb(const struct sh_mobile_meram_cfg *cfg,
-                  int xres,
-                  int yres,
-                  unsigned int base_addr,
-                  int yuv_mode,
-                  int *marker_icb,
-                  int *out_pitch);
-
-void sh_mobile_meram_free_icb(int marker_icb);
-
-#define SH_MOBILE_MERAM_START(ind, ab) \
-       (0xC0000000 | ((ab & 0x1) << 23) | ((ind & 0x1F) << 24))
-
-#endif /* !__sh_mobile_meram_h__ */
index 7525984..078ca21 100644 (file)
@@ -1333,19 +1333,14 @@ sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
 }
 
 static int
-sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
+sisfb_pan_var(struct sis_video_info *ivideo, struct fb_info *info,
+             struct fb_var_screeninfo *var)
 {
-       if(var->xoffset > (var->xres_virtual - var->xres)) {
-               return -EINVAL;
-       }
-       if(var->yoffset > (var->yres_virtual - var->yres)) {
-               return -EINVAL;
-       }
-
-       ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
+       ivideo->current_base = var->yoffset * info->var.xres_virtual
+                            + var->xoffset;
 
        /* calculate base bpp dep. */
-       switch(var->bits_per_pixel) {
+       switch (info->var.bits_per_pixel) {
        case 32:
                break;
        case 16:
@@ -1635,20 +1630,15 @@ sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
        int err;
 
-       if(var->xoffset > (var->xres_virtual - var->xres))
-               return -EINVAL;
-
-       if(var->yoffset > (var->yres_virtual - var->yres))
-               return -EINVAL;
-
-       if(var->vmode & FB_VMODE_YWRAP)
+       if (var->vmode & FB_VMODE_YWRAP)
                return -EINVAL;
 
-       if(var->xoffset + info->var.xres > info->var.xres_virtual ||
-          var->yoffset + info->var.yres > info->var.yres_virtual)
+       if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+           var->yoffset + info->var.yres > info->var.yres_virtual)
                return -EINVAL;
 
-       if((err = sisfb_pan_var(ivideo, var)) < 0)
+       err = sisfb_pan_var(ivideo, info, var);
+       if (err < 0)
                return err;
 
        info->var.xoffset = var->xoffset;
index 89158bc..30f7a81 100644 (file)
@@ -989,7 +989,7 @@ static struct platform_device *xxxfb_device;
  */
 int __init xxxfb_setup(char *options)
 {
-    /* Parse user speficied options (`video=xxxfb:') */
+    /* Parse user specified options (`video=xxxfb:') */
 }
 #endif /* MODULE */
 
index 6294dca..a78254c 100644 (file)
@@ -582,7 +582,7 @@ static int sm501fb_pan_crt(struct fb_var_screeninfo *var,
 {
        struct sm501fb_par  *par = info->par;
        struct sm501fb_info *fbi = par->info;
-       unsigned int bytes_pixel = var->bits_per_pixel / 8;
+       unsigned int bytes_pixel = info->var.bits_per_pixel / 8;
        unsigned long reg;
        unsigned long xoffs;
 
@@ -614,10 +614,10 @@ static int sm501fb_pan_pnl(struct fb_var_screeninfo *var,
        struct sm501fb_info *fbi = par->info;
        unsigned long reg;
 
-       reg = var->xoffset | (var->xres_virtual << 16);
+       reg = var->xoffset | (info->var.xres_virtual << 16);
        smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
 
-       reg = var->yoffset | (var->yres_virtual << 16);
+       reg = var->yoffset | (info->var.yres_virtual << 16);
        smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
 
        sm501fb_sync_regs(fbi);
diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c
new file mode 100644 (file)
index 0000000..aaccffa
--- /dev/null
@@ -0,0 +1,1994 @@
+/*
+ * smscufx.c -- Framebuffer driver for SMSC UFX USB controller
+ *
+ * Copyright (C) 2011 Steve Glendinning <steve.glendinning@smsc.com>
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Based on udlfb, with work from Florian Echtler, Henrik Bjerregaard Pedersen,
+ * and others.
+ *
+ * Works well with Bernie Thompson's X DAMAGE patch to xf86-video-fbdev
+ * available from http://git.plugable.com
+ *
+ * Layout is based on skeletonfb by James Simmons and Geert Uytterhoeven,
+ * usb-skeleton by GregKH.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/uaccess.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "edid.h"
+
+#define check_warn(status, fmt, args...) \
+       ({ if (status < 0) pr_warn(fmt, ##args); })
+
+#define check_warn_return(status, fmt, args...) \
+       ({ if (status < 0) { pr_warn(fmt, ##args); return status; } })
+
+#define check_warn_goto_error(status, fmt, args...) \
+       ({ if (status < 0) { pr_warn(fmt, ##args); goto error; } })
+
+#define all_bits_set(x, bits) (((x) & (bits)) == (bits))
+
+#define USB_VENDOR_REQUEST_WRITE_REGISTER      0xA0
+#define USB_VENDOR_REQUEST_READ_REGISTER       0xA1
+
+/*
+ * TODO: Propose standard fb.h ioctl for reporting damage,
+ * using _IOWR() and one of the existing area structs from fb.h
+ * Consider these ioctls deprecated, but they're still used by the
+ * DisplayLink X server as yet - need both to be modified in tandem
+ * when new ioctl(s) are ready.
+ */
+#define UFX_IOCTL_RETURN_EDID  (0xAD)
+#define UFX_IOCTL_REPORT_DAMAGE        (0xAA)
+
+/* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */
+#define BULK_SIZE              (512)
+#define MAX_TRANSFER           (PAGE_SIZE*16 - BULK_SIZE)
+#define WRITES_IN_FLIGHT       (4)
+
+#define GET_URB_TIMEOUT                (HZ)
+#define FREE_URB_TIMEOUT       (HZ*2)
+
+#define BPP                    2
+
+#define UFX_DEFIO_WRITE_DELAY  5 /* fb_deferred_io.delay in jiffies */
+#define UFX_DEFIO_WRITE_DISABLE        (HZ*60) /* "disable" with long delay */
+
+struct dloarea {
+       int x, y;
+       int w, h;
+};
+
+struct urb_node {
+       struct list_head entry;
+       struct ufx_data *dev;
+       struct delayed_work release_urb_work;
+       struct urb *urb;
+};
+
+struct urb_list {
+       struct list_head list;
+       spinlock_t lock;
+       struct semaphore limit_sem;
+       int available;
+       int count;
+       size_t size;
+};
+
+struct ufx_data {
+       struct usb_device *udev;
+       struct device *gdev; /* &udev->dev */
+       struct fb_info *info;
+       struct urb_list urbs;
+       struct kref kref;
+       int fb_count;
+       bool virtualized; /* true when physical usb device not present */
+       struct delayed_work free_framebuffer_work;
+       atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
+       atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
+       u8 *edid; /* null until we read edid from hw or get from sysfs */
+       size_t edid_size;
+       u32 pseudo_palette[256];
+};
+
+static struct fb_fix_screeninfo ufx_fix = {
+       .id =           "smscufx",
+       .type =         FB_TYPE_PACKED_PIXELS,
+       .visual =       FB_VISUAL_TRUECOLOR,
+       .xpanstep =     0,
+       .ypanstep =     0,
+       .ywrapstep =    0,
+       .accel =        FB_ACCEL_NONE,
+};
+
+static const u32 smscufx_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
+       FBINFO_VIRTFB | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT |
+       FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR;
+
+static struct usb_device_id id_table[] = {
+       {USB_DEVICE(0x0424, 0x9d00),},
+       {USB_DEVICE(0x0424, 0x9d01),},
+       {},
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+/* module options */
+static int console;   /* Optionally allow fbcon to consume first framebuffer */
+static int fb_defio = true;  /* Optionally enable fb_defio mmap support */
+
+/* ufx keeps a list of urbs for efficient bulk transfers */
+static void ufx_urb_completion(struct urb *urb);
+static struct urb *ufx_get_urb(struct ufx_data *dev);
+static int ufx_submit_urb(struct ufx_data *dev, struct urb * urb, size_t len);
+static int ufx_alloc_urb_list(struct ufx_data *dev, int count, size_t size);
+static void ufx_free_urb_list(struct ufx_data *dev);
+
+/* reads a control register */
+static int ufx_reg_read(struct ufx_data *dev, u32 index, u32 *data)
+{
+       u32 *buf = kmalloc(4, GFP_KERNEL);
+       int ret;
+
+       BUG_ON(!dev);
+
+       if (!buf)
+               return -ENOMEM;
+
+       ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+               USB_VENDOR_REQUEST_READ_REGISTER,
+               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               00, index, buf, 4, USB_CTRL_GET_TIMEOUT);
+
+       le32_to_cpus(buf);
+       *data = *buf;
+       kfree(buf);
+
+       if (unlikely(ret < 0))
+               pr_warn("Failed to read register index 0x%08x\n", index);
+
+       return ret;
+}
+
+/* writes a control register */
+static int ufx_reg_write(struct ufx_data *dev, u32 index, u32 data)
+{
+       u32 *buf = kmalloc(4, GFP_KERNEL);
+       int ret;
+
+       BUG_ON(!dev);
+
+       if (!buf)
+               return -ENOMEM;
+
+       *buf = data;
+       cpu_to_le32s(buf);
+
+       ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+               USB_VENDOR_REQUEST_WRITE_REGISTER,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               00, index, buf, 4, USB_CTRL_SET_TIMEOUT);
+
+       kfree(buf);
+
+       if (unlikely(ret < 0))
+               pr_warn("Failed to write register index 0x%08x with value "
+                       "0x%08x\n", index, data);
+
+       return ret;
+}
+
+static int ufx_reg_clear_and_set_bits(struct ufx_data *dev, u32 index,
+       u32 bits_to_clear, u32 bits_to_set)
+{
+       u32 data;
+       int status = ufx_reg_read(dev, index, &data);
+       check_warn_return(status, "ufx_reg_clear_and_set_bits error reading "
+               "0x%x", index);
+
+       data &= (~bits_to_clear);
+       data |= bits_to_set;
+
+       status = ufx_reg_write(dev, index, data);
+       check_warn_return(status, "ufx_reg_clear_and_set_bits error writing "
+               "0x%x", index);
+
+       return 0;
+}
+
+static int ufx_reg_set_bits(struct ufx_data *dev, u32 index, u32 bits)
+{
+       return ufx_reg_clear_and_set_bits(dev, index, 0, bits);
+}
+
+static int ufx_reg_clear_bits(struct ufx_data *dev, u32 index, u32 bits)
+{
+       return ufx_reg_clear_and_set_bits(dev, index, bits, 0);
+}
+
+static int ufx_lite_reset(struct ufx_data *dev)
+{
+       int status;
+       u32 value;
+
+       status = ufx_reg_write(dev, 0x3008, 0x00000001);
+       check_warn_return(status, "ufx_lite_reset error writing 0x3008");
+
+       status = ufx_reg_read(dev, 0x3008, &value);
+       check_warn_return(status, "ufx_lite_reset error reading 0x3008");
+
+       return (value == 0) ? 0 : -EIO;
+}
+
+/* If display is unblanked, then blank it */
+static int ufx_blank(struct ufx_data *dev, bool wait)
+{
+       u32 dc_ctrl, dc_sts;
+       int i;
+
+       int status = ufx_reg_read(dev, 0x2004, &dc_sts);
+       check_warn_return(status, "ufx_blank error reading 0x2004");
+
+       status = ufx_reg_read(dev, 0x2000, &dc_ctrl);
+       check_warn_return(status, "ufx_blank error reading 0x2000");
+
+       /* return success if display is already blanked */
+       if ((dc_sts & 0x00000100) || (dc_ctrl & 0x00000100))
+               return 0;
+
+       /* request the DC to blank the display */
+       dc_ctrl |= 0x00000100;
+       status = ufx_reg_write(dev, 0x2000, dc_ctrl);
+       check_warn_return(status, "ufx_blank error writing 0x2000");
+
+       /* return success immediately if we don't have to wait */
+       if (!wait)
+               return 0;
+
+       for (i = 0; i < 250; i++) {
+               status = ufx_reg_read(dev, 0x2004, &dc_sts);
+               check_warn_return(status, "ufx_blank error reading 0x2004");
+
+               if (dc_sts & 0x00000100)
+                       return 0;
+       }
+
+       /* timed out waiting for display to blank */
+       return -EIO;
+}
+
+/* If display is blanked, then unblank it */
+static int ufx_unblank(struct ufx_data *dev, bool wait)
+{
+       u32 dc_ctrl, dc_sts;
+       int i;
+
+       int status = ufx_reg_read(dev, 0x2004, &dc_sts);
+       check_warn_return(status, "ufx_unblank error reading 0x2004");
+
+       status = ufx_reg_read(dev, 0x2000, &dc_ctrl);
+       check_warn_return(status, "ufx_unblank error reading 0x2000");
+
+       /* return success if display is already unblanked */
+       if (((dc_sts & 0x00000100) == 0) || ((dc_ctrl & 0x00000100) == 0))
+               return 0;
+
+       /* request the DC to unblank the display */
+       dc_ctrl &= ~0x00000100;
+       status = ufx_reg_write(dev, 0x2000, dc_ctrl);
+       check_warn_return(status, "ufx_unblank error writing 0x2000");
+
+       /* return success immediately if we don't have to wait */
+       if (!wait)
+               return 0;
+
+       for (i = 0; i < 250; i++) {
+               status = ufx_reg_read(dev, 0x2004, &dc_sts);
+               check_warn_return(status, "ufx_unblank error reading 0x2004");
+
+               if ((dc_sts & 0x00000100) == 0)
+                       return 0;
+       }
+
+       /* timed out waiting for display to unblank */
+       return -EIO;
+}
+
+/* If display is enabled, then disable it */
+static int ufx_disable(struct ufx_data *dev, bool wait)
+{
+       u32 dc_ctrl, dc_sts;
+       int i;
+
+       int status = ufx_reg_read(dev, 0x2004, &dc_sts);
+       check_warn_return(status, "ufx_disable error reading 0x2004");
+
+       status = ufx_reg_read(dev, 0x2000, &dc_ctrl);
+       check_warn_return(status, "ufx_disable error reading 0x2000");
+
+       /* return success if display is already disabled */
+       if (((dc_sts & 0x00000001) == 0) || ((dc_ctrl & 0x00000001) == 0))
+               return 0;
+
+       /* request the DC to disable the display */
+       dc_ctrl &= ~(0x00000001);
+       status = ufx_reg_write(dev, 0x2000, dc_ctrl);
+       check_warn_return(status, "ufx_disable error writing 0x2000");
+
+       /* return success immediately if we don't have to wait */
+       if (!wait)
+               return 0;
+
+       for (i = 0; i < 250; i++) {
+               status = ufx_reg_read(dev, 0x2004, &dc_sts);
+               check_warn_return(status, "ufx_disable error reading 0x2004");
+
+               if ((dc_sts & 0x00000001) == 0)
+                       return 0;
+       }
+
+       /* timed out waiting for display to disable */
+       return -EIO;
+}
+
+/* If display is disabled, then enable it */
+static int ufx_enable(struct ufx_data *dev, bool wait)
+{
+       u32 dc_ctrl, dc_sts;
+       int i;
+
+       int status = ufx_reg_read(dev, 0x2004, &dc_sts);
+       check_warn_return(status, "ufx_enable error reading 0x2004");
+
+       status = ufx_reg_read(dev, 0x2000, &dc_ctrl);
+       check_warn_return(status, "ufx_enable error reading 0x2000");
+
+       /* return success if display is already enabled */
+       if ((dc_sts & 0x00000001) || (dc_ctrl & 0x00000001))
+               return 0;
+
+       /* request the DC to enable the display */
+       dc_ctrl |= 0x00000001;
+       status = ufx_reg_write(dev, 0x2000, dc_ctrl);
+       check_warn_return(status, "ufx_enable error writing 0x2000");
+
+       /* return success immediately if we don't have to wait */
+       if (!wait)
+               return 0;
+
+       for (i = 0; i < 250; i++) {
+               status = ufx_reg_read(dev, 0x2004, &dc_sts);
+               check_warn_return(status, "ufx_enable error reading 0x2004");
+
+               if (dc_sts & 0x00000001)
+                       return 0;
+       }
+
+       /* timed out waiting for display to enable */
+       return -EIO;
+}
+
+static int ufx_config_sys_clk(struct ufx_data *dev)
+{
+       int status = ufx_reg_write(dev, 0x700C, 0x8000000F);
+       check_warn_return(status, "error writing 0x700C");
+
+       status = ufx_reg_write(dev, 0x7014, 0x0010024F);
+       check_warn_return(status, "error writing 0x7014");
+
+       status = ufx_reg_write(dev, 0x7010, 0x00000000);
+       check_warn_return(status, "error writing 0x7010");
+
+       status = ufx_reg_clear_bits(dev, 0x700C, 0x0000000A);
+       check_warn_return(status, "error clearing PLL1 bypass in 0x700C");
+       msleep(1);
+
+       status = ufx_reg_clear_bits(dev, 0x700C, 0x80000000);
+       check_warn_return(status, "error clearing output gate in 0x700C");
+
+       return 0;
+}
+
+static int ufx_config_ddr2(struct ufx_data *dev)
+{
+       int status, i = 0;
+       u32 tmp;
+
+       status = ufx_reg_write(dev, 0x0004, 0x001F0F77);
+       check_warn_return(status, "error writing 0x0004");
+
+       status = ufx_reg_write(dev, 0x0008, 0xFFF00000);
+       check_warn_return(status, "error writing 0x0008");
+
+       status = ufx_reg_write(dev, 0x000C, 0x0FFF2222);
+       check_warn_return(status, "error writing 0x000C");
+
+       status = ufx_reg_write(dev, 0x0010, 0x00030814);
+       check_warn_return(status, "error writing 0x0010");
+
+       status = ufx_reg_write(dev, 0x0014, 0x00500019);
+       check_warn_return(status, "error writing 0x0014");
+
+       status = ufx_reg_write(dev, 0x0018, 0x020D0F15);
+       check_warn_return(status, "error writing 0x0018");
+
+       status = ufx_reg_write(dev, 0x001C, 0x02532305);
+       check_warn_return(status, "error writing 0x001C");
+
+       status = ufx_reg_write(dev, 0x0020, 0x0B030905);
+       check_warn_return(status, "error writing 0x0020");
+
+       status = ufx_reg_write(dev, 0x0024, 0x00000827);
+       check_warn_return(status, "error writing 0x0024");
+
+       status = ufx_reg_write(dev, 0x0028, 0x00000000);
+       check_warn_return(status, "error writing 0x0028");
+
+       status = ufx_reg_write(dev, 0x002C, 0x00000042);
+       check_warn_return(status, "error writing 0x002C");
+
+       status = ufx_reg_write(dev, 0x0030, 0x09520000);
+       check_warn_return(status, "error writing 0x0030");
+
+       status = ufx_reg_write(dev, 0x0034, 0x02223314);
+       check_warn_return(status, "error writing 0x0034");
+
+       status = ufx_reg_write(dev, 0x0038, 0x00430043);
+       check_warn_return(status, "error writing 0x0038");
+
+       status = ufx_reg_write(dev, 0x003C, 0xF00F000F);
+       check_warn_return(status, "error writing 0x003C");
+
+       status = ufx_reg_write(dev, 0x0040, 0xF380F00F);
+       check_warn_return(status, "error writing 0x0040");
+
+       status = ufx_reg_write(dev, 0x0044, 0xF00F0496);
+       check_warn_return(status, "error writing 0x0044");
+
+       status = ufx_reg_write(dev, 0x0048, 0x03080406);
+       check_warn_return(status, "error writing 0x0048");
+
+       status = ufx_reg_write(dev, 0x004C, 0x00001000);
+       check_warn_return(status, "error writing 0x004C");
+
+       status = ufx_reg_write(dev, 0x005C, 0x00000007);
+       check_warn_return(status, "error writing 0x005C");
+
+       status = ufx_reg_write(dev, 0x0100, 0x54F00012);
+       check_warn_return(status, "error writing 0x0100");
+
+       status = ufx_reg_write(dev, 0x0104, 0x00004012);
+       check_warn_return(status, "error writing 0x0104");
+
+       status = ufx_reg_write(dev, 0x0118, 0x40404040);
+       check_warn_return(status, "error writing 0x0118");
+
+       status = ufx_reg_write(dev, 0x0000, 0x00000001);
+       check_warn_return(status, "error writing 0x0000");
+
+       while (i++ < 500) {
+               status = ufx_reg_read(dev, 0x0000, &tmp);
+               check_warn_return(status, "error reading 0x0000");
+
+               if (all_bits_set(tmp, 0xC0000000))
+                       return 0;
+       }
+
+       pr_err("DDR2 initialisation timed out, reg 0x0000=0x%08x", tmp);
+       return -ETIMEDOUT;
+}
+
+struct pll_values {
+       u32 div_r0;
+       u32 div_f0;
+       u32 div_q0;
+       u32 range0;
+       u32 div_r1;
+       u32 div_f1;
+       u32 div_q1;
+       u32 range1;
+};
+
+static u32 ufx_calc_range(u32 ref_freq)
+{
+       if (ref_freq >= 88000000)
+               return 7;
+
+       if (ref_freq >= 54000000)
+               return 6;
+
+       if (ref_freq >= 34000000)
+               return 5;
+
+       if (ref_freq >= 21000000)
+               return 4;
+
+       if (ref_freq >= 13000000)
+               return 3;
+
+       if (ref_freq >= 8000000)
+               return 2;
+
+       return 1;
+}
+
+/* calculates PLL divider settings for a desired target frequency */
+static void ufx_calc_pll_values(const u32 clk_pixel_pll, struct pll_values *asic_pll)
+{
+       const u32 ref_clk = 25000000;
+       u32 div_r0, div_f0, div_q0, div_r1, div_f1, div_q1;
+       u32 min_error = clk_pixel_pll;
+
+       for (div_r0 = 1; div_r0 <= 32; div_r0++) {
+               u32 ref_freq0 = ref_clk / div_r0;
+               if (ref_freq0 < 5000000)
+                       break;
+
+               if (ref_freq0 > 200000000)
+                       continue;
+
+               for (div_f0 = 1; div_f0 <= 256; div_f0++) {
+                       u32 vco_freq0 = ref_freq0 * div_f0;
+
+                       if (vco_freq0 < 350000000)
+                               continue;
+
+                       if (vco_freq0 > 700000000)
+                               break;
+
+                       for (div_q0 = 0; div_q0 < 7; div_q0++) {
+                               u32 pllout_freq0 = vco_freq0 / (1 << div_q0);
+
+                               if (pllout_freq0 < 5000000)
+                                       break;
+
+                               if (pllout_freq0 > 200000000)
+                                       continue;
+
+                               for (div_r1 = 1; div_r1 <= 32; div_r1++) {
+                                       u32 ref_freq1 = pllout_freq0 / div_r1;
+
+                                       if (ref_freq1 < 5000000)
+                                               break;
+
+                                       for (div_f1 = 1; div_f1 <= 256; div_f1++) {
+                                               u32 vco_freq1 = ref_freq1 * div_f1;
+
+                                               if (vco_freq1 < 350000000)
+                                                       continue;
+
+                                               if (vco_freq1 > 700000000)
+                                                       break;
+
+                                               for (div_q1 = 0; div_q1 < 7; div_q1++) {
+                                                       u32 pllout_freq1 = vco_freq1 / (1 << div_q1);
+                                                       int error = abs(pllout_freq1 - clk_pixel_pll);
+
+                                                       if (pllout_freq1 < 5000000)
+                                                               break;
+
+                                                       if (pllout_freq1 > 700000000)
+                                                               continue;
+
+                                                       if (error < min_error) {
+                                                               min_error = error;
+
+                                                               /* final returned value is equal to calculated value - 1
+                                                                * because a value of 0 = divide by 1 */
+                                                               asic_pll->div_r0 = div_r0 - 1;
+                                                               asic_pll->div_f0 = div_f0 - 1;
+                                                               asic_pll->div_q0 = div_q0;
+                                                               asic_pll->div_r1 = div_r1 - 1;
+                                                               asic_pll->div_f1 = div_f1 - 1;
+                                                               asic_pll->div_q1 = div_q1;
+
+                                                               asic_pll->range0 = ufx_calc_range(ref_freq0);
+                                                               asic_pll->range1 = ufx_calc_range(ref_freq1);
+
+                                                               if (min_error == 0)
+                                                                       return;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+/* sets analog bit PLL configuration values */
+static int ufx_config_pix_clk(struct ufx_data *dev, u32 pixclock)
+{
+       struct pll_values asic_pll = {0};
+       u32 value, clk_pixel, clk_pixel_pll;
+       int status;
+
+       /* convert pixclock (in ps) to frequency (in Hz) */
+       clk_pixel = PICOS2KHZ(pixclock) * 1000;
+       pr_debug("pixclock %d ps = clk_pixel %d Hz", pixclock, clk_pixel);
+
+       /* clk_pixel = 1/2 clk_pixel_pll */
+       clk_pixel_pll = clk_pixel * 2;
+
+       ufx_calc_pll_values(clk_pixel_pll, &asic_pll);
+
+       /* Keep BYPASS and RESET signals asserted until configured */
+       status = ufx_reg_write(dev, 0x7000, 0x8000000F);
+       check_warn_return(status, "error writing 0x7000");
+
+       value = (asic_pll.div_f1 | (asic_pll.div_r1 << 8) |
+               (asic_pll.div_q1 << 16) | (asic_pll.range1 << 20));
+       status = ufx_reg_write(dev, 0x7008, value);
+       check_warn_return(status, "error writing 0x7008");
+
+       value = (asic_pll.div_f0 | (asic_pll.div_r0 << 8) |
+               (asic_pll.div_q0 << 16) | (asic_pll.range0 << 20));
+       status = ufx_reg_write(dev, 0x7004, value);
+       check_warn_return(status, "error writing 0x7004");
+
+       status = ufx_reg_clear_bits(dev, 0x7000, 0x00000005);
+       check_warn_return(status,
+               "error clearing PLL0 bypass bits in 0x7000");
+       msleep(1);
+
+       status = ufx_reg_clear_bits(dev, 0x7000, 0x0000000A);
+       check_warn_return(status,
+               "error clearing PLL1 bypass bits in 0x7000");
+       msleep(1);
+
+       status = ufx_reg_clear_bits(dev, 0x7000, 0x80000000);
+       check_warn_return(status, "error clearing gate bits in 0x7000");
+
+       return 0;
+}
+
+static int ufx_set_vid_mode(struct ufx_data *dev, struct fb_var_screeninfo *var)
+{
+       u32 temp;
+       u16 h_total, h_active, h_blank_start, h_blank_end, h_sync_start, h_sync_end;
+       u16 v_total, v_active, v_blank_start, v_blank_end, v_sync_start, v_sync_end;
+
+       int status = ufx_reg_write(dev, 0x8028, 0);
+       check_warn_return(status, "ufx_set_vid_mode error disabling RGB pad");
+
+       status = ufx_reg_write(dev, 0x8024, 0);
+       check_warn_return(status, "ufx_set_vid_mode error disabling VDAC");
+
+       /* shut everything down before changing timing */
+       status = ufx_blank(dev, true);
+       check_warn_return(status, "ufx_set_vid_mode error blanking display");
+
+       status = ufx_disable(dev, true);
+       check_warn_return(status, "ufx_set_vid_mode error disabling display");
+
+       status = ufx_config_pix_clk(dev, var->pixclock);
+       check_warn_return(status, "ufx_set_vid_mode error configuring pixclock");
+
+       status = ufx_reg_write(dev, 0x2000, 0x00000104);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x2000");
+
+       /* set horizontal timings */
+       h_total = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+       h_active = var->xres;
+       h_blank_start = var->xres + var->right_margin;
+       h_blank_end = var->xres + var->right_margin + var->hsync_len;
+       h_sync_start = var->xres + var->right_margin;
+       h_sync_end = var->xres + var->right_margin + var->hsync_len;
+
+       temp = ((h_total - 1) << 16) | (h_active - 1);
+       status = ufx_reg_write(dev, 0x2008, temp);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x2008");
+
+       temp = ((h_blank_start - 1) << 16) | (h_blank_end - 1);
+       status = ufx_reg_write(dev, 0x200C, temp);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x200C");
+
+       temp = ((h_sync_start - 1) << 16) | (h_sync_end - 1);
+       status = ufx_reg_write(dev, 0x2010, temp);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x2010");
+
+       /* set vertical timings */
+       v_total = var->upper_margin + var->yres + var->lower_margin + var->vsync_len;
+       v_active = var->yres;
+       v_blank_start = var->yres + var->lower_margin;
+       v_blank_end = var->yres + var->lower_margin + var->vsync_len;
+       v_sync_start = var->yres + var->lower_margin;
+       v_sync_end = var->yres + var->lower_margin + var->vsync_len;
+
+       temp = ((v_total - 1) << 16) | (v_active - 1);
+       status = ufx_reg_write(dev, 0x2014, temp);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x2014");
+
+       temp = ((v_blank_start - 1) << 16) | (v_blank_end - 1);
+       status = ufx_reg_write(dev, 0x2018, temp);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x2018");
+
+       temp = ((v_sync_start - 1) << 16) | (v_sync_end - 1);
+       status = ufx_reg_write(dev, 0x201C, temp);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x201C");
+
+       status = ufx_reg_write(dev, 0x2020, 0x00000000);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x2020");
+
+       status = ufx_reg_write(dev, 0x2024, 0x00000000);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x2024");
+
+       /* Set the frame length register (#pix * 2 bytes/pixel) */
+       temp = var->xres * var->yres * 2;
+       temp = (temp + 7) & (~0x7);
+       status = ufx_reg_write(dev, 0x2028, temp);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x2028");
+
+       /* enable desired output interface & disable others */
+       status = ufx_reg_write(dev, 0x2040, 0);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x2040");
+
+       status = ufx_reg_write(dev, 0x2044, 0);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x2044");
+
+       status = ufx_reg_write(dev, 0x2048, 0);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x2048");
+
+       /* set the sync polarities & enable bit */
+       temp = 0x00000001;
+       if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+               temp |= 0x00000010;
+
+       if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+               temp |= 0x00000008;
+
+       status = ufx_reg_write(dev, 0x2040, temp);
+       check_warn_return(status, "ufx_set_vid_mode error writing 0x2040");
+
+       /* start everything back up */
+       status = ufx_enable(dev, true);
+       check_warn_return(status, "ufx_set_vid_mode error enabling display");
+
+       /* Unblank the display */
+       status = ufx_unblank(dev, true);
+       check_warn_return(status, "ufx_set_vid_mode error unblanking display");
+
+       /* enable RGB pad */
+       status = ufx_reg_write(dev, 0x8028, 0x00000003);
+       check_warn_return(status, "ufx_set_vid_mode error enabling RGB pad");
+
+       /* enable VDAC */
+       status = ufx_reg_write(dev, 0x8024, 0x00000007);
+       check_warn_return(status, "ufx_set_vid_mode error enabling VDAC");
+
+       return 0;
+}
+
+static int ufx_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+       unsigned long start = vma->vm_start;
+       unsigned long size = vma->vm_end - vma->vm_start;
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       unsigned long page, pos;
+
+       if (offset + size > info->fix.smem_len)
+               return -EINVAL;
+
+       pos = (unsigned long)info->fix.smem_start + offset;
+
+       pr_debug("mmap() framebuffer addr:%lu size:%lu\n",
+                 pos, size);
+
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+                       return -EAGAIN;
+
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       vma->vm_flags |= VM_RESERVED;   /* avoid to swap out this VMA */
+       return 0;
+}
+
+static void ufx_raw_rect(struct ufx_data *dev, u16 *cmd, int x, int y,
+       int width, int height)
+{
+       size_t packed_line_len = ALIGN((width * 2), 4);
+       size_t packed_rect_len = packed_line_len * height;
+       int line;
+
+       BUG_ON(!dev);
+       BUG_ON(!dev->info);
+
+       /* command word */
+       *((u32 *)&cmd[0]) = cpu_to_le32(0x01);
+
+       /* length word */
+       *((u32 *)&cmd[2]) = cpu_to_le32(packed_rect_len + 16);
+
+       cmd[4] = cpu_to_le16(x);
+       cmd[5] = cpu_to_le16(y);
+       cmd[6] = cpu_to_le16(width);
+       cmd[7] = cpu_to_le16(height);
+
+       /* frame base address */
+       *((u32 *)&cmd[8]) = cpu_to_le32(0);
+
+       /* color mode and horizontal resolution */
+       cmd[10] = cpu_to_le16(0x4000 | dev->info->var.xres);
+
+       /* vertical resolution */
+       cmd[11] = cpu_to_le16(dev->info->var.yres);
+
+       /* packed data */
+       for (line = 0; line < height; line++) {
+               const int line_offset = dev->info->fix.line_length * (y + line);
+               const int byte_offset = line_offset + (x * BPP);
+               memcpy(&cmd[(24 + (packed_line_len * line)) / 2],
+                       (char *)dev->info->fix.smem_start + byte_offset, width * BPP);
+       }
+}
+
+int ufx_handle_damage(struct ufx_data *dev, int x, int y,
+       int width, int height)
+{
+       size_t packed_line_len = ALIGN((width * 2), 4);
+       int len, status, urb_lines, start_line = 0;
+
+       if ((width <= 0) || (height <= 0) ||
+           (x + width > dev->info->var.xres) ||
+           (y + height > dev->info->var.yres))
+               return -EINVAL;
+
+       if (!atomic_read(&dev->usb_active))
+               return 0;
+
+       while (start_line < height) {
+               struct urb *urb = ufx_get_urb(dev);
+               if (!urb) {
+                       pr_warn("ufx_handle_damage unable to get urb");
+                       return 0;
+               }
+
+               /* assume we have enough space to transfer at least one line */
+               BUG_ON(urb->transfer_buffer_length < (24 + (width * 2)));
+
+               /* calculate the maximum number of lines we could fit in */
+               urb_lines = (urb->transfer_buffer_length - 24) / packed_line_len;
+
+               /* but we might not need this many */
+               urb_lines = min(urb_lines, (height - start_line));
+
+               memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
+
+               ufx_raw_rect(dev, urb->transfer_buffer, x, (y + start_line), width, urb_lines);
+               len = 24 + (packed_line_len * urb_lines);
+
+               status = ufx_submit_urb(dev, urb, len);
+               check_warn_return(status, "Error submitting URB");
+
+               start_line += urb_lines;
+       }
+
+       return 0;
+}
+
+/* Path triggered by usermode clients who write to filesystem
+ * e.g. cat filename > /dev/fb1
+ * Not used by X Windows or text-mode console. But useful for testing.
+ * Slow because of extra copy and we must assume all pixels dirty. */
+static ssize_t ufx_ops_write(struct fb_info *info, const char __user *buf,
+                         size_t count, loff_t *ppos)
+{
+       ssize_t result;
+       struct ufx_data *dev = info->par;
+       u32 offset = (u32) *ppos;
+
+       result = fb_sys_write(info, buf, count, ppos);
+
+       if (result > 0) {
+               int start = max((int)(offset / info->fix.line_length) - 1, 0);
+               int lines = min((u32)((result / info->fix.line_length) + 1),
+                               (u32)info->var.yres);
+
+               ufx_handle_damage(dev, 0, start, info->var.xres, lines);
+       }
+
+       return result;
+}
+
+static void ufx_ops_copyarea(struct fb_info *info,
+                               const struct fb_copyarea *area)
+{
+
+       struct ufx_data *dev = info->par;
+
+       sys_copyarea(info, area);
+
+       ufx_handle_damage(dev, area->dx, area->dy,
+                       area->width, area->height);
+}
+
+static void ufx_ops_imageblit(struct fb_info *info,
+                               const struct fb_image *image)
+{
+       struct ufx_data *dev = info->par;
+
+       sys_imageblit(info, image);
+
+       ufx_handle_damage(dev, image->dx, image->dy,
+                       image->width, image->height);
+}
+
+static void ufx_ops_fillrect(struct fb_info *info,
+                         const struct fb_fillrect *rect)
+{
+       struct ufx_data *dev = info->par;
+
+       sys_fillrect(info, rect);
+
+       ufx_handle_damage(dev, rect->dx, rect->dy, rect->width,
+                             rect->height);
+}
+
+/* NOTE: fb_defio.c is holding info->fbdefio.mutex
+ *   Touching ANY framebuffer memory that triggers a page fault
+ *   in fb_defio will cause a deadlock, when it also tries to
+ *   grab the same mutex. */
+static void ufx_dpy_deferred_io(struct fb_info *info,
+                               struct list_head *pagelist)
+{
+       struct page *cur;
+       struct fb_deferred_io *fbdefio = info->fbdefio;
+       struct ufx_data *dev = info->par;
+
+       if (!fb_defio)
+               return;
+
+       if (!atomic_read(&dev->usb_active))
+               return;
+
+       /* walk the written page list and render each to device */
+       list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+               /* create a rectangle of full screen width that encloses the
+                * entire dirty framebuffer page */
+               const int x = 0;
+               const int width = dev->info->var.xres;
+               const int y = (cur->index << PAGE_SHIFT) / (width * 2);
+               int height = (PAGE_SIZE / (width * 2)) + 1;
+               height = min(height, (int)(dev->info->var.yres - y));
+
+               BUG_ON(y >= dev->info->var.yres);
+               BUG_ON((y + height) > dev->info->var.yres);
+
+               ufx_handle_damage(dev, x, y, width, height);
+       }
+}
+
+static int ufx_ops_ioctl(struct fb_info *info, unsigned int cmd,
+                        unsigned long arg)
+{
+       struct ufx_data *dev = info->par;
+       struct dloarea *area = NULL;
+
+       if (!atomic_read(&dev->usb_active))
+               return 0;
+
+       /* TODO: Update X server to get this from sysfs instead */
+       if (cmd == UFX_IOCTL_RETURN_EDID) {
+               u8 __user *edid = (u8 __user *)arg;
+               if (copy_to_user(edid, dev->edid, dev->edid_size))
+                       return -EFAULT;
+               return 0;
+       }
+
+       /* TODO: Help propose a standard fb.h ioctl to report mmap damage */
+       if (cmd == UFX_IOCTL_REPORT_DAMAGE) {
+               /* If we have a damage-aware client, turn fb_defio "off"
+                * To avoid perf imact of unecessary page fault handling.
+                * Done by resetting the delay for this fb_info to a very
+                * long period. Pages will become writable and stay that way.
+                * Reset to normal value when all clients have closed this fb.
+                */
+               if (info->fbdefio)
+                       info->fbdefio->delay = UFX_DEFIO_WRITE_DISABLE;
+
+               area = (struct dloarea *)arg;
+
+               if (area->x < 0)
+                       area->x = 0;
+
+               if (area->x > info->var.xres)
+                       area->x = info->var.xres;
+
+               if (area->y < 0)
+                       area->y = 0;
+
+               if (area->y > info->var.yres)
+                       area->y = info->var.yres;
+
+               ufx_handle_damage(dev, area->x, area->y, area->w, area->h);
+       }
+
+       return 0;
+}
+
+/* taken from vesafb */
+static int
+ufx_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
+              unsigned blue, unsigned transp, struct fb_info *info)
+{
+       int err = 0;
+
+       if (regno >= info->cmap.len)
+               return 1;
+
+       if (regno < 16) {
+               if (info->var.red.offset == 10) {
+                       /* 1:5:5:5 */
+                       ((u32 *) (info->pseudo_palette))[regno] =
+                           ((red & 0xf800) >> 1) |
+                           ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
+               } else {
+                       /* 0:5:6:5 */
+                       ((u32 *) (info->pseudo_palette))[regno] =
+                           ((red & 0xf800)) |
+                           ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+               }
+       }
+
+       return err;
+}
+
+/* It's common for several clients to have framebuffer open simultaneously.
+ * e.g. both fbcon and X. Makes things interesting.
+ * Assumes caller is holding info->lock (for open and release at least) */
+static int ufx_ops_open(struct fb_info *info, int user)
+{
+       struct ufx_data *dev = info->par;
+
+       /* fbcon aggressively connects to first framebuffer it finds,
+        * preventing other clients (X) from working properly. Usually
+        * not what the user wants. Fail by default with option to enable. */
+       if (user == 0 && !console)
+               return -EBUSY;
+
+       /* If the USB device is gone, we don't accept new opens */
+       if (dev->virtualized)
+               return -ENODEV;
+
+       dev->fb_count++;
+
+       kref_get(&dev->kref);
+
+       if (fb_defio && (info->fbdefio == NULL)) {
+               /* enable defio at last moment if not disabled by client */
+
+               struct fb_deferred_io *fbdefio;
+
+               fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
+
+               if (fbdefio) {
+                       fbdefio->delay = UFX_DEFIO_WRITE_DELAY;
+                       fbdefio->deferred_io = ufx_dpy_deferred_io;
+               }
+
+               info->fbdefio = fbdefio;
+               fb_deferred_io_init(info);
+       }
+
+       pr_debug("open /dev/fb%d user=%d fb_info=%p count=%d",
+               info->node, user, info, dev->fb_count);
+
+       return 0;
+}
+
+/*
+ * Called when all client interfaces to start transactions have been disabled,
+ * and all references to our device instance (ufx_data) are released.
+ * Every transaction must have a reference, so we know are fully spun down
+ */
+static void ufx_free(struct kref *kref)
+{
+       struct ufx_data *dev = container_of(kref, struct ufx_data, kref);
+
+       /* this function will wait for all in-flight urbs to complete */
+       if (dev->urbs.count > 0)
+               ufx_free_urb_list(dev);
+
+       pr_debug("freeing ufx_data %p", dev);
+
+       kfree(dev);
+}
+
+static void ufx_release_urb_work(struct work_struct *work)
+{
+       struct urb_node *unode = container_of(work, struct urb_node,
+                                             release_urb_work.work);
+
+       up(&unode->dev->urbs.limit_sem);
+}
+
+static void ufx_free_framebuffer_work(struct work_struct *work)
+{
+       struct ufx_data *dev = container_of(work, struct ufx_data,
+                                           free_framebuffer_work.work);
+       struct fb_info *info = dev->info;
+       int node = info->node;
+
+       unregister_framebuffer(info);
+
+       if (info->cmap.len != 0)
+               fb_dealloc_cmap(&info->cmap);
+       if (info->monspecs.modedb)
+               fb_destroy_modedb(info->monspecs.modedb);
+       if (info->screen_base)
+               vfree(info->screen_base);
+
+       fb_destroy_modelist(&info->modelist);
+
+       dev->info = 0;
+
+       /* Assume info structure is freed after this point */
+       framebuffer_release(info);
+
+       pr_debug("fb_info for /dev/fb%d has been freed", node);
+
+       /* ref taken in probe() as part of registering framebfufer */
+       kref_put(&dev->kref, ufx_free);
+}
+
+/*
+ * Assumes caller is holding info->lock mutex (for open and release at least)
+ */
+static int ufx_ops_release(struct fb_info *info, int user)
+{
+       struct ufx_data *dev = info->par;
+
+       dev->fb_count--;
+
+       /* We can't free fb_info here - fbmem will touch it when we return */
+       if (dev->virtualized && (dev->fb_count == 0))
+               schedule_delayed_work(&dev->free_framebuffer_work, HZ);
+
+       if ((dev->fb_count == 0) && (info->fbdefio)) {
+               fb_deferred_io_cleanup(info);
+               kfree(info->fbdefio);
+               info->fbdefio = NULL;
+               info->fbops->fb_mmap = ufx_ops_mmap;
+       }
+
+       pr_debug("released /dev/fb%d user=%d count=%d",
+                 info->node, user, dev->fb_count);
+
+       kref_put(&dev->kref, ufx_free);
+
+       return 0;
+}
+
+/* Check whether a video mode is supported by the chip
+ * We start from monitor's modes, so don't need to filter that here */
+static int ufx_is_valid_mode(struct fb_videomode *mode,
+               struct fb_info *info)
+{
+       if ((mode->xres * mode->yres) > (2048 * 1152)) {
+               pr_debug("%dx%d too many pixels",
+                      mode->xres, mode->yres);
+               return 0;
+       }
+
+       if (mode->pixclock < 5000) {
+               pr_debug("%dx%d %dps pixel clock too fast",
+                      mode->xres, mode->yres, mode->pixclock);
+               return 0;
+       }
+
+       pr_debug("%dx%d (pixclk %dps %dMHz) valid mode", mode->xres, mode->yres,
+               mode->pixclock, (1000000 / mode->pixclock));
+       return 1;
+}
+
+static void ufx_var_color_format(struct fb_var_screeninfo *var)
+{
+       const struct fb_bitfield red = { 11, 5, 0 };
+       const struct fb_bitfield green = { 5, 6, 0 };
+       const struct fb_bitfield blue = { 0, 5, 0 };
+
+       var->bits_per_pixel = 16;
+       var->red = red;
+       var->green = green;
+       var->blue = blue;
+}
+
+static int ufx_ops_check_var(struct fb_var_screeninfo *var,
+                               struct fb_info *info)
+{
+       struct fb_videomode mode;
+
+       /* TODO: support dynamically changing framebuffer size */
+       if ((var->xres * var->yres * 2) > info->fix.smem_len)
+               return -EINVAL;
+
+       /* set device-specific elements of var unrelated to mode */
+       ufx_var_color_format(var);
+
+       fb_var_to_videomode(&mode, var);
+
+       if (!ufx_is_valid_mode(&mode, info))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int ufx_ops_set_par(struct fb_info *info)
+{
+       struct ufx_data *dev = info->par;
+       int result;
+       u16 *pix_framebuffer;
+       int i;
+
+       pr_debug("set_par mode %dx%d", info->var.xres, info->var.yres);
+       result = ufx_set_vid_mode(dev, &info->var);
+
+       if ((result == 0) && (dev->fb_count == 0)) {
+               /* paint greenscreen */
+               pix_framebuffer = (u16 *) info->screen_base;
+               for (i = 0; i < info->fix.smem_len / 2; i++)
+                       pix_framebuffer[i] = 0x37e6;
+
+               ufx_handle_damage(dev, 0, 0, info->var.xres, info->var.yres);
+       }
+
+       /* re-enable defio if previously disabled by damage tracking */
+       if (info->fbdefio)
+               info->fbdefio->delay = UFX_DEFIO_WRITE_DELAY;
+
+       return result;
+}
+
+/* In order to come back from full DPMS off, we need to set the mode again */
+static int ufx_ops_blank(int blank_mode, struct fb_info *info)
+{
+       struct ufx_data *dev = info->par;
+       ufx_set_vid_mode(dev, &info->var);
+       return 0;
+}
+
+static struct fb_ops ufx_ops = {
+       .owner = THIS_MODULE,
+       .fb_read = fb_sys_read,
+       .fb_write = ufx_ops_write,
+       .fb_setcolreg = ufx_ops_setcolreg,
+       .fb_fillrect = ufx_ops_fillrect,
+       .fb_copyarea = ufx_ops_copyarea,
+       .fb_imageblit = ufx_ops_imageblit,
+       .fb_mmap = ufx_ops_mmap,
+       .fb_ioctl = ufx_ops_ioctl,
+       .fb_open = ufx_ops_open,
+       .fb_release = ufx_ops_release,
+       .fb_blank = ufx_ops_blank,
+       .fb_check_var = ufx_ops_check_var,
+       .fb_set_par = ufx_ops_set_par,
+};
+
+/* Assumes &info->lock held by caller
+ * Assumes no active clients have framebuffer open */
+static int ufx_realloc_framebuffer(struct ufx_data *dev, struct fb_info *info)
+{
+       int retval = -ENOMEM;
+       int old_len = info->fix.smem_len;
+       int new_len;
+       unsigned char *old_fb = info->screen_base;
+       unsigned char *new_fb;
+
+       pr_debug("Reallocating framebuffer. Addresses will change!");
+
+       new_len = info->fix.line_length * info->var.yres;
+
+       if (PAGE_ALIGN(new_len) > old_len) {
+               /*
+                * Alloc system memory for virtual framebuffer
+                */
+               new_fb = vmalloc(new_len);
+               if (!new_fb) {
+                       pr_err("Virtual framebuffer alloc failed");
+                       goto error;
+               }
+
+               if (info->screen_base) {
+                       memcpy(new_fb, old_fb, old_len);
+                       vfree(info->screen_base);
+               }
+
+               info->screen_base = new_fb;
+               info->fix.smem_len = PAGE_ALIGN(new_len);
+               info->fix.smem_start = (unsigned long) new_fb;
+               info->flags = smscufx_info_flags;
+       }
+
+       retval = 0;
+
+error:
+       return retval;
+}
+
+/* sets up I2C Controller for 100 Kbps, std. speed, 7-bit addr, master,
+ * restart enabled, but no start byte, enable controller */
+static int ufx_i2c_init(struct ufx_data *dev)
+{
+       u32 tmp;
+
+       /* disable the controller before it can be reprogrammed */
+       int status = ufx_reg_write(dev, 0x106C, 0x00);
+       check_warn_return(status, "failed to disable I2C");
+
+       /* Setup the clock count registers
+        * (12+1) = 13 clks @ 2.5 MHz = 5.2 uS */
+       status = ufx_reg_write(dev, 0x1018, 12);
+       check_warn_return(status, "error writing 0x1018");
+
+       /* (6+8) = 14 clks @ 2.5 MHz = 5.6 uS */
+       status = ufx_reg_write(dev, 0x1014, 6);
+       check_warn_return(status, "error writing 0x1014");
+
+       status = ufx_reg_read(dev, 0x1000, &tmp);
+       check_warn_return(status, "error reading 0x1000");
+
+       /* set speed to std mode */
+       tmp &= ~(0x06);
+       tmp |= 0x02;
+
+       /* 7-bit (not 10-bit) addressing */
+       tmp &= ~(0x10);
+
+       /* enable restart conditions and master mode */
+       tmp |= 0x21;
+
+       status = ufx_reg_write(dev, 0x1000, tmp);
+       check_warn_return(status, "error writing 0x1000");
+
+       /* Set normal tx using target address 0 */
+       status = ufx_reg_clear_and_set_bits(dev, 0x1004, 0xC00, 0x000);
+       check_warn_return(status, "error setting TX mode bits in 0x1004");
+
+       /* Enable the controller */
+       status = ufx_reg_write(dev, 0x106C, 0x01);
+       check_warn_return(status, "failed to enable I2C");
+
+       return 0;
+}
+
+/* sets the I2C port mux and target address */
+static int ufx_i2c_configure(struct ufx_data *dev)
+{
+       int status = ufx_reg_write(dev, 0x106C, 0x00);
+       check_warn_return(status, "failed to disable I2C");
+
+       status = ufx_reg_write(dev, 0x3010, 0x00000000);
+       check_warn_return(status, "failed to write 0x3010");
+
+       /* A0h is std for any EDID, right shifted by one */
+       status = ufx_reg_clear_and_set_bits(dev, 0x1004, 0x3FF, (0xA0 >> 1));
+       check_warn_return(status, "failed to set TAR bits in 0x1004");
+
+       status = ufx_reg_write(dev, 0x106C, 0x01);
+       check_warn_return(status, "failed to enable I2C");
+
+       return 0;
+}
+
+/* wait for BUSY to clear, with a timeout of 50ms with 10ms sleeps. if no
+ * monitor is connected, there is no error except for timeout */
+static int ufx_i2c_wait_busy(struct ufx_data *dev)
+{
+       u32 tmp;
+       int i, status;
+
+       for (i = 0; i < 15; i++) {
+               status = ufx_reg_read(dev, 0x1100, &tmp);
+               check_warn_return(status, "0x1100 read failed");
+
+               /* if BUSY is clear, check for error */
+               if ((tmp & 0x80000000) == 0) {
+                       if (tmp & 0x20000000) {
+                               pr_warn("I2C read failed, 0x1100=0x%08x", tmp);
+                               return -EIO;
+                       }
+
+                       return 0;
+               }
+
+               /* perform the first 10 retries without delay */
+               if (i >= 10)
+                       msleep(10);
+       }
+
+       pr_warn("I2C access timed out, resetting I2C hardware");
+       status =  ufx_reg_write(dev, 0x1100, 0x40000000);
+       check_warn_return(status, "0x1100 write failed");
+
+       return -ETIMEDOUT;
+}
+
+/* reads a 128-byte EDID block from the currently selected port and TAR */
+static int ufx_read_edid(struct ufx_data *dev, u8 *edid, int edid_len)
+{
+       int i, j, status;
+       u32 *edid_u32 = (u32 *)edid;
+
+       BUG_ON(edid_len != EDID_LENGTH);
+
+       status = ufx_i2c_configure(dev);
+       if (status < 0) {
+               pr_err("ufx_i2c_configure failed");
+               return status;
+       }
+
+       memset(edid, 0xff, EDID_LENGTH);
+
+       /* Read the 128-byte EDID as 2 bursts of 64 bytes */
+       for (i = 0; i < 2; i++) {
+               u32 temp = 0x28070000 | (63 << 20) | (((u32)(i * 64)) << 8);
+               status = ufx_reg_write(dev, 0x1100, temp);
+               check_warn_return(status, "Failed to write 0x1100");
+
+               temp |= 0x80000000;
+               status = ufx_reg_write(dev, 0x1100, temp);
+               check_warn_return(status, "Failed to write 0x1100");
+
+               status = ufx_i2c_wait_busy(dev);
+               check_warn_return(status, "Timeout waiting for I2C BUSY to clear");
+
+               for (j = 0; j < 16; j++) {
+                       u32 data_reg_addr = 0x1110 + (j * 4);
+                       status = ufx_reg_read(dev, data_reg_addr, edid_u32++);
+                       check_warn_return(status, "Error reading i2c data");
+               }
+       }
+
+       /* all FF's in the first 16 bytes indicates nothing is connected */
+       for (i = 0; i < 16; i++) {
+               if (edid[i] != 0xFF) {
+                       pr_debug("edid data read succesfully");
+                       return EDID_LENGTH;
+               }
+       }
+
+       pr_warn("edid data contains all 0xff");
+       return -ETIMEDOUT;
+}
+
+/* 1) use sw default
+ * 2) Parse into various fb_info structs
+ * 3) Allocate virtual framebuffer memory to back highest res mode
+ *
+ * Parses EDID into three places used by various parts of fbdev:
+ * fb_var_screeninfo contains the timing of the monitor's preferred mode
+ * fb_info.monspecs is full parsed EDID info, including monspecs.modedb
+ * fb_info.modelist is a linked list of all monitor & VESA modes which work
+ *
+ * If EDID is not readable/valid, then modelist is all VESA modes,
+ * monspecs is NULL, and fb_var_screeninfo is set to safe VESA mode
+ * Returns 0 if successful */
+static int ufx_setup_modes(struct ufx_data *dev, struct fb_info *info,
+       char *default_edid, size_t default_edid_size)
+{
+       const struct fb_videomode *default_vmode = NULL;
+       u8 *edid;
+       int i, result = 0, tries = 3;
+
+       if (info->dev) /* only use mutex if info has been registered */
+               mutex_lock(&info->lock);
+
+       edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
+       if (!edid) {
+               result = -ENOMEM;
+               goto error;
+       }
+
+       fb_destroy_modelist(&info->modelist);
+       memset(&info->monspecs, 0, sizeof(info->monspecs));
+
+       /* Try to (re)read EDID from hardware first
+        * EDID data may return, but not parse as valid
+        * Try again a few times, in case of e.g. analog cable noise */
+       while (tries--) {
+               i = ufx_read_edid(dev, edid, EDID_LENGTH);
+
+               if (i >= EDID_LENGTH)
+                       fb_edid_to_monspecs(edid, &info->monspecs);
+
+               if (info->monspecs.modedb_len > 0) {
+                       dev->edid = edid;
+                       dev->edid_size = i;
+                       break;
+               }
+       }
+
+       /* If that fails, use a previously returned EDID if available */
+       if (info->monspecs.modedb_len == 0) {
+               pr_err("Unable to get valid EDID from device/display\n");
+
+               if (dev->edid) {
+                       fb_edid_to_monspecs(dev->edid, &info->monspecs);
+                       if (info->monspecs.modedb_len > 0)
+                               pr_err("Using previously queried EDID\n");
+               }
+       }
+
+       /* If that fails, use the default EDID we were handed */
+       if (info->monspecs.modedb_len == 0) {
+               if (default_edid_size >= EDID_LENGTH) {
+                       fb_edid_to_monspecs(default_edid, &info->monspecs);
+                       if (info->monspecs.modedb_len > 0) {
+                               memcpy(edid, default_edid, default_edid_size);
+                               dev->edid = edid;
+                               dev->edid_size = default_edid_size;
+                               pr_err("Using default/backup EDID\n");
+                       }
+               }
+       }
+
+       /* If we've got modes, let's pick a best default mode */
+       if (info->monspecs.modedb_len > 0) {
+
+               for (i = 0; i < info->monspecs.modedb_len; i++) {
+                       if (ufx_is_valid_mode(&info->monspecs.modedb[i], info))
+                               fb_add_videomode(&info->monspecs.modedb[i],
+                                       &info->modelist);
+                       else /* if we've removed top/best mode */
+                               info->monspecs.misc &= ~FB_MISC_1ST_DETAIL;
+               }
+
+               default_vmode = fb_find_best_display(&info->monspecs,
+                                                    &info->modelist);
+       }
+
+       /* If everything else has failed, fall back to safe default mode */
+       if (default_vmode == NULL) {
+
+               struct fb_videomode fb_vmode = {0};
+
+               /* Add the standard VESA modes to our modelist
+                * Since we don't have EDID, there may be modes that
+                * overspec monitor and/or are incorrect aspect ratio, etc.
+                * But at least the user has a chance to choose
+                */
+               for (i = 0; i < VESA_MODEDB_SIZE; i++) {
+                       if (ufx_is_valid_mode((struct fb_videomode *)
+                                               &vesa_modes[i], info))
+                               fb_add_videomode(&vesa_modes[i],
+                                                &info->modelist);
+               }
+
+               /* default to resolution safe for projectors
+                * (since they are most common case without EDID)
+                */
+               fb_vmode.xres = 800;
+               fb_vmode.yres = 600;
+               fb_vmode.refresh = 60;
+               default_vmode = fb_find_nearest_mode(&fb_vmode,
+                                                    &info->modelist);
+       }
+
+       /* If we have good mode and no active clients */
+       if ((default_vmode != NULL) && (dev->fb_count == 0)) {
+
+               fb_videomode_to_var(&info->var, default_vmode);
+               ufx_var_color_format(&info->var);
+
+               /* with mode size info, we can now alloc our framebuffer */
+               memcpy(&info->fix, &ufx_fix, sizeof(ufx_fix));
+               info->fix.line_length = info->var.xres *
+                       (info->var.bits_per_pixel / 8);
+
+               result = ufx_realloc_framebuffer(dev, info);
+
+       } else
+               result = -EINVAL;
+
+error:
+       if (edid && (dev->edid != edid))
+               kfree(edid);
+
+       if (info->dev)
+               mutex_unlock(&info->lock);
+
+       return result;
+}
+
+static int ufx_usb_probe(struct usb_interface *interface,
+                       const struct usb_device_id *id)
+{
+       struct usb_device *usbdev;
+       struct ufx_data *dev;
+       struct fb_info *info = 0;
+       int retval = -ENOMEM;
+       u32 id_rev, fpga_rev;
+
+       /* usb initialization */
+       usbdev = interface_to_usbdev(interface);
+       BUG_ON(!usbdev);
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               dev_err(&usbdev->dev, "ufx_usb_probe: failed alloc of dev struct\n");
+               goto error;
+       }
+
+       /* we need to wait for both usb and fbdev to spin down on disconnect */
+       kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
+       kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */
+
+       dev->udev = usbdev;
+       dev->gdev = &usbdev->dev; /* our generic struct device * */
+       usb_set_intfdata(interface, dev);
+
+       dev_dbg(dev->gdev, "%s %s - serial #%s\n",
+               usbdev->manufacturer, usbdev->product, usbdev->serial);
+       dev_dbg(dev->gdev, "vid_%04x&pid_%04x&rev_%04x driver's ufx_data struct at %p\n",
+               usbdev->descriptor.idVendor, usbdev->descriptor.idProduct,
+               usbdev->descriptor.bcdDevice, dev);
+       dev_dbg(dev->gdev, "console enable=%d\n", console);
+       dev_dbg(dev->gdev, "fb_defio enable=%d\n", fb_defio);
+
+       if (!ufx_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
+               retval = -ENOMEM;
+               dev_err(dev->gdev, "ufx_alloc_urb_list failed\n");
+               goto error;
+       }
+
+       /* We don't register a new USB class. Our client interface is fbdev */
+
+       /* allocates framebuffer driver structure, not framebuffer memory */
+       info = framebuffer_alloc(0, &usbdev->dev);
+       if (!info) {
+               retval = -ENOMEM;
+               dev_err(dev->gdev, "framebuffer_alloc failed\n");
+               goto error;
+       }
+
+       dev->info = info;
+       info->par = dev;
+       info->pseudo_palette = dev->pseudo_palette;
+       info->fbops = &ufx_ops;
+
+       retval = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (retval < 0) {
+               dev_err(dev->gdev, "fb_alloc_cmap failed %x\n", retval);
+               goto error;
+       }
+
+       INIT_DELAYED_WORK(&dev->free_framebuffer_work,
+                         ufx_free_framebuffer_work);
+
+       INIT_LIST_HEAD(&info->modelist);
+
+       retval = ufx_reg_read(dev, 0x3000, &id_rev);
+       check_warn_goto_error(retval, "error %d reading 0x3000 register from device", retval);
+       dev_dbg(dev->gdev, "ID_REV register value 0x%08x", id_rev);
+
+       retval = ufx_reg_read(dev, 0x3004, &fpga_rev);
+       check_warn_goto_error(retval, "error %d reading 0x3004 register from device", retval);
+       dev_dbg(dev->gdev, "FPGA_REV register value 0x%08x", fpga_rev);
+
+       dev_dbg(dev->gdev, "resetting device");
+       retval = ufx_lite_reset(dev);
+       check_warn_goto_error(retval, "error %d resetting device", retval);
+
+       dev_dbg(dev->gdev, "configuring system clock");
+       retval = ufx_config_sys_clk(dev);
+       check_warn_goto_error(retval, "error %d configuring system clock", retval);
+
+       dev_dbg(dev->gdev, "configuring DDR2 controller");
+       retval = ufx_config_ddr2(dev);
+       check_warn_goto_error(retval, "error %d initialising DDR2 controller", retval);
+
+       dev_dbg(dev->gdev, "configuring I2C controller");
+       retval = ufx_i2c_init(dev);
+       check_warn_goto_error(retval, "error %d initialising I2C controller", retval);
+
+       dev_dbg(dev->gdev, "selecting display mode");
+       retval = ufx_setup_modes(dev, info, NULL, 0);
+       check_warn_goto_error(retval, "unable to find common mode for display and adapter");
+
+       retval = ufx_reg_set_bits(dev, 0x4000, 0x00000001);
+       check_warn_goto_error(retval, "error %d enabling graphics engine", retval);
+
+       /* ready to begin using device */
+       atomic_set(&dev->usb_active, 1);
+
+       dev_dbg(dev->gdev, "checking var");
+       retval = ufx_ops_check_var(&info->var, info);
+       check_warn_goto_error(retval, "error %d ufx_ops_check_var", retval);
+
+       dev_dbg(dev->gdev, "setting par");
+       retval = ufx_ops_set_par(info);
+       check_warn_goto_error(retval, "error %d ufx_ops_set_par", retval);
+
+       dev_dbg(dev->gdev, "registering framebuffer");
+       retval = register_framebuffer(info);
+       check_warn_goto_error(retval, "error %d register_framebuffer", retval);
+
+       dev_info(dev->gdev, "SMSC UDX USB device /dev/fb%d attached. %dx%d resolution."
+               " Using %dK framebuffer memory\n", info->node,
+               info->var.xres, info->var.yres, info->fix.smem_len >> 10);
+
+       return 0;
+
+error:
+       if (dev) {
+               if (info) {
+                       if (info->cmap.len != 0)
+                               fb_dealloc_cmap(&info->cmap);
+                       if (info->monspecs.modedb)
+                               fb_destroy_modedb(info->monspecs.modedb);
+                       if (info->screen_base)
+                               vfree(info->screen_base);
+
+                       fb_destroy_modelist(&info->modelist);
+
+                       framebuffer_release(info);
+               }
+
+               kref_put(&dev->kref, ufx_free); /* ref for framebuffer */
+               kref_put(&dev->kref, ufx_free); /* last ref from kref_init */
+
+               /* dev has been deallocated. Do not dereference */
+       }
+
+       return retval;
+}
+
+static void ufx_usb_disconnect(struct usb_interface *interface)
+{
+       struct ufx_data *dev;
+       struct fb_info *info;
+
+       dev = usb_get_intfdata(interface);
+       info = dev->info;
+
+       pr_debug("USB disconnect starting\n");
+
+       /* we virtualize until all fb clients release. Then we free */
+       dev->virtualized = true;
+
+       /* When non-active we'll update virtual framebuffer, but no new urbs */
+       atomic_set(&dev->usb_active, 0);
+
+       usb_set_intfdata(interface, NULL);
+
+       /* if clients still have us open, will be freed on last close */
+       if (dev->fb_count == 0)
+               schedule_delayed_work(&dev->free_framebuffer_work, 0);
+
+       /* release reference taken by kref_init in probe() */
+       kref_put(&dev->kref, ufx_free);
+
+       /* consider ufx_data freed */
+}
+
+static struct usb_driver ufx_driver = {
+       .name = "smscufx",
+       .probe = ufx_usb_probe,
+       .disconnect = ufx_usb_disconnect,
+       .id_table = id_table,
+};
+
+static int __init ufx_module_init(void)
+{
+       int res;
+
+       res = usb_register(&ufx_driver);
+       if (res)
+               err("usb_register failed. Error number %d", res);
+
+       return res;
+}
+
+static void __exit ufx_module_exit(void)
+{
+       usb_deregister(&ufx_driver);
+}
+
+module_init(ufx_module_init);
+module_exit(ufx_module_exit);
+
+static void ufx_urb_completion(struct urb *urb)
+{
+       struct urb_node *unode = urb->context;
+       struct ufx_data *dev = unode->dev;
+       unsigned long flags;
+
+       /* sync/async unlink faults aren't errors */
+       if (urb->status) {
+               if (!(urb->status == -ENOENT ||
+                   urb->status == -ECONNRESET ||
+                   urb->status == -ESHUTDOWN)) {
+                       pr_err("%s - nonzero write bulk status received: %d\n",
+                               __func__, urb->status);
+                       atomic_set(&dev->lost_pixels, 1);
+               }
+       }
+
+       urb->transfer_buffer_length = dev->urbs.size; /* reset to actual */
+
+       spin_lock_irqsave(&dev->urbs.lock, flags);
+       list_add_tail(&unode->entry, &dev->urbs.list);
+       dev->urbs.available++;
+       spin_unlock_irqrestore(&dev->urbs.lock, flags);
+
+       /* When using fb_defio, we deadlock if up() is called
+        * while another is waiting. So queue to another process */
+       if (fb_defio)
+               schedule_delayed_work(&unode->release_urb_work, 0);
+       else
+               up(&dev->urbs.limit_sem);
+}
+
+static void ufx_free_urb_list(struct ufx_data *dev)
+{
+       int count = dev->urbs.count;
+       struct list_head *node;
+       struct urb_node *unode;
+       struct urb *urb;
+       int ret;
+       unsigned long flags;
+
+       pr_debug("Waiting for completes and freeing all render urbs\n");
+
+       /* keep waiting and freeing, until we've got 'em all */
+       while (count--) {
+               /* Getting interrupted means a leak, but ok at shutdown*/
+               ret = down_interruptible(&dev->urbs.limit_sem);
+               if (ret)
+                       break;
+
+               spin_lock_irqsave(&dev->urbs.lock, flags);
+
+               node = dev->urbs.list.next; /* have reserved one with sem */
+               list_del_init(node);
+
+               spin_unlock_irqrestore(&dev->urbs.lock, flags);
+
+               unode = list_entry(node, struct urb_node, entry);
+               urb = unode->urb;
+
+               /* Free each separately allocated piece */
+               usb_free_coherent(urb->dev, dev->urbs.size,
+                                 urb->transfer_buffer, urb->transfer_dma);
+               usb_free_urb(urb);
+               kfree(node);
+       }
+}
+
+static int ufx_alloc_urb_list(struct ufx_data *dev, int count, size_t size)
+{
+       int i = 0;
+       struct urb *urb;
+       struct urb_node *unode;
+       char *buf;
+
+       spin_lock_init(&dev->urbs.lock);
+
+       dev->urbs.size = size;
+       INIT_LIST_HEAD(&dev->urbs.list);
+
+       while (i < count) {
+               unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
+               if (!unode)
+                       break;
+               unode->dev = dev;
+
+               INIT_DELAYED_WORK(&unode->release_urb_work,
+                         ufx_release_urb_work);
+
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!urb) {
+                       kfree(unode);
+                       break;
+               }
+               unode->urb = urb;
+
+               buf = usb_alloc_coherent(dev->udev, size, GFP_KERNEL,
+                                        &urb->transfer_dma);
+               if (!buf) {
+                       kfree(unode);
+                       usb_free_urb(urb);
+                       break;
+               }
+
+               /* urb->transfer_buffer_length set to actual before submit */
+               usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 1),
+                       buf, size, ufx_urb_completion, unode);
+               urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+               list_add_tail(&unode->entry, &dev->urbs.list);
+
+               i++;
+       }
+
+       sema_init(&dev->urbs.limit_sem, i);
+       dev->urbs.count = i;
+       dev->urbs.available = i;
+
+       pr_debug("allocated %d %d byte urbs\n", i, (int) size);
+
+       return i;
+}
+
+static struct urb *ufx_get_urb(struct ufx_data *dev)
+{
+       int ret = 0;
+       struct list_head *entry;
+       struct urb_node *unode;
+       struct urb *urb = NULL;
+       unsigned long flags;
+
+       /* Wait for an in-flight buffer to complete and get re-queued */
+       ret = down_timeout(&dev->urbs.limit_sem, GET_URB_TIMEOUT);
+       if (ret) {
+               atomic_set(&dev->lost_pixels, 1);
+               pr_warn("wait for urb interrupted: %x available: %d\n",
+                      ret, dev->urbs.available);
+               goto error;
+       }
+
+       spin_lock_irqsave(&dev->urbs.lock, flags);
+
+       BUG_ON(list_empty(&dev->urbs.list)); /* reserved one with limit_sem */
+       entry = dev->urbs.list.next;
+       list_del_init(entry);
+       dev->urbs.available--;
+
+       spin_unlock_irqrestore(&dev->urbs.lock, flags);
+
+       unode = list_entry(entry, struct urb_node, entry);
+       urb = unode->urb;
+
+error:
+       return urb;
+}
+
+static int ufx_submit_urb(struct ufx_data *dev, struct urb *urb, size_t len)
+{
+       int ret;
+
+       BUG_ON(len > dev->urbs.size);
+
+       urb->transfer_buffer_length = len; /* set to actual payload len */
+       ret = usb_submit_urb(urb, GFP_KERNEL);
+       if (ret) {
+               ufx_urb_completion(urb); /* because no one else will */
+               atomic_set(&dev->lost_pixels, 1);
+               pr_err("usb_submit_urb error %x\n", ret);
+       }
+       return ret;
+}
+
+module_param(console, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+MODULE_PARM_DESC(console, "Allow fbcon to be used on this display");
+
+module_param(fb_defio, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+MODULE_PARM_DESC(fb_defio, "Enable fb_defio mmap support");
+
+MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>");
+MODULE_DESCRIPTION("SMSC UFX kernel framebuffer driver");
+MODULE_LICENSE("GPL");
index cd1c4dc..8e4a446 100644 (file)
@@ -744,7 +744,7 @@ static int __devinit tmiofb_probe(struct platform_device *dev)
                goto err_ioremap_vram;
        }
 
-       retval = request_irq(irq, &tmiofb_irq, IRQF_DISABLED,
+       retval = request_irq(irq, &tmiofb_irq, 0,
                                        dev_name(&dev->dev), info);
 
        if (retval)
index c6c7756..34cf019 100644 (file)
@@ -987,8 +987,8 @@ static int tridentfb_pan_display(struct fb_var_screeninfo *var,
        unsigned int offset;
 
        debug("enter\n");
-       offset = (var->xoffset + (var->yoffset * var->xres_virtual))
-               * var->bits_per_pixel / 32;
+       offset = (var->xoffset + (var->yoffset * info->var.xres_virtual))
+               * info->var.bits_per_pixel / 32;
        set_screen_start(par, offset);
        debug("exit\n");
        return 0;
index 087fc99..3473e75 100644 (file)
@@ -48,20 +48,30 @@ static const u32 udlfb_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
                FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR;
 
 /*
- * There are many DisplayLink-based products, all with unique PIDs. We are able
- * to support all volume ones (circa 2009) with a single driver, so we match
- * globally on VID. TODO: Probe() needs to detect when we might be running
- * "future" chips, and bail on those, so a compatible driver can match.
+ * There are many DisplayLink-based graphics products, all with unique PIDs.
+ * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff)
+ * We also require a match on SubClass (0x00) and Protocol (0x00),
+ * which is compatible with all known USB 2.0 era graphics chips and firmware,
+ * but allows DisplayLink to increment those for any future incompatible chips
  */
 static struct usb_device_id id_table[] = {
-       {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
+       {.idVendor = 0x17e9,
+        .bInterfaceClass = 0xff,
+        .bInterfaceSubClass = 0x00,
+        .bInterfaceProtocol = 0x00,
+        .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+               USB_DEVICE_ID_MATCH_INT_CLASS |
+               USB_DEVICE_ID_MATCH_INT_SUBCLASS |
+               USB_DEVICE_ID_MATCH_INT_PROTOCOL,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
 /* module options */
-static int console;   /* Optionally allow fbcon to consume first framebuffer */
-static int fb_defio;  /* Optionally enable experimental fb_defio mmap support */
+static int console = 1; /* Allow fbcon to open framebuffer */
+static int fb_defio = 1;  /* Detect mmap writes using page faults */
+static int shadow = 1; /* Optionally disable shadow framebuffer */
 
 /* dlfb keeps a list of urbs for efficient bulk transfers */
 static void dlfb_urb_completion(struct urb *urb);
@@ -94,17 +104,39 @@ static char *dlfb_vidreg_unlock(char *buf)
 }
 
 /*
- * On/Off for driving the DisplayLink framebuffer to the display
- *  0x00 H and V sync on
- *  0x01 H and V sync off (screen blank but powered)
- *  0x07 DPMS powerdown (requires modeset to come back)
+ * Map FB_BLANK_* to DisplayLink register
+ * DLReg FB_BLANK_*
+ * ----- -----------------------------
+ *  0x00 FB_BLANK_UNBLANK (0)
+ *  0x01 FB_BLANK (1)
+ *  0x03 FB_BLANK_VSYNC_SUSPEND (2)
+ *  0x05 FB_BLANK_HSYNC_SUSPEND (3)
+ *  0x07 FB_BLANK_POWERDOWN (4) Note: requires modeset to come back
  */
-static char *dlfb_enable_hvsync(char *buf, bool enable)
+static char *dlfb_blanking(char *buf, int fb_blank)
 {
-       if (enable)
-               return dlfb_set_register(buf, 0x1F, 0x00);
-       else
-               return dlfb_set_register(buf, 0x1F, 0x07);
+       u8 reg;
+
+       switch (fb_blank) {
+       case FB_BLANK_POWERDOWN:
+               reg = 0x07;
+               break;
+       case FB_BLANK_HSYNC_SUSPEND:
+               reg = 0x05;
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+               reg = 0x03;
+               break;
+       case FB_BLANK_NORMAL:
+               reg = 0x01;
+               break;
+       default:
+               reg = 0x00;
+       }
+
+       buf = dlfb_set_register(buf, 0x1F, reg);
+
+       return buf;
 }
 
 static char *dlfb_set_color_depth(char *buf, u8 selection)
@@ -272,13 +304,15 @@ static int dlfb_set_video_mode(struct dlfb_data *dev,
        wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len);
 
        wrptr = dlfb_set_vid_cmds(wrptr, var);
-       wrptr = dlfb_enable_hvsync(wrptr, true);
+       wrptr = dlfb_blanking(wrptr, FB_BLANK_UNBLANK);
        wrptr = dlfb_vidreg_unlock(wrptr);
 
        writesize = wrptr - buf;
 
        retval = dlfb_submit_urb(dev, urb, writesize);
 
+       dev->blank_mode = FB_BLANK_UNBLANK;
+
        return retval;
 }
 
@@ -752,14 +786,13 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
 {
 
        struct dlfb_data *dev = info->par;
-       struct dloarea *area = NULL;
 
        if (!atomic_read(&dev->usb_active))
                return 0;
 
        /* TODO: Update X server to get this from sysfs instead */
        if (cmd == DLFB_IOCTL_RETURN_EDID) {
-               char *edid = (char *)arg;
+               void __user *edid = (void __user *)arg;
                if (copy_to_user(edid, dev->edid, dev->edid_size))
                        return -EFAULT;
                return 0;
@@ -767,6 +800,11 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
 
        /* TODO: Help propose a standard fb.h ioctl to report mmap damage */
        if (cmd == DLFB_IOCTL_REPORT_DAMAGE) {
+               struct dloarea area;
+
+               if (copy_from_user(&area, (void __user *)arg,
+                                 sizeof(struct dloarea)))
+                       return -EFAULT;
 
                /*
                 * If we have a damage-aware client, turn fb_defio "off"
@@ -778,21 +816,19 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
                if (info->fbdefio)
                        info->fbdefio->delay = DL_DEFIO_WRITE_DISABLE;
 
-               area = (struct dloarea *)arg;
+               if (area.x < 0)
+                       area.x = 0;
 
-               if (area->x < 0)
-                       area->x = 0;
+               if (area.x > info->var.xres)
+                       area.x = info->var.xres;
 
-               if (area->x > info->var.xres)
-                       area->x = info->var.xres;
+               if (area.y < 0)
+                       area.y = 0;
 
-               if (area->y < 0)
-                       area->y = 0;
+               if (area.y > info->var.yres)
+                       area.y = info->var.yres;
 
-               if (area->y > info->var.yres)
-                       area->y = info->var.yres;
-
-               dlfb_handle_damage(dev, area->x, area->y, area->w, area->h,
+               dlfb_handle_damage(dev, area.x, area.y, area.w, area.h,
                           info->screen_base);
        }
 
@@ -840,7 +876,7 @@ static int dlfb_ops_open(struct fb_info *info, int user)
         * preventing other clients (X) from working properly. Usually
         * not what the user wants. Fail by default with option to enable.
         */
-       if ((user == 0) & (!console))
+       if ((user == 0) && (!console))
                return -EBUSY;
 
        /* If the USB device is gone, we don't accept new opens */
@@ -1039,32 +1075,57 @@ static int dlfb_ops_set_par(struct fb_info *info)
        return result;
 }
 
+/* To fonzi the jukebox (e.g. make blanking changes take effect) */
+static char *dlfb_dummy_render(char *buf)
+{
+       *buf++ = 0xAF;
+       *buf++ = 0x6A; /* copy */
+       *buf++ = 0x00; /* from address*/
+       *buf++ = 0x00;
+       *buf++ = 0x00;
+       *buf++ = 0x01; /* one pixel */
+       *buf++ = 0x00; /* to address */
+       *buf++ = 0x00;
+       *buf++ = 0x00;
+       return buf;
+}
+
 /*
  * In order to come back from full DPMS off, we need to set the mode again
  */
 static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
 {
        struct dlfb_data *dev = info->par;
+       char *bufptr;
+       struct urb *urb;
 
-       if (blank_mode != FB_BLANK_UNBLANK) {
-               char *bufptr;
-               struct urb *urb;
-
-               urb = dlfb_get_urb(dev);
-               if (!urb)
-                       return 0;
+       pr_info("/dev/fb%d FB_BLANK mode %d --> %d\n",
+               info->node, dev->blank_mode, blank_mode);
 
-               bufptr = (char *) urb->transfer_buffer;
-               bufptr = dlfb_vidreg_lock(bufptr);
-               bufptr = dlfb_enable_hvsync(bufptr, false);
-               bufptr = dlfb_vidreg_unlock(bufptr);
+       if ((dev->blank_mode == FB_BLANK_POWERDOWN) &&
+           (blank_mode != FB_BLANK_POWERDOWN)) {
 
-               dlfb_submit_urb(dev, urb, bufptr -
-                               (char *) urb->transfer_buffer);
-       } else {
+               /* returning from powerdown requires a fresh modeset */
                dlfb_set_video_mode(dev, &info->var);
        }
 
+       urb = dlfb_get_urb(dev);
+       if (!urb)
+               return 0;
+
+       bufptr = (char *) urb->transfer_buffer;
+       bufptr = dlfb_vidreg_lock(bufptr);
+       bufptr = dlfb_blanking(bufptr, blank_mode);
+       bufptr = dlfb_vidreg_unlock(bufptr);
+
+       /* seems like a render op is needed to have blank change take effect */
+       bufptr = dlfb_dummy_render(bufptr);
+
+       dlfb_submit_urb(dev, urb, bufptr -
+                       (char *) urb->transfer_buffer);
+
+       dev->blank_mode = blank_mode;
+
        return 0;
 }
 
@@ -1097,7 +1158,7 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info)
        int new_len;
        unsigned char *old_fb = info->screen_base;
        unsigned char *new_fb;
-       unsigned char *new_back;
+       unsigned char *new_back = 0;
 
        pr_warn("Reallocating framebuffer. Addresses will change!\n");
 
@@ -1129,7 +1190,8 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info)
                 * But with imperfect damage info we may send pixels over USB
                 * that were, in fact, unchanged - wasting limited USB bandwidth
                 */
-               new_back = vzalloc(new_len);
+               if (shadow)
+                       new_back = vzalloc(new_len);
                if (!new_back)
                        pr_info("No shadow/backing buffer allocated\n");
                else {
@@ -1430,21 +1492,30 @@ static int dlfb_select_std_channel(struct dlfb_data *dev)
 }
 
 static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev,
-                                       struct usb_device *usbdev)
+                                       struct usb_interface *interface)
 {
        char *desc;
        char *buf;
        char *desc_end;
 
-       u8 total_len = 0;
+       int total_len = 0;
 
        buf = kzalloc(MAX_VENDOR_DESCRIPTOR_SIZE, GFP_KERNEL);
        if (!buf)
                return false;
        desc = buf;
 
-       total_len = usb_get_descriptor(usbdev, 0x5f, /* vendor specific */
-                                   0, desc, MAX_VENDOR_DESCRIPTOR_SIZE);
+       total_len = usb_get_descriptor(interface_to_usbdev(interface),
+                                       0x5f, /* vendor specific */
+                                       0, desc, MAX_VENDOR_DESCRIPTOR_SIZE);
+
+       /* if not found, look in configuration descriptor */
+       if (total_len < 0) {
+               if (0 == usb_get_extra_descriptor(interface->cur_altsetting,
+                       0x5f, &desc))
+                       total_len = (int) desc[0];
+       }
+
        if (total_len > 5) {
                pr_info("vendor descriptor length:%x data:%02x %02x %02x %02x" \
                        "%02x %02x %02x %02x %02x %02x %02x\n",
@@ -1485,6 +1556,8 @@ static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev,
                        }
                        desc += length;
                }
+       } else {
+               pr_info("vendor descriptor not available (%d)\n", total_len);
        }
 
        goto success;
@@ -1531,10 +1604,11 @@ static int dlfb_usb_probe(struct usb_interface *interface,
                usbdev->descriptor.bcdDevice, dev);
        pr_info("console enable=%d\n", console);
        pr_info("fb_defio enable=%d\n", fb_defio);
+       pr_info("shadow enable=%d\n", shadow);
 
        dev->sku_pixel_limit = 2048 * 1152; /* default to maximum */
 
-       if (!dlfb_parse_vendor_descriptor(dev, usbdev)) {
+       if (!dlfb_parse_vendor_descriptor(dev, interface)) {
                pr_err("firmware not recognized. Assume incompatible device\n");
                goto error;
        }
@@ -1548,7 +1622,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
        /* We don't register a new USB class. Our client interface is fbdev */
 
        /* allocates framebuffer driver structure, not framebuffer memory */
-       info = framebuffer_alloc(0, &usbdev->dev);
+       info = framebuffer_alloc(0, &interface->dev);
        if (!info) {
                retval = -ENOMEM;
                pr_err("framebuffer_alloc failed\n");
@@ -1883,10 +1957,13 @@ static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len)
 }
 
 module_param(console, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
-MODULE_PARM_DESC(console, "Allow fbcon to consume first framebuffer found");
+MODULE_PARM_DESC(console, "Allow fbcon to open framebuffer");
 
 module_param(fb_defio, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
-MODULE_PARM_DESC(fb_defio, "Enable fb_defio mmap support. *Experimental*");
+MODULE_PARM_DESC(fb_defio, "Page fault detection of mmap writes");
+
+module_param(shadow, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+MODULE_PARM_DESC(shadow, "Shadow vid mem. Disable to save mem but lose perf");
 
 MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
              "Jaya Kumar <jayakumar.lkml@gmail.com>, "
index 6b52bf6..3f5a041 100644 (file)
@@ -555,7 +555,7 @@ static int __init valkyrie_init_info(struct fb_info *info,
 
 
 /*
- * Parse user speficied options (`video=valkyriefb:')
+ * Parse user specified options (`video=valkyriefb:')
  */
 int __init valkyriefb_setup(char *options)
 {
index bc67251..bf2f780 100644 (file)
@@ -395,8 +395,8 @@ static int vfb_pan_display(struct fb_var_screeninfo *var,
                    || var->xoffset)
                        return -EINVAL;
        } else {
-               if (var->xoffset + var->xres > info->var.xres_virtual ||
-                   var->yoffset + var->yres > info->var.yres_virtual)
+               if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+                   var->yoffset + info->var.yres > info->var.yres_virtual)
                        return -EINVAL;
        }
        info->var.xoffset = var->xoffset;
index 305c975..0267acd 100644 (file)
@@ -207,7 +207,7 @@ static void vga16fb_pan_var(struct fb_info *info,
         * granularity if someone supports xoffset in bit resolution */
        vga_io_r(VGA_IS1_RC);           /* reset flip-flop */
        vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
-       if (var->bits_per_pixel == 8)
+       if (info->var.bits_per_pixel == 8)
                vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
        else
                vga_io_w(VGA_ATT_IW, xoffset & 7);
index b1f3647..9138e51 100644 (file)
@@ -172,30 +172,20 @@ static int tmds_register_read_bytes(int index, u8 *buff, int buff_len)
 }
 
 /* DVI Set Mode */
-void viafb_dvi_set_mode(struct VideoModeTable *mode, int mode_bpp,
-       int set_iga)
+void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, int iga)
 {
-       struct VideoModeTable *rb_mode;
-       struct crt_mode_table *pDviTiming;
-       unsigned long desirePixelClock, maxPixelClock;
-       pDviTiming = mode->crtc;
-       desirePixelClock = pDviTiming->refresh_rate
-               * pDviTiming->crtc.hor_total * pDviTiming->crtc.ver_total
-               / 1000000;
-       maxPixelClock = (unsigned long)viaparinfo->
-               tmds_setting_info->max_pixel_clock;
-
-       DEBUG_MSG(KERN_INFO "\nDVI_set_mode!!\n");
-
-       if ((maxPixelClock != 0) && (desirePixelClock > maxPixelClock)) {
-               rb_mode = viafb_get_rb_mode(mode->crtc[0].crtc.hor_addr,
-                       mode->crtc[0].crtc.ver_addr);
-               if (rb_mode) {
-                       mode = rb_mode;
-                       pDviTiming = rb_mode->crtc;
-               }
+       struct fb_var_screeninfo dvi_var = *var;
+       struct crt_mode_table *rb_mode;
+       int maxPixelClock;
+
+       maxPixelClock = viaparinfo->shared->tmds_setting_info.max_pixel_clock;
+       if (maxPixelClock && PICOS2KHZ(var->pixclock) / 1000 > maxPixelClock) {
+               rb_mode = viafb_get_best_rb_mode(var->xres, var->yres, 60);
+               if (rb_mode)
+                       viafb_fill_var_timing_info(&dvi_var, rb_mode);
        }
-       viafb_fill_crtc_timing(pDviTiming, mode, mode_bpp / 8, set_iga);
+
+       viafb_fill_crtc_timing(&dvi_var, iga);
 }
 
 /* Sense DVI Connector */
index f473dd0..e2116aa 100644 (file)
@@ -59,7 +59,6 @@ void viafb_dvi_enable(void);
 bool __devinit viafb_tmds_trasmitter_identify(void);
 void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
        struct tmds_setting_information *tmds_setting);
-void viafb_dvi_set_mode(struct VideoModeTable *videoMode, int mode_bpp,
-       int set_iga);
+void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, int iga);
 
 #endif /* __DVI_H__ */
index e10d824..3102171 100644 (file)
@@ -35,6 +35,8 @@ int viafb_LCD_ON ;
 int viafb_LCD2_ON;
 int viafb_SAMM_ON;
 int viafb_dual_fb;
+unsigned int viafb_second_xres = 640;
+unsigned int viafb_second_yres = 480;
 int viafb_hotplug_Xres = 640;
 int viafb_hotplug_Yres = 480;
 int viafb_hotplug_bpp = 32;
index ff969dc..275dbbb 100644 (file)
@@ -67,6 +67,8 @@ extern int viafb_lcd_dsp_method;
 extern int viafb_lcd_mode;
 
 extern int viafb_CRT_ON;
+extern unsigned int viafb_second_xres;
+extern unsigned int viafb_second_yres;
 extern int viafb_hotplug_Xres;
 extern int viafb_hotplug_Yres;
 extern int viafb_hotplug_bpp;
index 47b1353..d5aaca9 100644 (file)
@@ -191,67 +191,6 @@ static struct fetch_count fetch_count_reg = {
        {IGA2_FETCH_COUNT_REG_NUM, {{CR65, 0, 7}, {CR67, 2, 3} } }
 };
 
-static struct iga1_crtc_timing iga1_crtc_reg = {
-       /* IGA1 Horizontal Total */
-       {IGA1_HOR_TOTAL_REG_NUM, {{CR00, 0, 7}, {CR36, 3, 3} } },
-       /* IGA1 Horizontal Addressable Video */
-       {IGA1_HOR_ADDR_REG_NUM, {{CR01, 0, 7} } },
-       /* IGA1 Horizontal Blank Start */
-       {IGA1_HOR_BLANK_START_REG_NUM, {{CR02, 0, 7} } },
-       /* IGA1 Horizontal Blank End */
-       {IGA1_HOR_BLANK_END_REG_NUM,
-        {{CR03, 0, 4}, {CR05, 7, 7}, {CR33, 5, 5} } },
-       /* IGA1 Horizontal Sync Start */
-       {IGA1_HOR_SYNC_START_REG_NUM, {{CR04, 0, 7}, {CR33, 4, 4} } },
-       /* IGA1 Horizontal Sync End */
-       {IGA1_HOR_SYNC_END_REG_NUM, {{CR05, 0, 4} } },
-       /* IGA1 Vertical Total */
-       {IGA1_VER_TOTAL_REG_NUM,
-        {{CR06, 0, 7}, {CR07, 0, 0}, {CR07, 5, 5}, {CR35, 0, 0} } },
-       /* IGA1 Vertical Addressable Video */
-       {IGA1_VER_ADDR_REG_NUM,
-        {{CR12, 0, 7}, {CR07, 1, 1}, {CR07, 6, 6}, {CR35, 2, 2} } },
-       /* IGA1 Vertical Blank Start */
-       {IGA1_VER_BLANK_START_REG_NUM,
-        {{CR15, 0, 7}, {CR07, 3, 3}, {CR09, 5, 5}, {CR35, 3, 3} } },
-       /* IGA1 Vertical Blank End */
-       {IGA1_VER_BLANK_END_REG_NUM, {{CR16, 0, 7} } },
-       /* IGA1 Vertical Sync Start */
-       {IGA1_VER_SYNC_START_REG_NUM,
-        {{CR10, 0, 7}, {CR07, 2, 2}, {CR07, 7, 7}, {CR35, 1, 1} } },
-       /* IGA1 Vertical Sync End */
-       {IGA1_VER_SYNC_END_REG_NUM, {{CR11, 0, 3} } }
-};
-
-static struct iga2_crtc_timing iga2_crtc_reg = {
-       /* IGA2 Horizontal Total */
-       {IGA2_HOR_TOTAL_REG_NUM, {{CR50, 0, 7}, {CR55, 0, 3} } },
-       /* IGA2 Horizontal Addressable Video */
-       {IGA2_HOR_ADDR_REG_NUM, {{CR51, 0, 7}, {CR55, 4, 6} } },
-       /* IGA2 Horizontal Blank Start */
-       {IGA2_HOR_BLANK_START_REG_NUM, {{CR52, 0, 7}, {CR54, 0, 2} } },
-       /* IGA2 Horizontal Blank End */
-       {IGA2_HOR_BLANK_END_REG_NUM,
-        {{CR53, 0, 7}, {CR54, 3, 5}, {CR5D, 6, 6} } },
-       /* IGA2 Horizontal Sync Start */
-       {IGA2_HOR_SYNC_START_REG_NUM,
-        {{CR56, 0, 7}, {CR54, 6, 7}, {CR5C, 7, 7}, {CR5D, 7, 7} } },
-       /* IGA2 Horizontal Sync End */
-       {IGA2_HOR_SYNC_END_REG_NUM, {{CR57, 0, 7}, {CR5C, 6, 6} } },
-       /* IGA2 Vertical Total */
-       {IGA2_VER_TOTAL_REG_NUM, {{CR58, 0, 7}, {CR5D, 0, 2} } },
-       /* IGA2 Vertical Addressable Video */
-       {IGA2_VER_ADDR_REG_NUM, {{CR59, 0, 7}, {CR5D, 3, 5} } },
-       /* IGA2 Vertical Blank Start */
-       {IGA2_VER_BLANK_START_REG_NUM, {{CR5A, 0, 7}, {CR5C, 0, 2} } },
-       /* IGA2 Vertical Blank End */
-       {IGA2_VER_BLANK_END_REG_NUM, {{CR5B, 0, 7}, {CR5C, 3, 5} } },
-       /* IGA2 Vertical Sync Start */
-       {IGA2_VER_SYNC_START_REG_NUM, {{CR5E, 0, 7}, {CR5F, 5, 7} } },
-       /* IGA2 Vertical Sync End */
-       {IGA2_VER_SYNC_END_REG_NUM, {{CR5F, 0, 4} } }
-};
-
 static struct rgbLUT palLUT_table[] = {
        /* {R,G,B} */
        /* Index 0x00~0x03 */
@@ -1528,302 +1467,40 @@ void viafb_set_vclock(u32 clk, int set_iga)
        via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */
 }
 
-void viafb_load_crtc_timing(struct display_timing device_timing,
-       int set_iga)
+static struct display_timing var_to_timing(const struct fb_var_screeninfo *var)
 {
-       int i;
-       int viafb_load_reg_num = 0;
-       int reg_value = 0;
-       struct io_register *reg = NULL;
-
-       viafb_unlock_crt();
-
-       for (i = 0; i < 12; i++) {
-               if (set_iga == IGA1) {
-                       switch (i) {
-                       case H_TOTAL_INDEX:
-                               reg_value =
-                                   IGA1_HOR_TOTAL_FORMULA(device_timing.
-                                                          hor_total);
-                               viafb_load_reg_num =
-                                       iga1_crtc_reg.hor_total.reg_num;
-                               reg = iga1_crtc_reg.hor_total.reg;
-                               break;
-                       case H_ADDR_INDEX:
-                               reg_value =
-                                   IGA1_HOR_ADDR_FORMULA(device_timing.
-                                                         hor_addr);
-                               viafb_load_reg_num =
-                                       iga1_crtc_reg.hor_addr.reg_num;
-                               reg = iga1_crtc_reg.hor_addr.reg;
-                               break;
-                       case H_BLANK_START_INDEX:
-                               reg_value =
-                                   IGA1_HOR_BLANK_START_FORMULA
-                                   (device_timing.hor_blank_start);
-                               viafb_load_reg_num =
-                                   iga1_crtc_reg.hor_blank_start.reg_num;
-                               reg = iga1_crtc_reg.hor_blank_start.reg;
-                               break;
-                       case H_BLANK_END_INDEX:
-                               reg_value =
-                                   IGA1_HOR_BLANK_END_FORMULA
-                                   (device_timing.hor_blank_start,
-                                    device_timing.hor_blank_end);
-                               viafb_load_reg_num =
-                                   iga1_crtc_reg.hor_blank_end.reg_num;
-                               reg = iga1_crtc_reg.hor_blank_end.reg;
-                               break;
-                       case H_SYNC_START_INDEX:
-                               reg_value =
-                                   IGA1_HOR_SYNC_START_FORMULA
-                                   (device_timing.hor_sync_start);
-                               viafb_load_reg_num =
-                                   iga1_crtc_reg.hor_sync_start.reg_num;
-                               reg = iga1_crtc_reg.hor_sync_start.reg;
-                               break;
-                       case H_SYNC_END_INDEX:
-                               reg_value =
-                                   IGA1_HOR_SYNC_END_FORMULA
-                                   (device_timing.hor_sync_start,
-                                    device_timing.hor_sync_end);
-                               viafb_load_reg_num =
-                                   iga1_crtc_reg.hor_sync_end.reg_num;
-                               reg = iga1_crtc_reg.hor_sync_end.reg;
-                               break;
-                       case V_TOTAL_INDEX:
-                               reg_value =
-                                   IGA1_VER_TOTAL_FORMULA(device_timing.
-                                                          ver_total);
-                               viafb_load_reg_num =
-                                       iga1_crtc_reg.ver_total.reg_num;
-                               reg = iga1_crtc_reg.ver_total.reg;
-                               break;
-                       case V_ADDR_INDEX:
-                               reg_value =
-                                   IGA1_VER_ADDR_FORMULA(device_timing.
-                                                         ver_addr);
-                               viafb_load_reg_num =
-                                       iga1_crtc_reg.ver_addr.reg_num;
-                               reg = iga1_crtc_reg.ver_addr.reg;
-                               break;
-                       case V_BLANK_START_INDEX:
-                               reg_value =
-                                   IGA1_VER_BLANK_START_FORMULA
-                                   (device_timing.ver_blank_start);
-                               viafb_load_reg_num =
-                                   iga1_crtc_reg.ver_blank_start.reg_num;
-                               reg = iga1_crtc_reg.ver_blank_start.reg;
-                               break;
-                       case V_BLANK_END_INDEX:
-                               reg_value =
-                                   IGA1_VER_BLANK_END_FORMULA
-                                   (device_timing.ver_blank_start,
-                                    device_timing.ver_blank_end);
-                               viafb_load_reg_num =
-                                   iga1_crtc_reg.ver_blank_end.reg_num;
-                               reg = iga1_crtc_reg.ver_blank_end.reg;
-                               break;
-                       case V_SYNC_START_INDEX:
-                               reg_value =
-                                   IGA1_VER_SYNC_START_FORMULA
-                                   (device_timing.ver_sync_start);
-                               viafb_load_reg_num =
-                                   iga1_crtc_reg.ver_sync_start.reg_num;
-                               reg = iga1_crtc_reg.ver_sync_start.reg;
-                               break;
-                       case V_SYNC_END_INDEX:
-                               reg_value =
-                                   IGA1_VER_SYNC_END_FORMULA
-                                   (device_timing.ver_sync_start,
-                                    device_timing.ver_sync_end);
-                               viafb_load_reg_num =
-                                   iga1_crtc_reg.ver_sync_end.reg_num;
-                               reg = iga1_crtc_reg.ver_sync_end.reg;
-                               break;
-
-                       }
-               }
-
-               if (set_iga == IGA2) {
-                       switch (i) {
-                       case H_TOTAL_INDEX:
-                               reg_value =
-                                   IGA2_HOR_TOTAL_FORMULA(device_timing.
-                                                          hor_total);
-                               viafb_load_reg_num =
-                                       iga2_crtc_reg.hor_total.reg_num;
-                               reg = iga2_crtc_reg.hor_total.reg;
-                               break;
-                       case H_ADDR_INDEX:
-                               reg_value =
-                                   IGA2_HOR_ADDR_FORMULA(device_timing.
-                                                         hor_addr);
-                               viafb_load_reg_num =
-                                       iga2_crtc_reg.hor_addr.reg_num;
-                               reg = iga2_crtc_reg.hor_addr.reg;
-                               break;
-                       case H_BLANK_START_INDEX:
-                               reg_value =
-                                   IGA2_HOR_BLANK_START_FORMULA
-                                   (device_timing.hor_blank_start);
-                               viafb_load_reg_num =
-                                   iga2_crtc_reg.hor_blank_start.reg_num;
-                               reg = iga2_crtc_reg.hor_blank_start.reg;
-                               break;
-                       case H_BLANK_END_INDEX:
-                               reg_value =
-                                   IGA2_HOR_BLANK_END_FORMULA
-                                   (device_timing.hor_blank_start,
-                                    device_timing.hor_blank_end);
-                               viafb_load_reg_num =
-                                   iga2_crtc_reg.hor_blank_end.reg_num;
-                               reg = iga2_crtc_reg.hor_blank_end.reg;
-                               break;
-                       case H_SYNC_START_INDEX:
-                               reg_value =
-                                   IGA2_HOR_SYNC_START_FORMULA
-                                   (device_timing.hor_sync_start);
-                               if (UNICHROME_CN700 <=
-                                       viaparinfo->chip_info->gfx_chip_name)
-                                       viafb_load_reg_num =
-                                           iga2_crtc_reg.hor_sync_start.
-                                           reg_num;
-                               else
-                                       viafb_load_reg_num = 3;
-                               reg = iga2_crtc_reg.hor_sync_start.reg;
-                               break;
-                       case H_SYNC_END_INDEX:
-                               reg_value =
-                                   IGA2_HOR_SYNC_END_FORMULA
-                                   (device_timing.hor_sync_start,
-                                    device_timing.hor_sync_end);
-                               viafb_load_reg_num =
-                                   iga2_crtc_reg.hor_sync_end.reg_num;
-                               reg = iga2_crtc_reg.hor_sync_end.reg;
-                               break;
-                       case V_TOTAL_INDEX:
-                               reg_value =
-                                   IGA2_VER_TOTAL_FORMULA(device_timing.
-                                                          ver_total);
-                               viafb_load_reg_num =
-                                       iga2_crtc_reg.ver_total.reg_num;
-                               reg = iga2_crtc_reg.ver_total.reg;
-                               break;
-                       case V_ADDR_INDEX:
-                               reg_value =
-                                   IGA2_VER_ADDR_FORMULA(device_timing.
-                                                         ver_addr);
-                               viafb_load_reg_num =
-                                       iga2_crtc_reg.ver_addr.reg_num;
-                               reg = iga2_crtc_reg.ver_addr.reg;
-                               break;
-                       case V_BLANK_START_INDEX:
-                               reg_value =
-                                   IGA2_VER_BLANK_START_FORMULA
-                                   (device_timing.ver_blank_start);
-                               viafb_load_reg_num =
-                                   iga2_crtc_reg.ver_blank_start.reg_num;
-                               reg = iga2_crtc_reg.ver_blank_start.reg;
-                               break;
-                       case V_BLANK_END_INDEX:
-                               reg_value =
-                                   IGA2_VER_BLANK_END_FORMULA
-                                   (device_timing.ver_blank_start,
-                                    device_timing.ver_blank_end);
-                               viafb_load_reg_num =
-                                   iga2_crtc_reg.ver_blank_end.reg_num;
-                               reg = iga2_crtc_reg.ver_blank_end.reg;
-                               break;
-                       case V_SYNC_START_INDEX:
-                               reg_value =
-                                   IGA2_VER_SYNC_START_FORMULA
-                                   (device_timing.ver_sync_start);
-                               viafb_load_reg_num =
-                                   iga2_crtc_reg.ver_sync_start.reg_num;
-                               reg = iga2_crtc_reg.ver_sync_start.reg;
-                               break;
-                       case V_SYNC_END_INDEX:
-                               reg_value =
-                                   IGA2_VER_SYNC_END_FORMULA
-                                   (device_timing.ver_sync_start,
-                                    device_timing.ver_sync_end);
-                               viafb_load_reg_num =
-                                   iga2_crtc_reg.ver_sync_end.reg_num;
-                               reg = iga2_crtc_reg.ver_sync_end.reg;
-                               break;
-
-                       }
-               }
-               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
-       }
-
-       viafb_lock_crt();
+       struct display_timing timing;
+
+       timing.hor_addr = var->xres;
+       timing.hor_sync_start = timing.hor_addr + var->right_margin;
+       timing.hor_sync_end = timing.hor_sync_start + var->hsync_len;
+       timing.hor_total = timing.hor_sync_end + var->left_margin;
+       timing.hor_blank_start = timing.hor_addr;
+       timing.hor_blank_end = timing.hor_total;
+       timing.ver_addr = var->yres;
+       timing.ver_sync_start = timing.ver_addr + var->lower_margin;
+       timing.ver_sync_end = timing.ver_sync_start + var->vsync_len;
+       timing.ver_total = timing.ver_sync_end + var->upper_margin;
+       timing.ver_blank_start = timing.ver_addr;
+       timing.ver_blank_end = timing.ver_total;
+       return timing;
 }
 
-void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
-       struct VideoModeTable *video_mode, int bpp_byte, int set_iga)
+void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, int iga)
 {
-       struct display_timing crt_reg;
-       int i;
-       int index = 0;
-       int h_addr, v_addr;
-       u32 clock, refresh = viafb_refresh;
-
-       if (viafb_SAMM_ON && set_iga == IGA2)
-               refresh = viafb_refresh1;
-
-       for (i = 0; i < video_mode->mode_array; i++) {
-               index = i;
-
-               if (crt_table[i].refresh_rate == refresh)
-                       break;
-       }
+       struct display_timing crt_reg = var_to_timing(var);
 
-       crt_reg = crt_table[index].crtc;
+       if (iga == IGA1)
+               via_set_primary_timing(&crt_reg);
+       else if (iga == IGA2)
+               via_set_secondary_timing(&crt_reg);
 
-       /* Mode 640x480 has border, but LCD/DFP didn't have border. */
-       /* So we would delete border. */
-       if ((viafb_LCD_ON | viafb_DVI_ON)
-           && video_mode->crtc[0].crtc.hor_addr == 640
-           && video_mode->crtc[0].crtc.ver_addr == 480
-           && refresh == 60) {
-               /* The border is 8 pixels. */
-               crt_reg.hor_blank_start = crt_reg.hor_blank_start - 8;
-
-               /* Blanking time should add left and right borders. */
-               crt_reg.hor_blank_end = crt_reg.hor_blank_end + 16;
-       }
-
-       h_addr = crt_reg.hor_addr;
-       v_addr = crt_reg.ver_addr;
-       if (set_iga == IGA1) {
-               viafb_unlock_crt();
-               viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
-       }
-
-       switch (set_iga) {
-       case IGA1:
-               viafb_load_crtc_timing(crt_reg, IGA1);
-               break;
-       case IGA2:
-               viafb_load_crtc_timing(crt_reg, IGA2);
-               break;
-       }
-
-       viafb_lock_crt();
-       viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
-       viafb_load_fetch_count_reg(h_addr, bpp_byte, set_iga);
-
-       /* load FIFO */
-       if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
-           && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400))
-               viafb_load_FIFO_reg(set_iga, h_addr, v_addr);
-
-       clock = crt_reg.hor_total * crt_reg.ver_total
-               * crt_table[index].refresh_rate;
-       viafb_set_vclock(clock, set_iga);
+       viafb_load_fetch_count_reg(var->xres, var->bits_per_pixel / 8, iga);
+       if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266
+               && viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400)
+               viafb_load_FIFO_reg(iga, var->xres, var->yres);
 
+       viafb_set_vclock(PICOS2KHZ(var->pixclock) * 1000, iga);
 }
 
 void __devinit viafb_init_chip_info(int chip_type)
@@ -2092,23 +1769,9 @@ static u8 get_sync(struct fb_info *info)
        return polarity;
 }
 
-int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
-       struct VideoModeTable *vmode_tbl1, int video_bpp1)
+static void hw_init(void)
 {
-       int i, j;
-       int port;
-       u32 devices = viaparinfo->shared->iga1_devices
-               | viaparinfo->shared->iga2_devices;
-       u8 value, index, mask;
-       struct crt_mode_table *crt_timing;
-       struct crt_mode_table *crt_timing1 = NULL;
-
-       device_screen_off();
-       crt_timing = vmode_tbl->crtc;
-
-       if (viafb_SAMM_ON == 1) {
-               crt_timing1 = vmode_tbl1->crtc;
-       }
+       int i;
 
        inb(VIAStatus);
        outb(0x00, VIAAR);
@@ -2147,9 +1810,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
                break;
        }
 
+       /* probably this should go to the scaling code one day */
        viafb_write_regx(scaling_parameters, ARRAY_SIZE(scaling_parameters));
-       device_off();
-       via_set_state(devices, VIA_STATE_OFF);
 
        /* Fill VPIT Parameters */
        /* Write Misc Register */
@@ -2175,12 +1837,29 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
        inb(VIAStatus);
        outb(0x20, VIAAR);
 
+       load_fix_bit_crtc_reg();
+}
+
+int viafb_setmode(int video_bpp, int video_bpp1)
+{
+       int j;
+       int port;
+       u32 devices = viaparinfo->shared->iga1_devices
+               | viaparinfo->shared->iga2_devices;
+       u8 value, index, mask;
+       struct fb_var_screeninfo var2;
+
+       device_screen_off();
+       device_off();
+       via_set_state(devices, VIA_STATE_OFF);
+
+       hw_init();
+
        /* Update Patch Register */
 
        if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266
-           || viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400)
-           && vmode_tbl->crtc[0].crtc.hor_addr == 1024
-           && vmode_tbl->crtc[0].crtc.ver_addr == 768) {
+               || viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400)
+               && viafbinfo->var.xres == 1024 && viafbinfo->var.yres == 768) {
                for (j = 0; j < res_patch_table[0].table_length; j++) {
                        index = res_patch_table[0].io_reg_table[j].index;
                        port = res_patch_table[0].io_reg_table[j].port;
@@ -2190,7 +1869,6 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
                }
        }
 
-       load_fix_bit_crtc_reg();
        via_set_primary_pitch(viafbinfo->fix.line_length);
        via_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length
                : viafbinfo->fix.line_length);
@@ -2208,23 +1886,28 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
 
        /* Clear On Screen */
 
+       if (viafb_dual_fb) {
+               var2 = viafbinfo1->var;
+       } else if (viafb_SAMM_ON) {
+               viafb_fill_var_timing_info(&var2, viafb_get_best_mode(
+                       viafb_second_xres, viafb_second_yres, viafb_refresh1));
+               var2.bits_per_pixel = viafbinfo->var.bits_per_pixel;
+       }
+
        /* CRT set mode */
        if (viafb_CRT_ON) {
-               if (viafb_SAMM_ON &&
-                       viaparinfo->shared->iga2_devices & VIA_CRT) {
-                       viafb_fill_crtc_timing(crt_timing1, vmode_tbl1,
-                               video_bpp1 / 8, IGA2);
-               } else {
-                       viafb_fill_crtc_timing(crt_timing, vmode_tbl,
-                               video_bpp / 8,
+               if (viaparinfo->shared->iga2_devices & VIA_CRT
+                       && viafb_SAMM_ON)
+                       viafb_fill_crtc_timing(&var2, IGA2);
+               else
+                       viafb_fill_crtc_timing(&viafbinfo->var,
                                (viaparinfo->shared->iga1_devices & VIA_CRT)
                                ? IGA1 : IGA2);
-               }
 
                /* Patch if set_hres is not 8 alignment (1366) to viafb_setmode
                to 8 alignment (1368),there is several pixels (2 pixels)
                on right side of screen. */
-               if (vmode_tbl->crtc[0].crtc.hor_addr % 8) {
+               if (viafbinfo->var.xres % 8) {
                        viafb_unlock_crt();
                        viafb_write_reg(CR02, VIACR,
                                viafb_read_reg(VIACR, CR02) - 1);
@@ -2233,31 +1916,20 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
        }
 
        if (viafb_DVI_ON) {
-               if (viafb_SAMM_ON &&
-                       (viaparinfo->tmds_setting_info->iga_path == IGA2)) {
-                       viafb_dvi_set_mode(viafb_get_mode
-                                    (viaparinfo->tmds_setting_info->h_active,
-                                     viaparinfo->tmds_setting_info->
-                                     v_active),
-                                    video_bpp1, viaparinfo->
-                                    tmds_setting_info->iga_path);
-               } else {
-                       viafb_dvi_set_mode(viafb_get_mode
-                                    (viaparinfo->tmds_setting_info->h_active,
-                                     viaparinfo->
-                                     tmds_setting_info->v_active),
-                                    video_bpp, viaparinfo->
-                                    tmds_setting_info->iga_path);
-               }
+               if (viaparinfo->shared->tmds_setting_info.iga_path == IGA2
+                       && viafb_SAMM_ON)
+                       viafb_dvi_set_mode(&var2, IGA2);
+               else
+                       viafb_dvi_set_mode(&viafbinfo->var,
+                               viaparinfo->tmds_setting_info->iga_path);
        }
 
        if (viafb_LCD_ON) {
                if (viafb_SAMM_ON &&
                        (viaparinfo->lvds_setting_info->iga_path == IGA2)) {
                        viaparinfo->lvds_setting_info->bpp = video_bpp1;
-                       viafb_lcd_set_mode(crt_timing1, viaparinfo->
-                               lvds_setting_info,
-                                    &viaparinfo->chip_info->lvds_chip_info);
+                       viafb_lcd_set_mode(viaparinfo->lvds_setting_info,
+                               &viaparinfo->chip_info->lvds_chip_info);
                } else {
                        /* IGA1 doesn't have LCD scaling, so set it center. */
                        if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
@@ -2265,18 +1937,16 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
                                    LCD_CENTERING;
                        }
                        viaparinfo->lvds_setting_info->bpp = video_bpp;
-                       viafb_lcd_set_mode(crt_timing, viaparinfo->
-                               lvds_setting_info,
-                                    &viaparinfo->chip_info->lvds_chip_info);
+                       viafb_lcd_set_mode(viaparinfo->lvds_setting_info,
+                               &viaparinfo->chip_info->lvds_chip_info);
                }
        }
        if (viafb_LCD2_ON) {
                if (viafb_SAMM_ON &&
                        (viaparinfo->lvds_setting_info2->iga_path == IGA2)) {
                        viaparinfo->lvds_setting_info2->bpp = video_bpp1;
-                       viafb_lcd_set_mode(crt_timing1, viaparinfo->
-                               lvds_setting_info2,
-                                    &viaparinfo->chip_info->lvds_chip_info2);
+                       viafb_lcd_set_mode(viaparinfo->lvds_setting_info2,
+                               &viaparinfo->chip_info->lvds_chip_info2);
                } else {
                        /* IGA1 doesn't have LCD scaling, so set it center. */
                        if (viaparinfo->lvds_setting_info2->iga_path == IGA1) {
@@ -2284,9 +1954,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
                                    LCD_CENTERING;
                        }
                        viaparinfo->lvds_setting_info2->bpp = video_bpp;
-                       viafb_lcd_set_mode(crt_timing, viaparinfo->
-                               lvds_setting_info2,
-                                    &viaparinfo->chip_info->lvds_chip_info2);
+                       viafb_lcd_set_mode(viaparinfo->lvds_setting_info2,
+                               &viaparinfo->chip_info->lvds_chip_info2);
                }
        }
 
@@ -2296,8 +1965,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
 
        /* If set mode normally, save resolution information for hot-plug . */
        if (!viafb_hotplug) {
-               viafb_hotplug_Xres = vmode_tbl->crtc[0].crtc.hor_addr;
-               viafb_hotplug_Yres = vmode_tbl->crtc[0].crtc.ver_addr;
+               viafb_hotplug_Xres = viafbinfo->var.xres;
+               viafb_hotplug_Yres = viafbinfo->var.yres;
                viafb_hotplug_bpp = video_bpp;
                viafb_hotplug_refresh = viafb_refresh;
 
@@ -2348,42 +2017,14 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
        return 1;
 }
 
-int viafb_get_pixclock(int hres, int vres, int vmode_refresh)
-{
-       int i;
-       struct crt_mode_table *best;
-       struct VideoModeTable *vmode = viafb_get_mode(hres, vres);
-
-       if (!vmode)
-               return RES_640X480_60HZ_PIXCLOCK;
-
-       best = &vmode->crtc[0];
-       for (i = 1; i < vmode->mode_array; i++) {
-               if (abs(vmode->crtc[i].refresh_rate - vmode_refresh)
-                       < abs(best->refresh_rate - vmode_refresh))
-                       best = &vmode->crtc[i];
-       }
-
-       return 1000000000 / (best->crtc.hor_total * best->crtc.ver_total)
-               * 1000 / best->refresh_rate;
-}
-
 int viafb_get_refresh(int hres, int vres, u32 long_refresh)
 {
-       int i;
        struct crt_mode_table *best;
-       struct VideoModeTable *vmode = viafb_get_mode(hres, vres);
 
-       if (!vmode)
+       best = viafb_get_best_mode(hres, vres, long_refresh);
+       if (!best)
                return 60;
 
-       best = &vmode->crtc[0];
-       for (i = 1; i < vmode->mode_array; i++) {
-               if (abs(vmode->crtc[i].refresh_rate - long_refresh)
-                       < abs(best->refresh_rate - long_refresh))
-                       best = &vmode->crtc[i];
-       }
-
        if (abs(best->refresh_rate - long_refresh) > 3) {
                if (hres == 1200 && vres == 900)
                        return 49; /* OLPC DCON only supports 50 Hz */
@@ -2485,21 +2126,14 @@ void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
 }
 
 /*According var's xres, yres fill var's other timing information*/
-void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
-       struct VideoModeTable *vmode_tbl)
+void viafb_fill_var_timing_info(struct fb_var_screeninfo *var,
+       struct crt_mode_table *mode)
 {
-       struct crt_mode_table *crt_timing = NULL;
        struct display_timing crt_reg;
-       int i = 0, index = 0;
-       crt_timing = vmode_tbl->crtc;
-       for (i = 0; i < vmode_tbl->mode_array; i++) {
-               index = i;
-               if (crt_timing[i].refresh_rate == refresh)
-                       break;
-       }
 
-       crt_reg = crt_timing[index].crtc;
-       var->pixclock = viafb_get_pixclock(var->xres, var->yres, refresh);
+       crt_reg = mode->crtc;
+       var->pixclock = 1000000000 / (crt_reg.hor_total * crt_reg.ver_total)
+               * 1000 / mode->refresh_rate;
        var->left_margin =
            crt_reg.hor_total - (crt_reg.hor_sync_start + crt_reg.hor_sync_end);
        var->right_margin = crt_reg.hor_sync_start - crt_reg.hor_addr;
@@ -2509,8 +2143,8 @@ void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
        var->lower_margin = crt_reg.ver_sync_start - crt_reg.ver_addr;
        var->vsync_len = crt_reg.ver_sync_end;
        var->sync = 0;
-       if (crt_timing[index].h_sync_polarity == POSITIVE)
+       if (mode->h_sync_polarity == POSITIVE)
                var->sync |= FB_SYNC_HOR_HIGH_ACT;
-       if (crt_timing[index].v_sync_polarity == POSITIVE)
+       if (mode->v_sync_polarity == POSITIVE)
                var->sync |= FB_SYNC_VERT_HIGH_ACT;
 }
index c7239eb..4db5b6e 100644 (file)
 #define VIA_HSYNC_NEGATIVE     0x01
 #define VIA_VSYNC_NEGATIVE     0x02
 
-/***************************************************
-* Definition IGA1 Design Method of CRTC Registers *
-****************************************************/
-#define IGA1_HOR_TOTAL_FORMULA(x)           (((x)/8)-5)
-#define IGA1_HOR_ADDR_FORMULA(x)            (((x)/8)-1)
-#define IGA1_HOR_BLANK_START_FORMULA(x)     (((x)/8)-1)
-#define IGA1_HOR_BLANK_END_FORMULA(x, y)     (((x+y)/8)-1)
-#define IGA1_HOR_SYNC_START_FORMULA(x)      ((x)/8)
-#define IGA1_HOR_SYNC_END_FORMULA(x, y)      ((x+y)/8)
-
-#define IGA1_VER_TOTAL_FORMULA(x)           ((x)-2)
-#define IGA1_VER_ADDR_FORMULA(x)            ((x)-1)
-#define IGA1_VER_BLANK_START_FORMULA(x)     ((x)-1)
-#define IGA1_VER_BLANK_END_FORMULA(x, y)     ((x+y)-1)
-#define IGA1_VER_SYNC_START_FORMULA(x)      ((x)-1)
-#define IGA1_VER_SYNC_END_FORMULA(x, y)      ((x+y)-1)
-
-/***************************************************
-** Definition IGA2 Design Method of CRTC Registers *
-****************************************************/
-#define IGA2_HOR_TOTAL_FORMULA(x)           ((x)-1)
-#define IGA2_HOR_ADDR_FORMULA(x)            ((x)-1)
-#define IGA2_HOR_BLANK_START_FORMULA(x)     ((x)-1)
-#define IGA2_HOR_BLANK_END_FORMULA(x, y)     ((x+y)-1)
-#define IGA2_HOR_SYNC_START_FORMULA(x)      ((x)-1)
-#define IGA2_HOR_SYNC_END_FORMULA(x, y)      ((x+y)-1)
-
-#define IGA2_VER_TOTAL_FORMULA(x)           ((x)-1)
-#define IGA2_VER_ADDR_FORMULA(x)            ((x)-1)
-#define IGA2_VER_BLANK_START_FORMULA(x)     ((x)-1)
-#define IGA2_VER_BLANK_END_FORMULA(x, y)     ((x+y)-1)
-#define IGA2_VER_SYNC_START_FORMULA(x)      ((x)-1)
-#define IGA2_VER_SYNC_END_FORMULA(x, y)      ((x+y)-1)
-
 /**********************************************************/
 /* Definition IGA2 Design Method of CRTC Shadow Registers */
 /**********************************************************/
 #define IGA2_VER_SYNC_START_SHADOW_FORMULA(x)      (x)
 #define IGA2_VER_SYNC_END_SHADOW_FORMULA(x, y)      (x+y)
 
-/* Define Register Number for IGA1 CRTC Timing */
-
-/* location: {CR00,0,7},{CR36,3,3} */
-#define IGA1_HOR_TOTAL_REG_NUM         2
-/* location: {CR01,0,7} */
-#define IGA1_HOR_ADDR_REG_NUM          1
-/* location: {CR02,0,7} */
-#define IGA1_HOR_BLANK_START_REG_NUM    1
-/* location: {CR03,0,4},{CR05,7,7},{CR33,5,5} */
-#define IGA1_HOR_BLANK_END_REG_NUM     3
-/* location: {CR04,0,7},{CR33,4,4} */
-#define IGA1_HOR_SYNC_START_REG_NUM    2
-/* location: {CR05,0,4} */
-#define IGA1_HOR_SYNC_END_REG_NUM       1
-/* location: {CR06,0,7},{CR07,0,0},{CR07,5,5},{CR35,0,0} */
-#define IGA1_VER_TOTAL_REG_NUM          4
-/* location: {CR12,0,7},{CR07,1,1},{CR07,6,6},{CR35,2,2} */
-#define IGA1_VER_ADDR_REG_NUM           4
-/* location: {CR15,0,7},{CR07,3,3},{CR09,5,5},{CR35,3,3} */
-#define IGA1_VER_BLANK_START_REG_NUM    4
-/* location: {CR16,0,7} */
-#define IGA1_VER_BLANK_END_REG_NUM      1
-/* location: {CR10,0,7},{CR07,2,2},{CR07,7,7},{CR35,1,1} */
-#define IGA1_VER_SYNC_START_REG_NUM     4
-/* location: {CR11,0,3} */
-#define IGA1_VER_SYNC_END_REG_NUM       1
-
 /* Define Register Number for IGA2 Shadow CRTC Timing */
 
 /* location: {CR6D,0,7},{CR71,3,3} */
 /* location: {CR76,0,3} */
 #define IGA2_SHADOW_VER_SYNC_END_REG_NUM    1
 
-/* Define Register Number for IGA2 CRTC Timing */
-
-/* location: {CR50,0,7},{CR55,0,3} */
-#define IGA2_HOR_TOTAL_REG_NUM          2
-/* location: {CR51,0,7},{CR55,4,6} */
-#define IGA2_HOR_ADDR_REG_NUM           2
-/* location: {CR52,0,7},{CR54,0,2} */
-#define IGA2_HOR_BLANK_START_REG_NUM    2
-/* location: CLE266: {CR53,0,7},{CR54,3,5} => CLE266's CR5D[6]
-is reserved, so it may have problem to set 1600x1200 on IGA2. */
-/*             Others: {CR53,0,7},{CR54,3,5},{CR5D,6,6} */
-#define IGA2_HOR_BLANK_END_REG_NUM      3
-/* location: {CR56,0,7},{CR54,6,7},{CR5C,7,7} */
-/* VT3314 and Later: {CR56,0,7},{CR54,6,7},{CR5C,7,7}, {CR5D,7,7} */
-#define IGA2_HOR_SYNC_START_REG_NUM     4
-
-/* location: {CR57,0,7},{CR5C,6,6} */
-#define IGA2_HOR_SYNC_END_REG_NUM       2
-/* location: {CR58,0,7},{CR5D,0,2} */
-#define IGA2_VER_TOTAL_REG_NUM          2
-/* location: {CR59,0,7},{CR5D,3,5} */
-#define IGA2_VER_ADDR_REG_NUM           2
-/* location: {CR5A,0,7},{CR5C,0,2} */
-#define IGA2_VER_BLANK_START_REG_NUM    2
-/* location: {CR5E,0,7},{CR5C,3,5} */
-#define IGA2_VER_BLANK_END_REG_NUM      2
-/* location: {CR5E,0,7},{CR5F,5,7} */
-#define IGA2_VER_SYNC_START_REG_NUM     2
-/* location: {CR5F,0,4} */
-#define IGA2_VER_SYNC_END_REG_NUM       1
-
 /* Define Fetch Count Register*/
 
 /* location: {SR1C,0,7},{SR1D,0,1} */
@@ -446,87 +354,12 @@ is reserved, so it may have problem to set 1600x1200 on IGA2. */
 /* location: {CR78,0,7},{CR79,6,7} */
 #define LCD_VER_SCALING_FACTOR_REG_NUM_CLE  2
 
-/************************************************
- *****     Define IGA1 Display Timing       *****
- ************************************************/
 struct io_register {
        u8 io_addr;
        u8 start_bit;
        u8 end_bit;
 };
 
-/* IGA1 Horizontal Total */
-struct iga1_hor_total {
-       int reg_num;
-       struct io_register reg[IGA1_HOR_TOTAL_REG_NUM];
-};
-
-/* IGA1 Horizontal Addressable Video */
-struct iga1_hor_addr {
-       int reg_num;
-       struct io_register reg[IGA1_HOR_ADDR_REG_NUM];
-};
-
-/* IGA1 Horizontal Blank Start */
-struct iga1_hor_blank_start {
-       int reg_num;
-       struct io_register reg[IGA1_HOR_BLANK_START_REG_NUM];
-};
-
-/* IGA1 Horizontal Blank End */
-struct iga1_hor_blank_end {
-       int reg_num;
-       struct io_register reg[IGA1_HOR_BLANK_END_REG_NUM];
-};
-
-/* IGA1 Horizontal Sync Start */
-struct iga1_hor_sync_start {
-       int reg_num;
-       struct io_register reg[IGA1_HOR_SYNC_START_REG_NUM];
-};
-
-/* IGA1 Horizontal Sync End */
-struct iga1_hor_sync_end {
-       int reg_num;
-       struct io_register reg[IGA1_HOR_SYNC_END_REG_NUM];
-};
-
-/* IGA1 Vertical Total */
-struct iga1_ver_total {
-       int reg_num;
-       struct io_register reg[IGA1_VER_TOTAL_REG_NUM];
-};
-
-/* IGA1 Vertical Addressable Video */
-struct iga1_ver_addr {
-       int reg_num;
-       struct io_register reg[IGA1_VER_ADDR_REG_NUM];
-};
-
-/* IGA1 Vertical Blank Start */
-struct iga1_ver_blank_start {
-       int reg_num;
-       struct io_register reg[IGA1_VER_BLANK_START_REG_NUM];
-};
-
-/* IGA1 Vertical Blank End */
-struct iga1_ver_blank_end {
-       int reg_num;
-       struct io_register reg[IGA1_VER_BLANK_END_REG_NUM];
-};
-
-/* IGA1 Vertical Sync Start */
-struct iga1_ver_sync_start {
-       int reg_num;
-       struct io_register reg[IGA1_VER_SYNC_START_REG_NUM];
-};
-
-/* IGA1 Vertical Sync End */
-struct iga1_ver_sync_end {
-       int reg_num;
-       struct io_register reg[IGA1_VER_SYNC_END_REG_NUM];
-};
-
 /*****************************************************
 **      Define IGA2 Shadow Display Timing         ****
 *****************************************************/
@@ -579,82 +412,6 @@ struct iga2_shadow_ver_sync_end {
        struct io_register reg[IGA2_SHADOW_VER_SYNC_END_REG_NUM];
 };
 
-/*****************************************************
-**      Define IGA2 Display Timing                ****
-******************************************************/
-
-/* IGA2 Horizontal Total */
-struct iga2_hor_total {
-       int reg_num;
-       struct io_register reg[IGA2_HOR_TOTAL_REG_NUM];
-};
-
-/* IGA2 Horizontal Addressable Video */
-struct iga2_hor_addr {
-       int reg_num;
-       struct io_register reg[IGA2_HOR_ADDR_REG_NUM];
-};
-
-/* IGA2 Horizontal Blank Start */
-struct iga2_hor_blank_start {
-       int reg_num;
-       struct io_register reg[IGA2_HOR_BLANK_START_REG_NUM];
-};
-
-/* IGA2 Horizontal Blank End */
-struct iga2_hor_blank_end {
-       int reg_num;
-       struct io_register reg[IGA2_HOR_BLANK_END_REG_NUM];
-};
-
-/* IGA2 Horizontal Sync Start */
-struct iga2_hor_sync_start {
-       int reg_num;
-       struct io_register reg[IGA2_HOR_SYNC_START_REG_NUM];
-};
-
-/* IGA2 Horizontal Sync End */
-struct iga2_hor_sync_end {
-       int reg_num;
-       struct io_register reg[IGA2_HOR_SYNC_END_REG_NUM];
-};
-
-/* IGA2 Vertical Total */
-struct iga2_ver_total {
-       int reg_num;
-       struct io_register reg[IGA2_VER_TOTAL_REG_NUM];
-};
-
-/* IGA2 Vertical Addressable Video */
-struct iga2_ver_addr {
-       int reg_num;
-       struct io_register reg[IGA2_VER_ADDR_REG_NUM];
-};
-
-/* IGA2 Vertical Blank Start */
-struct iga2_ver_blank_start {
-       int reg_num;
-       struct io_register reg[IGA2_VER_BLANK_START_REG_NUM];
-};
-
-/* IGA2 Vertical Blank End */
-struct iga2_ver_blank_end {
-       int reg_num;
-       struct io_register reg[IGA2_VER_BLANK_END_REG_NUM];
-};
-
-/* IGA2 Vertical Sync Start */
-struct iga2_ver_sync_start {
-       int reg_num;
-       struct io_register reg[IGA2_VER_SYNC_START_REG_NUM];
-};
-
-/* IGA2 Vertical Sync End */
-struct iga2_ver_sync_end {
-       int reg_num;
-       struct io_register reg[IGA2_VER_SYNC_END_REG_NUM];
-};
-
 /* IGA1 Fetch Count Register */
 struct iga1_fetch_count {
        int reg_num;
@@ -817,21 +574,6 @@ struct display_queue_expire_num {
         iga2_display_queue_expire_num_reg;
 };
 
-struct iga1_crtc_timing {
-       struct iga1_hor_total hor_total;
-       struct iga1_hor_addr hor_addr;
-       struct iga1_hor_blank_start hor_blank_start;
-       struct iga1_hor_blank_end hor_blank_end;
-       struct iga1_hor_sync_start hor_sync_start;
-       struct iga1_hor_sync_end hor_sync_end;
-       struct iga1_ver_total ver_total;
-       struct iga1_ver_addr ver_addr;
-       struct iga1_ver_blank_start ver_blank_start;
-       struct iga1_ver_blank_end ver_blank_end;
-       struct iga1_ver_sync_start ver_sync_start;
-       struct iga1_ver_sync_end ver_sync_end;
-};
-
 struct iga2_shadow_crtc_timing {
        struct iga2_shadow_hor_total hor_total_shadow;
        struct iga2_shadow_hor_blank_end hor_blank_end_shadow;
@@ -843,21 +585,6 @@ struct iga2_shadow_crtc_timing {
        struct iga2_shadow_ver_sync_end ver_sync_end_shadow;
 };
 
-struct iga2_crtc_timing {
-       struct iga2_hor_total hor_total;
-       struct iga2_hor_addr hor_addr;
-       struct iga2_hor_blank_start hor_blank_start;
-       struct iga2_hor_blank_end hor_blank_end;
-       struct iga2_hor_sync_start hor_sync_start;
-       struct iga2_hor_sync_end hor_sync_end;
-       struct iga2_ver_total ver_total;
-       struct iga2_ver_addr ver_addr;
-       struct iga2_ver_blank_start ver_blank_start;
-       struct iga2_ver_blank_end ver_blank_end;
-       struct iga2_ver_sync_start ver_sync_start;
-       struct iga2_ver_sync_end ver_sync_end;
-};
-
 /* device ID */
 #define CLE266_FUNCTION3    0x3123
 #define KM400_FUNCTION3     0x3205
@@ -910,9 +637,7 @@ extern int viafb_LCD_ON;
 extern int viafb_DVI_ON;
 extern int viafb_hotplug;
 
-void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
-       struct VideoModeTable *video_mode, int bpp_byte, int set_iga);
-
+void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, int iga);
 void viafb_set_vclock(u32 CLK, int set_iga);
 void viafb_load_reg(int timing_value, int viafb_load_reg_num,
        struct io_register *reg,
@@ -932,13 +657,11 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active);
 void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
                                        *p_gfx_dpa_setting);
 
-int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
-       struct VideoModeTable *vmode_tbl1, int video_bpp1);
-void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
-       struct VideoModeTable *vmode_tbl);
+int viafb_setmode(int video_bpp, int video_bpp1);
+void viafb_fill_var_timing_info(struct fb_var_screeninfo *var,
+       struct crt_mode_table *mode);
 void __devinit viafb_init_chip_info(int chip_type);
 void __devinit viafb_init_dac(int set_iga);
-int viafb_get_pixclock(int hres, int vres, int vmode_refresh);
 int viafb_get_refresh(int hres, int vres, u32 float_refresh);
 void viafb_update_device_setting(int hres, int vres, int bpp, int flag);
 
index 6e06981..5f3b4e3 100644 (file)
@@ -548,9 +548,8 @@ static void lcd_patch_skew(struct lvds_setting_information
 }
 
 /* LCD Set Mode */
-void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
-                 struct lvds_setting_information *plvds_setting_info,
-                 struct lvds_chip_information *plvds_chip_info)
+void viafb_lcd_set_mode(struct lvds_setting_information *plvds_setting_info,
+       struct lvds_chip_information *plvds_chip_info)
 {
        int set_iga = plvds_setting_info->iga_path;
        int mode_bpp = plvds_setting_info->bpp;
@@ -559,16 +558,15 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
        int panel_hres = plvds_setting_info->lcd_panel_hres;
        int panel_vres = plvds_setting_info->lcd_panel_vres;
        u32 clock;
-       struct display_timing mode_crt_reg, panel_crt_reg;
-       struct crt_mode_table *panel_crt_table = NULL;
-       struct VideoModeTable *vmode_tbl = viafb_get_mode(panel_hres,
-               panel_vres);
+       struct display_timing mode_crt_reg, panel_crt_reg, timing;
+       struct crt_mode_table *mode_crt_table, *panel_crt_table;
 
        DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n");
        /* Get mode table */
+       mode_crt_table = viafb_get_best_mode(set_hres, set_vres, 60);
        mode_crt_reg = mode_crt_table->crtc;
        /* Get panel table Pointer */
-       panel_crt_table = vmode_tbl->crtc;
+       panel_crt_table = viafb_get_best_mode(panel_hres, panel_vres, 60);
        panel_crt_reg = panel_crt_table->crtc;
        DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n");
        if (VT1636_LVDS == plvds_chip_info->lvds_chip_name)
@@ -576,31 +574,28 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
        clock = panel_crt_reg.hor_total * panel_crt_reg.ver_total
                * panel_crt_table->refresh_rate;
        plvds_setting_info->vclk = clock;
-       if (set_iga == IGA1) {
-               /* IGA1 doesn't have LCD scaling, so set it as centering. */
-               viafb_load_crtc_timing(lcd_centering_timging
-                                (mode_crt_reg, panel_crt_reg), IGA1);
+
+       if (set_iga == IGA2 && (set_hres < panel_hres || set_vres < panel_vres)
+               && plvds_setting_info->display_method == LCD_EXPANDSION) {
+               timing = panel_crt_reg;
+               load_lcd_scaling(set_hres, set_vres, panel_hres, panel_vres);
        } else {
-               /* Expansion */
-               if (plvds_setting_info->display_method == LCD_EXPANDSION
-                       && (set_hres < panel_hres || set_vres < panel_vres)) {
-                       /* expansion timing IGA2 loaded panel set timing*/
-                       viafb_load_crtc_timing(panel_crt_reg, IGA2);
-                       DEBUG_MSG(KERN_INFO "viafb_load_crtc_timing!!\n");
-                       load_lcd_scaling(set_hres, set_vres, panel_hres,
-                                        panel_vres);
-                       DEBUG_MSG(KERN_INFO "load_lcd_scaling!!\n");
-               } else {        /* Centering */
-                       /* centering timing IGA2 always loaded panel
-                          and mode releative timing */
-                       viafb_load_crtc_timing(lcd_centering_timging
-                                        (mode_crt_reg, panel_crt_reg), IGA2);
-                       viafb_write_reg_mask(CR79, VIACR, 0x00,
+               timing = lcd_centering_timging(mode_crt_reg, panel_crt_reg);
+               if (set_iga == IGA2)
+                       /* disable scaling */
+                       via_write_reg_mask(VIACR, 0x79, 0x00,
                                BIT0 + BIT1 + BIT2);
-                       /* LCD scaling disabled */
-               }
        }
 
+       timing.hor_blank_end += timing.hor_blank_start;
+       timing.hor_sync_end += timing.hor_sync_start;
+       timing.ver_blank_end += timing.ver_blank_start;
+       timing.ver_sync_end += timing.ver_sync_start;
+       if (set_iga == IGA1)
+               via_set_primary_timing(&timing);
+       else if (set_iga == IGA2)
+               via_set_secondary_timing(&timing);
+
        /* Fetch count for IGA2 only */
        viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga);
 
index 75f60a6..77ca7b8 100644 (file)
@@ -76,16 +76,13 @@ void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information
                                *plvds_chip_info,
                                struct lvds_setting_information
                                *plvds_setting_info);
-void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
-                 struct lvds_setting_information *plvds_setting_info,
-                 struct lvds_chip_information *plvds_chip_info);
+void viafb_lcd_set_mode(struct lvds_setting_information *plvds_setting_info,
+       struct lvds_chip_information *plvds_chip_info);
 bool __devinit viafb_lvds_trasmitter_identify(void);
 void viafb_init_lvds_output_interface(struct lvds_chip_information
                                *plvds_chip_info,
                                struct lvds_setting_information
                                *plvds_setting_info);
 bool viafb_lcd_get_mobile_state(bool *mobile);
-void viafb_load_crtc_timing(struct display_timing device_timing,
-       int set_iga);
 
 #endif /* __LCD_H__ */
index 61b0bd5..69d882c 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef __SHARE_H__
 #define __SHARE_H__
 
+#include "via_modesetting.h"
+
 /* Define Bit Field */
 #define BIT0    0x01
 #define BIT1    0x02
 #define V_SYNC_SATRT_SHADOW_INDEX   18
 #define V_SYNC_END_SHADOW_INDEX     19
 
-/* Definition Video Mode Pixel Clock (picoseconds)
-*/
-#define RES_640X480_60HZ_PIXCLOCK    39722
-
 /* LCD display method
 */
 #define     LCD_EXPANDSION              0x00
 #define     LCD_OPENLDI               0x00
 #define     LCD_SPWG                  0x01
 
-/* Define display timing
-*/
-struct display_timing {
-       u16 hor_total;
-       u16 hor_addr;
-       u16 hor_blank_start;
-       u16 hor_blank_end;
-       u16 hor_sync_start;
-       u16 hor_sync_end;
-       u16 ver_total;
-       u16 ver_addr;
-       u16 ver_blank_start;
-       u16 ver_blank_end;
-       u16 ver_sync_start;
-       u16 ver_sync_end;
-};
-
 struct crt_mode_table {
        int refresh_rate;
        int h_sync_polarity;
index eb112b6..dd58b53 100644 (file)
@@ -35,7 +35,7 @@ static struct via_port_cfg adap_configs[] = {
  * The OLPC XO-1.5 puts the camera power and reset lines onto
  * GPIO 2C.
  */
-static const struct via_port_cfg olpc_adap_configs[] = {
+static struct via_port_cfg olpc_adap_configs[] = {
        [VIA_PORT_26]   = { VIA_PORT_I2C,  VIA_MODE_I2C, VIASR, 0x26 },
        [VIA_PORT_31]   = { VIA_PORT_I2C,  VIA_MODE_I2C, VIASR, 0x31 },
        [VIA_PORT_25]   = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 },
index 3cddcff..0e431ae 100644 (file)
 #include "share.h"
 #include "debug.h"
 
+
+void via_set_primary_timing(const struct display_timing *timing)
+{
+       struct display_timing raw;
+
+       raw.hor_total = timing->hor_total / 8 - 5;
+       raw.hor_addr = timing->hor_addr / 8 - 1;
+       raw.hor_blank_start = timing->hor_blank_start / 8 - 1;
+       raw.hor_blank_end = timing->hor_blank_end / 8 - 1;
+       raw.hor_sync_start = timing->hor_sync_start / 8;
+       raw.hor_sync_end = timing->hor_sync_end / 8;
+       raw.ver_total = timing->ver_total - 2;
+       raw.ver_addr = timing->ver_addr - 1;
+       raw.ver_blank_start = timing->ver_blank_start - 1;
+       raw.ver_blank_end = timing->ver_blank_end - 1;
+       raw.ver_sync_start = timing->ver_sync_start - 1;
+       raw.ver_sync_end = timing->ver_sync_end - 1;
+
+       /* unlock timing registers */
+       via_write_reg_mask(VIACR, 0x11, 0x00, 0x80);
+
+       via_write_reg(VIACR, 0x00, raw.hor_total & 0xFF);
+       via_write_reg(VIACR, 0x01, raw.hor_addr & 0xFF);
+       via_write_reg(VIACR, 0x02, raw.hor_blank_start & 0xFF);
+       via_write_reg_mask(VIACR, 0x03, raw.hor_blank_end & 0x1F, 0x1F);
+       via_write_reg(VIACR, 0x04, raw.hor_sync_start & 0xFF);
+       via_write_reg_mask(VIACR, 0x05, (raw.hor_sync_end & 0x1F)
+               | (raw.hor_blank_end << (7 - 5) & 0x80), 0x9F);
+       via_write_reg(VIACR, 0x06, raw.ver_total & 0xFF);
+       via_write_reg_mask(VIACR, 0x07, (raw.ver_total >> 8 & 0x01)
+               | (raw.ver_addr >> (8 - 1) & 0x02)
+               | (raw.ver_sync_start >> (8 - 2) & 0x04)
+               | (raw.ver_blank_start >> (8 - 3) & 0x08)
+               | (raw.ver_total >> (9 - 5) & 0x20)
+               | (raw.ver_addr >> (9 - 6) & 0x40)
+               | (raw.ver_sync_start >> (9 - 7) & 0x80), 0xEF);
+       via_write_reg_mask(VIACR, 0x09, raw.ver_blank_start >> (9 - 5) & 0x20,
+               0x20);
+       via_write_reg(VIACR, 0x10, raw.ver_sync_start & 0xFF);
+       via_write_reg_mask(VIACR, 0x11, raw.ver_sync_end & 0x0F, 0x0F);
+       via_write_reg(VIACR, 0x12, raw.ver_addr & 0xFF);
+       via_write_reg(VIACR, 0x15, raw.ver_blank_start & 0xFF);
+       via_write_reg(VIACR, 0x16, raw.ver_blank_end & 0xFF);
+       via_write_reg_mask(VIACR, 0x33, (raw.hor_sync_start >> (8 - 4) & 0x10)
+               | (raw.hor_blank_end >> (6 - 5) & 0x20), 0x30);
+       via_write_reg_mask(VIACR, 0x35, (raw.ver_total >> 10 & 0x01)
+               | (raw.ver_sync_start >> (10 - 1) & 0x02)
+               | (raw.ver_addr >> (10 - 2) & 0x04)
+               | (raw.ver_blank_start >> (10 - 3) & 0x08), 0x0F);
+       via_write_reg_mask(VIACR, 0x36, raw.hor_total >> (8 - 3) & 0x08, 0x08);
+
+       /* lock timing registers */
+       via_write_reg_mask(VIACR, 0x11, 0x80, 0x80);
+
+       /* reset timing control */
+       via_write_reg_mask(VIACR, 0x17, 0x00, 0x80);
+       via_write_reg_mask(VIACR, 0x17, 0x80, 0x80);
+}
+
+void via_set_secondary_timing(const struct display_timing *timing)
+{
+       struct display_timing raw;
+
+       raw.hor_total = timing->hor_total - 1;
+       raw.hor_addr = timing->hor_addr - 1;
+       raw.hor_blank_start = timing->hor_blank_start - 1;
+       raw.hor_blank_end = timing->hor_blank_end - 1;
+       raw.hor_sync_start = timing->hor_sync_start - 1;
+       raw.hor_sync_end = timing->hor_sync_end - 1;
+       raw.ver_total = timing->ver_total - 1;
+       raw.ver_addr = timing->ver_addr - 1;
+       raw.ver_blank_start = timing->ver_blank_start - 1;
+       raw.ver_blank_end = timing->ver_blank_end - 1;
+       raw.ver_sync_start = timing->ver_sync_start - 1;
+       raw.ver_sync_end = timing->ver_sync_end - 1;
+
+       via_write_reg(VIACR, 0x50, raw.hor_total & 0xFF);
+       via_write_reg(VIACR, 0x51, raw.hor_addr & 0xFF);
+       via_write_reg(VIACR, 0x52, raw.hor_blank_start & 0xFF);
+       via_write_reg(VIACR, 0x53, raw.hor_blank_end & 0xFF);
+       via_write_reg(VIACR, 0x54, (raw.hor_blank_start >> 8 & 0x07)
+               | (raw.hor_blank_end >> (8 - 3) & 0x38)
+               | (raw.hor_sync_start >> (8 - 6) & 0xC0));
+       via_write_reg_mask(VIACR, 0x55, (raw.hor_total >> 8 & 0x0F)
+               | (raw.hor_addr >> (8 - 4) & 0x70), 0x7F);
+       via_write_reg(VIACR, 0x56, raw.hor_sync_start & 0xFF);
+       via_write_reg(VIACR, 0x57, raw.hor_sync_end & 0xFF);
+       via_write_reg(VIACR, 0x58, raw.ver_total & 0xFF);
+       via_write_reg(VIACR, 0x59, raw.ver_addr & 0xFF);
+       via_write_reg(VIACR, 0x5A, raw.ver_blank_start & 0xFF);
+       via_write_reg(VIACR, 0x5B, raw.ver_blank_end & 0xFF);
+       via_write_reg(VIACR, 0x5C, (raw.ver_blank_start >> 8 & 0x07)
+               | (raw.ver_blank_end >> (8 - 3) & 0x38)
+               | (raw.hor_sync_end >> (8 - 6) & 0x40)
+               | (raw.hor_sync_start >> (10 - 7) & 0x80));
+       via_write_reg(VIACR, 0x5D, (raw.ver_total >> 8 & 0x07)
+               | (raw.ver_addr >> (8 - 3) & 0x38)
+               | (raw.hor_blank_end >> (11 - 6) & 0x40)
+               | (raw.hor_sync_start >> (11 - 7) & 0x80));
+       via_write_reg(VIACR, 0x5E, raw.ver_sync_start & 0xFF);
+       via_write_reg(VIACR, 0x5F, (raw.ver_sync_end & 0x1F)
+               | (raw.ver_sync_start >> (8 - 5) & 0xE0));
+}
+
 void via_set_primary_address(u32 addr)
 {
        DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n", addr);
index ae35cfd..06e09fe 100644 (file)
 
 #include <linux/types.h>
 
+
+#define VIA_PITCH_SIZE (1<<3)
+#define VIA_PITCH_MAX  0x3FF8
+
+
+struct display_timing {
+       u16 hor_total;
+       u16 hor_addr;
+       u16 hor_blank_start;
+       u16 hor_blank_end;
+       u16 hor_sync_start;
+       u16 hor_sync_end;
+       u16 ver_total;
+       u16 ver_addr;
+       u16 ver_blank_start;
+       u16 ver_blank_end;
+       u16 ver_sync_start;
+       u16 ver_sync_end;
+};
+
+
+void via_set_primary_timing(const struct display_timing *timing);
+void via_set_secondary_timing(const struct display_timing *timing);
 void via_set_primary_address(u32 addr);
 void via_set_secondary_address(u32 addr);
 void via_set_primary_pitch(u32 pitch);
index 53aa443..a13c258 100644 (file)
@@ -38,8 +38,6 @@ static char *viafb_mode1;
 static int viafb_bpp = 32;
 static int viafb_bpp1 = 32;
 
-static unsigned int viafb_second_xres = 640;
-static unsigned int viafb_second_yres = 480;
 static unsigned int viafb_second_offset;
 static int viafb_second_size;
 
@@ -151,7 +149,8 @@ static void viafb_update_fix(struct fb_info *info)
 
        info->fix.visual =
                bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
-       info->fix.line_length = (info->var.xres_virtual * bpp / 8 + 7) & ~7;
+       info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8,
+               VIA_PITCH_SIZE);
 }
 
 static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
@@ -200,7 +199,6 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
        struct fb_info *info)
 {
        int depth, refresh;
-       struct VideoModeTable *vmode_entry;
        struct viafb_par *ppar = info->par;
        u32 line;
 
@@ -210,8 +208,10 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
        if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE)
                return -EINVAL;
 
-       vmode_entry = viafb_get_mode(var->xres, var->yres);
-       if (!vmode_entry) {
+       /* the refresh rate is not important here, as we only want to know
+        * whether the resolution exists
+        */
+       if (!viafb_get_best_mode(var->xres, var->yres, 60)) {
                DEBUG_MSG(KERN_INFO
                          "viafb: Mode %dx%dx%d not supported!!\n",
                          var->xres, var->yres, var->bits_per_pixel);
@@ -238,8 +238,12 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
                depth = 24;
 
        viafb_fill_var_color_info(var, depth);
-       line = (var->xres_virtual * var->bits_per_pixel / 8 + 7) & ~7;
-       if (line * var->yres_virtual > ppar->memsize)
+       if (var->xres_virtual < var->xres)
+               var->xres_virtual = var->xres;
+
+       line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8,
+               VIA_PITCH_SIZE);
+       if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize)
                return -EINVAL;
 
        /* Based on var passed in to calculate the refresh,
@@ -249,7 +253,8 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
                get_var_refresh(var));
 
        /* Adjust var according to our driver's own table */
-       viafb_fill_var_timing_info(var, refresh, vmode_entry);
+       viafb_fill_var_timing_info(var,
+               viafb_get_best_mode(var->xres, var->yres, refresh));
        if (var->accel_flags & FB_ACCELF_TEXT &&
                !ppar->shared->vdev->engine_mmio)
                var->accel_flags = 0;
@@ -260,7 +265,6 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
 static int viafb_set_par(struct fb_info *info)
 {
        struct viafb_par *viapar = info->par;
-       struct VideoModeTable *vmode_entry, *vmode_entry1 = NULL;
        int refresh;
        DEBUG_MSG(KERN_INFO "viafb_set_par!\n");
 
@@ -269,10 +273,7 @@ static int viafb_set_par(struct fb_info *info)
        viafb_update_device_setting(viafbinfo->var.xres, viafbinfo->var.yres,
                viafbinfo->var.bits_per_pixel, 0);
 
-       vmode_entry = viafb_get_mode(viafbinfo->var.xres, viafbinfo->var.yres);
        if (viafb_dual_fb) {
-               vmode_entry1 = viafb_get_mode(viafbinfo1->var.xres,
-                       viafbinfo1->var.yres);
                viafb_update_device_setting(viafbinfo1->var.xres,
                        viafbinfo1->var.yres, viafbinfo1->var.bits_per_pixel,
                        1);
@@ -280,8 +281,6 @@ static int viafb_set_par(struct fb_info *info)
                DEBUG_MSG(KERN_INFO
                "viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n",
                          viafb_second_xres, viafb_second_yres, viafb_bpp1);
-               vmode_entry1 = viafb_get_mode(viafb_second_xres,
-                       viafb_second_yres);
 
                viafb_update_device_setting(viafb_second_xres,
                        viafb_second_yres, viafb_bpp1, 1);
@@ -289,7 +288,8 @@ static int viafb_set_par(struct fb_info *info)
 
        refresh = viafb_get_refresh(info->var.xres, info->var.yres,
                get_var_refresh(&info->var));
-       if (vmode_entry) {
+       if (viafb_get_best_mode(viafbinfo->var.xres, viafbinfo->var.yres,
+               refresh)) {
                if (viafb_dual_fb && viapar->iga_path == IGA2) {
                        viafb_bpp1 = info->var.bits_per_pixel;
                        viafb_refresh1 = refresh;
@@ -302,8 +302,7 @@ static int viafb_set_par(struct fb_info *info)
                        info->flags &= ~FBINFO_HWACCEL_DISABLED;
                else
                        info->flags |= FBINFO_HWACCEL_DISABLED;
-               viafb_setmode(vmode_entry, info->var.bits_per_pixel,
-                       vmode_entry1, viafb_bpp1);
+               viafb_setmode(info->var.bits_per_pixel, viafb_bpp1);
                viafb_pan_display(&info->var, info);
        }
 
@@ -348,8 +347,9 @@ static int viafb_pan_display(struct fb_var_screeninfo *var,
        struct fb_info *info)
 {
        struct viafb_par *viapar = info->par;
-       u32 vram_addr = (var->yoffset * var->xres_virtual + var->xoffset)
-               * (var->bits_per_pixel / 8) + viapar->vram_addr;
+       u32 vram_addr = viapar->vram_addr
+               + var->yoffset * info->fix.line_length
+               + var->xoffset * info->var.bits_per_pixel / 8;
 
        DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);
        if (!viafb_dual_fb) {
@@ -1158,7 +1158,8 @@ static ssize_t viafb_dvp0_proc_write(struct file *file,
        for (i = 0; i < 3; i++) {
                value = strsep(&pbuf, " ");
                if (value != NULL) {
-                       strict_strtoul(value, 0, (unsigned long *)&reg_val);
+                       if (kstrtou8(value, 0, &reg_val) < 0)
+                               return -EINVAL;
                        DEBUG_MSG(KERN_INFO "DVP0:reg_val[%l]=:%x\n", i,
                                  reg_val);
                        switch (i) {
@@ -1228,7 +1229,8 @@ static ssize_t viafb_dvp1_proc_write(struct file *file,
        for (i = 0; i < 3; i++) {
                value = strsep(&pbuf, " ");
                if (value != NULL) {
-                       strict_strtoul(value, 0, (unsigned long *)&reg_val);
+                       if (kstrtou8(value, 0, &reg_val) < 0)
+                               return -EINVAL;
                        switch (i) {
                        case 0:
                                viafb_write_reg_mask(CR9B, VIACR,
@@ -1286,7 +1288,8 @@ static ssize_t viafb_dfph_proc_write(struct file *file,
        if (copy_from_user(&buf[0], buffer, length))
                return -EFAULT;
        buf[length - 1] = '\0'; /*Ensure end string */
-       strict_strtoul(&buf[0], 0, (unsigned long *)&reg_val);
+       if (kstrtou8(buf, 0, &reg_val) < 0)
+               return -EINVAL;
        viafb_write_reg_mask(CR97, VIACR, reg_val, 0x0f);
        return count;
 }
@@ -1325,7 +1328,8 @@ static ssize_t viafb_dfpl_proc_write(struct file *file,
        if (copy_from_user(&buf[0], buffer, length))
                return -EFAULT;
        buf[length - 1] = '\0'; /*Ensure end string */
-       strict_strtoul(&buf[0], 0, (unsigned long *)&reg_val);
+       if (kstrtou8(buf, 0, &reg_val) < 0)
+               return -EINVAL;
        viafb_write_reg_mask(CR99, VIACR, reg_val, 0x0f);
        return count;
 }
@@ -1394,8 +1398,8 @@ static ssize_t viafb_vt1636_proc_write(struct file *file,
                for (i = 0; i < 2; i++) {
                        value = strsep(&pbuf, " ");
                        if (value != NULL) {
-                               strict_strtoul(value, 0,
-                                       (unsigned long *)&reg_val.Data);
+                               if (kstrtou8(value, 0, &reg_val.Data) < 0)
+                                       return -EINVAL;
                                switch (i) {
                                case 0:
                                        reg_val.Index = 0x08;
@@ -1431,8 +1435,8 @@ static ssize_t viafb_vt1636_proc_write(struct file *file,
                for (i = 0; i < 2; i++) {
                        value = strsep(&pbuf, " ");
                        if (value != NULL) {
-                               strict_strtoul(value, 0,
-                                       (unsigned long *)&reg_val.Data);
+                               if (kstrtou8(value, 0, &reg_val.Data) < 0)
+                                       return -EINVAL;
                                switch (i) {
                                case 0:
                                        reg_val.Index = 0x08;
@@ -1729,7 +1733,6 @@ static struct viafb_pm_hooks viafb_fb_pm_hooks = {
 int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
 {
        u32 default_xres, default_yres;
-       struct VideoModeTable *vmode_entry;
        struct fb_var_screeninfo default_var;
        int rc;
        u32 viafb_par_length;
@@ -1802,7 +1805,6 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
        }
 
        parse_mode(viafb_mode, &default_xres, &default_yres);
-       vmode_entry = viafb_get_mode(default_xres, default_yres);
        if (viafb_SAMM_ON == 1)
                parse_mode(viafb_mode1, &viafb_second_xres,
                        &viafb_second_yres);
@@ -1812,9 +1814,8 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
        default_var.xres_virtual = default_xres;
        default_var.yres_virtual = default_yres;
        default_var.bits_per_pixel = viafb_bpp;
-       viafb_fill_var_timing_info(&default_var, viafb_get_refresh(
-               default_var.xres, default_var.yres, viafb_refresh),
-               viafb_get_mode(default_var.xres, default_var.yres));
+       viafb_fill_var_timing_info(&default_var, viafb_get_best_mode(
+               default_var.xres, default_var.yres, viafb_refresh));
        viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo);
        viafbinfo->var = default_var;
 
@@ -1853,9 +1854,8 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
                default_var.xres_virtual = viafb_second_xres;
                default_var.yres_virtual = viafb_second_yres;
                default_var.bits_per_pixel = viafb_bpp1;
-               viafb_fill_var_timing_info(&default_var, viafb_get_refresh(
-                       default_var.xres, default_var.yres, viafb_refresh1),
-                       viafb_get_mode(default_var.xres, default_var.yres));
+               viafb_fill_var_timing_info(&default_var, viafb_get_best_mode(
+                       default_var.xres, default_var.yres, viafb_refresh1));
 
                viafb_setup_fixinfo(&viafbinfo1->fix, viaparinfo1);
                viafb_check_var(&default_var, viafbinfo1);
@@ -1950,61 +1950,67 @@ static int __init viafb_setup(void)
                if (!*this_opt)
                        continue;
 
-               if (!strncmp(this_opt, "viafb_mode1=", 12))
+               if (!strncmp(this_opt, "viafb_mode1=", 12)) {
                        viafb_mode1 = kstrdup(this_opt + 12, GFP_KERNEL);
-               else if (!strncmp(this_opt, "viafb_mode=", 11))
+               } else if (!strncmp(this_opt, "viafb_mode=", 11)) {
                        viafb_mode = kstrdup(this_opt + 11, GFP_KERNEL);
-               else if (!strncmp(this_opt, "viafb_bpp1=", 11))
-                       strict_strtoul(this_opt + 11, 0,
-                               (unsigned long *)&viafb_bpp1);
-               else if (!strncmp(this_opt, "viafb_bpp=", 10))
-                       strict_strtoul(this_opt + 10, 0,
-                               (unsigned long *)&viafb_bpp);
-               else if (!strncmp(this_opt, "viafb_refresh1=", 15))
-                       strict_strtoul(this_opt + 15, 0,
-                               (unsigned long *)&viafb_refresh1);
-               else if (!strncmp(this_opt, "viafb_refresh=", 14))
-                       strict_strtoul(this_opt + 14, 0,
-                               (unsigned long *)&viafb_refresh);
-               else if (!strncmp(this_opt, "viafb_lcd_dsp_method=", 21))
-                       strict_strtoul(this_opt + 21, 0,
-                               (unsigned long *)&viafb_lcd_dsp_method);
-               else if (!strncmp(this_opt, "viafb_lcd_panel_id=", 19))
-                       strict_strtoul(this_opt + 19, 0,
-                               (unsigned long *)&viafb_lcd_panel_id);
-               else if (!strncmp(this_opt, "viafb_accel=", 12))
-                       strict_strtoul(this_opt + 12, 0,
-                               (unsigned long *)&viafb_accel);
-               else if (!strncmp(this_opt, "viafb_SAMM_ON=", 14))
-                       strict_strtoul(this_opt + 14, 0,
-                               (unsigned long *)&viafb_SAMM_ON);
-               else if (!strncmp(this_opt, "viafb_active_dev=", 17))
+               } else if (!strncmp(this_opt, "viafb_bpp1=", 11)) {
+                       if (kstrtouint(this_opt + 11, 0, &viafb_bpp1) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt, "viafb_bpp=", 10)) {
+                       if (kstrtouint(this_opt + 10, 0, &viafb_bpp) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt, "viafb_refresh1=", 15)) {
+                       if (kstrtoint(this_opt + 15, 0, &viafb_refresh1) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt, "viafb_refresh=", 14)) {
+                       if (kstrtoint(this_opt + 14, 0, &viafb_refresh) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt, "viafb_lcd_dsp_method=", 21)) {
+                       if (kstrtoint(this_opt + 21, 0,
+                                     &viafb_lcd_dsp_method) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt, "viafb_lcd_panel_id=", 19)) {
+                       if (kstrtoint(this_opt + 19, 0,
+                                     &viafb_lcd_panel_id) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt, "viafb_accel=", 12)) {
+                       if (kstrtoint(this_opt + 12, 0, &viafb_accel) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt, "viafb_SAMM_ON=", 14)) {
+                       if (kstrtoint(this_opt + 14, 0, &viafb_SAMM_ON) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt, "viafb_active_dev=", 17)) {
                        viafb_active_dev = kstrdup(this_opt + 17, GFP_KERNEL);
-               else if (!strncmp(this_opt,
-                       "viafb_display_hardware_layout=", 30))
-                       strict_strtoul(this_opt + 30, 0,
-                       (unsigned long *)&viafb_display_hardware_layout);
-               else if (!strncmp(this_opt, "viafb_second_size=", 18))
-                       strict_strtoul(this_opt + 18, 0,
-                               (unsigned long *)&viafb_second_size);
-               else if (!strncmp(this_opt,
-                       "viafb_platform_epia_dvi=", 24))
-                       strict_strtoul(this_opt + 24, 0,
-                               (unsigned long *)&viafb_platform_epia_dvi);
-               else if (!strncmp(this_opt,
-                       "viafb_device_lcd_dualedge=", 26))
-                       strict_strtoul(this_opt + 26, 0,
-                               (unsigned long *)&viafb_device_lcd_dualedge);
-               else if (!strncmp(this_opt, "viafb_bus_width=", 16))
-                       strict_strtoul(this_opt + 16, 0,
-                               (unsigned long *)&viafb_bus_width);
-               else if (!strncmp(this_opt, "viafb_lcd_mode=", 15))
-                       strict_strtoul(this_opt + 15, 0,
-                               (unsigned long *)&viafb_lcd_mode);
-               else if (!strncmp(this_opt, "viafb_lcd_port=", 15))
+               } else if (!strncmp(this_opt,
+                       "viafb_display_hardware_layout=", 30)) {
+                       if (kstrtoint(this_opt + 30, 0,
+                                     &viafb_display_hardware_layout) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt, "viafb_second_size=", 18)) {
+                       if (kstrtoint(this_opt + 18, 0, &viafb_second_size) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt,
+                       "viafb_platform_epia_dvi=", 24)) {
+                       if (kstrtoint(this_opt + 24, 0,
+                                     &viafb_platform_epia_dvi) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt,
+                       "viafb_device_lcd_dualedge=", 26)) {
+                       if (kstrtoint(this_opt + 26, 0,
+                                     &viafb_device_lcd_dualedge) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt, "viafb_bus_width=", 16)) {
+                       if (kstrtoint(this_opt + 16, 0, &viafb_bus_width) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt, "viafb_lcd_mode=", 15)) {
+                       if (kstrtoint(this_opt + 15, 0, &viafb_lcd_mode) < 0)
+                               return -EINVAL;
+               } else if (!strncmp(this_opt, "viafb_lcd_port=", 15)) {
                        viafb_lcd_port = kstrdup(this_opt + 15, GFP_KERNEL);
-               else if (!strncmp(this_opt, "viafb_dvi_port=", 15))
+               } else if (!strncmp(this_opt, "viafb_dvi_port=", 15)) {
                        viafb_dvi_port = kstrdup(this_opt + 15, GFP_KERNEL);
+               }
        }
        return 0;
 }
@@ -2028,9 +2034,9 @@ int __init viafb_init(void)
                return r;
 #endif
        if (parse_mode(viafb_mode, &dummy_x, &dummy_y)
-               || !viafb_get_mode(dummy_x, dummy_y)
+               || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh)
                || parse_mode(viafb_mode1, &dummy_x, &dummy_y)
-               || !viafb_get_mode(dummy_x, dummy_y)
+               || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh1)
                || viafb_bpp < 0 || viafb_bpp > 32
                || viafb_bpp1 < 0 || viafb_bpp1 > 32
                || parse_active_dev())
index 58df74e..0911cac 100644 (file)
@@ -281,7 +281,7 @@ static struct crt_mode_table CRTM640x480[] = {
        /*r_rate,hsp,vsp */
        /*HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
        {REFRESH_60, M640X480_R60_HSP, M640X480_R60_VSP,
-        {800, 640, 648, 144, 656, 96, 525, 480, 480, 45, 490, 2} },
+        {800, 640, 640, 160, 656, 96, 525, 480, 480, 45, 490, 2} },
        {REFRESH_75, M640X480_R75_HSP, M640X480_R75_VSP,
         {840, 640, 640, 200, 656, 64, 500, 480, 480, 20, 481, 3} },
        {REFRESH_85, M640X480_R85_HSP, M640X480_R85_VSP,
@@ -863,26 +863,56 @@ int NUM_TOTAL_CLE266_ModeXregs = ARRAY_SIZE(CLE266_ModeXregs);
 int NUM_TOTAL_PATCH_MODE = ARRAY_SIZE(res_patch_table);
 
 
-struct VideoModeTable *viafb_get_mode(int hres, int vres)
+static struct VideoModeTable *get_modes(struct VideoModeTable *vmt, int n,
+       int hres, int vres)
 {
-       u32 i;
-       for (i = 0; i < ARRAY_SIZE(viafb_modes); i++)
-               if (viafb_modes[i].mode_array &&
-                       viafb_modes[i].crtc[0].crtc.hor_addr == hres &&
-                       viafb_modes[i].crtc[0].crtc.ver_addr == vres)
+       int i;
+
+       for (i = 0; i < n; i++)
+               if (vmt[i].mode_array &&
+                       vmt[i].crtc[0].crtc.hor_addr == hres &&
+                       vmt[i].crtc[0].crtc.ver_addr == vres)
                        return &viafb_modes[i];
 
        return NULL;
 }
 
-struct VideoModeTable *viafb_get_rb_mode(int hres, int vres)
+static struct crt_mode_table *get_best_mode(struct VideoModeTable *vmt,
+       int refresh)
 {
-       u32 i;
-       for (i = 0; i < ARRAY_SIZE(viafb_rb_modes); i++)
-               if (viafb_rb_modes[i].mode_array &&
-                       viafb_rb_modes[i].crtc[0].crtc.hor_addr == hres &&
-                       viafb_rb_modes[i].crtc[0].crtc.ver_addr == vres)
-                       return &viafb_rb_modes[i];
+       struct crt_mode_table *best;
+       int i;
 
-       return NULL;
+       if (!vmt)
+               return NULL;
+
+       best = &vmt->crtc[0];
+       for (i = 1; i < vmt->mode_array; i++) {
+               if (abs(vmt->crtc[i].refresh_rate - refresh)
+                       < abs(best->refresh_rate - refresh))
+                       best = &vmt->crtc[i];
+       }
+
+       return best;
+}
+
+static struct VideoModeTable *viafb_get_mode(int hres, int vres)
+{
+       return get_modes(viafb_modes, ARRAY_SIZE(viafb_modes), hres, vres);
+}
+
+struct crt_mode_table *viafb_get_best_mode(int hres, int vres, int refresh)
+{
+       return get_best_mode(viafb_get_mode(hres, vres), refresh);
+}
+
+static struct VideoModeTable *viafb_get_rb_mode(int hres, int vres)
+{
+       return get_modes(viafb_rb_modes, ARRAY_SIZE(viafb_rb_modes), hres,
+               vres);
+}
+
+struct crt_mode_table *viafb_get_best_rb_mode(int hres, int vres, int refresh)
+{
+       return get_best_mode(viafb_get_rb_mode(hres, vres), refresh);
 }
index 3751289..5917a2b 100644 (file)
@@ -60,7 +60,7 @@ extern struct io_reg PM1024x768[];
 extern struct patch_table res_patch_table[];
 extern struct VPITTable VPIT;
 
-struct VideoModeTable *viafb_get_mode(int hres, int vres);
-struct VideoModeTable *viafb_get_rb_mode(int hres, int vres);
+struct crt_mode_table *viafb_get_best_mode(int hres, int vres, int refresh);
+struct crt_mode_table *viafb_get_best_rb_mode(int hres, int vres, int refresh);
 
 #endif /* __VIAMODE_H__ */
index 0e120d6..777c21d 100644 (file)
@@ -210,8 +210,8 @@ static int vt8500lcd_pan_display(struct fb_var_screeninfo *var,
        struct vt8500lcd_info *fbi = to_vt8500lcd_info(info);
 
        writel((1 << 31)
-               | (((var->xres_virtual - var->xres) * pixlen / 4) << 20)
-               | (off >> 2), fbi->regbase + 0x20);
+            | (((info->var.xres_virtual - info->var.xres) * pixlen / 4) << 20)
+            | (off >> 2), fbi->regbase + 0x20);
        return 0;
 }
 
@@ -355,7 +355,7 @@ static int __devinit vt8500lcd_probe(struct platform_device *pdev)
                goto failed_free_palette;
        }
 
-       ret = request_irq(irq, vt8500lcd_handle_irq, IRQF_DISABLED, "LCD", fbi);
+       ret = request_irq(irq, vt8500lcd_handle_irq, 0, "LCD", fbi);
        if (ret) {
                dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
                ret = -EBUSY;
index f9b3e3d..4e74d26 100644 (file)
@@ -620,13 +620,14 @@ static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *i
        unsigned int offset;
 
        /* Calculate the offset */
-       if (var->bits_per_pixel == 0) {
-               offset = (var->yoffset / 16) * var->xres_virtual + var->xoffset;
+       if (info->var.bits_per_pixel == 0) {
+               offset = (var->yoffset / 16) * info->var.xres_virtual
+                      + var->xoffset;
                offset = offset >> 3;
        } else {
                offset = (var->yoffset * info->fix.line_length) +
-                        (var->xoffset * var->bits_per_pixel / 8);
-               offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 1);
+                        (var->xoffset * info->var.bits_per_pixel / 8);
+               offset = offset >> ((info->var.bits_per_pixel == 4) ? 2 : 1);
        }
 
        /* Set the offset */
index 77dea01..fcb6cd9 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mm.h>
index bdcf361..85e78fc 100644 (file)
@@ -33,6 +33,7 @@ struct class;
 struct subsys_private;
 struct bus_type;
 struct device_node;
+struct iommu_ops;
 
 struct bus_attribute {
        struct attribute        attr;
@@ -67,6 +68,9 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
  * @resume:    Called to bring a device on this bus out of sleep mode.
  * @pm:                Power management operations of this bus, callback the specific
  *             device driver's pm-ops.
+ * @iommu_ops   IOMMU specific operations for this bus, used to attach IOMMU
+ *              driver implementations to a bus and allow the driver to do
+ *              bus-specific setup
  * @p:         The private data of the driver core, only the driver core can
  *             touch this.
  *
@@ -96,6 +100,8 @@ struct bus_type {
 
        const struct dev_pm_ops *pm;
 
+       struct iommu_ops *iommu_ops;
+
        struct subsys_private *p;
 };
 
index 36a3ed6..1b1094c 100644 (file)
@@ -349,6 +349,7 @@ typedef enum fe_delivery_system {
        SYS_CMMB,
        SYS_DAB,
        SYS_DVBT2,
+       SYS_TURBO,
 } fe_delivery_system_t;
 
 struct dtv_cmds_h {
index 1421cc8..66594b1 100644 (file)
@@ -24,6 +24,6 @@
 #define _DVBVERSION_H_
 
 #define DVB_API_VERSION 5
-#define DVB_API_VERSION_MINOR 3
+#define DVB_API_VERSION_MINOR 4
 
 #endif /*_DVBVERSION_H_*/
index daa9952..11c16a1 100644 (file)
 #ifndef __FSL_DIU_FB_H__
 #define __FSL_DIU_FB_H__
 
-/* Arbitrary threshold to determine the allocation method
- * See mpc8610fb_set_par(), map_video_memory(), and unmap_video_memory()
- */
-#define MEM_ALLOC_THRESHOLD (1024*768*4+32)
-
 #include <linux/types.h>
 
-struct mfb_alpha {
-       int enable;
-       int alpha;
-};
-
 struct mfb_chroma_key {
        int enable;
        __u8  red_max;
@@ -43,25 +33,29 @@ struct mfb_chroma_key {
 };
 
 struct aoi_display_offset {
-       int x_aoi_d;
-       int y_aoi_d;
+       __s32 x_aoi_d;
+       __s32 y_aoi_d;
 };
 
 #define MFB_SET_CHROMA_KEY     _IOW('M', 1, struct mfb_chroma_key)
 #define MFB_SET_BRIGHTNESS     _IOW('M', 3, __u8)
+#define MFB_SET_ALPHA          _IOW('M', 0, __u8)
+#define MFB_GET_ALPHA          _IOR('M', 0, __u8)
+#define MFB_SET_AOID           _IOW('M', 4, struct aoi_display_offset)
+#define MFB_GET_AOID           _IOR('M', 4, struct aoi_display_offset)
+#define MFB_SET_PIXFMT         _IOW('M', 8, __u32)
+#define MFB_GET_PIXFMT         _IOR('M', 8, __u32)
 
-#define MFB_SET_ALPHA          0x80014d00
-#define MFB_GET_ALPHA          0x40014d00
-#define MFB_SET_AOID           0x80084d04
-#define MFB_GET_AOID           0x40084d04
-#define MFB_SET_PIXFMT         0x80014d08
-#define MFB_GET_PIXFMT         0x40014d08
-
-#define FBIOGET_GWINFO         0x46E0
-#define FBIOPUT_GWINFO         0x46E1
+/*
+ * The original definitions of MFB_SET_PIXFMT and MFB_GET_PIXFMT used the
+ * wrong value for 'size' field of the ioctl.  The current macros above use the
+ * right size, but we still need to provide backwards compatibility, at least
+ * for a while.
+*/
+#define MFB_SET_PIXFMT_OLD     0x80014d08
+#define MFB_GET_PIXFMT_OLD     0x40014d08
 
 #ifdef __KERNEL__
-#include <linux/spinlock.h>
 
 /*
  * These are the fields of area descriptor(in DDR memory) for every plane
@@ -159,58 +153,12 @@ struct diu {
        __be32 plut;
 } __attribute__ ((packed));
 
-struct diu_hw {
-       struct diu *diu_reg;
-       spinlock_t reg_lock;
-
-       __u32 mode;             /* DIU operation mode */
-};
-
-struct diu_addr {
-       __u8 __iomem *vaddr;    /* Virtual address */
-       dma_addr_t paddr;       /* Physical address */
-       __u32      offset;
-};
-
-struct diu_pool {
-       struct diu_addr ad;
-       struct diu_addr gamma;
-       struct diu_addr pallete;
-       struct diu_addr cursor;
-};
-
-#define FSL_DIU_BASE_OFFSET    0x2C000 /* Offset of DIU */
-#define INT_LCDC               64      /* DIU interrupt number */
-
-#define FSL_AOI_NUM    6       /* 5 AOIs and one dummy AOI */
-                               /* 1 for plane 0, 2 for plane 1&2 each */
-
-/* Minimum X and Y resolutions */
-#define MIN_XRES       64
-#define MIN_YRES       64
-
-/* HW cursor parameters */
-#define MAX_CURS               32
-
-/* Modes of operation of DIU */
+/*
+ * Modes of operation of DIU.  The DIU supports five different modes, but
+ * the driver only supports modes 0 and 1.
+ */
 #define MFB_MODE0      0       /* DIU off */
 #define MFB_MODE1      1       /* All three planes output to display */
-#define MFB_MODE2      2       /* Plane 1 to display, planes 2+3 written back*/
-#define MFB_MODE3      3       /* All three planes written back to memory */
-#define MFB_MODE4      4       /* Color bar generation */
-
-/* INT_STATUS/INT_MASK field descriptions */
-#define INT_VSYNC      0x01    /* Vsync interrupt  */
-#define INT_VSYNC_WB   0x02    /* Vsync interrupt for write back operation */
-#define INT_UNDRUN     0x04    /* Under run exception interrupt */
-#define INT_PARERR     0x08    /* Display parameters error interrupt */
-#define INT_LS_BF_VS   0x10    /* Lines before vsync. interrupt */
-
-/* Panels'operation modes */
-#define MFB_TYPE_OUTPUT        0       /* Panel output to display */
-#define MFB_TYPE_OFF   1       /* Panel off */
-#define MFB_TYPE_WB    2       /* Panel written back to memory */
-#define MFB_TYPE_TEST  3       /* Panel generate color bar */
 
 #endif /* __KERNEL__ */
 #endif /* __FSL_DIU_FB_H__ */
index a6c652e..38a21c3 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/sched.h>       /* for completion */
 #include <linux/mutex.h>
 #include <linux/of.h>          /* for struct device_node */
+#include <linux/swab.h>                /* for swab16 */
 
 extern struct bus_type i2c_bus_type;
 extern struct device_type i2c_adapter_type;
@@ -88,6 +89,22 @@ extern s32 i2c_smbus_read_word_data(const struct i2c_client *client,
                                    u8 command);
 extern s32 i2c_smbus_write_word_data(const struct i2c_client *client,
                                     u8 command, u16 value);
+
+static inline s32
+i2c_smbus_read_word_swapped(const struct i2c_client *client, u8 command)
+{
+       s32 value = i2c_smbus_read_word_data(client, command);
+
+       return (value < 0) ? value : swab16(value);
+}
+
+static inline s32
+i2c_smbus_write_word_swapped(const struct i2c_client *client,
+                            u8 command, u16 value)
+{
+       return i2c_smbus_write_word_data(client, command, swab16(value));
+}
+
 /* Returns the number of read bytes */
 extern s32 i2c_smbus_read_block_data(const struct i2c_client *client,
                                     u8 command, u8 *values);
index 44da482..12d5543 100644 (file)
@@ -106,7 +106,7 @@ extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
 extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
 extern u16 vlan_dev_vlan_id(const struct net_device *dev);
 
-extern bool vlan_do_receive(struct sk_buff **skb);
+extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler);
 extern struct sk_buff *vlan_untag(struct sk_buff *skb);
 
 #else
@@ -128,9 +128,9 @@ static inline u16 vlan_dev_vlan_id(const struct net_device *dev)
        return 0;
 }
 
-static inline bool vlan_do_receive(struct sk_buff **skb)
+static inline bool vlan_do_receive(struct sk_buff **skb, bool last_handler)
 {
-       if ((*skb)->vlan_tci & VLAN_VID_MASK)
+       if (((*skb)->vlan_tci & VLAN_VID_MASK) && last_handler)
                (*skb)->pkt_type = PACKET_OTHERHOST;
        return false;
 }
index 9940319..432acc4 100644 (file)
 #define IOMMU_WRITE    (2)
 #define IOMMU_CACHE    (4) /* DMA cache coherency */
 
+struct iommu_ops;
+struct bus_type;
 struct device;
+struct iommu_domain;
+
+/* iommu fault flags */
+#define IOMMU_FAULT_READ       0x0
+#define IOMMU_FAULT_WRITE      0x1
+
+typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
+                               struct device *, unsigned long, int);
 
 struct iommu_domain {
+       struct iommu_ops *ops;
        void *priv;
+       iommu_fault_handler_t handler;
 };
 
 #define IOMMU_CAP_CACHE_COHERENCY      0x1
 #define IOMMU_CAP_INTR_REMAP           0x2     /* isolates device intrs */
 
+#ifdef CONFIG_IOMMU_API
+
 struct iommu_ops {
        int (*domain_init)(struct iommu_domain *domain);
        void (*domain_destroy)(struct iommu_domain *domain);
@@ -49,11 +63,9 @@ struct iommu_ops {
                              unsigned long cap);
 };
 
-#ifdef CONFIG_IOMMU_API
-
-extern void register_iommu(struct iommu_ops *ops);
-extern bool iommu_found(void);
-extern struct iommu_domain *iommu_domain_alloc(void);
+extern int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops);
+extern bool iommu_present(struct bus_type *bus);
+extern struct iommu_domain *iommu_domain_alloc(struct bus_type *bus);
 extern void iommu_domain_free(struct iommu_domain *domain);
 extern int iommu_attach_device(struct iommu_domain *domain,
                               struct device *dev);
@@ -67,19 +79,58 @@ extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
                                      unsigned long iova);
 extern int iommu_domain_has_cap(struct iommu_domain *domain,
                                unsigned long cap);
+extern void iommu_set_fault_handler(struct iommu_domain *domain,
+                                       iommu_fault_handler_t handler);
+
+/**
+ * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework
+ * @domain: the iommu domain where the fault has happened
+ * @dev: the device where the fault has happened
+ * @iova: the faulting address
+ * @flags: mmu fault flags (e.g. IOMMU_FAULT_READ/IOMMU_FAULT_WRITE/...)
+ *
+ * This function should be called by the low-level IOMMU implementations
+ * whenever IOMMU faults happen, to allow high-level users, that are
+ * interested in such events, to know about them.
+ *
+ * This event may be useful for several possible use cases:
+ * - mere logging of the event
+ * - dynamic TLB/PTE loading
+ * - if restarting of the faulting device is required
+ *
+ * Returns 0 on success and an appropriate error code otherwise (if dynamic
+ * PTE/TLB loading will one day be supported, implementations will be able
+ * to tell whether it succeeded or not according to this return value).
+ *
+ * Specifically, -ENOSYS is returned if a fault handler isn't installed
+ * (though fault handlers can also return -ENOSYS, in case they want to
+ * elicit the default behavior of the IOMMU drivers).
+ */
+static inline int report_iommu_fault(struct iommu_domain *domain,
+               struct device *dev, unsigned long iova, int flags)
+{
+       int ret = -ENOSYS;
 
-#else /* CONFIG_IOMMU_API */
+       /*
+        * if upper layers showed interest and installed a fault handler,
+        * invoke it.
+        */
+       if (domain->handler)
+               ret = domain->handler(domain, dev, iova, flags);
 
-static inline void register_iommu(struct iommu_ops *ops)
-{
+       return ret;
 }
 
-static inline bool iommu_found(void)
+#else /* CONFIG_IOMMU_API */
+
+struct iommu_ops {};
+
+static inline bool iommu_present(struct bus_type *bus)
 {
        return false;
 }
 
-static inline struct iommu_domain *iommu_domain_alloc(void)
+static inline struct iommu_domain *iommu_domain_alloc(struct bus_type *bus)
 {
        return NULL;
 }
@@ -123,6 +174,11 @@ static inline int domain_has_cap(struct iommu_domain *domain,
        return 0;
 }
 
+static inline void iommu_set_fault_handler(struct iommu_domain *domain,
+                                       iommu_fault_handler_t handler)
+{
+}
+
 #endif /* CONFIG_IOMMU_API */
 
 #endif /* __LINUX_IOMMU_H */
index aace6b8..f47fcd3 100644 (file)
@@ -371,6 +371,7 @@ struct kvm_s390_psw {
 #define KVM_S390_INT_VIRTIO            0xffff2603u
 #define KVM_S390_INT_SERVICE           0xffff2401u
 #define KVM_S390_INT_EMERGENCY         0xffff1201u
+#define KVM_S390_INT_EXTERNAL_CALL     0xffff1202u
 
 struct kvm_s390_interrupt {
        __u32 type;
@@ -463,7 +464,7 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_VAPIC 6
 #define KVM_CAP_EXT_CPUID 7
 #define KVM_CAP_CLOCKSOURCE 8
-#define KVM_CAP_NR_VCPUS 9       /* returns max vcpus per vm */
+#define KVM_CAP_NR_VCPUS 9       /* returns recommended max vcpus per vm */
 #define KVM_CAP_NR_MEMSLOTS 10   /* returns max memory slots per vm */
 #define KVM_CAP_PIT 11
 #define KVM_CAP_NOP_IO_DELAY 12
@@ -553,6 +554,9 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_SPAPR_TCE 63
 #define KVM_CAP_PPC_SMT 64
 #define KVM_CAP_PPC_RMA        65
+#define KVM_CAP_MAX_VCPUS 66       /* returns max vcpus per vm */
+#define KVM_CAP_PPC_HIOR 67
+#define KVM_CAP_PPC_PAPR 68
 #define KVM_CAP_S390_GMAP 71
 
 #ifdef KVM_CAP_IRQ_ROUTING
index eabb21a..d526231 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/msi.h>
 #include <linux/slab.h>
 #include <linux/rcupdate.h>
+#include <linux/ratelimit.h>
 #include <asm/signal.h>
 
 #include <linux/kvm.h>
@@ -48,6 +49,7 @@
 #define KVM_REQ_EVENT             11
 #define KVM_REQ_APF_HALT          12
 #define KVM_REQ_STEAL_UPDATE      13
+#define KVM_REQ_NMI               14
 
 #define KVM_USERSPACE_IRQ_SOURCE_ID    0
 
@@ -55,16 +57,16 @@ struct kvm;
 struct kvm_vcpu;
 extern struct kmem_cache *kvm_vcpu_cache;
 
-/*
- * It would be nice to use something smarter than a linear search, TBD...
- * Thankfully we dont expect many devices to register (famous last words :),
- * so until then it will suffice.  At least its abstracted so we can change
- * in one place.
- */
+struct kvm_io_range {
+       gpa_t addr;
+       int len;
+       struct kvm_io_device *dev;
+};
+
 struct kvm_io_bus {
        int                   dev_count;
-#define NR_IOBUS_DEVS 200
-       struct kvm_io_device *devs[NR_IOBUS_DEVS];
+#define NR_IOBUS_DEVS 300
+       struct kvm_io_range range[NR_IOBUS_DEVS];
 };
 
 enum kvm_bus {
@@ -77,8 +79,8 @@ int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
                     int len, const void *val);
 int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, int len,
                    void *val);
-int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx,
-                           struct kvm_io_device *dev);
+int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+                           int len, struct kvm_io_device *dev);
 int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
                              struct kvm_io_device *dev);
 
@@ -256,8 +258,9 @@ struct kvm {
        struct kvm_arch arch;
        atomic_t users_count;
 #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
-       struct kvm_coalesced_mmio_dev *coalesced_mmio_dev;
        struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
+       spinlock_t ring_lock;
+       struct list_head coalesced_zones;
 #endif
 
        struct mutex irq_lock;
@@ -281,11 +284,8 @@ struct kvm {
 
 /* The guest did something we don't support. */
 #define pr_unimpl(vcpu, fmt, ...)                                      \
- do {                                                                  \
-       if (printk_ratelimit())                                         \
-               printk(KERN_ERR "kvm: %i: cpu%i " fmt,                  \
-                      current->tgid, (vcpu)->vcpu_id , ## __VA_ARGS__); \
- } while (0)
+       pr_err_ratelimited("kvm: %i: cpu%i " fmt,                       \
+                          current->tgid, (vcpu)->vcpu_id , ## __VA_ARGS__)
 
 #define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
 #define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
index b6111f8..c73a34c 100644 (file)
  * V4L2_EVENT_OMAP3ISP_AEWB: AEWB statistics data ready
  * V4L2_EVENT_OMAP3ISP_AF: AF statistics data ready
  * V4L2_EVENT_OMAP3ISP_HIST: Histogram statistics data ready
- * V4L2_EVENT_OMAP3ISP_HS_VS: Horizontal/vertical synchronization detected
  */
 
 #define V4L2_EVENT_OMAP3ISP_CLASS      (V4L2_EVENT_PRIVATE_START | 0x100)
 #define V4L2_EVENT_OMAP3ISP_AEWB       (V4L2_EVENT_OMAP3ISP_CLASS | 0x1)
 #define V4L2_EVENT_OMAP3ISP_AF         (V4L2_EVENT_OMAP3ISP_CLASS | 0x2)
 #define V4L2_EVENT_OMAP3ISP_HIST       (V4L2_EVENT_OMAP3ISP_CLASS | 0x3)
-#define V4L2_EVENT_OMAP3ISP_HS_VS      (V4L2_EVENT_OMAP3ISP_CLASS | 0x4)
 
 struct omap3isp_stat_event_status {
        __u32 frame_number;
index ed91fb6..b607f35 100644 (file)
@@ -7,3 +7,4 @@ header-y += gadgetfs.h
 header-y += midi.h
 header-y += g_printer.h
 header-y += tmc.h
+header-y += video.h
index fca24cc..225560c 100644 (file)
@@ -759,10 +759,10 @@ typedef __u64 v4l2_std_id;
 #define V4L2_STD_PAL_Nc         ((v4l2_std_id)0x00000400)
 #define V4L2_STD_PAL_60         ((v4l2_std_id)0x00000800)
 
-#define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)
-#define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)
+#define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)      /* BTSC */
+#define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)      /* EIA-J */
 #define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)
-#define V4L2_STD_NTSC_M_KR      ((v4l2_std_id)0x00008000)
+#define V4L2_STD_NTSC_M_KR      ((v4l2_std_id)0x00008000)      /* FM A2 */
 
 #define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
 #define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
@@ -786,47 +786,86 @@ typedef __u64 v4l2_std_id;
    v4l2-common.c should be fixed.
  */
 
-/* some merged standards */
-#define V4L2_STD_MN    (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
-#define V4L2_STD_B     (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
-#define V4L2_STD_GH    (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
-#define V4L2_STD_DK    (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK)
+/*
+ * Some macros to merge video standards in order to make live easier for the
+ * drivers and V4L2 applications
+ */
 
-/* some common needed stuff */
-#define V4L2_STD_PAL_BG                (V4L2_STD_PAL_B         |\
-                                V4L2_STD_PAL_B1        |\
-                                V4L2_STD_PAL_G)
-#define V4L2_STD_PAL_DK                (V4L2_STD_PAL_D         |\
-                                V4L2_STD_PAL_D1        |\
-                                V4L2_STD_PAL_K)
-#define V4L2_STD_PAL           (V4L2_STD_PAL_BG        |\
-                                V4L2_STD_PAL_DK        |\
-                                V4L2_STD_PAL_H         |\
-                                V4L2_STD_PAL_I)
+/*
+ * "Common" NTSC/M - It should be noticed that V4L2_STD_NTSC_443 is
+ * Missing here.
+ */
 #define V4L2_STD_NTSC           (V4L2_STD_NTSC_M       |\
                                 V4L2_STD_NTSC_M_JP     |\
                                 V4L2_STD_NTSC_M_KR)
+/* Secam macros */
 #define V4L2_STD_SECAM_DK              (V4L2_STD_SECAM_D       |\
                                 V4L2_STD_SECAM_K       |\
                                 V4L2_STD_SECAM_K1)
+/* All Secam Standards */
 #define V4L2_STD_SECAM         (V4L2_STD_SECAM_B       |\
                                 V4L2_STD_SECAM_G       |\
                                 V4L2_STD_SECAM_H       |\
                                 V4L2_STD_SECAM_DK      |\
                                 V4L2_STD_SECAM_L       |\
                                 V4L2_STD_SECAM_LC)
+/* PAL macros */
+#define V4L2_STD_PAL_BG                (V4L2_STD_PAL_B         |\
+                                V4L2_STD_PAL_B1        |\
+                                V4L2_STD_PAL_G)
+#define V4L2_STD_PAL_DK                (V4L2_STD_PAL_D         |\
+                                V4L2_STD_PAL_D1        |\
+                                V4L2_STD_PAL_K)
+/*
+ * "Common" PAL - This macro is there to be compatible with the old
+ * V4L1 concept of "PAL": /BGDKHI.
+ * Several PAL standards are mising here: /M, /N and /Nc
+ */
+#define V4L2_STD_PAL           (V4L2_STD_PAL_BG        |\
+                                V4L2_STD_PAL_DK        |\
+                                V4L2_STD_PAL_H         |\
+                                V4L2_STD_PAL_I)
+/* Chroma "agnostic" standards */
+#define V4L2_STD_B             (V4L2_STD_PAL_B         |\
+                                V4L2_STD_PAL_B1        |\
+                                V4L2_STD_SECAM_B)
+#define V4L2_STD_G             (V4L2_STD_PAL_G         |\
+                                V4L2_STD_SECAM_G)
+#define V4L2_STD_H             (V4L2_STD_PAL_H         |\
+                                V4L2_STD_SECAM_H)
+#define V4L2_STD_L             (V4L2_STD_SECAM_L       |\
+                                V4L2_STD_SECAM_LC)
+#define V4L2_STD_GH            (V4L2_STD_G             |\
+                                V4L2_STD_H)
+#define V4L2_STD_DK            (V4L2_STD_PAL_DK        |\
+                                V4L2_STD_SECAM_DK)
+#define V4L2_STD_BG            (V4L2_STD_B             |\
+                                V4L2_STD_G)
+#define V4L2_STD_MN            (V4L2_STD_PAL_M         |\
+                                V4L2_STD_PAL_N         |\
+                                V4L2_STD_PAL_Nc        |\
+                                V4L2_STD_NTSC)
+
+/* Standards where MTS/BTSC stereo could be found */
+#define V4L2_STD_MTS           (V4L2_STD_NTSC_M        |\
+                                V4L2_STD_PAL_M         |\
+                                V4L2_STD_PAL_N         |\
+                                V4L2_STD_PAL_Nc)
 
+/* Standards for Countries with 60Hz Line frequency */
 #define V4L2_STD_525_60                (V4L2_STD_PAL_M         |\
                                 V4L2_STD_PAL_60        |\
                                 V4L2_STD_NTSC          |\
                                 V4L2_STD_NTSC_443)
+/* Standards for Countries with 50Hz Line frequency */
 #define V4L2_STD_625_50                (V4L2_STD_PAL           |\
                                 V4L2_STD_PAL_N         |\
                                 V4L2_STD_PAL_Nc        |\
                                 V4L2_STD_SECAM)
+
 #define V4L2_STD_ATSC           (V4L2_STD_ATSC_8_VSB    |\
                                 V4L2_STD_ATSC_16_VSB)
-
+/* Macros with none and all analog standards */
 #define V4L2_STD_UNKNOWN        0
 #define V4L2_STD_ALL            (V4L2_STD_525_60       |\
                                 V4L2_STD_625_50)
@@ -1082,6 +1121,7 @@ struct v4l2_querymenu {
 #define V4L2_CTRL_FLAG_INACTIVE        0x0010
 #define V4L2_CTRL_FLAG_SLIDER          0x0020
 #define V4L2_CTRL_FLAG_WRITE_ONLY      0x0040
+#define V4L2_CTRL_FLAG_VOLATILE                0x0080
 
 /*  Query flag, to be ORed with the control ID */
 #define V4L2_CTRL_FLAG_NEXT_CTRL       0x80000000
@@ -2006,6 +2046,7 @@ struct v4l2_streamparm {
 #define V4L2_EVENT_VSYNC                       1
 #define V4L2_EVENT_EOS                         2
 #define V4L2_EVENT_CTRL                                3
+#define V4L2_EVENT_FRAME_SYNC                  4
 #define V4L2_EVENT_PRIVATE_START               0x08000000
 
 /* Payload for V4L2_EVENT_VSYNC */
@@ -2032,12 +2073,17 @@ struct v4l2_event_ctrl {
        __s32 default_value;
 };
 
+struct v4l2_event_frame_sync {
+       __u32 frame_sequence;
+};
+
 struct v4l2_event {
        __u32                           type;
        union {
-               struct v4l2_event_vsync vsync;
-               struct v4l2_event_ctrl  ctrl;
-               __u8                    data[64];
+               struct v4l2_event_vsync         vsync;
+               struct v4l2_event_ctrl          ctrl;
+               struct v4l2_event_frame_sync    frame_sync;
+               __u8                            data[64];
        } u;
        __u32                           pending;
        __u32                           sequence;
index aac2c0e..4a825ae 100644 (file)
 
 /**
  * struct m5mols_platform_data - platform data for M-5MOLS driver
- * @irq:       GPIO getting the irq pin of M-5MOLS
  * @gpio_reset:        GPIO driving the reset pin of M-5MOLS
- * @reset_polarity: active state for gpio_rst pin, 0 or 1
+ * @reset_polarity: active state for gpio_reset pin, 0 or 1
  * @set_power: an additional callback to the board setup code
  *             to be called after enabling and before disabling
  *             the sensor's supply regulators
  */
 struct m5mols_platform_data {
-       int irq;
        int gpio_reset;
        u8 reset_polarity;
        int (*set_power)(struct device *dev, int on);
diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h
new file mode 100644 (file)
index 0000000..96448c7
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef MT9P031_H
+#define MT9P031_H
+
+struct v4l2_subdev;
+
+enum {
+       MT9P031_COLOR_VERSION,
+       MT9P031_MONOCHROME_VERSION,
+};
+
+struct mt9p031_platform_data {
+       int (*set_xclk)(struct v4l2_subdev *subdev, int hz);
+       int (*reset)(struct v4l2_subdev *subdev, int active);
+       int ext_freq; /* input frequency to the mt9p031 for PLL dividers */
+       int target_freq; /* frequency target for the PLL */
+       int version; /* MT9P031_COLOR_VERSION or MT9P031_MONOCHROME_VERSION */
+};
+
+#endif
diff --git a/include/media/mt9t001.h b/include/media/mt9t001.h
new file mode 100644 (file)
index 0000000..e839a78
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _MEDIA_MT9T001_H
+#define _MEDIA_MT9T001_H
+
+struct mt9t001_platform_data {
+       unsigned int clk_pol:1;
+};
+
+#endif
diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h
new file mode 100644 (file)
index 0000000..e917b1d
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * omap3isp.h
+ *
+ * TI OMAP3 ISP - Platform data
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __MEDIA_OMAP3ISP_H__
+#define __MEDIA_OMAP3ISP_H__
+
+struct i2c_board_info;
+struct isp_device;
+
+enum isp_interface_type {
+       ISP_INTERFACE_PARALLEL,
+       ISP_INTERFACE_CSI2A_PHY2,
+       ISP_INTERFACE_CCP2B_PHY1,
+       ISP_INTERFACE_CCP2B_PHY2,
+       ISP_INTERFACE_CSI2C_PHY1,
+};
+
+enum {
+       ISP_BRIDGE_DISABLE = 0,
+       ISP_BRIDGE_LITTLE_ENDIAN = 2,
+       ISP_BRIDGE_BIG_ENDIAN = 3,
+};
+
+enum {
+       ISP_LANE_SHIFT_0 = 0,
+       ISP_LANE_SHIFT_2 = 1,
+       ISP_LANE_SHIFT_4 = 2,
+       ISP_LANE_SHIFT_6 = 3,
+};
+
+/**
+ * struct isp_parallel_platform_data - Parallel interface platform data
+ * @data_lane_shift: Data lane shifter
+ *             ISP_LANE_SHIFT_0 - CAMEXT[13:0] -> CAM[13:0]
+ *             ISP_LANE_SHIFT_2 - CAMEXT[13:2] -> CAM[11:0]
+ *             ISP_LANE_SHIFT_4 - CAMEXT[13:4] -> CAM[9:0]
+ *             ISP_LANE_SHIFT_6 - CAMEXT[13:6] -> CAM[7:0]
+ * @clk_pol: Pixel clock polarity
+ *             0 - Non Inverted, 1 - Inverted
+ * @hs_pol: Horizontal synchronization polarity
+ *             0 - Active high, 1 - Active low
+ * @vs_pol: Vertical synchronization polarity
+ *             0 - Active high, 1 - Active low
+ * @bridge: CCDC Bridge input control
+ *             ISP_BRIDGE_DISABLE - Disable
+ *             ISP_BRIDGE_LITTLE_ENDIAN - Little endian
+ *             ISP_BRIDGE_BIG_ENDIAN - Big endian
+ */
+struct isp_parallel_platform_data {
+       unsigned int data_lane_shift:2;
+       unsigned int clk_pol:1;
+       unsigned int hs_pol:1;
+       unsigned int vs_pol:1;
+       unsigned int bridge:2;
+};
+
+enum {
+       ISP_CCP2_PHY_DATA_CLOCK = 0,
+       ISP_CCP2_PHY_DATA_STROBE = 1,
+};
+
+enum {
+       ISP_CCP2_MODE_MIPI = 0,
+       ISP_CCP2_MODE_CCP2 = 1,
+};
+
+/**
+ * struct isp_ccp2_platform_data - CCP2 interface platform data
+ * @strobe_clk_pol: Strobe/clock polarity
+ *             0 - Non Inverted, 1 - Inverted
+ * @crc: Enable the cyclic redundancy check
+ * @ccp2_mode: Enable CCP2 compatibility mode
+ *             ISP_CCP2_MODE_MIPI - MIPI-CSI1 mode
+ *             ISP_CCP2_MODE_CCP2 - CCP2 mode
+ * @phy_layer: Physical layer selection
+ *             ISP_CCP2_PHY_DATA_CLOCK - Data/clock physical layer
+ *             ISP_CCP2_PHY_DATA_STROBE - Data/strobe physical layer
+ * @vpclk_div: Video port output clock control
+ */
+struct isp_ccp2_platform_data {
+       unsigned int strobe_clk_pol:1;
+       unsigned int crc:1;
+       unsigned int ccp2_mode:1;
+       unsigned int phy_layer:1;
+       unsigned int vpclk_div:2;
+};
+
+/**
+ * struct isp_csi2_platform_data - CSI2 interface platform data
+ * @crc: Enable the cyclic redundancy check
+ * @vpclk_div: Video port output clock control
+ */
+struct isp_csi2_platform_data {
+       unsigned crc:1;
+       unsigned vpclk_div:2;
+};
+
+struct isp_subdev_i2c_board_info {
+       struct i2c_board_info *board_info;
+       int i2c_adapter_id;
+};
+
+struct isp_v4l2_subdevs_group {
+       struct isp_subdev_i2c_board_info *subdevs;
+       enum isp_interface_type interface;
+       union {
+               struct isp_parallel_platform_data parallel;
+               struct isp_ccp2_platform_data ccp2;
+               struct isp_csi2_platform_data csi2;
+       } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */
+};
+
+struct isp_platform_data {
+       struct isp_v4l2_subdevs_group *subdevs;
+       void (*set_constraints)(struct isp_device *isp, bool enable);
+};
+
+#endif /* __MEDIA_OMAP3ISP_H__ */
index b1f19b7..b0c494a 100644 (file)
 #include <media/rc-map.h>
 
 extern int rc_core_debug;
-#define IR_dprintk(level, fmt, arg...) if (rc_core_debug >= level) \
-       printk(KERN_DEBUG "%s: " fmt , __func__, ## arg)
+#define IR_dprintk(level, fmt, ...)                            \
+do {                                                           \
+       if (rc_core_debug >= level)                             \
+               pr_debug("%s: " fmt, __func__, ##__VA_ARGS__);  \
+} while (0)
 
 enum rc_driver_type {
        RC_DRIVER_SCANCODE = 0, /* Driver or hardware generates a scancode */
index 17c9759..26a3bd0 100644 (file)
@@ -61,6 +61,7 @@ void rc_map_init(void);
 #define RC_MAP_APAC_VIEWCOMP             "rc-apac-viewcomp"
 #define RC_MAP_ASUS_PC39                 "rc-asus-pc39"
 #define RC_MAP_ATI_TV_WONDER_HD_600      "rc-ati-tv-wonder-hd-600"
+#define RC_MAP_ATI_X10                   "rc-ati-x10"
 #define RC_MAP_AVERMEDIA_A16D            "rc-avermedia-a16d"
 #define RC_MAP_AVERMEDIA_CARDBUS         "rc-avermedia-cardbus"
 #define RC_MAP_AVERMEDIA_DVBT            "rc-avermedia-dvbt"
@@ -106,6 +107,7 @@ void rc_map_init(void);
 #define RC_MAP_LIRC                      "rc-lirc"
 #define RC_MAP_LME2510                   "rc-lme2510"
 #define RC_MAP_MANLI                     "rc-manli"
+#define RC_MAP_MEDION_X10                "rc-medion-x10"
 #define RC_MAP_MSI_DIGIVOX_II            "rc-msi-digivox-ii"
 #define RC_MAP_MSI_DIGIVOX_III           "rc-msi-digivox-iii"
 #define RC_MAP_MSI_TVANYWHERE_PLUS       "rc-msi-tvanywhere-plus"
@@ -130,6 +132,7 @@ void rc_map_init(void);
 #define RC_MAP_RC5_TV                    "rc-rc5-tv"
 #define RC_MAP_RC6_MCE                   "rc-rc6-mce"
 #define RC_MAP_REAL_AUDIO_220_32_KEYS    "rc-real-audio-220-32-keys"
+#define RC_MAP_SNAPSTREAM_FIREFLY        "rc-snapstream-firefly"
 #define RC_MAP_STREAMZAP                 "rc-streamzap"
 #define RC_MAP_TBS_NEC                   "rc-tbs-nec"
 #define RC_MAP_TECHNISAT_USB2            "rc-technisat-usb2"
index 9fdff8a..688fb3f 100644 (file)
@@ -19,11 +19,6 @@ enum cam_bus_type {
        FIMC_LCD_WB, /* FIFO link from LCD mixer */
 };
 
-#define FIMC_CLK_INV_PCLK      (1 << 0)
-#define FIMC_CLK_INV_VSYNC     (1 << 1)
-#define FIMC_CLK_INV_HREF      (1 << 2)
-#define FIMC_CLK_INV_HSYNC     (1 << 3)
-
 struct i2c_board_info;
 
 /**
@@ -36,7 +31,8 @@ struct i2c_board_info;
  * @csi_data_align: MIPI-CSI interface data alignment in bits
  * @i2c_bus_num: i2c control bus id the sensor is attached to
  * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU)
- * @flags: flags defining bus signals polarity inversion (High by default)
+ * @clk_id: index of the SoC peripheral clock for sensors
+ * @flags: the parallel bus flags defining signals polarity (V4L2_MBUS_*)
  */
 struct s5p_fimc_isp_info {
        struct i2c_board_info *board_info;
@@ -46,6 +42,7 @@ struct s5p_fimc_isp_info {
        u16 i2c_bus_num;
        u16 mux_id;
        u16 flags;
+       u8 clk_id;
 };
 
 /**
@@ -58,4 +55,13 @@ struct s5p_platform_fimc {
        struct s5p_fimc_isp_info *isp_info;
        int num_clients;
 };
+
+/*
+ * v4l2_device notification id. This is only for internal use in the kernel.
+ * Sensor subdevs should issue S5P_FIMC_TX_END_NOTIFY notification in single
+ * frame capture mode when there is only one VSYNC pulse issued by the sensor
+ * at begining of the frame transmission.
+ */
+#define S5P_FIMC_TX_END_NOTIFY _IO('e', 0)
+
 #endif /* S5P_FIMC_H_ */
index 7982714..5017500 100644 (file)
 
 extern unsigned int saa7146_debug;
 
-//#define DEBUG_PROLOG printk("(0x%08x)(0x%08x) %s: %s(): ",(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,RPS_ADDR0))),(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,IER))),KBUILD_MODNAME,__func__)
-
 #ifndef DEBUG_VARIABLE
        #define DEBUG_VARIABLE saa7146_debug
 #endif
 
-#define DEBUG_PROLOG printk("%s: %s(): ",KBUILD_MODNAME, __func__)
-#define INFO(x) { printk("%s: ",KBUILD_MODNAME); printk x; }
-
-#define ERR(x) { DEBUG_PROLOG; printk x; }
-
-#define DEB_S(x)    if (0!=(DEBUG_VARIABLE&0x01)) { DEBUG_PROLOG; printk x; } /* simple debug messages */
-#define DEB_D(x)    if (0!=(DEBUG_VARIABLE&0x02)) { DEBUG_PROLOG; printk x; } /* more detailed debug messages */
-#define DEB_EE(x)   if (0!=(DEBUG_VARIABLE&0x04)) { DEBUG_PROLOG; printk x; } /* print enter and exit of functions */
-#define DEB_I2C(x)  if (0!=(DEBUG_VARIABLE&0x08)) { DEBUG_PROLOG; printk x; } /* i2c debug messages */
-#define DEB_VBI(x)  if (0!=(DEBUG_VARIABLE&0x10)) { DEBUG_PROLOG; printk x; } /* vbi debug messages */
-#define DEB_INT(x)  if (0!=(DEBUG_VARIABLE&0x20)) { DEBUG_PROLOG; printk x; } /* interrupt debug messages */
-#define DEB_CAP(x)  if (0!=(DEBUG_VARIABLE&0x40)) { DEBUG_PROLOG; printk x; } /* capture debug messages */
+#define ERR(fmt, ...)  pr_err("%s: " fmt, __func__, ##__VA_ARGS__)
+
+#define _DBG(mask, fmt, ...)                                           \
+do {                                                                   \
+       if (DEBUG_VARIABLE & mask)                                      \
+               pr_debug("%s(): " fmt, __func__, ##__VA_ARGS__);        \
+} while (0)
+
+/* simple debug messages */
+#define DEB_S(fmt, ...)                _DBG(0x01, fmt, ##__VA_ARGS__)
+/* more detailed debug messages */
+#define DEB_D(fmt, ...)                _DBG(0x02, fmt, ##__VA_ARGS__)
+/* print enter and exit of functions */
+#define DEB_EE(fmt, ...)       _DBG(0x04, fmt, ##__VA_ARGS__)
+/* i2c debug messages */
+#define DEB_I2C(fmt, ...)      _DBG(0x08, fmt, ##__VA_ARGS__)
+/* vbi debug messages */
+#define DEB_VBI(fmt, ...)      _DBG(0x10, fmt, ##__VA_ARGS__)
+/* interrupt debug messages */
+#define DEB_INT(fmt, ...)      _DBG(0x20, fmt, ##__VA_ARGS__)
+/* capture debug messages */
+#define DEB_CAP(fmt, ...)      _DBG(0x40, fmt, ##__VA_ARGS__)
 
 #define SAA7146_ISR_CLEAR(x,y) \
        saa7146_write(x, ISR, (y));
index 63fd9d3..810a209 100644 (file)
@@ -212,9 +212,6 @@ enum {
        /* module sn9c20x: just ident 10000 */
        V4L2_IDENT_SN9C20X = 10000,
 
-       /* Siliconfile sensors: reserved range 10100 - 10199 */
-       V4L2_IDENT_NOON010PC30  = 10100,
-
        /* module cx231xx and cx25840 */
        V4L2_IDENT_CX2310X_AV = 23099, /* Integrated A/V decoder; not in '100 */
        V4L2_IDENT_CX23100    = 23100,
index 13fe4d7..eeb3df6 100644 (file)
@@ -65,14 +65,12 @@ struct v4l2_ctrl_ops {
   * @is_private: If set, then this control is private to its handler and it
   *            will not be added to any other handlers. Drivers can set
   *            this flag.
-  * @is_volatile: If set, then this control is volatile. This means that the
-  *            control's current value cannot be cached and needs to be
-  *            retrieved through the g_volatile_ctrl op. Drivers can set
-  *            this flag.
   * @is_auto:   If set, then this control selects whether the other cluster
   *            members are in 'automatic' mode or 'manual' mode. This is
   *            used for autogain/gain type clusters. Drivers should never
   *            set this flag directly.
+  * @has_volatiles: If set, then one or more members of the cluster are volatile.
+  *            Drivers should never touch this flag.
   * @manual_mode_value: If the is_auto flag is set, then this is the value
   *            of the auto control that determines if that control is in
   *            manual mode. So if the value of the auto control equals this
@@ -118,8 +116,8 @@ struct v4l2_ctrl {
 
        unsigned int is_new:1;
        unsigned int is_private:1;
-       unsigned int is_volatile:1;
        unsigned int is_auto:1;
+       unsigned int has_volatiles:1;
        unsigned int manual_mode_value:8;
 
        const struct v4l2_ctrl_ops *ops;
@@ -208,9 +206,6 @@ struct v4l2_ctrl_handler {
   *            must be NULL.
   * @is_private: If set, then this control is private to its handler and it
   *            will not be added to any other handlers.
-  * @is_volatile: If set, then this control is volatile. This means that the
-  *            control's current value cannot be cached and needs to be
-  *            retrieved through the g_volatile_ctrl op.
   */
 struct v4l2_ctrl_config {
        const struct v4l2_ctrl_ops *ops;
@@ -225,7 +220,6 @@ struct v4l2_ctrl_config {
        u32 menu_skip_mask;
        const char * const *qmenu;
        unsigned int is_private:1;
-       unsigned int is_volatile:1;
 };
 
 /** v4l2_ctrl_fill() - Fill in the control fields based on the control ID.
@@ -389,8 +383,7 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls);
   * @manual_val: The value for the first control in the cluster that equals the
   *            manual setting.
   * @set_volatile: If true, then all controls except the first auto control will
-  *            have is_volatile set to true. If false, then is_volatile will not
-  *            be touched.
+  *            be volatile.
   *
   * Use for control groups where one control selects some automatic feature and
   * the other controls are only active whenever the automatic feature is turned
index 6114007..83ae07e 100644 (file)
  */
 #define V4L2_MBUS_MASTER                       (1 << 0)
 #define V4L2_MBUS_SLAVE                                (1 << 1)
-/* Which signal polarities it supports */
-/* Note: in BT.656 mode HSYNC and VSYNC are unused */
+/*
+ * Signal polarity flags
+ * Note: in BT.656 mode HSYNC, FIELD, and VSYNC are unused
+ * V4L2_MBUS_[HV]SYNC* flags should be also used for specifying
+ * configuration of hardware that uses [HV]REF signals
+ */
 #define V4L2_MBUS_HSYNC_ACTIVE_HIGH            (1 << 2)
 #define V4L2_MBUS_HSYNC_ACTIVE_LOW             (1 << 3)
 #define V4L2_MBUS_VSYNC_ACTIVE_HIGH            (1 << 4)
 #define V4L2_MBUS_PCLK_SAMPLE_FALLING          (1 << 7)
 #define V4L2_MBUS_DATA_ACTIVE_HIGH             (1 << 8)
 #define V4L2_MBUS_DATA_ACTIVE_LOW              (1 << 9)
+/* FIELD = 0/1 - Field1 (odd)/Field2 (even) */
+#define V4L2_MBUS_FIELD_EVEN_HIGH              (1 << 10)
+/* FIELD = 1/0 - Field1 (odd)/Field2 (even) */
+#define V4L2_MBUS_FIELD_EVEN_LOW               (1 << 11)
 
 /* Serial flags */
 /* How many lanes the client can use */
index f87472a..ea55c08 100644 (file)
@@ -75,7 +75,6 @@ struct vb2_mem_ops {
 
 struct vb2_plane {
        void                    *mem_priv;
-       int                     mapped:1;
 };
 
 /**
@@ -147,7 +146,6 @@ struct vb2_queue;
  * @done_entry:                entry on the list that stores all buffers ready to
  *                     be dequeued to userspace
  * @planes:            private per-plane information; do not change
- * @num_planes_mapped: number of mapped planes; do not change
  */
 struct vb2_buffer {
        struct v4l2_buffer      v4l2_buf;
@@ -164,7 +162,6 @@ struct vb2_buffer {
        struct list_head        done_entry;
 
        struct vb2_plane        planes[VIDEO_MAX_PLANES];
-       unsigned int            num_planes_mapped;
 };
 
 /**
@@ -199,19 +196,28 @@ struct vb2_buffer {
  *                     before userspace accesses the buffer; optional
  * @buf_cleanup:       called once before the buffer is freed; drivers may
  *                     perform any additional cleanup; optional
- * @start_streaming:   called once before entering 'streaming' state; enables
- *                     driver to receive buffers over buf_queue() callback
+ * @start_streaming:   called once to enter 'streaming' state; the driver may
+ *                     receive buffers with @buf_queue callback before
+ *                     @start_streaming is called; the driver gets the number
+ *                     of already queued buffers in count parameter; driver
+ *                     can return an error if hardware fails or not enough
+ *                     buffers has been queued, in such case all buffers that
+ *                     have been already given by the @buf_queue callback are
+ *                     invalidated.
  * @stop_streaming:    called when 'streaming' state must be disabled; driver
  *                     should stop any DMA transactions or wait until they
  *                     finish and give back all buffers it got from buf_queue()
  *                     callback; may use vb2_wait_for_all_buffers() function
  * @buf_queue:         passes buffer vb to the driver; driver may start
  *                     hardware operation on this buffer; driver should give
- *                     the buffer back by calling vb2_buffer_done() function
+ *                     the buffer back by calling vb2_buffer_done() function;
+ *                     it is allways called after calling STREAMON ioctl;
+ *                     might be called before start_streaming callback if user
+ *                     pre-queued buffers before calling STREAMON
  */
 struct vb2_ops {
        int (*queue_setup)(struct vb2_queue *q, unsigned int *num_buffers,
-                          unsigned int *num_planes, unsigned long sizes[],
+                          unsigned int *num_planes, unsigned int sizes[],
                           void *alloc_ctxs[]);
 
        void (*wait_prepare)(struct vb2_queue *q);
@@ -222,7 +228,7 @@ struct vb2_ops {
        int (*buf_finish)(struct vb2_buffer *vb);
        void (*buf_cleanup)(struct vb2_buffer *vb);
 
-       int (*start_streaming)(struct vb2_queue *q);
+       int (*start_streaming)(struct vb2_queue *q, unsigned int count);
        int (*stop_streaming)(struct vb2_queue *q);
 
        void (*buf_queue)(struct vb2_buffer *vb);
@@ -276,6 +282,7 @@ struct vb2_queue {
        wait_queue_head_t               done_wq;
 
        void                            *alloc_ctx[VIDEO_MAX_PLANES];
+       unsigned int                    plane_sizes[VIDEO_MAX_PLANES];
 
        unsigned int                    streaming:1;
 
index 7e6c68b..19ae1e3 100644 (file)
 #include <linux/dma-mapping.h>
 
 static inline dma_addr_t
-vb2_dma_contig_plane_paddr(struct vb2_buffer *vb, unsigned int plane_no)
+vb2_dma_contig_plane_dma_addr(struct vb2_buffer *vb, unsigned int plane_no)
 {
-       dma_addr_t *paddr = vb2_plane_cookie(vb, plane_no);
+       dma_addr_t *addr = vb2_plane_cookie(vb, plane_no);
 
-       return *paddr;
+       return *addr;
 }
 
 void *vb2_dma_contig_init_ctx(struct device *dev);
diff --git a/include/misc/altera.h b/include/misc/altera.h
new file mode 100644 (file)
index 0000000..94c0c61
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * altera.h
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * 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 _ALTERA_H_
+#define _ALTERA_H_
+
+struct altera_config {
+       void *dev;
+       u8 *action;
+       int (*jtag_io) (void *dev, int tms, int tdi, int tdo);
+};
+
+#if defined(CONFIG_ALTERA_STAPL) || \
+               (defined(CONFIG_ALTERA_STAPL_MODULE) && defined(MODULE))
+
+extern int altera_init(struct altera_config *config, const struct firmware *fw);
+#else
+
+static inline int altera_init(struct altera_config *config,
+                                               const struct firmware *fw)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return 0;
+}
+#endif /* CONFIG_ALTERA_STAPL */
+
+#endif /* _ALTERA_H_ */
index 180231c..f91a1fb 100644 (file)
@@ -134,6 +134,7 @@ struct inet_timewait_sock {
        struct inet_bind_bucket *tw_tb;
        struct hlist_node       tw_death_node;
 };
+#define tw_tclass tw_tos
 
 static inline void inet_twsk_add_node_rcu(struct inet_timewait_sock *tw,
                                      struct hlist_nulls_head *list)
index 3b5ac1f..a366a8a 100644 (file)
@@ -486,7 +486,8 @@ extern int                  ip6_rcv_finish(struct sk_buff *skb);
 extern int                     ip6_xmit(struct sock *sk,
                                         struct sk_buff *skb,
                                         struct flowi6 *fl6,
-                                        struct ipv6_txoptions *opt);
+                                        struct ipv6_txoptions *opt,
+                                        int tclass);
 
 extern int                     ip6_nd_hdr(struct sock *sk,
                                           struct sk_buff *skb,
diff --git a/include/video/omap-panel-dvi.h b/include/video/omap-panel-dvi.h
new file mode 100644 (file)
index 0000000..87ad567
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Header for DVI output driver
+ *
+ * Copyright (C) 2011 Texas Instruments Inc
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OMAP_PANEL_DVI_H
+#define __OMAP_PANEL_DVI_H
+
+struct omap_dss_device;
+
+/**
+ * struct panel_dvi_platform_data - panel driver configuration data
+ * @platform_enable: platform specific panel enable function
+ * @platform_disable: platform specific panel disable function
+ * @i2c_bus_num: i2c bus id for the panel
+ */
+struct panel_dvi_platform_data {
+       int (*platform_enable)(struct omap_dss_device *dssdev);
+       void (*platform_disable)(struct omap_dss_device *dssdev);
+       u16 i2c_bus_num;
+};
+
+#endif /* __OMAP_PANEL_DVI_H */
diff --git a/include/video/omap-panel-n8x0.h b/include/video/omap-panel-n8x0.h
new file mode 100644 (file)
index 0000000..50a1302
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __OMAP_PANEL_N8X0_H
+#define __OMAP_PANEL_N8X0_H
+
+struct omap_dss_device;
+
+struct panel_n8x0_data {
+       int (*platform_enable)(struct omap_dss_device *dssdev);
+       void (*platform_disable)(struct omap_dss_device *dssdev);
+       int panel_reset;
+       int ctrl_pwrdown;
+
+       int (*set_backlight)(struct omap_dss_device *dssdev, int level);
+};
+
+#endif
index 921ae93..7dc71f9 100644 (file)
@@ -10,9 +10,7 @@ struct omap_dss_device;
  * @ext_te_gpio: external TE GPIO
  * @esd_interval: interval of ESD checks, 0 = disabled (ms)
  * @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms)
- * @max_backlight_level: maximum backlight level
- * @set_backlight: pointer to backlight set function
- * @get_backlight: pointer to backlight get function
+ * @use_dsi_backlight: true if panel uses DSI command to control backlight
  */
 struct nokia_dsi_panel_data {
        const char *name;
@@ -25,9 +23,7 @@ struct nokia_dsi_panel_data {
        unsigned esd_interval;
        unsigned ulps_timeout;
 
-       int max_backlight_level;
-       int (*set_backlight)(struct omap_dss_device *dssdev, int level);
-       int (*get_backlight)(struct omap_dss_device *dssdev);
+       bool use_dsi_backlight;
 };
 
 #endif /* __OMAP_NOKIA_DSI_PANEL_H */
diff --git a/include/video/omap-panel-picodlp.h b/include/video/omap-panel-picodlp.h
new file mode 100644 (file)
index 0000000..1c342ef
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * panel data for picodlp panel
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * Author: Mayuresh Janorkar <mayur@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __PANEL_PICODLP_H
+#define __PANEL_PICODLP_H
+/**
+ * struct : picodlp panel data
+ * picodlp_adapter_id: i2c_adapter number for picodlp
+ */
+struct picodlp_panel_data {
+       int picodlp_adapter_id;
+       int emu_done_gpio;
+       int pwrgood_gpio;
+};
+#endif /* __PANEL_PICODLP_H */
index 3b55ef2..b66ebb2 100644 (file)
 #define DISPC_IRQ_WAKEUP               (1 << 16)
 #define DISPC_IRQ_SYNC_LOST2           (1 << 17)
 #define DISPC_IRQ_VSYNC2               (1 << 18)
+#define DISPC_IRQ_VID3_END_WIN         (1 << 19)
+#define DISPC_IRQ_VID3_FIFO_UNDERFLOW  (1 << 20)
 #define DISPC_IRQ_ACBIAS_COUNT_STAT2   (1 << 21)
 #define DISPC_IRQ_FRAMEDONE2           (1 << 22)
+#define DISPC_IRQ_FRAMEDONEWB          (1 << 23)
+#define DISPC_IRQ_FRAMEDONETV          (1 << 24)
+#define DISPC_IRQ_WBBUFFEROVERFLOW     (1 << 25)
 
 struct omap_dss_device;
 struct omap_overlay_manager;
@@ -60,7 +65,8 @@ enum omap_display_type {
 enum omap_plane {
        OMAP_DSS_GFX    = 0,
        OMAP_DSS_VIDEO1 = 1,
-       OMAP_DSS_VIDEO2 = 2
+       OMAP_DSS_VIDEO2 = 2,
+       OMAP_DSS_VIDEO3 = 3,
 };
 
 enum omap_channel {
@@ -129,6 +135,18 @@ enum omap_dss_venc_type {
        OMAP_DSS_VENC_TYPE_SVIDEO,
 };
 
+enum omap_dss_dsi_pixel_format {
+       OMAP_DSS_DSI_FMT_RGB888,
+       OMAP_DSS_DSI_FMT_RGB666,
+       OMAP_DSS_DSI_FMT_RGB666_PACKED,
+       OMAP_DSS_DSI_FMT_RGB565,
+};
+
+enum omap_dss_dsi_mode {
+       OMAP_DSS_DSI_CMD_MODE = 0,
+       OMAP_DSS_DSI_VIDEO_MODE,
+};
+
 enum omap_display_caps {
        OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE      = 1 << 0,
        OMAP_DSS_DISPLAY_CAP_TEAR_ELIM          = 1 << 1,
@@ -162,11 +180,13 @@ enum omap_dss_rotation_angle {
 
 enum omap_overlay_caps {
        OMAP_DSS_OVL_CAP_SCALE = 1 << 0,
-       OMAP_DSS_OVL_CAP_DISPC = 1 << 1,
+       OMAP_DSS_OVL_CAP_GLOBAL_ALPHA = 1 << 1,
+       OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA = 1 << 2,
+       OMAP_DSS_OVL_CAP_ZORDER = 1 << 3,
 };
 
 enum omap_overlay_manager_caps {
-       OMAP_DSS_OVL_MGR_CAP_DISPC = 1 << 0,
+       OMAP_DSS_DUMMY_VALUE, /* add a dummy value to prevent compiler error */
 };
 
 enum omap_dss_clk_source {
@@ -215,26 +235,67 @@ void rfbi_bus_lock(void);
 void rfbi_bus_unlock(void);
 
 /* DSI */
+
+struct omap_dss_dsi_videomode_data {
+       /* DSI video mode blanking data */
+       /* Unit: byte clock cycles */
+       u16 hsa;
+       u16 hfp;
+       u16 hbp;
+       /* Unit: line clocks */
+       u16 vsa;
+       u16 vfp;
+       u16 vbp;
+
+       /* DSI blanking modes */
+       int blanking_mode;
+       int hsa_blanking_mode;
+       int hbp_blanking_mode;
+       int hfp_blanking_mode;
+
+       /* Video port sync events */
+       int vp_de_pol;
+       int vp_hsync_pol;
+       int vp_vsync_pol;
+       bool vp_vsync_end;
+       bool vp_hsync_end;
+
+       bool ddr_clk_always_on;
+       int window_sync;
+};
+
 void dsi_bus_lock(struct omap_dss_device *dssdev);
 void dsi_bus_unlock(struct omap_dss_device *dssdev);
 int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
                int len);
-int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel,
-               u8 dcs_cmd);
+int dsi_vc_generic_write(struct omap_dss_device *dssdev, int channel, u8 *data,
+               int len);
+int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd);
+int dsi_vc_generic_write_0(struct omap_dss_device *dssdev, int channel);
 int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
                u8 param);
+int dsi_vc_generic_write_1(struct omap_dss_device *dssdev, int channel,
+               u8 param);
+int dsi_vc_generic_write_2(struct omap_dss_device *dssdev, int channel,
+               u8 param1, u8 param2);
 int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
                u8 *data, int len);
+int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel,
+               u8 *data, int len);
 int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
                u8 *buf, int buflen);
-int dsi_vc_dcs_read_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
-               u8 *data);
-int dsi_vc_dcs_read_2(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
-               u8 *data1, u8 *data2);
+int dsi_vc_generic_read_0(struct omap_dss_device *dssdev, int channel, u8 *buf,
+               int buflen);
+int dsi_vc_generic_read_1(struct omap_dss_device *dssdev, int channel, u8 param,
+               u8 *buf, int buflen);
+int dsi_vc_generic_read_2(struct omap_dss_device *dssdev, int channel,
+               u8 param1, u8 param2, u8 *buf, int buflen);
 int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
                u16 len);
 int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);
 int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel);
+int dsi_video_mode_enable(struct omap_dss_device *dssdev, int channel);
+void dsi_video_mode_disable(struct omap_dss_device *dssdev, int channel);
 
 /* Board specific data */
 struct omap_dss_board_info {
@@ -242,7 +303,8 @@ struct omap_dss_board_info {
        int num_devices;
        struct omap_dss_device **devices;
        struct omap_dss_device *default_device;
-       void (*dsi_mux_pads)(bool enable);
+       int (*dsi_enable_pads)(int dsi_id, unsigned lane_mask);
+       void (*dsi_disable_pads)(int dsi_id, unsigned lane_mask);
 };
 
 #if defined(CONFIG_OMAP2_DSS_MODULE) || defined(CONFIG_OMAP2_DSS)
@@ -300,7 +362,6 @@ struct omap_overlay_info {
        bool enabled;
 
        u32 paddr;
-       void __iomem *vaddr;
        u32 p_uv_addr;  /* for NV12 format */
        u16 screen_width;
        u16 width;
@@ -316,6 +377,7 @@ struct omap_overlay_info {
        u16 out_height; /* if 0, out_height == height */
        u8 global_alpha;
        u8 pre_mult_alpha;
+       u8 zorder;
 };
 
 struct omap_overlay {
@@ -324,7 +386,7 @@ struct omap_overlay {
 
        /* static fields */
        const char *name;
-       int id;
+       enum omap_plane id;
        enum omap_color_mode supported_modes;
        enum omap_overlay_caps caps;
 
@@ -332,6 +394,7 @@ struct omap_overlay {
        struct omap_overlay_manager *manager;
        struct omap_overlay_info info;
 
+       bool manager_changed;
        /* if true, info has been changed, but not applied() yet */
        bool info_dirty;
 
@@ -354,7 +417,7 @@ struct omap_overlay_manager_info {
        u32 trans_key;
        bool trans_enabled;
 
-       bool alpha_enabled;
+       bool partial_alpha_enabled;
 
        bool cpr_enable;
        struct omap_dss_cpr_coefs cpr_coefs;
@@ -366,7 +429,7 @@ struct omap_overlay_manager {
 
        /* static fields */
        const char *name;
-       int id;
+       enum omap_channel id;
        enum omap_overlay_manager_caps caps;
        int num_overlays;
        struct omap_overlay **overlays;
@@ -454,6 +517,7 @@ struct omap_dss_device {
                } dispc;
 
                struct {
+                       /* regn is one greater than TRM's REGN value */
                        u16 regn;
                        u16 regm;
                        u16 regm_dispc;
@@ -464,6 +528,7 @@ struct omap_dss_device {
                } dsi;
 
                struct {
+                       /* regn is one greater than TRM's REGN value */
                        u16 regn;
                        u16 regm2;
                } hdmi;
@@ -477,6 +542,10 @@ struct omap_dss_device {
                int acb;        /* ac-bias pin frequency */
 
                enum omap_panel_config config;
+
+               enum omap_dss_dsi_pixel_format dsi_pix_fmt;
+               enum omap_dss_dsi_mode dsi_mode;
+               struct omap_dss_dsi_videomode_data dsi_vm_data;
        } panel;
 
        struct {
@@ -557,6 +626,9 @@ struct omap_dss_driver {
 
        int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
        u32 (*get_wss)(struct omap_dss_device *dssdev);
+
+       int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
+       bool (*detect)(struct omap_dss_device *dssdev);
 };
 
 int omap_dss_register_driver(struct omap_dss_driver *);
index d964e68..8101b72 100644 (file)
 #include <linux/fb.h>
 #include <video/sh_mobile_meram.h>
 
+/* Register definitions */
+#define _LDDCKR                        0x410
+#define LDDCKR_ICKSEL_BUS      (0 << 16)
+#define LDDCKR_ICKSEL_MIPI     (1 << 16)
+#define LDDCKR_ICKSEL_HDMI     (2 << 16)
+#define LDDCKR_ICKSEL_EXT      (3 << 16)
+#define LDDCKR_ICKSEL_MASK     (7 << 16)
+#define LDDCKR_MOSEL           (1 << 6)
+#define _LDDCKSTPR             0x414
+#define _LDINTR                        0x468
+#define LDINTR_FE              (1 << 10)
+#define LDINTR_VSE             (1 << 9)
+#define LDINTR_VEE             (1 << 8)
+#define LDINTR_FS              (1 << 2)
+#define LDINTR_VSS             (1 << 1)
+#define LDINTR_VES             (1 << 0)
+#define LDINTR_STATUS_MASK     (0xff << 0)
+#define _LDSR                  0x46c
+#define LDSR_MSS               (1 << 10)
+#define LDSR_MRS               (1 << 8)
+#define LDSR_AS                        (1 << 1)
+#define _LDCNT1R               0x470
+#define LDCNT1R_DE             (1 << 0)
+#define _LDCNT2R               0x474
+#define LDCNT2R_BR             (1 << 8)
+#define LDCNT2R_MD             (1 << 3)
+#define LDCNT2R_SE             (1 << 2)
+#define LDCNT2R_ME             (1 << 1)
+#define LDCNT2R_DO             (1 << 0)
+#define _LDRCNTR               0x478
+#define LDRCNTR_SRS            (1 << 17)
+#define LDRCNTR_SRC            (1 << 16)
+#define LDRCNTR_MRS            (1 << 1)
+#define LDRCNTR_MRC            (1 << 0)
+#define _LDDDSR                        0x47c
+#define LDDDSR_LS              (1 << 2)
+#define LDDDSR_WS              (1 << 1)
+#define LDDDSR_BS              (1 << 0)
+
+#define LDMT1R_VPOL            (1 << 28)
+#define LDMT1R_HPOL            (1 << 27)
+#define LDMT1R_DWPOL           (1 << 26)
+#define LDMT1R_DIPOL           (1 << 25)
+#define LDMT1R_DAPOL           (1 << 24)
+#define LDMT1R_HSCNT           (1 << 17)
+#define LDMT1R_DWCNT           (1 << 16)
+#define LDMT1R_IFM             (1 << 12)
+#define LDMT1R_MIFTYP_RGB8     (0x0 << 0)
+#define LDMT1R_MIFTYP_RGB9     (0x4 << 0)
+#define LDMT1R_MIFTYP_RGB12A   (0x5 << 0)
+#define LDMT1R_MIFTYP_RGB12B   (0x6 << 0)
+#define LDMT1R_MIFTYP_RGB16    (0x7 << 0)
+#define LDMT1R_MIFTYP_RGB18    (0xa << 0)
+#define LDMT1R_MIFTYP_RGB24    (0xb << 0)
+#define LDMT1R_MIFTYP_YCBCR    (0xf << 0)
+#define LDMT1R_MIFTYP_SYS8A    (0x0 << 0)
+#define LDMT1R_MIFTYP_SYS8B    (0x1 << 0)
+#define LDMT1R_MIFTYP_SYS8C    (0x2 << 0)
+#define LDMT1R_MIFTYP_SYS8D    (0x3 << 0)
+#define LDMT1R_MIFTYP_SYS9     (0x4 << 0)
+#define LDMT1R_MIFTYP_SYS12    (0x5 << 0)
+#define LDMT1R_MIFTYP_SYS16A   (0x7 << 0)
+#define LDMT1R_MIFTYP_SYS16B   (0x8 << 0)
+#define LDMT1R_MIFTYP_SYS16C   (0x9 << 0)
+#define LDMT1R_MIFTYP_SYS18    (0xa << 0)
+#define LDMT1R_MIFTYP_SYS24    (0xb << 0)
+#define LDMT1R_MIFTYP_MASK     (0xf << 0)
+
+#define LDDFR_CF1              (1 << 18)
+#define LDDFR_CF0              (1 << 17)
+#define LDDFR_CC               (1 << 16)
+#define LDDFR_YF_420           (0 << 8)
+#define LDDFR_YF_422           (1 << 8)
+#define LDDFR_YF_444           (2 << 8)
+#define LDDFR_YF_MASK          (3 << 8)
+#define LDDFR_PKF_ARGB32       (0x00 << 0)
+#define LDDFR_PKF_RGB16                (0x03 << 0)
+#define LDDFR_PKF_RGB24                (0x0b << 0)
+#define LDDFR_PKF_MASK         (0x1f << 0)
+
+#define LDSM1R_OS              (1 << 0)
+
+#define LDSM2R_OSTRG           (1 << 0)
+
+#define LDPMR_LPS              (3 << 0)
+
+#define _LDDWD0R               0x800
+#define LDDWDxR_WDACT          (1 << 28)
+#define LDDWDxR_RSW            (1 << 24)
+#define _LDDRDR                        0x840
+#define LDDRDR_RSR             (1 << 24)
+#define LDDRDR_DRD_MASK                (0x3ffff << 0)
+#define _LDDWAR                        0x900
+#define LDDWAR_WA              (1 << 0)
+#define _LDDRAR                        0x904
+#define LDDRAR_RA              (1 << 0)
+
 enum {
-       RGB8,   /* 24bpp, 8:8:8 */
-       RGB9,   /* 18bpp, 9:9 */
-       RGB12A, /* 24bpp, 12:12 */
-       RGB12B, /* 12bpp */
-       RGB16,  /* 16bpp */
-       RGB18,  /* 18bpp */
-       RGB24,  /* 24bpp */
-       YUV422, /* 16bpp */
-       SYS8A,  /* 24bpp, 8:8:8 */
-       SYS8B,  /* 18bpp, 8:8:2 */
-       SYS8C,  /* 18bpp, 2:8:8 */
-       SYS8D,  /* 16bpp, 8:8 */
-       SYS9,   /* 18bpp, 9:9 */
-       SYS12,  /* 24bpp, 12:12 */
-       SYS16A, /* 16bpp */
-       SYS16B, /* 18bpp, 16:2 */
-       SYS16C, /* 18bpp, 2:16 */
-       SYS18,  /* 18bpp */
-       SYS24,  /* 24bpp */
+       RGB8    = LDMT1R_MIFTYP_RGB8,   /* 24bpp, 8:8:8 */
+       RGB9    = LDMT1R_MIFTYP_RGB9,   /* 18bpp, 9:9 */
+       RGB12A  = LDMT1R_MIFTYP_RGB12A, /* 24bpp, 12:12 */
+       RGB12B  = LDMT1R_MIFTYP_RGB12B, /* 12bpp */
+       RGB16   = LDMT1R_MIFTYP_RGB16,  /* 16bpp */
+       RGB18   = LDMT1R_MIFTYP_RGB18,  /* 18bpp */
+       RGB24   = LDMT1R_MIFTYP_RGB24,  /* 24bpp */
+       YUV422  = LDMT1R_MIFTYP_YCBCR,  /* 16bpp */
+       SYS8A   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8A,     /* 24bpp, 8:8:8 */
+       SYS8B   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8B,     /* 18bpp, 8:8:2 */
+       SYS8C   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8C,     /* 18bpp, 2:8:8 */
+       SYS8D   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8D,     /* 16bpp, 8:8 */
+       SYS9    = LDMT1R_IFM | LDMT1R_MIFTYP_SYS9,      /* 18bpp, 9:9 */
+       SYS12   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS12,     /* 24bpp, 12:12 */
+       SYS16A  = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16A,    /* 16bpp */
+       SYS16B  = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16B,    /* 18bpp, 16:2 */
+       SYS16C  = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16C,    /* 18bpp, 2:16 */
+       SYS18   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS18,     /* 18bpp */
+       SYS24   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS24,     /* 24bpp */
 };
 
 enum { LCDC_CHAN_DISABLED = 0,
index 69d485a..c41f308 100644 (file)
@@ -50,6 +50,7 @@ struct dlfb_data {
        int base16;
        int base8;
        u32 pseudo_palette[256];
+       int blank_mode; /*one of FB_BLANK_ */
        /* blit-only rendering path metrics, exposed through sysfs */
        atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */
        atomic_t bytes_identical; /* saved effort with backbuffer comparison */
index db07bfd..79700fa 100644 (file)
@@ -62,6 +62,8 @@ struct dma_debug_entry {
 #endif
 };
 
+typedef bool (*match_fn)(struct dma_debug_entry *, struct dma_debug_entry *);
+
 struct hash_bucket {
        struct list_head list;
        spinlock_t lock;
@@ -240,18 +242,37 @@ static void put_hash_bucket(struct hash_bucket *bucket,
        spin_unlock_irqrestore(&bucket->lock, __flags);
 }
 
+static bool exact_match(struct dma_debug_entry *a, struct dma_debug_entry *b)
+{
+       return ((a->dev_addr == a->dev_addr) &&
+               (a->dev == b->dev)) ? true : false;
+}
+
+static bool containing_match(struct dma_debug_entry *a,
+                            struct dma_debug_entry *b)
+{
+       if (a->dev != b->dev)
+               return false;
+
+       if ((b->dev_addr <= a->dev_addr) &&
+           ((b->dev_addr + b->size) >= (a->dev_addr + a->size)))
+               return true;
+
+       return false;
+}
+
 /*
  * Search a given entry in the hash bucket list
  */
-static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket,
-                                               struct dma_debug_entry *ref)
+static struct dma_debug_entry *__hash_bucket_find(struct hash_bucket *bucket,
+                                                 struct dma_debug_entry *ref,
+                                                 match_fn match)
 {
        struct dma_debug_entry *entry, *ret = NULL;
        int matches = 0, match_lvl, last_lvl = 0;
 
        list_for_each_entry(entry, &bucket->list, list) {
-               if ((entry->dev_addr != ref->dev_addr) ||
-                   (entry->dev != ref->dev))
+               if (!match(ref, entry))
                        continue;
 
                /*
@@ -293,6 +314,39 @@ static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket,
        return ret;
 }
 
+static struct dma_debug_entry *bucket_find_exact(struct hash_bucket *bucket,
+                                                struct dma_debug_entry *ref)
+{
+       return __hash_bucket_find(bucket, ref, exact_match);
+}
+
+static struct dma_debug_entry *bucket_find_contain(struct hash_bucket **bucket,
+                                                  struct dma_debug_entry *ref,
+                                                  unsigned long *flags)
+{
+
+       unsigned int max_range = dma_get_max_seg_size(ref->dev);
+       struct dma_debug_entry *entry, index = *ref;
+       unsigned int range = 0;
+
+       while (range <= max_range) {
+               entry = __hash_bucket_find(*bucket, &index, containing_match);
+
+               if (entry)
+                       return entry;
+
+               /*
+                * Nothing found, go back a hash bucket
+                */
+               put_hash_bucket(*bucket, flags);
+               range          += (1 << HASH_FN_SHIFT);
+               index.dev_addr -= (1 << HASH_FN_SHIFT);
+               *bucket = get_hash_bucket(&index, flags);
+       }
+
+       return NULL;
+}
+
 /*
  * Add an entry to a hash bucket
  */
@@ -802,7 +856,7 @@ static void check_unmap(struct dma_debug_entry *ref)
        }
 
        bucket = get_hash_bucket(ref, &flags);
-       entry = hash_bucket_find(bucket, ref);
+       entry = bucket_find_exact(bucket, ref);
 
        if (!entry) {
                err_printk(ref->dev, NULL, "DMA-API: device driver tries "
@@ -902,7 +956,7 @@ static void check_sync(struct device *dev,
 
        bucket = get_hash_bucket(ref, &flags);
 
-       entry = hash_bucket_find(bucket, ref);
+       entry = bucket_find_contain(&bucket, ref, &flags);
 
        if (!entry) {
                err_printk(dev, NULL, "DMA-API: device driver tries "
@@ -1060,7 +1114,7 @@ static int get_nr_mapped_entries(struct device *dev,
        int mapped_ents;
 
        bucket       = get_hash_bucket(ref, &flags);
-       entry        = hash_bucket_find(bucket, ref);
+       entry        = bucket_find_exact(bucket, ref);
        mapped_ents  = 0;
 
        if (entry)
index f1f2f7b..163397f 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/netpoll.h>
 #include "vlan.h"
 
-bool vlan_do_receive(struct sk_buff **skbp)
+bool vlan_do_receive(struct sk_buff **skbp, bool last_handler)
 {
        struct sk_buff *skb = *skbp;
        u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;
@@ -13,7 +13,10 @@ bool vlan_do_receive(struct sk_buff **skbp)
 
        vlan_dev = vlan_find_dev(skb->dev, vlan_id);
        if (!vlan_dev) {
-               if (vlan_id)
+               /* Only the last call to vlan_do_receive() should change
+                * pkt_type to PACKET_OTHERHOST
+                */
+               if (vlan_id && last_handler)
                        skb->pkt_type = PACKET_OTHERHOST;
                return false;
        }
index 873fb3d..c7aafc7 100644 (file)
@@ -137,10 +137,22 @@ static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
                kfree_rcu(tt_local_entry, rcu);
 }
 
+static void tt_global_entry_free_rcu(struct rcu_head *rcu)
+{
+       struct tt_global_entry *tt_global_entry;
+
+       tt_global_entry = container_of(rcu, struct tt_global_entry, rcu);
+
+       if (tt_global_entry->orig_node)
+               orig_node_free_ref(tt_global_entry->orig_node);
+
+       kfree(tt_global_entry);
+}
+
 static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
 {
        if (atomic_dec_and_test(&tt_global_entry->refcount))
-               kfree_rcu(tt_global_entry, rcu);
+               call_rcu(&tt_global_entry->rcu, tt_global_entry_free_rcu);
 }
 
 static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
@@ -710,6 +722,9 @@ void tt_global_del_orig(struct bat_priv *bat_priv,
        struct hlist_head *head;
        spinlock_t *list_lock; /* protects write access to the hash lists */
 
+       if (!hash)
+               return;
+
        for (i = 0; i < hash->size; i++) {
                head = &hash->table[i];
                list_lock = &hash->list_locks[i];
index 1ae3557..ab8d0fe 100644 (file)
@@ -224,22 +224,22 @@ struct socket_packet {
 
 struct tt_local_entry {
        uint8_t addr[ETH_ALEN];
+       struct hlist_node hash_entry;
        unsigned long last_seen;
        uint16_t flags;
        atomic_t refcount;
        struct rcu_head rcu;
-       struct hlist_node hash_entry;
 };
 
 struct tt_global_entry {
        uint8_t addr[ETH_ALEN];
+       struct hlist_node hash_entry; /* entry in the global table */
        struct orig_node *orig_node;
        uint8_t ttvn;
        uint16_t flags; /* only TT_GLOBAL_ROAM is used */
        unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */
        atomic_t refcount;
        struct rcu_head rcu;
-       struct hlist_node hash_entry; /* entry in the global table */
 };
 
 struct tt_change_node {
index edcf019..6ba50a1 100644 (file)
@@ -3283,18 +3283,18 @@ another_round:
 ncls:
 #endif
 
+       rx_handler = rcu_dereference(skb->dev->rx_handler);
        if (vlan_tx_tag_present(skb)) {
                if (pt_prev) {
                        ret = deliver_skb(skb, pt_prev, orig_dev);
                        pt_prev = NULL;
                }
-               if (vlan_do_receive(&skb))
+               if (vlan_do_receive(&skb, !rx_handler))
                        goto another_round;
                else if (unlikely(!skb))
                        goto out;
        }
 
-       rx_handler = rcu_dereference(skb->dev->rx_handler);
        if (rx_handler) {
                if (pt_prev) {
                        ret = deliver_skb(skb, pt_prev, orig_dev);
index b74f761..17ee85c 100644 (file)
@@ -271,7 +271,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
                                                         &ireq6->loc_addr,
                                                         &ireq6->rmt_addr);
                ipv6_addr_copy(&fl6.daddr, &ireq6->rmt_addr);
-               err = ip6_xmit(sk, skb, &fl6, opt);
+               err = ip6_xmit(sk, skb, &fl6, opt, np->tclass);
                err = net_xmit_eval(err);
        }
 
@@ -326,7 +326,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
        dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false);
        if (!IS_ERR(dst)) {
                skb_dst_set(skb, dst);
-               ip6_xmit(ctl_sk, skb, &fl6, NULL);
+               ip6_xmit(ctl_sk, skb, &fl6, NULL, 0);
                DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
                DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
                return;
index 85a2fbe..66363b6 100644 (file)
@@ -345,6 +345,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
                        tw6 = inet6_twsk((struct sock *)tw);
                        ipv6_addr_copy(&tw6->tw_v6_daddr, &np->daddr);
                        ipv6_addr_copy(&tw6->tw_v6_rcv_saddr, &np->rcv_saddr);
+                       tw->tw_tclass = np->tclass;
                        tw->tw_ipv6only = np->ipv6only;
                }
 #endif
index e39239e..d0611a5 100644 (file)
@@ -1713,6 +1713,40 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
        ip6_route_add(&cfg);
 }
 
+
+static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
+                                                 int plen,
+                                                 const struct net_device *dev,
+                                                 u32 flags, u32 noflags)
+{
+       struct fib6_node *fn;
+       struct rt6_info *rt = NULL;
+       struct fib6_table *table;
+
+       table = fib6_get_table(dev_net(dev), RT6_TABLE_PREFIX);
+       if (table == NULL)
+               return NULL;
+
+       write_lock_bh(&table->tb6_lock);
+       fn = fib6_locate(&table->tb6_root, pfx, plen, NULL, 0);
+       if (!fn)
+               goto out;
+       for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
+               if (rt->rt6i_dev->ifindex != dev->ifindex)
+                       continue;
+               if ((rt->rt6i_flags & flags) != flags)
+                       continue;
+               if ((noflags != 0) && ((rt->rt6i_flags & flags) != 0))
+                       continue;
+               dst_hold(&rt->dst);
+               break;
+       }
+out:
+       write_unlock_bh(&table->tb6_lock);
+       return rt;
+}
+
+
 /* Create "default" multicast route to the interface */
 
 static void addrconf_add_mroute(struct net_device *dev)
@@ -1842,10 +1876,13 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
                if (addrconf_finite_timeout(rt_expires))
                        rt_expires *= HZ;
 
-               rt = rt6_lookup(net, &pinfo->prefix, NULL,
-                               dev->ifindex, 1);
+               rt = addrconf_get_prefix_route(&pinfo->prefix,
+                                              pinfo->prefix_len,
+                                              dev,
+                                              RTF_ADDRCONF | RTF_PREFIX_RT,
+                                              RTF_GATEWAY | RTF_DEFAULT);
 
-               if (rt && addrconf_is_prefix_route(rt)) {
+               if (rt) {
                        /* Autoconf prefix route */
                        if (valid_lft == 0) {
                                ip6_del_rt(rt);
index 2916200..fee46d5 100644 (file)
@@ -248,7 +248,7 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
        /* Restore final destination back after routing done */
        ipv6_addr_copy(&fl6.daddr, &np->daddr);
 
-       res = ip6_xmit(sk, skb, &fl6, np->opt);
+       res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
        rcu_read_unlock();
        return res;
 }
index 1c9bf8b..84d0bd5 100644 (file)
@@ -180,7 +180,7 @@ int ip6_output(struct sk_buff *skb)
  */
 
 int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
-            struct ipv6_txoptions *opt)
+            struct ipv6_txoptions *opt, int tclass)
 {
        struct net *net = sock_net(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -190,7 +190,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
        u8  proto = fl6->flowi6_proto;
        int seg_len = skb->len;
        int hlimit = -1;
-       int tclass = 0;
        u32 mtu;
 
        if (opt) {
@@ -228,10 +227,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
        /*
         *      Fill in the IPv6 header
         */
-       if (np) {
-               tclass = np->tclass;
+       if (np)
                hlimit = np->hop_limit;
-       }
        if (hlimit < 0)
                hlimit = ip6_dst_hoplimit(dst);
 
@@ -1126,7 +1123,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                        hh_len + fragheaderlen + transhdrlen + 20,
                        (flags & MSG_DONTWAIT), &err);
                if (skb == NULL)
-                       return -ENOMEM;
+                       return err;
 
                /* reserve space for Hardware header */
                skb_reserve(skb, hh_len);
index fb545ed..57b82dc 100644 (file)
@@ -1086,11 +1086,10 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
        rt->dst.output  = ip6_output;
        dst_set_neighbour(&rt->dst, neigh);
        atomic_set(&rt->dst.__refcnt, 1);
-       dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
-
        ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
        rt->rt6i_dst.plen = 128;
        rt->rt6i_idev     = idev;
+       dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
 
        spin_lock_bh(&icmp6_dst_lock);
        rt->dst.next = icmp6_dst_gc_list;
index c8683fc..10b2b31 100644 (file)
@@ -513,7 +513,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
                __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
 
                ipv6_addr_copy(&fl6.daddr, &treq->rmt_addr);
-               err = ip6_xmit(sk, skb, &fl6, opt);
+               err = ip6_xmit(sk, skb, &fl6, opt, np->tclass);
                err = net_xmit_eval(err);
        }
 
@@ -979,7 +979,7 @@ static int tcp6_gro_complete(struct sk_buff *skb)
 }
 
 static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
-                                u32 ts, struct tcp_md5sig_key *key, int rst)
+                                u32 ts, struct tcp_md5sig_key *key, int rst, u8 tclass)
 {
        const struct tcphdr *th = tcp_hdr(skb);
        struct tcphdr *t1;
@@ -1060,7 +1060,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
        dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false);
        if (!IS_ERR(dst)) {
                skb_dst_set(buff, dst);
-               ip6_xmit(ctl_sk, buff, &fl6, NULL);
+               ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass);
                TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
                if (rst)
                        TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
@@ -1093,13 +1093,13 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
                ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
                          (th->doff << 2);
 
-       tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1);
+       tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0);
 }
 
 static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
-                           struct tcp_md5sig_key *key)
+                           struct tcp_md5sig_key *key, u8 tclass)
 {
-       tcp_v6_send_response(skb, seq, ack, win, ts, key, 0);
+       tcp_v6_send_response(skb, seq, ack, win, ts, key, 0, tclass);
 }
 
 static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
@@ -1109,7 +1109,8 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
 
        tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
                        tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
-                       tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw));
+                       tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw),
+                       tw->tw_tclass);
 
        inet_twsk_put(tw);
 }
@@ -1118,7 +1119,7 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
                                  struct request_sock *req)
 {
        tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent,
-                       tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr));
+                       tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0);
 }
 
 
index aabaee4..8104278 100644 (file)
@@ -243,7 +243,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
        if (!(transport->param_flags & SPP_PMTUD_ENABLE))
                skb->local_df = 1;
 
-       return ip6_xmit(sk, skb, &fl6, np->opt);
+       return ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
 }
 
 /* Returns the dst cache entry for the given source and destination ip
index eaf3a50..3ad0925 100644 (file)
@@ -58,8 +58,6 @@ static int find_index_from_host_irq(struct kvm_assigned_dev_kernel
 static irqreturn_t kvm_assigned_dev_thread(int irq, void *dev_id)
 {
        struct kvm_assigned_dev_kernel *assigned_dev = dev_id;
-       u32 vector;
-       int index;
 
        if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_INTX) {
                spin_lock(&assigned_dev->intx_lock);
@@ -68,31 +66,35 @@ static irqreturn_t kvm_assigned_dev_thread(int irq, void *dev_id)
                spin_unlock(&assigned_dev->intx_lock);
        }
 
-       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
-               index = find_index_from_host_irq(assigned_dev, irq);
-               if (index >= 0) {
-                       vector = assigned_dev->
-                                       guest_msix_entries[index].vector;
-                       kvm_set_irq(assigned_dev->kvm,
-                                   assigned_dev->irq_source_id, vector, 1);
-               }
-       } else
+       kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
+                   assigned_dev->guest_irq, 1);
+
+       return IRQ_HANDLED;
+}
+
+#ifdef __KVM_HAVE_MSIX
+static irqreturn_t kvm_assigned_dev_thread_msix(int irq, void *dev_id)
+{
+       struct kvm_assigned_dev_kernel *assigned_dev = dev_id;
+       int index = find_index_from_host_irq(assigned_dev, irq);
+       u32 vector;
+
+       if (index >= 0) {
+               vector = assigned_dev->guest_msix_entries[index].vector;
                kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
-                           assigned_dev->guest_irq, 1);
+                           vector, 1);
+       }
 
        return IRQ_HANDLED;
 }
+#endif
 
 /* Ack the irq line for an assigned device */
 static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
 {
-       struct kvm_assigned_dev_kernel *dev;
-
-       if (kian->gsi == -1)
-               return;
-
-       dev = container_of(kian, struct kvm_assigned_dev_kernel,
-                          ack_notifier);
+       struct kvm_assigned_dev_kernel *dev =
+               container_of(kian, struct kvm_assigned_dev_kernel,
+                            ack_notifier);
 
        kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0);
 
@@ -110,8 +112,9 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
 static void deassign_guest_irq(struct kvm *kvm,
                               struct kvm_assigned_dev_kernel *assigned_dev)
 {
-       kvm_unregister_irq_ack_notifier(kvm, &assigned_dev->ack_notifier);
-       assigned_dev->ack_notifier.gsi = -1;
+       if (assigned_dev->ack_notifier.gsi != -1)
+               kvm_unregister_irq_ack_notifier(kvm,
+                                               &assigned_dev->ack_notifier);
 
        kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
                    assigned_dev->guest_irq, 0);
@@ -143,7 +146,7 @@ static void deassign_host_irq(struct kvm *kvm,
 
                for (i = 0; i < assigned_dev->entries_nr; i++)
                        free_irq(assigned_dev->host_msix_entries[i].vector,
-                                (void *)assigned_dev);
+                                assigned_dev);
 
                assigned_dev->entries_nr = 0;
                kfree(assigned_dev->host_msix_entries);
@@ -153,7 +156,7 @@ static void deassign_host_irq(struct kvm *kvm,
                /* Deal with MSI and INTx */
                disable_irq(assigned_dev->host_irq);
 
-               free_irq(assigned_dev->host_irq, (void *)assigned_dev);
+               free_irq(assigned_dev->host_irq, assigned_dev);
 
                if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSI)
                        pci_disable_msi(assigned_dev->dev);
@@ -239,7 +242,7 @@ static int assigned_device_enable_host_intx(struct kvm *kvm,
         * are going to be long delays in accepting, acking, etc.
         */
        if (request_threaded_irq(dev->host_irq, NULL, kvm_assigned_dev_thread,
-                                IRQF_ONESHOT, dev->irq_name, (void *)dev))
+                                IRQF_ONESHOT, dev->irq_name, dev))
                return -EIO;
        return 0;
 }
@@ -258,7 +261,7 @@ static int assigned_device_enable_host_msi(struct kvm *kvm,
 
        dev->host_irq = dev->dev->irq;
        if (request_threaded_irq(dev->host_irq, NULL, kvm_assigned_dev_thread,
-                                0, dev->irq_name, (void *)dev)) {
+                                0, dev->irq_name, dev)) {
                pci_disable_msi(dev->dev);
                return -EIO;
        }
@@ -284,8 +287,8 @@ static int assigned_device_enable_host_msix(struct kvm *kvm,
 
        for (i = 0; i < dev->entries_nr; i++) {
                r = request_threaded_irq(dev->host_msix_entries[i].vector,
-                                        NULL, kvm_assigned_dev_thread,
-                                        0, dev->irq_name, (void *)dev);
+                                        NULL, kvm_assigned_dev_thread_msix,
+                                        0, dev->irq_name, dev);
                if (r)
                        goto err;
        }
@@ -293,7 +296,7 @@ static int assigned_device_enable_host_msix(struct kvm *kvm,
        return 0;
 err:
        for (i -= 1; i >= 0; i--)
-               free_irq(dev->host_msix_entries[i].vector, (void *)dev);
+               free_irq(dev->host_msix_entries[i].vector, dev);
        pci_disable_msix(dev->dev);
        return r;
 }
@@ -406,7 +409,8 @@ static int assign_guest_irq(struct kvm *kvm,
 
        if (!r) {
                dev->irq_requested_type |= guest_irq_type;
-               kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier);
+               if (dev->ack_notifier.gsi != -1)
+                       kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier);
        } else
                kvm_free_irq_source_id(kvm, dev->irq_source_id);
 
index fc84875..a6ec206 100644 (file)
@@ -24,10 +24,19 @@ static inline struct kvm_coalesced_mmio_dev *to_mmio(struct kvm_io_device *dev)
 static int coalesced_mmio_in_range(struct kvm_coalesced_mmio_dev *dev,
                                   gpa_t addr, int len)
 {
-       struct kvm_coalesced_mmio_zone *zone;
+       /* is it in a batchable area ?
+        * (addr,len) is fully included in
+        * (zone->addr, zone->size)
+        */
+
+       return (dev->zone.addr <= addr &&
+               addr + len <= dev->zone.addr + dev->zone.size);
+}
+
+static int coalesced_mmio_has_room(struct kvm_coalesced_mmio_dev *dev)
+{
        struct kvm_coalesced_mmio_ring *ring;
        unsigned avail;
-       int i;
 
        /* Are we able to batch it ? */
 
@@ -37,25 +46,12 @@ static int coalesced_mmio_in_range(struct kvm_coalesced_mmio_dev *dev,
         */
        ring = dev->kvm->coalesced_mmio_ring;
        avail = (ring->first - ring->last - 1) % KVM_COALESCED_MMIO_MAX;
-       if (avail < KVM_MAX_VCPUS) {
+       if (avail == 0) {
                /* full */
                return 0;
        }
 
-       /* is it in a batchable area ? */
-
-       for (i = 0; i < dev->nb_zones; i++) {
-               zone = &dev->zone[i];
-
-               /* (addr,len) is fully included in
-                * (zone->addr, zone->size)
-                */
-
-               if (zone->addr <= addr &&
-                   addr + len <= zone->addr + zone->size)
-                       return 1;
-       }
-       return 0;
+       return 1;
 }
 
 static int coalesced_mmio_write(struct kvm_io_device *this,
@@ -63,10 +59,16 @@ static int coalesced_mmio_write(struct kvm_io_device *this,
 {
        struct kvm_coalesced_mmio_dev *dev = to_mmio(this);
        struct kvm_coalesced_mmio_ring *ring = dev->kvm->coalesced_mmio_ring;
+
        if (!coalesced_mmio_in_range(dev, addr, len))
                return -EOPNOTSUPP;
 
-       spin_lock(&dev->lock);
+       spin_lock(&dev->kvm->ring_lock);
+
+       if (!coalesced_mmio_has_room(dev)) {
+               spin_unlock(&dev->kvm->ring_lock);
+               return -EOPNOTSUPP;
+       }
 
        /* copy data in first free entry of the ring */
 
@@ -75,7 +77,7 @@ static int coalesced_mmio_write(struct kvm_io_device *this,
        memcpy(ring->coalesced_mmio[ring->last].data, val, len);
        smp_wmb();
        ring->last = (ring->last + 1) % KVM_COALESCED_MMIO_MAX;
-       spin_unlock(&dev->lock);
+       spin_unlock(&dev->kvm->ring_lock);
        return 0;
 }
 
@@ -83,6 +85,8 @@ static void coalesced_mmio_destructor(struct kvm_io_device *this)
 {
        struct kvm_coalesced_mmio_dev *dev = to_mmio(this);
 
+       list_del(&dev->list);
+
        kfree(dev);
 }
 
@@ -93,7 +97,6 @@ static const struct kvm_io_device_ops coalesced_mmio_ops = {
 
 int kvm_coalesced_mmio_init(struct kvm *kvm)
 {
-       struct kvm_coalesced_mmio_dev *dev;
        struct page *page;
        int ret;
 
@@ -101,31 +104,18 @@ int kvm_coalesced_mmio_init(struct kvm *kvm)
        page = alloc_page(GFP_KERNEL | __GFP_ZERO);
        if (!page)
                goto out_err;
-       kvm->coalesced_mmio_ring = page_address(page);
-
-       ret = -ENOMEM;
-       dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev), GFP_KERNEL);
-       if (!dev)
-               goto out_free_page;
-       spin_lock_init(&dev->lock);
-       kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops);
-       dev->kvm = kvm;
-       kvm->coalesced_mmio_dev = dev;
 
-       mutex_lock(&kvm->slots_lock);
-       ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, &dev->dev);
-       mutex_unlock(&kvm->slots_lock);
-       if (ret < 0)
-               goto out_free_dev;
+       ret = 0;
+       kvm->coalesced_mmio_ring = page_address(page);
 
-       return ret;
+       /*
+        * We're using this spinlock to sync access to the coalesced ring.
+        * The list doesn't need it's own lock since device registration and
+        * unregistration should only happen when kvm->slots_lock is held.
+        */
+       spin_lock_init(&kvm->ring_lock);
+       INIT_LIST_HEAD(&kvm->coalesced_zones);
 
-out_free_dev:
-       kvm->coalesced_mmio_dev = NULL;
-       kfree(dev);
-out_free_page:
-       kvm->coalesced_mmio_ring = NULL;
-       __free_page(page);
 out_err:
        return ret;
 }
@@ -139,51 +129,50 @@ void kvm_coalesced_mmio_free(struct kvm *kvm)
 int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
                                         struct kvm_coalesced_mmio_zone *zone)
 {
-       struct kvm_coalesced_mmio_dev *dev = kvm->coalesced_mmio_dev;
+       int ret;
+       struct kvm_coalesced_mmio_dev *dev;
 
-       if (dev == NULL)
-               return -ENXIO;
+       dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops);
+       dev->kvm = kvm;
+       dev->zone = *zone;
 
        mutex_lock(&kvm->slots_lock);
-       if (dev->nb_zones >= KVM_COALESCED_MMIO_ZONE_MAX) {
-               mutex_unlock(&kvm->slots_lock);
-               return -ENOBUFS;
-       }
+       ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, zone->addr,
+                                     zone->size, &dev->dev);
+       if (ret < 0)
+               goto out_free_dev;
+       list_add_tail(&dev->list, &kvm->coalesced_zones);
+       mutex_unlock(&kvm->slots_lock);
 
-       dev->zone[dev->nb_zones] = *zone;
-       dev->nb_zones++;
+       return ret;
 
+out_free_dev:
        mutex_unlock(&kvm->slots_lock);
+
+       kfree(dev);
+
+       if (dev == NULL)
+               return -ENXIO;
+
        return 0;
 }
 
 int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
                                           struct kvm_coalesced_mmio_zone *zone)
 {
-       int i;
-       struct kvm_coalesced_mmio_dev *dev = kvm->coalesced_mmio_dev;
-       struct kvm_coalesced_mmio_zone *z;
-
-       if (dev == NULL)
-               return -ENXIO;
+       struct kvm_coalesced_mmio_dev *dev, *tmp;
 
        mutex_lock(&kvm->slots_lock);
 
-       i = dev->nb_zones;
-       while (i) {
-               z = &dev->zone[i - 1];
-
-               /* unregister all zones
-                * included in (zone->addr, zone->size)
-                */
-
-               if (zone->addr <= z->addr &&
-                   z->addr + z->size <= zone->addr + zone->size) {
-                       dev->nb_zones--;
-                       *z = dev->zone[dev->nb_zones];
+       list_for_each_entry_safe(dev, tmp, &kvm->coalesced_zones, list)
+               if (coalesced_mmio_in_range(dev, zone->addr, zone->size)) {
+                       kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &dev->dev);
+                       kvm_iodevice_destructor(&dev->dev);
                }
-               i--;
-       }
 
        mutex_unlock(&kvm->slots_lock);
 
index 8a5959e..b280c20 100644 (file)
 
 #ifdef CONFIG_KVM_MMIO
 
-#define KVM_COALESCED_MMIO_ZONE_MAX 100
+#include <linux/list.h>
 
 struct kvm_coalesced_mmio_dev {
+       struct list_head list;
        struct kvm_io_device dev;
        struct kvm *kvm;
-       spinlock_t lock;
-       int nb_zones;
-       struct kvm_coalesced_mmio_zone zone[KVM_COALESCED_MMIO_ZONE_MAX];
+       struct kvm_coalesced_mmio_zone zone;
 };
 
 int kvm_coalesced_mmio_init(struct kvm *kvm);
index 73358d2..f59c1e8 100644 (file)
@@ -586,7 +586,8 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
 
        kvm_iodevice_init(&p->dev, &ioeventfd_ops);
 
-       ret = kvm_io_bus_register_dev(kvm, bus_idx, &p->dev);
+       ret = kvm_io_bus_register_dev(kvm, bus_idx, p->addr, p->length,
+                                     &p->dev);
        if (ret < 0)
                goto unlock_fail;
 
index 8df1ca1..3eed61e 100644 (file)
@@ -394,7 +394,8 @@ int kvm_ioapic_init(struct kvm *kvm)
        kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
        ioapic->kvm = kvm;
        mutex_lock(&kvm->slots_lock);
-       ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, &ioapic->dev);
+       ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, ioapic->base_address,
+                                     IOAPIC_MEM_LENGTH, &ioapic->dev);
        mutex_unlock(&kvm->slots_lock);
        if (ret < 0) {
                kvm->arch.vioapic = NULL;
index 967aba1..d5f3b8d 100644 (file)
@@ -232,12 +232,12 @@ int kvm_iommu_map_guest(struct kvm *kvm)
 {
        int r;
 
-       if (!iommu_found()) {
+       if (!iommu_present(&pci_bus_type)) {
                printk(KERN_ERR "%s: iommu not found\n", __func__);
                return -ENODEV;
        }
 
-       kvm->arch.iommu_domain = iommu_domain_alloc();
+       kvm->arch.iommu_domain = iommu_domain_alloc(&pci_bus_type);
        if (!kvm->arch.iommu_domain)
                return -ENOMEM;
 
index aefdda3..d9cfb78 100644 (file)
@@ -47,6 +47,8 @@
 #include <linux/srcu.h>
 #include <linux/hugetlb.h>
 #include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/bsearch.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -2391,24 +2393,92 @@ static void kvm_io_bus_destroy(struct kvm_io_bus *bus)
        int i;
 
        for (i = 0; i < bus->dev_count; i++) {
-               struct kvm_io_device *pos = bus->devs[i];
+               struct kvm_io_device *pos = bus->range[i].dev;
 
                kvm_iodevice_destructor(pos);
        }
        kfree(bus);
 }
 
+int kvm_io_bus_sort_cmp(const void *p1, const void *p2)
+{
+       const struct kvm_io_range *r1 = p1;
+       const struct kvm_io_range *r2 = p2;
+
+       if (r1->addr < r2->addr)
+               return -1;
+       if (r1->addr + r1->len > r2->addr + r2->len)
+               return 1;
+       return 0;
+}
+
+int kvm_io_bus_insert_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev,
+                         gpa_t addr, int len)
+{
+       if (bus->dev_count == NR_IOBUS_DEVS)
+               return -ENOSPC;
+
+       bus->range[bus->dev_count++] = (struct kvm_io_range) {
+               .addr = addr,
+               .len = len,
+               .dev = dev,
+       };
+
+       sort(bus->range, bus->dev_count, sizeof(struct kvm_io_range),
+               kvm_io_bus_sort_cmp, NULL);
+
+       return 0;
+}
+
+int kvm_io_bus_get_first_dev(struct kvm_io_bus *bus,
+                            gpa_t addr, int len)
+{
+       struct kvm_io_range *range, key;
+       int off;
+
+       key = (struct kvm_io_range) {
+               .addr = addr,
+               .len = len,
+       };
+
+       range = bsearch(&key, bus->range, bus->dev_count,
+                       sizeof(struct kvm_io_range), kvm_io_bus_sort_cmp);
+       if (range == NULL)
+               return -ENOENT;
+
+       off = range - bus->range;
+
+       while (off > 0 && kvm_io_bus_sort_cmp(&key, &bus->range[off-1]) == 0)
+               off--;
+
+       return off;
+}
+
 /* kvm_io_bus_write - called under kvm->slots_lock */
 int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
                     int len, const void *val)
 {
-       int i;
+       int idx;
        struct kvm_io_bus *bus;
+       struct kvm_io_range range;
+
+       range = (struct kvm_io_range) {
+               .addr = addr,
+               .len = len,
+       };
 
        bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
-       for (i = 0; i < bus->dev_count; i++)
-               if (!kvm_iodevice_write(bus->devs[i], addr, len, val))
+       idx = kvm_io_bus_get_first_dev(bus, addr, len);
+       if (idx < 0)
+               return -EOPNOTSUPP;
+
+       while (idx < bus->dev_count &&
+               kvm_io_bus_sort_cmp(&range, &bus->range[idx]) == 0) {
+               if (!kvm_iodevice_write(bus->range[idx].dev, addr, len, val))
                        return 0;
+               idx++;
+       }
+
        return -EOPNOTSUPP;
 }
 
@@ -2416,19 +2486,33 @@ int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
 int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
                    int len, void *val)
 {
-       int i;
+       int idx;
        struct kvm_io_bus *bus;
+       struct kvm_io_range range;
+
+       range = (struct kvm_io_range) {
+               .addr = addr,
+               .len = len,
+       };
 
        bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
-       for (i = 0; i < bus->dev_count; i++)
-               if (!kvm_iodevice_read(bus->devs[i], addr, len, val))
+       idx = kvm_io_bus_get_first_dev(bus, addr, len);
+       if (idx < 0)
+               return -EOPNOTSUPP;
+
+       while (idx < bus->dev_count &&
+               kvm_io_bus_sort_cmp(&range, &bus->range[idx]) == 0) {
+               if (!kvm_iodevice_read(bus->range[idx].dev, addr, len, val))
                        return 0;
+               idx++;
+       }
+
        return -EOPNOTSUPP;
 }
 
 /* Caller must hold slots_lock. */
-int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx,
-                           struct kvm_io_device *dev)
+int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+                           int len, struct kvm_io_device *dev)
 {
        struct kvm_io_bus *new_bus, *bus;
 
@@ -2440,7 +2524,7 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx,
        if (!new_bus)
                return -ENOMEM;
        memcpy(new_bus, bus, sizeof(struct kvm_io_bus));
-       new_bus->devs[new_bus->dev_count++] = dev;
+       kvm_io_bus_insert_dev(new_bus, dev, addr, len);
        rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
        synchronize_srcu_expedited(&kvm->srcu);
        kfree(bus);
@@ -2464,9 +2548,13 @@ int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
 
        r = -ENOENT;
        for (i = 0; i < new_bus->dev_count; i++)
-               if (new_bus->devs[i] == dev) {
+               if (new_bus->range[i].dev == dev) {
                        r = 0;
-                       new_bus->devs[i] = new_bus->devs[--new_bus->dev_count];
+                       new_bus->dev_count--;
+                       new_bus->range[i] = new_bus->range[new_bus->dev_count];
+                       sort(new_bus->range, new_bus->dev_count,
+                            sizeof(struct kvm_io_range),
+                            kvm_io_bus_sort_cmp, NULL);
                        break;
                }