Merge tag 'media/v3.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 11 Oct 2014 02:04:49 +0000 (22:04 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 11 Oct 2014 02:04:49 +0000 (22:04 -0400)
Pull media updates from Mauro Carvalho Chehab:

 - new IR driver: hix5hd2-ir

 - the virtual test driver (vivi) was replaced by vivid, with has an
   almost complete set of features to emulate most v4l2 devices and
   properly test all sorts of userspace apps

 - the as102 driver had several bugs fixed and was properly split into a
   frontend and a core driver.  With that, it got promoted from staging
   into mainstream

 - one new CI driver got added for CIMaX SP2/SP2HF (sp2 driver)

 - one new frontend driver for Toshiba ISDB-T/ISDB-S demod (tc90522)

 - one new PCI driver for ISDB-T/ISDB-S (pt3 driver)

 - saa7134 driver got support for go7007-based devices

 - added a new PCI driver for Techwell 68xx chipsets (tw68)

 - a new platform driver was added (coda)

 - new tuner drivers: mxl301rf and qm1d1c0042

 - a new DVB USB driver was added for DVBSky S860 & similar devices

 - added a new SDR driver (hackrf)

 - usbtv got audio support

 - several platform drivers are now compiled with COMPILE_TEST

 - a series of compiler fixup patches, making sparse/spatch happier with
   the media stuff and removing several warnings, especially on those
   platform drivers that didn't use to compile on x86

 - Support for several new modern devices got added

 - lots of other fixes, improvements and cleanups

* tag 'media/v3.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (544 commits)
  [media] ir-hix5hd2: fix build on c6x arch
  [media] pt3: fix DTV FE I2C driver load error paths
  Revert "[media] media: em28xx - remove reset_resume interface"
  [media] exynos4-is: fix some warnings when compiling on arm64
  [media] usb drivers: use %zu instead of %zd
  [media] pci drivers: use %zu instead of %zd
  [media] dvb-frontends: use %zu instead of %zd
  [media] s5p-mfc: Fix several printk warnings
  [media] s5p_mfc_opr: Fix warnings
  [media] ti-vpe: Fix typecast
  [media] s3c-camif: fix dma_addr_t printks
  [media] s5p_mfc_opr_v6: get rid of warnings when compiled with 64 bits
  [media] s5p_mfc_opr_v5: Fix lots of warnings on x86_64
  [media] em28xx: Fix identation
  [media] drxd: remove a dead code
  [media] saa7146: remove return after BUG()
  [media] cx88: remove return after BUG()
  [media] cx88: fix cards table CodingStyle
  [media] radio-sf16fmr2: declare some structs as static
  [media] radio-sf16fmi: declare pnp_attached as static
  ...

490 files changed:
Documentation/DocBook/media/v4l/compat.xml
Documentation/DocBook/media/v4l/controls.xml
Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
Documentation/DocBook/media/v4l/vidioc-dqevent.xml
Documentation/DocBook/media/v4l/vidioc-g-edid.xml
Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
Documentation/devicetree/bindings/media/hix5hd2-ir.txt [new file with mode: 0644]
Documentation/dvb/get_dvb_firmware
Documentation/video4linux/vivid.txt [new file with mode: 0644]
MAINTAINERS
drivers/media/common/b2c2/flexcop.h
drivers/media/common/saa7146/saa7146_fops.c
drivers/media/common/siano/sms-cards.c
drivers/media/common/siano/sms-cards.h
drivers/media/common/siano/smscoreapi.c
drivers/media/dvb-core/dmxdev.c
drivers/media/dvb-core/dvb-usb-ids.h
drivers/media/dvb-core/dvb_frontend.c
drivers/media/dvb-core/dvb_frontend.h
drivers/media/dvb-core/dvb_ringbuffer.c
drivers/media/dvb-core/dvb_ringbuffer.h
drivers/media/dvb-frontends/Kconfig
drivers/media/dvb-frontends/Makefile
drivers/media/dvb-frontends/af9013.c
drivers/media/dvb-frontends/af9033.c
drivers/media/dvb-frontends/af9033.h
drivers/media/dvb-frontends/af9033_priv.h
drivers/media/dvb-frontends/as102_fe.c [new file with mode: 0644]
drivers/media/dvb-frontends/as102_fe.h [new file with mode: 0644]
drivers/media/dvb-frontends/as102_fe_types.h [new file with mode: 0644]
drivers/media/dvb-frontends/bcm3510.c
drivers/media/dvb-frontends/cxd2820r_c.c
drivers/media/dvb-frontends/cxd2820r_core.c
drivers/media/dvb-frontends/cxd2820r_t.c
drivers/media/dvb-frontends/dib7000p.c
drivers/media/dvb-frontends/drx39xyj/drxj.c
drivers/media/dvb-frontends/drxd_hard.c
drivers/media/dvb-frontends/drxk_hard.c
drivers/media/dvb-frontends/m88ds3103.c
drivers/media/dvb-frontends/m88ds3103.h
drivers/media/dvb-frontends/mb86a16.c
drivers/media/dvb-frontends/mb86a20s.c
drivers/media/dvb-frontends/mt312.c
drivers/media/dvb-frontends/or51211.c
drivers/media/dvb-frontends/rtl2832.c
drivers/media/dvb-frontends/rtl2832_sdr.c
drivers/media/dvb-frontends/si2165.c
drivers/media/dvb-frontends/si2165_priv.h
drivers/media/dvb-frontends/si2168.c
drivers/media/dvb-frontends/si2168.h
drivers/media/dvb-frontends/si2168_priv.h
drivers/media/dvb-frontends/si21xx.c
drivers/media/dvb-frontends/sp2.c [new file with mode: 0644]
drivers/media/dvb-frontends/sp2.h [new file with mode: 0644]
drivers/media/dvb-frontends/sp2_priv.h [new file with mode: 0644]
drivers/media/dvb-frontends/sp8870.c
drivers/media/dvb-frontends/stv0367.c
drivers/media/dvb-frontends/stv0900_core.c
drivers/media/dvb-frontends/stv0900_sw.c
drivers/media/dvb-frontends/tc90522.c [new file with mode: 0644]
drivers/media/dvb-frontends/tc90522.h [new file with mode: 0644]
drivers/media/dvb-frontends/tda10071.c
drivers/media/dvb-frontends/zl10039.c
drivers/media/firewire/firedtv-avc.c
drivers/media/i2c/adv7343_regs.h
drivers/media/i2c/adv7604.c
drivers/media/i2c/adv7842.c
drivers/media/i2c/lm3560.c
drivers/media/i2c/ov7670.c
drivers/media/i2c/s5k5baf.c
drivers/media/i2c/saa6752hs.c
drivers/media/i2c/smiapp/smiapp-core.c
drivers/media/i2c/smiapp/smiapp.h
drivers/media/i2c/soc_camera/mt9t112.c
drivers/media/i2c/soc_camera/ov772x.c
drivers/media/i2c/soc_camera/ov9740.c
drivers/media/i2c/tda7432.c
drivers/media/i2c/tvp7002.c
drivers/media/i2c/vs6624.c
drivers/media/media-device.c
drivers/media/media-devnode.c
drivers/media/parport/pms.c
drivers/media/pci/Kconfig
drivers/media/pci/Makefile
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/pci/bt8xx/dst_ca.c
drivers/media/pci/cx18/cx18-alsa-pcm.c
drivers/media/pci/cx18/cx18-firmware.c
drivers/media/pci/cx18/cx18-queue.c
drivers/media/pci/cx23885/Kconfig
drivers/media/pci/cx23885/Makefile
drivers/media/pci/cx23885/altera-ci.c
drivers/media/pci/cx23885/altera-ci.h
drivers/media/pci/cx23885/cimax2.c
drivers/media/pci/cx23885/cimax2.h
drivers/media/pci/cx23885/cx23885-417.c
drivers/media/pci/cx23885/cx23885-alsa.c
drivers/media/pci/cx23885/cx23885-av.c
drivers/media/pci/cx23885/cx23885-av.h
drivers/media/pci/cx23885/cx23885-cards.c
drivers/media/pci/cx23885/cx23885-core.c
drivers/media/pci/cx23885/cx23885-dvb.c
drivers/media/pci/cx23885/cx23885-f300.c
drivers/media/pci/cx23885/cx23885-i2c.c
drivers/media/pci/cx23885/cx23885-input.c
drivers/media/pci/cx23885/cx23885-input.h
drivers/media/pci/cx23885/cx23885-ioctl.c
drivers/media/pci/cx23885/cx23885-ioctl.h
drivers/media/pci/cx23885/cx23885-ir.c
drivers/media/pci/cx23885/cx23885-ir.h
drivers/media/pci/cx23885/cx23885-reg.h
drivers/media/pci/cx23885/cx23885-vbi.c
drivers/media/pci/cx23885/cx23885-video.c
drivers/media/pci/cx23885/cx23885-video.h
drivers/media/pci/cx23885/cx23885.h
drivers/media/pci/cx23885/cx23888-ir.c
drivers/media/pci/cx23885/cx23888-ir.h
drivers/media/pci/cx23885/netup-eeprom.c
drivers/media/pci/cx23885/netup-eeprom.h
drivers/media/pci/cx23885/netup-init.c
drivers/media/pci/cx23885/netup-init.h
drivers/media/pci/cx25821/cx25821-video-upstream.c
drivers/media/pci/cx88/cx88-cards.c
drivers/media/pci/cx88/cx88-video.c
drivers/media/pci/ddbridge/ddbridge-core.c
drivers/media/pci/ddbridge/ddbridge.h
drivers/media/pci/dm1105/dm1105.c
drivers/media/pci/ivtv/ivtv-alsa-pcm.c
drivers/media/pci/ivtv/ivtv-firmware.c
drivers/media/pci/ivtv/ivtv-irq.c
drivers/media/pci/mantis/hopper_vp3028.c
drivers/media/pci/mantis/mantis_common.h
drivers/media/pci/mantis/mantis_vp1033.c
drivers/media/pci/mantis/mantis_vp1034.c
drivers/media/pci/mantis/mantis_vp1041.c
drivers/media/pci/mantis/mantis_vp2033.c
drivers/media/pci/mantis/mantis_vp2040.c
drivers/media/pci/mantis/mantis_vp3030.c
drivers/media/pci/ngene/ngene-cards.c
drivers/media/pci/ngene/ngene-core.c
drivers/media/pci/ngene/ngene-dvb.c
drivers/media/pci/ngene/ngene.h
drivers/media/pci/pt3/Kconfig [new file with mode: 0644]
drivers/media/pci/pt3/Makefile [new file with mode: 0644]
drivers/media/pci/pt3/pt3.c [new file with mode: 0644]
drivers/media/pci/pt3/pt3.h [new file with mode: 0644]
drivers/media/pci/pt3/pt3_dma.c [new file with mode: 0644]
drivers/media/pci/pt3/pt3_i2c.c [new file with mode: 0644]
drivers/media/pci/saa7134/Kconfig
drivers/media/pci/saa7134/Makefile
drivers/media/pci/saa7134/saa7134-cards.c
drivers/media/pci/saa7134/saa7134-core.c
drivers/media/pci/saa7134/saa7134-go7007.c [new file with mode: 0644]
drivers/media/pci/saa7134/saa7134-vbi.c
drivers/media/pci/saa7134/saa7134-video.c
drivers/media/pci/saa7134/saa7134.h
drivers/media/pci/saa7164/saa7164-api.c
drivers/media/pci/saa7164/saa7164-core.c
drivers/media/pci/solo6x10/Kconfig
drivers/media/pci/solo6x10/solo6x10-disp.c
drivers/media/pci/solo6x10/solo6x10-eeprom.c
drivers/media/pci/solo6x10/solo6x10.h
drivers/media/pci/sta2x11/Kconfig
drivers/media/pci/sta2x11/sta2x11_vip.c
drivers/media/pci/ttpci/Kconfig
drivers/media/pci/ttpci/Makefile
drivers/media/pci/ttpci/av7110.c
drivers/media/pci/tw68/Kconfig [new file with mode: 0644]
drivers/media/pci/tw68/Makefile [new file with mode: 0644]
drivers/media/pci/tw68/tw68-core.c [new file with mode: 0644]
drivers/media/pci/tw68/tw68-reg.h [new file with mode: 0644]
drivers/media/pci/tw68/tw68-risc.c [new file with mode: 0644]
drivers/media/pci/tw68/tw68-video.c [new file with mode: 0644]
drivers/media/pci/tw68/tw68.h [new file with mode: 0644]
drivers/media/pci/zoran/zoran_device.c
drivers/media/platform/Kconfig
drivers/media/platform/Makefile
drivers/media/platform/blackfin/Kconfig
drivers/media/platform/coda.c [deleted file]
drivers/media/platform/coda.h [deleted file]
drivers/media/platform/coda/Makefile [new file with mode: 0644]
drivers/media/platform/coda/coda-bit.c [new file with mode: 0644]
drivers/media/platform/coda/coda-common.c [new file with mode: 0644]
drivers/media/platform/coda/coda-h264.c [new file with mode: 0644]
drivers/media/platform/coda/coda.h [new file with mode: 0644]
drivers/media/platform/coda/coda_regs.h [new file with mode: 0644]
drivers/media/platform/davinci/Kconfig
drivers/media/platform/davinci/dm355_ccdc.c
drivers/media/platform/davinci/dm644x_ccdc.c
drivers/media/platform/davinci/vpfe_capture.c
drivers/media/platform/davinci/vpif.c
drivers/media/platform/davinci/vpif_capture.c
drivers/media/platform/davinci/vpif_display.c
drivers/media/platform/exynos-gsc/gsc-core.c
drivers/media/platform/exynos-gsc/gsc-m2m.c
drivers/media/platform/exynos-gsc/gsc-regs.c
drivers/media/platform/exynos4-is/Kconfig
drivers/media/platform/exynos4-is/fimc-is-errno.c
drivers/media/platform/exynos4-is/fimc-is-errno.h
drivers/media/platform/exynos4-is/fimc-is-param.c
drivers/media/platform/exynos4-is/fimc-is.c
drivers/media/platform/exynos4-is/fimc-isp-video.c
drivers/media/platform/exynos4-is/media-dev.c
drivers/media/platform/exynos4-is/mipi-csis.c
drivers/media/platform/marvell-ccic/Kconfig
drivers/media/platform/marvell-ccic/mcam-core.c
drivers/media/platform/mx2_emmaprp.c
drivers/media/platform/omap/Kconfig
drivers/media/platform/omap/omap_vout.c
drivers/media/platform/omap/omap_vout_vrfb.c
drivers/media/platform/omap/omap_vout_vrfb.h
drivers/media/platform/omap3isp/cfa_coef_table.h
drivers/media/platform/omap3isp/gamma_table.h
drivers/media/platform/omap3isp/isp.c
drivers/media/platform/omap3isp/isp.h
drivers/media/platform/omap3isp/ispccdc.c
drivers/media/platform/omap3isp/ispccdc.h
drivers/media/platform/omap3isp/ispccp2.c
drivers/media/platform/omap3isp/ispccp2.h
drivers/media/platform/omap3isp/ispcsi2.c
drivers/media/platform/omap3isp/ispcsi2.h
drivers/media/platform/omap3isp/ispcsiphy.c
drivers/media/platform/omap3isp/ispcsiphy.h
drivers/media/platform/omap3isp/isph3a.h
drivers/media/platform/omap3isp/isph3a_aewb.c
drivers/media/platform/omap3isp/isph3a_af.c
drivers/media/platform/omap3isp/isphist.c
drivers/media/platform/omap3isp/isphist.h
drivers/media/platform/omap3isp/isppreview.c
drivers/media/platform/omap3isp/isppreview.h
drivers/media/platform/omap3isp/ispreg.h
drivers/media/platform/omap3isp/ispresizer.c
drivers/media/platform/omap3isp/ispresizer.h
drivers/media/platform/omap3isp/ispstat.c
drivers/media/platform/omap3isp/ispstat.h
drivers/media/platform/omap3isp/ispvideo.c
drivers/media/platform/omap3isp/ispvideo.h
drivers/media/platform/omap3isp/luma_enhance_table.h
drivers/media/platform/omap3isp/noise_filter_table.h
drivers/media/platform/s3c-camif/camif-capture.c
drivers/media/platform/s3c-camif/camif-regs.c
drivers/media/platform/s5p-g2d/g2d.c
drivers/media/platform/s5p-jpeg/jpeg-core.c
drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c
drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c
drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c
drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
drivers/media/platform/s5p-mfc/s5p_mfc_common.h
drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
drivers/media/platform/s5p-tv/Kconfig
drivers/media/platform/s5p-tv/hdmi_drv.c
drivers/media/platform/s5p-tv/sdo_drv.c
drivers/media/platform/s5p-tv/sii9234_drv.c
drivers/media/platform/sh_veu.c
drivers/media/platform/soc_camera/Kconfig
drivers/media/platform/soc_camera/atmel-isi.c
drivers/media/platform/soc_camera/mx2_camera.c
drivers/media/platform/soc_camera/pxa_camera.c
drivers/media/platform/soc_camera/rcar_vin.c
drivers/media/platform/soc_camera/soc_camera.c
drivers/media/platform/ti-vpe/vpdma.c
drivers/media/platform/ti-vpe/vpe.c
drivers/media/platform/via-camera.c
drivers/media/platform/vivi.c [deleted file]
drivers/media/platform/vivid/Kconfig [new file with mode: 0644]
drivers/media/platform/vivid/Makefile [new file with mode: 0644]
drivers/media/platform/vivid/vivid-core.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-core.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-ctrls.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-ctrls.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-kthread-cap.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-kthread-cap.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-kthread-out.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-kthread-out.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-osd.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-osd.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-radio-common.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-radio-common.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-radio-rx.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-radio-rx.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-radio-tx.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-radio-tx.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-rds-gen.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-rds-gen.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-sdr-cap.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-sdr-cap.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-tpg-colors.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-tpg-colors.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-tpg.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-tpg.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vbi-cap.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vbi-cap.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vbi-gen.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vbi-gen.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vbi-out.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vbi-out.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vid-cap.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vid-cap.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vid-common.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vid-common.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vid-out.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vid-out.h [new file with mode: 0644]
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-tea5764.c
drivers/media/radio/si470x/radio-si470x-common.c
drivers/media/radio/si470x/radio-si470x-usb.c
drivers/media/radio/wl128x/fmdrv_common.c
drivers/media/radio/wl128x/fmdrv_rx.c
drivers/media/radio/wl128x/fmdrv_tx.c
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/ene_ir.c
drivers/media/rc/fintek-cir.c
drivers/media/rc/img-ir/img-ir-hw.c
drivers/media/rc/img-ir/img-ir-hw.h
drivers/media/rc/imon.c
drivers/media/rc/ir-hix5hd2.c [new file with mode: 0644]
drivers/media/rc/ite-cir.c
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-dvbsky.c [new file with mode: 0644]
drivers/media/rc/lirc_dev.c
drivers/media/rc/mceusb.c
drivers/media/rc/nuvoton-cir.c
drivers/media/rc/st_rc.c
drivers/media/rc/streamzap.c
drivers/media/tuners/Kconfig
drivers/media/tuners/Makefile
drivers/media/tuners/e4000.c
drivers/media/tuners/it913x.c [new file with mode: 0644]
drivers/media/tuners/it913x.h [new file with mode: 0644]
drivers/media/tuners/m88ts2022.c
drivers/media/tuners/m88ts2022_priv.h
drivers/media/tuners/msi001.c
drivers/media/tuners/mt2060.c
drivers/media/tuners/mt2063.c
drivers/media/tuners/mxl301rf.c [new file with mode: 0644]
drivers/media/tuners/mxl301rf.h [new file with mode: 0644]
drivers/media/tuners/mxl5005s.c
drivers/media/tuners/qm1d1c0042.c [new file with mode: 0644]
drivers/media/tuners/qm1d1c0042.h [new file with mode: 0644]
drivers/media/tuners/si2157.c
drivers/media/tuners/si2157.h
drivers/media/tuners/si2157_priv.h
drivers/media/tuners/tda18212.c
drivers/media/tuners/tda18212.h
drivers/media/tuners/tda18271-common.c
drivers/media/tuners/tda18271-priv.h
drivers/media/tuners/tuner-xc2028.c
drivers/media/tuners/tuner_it913x.c [deleted file]
drivers/media/tuners/tuner_it913x.h [deleted file]
drivers/media/tuners/tuner_it913x_priv.h [deleted file]
drivers/media/tuners/xc4000.c
drivers/media/tuners/xc5000.c
drivers/media/usb/Kconfig
drivers/media/usb/Makefile
drivers/media/usb/airspy/airspy.c
drivers/media/usb/as102/Kconfig [new file with mode: 0644]
drivers/media/usb/as102/Makefile [new file with mode: 0644]
drivers/media/usb/as102/as102_drv.c [new file with mode: 0644]
drivers/media/usb/as102/as102_drv.h [new file with mode: 0644]
drivers/media/usb/as102/as102_fw.c [new file with mode: 0644]
drivers/media/usb/as102/as102_fw.h [new file with mode: 0644]
drivers/media/usb/as102/as102_usb_drv.c [new file with mode: 0644]
drivers/media/usb/as102/as102_usb_drv.h [new file with mode: 0644]
drivers/media/usb/as102/as10x_cmd.c [new file with mode: 0644]
drivers/media/usb/as102/as10x_cmd.h [new file with mode: 0644]
drivers/media/usb/as102/as10x_cmd_cfg.c [new file with mode: 0644]
drivers/media/usb/as102/as10x_cmd_stream.c [new file with mode: 0644]
drivers/media/usb/as102/as10x_handle.h [new file with mode: 0644]
drivers/media/usb/au0828/au0828-cards.c
drivers/media/usb/au0828/au0828-core.c
drivers/media/usb/au0828/au0828-dvb.c
drivers/media/usb/au0828/au0828-i2c.c
drivers/media/usb/au0828/au0828-input.c
drivers/media/usb/au0828/au0828-vbi.c
drivers/media/usb/au0828/au0828-video.c
drivers/media/usb/au0828/au0828.h
drivers/media/usb/cx231xx/cx231xx-avcore.c
drivers/media/usb/cx231xx/cx231xx-cards.c
drivers/media/usb/cx231xx/cx231xx-core.c
drivers/media/usb/cx231xx/cx231xx-dvb.c
drivers/media/usb/dvb-usb-v2/Kconfig
drivers/media/usb/dvb-usb-v2/Makefile
drivers/media/usb/dvb-usb-v2/af9015.c
drivers/media/usb/dvb-usb-v2/af9035.c
drivers/media/usb/dvb-usb-v2/af9035.h
drivers/media/usb/dvb-usb-v2/anysee.c
drivers/media/usb/dvb-usb-v2/anysee.h
drivers/media/usb/dvb-usb-v2/dvb_usb.h
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
drivers/media/usb/dvb-usb-v2/dvbsky.c [new file with mode: 0644]
drivers/media/usb/dvb-usb-v2/lmedm04.c
drivers/media/usb/dvb-usb-v2/mxl111sf.c
drivers/media/usb/dvb-usb/Kconfig
drivers/media/usb/dvb-usb/af9005.c
drivers/media/usb/dvb-usb/cxusb.c
drivers/media/usb/dvb-usb/cxusb.h
drivers/media/usb/dvb-usb/dib0700_devices.c
drivers/media/usb/dvb-usb/dibusb-common.c
drivers/media/usb/dvb-usb/dw2102.c
drivers/media/usb/dvb-usb/opera1.c
drivers/media/usb/dvb-usb/pctv452e.c
drivers/media/usb/em28xx/em28xx-audio.c
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/em28xx/em28xx-core.c
drivers/media/usb/em28xx/em28xx-dvb.c
drivers/media/usb/em28xx/em28xx-input.c
drivers/media/usb/em28xx/em28xx-vbi.c
drivers/media/usb/em28xx/em28xx-video.c
drivers/media/usb/em28xx/em28xx.h
drivers/media/usb/go7007/go7007-usb.c
drivers/media/usb/gspca/gspca.c
drivers/media/usb/gspca/gspca.h
drivers/media/usb/gspca/kinect.c
drivers/media/usb/gspca/sn9c20x.c
drivers/media/usb/hackrf/Kconfig [new file with mode: 0644]
drivers/media/usb/hackrf/Makefile [new file with mode: 0644]
drivers/media/usb/hackrf/hackrf.c [new file with mode: 0644]
drivers/media/usb/hdpvr/hdpvr-control.c
drivers/media/usb/hdpvr/hdpvr-core.c
drivers/media/usb/msi2500/msi2500.c
drivers/media/usb/pwc/pwc-v4l.c
drivers/media/usb/s2255/s2255drv.c
drivers/media/usb/siano/smsusb.c
drivers/media/usb/ttusb-dec/ttusbdecfe.c
drivers/media/usb/usbtv/Kconfig
drivers/media/usb/usbtv/Makefile
drivers/media/usb/usbtv/usbtv-audio.c [new file with mode: 0644]
drivers/media/usb/usbtv/usbtv-core.c
drivers/media/usb/usbtv/usbtv-video.c
drivers/media/usb/usbtv/usbtv.h
drivers/media/usb/uvc/uvc_ctrl.c
drivers/media/usb/uvc/uvc_driver.c
drivers/media/usb/uvc/uvc_v4l2.c
drivers/media/usb/uvc/uvc_video.c
drivers/media/usb/uvc/uvcvideo.h
drivers/media/v4l2-core/tuner-core.c
drivers/media/v4l2-core/v4l2-common.c
drivers/media/v4l2-core/v4l2-compat-ioctl32.c
drivers/media/v4l2-core/v4l2-ctrls.c
drivers/media/v4l2-core/v4l2-dv-timings.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/v4l2-subdev.c
drivers/media/v4l2-core/videobuf-core.c
drivers/media/v4l2-core/videobuf-dma-sg.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/staging/media/Kconfig
drivers/staging/media/Makefile
drivers/staging/media/as102/Kconfig [deleted file]
drivers/staging/media/as102/Makefile [deleted file]
drivers/staging/media/as102/as102_drv.c [deleted file]
drivers/staging/media/as102/as102_drv.h [deleted file]
drivers/staging/media/as102/as102_fe.c [deleted file]
drivers/staging/media/as102/as102_fw.c [deleted file]
drivers/staging/media/as102/as102_fw.h [deleted file]
drivers/staging/media/as102/as102_usb_drv.c [deleted file]
drivers/staging/media/as102/as102_usb_drv.h [deleted file]
drivers/staging/media/as102/as10x_cmd.c [deleted file]
drivers/staging/media/as102/as10x_cmd.h [deleted file]
drivers/staging/media/as102/as10x_cmd_cfg.c [deleted file]
drivers/staging/media/as102/as10x_cmd_stream.c [deleted file]
drivers/staging/media/as102/as10x_handle.h [deleted file]
drivers/staging/media/as102/as10x_types.h [deleted file]
drivers/staging/media/davinci_vpfe/Kconfig
drivers/staging/media/dt3155v4l/Kconfig
drivers/staging/media/lirc/lirc_imon.c
drivers/staging/media/lirc/lirc_sasem.c
drivers/staging/media/omap4iss/Kconfig
include/media/davinci/dm644x_ccdc.h
include/media/omap3isp.h
include/media/rc-map.h
include/media/videobuf2-core.h
include/uapi/linux/Kbuild
include/uapi/linux/smiapp.h [new file with mode: 0644]
include/uapi/linux/v4l2-controls.h
include/uapi/linux/v4l2-dv-timings.h
include/uapi/linux/videodev2.h

index 3a626d1b8f2e4d8022831f0961fbb83bc359b487..07ffc76553ba098490cbba874f6f513f8981222e 100644 (file)
@@ -2566,6 +2566,12 @@ fields changed from _s32 to _u32.
          <para>Added compound control types and &VIDIOC-QUERY-EXT-CTRL;.
          </para>
         </listitem>
+      <title>V4L2 in Linux 3.18</title>
+      <orderedlist>
+       <listitem>
+         <para>Added <constant>V4L2_CID_PAN_SPEED</constant> and
+ <constant>V4L2_CID_TILT_SPEED</constant> camera controls.</para>
+       </listitem>
       </orderedlist>
     </section>
 
index 9f5ffd85560b58b3032867b57ec095153e7bfd07..e013e4bf244c509fef7477cd8ae182bcded29693 100644 (file)
@@ -3965,6 +3965,27 @@ by exposure, white balance or focus controls.</entry>
          </row>
          <row><entry></entry></row>
 
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_PAN_SPEED</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">This control turns the
+camera horizontally at the specific speed. The unit is undefined. A
+positive value moves the camera to the right (clockwise when viewed
+from above), a negative value to the left. A value of zero stops the motion
+if one is in progress and has no effect otherwise.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_TILT_SPEED</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">This control turns the
+camera vertically at the specified speed. The unit is undefined. A
+positive value moves the camera up, a negative value down. A value of zero
+stops the motion if one is in progress and has no effect otherwise.</entry>
+         </row>
+         <row><entry></entry></row>
+
        </tbody>
       </tgroup>
     </table>
@@ -4790,6 +4811,40 @@ interface and may change in the future.</para>
            conversion.
            </entry>
          </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN_RED</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Test pattern red colour component.
+           </entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN_GREENR</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Test pattern green (next to red)
+           colour component.
+           </entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN_BLUE</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Test pattern blue colour component.
+           </entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN_GREENB</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Test pattern green (next to blue)
+           colour component.
+           </entry>
+         </row>
          <row><entry></entry></row>
        </tbody>
       </tgroup>
index 2aae8e9452a42dd41656f9692e78122343957d21..6ab4f0f3db64abdc9de76ff3ccf458881f9b49e2 100644 (file)
@@ -237,9 +237,9 @@ for a pixel lie next to each other in memory.</para>
            <entry>g<subscript>4</subscript></entry>
            <entry>g<subscript>3</subscript></entry>
          </row>
-         <row id="V4L2-PIX-FMT-RGB555X">
-           <entry><constant>V4L2_PIX_FMT_RGB555X</constant></entry>
-           <entry>'RGBQ'</entry>
+         <row id="V4L2-PIX-FMT-ARGB555X">
+           <entry><constant>V4L2_PIX_FMT_ARGB555X</constant></entry>
+           <entry>'AR15' | (1 &lt;&lt; 31)</entry>
            <entry></entry>
            <entry>a</entry>
            <entry>r<subscript>4</subscript></entry>
@@ -259,6 +259,28 @@ for a pixel lie next to each other in memory.</para>
            <entry>b<subscript>1</subscript></entry>
            <entry>b<subscript>0</subscript></entry>
          </row>
+         <row id="V4L2-PIX-FMT-XRGB555X">
+           <entry><constant>V4L2_PIX_FMT_XRGB555X</constant></entry>
+           <entry>'XR15' | (1 &lt;&lt; 31)</entry>
+           <entry></entry>
+           <entry>-</entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+         </row>
          <row id="V4L2-PIX-FMT-RGB565X">
            <entry><constant>V4L2_PIX_FMT_RGB565X</constant></entry>
            <entry>'RGBR'</entry>
@@ -464,7 +486,7 @@ for a pixel lie next to each other in memory.</para>
          </row>
          <row id="V4L2-PIX-FMT-ARGB32">
            <entry><constant>V4L2_PIX_FMT_ARGB32</constant></entry>
-           <entry>'AX24'</entry>
+           <entry>'BA24'</entry>
            <entry></entry>
            <entry>a<subscript>7</subscript></entry>
            <entry>a<subscript>6</subscript></entry>
@@ -800,6 +822,28 @@ image</title>
            <entry>g<subscript>4</subscript></entry>
            <entry>g<subscript>3</subscript></entry>
          </row>
+         <row id="V4L2-PIX-FMT-RGB555X">
+           <entry><constant>V4L2_PIX_FMT_RGB555X</constant></entry>
+           <entry>'RGBQ'</entry>
+           <entry></entry>
+           <entry>a</entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+         </row>
          <row id="V4L2-PIX-FMT-BGR32">
            <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry>
            <entry>'BGR4'</entry>
index cb7732582f0365861ccf14f25a3a83ecfdb5d05e..b036f8963353a2a2f88c336855da9282e7d68fb6 100644 (file)
            <entry></entry>
            <entry>&v4l2-event-vsync;</entry>
             <entry><structfield>vsync</structfield></entry>
-           <entry>Event data for event V4L2_EVENT_VSYNC.
+           <entry>Event data for event <constant>V4L2_EVENT_VSYNC</constant>.
             </entry>
          </row>
          <row>
            <entry></entry>
            <entry>&v4l2-event-ctrl;</entry>
             <entry><structfield>ctrl</structfield></entry>
-           <entry>Event data for event V4L2_EVENT_CTRL.
+           <entry>Event data for event <constant>V4L2_EVENT_CTRL</constant>.
             </entry>
          </row>
          <row>
            <entry></entry>
            <entry>&v4l2-event-frame-sync;</entry>
             <entry><structfield>frame_sync</structfield></entry>
-           <entry>Event data for event V4L2_EVENT_FRAME_SYNC.</entry>
+           <entry>Event data for event
+           <constant>V4L2_EVENT_FRAME_SYNC</constant>.</entry>
          </row>
          <row>
            <entry></entry>
index ce4563b87131c5ad384a22cf63fadcd95d85206d..6df40db4c8ba9f7674dda280e914a365ed3abe7d 100644 (file)
@@ -24,7 +24,7 @@
        <funcdef>int <function>ioctl</function></funcdef>
        <paramdef>int <parameter>fd</parameter></paramdef>
        <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_edid *<parameter>argp</parameter></paramdef>
+       <paramdef>struct v4l2_edid *<parameter>argp</parameter></paramdef>
       </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
            maximum number of blocks as defined by the standard). When you set the EDID and
            <structfield>blocks</structfield> is 0, then the EDID is disabled or erased.</entry>
          </row>
-         <row>
-           <entry>__u8&nbsp;*</entry>
-           <entry><structfield>edid</structfield></entry>
-           <entry>Pointer to memory that contains the EDID. The minimum size is
-           <structfield>blocks</structfield>&nbsp;*&nbsp;128.</entry>
-         </row>
          <row>
            <entry>__u32</entry>
            <entry><structfield>reserved</structfield>[5]</entry>
            <entry>Reserved for future extensions. Applications and drivers must
            set the array to zero.</entry>
          </row>
+         <row>
+           <entry>__u8&nbsp;*</entry>
+           <entry><structfield>edid</structfield></entry>
+           <entry>Pointer to memory that contains the EDID. The minimum size is
+           <structfield>blocks</structfield>&nbsp;*&nbsp;128.</entry>
+         </row>
        </tbody>
       </tgroup>
     </table>
index 9f6095608837b29085aa49171f544474801d3c6e..d7c9365ecdbe245e05aee3875ee09ab5b8fa0199 100644 (file)
          </row>
          <row>
            <entry><constant>V4L2_EVENT_MOTION_DET</constant></entry>
-           <entry>5</entry>
+           <entry>6</entry>
            <entry>
              <para>Triggered whenever the motion detection state for one or more of the regions
              changes. This event has a &v4l2-event-motion-det; associated with it.</para>
diff --git a/Documentation/devicetree/bindings/media/hix5hd2-ir.txt b/Documentation/devicetree/bindings/media/hix5hd2-ir.txt
new file mode 100644 (file)
index 0000000..fb5e760
--- /dev/null
@@ -0,0 +1,25 @@
+Device-Tree bindings for hix5hd2 ir IP
+
+Required properties:
+       - compatible: Should contain "hisilicon,hix5hd2-ir".
+       - reg: Base physical address of the controller and length of memory
+         mapped region.
+       - interrupts: interrupt-specifier for the sole interrupt generated by
+         the device. The interrupt specifier format depends on the interrupt
+         controller parent.
+       - clocks: clock phandle and specifier pair.
+       - hisilicon,power-syscon: phandle of syscon used to control power.
+
+Optional properties:
+       - linux,rc-map-name : Remote control map name.
+
+Example node:
+
+       ir: ir@f8001000 {
+               compatible = "hisilicon,hix5hd2-ir";
+               reg = <0xf8001000 0x1000>;
+               interrupts = <0 47 4>;
+               clocks = <&clock HIX5HD2_FIXED_24M>;
+               hisilicon,power-syscon = <&sysctrl>;
+               linux,rc-map-name = "rc-tivo";
+       };
index 26c623dd3aa34699561a5cbbeeab4592ff161e97..91b43d2738c7935d8a919a6655b52fc95add8541 100755 (executable)
@@ -708,23 +708,25 @@ sub drxk_terratec_htc_stick {
 }
 
 sub it9135 {
-       my $sourcefile = "dvb-usb-it9135.zip";
-       my $url = "http://www.ite.com.tw/uploads/firmware/v3.6.0.0/$sourcefile";
-       my $hash = "1e55f6c8833f1d0ae067c2bb2953e6a9";
-       my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
-       my $outfile = "dvb-usb-it9135.fw";
+       my $url = "http://www.ite.com.tw/uploads/firmware/v3.25.0.0/";
+       my $file1 = "dvb-usb-it9135-01.zip";
        my $fwfile1 = "dvb-usb-it9135-01.fw";
+       my $hash1 = "02fcf11174eda84745dae7e61c5ff9ba";
+       my $file2 = "dvb-usb-it9135-02.zip";
        my $fwfile2 = "dvb-usb-it9135-02.fw";
+       my $hash2 = "d5e1437dc24358578e07999475d4cac9";
 
        checkstandard();
 
-       wgetfile($sourcefile, $url);
-       unzip($sourcefile, $tmpdir);
-       verify("$tmpdir/$outfile", $hash);
-       extract("$tmpdir/$outfile", 64, 8128, "$fwfile1");
-       extract("$tmpdir/$outfile", 12866, 5817, "$fwfile2");
+       wgetfile($file1, $url . $file1);
+       unzip($file1, "");
+       verify("$fwfile1", $hash1);
+
+       wgetfile($file2, $url . $file2);
+       unzip($file2, "");
+       verify("$fwfile2", $hash2);
 
-       "$fwfile1 $fwfile2"
+       "$file1 $file2"
 }
 
 sub tda10071 {
diff --git a/Documentation/video4linux/vivid.txt b/Documentation/video4linux/vivid.txt
new file mode 100644 (file)
index 0000000..eeb11a2
--- /dev/null
@@ -0,0 +1,1111 @@
+vivid: Virtual Video Test Driver
+================================
+
+This driver emulates video4linux hardware of various types: video capture, video
+output, vbi capture and output, radio receivers and transmitters and a software
+defined radio receiver. In addition a simple framebuffer device is available for
+testing capture and output overlays.
+
+Up to 64 vivid instances can be created, each with up to 16 inputs and 16 outputs.
+
+Each input can be a webcam, TV capture device, S-Video capture device or an HDMI
+capture device. Each output can be an S-Video output device or an HDMI output
+device.
+
+These inputs and outputs act exactly as a real hardware device would behave. This
+allows you to use this driver as a test input for application development, since
+you can test the various features without requiring special hardware.
+
+This document describes the features implemented by this driver:
+
+- Support for read()/write(), MMAP, USERPTR and DMABUF streaming I/O.
+- A large list of test patterns and variations thereof
+- Working brightness, contrast, saturation and hue controls
+- Support for the alpha color component
+- Full colorspace support, including limited/full RGB range
+- All possible control types are present
+- Support for various pixel aspect ratios and video aspect ratios
+- Error injection to test what happens if errors occur
+- Supports crop/compose/scale in any combination for both input and output
+- Can emulate up to 4K resolutions
+- All Field settings are supported for testing interlaced capturing
+- Supports all standard YUV and RGB formats, including two multiplanar YUV formats
+- Raw and Sliced VBI capture and output support
+- Radio receiver and transmitter support, including RDS support
+- Software defined radio (SDR) support
+- Capture and output overlay support
+
+These features will be described in more detail below.
+
+
+Table of Contents
+-----------------
+
+Section 1: Configuring the driver
+Section 2: Video Capture
+Section 2.1: Webcam Input
+Section 2.2: TV and S-Video Inputs
+Section 2.3: HDMI Input
+Section 3: Video Output
+Section 3.1: S-Video Output
+Section 3.2: HDMI Output
+Section 4: VBI Capture
+Section 5: VBI Output
+Section 6: Radio Receiver
+Section 7: Radio Transmitter
+Section 8: Software Defined Radio Receiver
+Section 9: Controls
+Section 9.1: User Controls - Test Controls
+Section 9.2: User Controls - Video Capture
+Section 9.3: User Controls - Audio
+Section 9.4: Vivid Controls
+Section 9.4.1: Test Pattern Controls
+Section 9.4.2: Capture Feature Selection Controls
+Section 9.4.3: Output Feature Selection Controls
+Section 9.4.4: Error Injection Controls
+Section 9.4.5: VBI Raw Capture Controls
+Section 9.5: Digital Video Controls
+Section 9.6: FM Radio Receiver Controls
+Section 9.7: FM Radio Modulator
+Section 10: Video, VBI and RDS Looping
+Section 10.1: Video and Sliced VBI looping
+Section 10.2: Radio & RDS Looping
+Section 11: Cropping, Composing, Scaling
+Section 12: Formats
+Section 13: Capture Overlay
+Section 14: Output Overlay
+Section 15: Some Future Improvements
+
+
+Section 1: Configuring the driver
+---------------------------------
+
+By default the driver will create a single instance that has a video capture
+device with webcam, TV, S-Video and HDMI inputs, a video output device with
+S-Video and HDMI outputs, one vbi capture device, one vbi output device, one
+radio receiver device, one radio transmitter device and one SDR device.
+
+The number of instances, devices, video inputs and outputs and their types are
+all configurable using the following module options:
+
+n_devs: number of driver instances to create. By default set to 1. Up to 64
+       instances can be created.
+
+node_types: which devices should each driver instance create. An array of
+       hexadecimal values, one for each instance. The default is 0x1d3d.
+       Each value is a bitmask with the following meaning:
+               bit 0: Video Capture node
+               bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both
+               bit 4: Radio Receiver node
+               bit 5: Software Defined Radio Receiver node
+               bit 8: Video Output node
+               bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both
+               bit 12: Radio Transmitter node
+               bit 16: Framebuffer for testing overlays
+
+       So to create four instances, the first two with just one video capture
+       device, the second two with just one video output device you would pass
+       these module options to vivid:
+
+               n_devs=4 node_types=0x1,0x1,0x100,0x100
+
+num_inputs: the number of inputs, one for each instance. By default 4 inputs
+       are created for each video capture device. At most 16 inputs can be created,
+       and there must be at least one.
+
+input_types: the input types for each instance, the default is 0xe4. This defines
+       what the type of each input is when the inputs are created for each driver
+       instance. This is a hexadecimal value with up to 16 pairs of bits, each
+       pair gives the type and bits 0-1 map to input 0, bits 2-3 map to input 1,
+       30-31 map to input 15. Each pair of bits has the following meaning:
+
+               00: this is a webcam input
+               01: this is a TV tuner input
+               10: this is an S-Video input
+               11: this is an HDMI input
+
+       So to create a video capture device with 8 inputs where input 0 is a TV
+       tuner, inputs 1-3 are S-Video inputs and inputs 4-7 are HDMI inputs you
+       would use the following module options:
+
+               num_inputs=8 input_types=0xffa9
+
+num_outputs: the number of outputs, one for each instance. By default 2 outputs
+       are created for each video output device. At most 16 outputs can be
+       created, and there must be at least one.
+
+output_types: the output types for each instance, the default is 0x02. This defines
+       what the type of each output is when the outputs are created for each
+       driver instance. This is a hexadecimal value with up to 16 bits, each bit
+       gives the type and bit 0 maps to output 0, bit 1 maps to output 1, bit
+       15 maps to output 15. The meaning of each bit is as follows:
+
+               0: this is an S-Video output
+               1: this is an HDMI output
+
+       So to create a video output device with 8 outputs where outputs 0-3 are
+       S-Video outputs and outputs 4-7 are HDMI outputs you would use the
+       following module options:
+
+               num_outputs=8 output_types=0xf0
+
+vid_cap_nr: give the desired videoX start number for each video capture device.
+       The default is -1 which will just take the first free number. This allows
+       you to map capture video nodes to specific videoX device nodes. Example:
+
+               n_devs=4 vid_cap_nr=2,4,6,8
+
+       This will attempt to assign /dev/video2 for the video capture device of
+       the first vivid instance, video4 for the next up to video8 for the last
+       instance. If it can't succeed, then it will just take the next free
+       number.
+
+vid_out_nr: give the desired videoX start number for each video output device.
+        The default is -1 which will just take the first free number.
+
+vbi_cap_nr: give the desired vbiX start number for each vbi capture device.
+        The default is -1 which will just take the first free number.
+
+vbi_out_nr: give the desired vbiX start number for each vbi output device.
+        The default is -1 which will just take the first free number.
+
+radio_rx_nr: give the desired radioX start number for each radio receiver device.
+        The default is -1 which will just take the first free number.
+
+radio_tx_nr: give the desired radioX start number for each radio transmitter
+       device. The default is -1 which will just take the first free number.
+
+sdr_cap_nr: give the desired swradioX start number for each SDR capture device.
+        The default is -1 which will just take the first free number.
+
+ccs_cap_mode: specify the allowed video capture crop/compose/scaling combination
+       for each driver instance. Video capture devices can have any combination
+       of cropping, composing and scaling capabilities and this will tell the
+       vivid driver which of those is should emulate. By default the user can
+       select this through controls.
+
+       The value is either -1 (controlled by the user) or a set of three bits,
+       each enabling (1) or disabling (0) one of the features:
+
+               bit 0: Enable crop support. Cropping will take only part of the
+                      incoming picture.
+               bit 1: Enable compose support. Composing will copy the incoming
+                      picture into a larger buffer.
+               bit 2: Enable scaling support. Scaling can scale the incoming
+                      picture. The scaler of the vivid driver can enlarge up
+                      or down to four times the original size. The scaler is
+                      very simple and low-quality. Simplicity and speed were
+                      key, not quality.
+
+       Note that this value is ignored by webcam inputs: those enumerate
+       discrete framesizes and that is incompatible with cropping, composing
+       or scaling.
+
+ccs_out_mode: specify the allowed video output crop/compose/scaling combination
+       for each driver instance. Video output devices can have any combination
+       of cropping, composing and scaling capabilities and this will tell the
+       vivid driver which of those is should emulate. By default the user can
+       select this through controls.
+
+       The value is either -1 (controlled by the user) or a set of three bits,
+       each enabling (1) or disabling (0) one of the features:
+
+               bit 0: Enable crop support. Cropping will take only part of the
+                      outgoing buffer.
+               bit 1: Enable compose support. Composing will copy the incoming
+                      buffer into a larger picture frame.
+               bit 2: Enable scaling support. Scaling can scale the incoming
+                      buffer. The scaler of the vivid driver can enlarge up
+                      or down to four times the original size. The scaler is
+                      very simple and low-quality. Simplicity and speed were
+                      key, not quality.
+
+multiplanar: select whether each device instance supports multi-planar formats,
+       and thus the V4L2 multi-planar API. By default the first device instance
+       is single-planar, the second multi-planar, and it keeps alternating.
+
+       This module option can override that for each instance. Values are:
+
+               0: use alternating single and multi-planar devices.
+               1: this is a single-planar instance.
+               2: this is a multi-planar instance.
+
+vivid_debug: enable driver debugging info
+
+no_error_inj: if set disable the error injecting controls. This option is
+       needed in order to run a tool like v4l2-compliance. Tools like that
+       exercise all controls including a control like 'Disconnect' which
+       emulates a USB disconnect, making the device inaccessible and so
+       all tests that v4l2-compliance is doing will fail afterwards.
+
+       There may be other situations as well where you want to disable the
+       error injection support of vivid. When this option is set, then the
+       controls that select crop, compose and scale behavior are also
+       removed. Unless overridden by ccs_cap_mode and/or ccs_out_mode the
+       will default to enabling crop, compose and scaling.
+
+Taken together, all these module options allow you to precisely customize
+the driver behavior and test your application with all sorts of permutations.
+It is also very suitable to emulate hardware that is not yet available, e.g.
+when developing software for a new upcoming device.
+
+
+Section 2: Video Capture
+------------------------
+
+This is probably the most frequently used feature. The video capture device
+can be configured by using the module options num_inputs, input_types and
+ccs_cap_mode (see section 1 for more detailed information), but by default
+four inputs are configured: a webcam, a TV tuner, an S-Video and an HDMI
+input, one input for each input type. Those are described in more detail
+below.
+
+Special attention has been given to the rate at which new frames become
+available. The jitter will be around 1 jiffie (that depends on the HZ
+configuration of your kernel, so usually 1/100, 1/250 or 1/1000 of a second),
+but the long-term behavior is exactly following the framerate. So a
+framerate of 59.94 Hz is really different from 60 Hz. If the framerate
+exceeds your kernel's HZ value, then you will get dropped frames, but the
+frame/field sequence counting will keep track of that so the sequence
+count will skip whenever frames are dropped.
+
+
+Section 2.1: Webcam Input
+-------------------------
+
+The webcam input supports three framesizes: 320x180, 640x360 and 1280x720. It
+supports frames per second settings of 10, 15, 25, 30, 50 and 60 fps. Which ones
+are available depends on the chosen framesize: the larger the framesize, the
+lower the maximum frames per second.
+
+The initially selected colorspace when you switch to the webcam input will be
+sRGB.
+
+
+Section 2.2: TV and S-Video Inputs
+----------------------------------
+
+The only difference between the TV and S-Video input is that the TV has a
+tuner. Otherwise they behave identically.
+
+These inputs support audio inputs as well: one TV and one Line-In. They
+both support all TV standards. If the standard is queried, then the Vivid
+controls 'Standard Signal Mode' and 'Standard' determine what
+the result will be.
+
+These inputs support all combinations of the field setting. Special care has
+been taken to faithfully reproduce how fields are handled for the different
+TV standards. This is particularly noticable when generating a horizontally
+moving image so the temporal effect of using interlaced formats becomes clearly
+visible. For 50 Hz standards the top field is the oldest and the bottom field
+is the newest in time. For 60 Hz standards that is reversed: the bottom field
+is the oldest and the top field is the newest in time.
+
+When you start capturing in V4L2_FIELD_ALTERNATE mode the first buffer will
+contain the top field for 50 Hz standards and the bottom field for 60 Hz
+standards. This is what capture hardware does as well.
+
+Finally, for PAL/SECAM standards the first half of the top line contains noise.
+This simulates the Wide Screen Signal that is commonly placed there.
+
+The initially selected colorspace when you switch to the TV or S-Video input
+will be SMPTE-170M.
+
+The pixel aspect ratio will depend on the TV standard. The video aspect ratio
+can be selected through the 'Standard Aspect Ratio' Vivid control.
+Choices are '4x3', '16x9' which will give letterboxed widescreen video and
+'16x9 Anomorphic' which will give full screen squashed anamorphic widescreen
+video that will need to be scaled accordingly.
+
+The TV 'tuner' supports a frequency range of 44-958 MHz. Channels are available
+every 6 MHz, starting from 49.25 MHz. For each channel the generated image
+will be in color for the +/- 0.25 MHz around it, and in grayscale for
++/- 1 MHz around the channel. Beyond that it is just noise. The VIDIOC_G_TUNER
+ioctl will return 100% signal strength for +/- 0.25 MHz and 50% for +/- 1 MHz.
+It will also return correct afc values to show whether the frequency is too
+low or too high.
+
+The audio subchannels that are returned are MONO for the +/- 1 MHz range around
+a valid channel frequency. When the frequency is within +/- 0.25 MHz of the
+channel it will return either MONO, STEREO, either MONO | SAP (for NTSC) or
+LANG1 | LANG2 (for others), or STEREO | SAP.
+
+Which one is returned depends on the chosen channel, each next valid channel
+will cycle through the possible audio subchannel combinations. This allows
+you to test the various combinations by just switching channels..
+
+Finally, for these inputs the v4l2_timecode struct is filled in in the
+dequeued v4l2_buffer struct.
+
+
+Section 2.3: HDMI Input
+-----------------------
+
+The HDMI inputs supports all CEA-861 and DMT timings, both progressive and
+interlaced, for pixelclock frequencies between 25 and 600 MHz. The field
+mode for interlaced formats is always V4L2_FIELD_ALTERNATE. For HDMI the
+field order is always top field first, and when you start capturing an
+interlaced format you will receive the top field first.
+
+The initially selected colorspace when you switch to the HDMI input or
+select an HDMI timing is based on the format resolution: for resolutions
+less than or equal to 720x576 the colorspace is set to SMPTE-170M, for
+others it is set to REC-709 (CEA-861 timings) or sRGB (VESA DMT timings).
+
+The pixel aspect ratio will depend on the HDMI timing: for 720x480 is it
+set as for the NTSC TV standard, for 720x576 it is set as for the PAL TV
+standard, and for all others a 1:1 pixel aspect ratio is returned.
+
+The video aspect ratio can be selected through the 'DV Timings Aspect Ratio'
+Vivid control. Choices are 'Source Width x Height' (just use the
+same ratio as the chosen format), '4x3' or '16x9', either of which can
+result in pillarboxed or letterboxed video.
+
+For HDMI inputs it is possible to set the EDID. By default a simple EDID
+is provided. You can only set the EDID for HDMI inputs. Internally, however,
+the EDID is shared between all HDMI inputs.
+
+No interpretation is done of the EDID data.
+
+
+Section 3: Video Output
+-----------------------
+
+The video output device can be configured by using the module options
+num_outputs, output_types and ccs_out_mode (see section 1 for more detailed
+information), but by default two outputs are configured: an S-Video and an
+HDMI input, one output for each output type. Those are described in more detail
+below.
+
+Like with video capture the framerate is also exact in the long term.
+
+
+Section 3.1: S-Video Output
+---------------------------
+
+This output supports audio outputs as well: "Line-Out 1" and "Line-Out 2".
+The S-Video output supports all TV standards.
+
+This output supports all combinations of the field setting.
+
+The initially selected colorspace when you switch to the TV or S-Video input
+will be SMPTE-170M.
+
+
+Section 3.2: HDMI Output
+------------------------
+
+The HDMI output supports all CEA-861 and DMT timings, both progressive and
+interlaced, for pixelclock frequencies between 25 and 600 MHz. The field
+mode for interlaced formats is always V4L2_FIELD_ALTERNATE.
+
+The initially selected colorspace when you switch to the HDMI output or
+select an HDMI timing is based on the format resolution: for resolutions
+less than or equal to 720x576 the colorspace is set to SMPTE-170M, for
+others it is set to REC-709 (CEA-861 timings) or sRGB (VESA DMT timings).
+
+The pixel aspect ratio will depend on the HDMI timing: for 720x480 is it
+set as for the NTSC TV standard, for 720x576 it is set as for the PAL TV
+standard, and for all others a 1:1 pixel aspect ratio is returned.
+
+An HDMI output has a valid EDID which can be obtained through VIDIOC_G_EDID.
+
+
+Section 4: VBI Capture
+----------------------
+
+There are three types of VBI capture devices: those that only support raw
+(undecoded) VBI, those that only support sliced (decoded) VBI and those that
+support both. This is determined by the node_types module option. In all
+cases the driver will generate valid VBI data: for 60 Hz standards it will
+generate Closed Caption and XDS data. The closed caption stream will
+alternate between "Hello world!" and "Closed captions test" every second.
+The XDS stream will give the current time once a minute. For 50 Hz standards
+it will generate the Wide Screen Signal which is based on the actual Video
+Aspect Ratio control setting and teletext pages 100-159, one page per frame.
+
+The VBI device will only work for the S-Video and TV inputs, it will give
+back an error if the current input is a webcam or HDMI.
+
+
+Section 5: VBI Output
+---------------------
+
+There are three types of VBI output devices: those that only support raw
+(undecoded) VBI, those that only support sliced (decoded) VBI and those that
+support both. This is determined by the node_types module option.
+
+The sliced VBI output supports the Wide Screen Signal and the teletext signal
+for 50 Hz standards and Closed Captioning + XDS for 60 Hz standards.
+
+The VBI device will only work for the S-Video output, it will give
+back an error if the current output is HDMI.
+
+
+Section 6: Radio Receiver
+-------------------------
+
+The radio receiver emulates an FM/AM/SW receiver. The FM band also supports RDS.
+The frequency ranges are:
+
+       FM: 64 MHz - 108 MHz
+       AM: 520 kHz - 1710 kHz
+       SW: 2300 kHz - 26.1 MHz
+
+Valid channels are emulated every 1 MHz for FM and every 100 kHz for AM and SW.
+The signal strength decreases the further the frequency is from the valid
+frequency until it becomes 0% at +/- 50 kHz (FM) or 5 kHz (AM/SW) from the
+ideal frequency. The initial frequency when the driver is loaded is set to
+95 MHz.
+
+The FM receiver supports RDS as well, both using 'Block I/O' and 'Controls'
+modes. In the 'Controls' mode the RDS information is stored in read-only
+controls. These controls are updated every time the frequency is changed,
+or when the tuner status is requested. The Block I/O method uses the read()
+interface to pass the RDS blocks on to the application for decoding.
+
+The RDS signal is 'detected' for +/- 12.5 kHz around the channel frequency,
+and the further the frequency is away from the valid frequency the more RDS
+errors are randomly introduced into the block I/O stream, up to 50% of all
+blocks if you are +/- 12.5 kHz from the channel frequency. All four errors
+can occur in equal proportions: blocks marked 'CORRECTED', blocks marked
+'ERROR', blocks marked 'INVALID' and dropped blocks.
+
+The generated RDS stream contains all the standard fields contained in a
+0B group, and also radio text and the current time.
+
+The receiver supports HW frequency seek, either in Bounded mode, Wrap Around
+mode or both, which is configurable with the "Radio HW Seek Mode" control.
+
+
+Section 7: Radio Transmitter
+----------------------------
+
+The radio transmitter emulates an FM/AM/SW transmitter. The FM band also supports RDS.
+The frequency ranges are:
+
+       FM: 64 MHz - 108 MHz
+       AM: 520 kHz - 1710 kHz
+       SW: 2300 kHz - 26.1 MHz
+
+The initial frequency when the driver is loaded is 95.5 MHz.
+
+The FM transmitter supports RDS as well, both using 'Block I/O' and 'Controls'
+modes. In the 'Controls' mode the transmitted RDS information is configured
+using controls, and in 'Block I/O' mode the blocks are passed to the driver
+using write().
+
+
+Section 8: Software Defined Radio Receiver
+------------------------------------------
+
+The SDR receiver has three frequency bands for the ADC tuner:
+
+       - 300 kHz
+       - 900 kHz - 2800 kHz
+       - 3200 kHz
+
+The RF tuner supports 50 MHz - 2000 MHz.
+
+The generated data contains the In-phase and Quadrature components of a
+1 kHz tone that has an amplitude of sqrt(2).
+
+
+Section 9: Controls
+-------------------
+
+Different devices support different controls. The sections below will describe
+each control and which devices support them.
+
+
+Section 9.1: User Controls - Test Controls
+------------------------------------------
+
+The Button, Boolean, Integer 32 Bits, Integer 64 Bits, Menu, String, Bitmask and
+Integer Menu are controls that represent all possible control types. The Menu
+control and the Integer Menu control both have 'holes' in their menu list,
+meaning that one or more menu items return EINVAL when VIDIOC_QUERYMENU is called.
+Both menu controls also have a non-zero minimum control value.  These features
+allow you to check if your application can handle such things correctly.
+These controls are supported for every device type.
+
+
+Section 9.2: User Controls - Video Capture
+------------------------------------------
+
+The following controls are specific to video capture.
+
+The Brightness, Contrast, Saturation and Hue controls actually work and are
+standard. There is one special feature with the Brightness control: each
+video input has its own brightness value, so changing input will restore
+the brightness for that input. In addition, each video input uses a different
+brightness range (minimum and maximum control values). Switching inputs will
+cause a control event to be sent with the V4L2_EVENT_CTRL_CH_RANGE flag set.
+This allows you to test controls that can change their range.
+
+The 'Gain, Automatic' and Gain controls can be used to test volatile controls:
+if 'Gain, Automatic' is set, then the Gain control is volatile and changes
+constantly. If 'Gain, Automatic' is cleared, then the Gain control is a normal
+control.
+
+The 'Horizontal Flip' and 'Vertical Flip' controls can be used to flip the
+image. These combine with the 'Sensor Flipped Horizontally/Vertically' Vivid
+controls.
+
+The 'Alpha Component' control can be used to set the alpha component for
+formats containing an alpha channel.
+
+
+Section 9.3: User Controls - Audio
+----------------------------------
+
+The following controls are specific to video capture and output and radio
+receivers and transmitters.
+
+The 'Volume' and 'Mute' audio controls are typical for such devices to
+control the volume and mute the audio. They don't actually do anything in
+the vivid driver.
+
+
+Section 9.4: Vivid Controls
+---------------------------
+
+These vivid custom controls control the image generation, error injection, etc.
+
+
+Section 9.4.1: Test Pattern Controls
+------------------------------------
+
+The Test Pattern Controls are all specific to video capture.
+
+Test Pattern: selects which test pattern to use. Use the CSC Colorbar for
+       testing colorspace conversions: the colors used in that test pattern
+       map to valid colors in all colorspaces. The colorspace conversion
+       is disabled for the other test patterns.
+
+OSD Text Mode: selects whether the text superimposed on the
+       test pattern should be shown, and if so, whether only counters should
+       be displayed or the full text.
+
+Horizontal Movement: selects whether the test pattern should
+       move to the left or right and at what speed.
+
+Vertical Movement: does the same for the vertical direction.
+
+Show Border: show a two-pixel wide border at the edge of the actual image,
+       excluding letter or pillarboxing.
+
+Show Square: show a square in the middle of the image. If the image is
+       displayed with the correct pixel and image aspect ratio corrections,
+       then the width and height of the square on the monitor should be
+       the same.
+
+Insert SAV Code in Image: adds a SAV (Start of Active Video) code to the image.
+       This can be used to check if such codes in the image are inadvertently
+       interpreted instead of being ignored.
+
+Insert EAV Code in Image: does the same for the EAV (End of Active Video) code.
+
+
+Section 9.4.2: Capture Feature Selection Controls
+-------------------------------------------------
+
+These controls are all specific to video capture.
+
+Sensor Flipped Horizontally: the image is flipped horizontally and the
+       V4L2_IN_ST_HFLIP input status flag is set. This emulates the case where
+       a sensor is for example mounted upside down.
+
+Sensor Flipped Vertically: the image is flipped vertically and the
+       V4L2_IN_ST_VFLIP input status flag is set. This emulates the case where
+        a sensor is for example mounted upside down.
+
+Standard Aspect Ratio: selects if the image aspect ratio as used for the TV or
+       S-Video input should be 4x3, 16x9 or anamorphic widescreen. This may
+       introduce letterboxing.
+
+DV Timings Aspect Ratio: selects if the image aspect ratio as used for the HDMI
+       input should be the same as the source width and height ratio, or if
+       it should be 4x3 or 16x9. This may introduce letter or pillarboxing.
+
+Timestamp Source: selects when the timestamp for each buffer is taken.
+
+Colorspace: selects which colorspace should be used when generating the image.
+       This only applies if the CSC Colorbar test pattern is selected,
+       otherwise the test pattern will go through unconverted (except for
+       the so-called 'Transfer Function' corrections and the R'G'B' to Y'CbCr
+       conversion). This behavior is also what you want, since a 75% Colorbar
+       should really have 75% signal intensity and should not be affected
+       by colorspace conversions.
+
+       Changing the colorspace will result in the V4L2_EVENT_SOURCE_CHANGE
+       to be sent since it emulates a detected colorspace change.
+
+Limited RGB Range (16-235): selects if the RGB range of the HDMI source should
+       be limited or full range. This combines with the Digital Video 'Rx RGB
+       Quantization Range' control and can be used to test what happens if
+       a source provides you with the wrong quantization range information.
+       See the description of that control for more details.
+
+Apply Alpha To Red Only: apply the alpha channel as set by the 'Alpha Component'
+       user control to the red color of the test pattern only.
+
+Enable Capture Cropping: enables crop support. This control is only present if
+       the ccs_cap_mode module option is set to the default value of -1 and if
+       the no_error_inj module option is set to 0 (the default).
+
+Enable Capture Composing: enables composing support. This control is only
+       present if the ccs_cap_mode module option is set to the default value of
+       -1 and if the no_error_inj module option is set to 0 (the default).
+
+Enable Capture Scaler: enables support for a scaler (maximum 4 times upscaling
+       and downscaling). This control is only present if the ccs_cap_mode
+       module option is set to the default value of -1 and if the no_error_inj
+       module option is set to 0 (the default).
+
+Maximum EDID Blocks: determines how many EDID blocks the driver supports.
+       Note that the vivid driver does not actually interpret new EDID
+       data, it just stores it. It allows for up to 256 EDID blocks
+       which is the maximum supported by the standard.
+
+Fill Percentage of Frame: can be used to draw only the top X percent
+       of the image. Since each frame has to be drawn by the driver, this
+       demands a lot of the CPU. For large resolutions this becomes
+       problematic. By drawing only part of the image this CPU load can
+       be reduced.
+
+
+Section 9.4.3: Output Feature Selection Controls
+------------------------------------------------
+
+These controls are all specific to video output.
+
+Enable Output Cropping: enables crop support. This control is only present if
+       the ccs_out_mode module option is set to the default value of -1 and if
+       the no_error_inj module option is set to 0 (the default).
+
+Enable Output Composing: enables composing support. This control is only
+       present if the ccs_out_mode module option is set to the default value of
+       -1 and if the no_error_inj module option is set to 0 (the default).
+
+Enable Output Scaler: enables support for a scaler (maximum 4 times upscaling
+       and downscaling). This control is only present if the ccs_out_mode
+       module option is set to the default value of -1 and if the no_error_inj
+       module option is set to 0 (the default).
+
+
+Section 9.4.4: Error Injection Controls
+---------------------------------------
+
+The following two controls are only valid for video and vbi capture.
+
+Standard Signal Mode: selects the behavior of VIDIOC_QUERYSTD: what should
+       it return?
+
+       Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE
+       to be sent since it emulates a changed input condition (e.g. a cable
+       was plugged in or out).
+
+Standard: selects the standard that VIDIOC_QUERYSTD should return if the
+       previous control is set to "Selected Standard".
+
+       Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE
+       to be sent since it emulates a changed input standard.
+
+
+The following two controls are only valid for video capture.
+
+DV Timings Signal Mode: selects the behavior of VIDIOC_QUERY_DV_TIMINGS: what
+       should it return?
+
+       Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE
+       to be sent since it emulates a changed input condition (e.g. a cable
+       was plugged in or out).
+
+DV Timings: selects the timings the VIDIOC_QUERY_DV_TIMINGS should return
+       if the previous control is set to "Selected DV Timings".
+
+       Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE
+       to be sent since it emulates changed input timings.
+
+
+The following controls are only present if the no_error_inj module option
+is set to 0 (the default). These controls are valid for video and vbi
+capture and output streams and for the SDR capture device except for the
+Disconnect control which is valid for all devices.
+
+Wrap Sequence Number: test what happens when you wrap the sequence number in
+       struct v4l2_buffer around.
+
+Wrap Timestamp: test what happens when you wrap the timestamp in struct
+       v4l2_buffer around.
+
+Percentage of Dropped Buffers: sets the percentage of buffers that
+       are never returned by the driver (i.e., they are dropped).
+
+Disconnect: emulates a USB disconnect. The device will act as if it has
+       been disconnected. Only after all open filehandles to the device
+       node have been closed will the device become 'connected' again.
+
+Inject V4L2_BUF_FLAG_ERROR: when pressed, the next frame returned by
+       the driver will have the error flag set (i.e. the frame is marked
+       corrupt).
+
+Inject VIDIOC_REQBUFS Error: when pressed, the next REQBUFS or CREATE_BUFS
+       ioctl call will fail with an error. To be precise: the videobuf2
+       queue_setup() op will return -EINVAL.
+
+Inject VIDIOC_QBUF Error: when pressed, the next VIDIOC_QBUF or
+       VIDIOC_PREPARE_BUFFER ioctl call will fail with an error. To be
+       precise: the videobuf2 buf_prepare() op will return -EINVAL.
+
+Inject VIDIOC_STREAMON Error: when pressed, the next VIDIOC_STREAMON ioctl
+       call will fail with an error. To be precise: the videobuf2
+       start_streaming() op will return -EINVAL.
+
+Inject Fatal Streaming Error: when pressed, the streaming core will be
+       marked as having suffered a fatal error, the only way to recover
+       from that is to stop streaming. To be precise: the videobuf2
+       vb2_queue_error() function is called.
+
+
+Section 9.4.5: VBI Raw Capture Controls
+---------------------------------------
+
+Interlaced VBI Format: if set, then the raw VBI data will be interlaced instead
+       of providing it grouped by field.
+
+
+Section 9.5: Digital Video Controls
+-----------------------------------
+
+Rx RGB Quantization Range: sets the RGB quantization detection of the HDMI
+       input. This combines with the Vivid 'Limited RGB Range (16-235)'
+       control and can be used to test what happens if a source provides
+       you with the wrong quantization range information. This can be tested
+       by selecting an HDMI input, setting this control to Full or Limited
+       range and selecting the opposite in the 'Limited RGB Range (16-235)'
+       control. The effect is easy to see if the 'Gray Ramp' test pattern
+       is selected.
+
+Tx RGB Quantization Range: sets the RGB quantization detection of the HDMI
+       output. It is currently not used for anything in vivid, but most HDMI
+       transmitters would typically have this control.
+
+Transmit Mode: sets the transmit mode of the HDMI output to HDMI or DVI-D. This
+       affects the reported colorspace since DVI_D outputs will always use
+       sRGB.
+
+
+Section 9.6: FM Radio Receiver Controls
+---------------------------------------
+
+RDS Reception: set if the RDS receiver should be enabled.
+
+RDS Program Type:
+RDS PS Name:
+RDS Radio Text:
+RDS Traffic Announcement:
+RDS Traffic Program:
+RDS Music: these are all read-only controls. If RDS Rx I/O Mode is set to
+       "Block I/O", then they are inactive as well. If RDS Rx I/O Mode is set
+       to "Controls", then these controls report the received RDS data. Note
+       that the vivid implementation of this is pretty basic: they are only
+       updated when you set a new frequency or when you get the tuner status
+       (VIDIOC_G_TUNER).
+
+Radio HW Seek Mode: can be one of "Bounded", "Wrap Around" or "Both". This
+       determines if VIDIOC_S_HW_FREQ_SEEK will be bounded by the frequency
+       range or wrap-around or if it is selectable by the user.
+
+Radio Programmable HW Seek: if set, then the user can provide the lower and
+       upper bound of the HW Seek. Otherwise the frequency range boundaries
+       will be used.
+
+Generate RBDS Instead of RDS: if set, then generate RBDS (the US variant of
+       RDS) data instead of RDS (European-style RDS). This affects only the
+       PICODE and PTY codes.
+
+RDS Rx I/O Mode: this can be "Block I/O" where the RDS blocks have to be read()
+       by the application, or "Controls" where the RDS data is provided by
+       the RDS controls mentioned above.
+
+
+Section 9.7: FM Radio Modulator Controls
+----------------------------------------
+
+RDS Program ID:
+RDS Program Type:
+RDS PS Name:
+RDS Radio Text:
+RDS Stereo:
+RDS Artificial Head:
+RDS Compressed:
+RDS Dymanic PTY:
+RDS Traffic Announcement:
+RDS Traffic Program:
+RDS Music: these are all controls that set the RDS data that is transmitted by
+       the FM modulator.
+
+RDS Tx I/O Mode: this can be "Block I/O" where the application has to use write()
+       to pass the RDS blocks to the driver, or "Controls" where the RDS data is
+       provided by the RDS controls mentioned above.
+
+
+Section 10: Video, VBI and RDS Looping
+--------------------------------------
+
+The vivid driver supports looping of video output to video input, VBI output
+to VBI input and RDS output to RDS input. For video/VBI looping this emulates
+as if a cable was hooked up between the output and input connector. So video
+and VBI looping is only supported between S-Video and HDMI inputs and outputs.
+VBI is only valid for S-Video as it makes no sense for HDMI.
+
+Since radio is wireless this looping always happens if the radio receiver
+frequency is close to the radio transmitter frequency. In that case the radio
+transmitter will 'override' the emulated radio stations.
+
+Looping is currently supported only between devices created by the same
+vivid driver instance.
+
+
+Section 10.1: Video and Sliced VBI looping
+------------------------------------------
+
+The way to enable video/VBI looping is currently fairly crude. A 'Loop Video'
+control is available in the "Vivid" control class of the video
+output and VBI output devices. When checked the video looping will be enabled.
+Once enabled any video S-Video or HDMI input will show a static test pattern
+until the video output has started. At that time the video output will be
+looped to the video input provided that:
+
+- the input type matches the output type. So the HDMI input cannot receive
+  video from the S-Video output.
+
+- the video resolution of the video input must match that of the video output.
+  So it is not possible to loop a 50 Hz (720x576) S-Video output to a 60 Hz
+  (720x480) S-Video input, or a 720p60 HDMI output to a 1080p30 input.
+
+- the pixel formats must be identical on both sides. Otherwise the driver would
+  have to do pixel format conversion as well, and that's taking things too far.
+
+- the field settings must be identical on both sides. Same reason as above:
+  requiring the driver to convert from one field format to another complicated
+  matters too much. This also prohibits capturing with 'Field Top' or 'Field
+  Bottom' when the output video is set to 'Field Alternate'. This combination,
+  while legal, became too complicated to support. Both sides have to be 'Field
+  Alternate' for this to work. Also note that for this specific case the
+  sequence and field counting in struct v4l2_buffer on the capture side may not
+  be 100% accurate.
+
+- on the input side the "Standard Signal Mode" for the S-Video input or the
+  "DV Timings Signal Mode" for the HDMI input should be configured so that a
+  valid signal is passed to the video input.
+
+The framerates do not have to match, although this might change in the future.
+
+By default you will see the OSD text superimposed on top of the looped video.
+This can be turned off by changing the "OSD Text Mode" control of the video
+capture device.
+
+For VBI looping to work all of the above must be valid and in addition the vbi
+output must be configured for sliced VBI. The VBI capture side can be configured
+for either raw or sliced VBI. Note that at the moment only CC/XDS (60 Hz formats)
+and WSS (50 Hz formats) VBI data is looped. Teletext VBI data is not looped.
+
+
+Section 10.2: Radio & RDS Looping
+---------------------------------
+
+As mentioned in section 6 the radio receiver emulates stations are regular
+frequency intervals. Depending on the frequency of the radio receiver a
+signal strength value is calculated (this is returned by VIDIOC_G_TUNER).
+However, it will also look at the frequency set by the radio transmitter and
+if that results in a higher signal strength than the settings of the radio
+transmitter will be used as if it was a valid station. This also includes
+the RDS data (if any) that the transmitter 'transmits'. This is received
+faithfully on the receiver side. Note that when the driver is loaded the
+frequencies of the radio receiver and transmitter are not identical, so
+initially no looping takes place.
+
+
+Section 11: Cropping, Composing, Scaling
+----------------------------------------
+
+This driver supports cropping, composing and scaling in any combination. Normally
+which features are supported can be selected through the Vivid controls,
+but it is also possible to hardcode it when the module is loaded through the
+ccs_cap_mode and ccs_out_mode module options. See section 1 on the details of
+these module options.
+
+This allows you to test your application for all these variations.
+
+Note that the webcam input never supports cropping, composing or scaling. That
+only applies to the TV/S-Video/HDMI inputs and outputs. The reason is that
+webcams, including this virtual implementation, normally use
+VIDIOC_ENUM_FRAMESIZES to list a set of discrete framesizes that it supports.
+And that does not combine with cropping, composing or scaling. This is
+primarily a limitation of the V4L2 API which is carefully reproduced here.
+
+The minimum and maximum resolutions that the scaler can achieve are 16x16 and
+(4096 * 4) x (2160 x 4), but it can only scale up or down by a factor of 4 or
+less. So for a source resolution of 1280x720 the minimum the scaler can do is
+320x180 and the maximum is 5120x2880. You can play around with this using the
+qv4l2 test tool and you will see these dependencies.
+
+This driver also supports larger 'bytesperline' settings, something that
+VIDIOC_S_FMT allows but that few drivers implement.
+
+The scaler is a simple scaler that uses the Coarse Bresenham algorithm. It's
+designed for speed and simplicity, not quality.
+
+If the combination of crop, compose and scaling allows it, then it is possible
+to change crop and compose rectangles on the fly.
+
+
+Section 12: Formats
+-------------------
+
+The driver supports all the regular packed YUYV formats, 16, 24 and 32 RGB
+packed formats and two multiplanar formats (one luma and one chroma plane).
+
+The alpha component can be set through the 'Alpha Component' User control
+for those formats that support it. If the 'Apply Alpha To Red Only' control
+is set, then the alpha component is only used for the color red and set to
+0 otherwise.
+
+The driver has to be configured to support the multiplanar formats. By default
+the first driver instance is single-planar, the second is multi-planar, and it
+keeps alternating. This can be changed by setting the multiplanar module option,
+see section 1 for more details on that option.
+
+If the driver instance is using the multiplanar formats/API, then the first
+single planar format (YUYV) and the multiplanar NV16M and NV61M formats the
+will have a plane that has a non-zero data_offset of 128 bytes. It is rare for
+data_offset to be non-zero, so this is a useful feature for testing applications.
+
+Video output will also honor any data_offset that the application set.
+
+
+Section 13: Capture Overlay
+---------------------------
+
+Note: capture overlay support is implemented primarily to test the existing
+V4L2 capture overlay API. In practice few if any GPUs support such overlays
+anymore, and neither are they generally needed anymore since modern hardware
+is so much more capable. By setting flag 0x10000 in the node_types module
+option the vivid driver will create a simple framebuffer device that can be
+used for testing this API. Whether this API should be used for new drivers is
+questionable.
+
+This driver has support for a destructive capture overlay with bitmap clipping
+and list clipping (up to 16 rectangles) capabilities. Overlays are not
+supported for multiplanar formats. It also honors the struct v4l2_window field
+setting: if it is set to FIELD_TOP or FIELD_BOTTOM and the capture setting is
+FIELD_ALTERNATE, then only the top or bottom fields will be copied to the overlay.
+
+The overlay only works if you are also capturing at that same time. This is a
+vivid limitation since it copies from a buffer to the overlay instead of
+filling the overlay directly. And if you are not capturing, then no buffers
+are available to fill.
+
+In addition, the pixelformat of the capture format and that of the framebuffer
+must be the same for the overlay to work. Otherwise VIDIOC_OVERLAY will return
+an error.
+
+In order to really see what it going on you will need to create two vivid
+instances: the first with a framebuffer enabled. You configure the capture
+overlay of the second instance to use the framebuffer of the first, then
+you start capturing in the second instance. For the first instance you setup
+the output overlay for the video output, turn on video looping and capture
+to see the blended framebuffer overlay that's being written to by the second
+instance. This setup would require the following commands:
+
+       $ sudo modprobe vivid n_devs=2 node_types=0x10101,0x1 multiplanar=1,1
+       $ v4l2-ctl -d1 --find-fb
+       /dev/fb1 is the framebuffer associated with base address 0x12800000
+       $ sudo v4l2-ctl -d2 --set-fbuf fb=1
+       $ v4l2-ctl -d1 --set-fbuf fb=1
+       $ v4l2-ctl -d0 --set-fmt-video=pixelformat='AR15'
+       $ v4l2-ctl -d1 --set-fmt-video-out=pixelformat='AR15'
+       $ v4l2-ctl -d2 --set-fmt-video=pixelformat='AR15'
+       $ v4l2-ctl -d0 -i2
+       $ v4l2-ctl -d2 -i2
+       $ v4l2-ctl -d2 -c horizontal_movement=4
+       $ v4l2-ctl -d1 --overlay=1
+       $ v4l2-ctl -d1 -c loop_video=1
+       $ v4l2-ctl -d2 --stream-mmap --overlay=1
+
+And from another console:
+
+       $ v4l2-ctl -d1 --stream-out-mmap
+
+And yet another console:
+
+       $ qv4l2
+
+and start streaming.
+
+As you can see, this is not for the faint of heart...
+
+
+Section 14: Output Overlay
+--------------------------
+
+Note: output overlays are primarily implemented in order to test the existing
+V4L2 output overlay API. Whether this API should be used for new drivers is
+questionable.
+
+This driver has support for an output overlay and is capable of:
+
+       - bitmap clipping,
+       - list clipping (up to 16 rectangles)
+       - chromakey
+       - source chromakey
+       - global alpha
+       - local alpha
+       - local inverse alpha
+
+Output overlays are not supported for multiplanar formats. In addition, the
+pixelformat of the capture format and that of the framebuffer must be the
+same for the overlay to work. Otherwise VIDIOC_OVERLAY will return an error.
+
+Output overlays only work if the driver has been configured to create a
+framebuffer by setting flag 0x10000 in the node_types module option. The
+created framebuffer has a size of 720x576 and supports ARGB 1:5:5:5 and
+RGB 5:6:5.
+
+In order to see the effects of the various clipping, chromakeying or alpha
+processing capabilities you need to turn on video looping and see the results
+on the capture side. The use of the clipping, chromakeying or alpha processing
+capabilities will slow down the video loop considerably as a lot of checks have
+to be done per pixel.
+
+
+Section 15: Some Future Improvements
+------------------------------------
+
+Just as a reminder and in no particular order:
+
+- Add a virtual alsa driver to test audio
+- Add virtual sub-devices and media controller support
+- Some support for testing compressed video
+- Add support to loop raw VBI output to raw VBI input
+- Add support to loop teletext sliced VBI output to VBI input
+- Fix sequence/field numbering when looping of video with alternate fields
+- Add support for V4L2_CID_BG_COLOR for video outputs
+- Add ARGB888 overlay support: better testing of the alpha channel
+- Add custom DV timings support
+- Add support for V4L2_DV_FL_REDUCED_FPS
+- Improve pixel aspect support in the tpg code by passing a real v4l2_fract
+- Use per-queue locks and/or per-device locks to improve throughput
+- Add support to loop from a specific output to a specific input across
+  vivid instances
+- Add support for VIDIOC_EXPBUF once support for that has been added to vb2
+- The SDR radio should use the same 'frequencies' for stations as the normal
+  radio receiver, and give back noise if the frequency doesn't match up with
+  a station frequency
+- Improve the sine generation of the SDR radio.
+- Make a thread for the RDS generation, that would help in particular for the
+  "Controls" RDS Rx I/O Mode as the read-only RDS controls could be updated
+  in real-time.
index 8b0902106cc0809454adb9e788902119933cd28b..2cddff1dd43942b9d0c58b0c8418b9f7d1dcc4ee 100644 (file)
@@ -4233,6 +4233,16 @@ L:       linuxppc-dev@lists.ozlabs.org
 S:     Odd Fixes
 F:     drivers/tty/hvc/
 
+HACKRF MEDIA DRIVER
+M:     Antti Palosaari <crope@iki.fi>
+L:     linux-media@vger.kernel.org
+W:     http://linuxtv.org/
+W:     http://palosaari.fi/linux/
+Q:     http://patchwork.linuxtv.org/project/linux-media/list/
+T:     git git://linuxtv.org/anttip/media_tree.git
+S:     Maintained
+F:     drivers/media/usb/hackrf/
+
 HARDWARE MONITORING
 M:     Jean Delvare <jdelvare@suse.de>
 M:     Guenter Roeck <linux@roeck-us.net>
@@ -5131,7 +5141,7 @@ W:        http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
 S:     Maintained
-F:     drivers/media/tuners/tuner_it913x*
+F:     drivers/media/tuners/it913x*
 
 IVTV VIDEO4LINUX DRIVER
 M:     Andy Walls <awalls@md.metrocast.net>
@@ -8672,6 +8682,14 @@ F:       include/sound/dmaengine_pcm.h
 F:     sound/core/pcm_dmaengine.c
 F:     sound/soc/soc-generic-dmaengine-pcm.c
 
+SP2 MEDIA DRIVER
+M:     Olli Salonen <olli.salonen@iki.fi>
+L:     linux-media@vger.kernel.org
+W:     http://linuxtv.org/
+Q:     http://patchwork.linuxtv.org/project/linux-media/list/
+S:     Maintained
+F:     drivers/media/dvb-frontends/sp2*
+
 SPARC + UltraSPARC (sparc/sparc64)
 M:     "David S. Miller" <davem@davemloft.net>
 L:     sparclinux@vger.kernel.org
@@ -9375,6 +9393,14 @@ T:       git git://linuxtv.org/media_tree.git
 S:     Odd fixes
 F:     drivers/media/usb/tm6000/
 
+TW68 VIDEO4LINUX DRIVER
+M:     Hans Verkuil <hverkuil@xs4all.nl>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+W:     http://linuxtv.org
+S:     Odd Fixes
+F:     drivers/media/pci/tw68/
+
 TPM DEVICE DRIVER
 M:     Peter Huewe <peterhuewe@gmx.de>
 M:     Ashley Lai <ashley@ashleylai.com>
index 897b10c85ad9273b75b9cb911b2f0c2853b9a167..8942bdacbf61befba5640d845d95d00e566cbc42 100644 (file)
@@ -4,7 +4,7 @@
  * see flexcop.c for copyright information
  */
 #ifndef __FLEXCOP_H__
-#define __FLEXCOP_H___
+#define __FLEXCOP_H__
 
 #define FC_LOG_PREFIX "b2c2-flexcop"
 #include "flexcop-common.h"
index 6c47f3fe9b0fc2ba2f8eb9263a2f0e9d0396d870..b7d63933dae61a6adbac2d95edfe1bb19c6aacf1 100644 (file)
@@ -311,7 +311,6 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
                }
        default:
                BUG();
-               return 0;
        }
 
        if (mutex_lock_interruptible(vdev->lock))
@@ -399,7 +398,6 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
                return -EINVAL;
        default:
                BUG();
-               return 0;
        }
 }
 
@@ -423,7 +421,6 @@ static ssize_t fops_write(struct file *file, const char __user *data, size_t cou
                return -EINVAL;
        default:
                BUG();
-               return -EINVAL;
        }
 }
 
index 82769993eeb7b390cc5441cffc9bf5096b6411a9..82c7a1289f053313bb7f866bb08a9288e2a67db6 100644 (file)
@@ -157,6 +157,12 @@ static struct sms_board sms_boards[] = {
                .type = SMS_DENVER_2160,
                .default_mode = DEVICE_MODE_DAB_TDMB,
        },
+       [SMS1XXX_BOARD_PCTV_77E] = {
+               .name   = "Hauppauge microStick 77e",
+               .type   = SMS_NOVA_B0,
+               .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ_B0,
+               .default_mode = DEVICE_MODE_DVBT_BDA,
+       },
 };
 
 struct sms_board *sms_get_board(unsigned id)
index c63b544c49c5b721769131d8065f044eebd76e91..4c4caddf986984e2aa94ce2da8bf7f1229718767 100644 (file)
@@ -45,6 +45,7 @@
 #define SMS1XXX_BOARD_SIANO_RIO                18
 #define SMS1XXX_BOARD_SIANO_DENVER_1530        19
 #define SMS1XXX_BOARD_SIANO_DENVER_2160 20
+#define SMS1XXX_BOARD_PCTV_77E         21
 
 struct sms_board_gpio_cfg {
        int lna_vhf_exist;
index 050984c5b1e3701aa00ea0d074bca9700754d9d3..a3677438205e8c88824e6f10f854168755725da9 100644 (file)
@@ -2129,8 +2129,6 @@ int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num,
 
 static int __init smscore_module_init(void)
 {
-       int rc = 0;
-
        INIT_LIST_HEAD(&g_smscore_notifyees);
        INIT_LIST_HEAD(&g_smscore_devices);
        kmutex_init(&g_smscore_deviceslock);
@@ -2138,7 +2136,7 @@ static int __init smscore_module_init(void)
        INIT_LIST_HEAD(&g_smscore_registry);
        kmutex_init(&g_smscore_registrylock);
 
-       return rc;
+       return 0;
 }
 
 static void __exit smscore_module_exit(void)
index c0363f1b6c90e06c34409766e4a69c56fb98164f..abff803ad69a7e9e55818e5fd42d04ff475cd2d5 100644 (file)
@@ -1087,8 +1087,8 @@ static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
        struct dmxdev_filter *dmxdevfilter = file->private_data;
        unsigned int mask = 0;
 
-       if (!dmxdevfilter)
-               return -EINVAL;
+       if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
+               return POLLERR;
 
        poll_wait(file, &dmxdevfilter->buffer.queue, wait);
 
@@ -1181,6 +1181,9 @@ static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
 
        dprintk("function : %s\n", __func__);
 
+       if (dmxdev->exit)
+               return POLLERR;
+
        poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
 
        if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
index 12ce19c98ded144bc37da6d7498edb5381b0d5ee..e07a84e7bc56d494ac795895b1b0a2ca4682bb2d 100644 (file)
 #define USB_PID_ITETECH_IT9135                         0x9135
 #define USB_PID_ITETECH_IT9135_9005                    0x9005
 #define USB_PID_ITETECH_IT9135_9006                    0x9006
+#define USB_PID_ITETECH_IT9303                         0x9306
 #define USB_PID_KWORLD_399U                            0xe399
 #define USB_PID_KWORLD_399U_2                          0xe400
 #define USB_PID_KWORLD_395U                            0xe396
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM     0x3009
 #define USB_PID_TECHNOTREND_CONNECT_CT3650             0x300d
+#define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI                0x3012
 #define USB_PID_TECHNOTREND_TVSTICK_CT2_4400           0x3014
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY       0x005a
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2     0x0081
index c2a6a0a858130b4db284ca845134656afcffc2f0..b8579ee68bd603567fa8a8827b279683f00a7928 100644 (file)
@@ -1934,15 +1934,13 @@ static int dvb_frontend_ioctl_properties(struct file *file,
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int err = 0;
 
-       struct dtv_properties *tvps = NULL;
+       struct dtv_properties *tvps = parg;
        struct dtv_property *tvp = NULL;
        int i;
 
        dev_dbg(fe->dvb->device, "%s:\n", __func__);
 
-       if(cmd == FE_SET_PROPERTY) {
-               tvps = (struct dtv_properties __user *)parg;
-
+       if (cmd == FE_SET_PROPERTY) {
                dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
                dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
 
@@ -1957,7 +1955,8 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                        goto out;
                }
 
-               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+               if (copy_from_user(tvp, (void __user *)tvps->props,
+                                  tvps->num * sizeof(struct dtv_property))) {
                        err = -EFAULT;
                        goto out;
                }
@@ -1972,10 +1971,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                if (c->state == DTV_TUNE)
                        dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__);
 
-       } else
-       if(cmd == FE_GET_PROPERTY) {
-               tvps = (struct dtv_properties __user *)parg;
-
+       } else if (cmd == FE_GET_PROPERTY) {
                dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
                dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
 
@@ -1990,7 +1986,8 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                        goto out;
                }
 
-               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+               if (copy_from_user(tvp, (void __user *)tvps->props,
+                                  tvps->num * sizeof(struct dtv_property))) {
                        err = -EFAULT;
                        goto out;
                }
@@ -2012,7 +2009,8 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                        (tvp + i)->result = err;
                }
 
-               if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+               if (copy_to_user((void __user *)tvps->props, tvp,
+                                tvps->num * sizeof(struct dtv_property))) {
                        err = -EFAULT;
                        goto out;
                }
@@ -2072,6 +2070,23 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
        case SYS_DVBC_ANNEX_C:
                rolloff = 113;
                break;
+       case SYS_DVBS:
+       case SYS_TURBO:
+               rolloff = 135;
+               break;
+       case SYS_DVBS2:
+               switch (c->rolloff) {
+               case ROLLOFF_20:
+                       rolloff = 120;
+                       break;
+               case ROLLOFF_25:
+                       rolloff = 125;
+                       break;
+               default:
+               case ROLLOFF_35:
+                       rolloff = 135;
+               }
+               break;
        default:
                break;
        }
@@ -2550,7 +2565,9 @@ int dvb_frontend_suspend(struct dvb_frontend *fe)
        dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
                        fe->id);
 
-       if (fe->ops.tuner_ops.sleep)
+       if (fe->ops.tuner_ops.suspend)
+               ret = fe->ops.tuner_ops.suspend(fe);
+       else if (fe->ops.tuner_ops.sleep)
                ret = fe->ops.tuner_ops.sleep(fe);
 
        if (fe->ops.sleep)
@@ -2572,7 +2589,9 @@ int dvb_frontend_resume(struct dvb_frontend *fe)
        if (fe->ops.init)
                ret = fe->ops.init(fe);
 
-       if (fe->ops.tuner_ops.init)
+       if (fe->ops.tuner_ops.resume)
+               ret = fe->ops.tuner_ops.resume(fe);
+       else if (fe->ops.tuner_ops.init)
                ret = fe->ops.tuner_ops.init(fe);
 
        fe->exit = DVB_FE_NO_EXIT;
index d398de4b6ef468cb7639ed8ce649ea0c4869291c..816269e5f7068b639a852651f4ad16817aea80a1 100644 (file)
@@ -201,6 +201,8 @@ struct dvb_tuner_ops {
        int (*release)(struct dvb_frontend *fe);
        int (*init)(struct dvb_frontend *fe);
        int (*sleep)(struct dvb_frontend *fe);
+       int (*suspend)(struct dvb_frontend *fe);
+       int (*resume)(struct dvb_frontend *fe);
 
        /** This is for simple PLLs - set all parameters in one go. */
        int (*set_params)(struct dvb_frontend *fe);
index a5712cd7c65ff084845cc86599d63f802ac81722..1100e98a7b1d36eaefe4440767d823d49d1ebf3b 100644 (file)
@@ -166,6 +166,31 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t
        return len;
 }
 
+ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
+                                 const u8 __user *buf, size_t len)
+{
+       int status;
+       size_t todo = len;
+       size_t split;
+
+       split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
+
+       if (split > 0) {
+               status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split);
+               if (status)
+                       return len - todo;
+               buf += split;
+               todo -= split;
+               rbuf->pwrite = 0;
+       }
+       status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo);
+       if (status)
+               return len - todo;
+       rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
+
+       return len;
+}
+
 ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
 {
        int status;
@@ -297,3 +322,4 @@ EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
 EXPORT_SYMBOL(dvb_ringbuffer_read_user);
 EXPORT_SYMBOL(dvb_ringbuffer_read);
 EXPORT_SYMBOL(dvb_ringbuffer_write);
+EXPORT_SYMBOL(dvb_ringbuffer_write_user);
index 41f04dae69b618badd91e783a1ad463b6bd0a393..9e1e11b7c39cb24113084234537cdf4c82254002 100644 (file)
@@ -133,6 +133,8 @@ extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
 */
 extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
                                    size_t len);
+extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
+                                        const u8 __user *buf, size_t len);
 
 
 /**
index fe0ddcca192c0f33f0bb7c3224bf0954b9fb5a35..5a134547e32579c3c6c59668c90986599982e82f 100644 (file)
@@ -471,6 +471,11 @@ config DVB_SI2168
        help
          Say Y when you want to support this frontend.
 
+config DVB_AS102_FE
+       tristate
+       depends on DVB_CORE
+       default DVB_AS102
+
 comment "DVB-C (cable) frontends"
        depends on DVB_CORE
 
@@ -643,6 +648,14 @@ config DVB_MB86A20S
          A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
          Say Y when you want to support this frontend.
 
+config DVB_TC90522
+       tristate "Toshiba TC90522"
+       depends on DVB_CORE && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         A Toshiba TC90522 2xISDB-T + 2xISDB-S demodulator.
+         Say Y when you want to support this frontend.
+
 comment "Digital terrestrial only tuners/PLL"
        depends on DVB_CORE
 
@@ -720,6 +733,13 @@ config DVB_A8293
        depends on DVB_CORE && I2C
        default m if !MEDIA_SUBDRV_AUTOSELECT
 
+config DVB_SP2
+       tristate "CIMaX SP2"
+       depends on DVB_CORE && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         CIMaX SP2/SP2HF Common Interface module.
+
 config DVB_LGS8GL5
        tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
        depends on DVB_CORE && I2C
index edf103d45920238df61e41917fb64126f9983eb1..ba59df63d05082062ca03bb2f4ca6ffe2418e7b0 100644 (file)
@@ -107,10 +107,12 @@ obj-$(CONFIG_DVB_DRXK) += drxk.o
 obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
 obj-$(CONFIG_DVB_SI2165) += si2165.o
 obj-$(CONFIG_DVB_A8293) += a8293.o
+obj-$(CONFIG_DVB_SP2) += sp2.o
 obj-$(CONFIG_DVB_TDA10071) += tda10071.o
 obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
 obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
 obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o
 obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
 obj-$(CONFIG_DVB_AF9033) += af9033.o
-
+obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o
+obj-$(CONFIG_DVB_TC90522) += tc90522.o
index ecf6388d2200608bd5d4f5327d7349e55a0ad6ed..8001690d7576c21579db9f0a8ac08846a5981328 100644 (file)
@@ -683,7 +683,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
 
        switch (c->transmission_mode) {
        case TRANSMISSION_MODE_AUTO:
-               auto_mode = 1;
+               auto_mode = true;
                break;
        case TRANSMISSION_MODE_2K:
                break;
@@ -693,12 +693,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
        default:
                dev_dbg(&state->i2c->dev, "%s: invalid transmission_mode\n",
                                __func__);
-               auto_mode = 1;
+               auto_mode = true;
        }
 
        switch (c->guard_interval) {
        case GUARD_INTERVAL_AUTO:
-               auto_mode = 1;
+               auto_mode = true;
                break;
        case GUARD_INTERVAL_1_32:
                break;
@@ -714,12 +714,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
        default:
                dev_dbg(&state->i2c->dev, "%s: invalid guard_interval\n",
                                __func__);
-               auto_mode = 1;
+               auto_mode = true;
        }
 
        switch (c->hierarchy) {
        case HIERARCHY_AUTO:
-               auto_mode = 1;
+               auto_mode = true;
                break;
        case HIERARCHY_NONE:
                break;
@@ -734,12 +734,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
                break;
        default:
                dev_dbg(&state->i2c->dev, "%s: invalid hierarchy\n", __func__);
-               auto_mode = 1;
+               auto_mode = true;
        }
 
        switch (c->modulation) {
        case QAM_AUTO:
-               auto_mode = 1;
+               auto_mode = true;
                break;
        case QPSK:
                break;
@@ -751,7 +751,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
                break;
        default:
                dev_dbg(&state->i2c->dev, "%s: invalid modulation\n", __func__);
-               auto_mode = 1;
+               auto_mode = true;
        }
 
        /* Use HP. How and which case we can switch to LP? */
@@ -759,7 +759,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
 
        switch (c->code_rate_HP) {
        case FEC_AUTO:
-               auto_mode = 1;
+               auto_mode = true;
                break;
        case FEC_1_2:
                break;
@@ -778,12 +778,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
        default:
                dev_dbg(&state->i2c->dev, "%s: invalid code_rate_HP\n",
                                __func__);
-               auto_mode = 1;
+               auto_mode = true;
        }
 
        switch (c->code_rate_LP) {
        case FEC_AUTO:
-               auto_mode = 1;
+               auto_mode = true;
                break;
        case FEC_1_2:
                break;
@@ -804,7 +804,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
        default:
                dev_dbg(&state->i2c->dev, "%s: invalid code_rate_LP\n",
                                __func__);
-               auto_mode = 1;
+               auto_mode = true;
        }
 
        switch (c->bandwidth_hz) {
index 5c90ea683a7e732d3431c8973e43b4ffea649c55..63a89c1c59ff7454293f24604fecbe562cf3cabe 100644 (file)
 /* Max transfer size done by I2C transfer functions */
 #define MAX_XFER_SIZE  64
 
-struct af9033_state {
-       struct i2c_adapter *i2c;
+struct af9033_dev {
+       struct i2c_client *client;
        struct dvb_frontend fe;
        struct af9033_config cfg;
+       bool is_af9035;
+       bool is_it9135;
 
        u32 bandwidth_hz;
        bool ts_mode_parallel;
        bool ts_mode_serial;
 
-       u32 ber;
-       u32 ucb;
-       unsigned long last_stat_check;
+       fe_status_t fe_status;
+       u64 post_bit_error_prev; /* for old read_ber we return (curr - prev) */
+       u64 post_bit_error;
+       u64 post_bit_count;
+       u64 error_block_count;
+       u64 total_block_count;
+       struct delayed_work stat_work;
 };
 
 /* write multiple registers */
-static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
+static int af9033_wr_regs(struct af9033_dev *dev, u32 reg, const u8 *val,
                int len)
 {
        int ret;
        u8 buf[MAX_XFER_SIZE];
        struct i2c_msg msg[1] = {
                {
-                       .addr = state->cfg.i2c_addr,
+                       .addr = dev->client->addr,
                        .flags = 0,
                        .len = 3 + len,
                        .buf = buf,
@@ -54,9 +60,9 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
        };
 
        if (3 + len > sizeof(buf)) {
-               dev_warn(&state->i2c->dev,
-                        "%s: i2c wr reg=%04x: len=%d is too big!\n",
-                        KBUILD_MODNAME, reg, len);
+               dev_warn(&dev->client->dev,
+                               "i2c wr reg=%04x: len=%d is too big!\n",
+                               reg, len);
                return -EINVAL;
        }
 
@@ -65,12 +71,12 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
        buf[2] = (reg >>  0) & 0xff;
        memcpy(&buf[3], val, len);
 
-       ret = i2c_transfer(state->i2c, msg, 1);
+       ret = i2c_transfer(dev->client->adapter, msg, 1);
        if (ret == 1) {
                ret = 0;
        } else {
-               dev_warn(&state->i2c->dev, "%s: i2c wr failed=%d reg=%06x " \
-                               "len=%d\n", KBUILD_MODNAME, ret, reg, len);
+               dev_warn(&dev->client->dev, "i2c wr failed=%d reg=%06x len=%d\n",
+                               ret, reg, len);
                ret = -EREMOTEIO;
        }
 
@@ -78,31 +84,31 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
 }
 
 /* read multiple registers */
-static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len)
+static int af9033_rd_regs(struct af9033_dev *dev, u32 reg, u8 *val, int len)
 {
        int ret;
        u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff,
                        (reg >> 0) & 0xff };
        struct i2c_msg msg[2] = {
                {
-                       .addr = state->cfg.i2c_addr,
+                       .addr = dev->client->addr,
                        .flags = 0,
                        .len = sizeof(buf),
                        .buf = buf
                }, {
-                       .addr = state->cfg.i2c_addr,
+                       .addr = dev->client->addr,
                        .flags = I2C_M_RD,
                        .len = len,
                        .buf = val
                }
        };
 
-       ret = i2c_transfer(state->i2c, msg, 2);
+       ret = i2c_transfer(dev->client->adapter, msg, 2);
        if (ret == 2) {
                ret = 0;
        } else {
-               dev_warn(&state->i2c->dev, "%s: i2c rd failed=%d reg=%06x " \
-                               "len=%d\n", KBUILD_MODNAME, ret, reg, len);
+               dev_warn(&dev->client->dev, "i2c rd failed=%d reg=%06x len=%d\n",
+                               ret, reg, len);
                ret = -EREMOTEIO;
        }
 
@@ -111,19 +117,19 @@ static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len)
 
 
 /* write single register */
-static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val)
+static int af9033_wr_reg(struct af9033_dev *dev, u32 reg, u8 val)
 {
-       return af9033_wr_regs(state, reg, &val, 1);
+       return af9033_wr_regs(dev, reg, &val, 1);
 }
 
 /* read single register */
-static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val)
+static int af9033_rd_reg(struct af9033_dev *dev, u32 reg, u8 *val)
 {
-       return af9033_rd_regs(state, reg, val, 1);
+       return af9033_rd_regs(dev, reg, val, 1);
 }
 
 /* write single register with mask */
-static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val,
+static int af9033_wr_reg_mask(struct af9033_dev *dev, u32 reg, u8 val,
                u8 mask)
 {
        int ret;
@@ -131,7 +137,7 @@ static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val,
 
        /* no need for read if whole reg is written */
        if (mask != 0xff) {
-               ret = af9033_rd_regs(state, reg, &tmp, 1);
+               ret = af9033_rd_regs(dev, reg, &tmp, 1);
                if (ret)
                        return ret;
 
@@ -140,17 +146,17 @@ static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val,
                val |= tmp;
        }
 
-       return af9033_wr_regs(state, reg, &val, 1);
+       return af9033_wr_regs(dev, reg, &val, 1);
 }
 
 /* read single register with mask */
-static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val,
+static int af9033_rd_reg_mask(struct af9033_dev *dev, u32 reg, u8 *val,
                u8 mask)
 {
        int ret, i;
        u8 tmp;
 
-       ret = af9033_rd_regs(state, reg, &tmp, 1);
+       ret = af9033_rd_regs(dev, reg, &tmp, 1);
        if (ret)
                return ret;
 
@@ -167,18 +173,17 @@ static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val,
 }
 
 /* write reg val table using reg addr auto increment */
-static int af9033_wr_reg_val_tab(struct af9033_state *state,
+static int af9033_wr_reg_val_tab(struct af9033_dev *dev,
                const struct reg_val *tab, int tab_len)
 {
 #define MAX_TAB_LEN 212
        int ret, i, j;
        u8 buf[1 + MAX_TAB_LEN];
 
-       dev_dbg(&state->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len);
+       dev_dbg(&dev->client->dev, "tab_len=%d\n", tab_len);
 
        if (tab_len > sizeof(buf)) {
-               dev_warn(&state->i2c->dev, "%s: tab len %d is too big\n",
-                               KBUILD_MODNAME, tab_len);
+               dev_warn(&dev->client->dev, "tab len %d is too big\n", tab_len);
                return -EINVAL;
        }
 
@@ -186,7 +191,7 @@ static int af9033_wr_reg_val_tab(struct af9033_state *state,
                buf[j] = tab[i].val;
 
                if (i == tab_len - 1 || tab[i].reg != tab[i + 1].reg - 1) {
-                       ret = af9033_wr_regs(state, tab[i].reg - j, buf, j + 1);
+                       ret = af9033_wr_regs(dev, tab[i].reg - j, buf, j + 1);
                        if (ret < 0)
                                goto err;
 
@@ -199,16 +204,16 @@ static int af9033_wr_reg_val_tab(struct af9033_state *state,
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
-static u32 af9033_div(struct af9033_state *state, u32 a, u32 b, u32 x)
+static u32 af9033_div(struct af9033_dev *dev, u32 a, u32 b, u32 x)
 {
        u32 r = 0, c = 0, i;
 
-       dev_dbg(&state->i2c->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x);
+       dev_dbg(&dev->client->dev, "a=%d b=%d x=%d\n", a, b, x);
 
        if (a > b) {
                c = a / b;
@@ -225,22 +230,15 @@ static u32 af9033_div(struct af9033_state *state, u32 a, u32 b, u32 x)
        }
        r = (c << (u32)x) + r;
 
-       dev_dbg(&state->i2c->dev, "%s: a=%d b=%d x=%d r=%d r=%x\n",
-                       __func__, a, b, x, r, r);
+       dev_dbg(&dev->client->dev, "a=%d b=%d x=%d r=%d r=%x\n", a, b, x, r, r);
 
        return r;
 }
 
-static void af9033_release(struct dvb_frontend *fe)
-{
-       struct af9033_state *state = fe->demodulator_priv;
-
-       kfree(state);
-}
-
 static int af9033_init(struct dvb_frontend *fe)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret, i, len;
        const struct reg_val *init;
        u8 buf[4];
@@ -248,7 +246,7 @@ static int af9033_init(struct dvb_frontend *fe)
        struct reg_val_mask tab[] = {
                { 0x80fb24, 0x00, 0x08 },
                { 0x80004c, 0x00, 0xff },
-               { 0x00f641, state->cfg.tuner, 0xff },
+               { 0x00f641, dev->cfg.tuner, 0xff },
                { 0x80f5ca, 0x01, 0x01 },
                { 0x80f715, 0x01, 0x01 },
                { 0x00f41f, 0x04, 0x04 },
@@ -267,88 +265,82 @@ static int af9033_init(struct dvb_frontend *fe)
                { 0x00d830, 0x01, 0xff },
                { 0x00d831, 0x00, 0xff },
                { 0x00d832, 0x00, 0xff },
-               { 0x80f985, state->ts_mode_serial, 0x01 },
-               { 0x80f986, state->ts_mode_parallel, 0x01 },
+               { 0x80f985, dev->ts_mode_serial, 0x01 },
+               { 0x80f986, dev->ts_mode_parallel, 0x01 },
                { 0x00d827, 0x00, 0xff },
                { 0x00d829, 0x00, 0xff },
-               { 0x800045, state->cfg.adc_multiplier, 0xff },
+               { 0x800045, dev->cfg.adc_multiplier, 0xff },
        };
 
        /* program clock control */
-       clock_cw = af9033_div(state, state->cfg.clock, 1000000ul, 19ul);
+       clock_cw = af9033_div(dev, dev->cfg.clock, 1000000ul, 19ul);
        buf[0] = (clock_cw >>  0) & 0xff;
        buf[1] = (clock_cw >>  8) & 0xff;
        buf[2] = (clock_cw >> 16) & 0xff;
        buf[3] = (clock_cw >> 24) & 0xff;
 
-       dev_dbg(&state->i2c->dev, "%s: clock=%d clock_cw=%08x\n",
-                       __func__, state->cfg.clock, clock_cw);
+       dev_dbg(&dev->client->dev, "clock=%d clock_cw=%08x\n",
+                       dev->cfg.clock, clock_cw);
 
-       ret = af9033_wr_regs(state, 0x800025, buf, 4);
+       ret = af9033_wr_regs(dev, 0x800025, buf, 4);
        if (ret < 0)
                goto err;
 
        /* program ADC control */
        for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
-               if (clock_adc_lut[i].clock == state->cfg.clock)
+               if (clock_adc_lut[i].clock == dev->cfg.clock)
                        break;
        }
 
-       adc_cw = af9033_div(state, clock_adc_lut[i].adc, 1000000ul, 19ul);
+       adc_cw = af9033_div(dev, clock_adc_lut[i].adc, 1000000ul, 19ul);
        buf[0] = (adc_cw >>  0) & 0xff;
        buf[1] = (adc_cw >>  8) & 0xff;
        buf[2] = (adc_cw >> 16) & 0xff;
 
-       dev_dbg(&state->i2c->dev, "%s: adc=%d adc_cw=%06x\n",
-                       __func__, clock_adc_lut[i].adc, adc_cw);
+       dev_dbg(&dev->client->dev, "adc=%d adc_cw=%06x\n",
+                       clock_adc_lut[i].adc, adc_cw);
 
-       ret = af9033_wr_regs(state, 0x80f1cd, buf, 3);
+       ret = af9033_wr_regs(dev, 0x80f1cd, buf, 3);
        if (ret < 0)
                goto err;
 
        /* program register table */
        for (i = 0; i < ARRAY_SIZE(tab); i++) {
-               ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val,
+               ret = af9033_wr_reg_mask(dev, tab[i].reg, tab[i].val,
                                tab[i].mask);
                if (ret < 0)
                        goto err;
        }
 
-       /* feed clock to RF tuner */
-       switch (state->cfg.tuner) {
-       case AF9033_TUNER_IT9135_38:
-       case AF9033_TUNER_IT9135_51:
-       case AF9033_TUNER_IT9135_52:
-       case AF9033_TUNER_IT9135_60:
-       case AF9033_TUNER_IT9135_61:
-       case AF9033_TUNER_IT9135_62:
-               ret = af9033_wr_reg(state, 0x80fba8, 0x00);
+       /* clock output */
+       if (dev->cfg.dyn0_clk) {
+               ret = af9033_wr_reg(dev, 0x80fba8, 0x00);
                if (ret < 0)
                        goto err;
        }
 
        /* settings for TS interface */
-       if (state->cfg.ts_mode == AF9033_TS_MODE_USB) {
-               ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01);
+       if (dev->cfg.ts_mode == AF9033_TS_MODE_USB) {
+               ret = af9033_wr_reg_mask(dev, 0x80f9a5, 0x00, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x80f9b5, 0x01, 0x01);
                if (ret < 0)
                        goto err;
        } else {
-               ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x80f990, 0x00, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x80f9b5, 0x00, 0x01);
                if (ret < 0)
                        goto err;
        }
 
        /* load OFSM settings */
-       dev_dbg(&state->i2c->dev, "%s: load ofsm settings\n", __func__);
-       switch (state->cfg.tuner) {
+       dev_dbg(&dev->client->dev, "load ofsm settings\n");
+       switch (dev->cfg.tuner) {
        case AF9033_TUNER_IT9135_38:
        case AF9033_TUNER_IT9135_51:
        case AF9033_TUNER_IT9135_52:
@@ -367,14 +359,13 @@ static int af9033_init(struct dvb_frontend *fe)
                break;
        }
 
-       ret = af9033_wr_reg_val_tab(state, init, len);
+       ret = af9033_wr_reg_val_tab(dev, init, len);
        if (ret < 0)
                goto err;
 
        /* load tuner specific settings */
-       dev_dbg(&state->i2c->dev, "%s: load tuner specific settings\n",
-                       __func__);
-       switch (state->cfg.tuner) {
+       dev_dbg(&dev->client->dev, "load tuner specific settings\n");
+       switch (dev->cfg.tuner) {
        case AF9033_TUNER_TUA9001:
                len = ARRAY_SIZE(tuner_init_tua9001);
                init = tuner_init_tua9001;
@@ -424,90 +415,108 @@ static int af9033_init(struct dvb_frontend *fe)
                init = tuner_init_it9135_62;
                break;
        default:
-               dev_dbg(&state->i2c->dev, "%s: unsupported tuner ID=%d\n",
-                               __func__, state->cfg.tuner);
+               dev_dbg(&dev->client->dev, "unsupported tuner ID=%d\n",
+                               dev->cfg.tuner);
                ret = -ENODEV;
                goto err;
        }
 
-       ret = af9033_wr_reg_val_tab(state, init, len);
+       ret = af9033_wr_reg_val_tab(dev, init, len);
        if (ret < 0)
                goto err;
 
-       if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
-               ret = af9033_wr_reg_mask(state, 0x00d91c, 0x01, 0x01);
+       if (dev->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
+               ret = af9033_wr_reg_mask(dev, 0x00d91c, 0x01, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x00d917, 0x00, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9033_wr_reg_mask(state, 0x00d916, 0x00, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x00d916, 0x00, 0x01);
                if (ret < 0)
                        goto err;
        }
 
-       switch (state->cfg.tuner) {
+       switch (dev->cfg.tuner) {
        case AF9033_TUNER_IT9135_60:
        case AF9033_TUNER_IT9135_61:
        case AF9033_TUNER_IT9135_62:
-               ret = af9033_wr_reg(state, 0x800000, 0x01);
+               ret = af9033_wr_reg(dev, 0x800000, 0x01);
                if (ret < 0)
                        goto err;
        }
 
-       state->bandwidth_hz = 0; /* force to program all parameters */
+       dev->bandwidth_hz = 0; /* force to program all parameters */
+       /* init stats here in order signal app which stats are supported */
+       c->strength.len = 1;
+       c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->cnr.len = 1;
+       c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->block_count.len = 1;
+       c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->block_error.len = 1;
+       c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->post_bit_count.len = 1;
+       c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->post_bit_error.len = 1;
+       c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       /* start statistics polling */
+       schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
 
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int af9033_sleep(struct dvb_frontend *fe)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        int ret, i;
        u8 tmp;
 
-       ret = af9033_wr_reg(state, 0x80004c, 1);
+       /* stop statistics polling */
+       cancel_delayed_work_sync(&dev->stat_work);
+
+       ret = af9033_wr_reg(dev, 0x80004c, 1);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg(state, 0x800000, 0);
+       ret = af9033_wr_reg(dev, 0x800000, 0);
        if (ret < 0)
                goto err;
 
        for (i = 100, tmp = 1; i && tmp; i--) {
-               ret = af9033_rd_reg(state, 0x80004c, &tmp);
+               ret = af9033_rd_reg(dev, 0x80004c, &tmp);
                if (ret < 0)
                        goto err;
 
                usleep_range(200, 10000);
        }
 
-       dev_dbg(&state->i2c->dev, "%s: loop=%d\n", __func__, i);
+       dev_dbg(&dev->client->dev, "loop=%d\n", i);
 
        if (i == 0) {
                ret = -ETIMEDOUT;
                goto err;
        }
 
-       ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08);
+       ret = af9033_wr_reg_mask(dev, 0x80fb24, 0x08, 0x08);
        if (ret < 0)
                goto err;
 
        /* prevent current leak (?) */
-       if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
+       if (dev->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
                /* enable parallel TS */
-               ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x00d917, 0x00, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x00d916, 0x01, 0x01);
                if (ret < 0)
                        goto err;
        }
@@ -515,7 +524,7 @@ static int af9033_sleep(struct dvb_frontend *fe)
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -533,14 +542,14 @@ static int af9033_get_tune_settings(struct dvb_frontend *fe,
 
 static int af9033_set_frontend(struct dvb_frontend *fe)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret, i, spec_inv, sampling_freq;
        u8 tmp, buf[3], bandwidth_reg_val;
        u32 if_frequency, freq_cw, adc_freq;
 
-       dev_dbg(&state->i2c->dev, "%s: frequency=%d bandwidth_hz=%d\n",
-                       __func__, c->frequency, c->bandwidth_hz);
+       dev_dbg(&dev->client->dev, "frequency=%d bandwidth_hz=%d\n",
+                       c->frequency, c->bandwidth_hz);
 
        /* check bandwidth */
        switch (c->bandwidth_hz) {
@@ -554,8 +563,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
                bandwidth_reg_val = 0x02;
                break;
        default:
-               dev_dbg(&state->i2c->dev, "%s: invalid bandwidth_hz\n",
-                               __func__);
+               dev_dbg(&dev->client->dev, "invalid bandwidth_hz\n");
                ret = -EINVAL;
                goto err;
        }
@@ -565,23 +573,23 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
                fe->ops.tuner_ops.set_params(fe);
 
        /* program CFOE coefficients */
-       if (c->bandwidth_hz != state->bandwidth_hz) {
+       if (c->bandwidth_hz != dev->bandwidth_hz) {
                for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) {
-                       if (coeff_lut[i].clock == state->cfg.clock &&
+                       if (coeff_lut[i].clock == dev->cfg.clock &&
                                coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
                                break;
                        }
                }
-               ret =  af9033_wr_regs(state, 0x800001,
+               ret =  af9033_wr_regs(dev, 0x800001,
                                coeff_lut[i].val, sizeof(coeff_lut[i].val));
        }
 
        /* program frequency control */
-       if (c->bandwidth_hz != state->bandwidth_hz) {
-               spec_inv = state->cfg.spec_inv ? -1 : 1;
+       if (c->bandwidth_hz != dev->bandwidth_hz) {
+               spec_inv = dev->cfg.spec_inv ? -1 : 1;
 
                for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
-                       if (clock_adc_lut[i].clock == state->cfg.clock)
+                       if (clock_adc_lut[i].clock == dev->cfg.clock)
                                break;
                }
                adc_freq = clock_adc_lut[i].adc;
@@ -602,12 +610,12 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
                else
                        sampling_freq *= -1;
 
-               freq_cw = af9033_div(state, sampling_freq, adc_freq, 23ul);
+               freq_cw = af9033_div(dev, sampling_freq, adc_freq, 23ul);
 
                if (spec_inv == -1)
                        freq_cw = 0x800000 - freq_cw;
 
-               if (state->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X)
+               if (dev->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X)
                        freq_cw /= 2;
 
                buf[0] = (freq_cw >>  0) & 0xff;
@@ -618,26 +626,26 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
                if (if_frequency == 0)
                        buf[2] = 0;
 
-               ret = af9033_wr_regs(state, 0x800029, buf, 3);
+               ret = af9033_wr_regs(dev, 0x800029, buf, 3);
                if (ret < 0)
                        goto err;
 
-               state->bandwidth_hz = c->bandwidth_hz;
+               dev->bandwidth_hz = c->bandwidth_hz;
        }
 
-       ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03);
+       ret = af9033_wr_reg_mask(dev, 0x80f904, bandwidth_reg_val, 0x03);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg(state, 0x800040, 0x00);
+       ret = af9033_wr_reg(dev, 0x800040, 0x00);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg(state, 0x800047, 0x00);
+       ret = af9033_wr_reg(dev, 0x800047, 0x00);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01);
+       ret = af9033_wr_reg_mask(dev, 0x80f999, 0x00, 0x01);
        if (ret < 0)
                goto err;
 
@@ -646,33 +654,33 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
        else
                tmp = 0x01; /* UHF */
 
-       ret = af9033_wr_reg(state, 0x80004b, tmp);
+       ret = af9033_wr_reg(dev, 0x80004b, tmp);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg(state, 0x800000, 0x00);
+       ret = af9033_wr_reg(dev, 0x800000, 0x00);
        if (ret < 0)
                goto err;
 
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int af9033_get_frontend(struct dvb_frontend *fe)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret;
        u8 buf[8];
 
-       dev_dbg(&state->i2c->dev, "%s:\n", __func__);
+       dev_dbg(&dev->client->dev, "\n");
 
        /* read all needed registers */
-       ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf));
+       ret = af9033_rd_regs(dev, 0x80f900, buf, sizeof(buf));
        if (ret < 0)
                goto err;
 
@@ -784,21 +792,21 @@ static int af9033_get_frontend(struct dvb_frontend *fe)
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        int ret;
        u8 tmp;
 
        *status = 0;
 
        /* radio channel status, 0=no result, 1=has signal, 2=no signal */
-       ret = af9033_rd_reg(state, 0x800047, &tmp);
+       ret = af9033_rd_reg(dev, 0x800047, &tmp);
        if (ret < 0)
                goto err;
 
@@ -808,7 +816,7 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
        if (tmp != 0x02) {
                /* TPS lock */
-               ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01);
+               ret = af9033_rd_reg_mask(dev, 0x80f5a9, &tmp, 0x01);
                if (ret < 0)
                        goto err;
 
@@ -817,7 +825,7 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
                                        FE_HAS_VITERBI;
 
                /* full lock */
-               ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01);
+               ret = af9033_rd_reg_mask(dev, 0x80f999, &tmp, 0x01);
                if (ret < 0)
                        goto err;
 
@@ -827,76 +835,38 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
                                        FE_HAS_LOCK;
        }
 
+       dev->fe_status = *status;
+
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-       struct af9033_state *state = fe->demodulator_priv;
-       int ret, i, len;
-       u8 buf[3], tmp;
-       u32 snr_val;
-       const struct val_snr *uninitialized_var(snr_lut);
-
-       /* read value */
-       ret = af9033_rd_regs(state, 0x80002c, buf, 3);
-       if (ret < 0)
-               goto err;
+       struct af9033_dev *dev = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
 
-       snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0];
-
-       /* read current modulation */
-       ret = af9033_rd_reg(state, 0x80f903, &tmp);
-       if (ret < 0)
-               goto err;
-
-       switch ((tmp >> 0) & 3) {
-       case 0:
-               len = ARRAY_SIZE(qpsk_snr_lut);
-               snr_lut = qpsk_snr_lut;
-               break;
-       case 1:
-               len = ARRAY_SIZE(qam16_snr_lut);
-               snr_lut = qam16_snr_lut;
-               break;
-       case 2:
-               len = ARRAY_SIZE(qam64_snr_lut);
-               snr_lut = qam64_snr_lut;
-               break;
-       default:
-               goto err;
-       }
-
-       for (i = 0; i < len; i++) {
-               tmp = snr_lut[i].snr;
-
-               if (snr_val < snr_lut[i].val)
-                       break;
-       }
-
-       *snr = tmp * 10; /* dB/10 */
+       /* use DVBv5 CNR */
+       if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL)
+               *snr = div_s64(c->cnr.stat[0].svalue, 100); /* 1000x => 10x */
+       else
+               *snr = 0;
 
        return 0;
-
-err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
-
-       return ret;
 }
 
 static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        int ret;
        u8 strength2;
 
        /* read signal strength of 0-100 scale */
-       ret = af9033_rd_reg(state, 0x800048, &strength2);
+       ret = af9033_rd_reg(dev, 0x800048, &strength2);
        if (ret < 0)
                goto err;
 
@@ -906,244 +876,225 @@ static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
-
-       return ret;
-}
-
-static int af9033_update_ch_stat(struct af9033_state *state)
-{
-       int ret = 0;
-       u32 err_cnt, bit_cnt;
-       u16 abort_cnt;
-       u8 buf[7];
-
-       /* only update data every half second */
-       if (time_after(jiffies, state->last_stat_check + msecs_to_jiffies(500))) {
-               ret = af9033_rd_regs(state, 0x800032, buf, sizeof(buf));
-               if (ret < 0)
-                       goto err;
-               /* in 8 byte packets? */
-               abort_cnt = (buf[1] << 8) + buf[0];
-               /* in bits */
-               err_cnt = (buf[4] << 16) + (buf[3] << 8) + buf[2];
-               /* in 8 byte packets? always(?) 0x2710 = 10000 */
-               bit_cnt = (buf[6] << 8) + buf[5];
-
-               if (bit_cnt < abort_cnt) {
-                       abort_cnt = 1000;
-                       state->ber = 0xffffffff;
-               } else {
-                       /* 8 byte packets, that have not been rejected already */
-                       bit_cnt -= (u32)abort_cnt;
-                       if (bit_cnt == 0) {
-                               state->ber = 0xffffffff;
-                       } else {
-                               err_cnt -= (u32)abort_cnt * 8 * 8;
-                               bit_cnt *= 8 * 8;
-                               state->ber = err_cnt * (0xffffffff / bit_cnt);
-                       }
-               }
-               state->ucb += abort_cnt;
-               state->last_stat_check = jiffies;
-       }
-
-       return 0;
-err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-       struct af9033_state *state = fe->demodulator_priv;
-       int ret;
-
-       ret = af9033_update_ch_stat(state);
-       if (ret < 0)
-               return ret;
+       struct af9033_dev *dev = fe->demodulator_priv;
 
-       *ber = state->ber;
+       *ber = (dev->post_bit_error - dev->post_bit_error_prev);
+       dev->post_bit_error_prev = dev->post_bit_error;
 
        return 0;
 }
 
 static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-       struct af9033_state *state = fe->demodulator_priv;
-       int ret;
-
-       ret = af9033_update_ch_stat(state);
-       if (ret < 0)
-               return ret;
-
-       *ucblocks = state->ucb;
+       struct af9033_dev *dev = fe->demodulator_priv;
 
+       *ucblocks = dev->error_block_count;
        return 0;
 }
 
 static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        int ret;
 
-       dev_dbg(&state->i2c->dev, "%s: enable=%d\n", __func__, enable);
+       dev_dbg(&dev->client->dev, "enable=%d\n", enable);
 
-       ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01);
+       ret = af9033_wr_reg_mask(dev, 0x00fa04, enable, 0x01);
        if (ret < 0)
                goto err;
 
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        int ret;
 
-       dev_dbg(&state->i2c->dev, "%s: onoff=%d\n", __func__, onoff);
+       dev_dbg(&dev->client->dev, "onoff=%d\n", onoff);
 
-       ret = af9033_wr_reg_mask(state, 0x80f993, onoff, 0x01);
+       ret = af9033_wr_reg_mask(dev, 0x80f993, onoff, 0x01);
        if (ret < 0)
                goto err;
 
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
-static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int onoff)
+static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid,
+               int onoff)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        int ret;
        u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff};
 
-       dev_dbg(&state->i2c->dev, "%s: index=%d pid=%04x onoff=%d\n",
-                       __func__, index, pid, onoff);
+       dev_dbg(&dev->client->dev, "index=%d pid=%04x onoff=%d\n",
+                       index, pid, onoff);
 
        if (pid > 0x1fff)
                return 0;
 
-       ret = af9033_wr_regs(state, 0x80f996, wbuf, 2);
+       ret = af9033_wr_regs(dev, 0x80f996, wbuf, 2);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg(state, 0x80f994, onoff);
+       ret = af9033_wr_reg(dev, 0x80f994, onoff);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg(state, 0x80f995, index);
+       ret = af9033_wr_reg(dev, 0x80f995, index);
        if (ret < 0)
                goto err;
 
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
-static struct dvb_frontend_ops af9033_ops;
-
-struct dvb_frontend *af9033_attach(const struct af9033_config *config,
-                                  struct i2c_adapter *i2c,
-                                  struct af9033_ops *ops)
+static void af9033_stat_work(struct work_struct *work)
 {
-       int ret;
-       struct af9033_state *state;
-       u8 buf[8];
+       struct af9033_dev *dev = container_of(work, struct af9033_dev, stat_work.work);
+       struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
+       int ret, tmp, i, len;
+       u8 u8tmp, buf[7];
+
+       dev_dbg(&dev->client->dev, "\n");
+
+       /* signal strength */
+       if (dev->fe_status & FE_HAS_SIGNAL) {
+               if (dev->is_af9035) {
+                       ret = af9033_rd_reg(dev, 0x80004a, &u8tmp);
+                       tmp = -u8tmp * 1000;
+               } else {
+                       ret = af9033_rd_reg(dev, 0x8000f7, &u8tmp);
+                       tmp = (u8tmp - 100) * 1000;
+               }
+               if (ret)
+                       goto err;
 
-       dev_dbg(&i2c->dev, "%s:\n", __func__);
+               c->strength.len = 1;
+               c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+               c->strength.stat[0].svalue = tmp;
+       } else {
+               c->strength.len = 1;
+               c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       }
 
-       /* allocate memory for the internal state */
-       state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL);
-       if (state == NULL)
-               goto err;
+       /* CNR */
+       if (dev->fe_status & FE_HAS_VITERBI) {
+               u32 snr_val;
+               const struct val_snr *snr_lut;
 
-       /* setup the state */
-       state->i2c = i2c;
-       memcpy(&state->cfg, config, sizeof(struct af9033_config));
+               /* read value */
+               ret = af9033_rd_regs(dev, 0x80002c, buf, 3);
+               if (ret)
+                       goto err;
 
-       if (state->cfg.clock != 12000000) {
-               dev_err(&state->i2c->dev, "%s: af9033: unsupported clock=%d, " \
-                               "only 12000000 Hz is supported currently\n",
-                               KBUILD_MODNAME, state->cfg.clock);
-               goto err;
-       }
+               snr_val = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0);
 
-       /* firmware version */
-       ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4);
-       if (ret < 0)
-               goto err;
+               /* read current modulation */
+               ret = af9033_rd_reg(dev, 0x80f903, &u8tmp);
+               if (ret)
+                       goto err;
 
-       ret = af9033_rd_regs(state, 0x804191, &buf[4], 4);
-       if (ret < 0)
-               goto err;
+               switch ((u8tmp >> 0) & 3) {
+               case 0:
+                       len = ARRAY_SIZE(qpsk_snr_lut);
+                       snr_lut = qpsk_snr_lut;
+                       break;
+               case 1:
+                       len = ARRAY_SIZE(qam16_snr_lut);
+                       snr_lut = qam16_snr_lut;
+                       break;
+               case 2:
+                       len = ARRAY_SIZE(qam64_snr_lut);
+                       snr_lut = qam64_snr_lut;
+                       break;
+               default:
+                       goto err_schedule_delayed_work;
+               }
 
-       dev_info(&state->i2c->dev, "%s: firmware version: LINK=%d.%d.%d.%d " \
-                       "OFDM=%d.%d.%d.%d\n", KBUILD_MODNAME, buf[0], buf[1],
-                       buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+               for (i = 0; i < len; i++) {
+                       tmp = snr_lut[i].snr * 1000;
+                       if (snr_val < snr_lut[i].val)
+                               break;
+               }
 
-       /* sleep */
-       switch (state->cfg.tuner) {
-       case AF9033_TUNER_IT9135_38:
-       case AF9033_TUNER_IT9135_51:
-       case AF9033_TUNER_IT9135_52:
-       case AF9033_TUNER_IT9135_60:
-       case AF9033_TUNER_IT9135_61:
-       case AF9033_TUNER_IT9135_62:
-               /* IT9135 did not like to sleep at that early */
-               break;
-       default:
-               ret = af9033_wr_reg(state, 0x80004c, 1);
-               if (ret < 0)
-                       goto err;
+               c->cnr.len = 1;
+               c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+               c->cnr.stat[0].svalue = tmp;
+       } else {
+               c->cnr.len = 1;
+               c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       }
 
-               ret = af9033_wr_reg(state, 0x800000, 0);
-               if (ret < 0)
+       /* UCB/PER/BER */
+       if (dev->fe_status & FE_HAS_LOCK) {
+               /* outer FEC, 204 byte packets */
+               u16 abort_packet_count, rsd_packet_count;
+               /* inner FEC, bits */
+               u32 rsd_bit_err_count;
+
+               /*
+                * Packet count used for measurement is 10000
+                * (rsd_packet_count). Maybe it should be increased?
+                */
+
+               ret = af9033_rd_regs(dev, 0x800032, buf, 7);
+               if (ret)
                        goto err;
-       }
 
-       /* configure internal TS mode */
-       switch (state->cfg.ts_mode) {
-       case AF9033_TS_MODE_PARALLEL:
-               state->ts_mode_parallel = true;
-               break;
-       case AF9033_TS_MODE_SERIAL:
-               state->ts_mode_serial = true;
-               break;
-       case AF9033_TS_MODE_USB:
-               /* usb mode for AF9035 */
-       default:
-               break;
-       }
+               abort_packet_count = (buf[1] << 8) | (buf[0] << 0);
+               rsd_bit_err_count = (buf[4] << 16) | (buf[3] << 8) | buf[2];
+               rsd_packet_count = (buf[6] << 8) | (buf[5] << 0);
 
-       /* create dvb_frontend */
-       memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops));
-       state->fe.demodulator_priv = state;
+               dev->error_block_count += abort_packet_count;
+               dev->total_block_count += rsd_packet_count;
+               dev->post_bit_error += rsd_bit_err_count;
+               dev->post_bit_count += rsd_packet_count * 204 * 8;
 
-       if (ops) {
-               ops->pid_filter = af9033_pid_filter;
-               ops->pid_filter_ctrl = af9033_pid_filter_ctrl;
-       }
+               c->block_count.len = 1;
+               c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+               c->block_count.stat[0].uvalue = dev->total_block_count;
+
+               c->block_error.len = 1;
+               c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+               c->block_error.stat[0].uvalue = dev->error_block_count;
+
+               c->post_bit_count.len = 1;
+               c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+               c->post_bit_count.stat[0].uvalue = dev->post_bit_count;
 
-       return &state->fe;
+               c->post_bit_error.len = 1;
+               c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+               c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
+       }
 
+err_schedule_delayed_work:
+       schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+       return;
 err:
-       kfree(state);
-       return NULL;
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 }
-EXPORT_SYMBOL(af9033_attach);
 
 static struct dvb_frontend_ops af9033_ops = {
        .delsys = { SYS_DVBT },
@@ -1170,8 +1121,6 @@ static struct dvb_frontend_ops af9033_ops = {
                        FE_CAN_MUTE_TS
        },
 
-       .release = af9033_release,
-
        .init = af9033_init,
        .sleep = af9033_sleep,
 
@@ -1188,6 +1137,150 @@ static struct dvb_frontend_ops af9033_ops = {
        .i2c_gate_ctrl = af9033_i2c_gate_ctrl,
 };
 
+static int af9033_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct af9033_config *cfg = client->dev.platform_data;
+       struct af9033_dev *dev;
+       int ret;
+       u8 buf[8];
+       u32 reg;
+
+       /* allocate memory for the internal state */
+       dev = kzalloc(sizeof(struct af9033_dev), GFP_KERNEL);
+       if (dev == NULL) {
+               ret = -ENOMEM;
+               dev_err(&client->dev, "Could not allocate memory for state\n");
+               goto err;
+       }
+
+       /* setup the state */
+       dev->client = client;
+       INIT_DELAYED_WORK(&dev->stat_work, af9033_stat_work);
+       memcpy(&dev->cfg, cfg, sizeof(struct af9033_config));
+
+       if (dev->cfg.clock != 12000000) {
+               ret = -ENODEV;
+               dev_err(&dev->client->dev,
+                               "unsupported clock %d Hz, only 12000000 Hz is supported currently\n",
+                               dev->cfg.clock);
+               goto err_kfree;
+       }
+
+       /* firmware version */
+       switch (dev->cfg.tuner) {
+       case AF9033_TUNER_IT9135_38:
+       case AF9033_TUNER_IT9135_51:
+       case AF9033_TUNER_IT9135_52:
+       case AF9033_TUNER_IT9135_60:
+       case AF9033_TUNER_IT9135_61:
+       case AF9033_TUNER_IT9135_62:
+               dev->is_it9135 = true;
+               reg = 0x004bfc;
+               break;
+       default:
+               dev->is_af9035 = true;
+               reg = 0x0083e9;
+               break;
+       }
+
+       ret = af9033_rd_regs(dev, reg, &buf[0], 4);
+       if (ret < 0)
+               goto err_kfree;
+
+       ret = af9033_rd_regs(dev, 0x804191, &buf[4], 4);
+       if (ret < 0)
+               goto err_kfree;
+
+       dev_info(&dev->client->dev,
+                       "firmware version: LINK %d.%d.%d.%d - OFDM %d.%d.%d.%d\n",
+                       buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
+                       buf[7]);
+
+       /* sleep */
+       switch (dev->cfg.tuner) {
+       case AF9033_TUNER_IT9135_38:
+       case AF9033_TUNER_IT9135_51:
+       case AF9033_TUNER_IT9135_52:
+       case AF9033_TUNER_IT9135_60:
+       case AF9033_TUNER_IT9135_61:
+       case AF9033_TUNER_IT9135_62:
+               /* IT9135 did not like to sleep at that early */
+               break;
+       default:
+               ret = af9033_wr_reg(dev, 0x80004c, 1);
+               if (ret < 0)
+                       goto err_kfree;
+
+               ret = af9033_wr_reg(dev, 0x800000, 0);
+               if (ret < 0)
+                       goto err_kfree;
+       }
+
+       /* configure internal TS mode */
+       switch (dev->cfg.ts_mode) {
+       case AF9033_TS_MODE_PARALLEL:
+               dev->ts_mode_parallel = true;
+               break;
+       case AF9033_TS_MODE_SERIAL:
+               dev->ts_mode_serial = true;
+               break;
+       case AF9033_TS_MODE_USB:
+               /* usb mode for AF9035 */
+       default:
+               break;
+       }
+
+       /* create dvb_frontend */
+       memcpy(&dev->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops));
+       dev->fe.demodulator_priv = dev;
+       *cfg->fe = &dev->fe;
+       if (cfg->ops) {
+               cfg->ops->pid_filter = af9033_pid_filter;
+               cfg->ops->pid_filter_ctrl = af9033_pid_filter_ctrl;
+       }
+       i2c_set_clientdata(client, dev);
+
+       dev_info(&dev->client->dev, "Afatech AF9033 successfully attached\n");
+       return 0;
+err_kfree:
+       kfree(dev);
+err:
+       dev_dbg(&client->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static int af9033_remove(struct i2c_client *client)
+{
+       struct af9033_dev *dev = i2c_get_clientdata(client);
+
+       dev_dbg(&dev->client->dev, "\n");
+
+       dev->fe.ops.release = NULL;
+       dev->fe.demodulator_priv = NULL;
+       kfree(dev);
+
+       return 0;
+}
+
+static const struct i2c_device_id af9033_id_table[] = {
+       {"af9033", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, af9033_id_table);
+
+static struct i2c_driver af9033_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "af9033",
+       },
+       .probe          = af9033_probe,
+       .remove         = af9033_remove,
+       .id_table       = af9033_id_table,
+};
+
+module_i2c_driver(af9033_driver);
+
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver");
 MODULE_LICENSE("GPL");
index 539f4db678b87f0076093f8f85b9139e182dc31d..6ad22b69a63605e6b14c5516614fc40640e9085e 100644 (file)
 
 #include <linux/kconfig.h>
 
+/*
+ * I2C address (TODO: are these in 8-bit format?)
+ * 0x38, 0x3a, 0x3c, 0x3e
+ */
 struct af9033_config {
-       /*
-        * I2C address
-        */
-       u8 i2c_addr;
-
        /*
         * clock Hz
         * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000,
@@ -75,8 +74,23 @@ struct af9033_config {
         * input spectrum inversion
         */
        bool spec_inv;
-};
 
+       /*
+        *
+        */
+       bool dyn0_clk;
+
+       /*
+        * PID filter ops
+        */
+       struct af9033_ops *ops;
+
+       /*
+        * frontend
+        * returned by that driver
+        */
+       struct dvb_frontend **fe;
+};
 
 struct af9033_ops {
        int (*pid_filter_ctrl)(struct dvb_frontend *fe, int onoff);
@@ -84,36 +98,4 @@ struct af9033_ops {
                          int onoff);
 };
 
-
-#if IS_ENABLED(CONFIG_DVB_AF9033)
-extern
-struct dvb_frontend *af9033_attach(const struct af9033_config *config,
-                                  struct i2c_adapter *i2c,
-                                  struct af9033_ops *ops);
-
-#else
-static inline
-struct dvb_frontend *af9033_attach(const struct af9033_config *config,
-                                  struct i2c_adapter *i2c,
-                                  struct af9033_ops *ops)
-{
-       pr_warn("%s: driver disabled by Kconfig\n", __func__);
-       return NULL;
-}
-
-static inline int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
-{
-       pr_warn("%s: driver disabled by Kconfig\n", __func__);
-       return -ENODEV;
-}
-
-static inline int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid,
-       int onoff)
-{
-       pr_warn("%s: driver disabled by Kconfig\n", __func__);
-       return -ENODEV;
-}
-
-#endif
-
 #endif /* AF9033_H */
index ded7b67d7526cab8b9cd364dfe6ce19fdb3da36e..c12c92cb5855ae587f332f1d32673947ac90d912 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "dvb_frontend.h"
 #include "af9033.h"
+#include <linux/math64.h>
 
 struct reg_val {
        u32 reg;
diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c
new file mode 100644 (file)
index 0000000..4936658
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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.
+ */
+
+#include <dvb_frontend.h>
+
+#include "as102_fe.h"
+
+struct as102_state {
+       struct dvb_frontend frontend;
+       struct as10x_demod_stats demod_stats;
+
+       const struct as102_fe_ops *ops;
+       void *priv;
+       uint8_t elna_cfg;
+
+       /* signal strength */
+       uint16_t signal_strength;
+       /* bit error rate */
+       uint32_t ber;
+};
+
+static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg)
+{
+       uint8_t c;
+
+       switch (arg) {
+       case FEC_1_2:
+               c = CODE_RATE_1_2;
+               break;
+       case FEC_2_3:
+               c = CODE_RATE_2_3;
+               break;
+       case FEC_3_4:
+               c = CODE_RATE_3_4;
+               break;
+       case FEC_5_6:
+               c = CODE_RATE_5_6;
+               break;
+       case FEC_7_8:
+               c = CODE_RATE_7_8;
+               break;
+       default:
+               c = CODE_RATE_UNKNOWN;
+               break;
+       }
+
+       return c;
+}
+
+static int as102_fe_set_frontend(struct dvb_frontend *fe)
+{
+       struct as102_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct as10x_tune_args tune_args = { 0 };
+
+       /* set frequency */
+       tune_args.freq = c->frequency / 1000;
+
+       /* fix interleaving_mode */
+       tune_args.interleaving_mode = INTLV_NATIVE;
+
+       switch (c->bandwidth_hz) {
+       case 8000000:
+               tune_args.bandwidth = BW_8_MHZ;
+               break;
+       case 7000000:
+               tune_args.bandwidth = BW_7_MHZ;
+               break;
+       case 6000000:
+               tune_args.bandwidth = BW_6_MHZ;
+               break;
+       default:
+               tune_args.bandwidth = BW_8_MHZ;
+       }
+
+       switch (c->guard_interval) {
+       case GUARD_INTERVAL_1_32:
+               tune_args.guard_interval = GUARD_INT_1_32;
+               break;
+       case GUARD_INTERVAL_1_16:
+               tune_args.guard_interval = GUARD_INT_1_16;
+               break;
+       case GUARD_INTERVAL_1_8:
+               tune_args.guard_interval = GUARD_INT_1_8;
+               break;
+       case GUARD_INTERVAL_1_4:
+               tune_args.guard_interval = GUARD_INT_1_4;
+               break;
+       case GUARD_INTERVAL_AUTO:
+       default:
+               tune_args.guard_interval = GUARD_UNKNOWN;
+               break;
+       }
+
+       switch (c->modulation) {
+       case QPSK:
+               tune_args.modulation = CONST_QPSK;
+               break;
+       case QAM_16:
+               tune_args.modulation = CONST_QAM16;
+               break;
+       case QAM_64:
+               tune_args.modulation = CONST_QAM64;
+               break;
+       default:
+               tune_args.modulation = CONST_UNKNOWN;
+               break;
+       }
+
+       switch (c->transmission_mode) {
+       case TRANSMISSION_MODE_2K:
+               tune_args.transmission_mode = TRANS_MODE_2K;
+               break;
+       case TRANSMISSION_MODE_8K:
+               tune_args.transmission_mode = TRANS_MODE_8K;
+               break;
+       default:
+               tune_args.transmission_mode = TRANS_MODE_UNKNOWN;
+       }
+
+       switch (c->hierarchy) {
+       case HIERARCHY_NONE:
+               tune_args.hierarchy = HIER_NONE;
+               break;
+       case HIERARCHY_1:
+               tune_args.hierarchy = HIER_ALPHA_1;
+               break;
+       case HIERARCHY_2:
+               tune_args.hierarchy = HIER_ALPHA_2;
+               break;
+       case HIERARCHY_4:
+               tune_args.hierarchy = HIER_ALPHA_4;
+               break;
+       case HIERARCHY_AUTO:
+               tune_args.hierarchy = HIER_UNKNOWN;
+               break;
+       }
+
+       pr_debug("as102: tuner parameters: freq: %d  bw: 0x%02x  gi: 0x%02x\n",
+                       c->frequency,
+                       tune_args.bandwidth,
+                       tune_args.guard_interval);
+
+       /*
+        * Detect a hierarchy selection
+        * if HP/LP are both set to FEC_NONE, HP will be selected.
+        */
+       if ((tune_args.hierarchy != HIER_NONE) &&
+                      ((c->code_rate_LP == FEC_NONE) ||
+                       (c->code_rate_HP == FEC_NONE))) {
+
+               if (c->code_rate_LP == FEC_NONE) {
+                       tune_args.hier_select = HIER_HIGH_PRIORITY;
+                       tune_args.code_rate =
+                          as102_fe_get_code_rate(c->code_rate_HP);
+               }
+
+               if (c->code_rate_HP == FEC_NONE) {
+                       tune_args.hier_select = HIER_LOW_PRIORITY;
+                       tune_args.code_rate =
+                          as102_fe_get_code_rate(c->code_rate_LP);
+               }
+
+               pr_debug("as102: \thierarchy: 0x%02x  selected: %s  code_rate_%s: 0x%02x\n",
+                       tune_args.hierarchy,
+                       tune_args.hier_select == HIER_HIGH_PRIORITY ?
+                       "HP" : "LP",
+                       tune_args.hier_select == HIER_HIGH_PRIORITY ?
+                       "HP" : "LP",
+                       tune_args.code_rate);
+       } else {
+               tune_args.code_rate =
+                       as102_fe_get_code_rate(c->code_rate_HP);
+       }
+
+       /* Set frontend arguments */
+       return state->ops->set_tune(state->priv, &tune_args);
+}
+
+static int as102_fe_get_frontend(struct dvb_frontend *fe)
+{
+       struct as102_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret = 0;
+       struct as10x_tps tps = { 0 };
+
+       /* send abilis command: GET_TPS */
+       ret = state->ops->get_tps(state->priv, &tps);
+       if (ret < 0)
+               return ret;
+
+       /* extract constellation */
+       switch (tps.modulation) {
+       case CONST_QPSK:
+               c->modulation = QPSK;
+               break;
+       case CONST_QAM16:
+               c->modulation = QAM_16;
+               break;
+       case CONST_QAM64:
+               c->modulation = QAM_64;
+               break;
+       }
+
+       /* extract hierarchy */
+       switch (tps.hierarchy) {
+       case HIER_NONE:
+               c->hierarchy = HIERARCHY_NONE;
+               break;
+       case HIER_ALPHA_1:
+               c->hierarchy = HIERARCHY_1;
+               break;
+       case HIER_ALPHA_2:
+               c->hierarchy = HIERARCHY_2;
+               break;
+       case HIER_ALPHA_4:
+               c->hierarchy = HIERARCHY_4;
+               break;
+       }
+
+       /* extract code rate HP */
+       switch (tps.code_rate_HP) {
+       case CODE_RATE_1_2:
+               c->code_rate_HP = FEC_1_2;
+               break;
+       case CODE_RATE_2_3:
+               c->code_rate_HP = FEC_2_3;
+               break;
+       case CODE_RATE_3_4:
+               c->code_rate_HP = FEC_3_4;
+               break;
+       case CODE_RATE_5_6:
+               c->code_rate_HP = FEC_5_6;
+               break;
+       case CODE_RATE_7_8:
+               c->code_rate_HP = FEC_7_8;
+               break;
+       }
+
+       /* extract code rate LP */
+       switch (tps.code_rate_LP) {
+       case CODE_RATE_1_2:
+               c->code_rate_LP = FEC_1_2;
+               break;
+       case CODE_RATE_2_3:
+               c->code_rate_LP = FEC_2_3;
+               break;
+       case CODE_RATE_3_4:
+               c->code_rate_LP = FEC_3_4;
+               break;
+       case CODE_RATE_5_6:
+               c->code_rate_LP = FEC_5_6;
+               break;
+       case CODE_RATE_7_8:
+               c->code_rate_LP = FEC_7_8;
+               break;
+       }
+
+       /* extract guard interval */
+       switch (tps.guard_interval) {
+       case GUARD_INT_1_32:
+               c->guard_interval = GUARD_INTERVAL_1_32;
+               break;
+       case GUARD_INT_1_16:
+               c->guard_interval = GUARD_INTERVAL_1_16;
+               break;
+       case GUARD_INT_1_8:
+               c->guard_interval = GUARD_INTERVAL_1_8;
+               break;
+       case GUARD_INT_1_4:
+               c->guard_interval = GUARD_INTERVAL_1_4;
+               break;
+       }
+
+       /* extract transmission mode */
+       switch (tps.transmission_mode) {
+       case TRANS_MODE_2K:
+               c->transmission_mode = TRANSMISSION_MODE_2K;
+               break;
+       case TRANS_MODE_8K:
+               c->transmission_mode = TRANSMISSION_MODE_8K;
+               break;
+       }
+
+       return 0;
+}
+
+static int as102_fe_get_tune_settings(struct dvb_frontend *fe,
+                       struct dvb_frontend_tune_settings *settings) {
+
+       settings->min_delay_ms = 1000;
+
+       return 0;
+}
+
+static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       int ret = 0;
+       struct as102_state *state = fe->demodulator_priv;
+       struct as10x_tune_status tstate = { 0 };
+
+       /* send abilis command: GET_TUNE_STATUS */
+       ret = state->ops->get_status(state->priv, &tstate);
+       if (ret < 0)
+               return ret;
+
+       state->signal_strength  = tstate.signal_strength;
+       state->ber  = tstate.BER;
+
+       switch (tstate.tune_state) {
+       case TUNE_STATUS_SIGNAL_DVB_OK:
+               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+               break;
+       case TUNE_STATUS_STREAM_DETECTED:
+               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
+                         FE_HAS_VITERBI;
+               break;
+       case TUNE_STATUS_STREAM_TUNED:
+               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
+                         FE_HAS_LOCK | FE_HAS_VITERBI;
+               break;
+       default:
+               *status = TUNE_STATUS_NOT_TUNED;
+       }
+
+       pr_debug("as102: tuner status: 0x%02x, strength %d, per: %d, ber: %d\n",
+                tstate.tune_state, tstate.signal_strength,
+                tstate.PER, tstate.BER);
+
+       if (!(*status & FE_HAS_LOCK)) {
+               memset(&state->demod_stats, 0, sizeof(state->demod_stats));
+               return 0;
+       }
+
+       ret = state->ops->get_stats(state->priv, &state->demod_stats);
+       if (ret < 0)
+               memset(&state->demod_stats, 0, sizeof(state->demod_stats));
+
+       return ret;
+}
+
+/*
+ * Note:
+ * - in AS102 SNR=MER
+ *   - the SNR will be returned in linear terms, i.e. not in dB
+ *   - the accuracy equals Â±2dB for a SNR range from 4dB to 30dB
+ *   - the accuracy is >2dB for SNR values outside this range
+ */
+static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct as102_state *state = fe->demodulator_priv;
+
+       *snr = state->demod_stats.mer;
+
+       return 0;
+}
+
+static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct as102_state *state = fe->demodulator_priv;
+
+       *ber = state->ber;
+
+       return 0;
+}
+
+static int as102_fe_read_signal_strength(struct dvb_frontend *fe,
+                                        u16 *strength)
+{
+       struct as102_state *state = fe->demodulator_priv;
+
+       *strength = (((0xffff * 400) * state->signal_strength + 41000) * 2);
+
+       return 0;
+}
+
+static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct as102_state *state = fe->demodulator_priv;
+
+       if (state->demod_stats.has_started)
+               *ucblocks = state->demod_stats.bad_frame_count;
+       else
+               *ucblocks = 0;
+
+       return 0;
+}
+
+static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+       struct as102_state *state = fe->demodulator_priv;
+
+       return state->ops->stream_ctrl(state->priv, acquire,
+                                     state->elna_cfg);
+}
+
+static void as102_fe_release(struct dvb_frontend *fe)
+{
+       struct as102_state *state = fe->demodulator_priv;
+
+       kfree(state);
+}
+
+
+static struct dvb_frontend_ops as102_fe_ops = {
+       .delsys = { SYS_DVBT },
+       .info = {
+               .name                   = "Abilis AS102 DVB-T",
+               .frequency_min          = 174000000,
+               .frequency_max          = 862000000,
+               .frequency_stepsize     = 166667,
+               .caps = FE_CAN_INVERSION_AUTO
+                       | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
+                       | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO
+                       | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK
+                       | FE_CAN_QAM_AUTO
+                       | FE_CAN_TRANSMISSION_MODE_AUTO
+                       | FE_CAN_GUARD_INTERVAL_AUTO
+                       | FE_CAN_HIERARCHY_AUTO
+                       | FE_CAN_RECOVER
+                       | FE_CAN_MUTE_TS
+       },
+
+       .set_frontend           = as102_fe_set_frontend,
+       .get_frontend           = as102_fe_get_frontend,
+       .get_tune_settings      = as102_fe_get_tune_settings,
+
+       .read_status            = as102_fe_read_status,
+       .read_snr               = as102_fe_read_snr,
+       .read_ber               = as102_fe_read_ber,
+       .read_signal_strength   = as102_fe_read_signal_strength,
+       .read_ucblocks          = as102_fe_read_ucblocks,
+       .ts_bus_ctrl            = as102_fe_ts_bus_ctrl,
+       .release                = as102_fe_release,
+};
+
+struct dvb_frontend *as102_attach(const char *name,
+                                 const struct as102_fe_ops *ops,
+                                 void *priv,
+                                 uint8_t elna_cfg)
+{
+       struct as102_state *state;
+       struct dvb_frontend *fe;
+
+       state = kzalloc(sizeof(struct as102_state), GFP_KERNEL);
+       if (state == NULL) {
+               pr_err("%s: unable to allocate memory for state\n", __func__);
+               return NULL;
+       }
+       fe = &state->frontend;
+       fe->demodulator_priv = state;
+       state->ops = ops;
+       state->priv = priv;
+       state->elna_cfg = elna_cfg;
+
+       /* init frontend callback ops */
+       memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops));
+       strncpy(fe->ops.info.name, name, sizeof(fe->ops.info.name));
+
+       return fe;
+
+}
+EXPORT_SYMBOL_GPL(as102_attach);
+
+MODULE_DESCRIPTION("as102-fe");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
diff --git a/drivers/media/dvb-frontends/as102_fe.h b/drivers/media/dvb-frontends/as102_fe.h
new file mode 100644 (file)
index 0000000..a7c9143
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2014 Mauro Carvalho Chehab <m.chehab@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, 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.
+ */
+
+#include "as102_fe_types.h"
+
+struct as102_fe_ops {
+       int (*set_tune)(void *priv, struct as10x_tune_args *tune_args);
+       int (*get_tps)(void *priv, struct as10x_tps *tps);
+       int (*get_status)(void *priv, struct as10x_tune_status *tstate);
+       int (*get_stats)(void *priv, struct as10x_demod_stats *demod_stats);
+       int (*stream_ctrl)(void *priv, int acquire, uint32_t elna_cfg);
+};
+
+struct dvb_frontend *as102_attach(const char *name,
+                                 const struct as102_fe_ops *ops,
+                                 void *priv,
+                                 uint8_t elna_cfg);
diff --git a/drivers/media/dvb-frontends/as102_fe_types.h b/drivers/media/dvb-frontends/as102_fe_types.h
new file mode 100644 (file)
index 0000000..80a5398
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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.
+ */
+#ifndef _AS10X_TYPES_H_
+#define _AS10X_TYPES_H_
+
+/*********************************/
+/*       MACRO DEFINITIONS       */
+/*********************************/
+
+/* bandwidth constant values */
+#define BW_5_MHZ               0x00
+#define BW_6_MHZ               0x01
+#define BW_7_MHZ               0x02
+#define BW_8_MHZ               0x03
+
+/* hierarchy priority selection values */
+#define HIER_NO_PRIORITY       0x00
+#define HIER_LOW_PRIORITY      0x01
+#define HIER_HIGH_PRIORITY     0x02
+
+/* constellation available values */
+#define CONST_QPSK             0x00
+#define CONST_QAM16            0x01
+#define CONST_QAM64            0x02
+#define CONST_UNKNOWN          0xFF
+
+/* hierarchy available values */
+#define HIER_NONE              0x00
+#define HIER_ALPHA_1           0x01
+#define HIER_ALPHA_2           0x02
+#define HIER_ALPHA_4           0x03
+#define HIER_UNKNOWN           0xFF
+
+/* interleaving available values */
+#define INTLV_NATIVE           0x00
+#define INTLV_IN_DEPTH         0x01
+#define INTLV_UNKNOWN          0xFF
+
+/* code rate available values */
+#define CODE_RATE_1_2          0x00
+#define CODE_RATE_2_3          0x01
+#define CODE_RATE_3_4          0x02
+#define CODE_RATE_5_6          0x03
+#define CODE_RATE_7_8          0x04
+#define CODE_RATE_UNKNOWN      0xFF
+
+/* guard interval available values */
+#define GUARD_INT_1_32         0x00
+#define GUARD_INT_1_16         0x01
+#define GUARD_INT_1_8          0x02
+#define GUARD_INT_1_4          0x03
+#define GUARD_UNKNOWN          0xFF
+
+/* transmission mode available values */
+#define TRANS_MODE_2K          0x00
+#define TRANS_MODE_8K          0x01
+#define TRANS_MODE_4K          0x02
+#define TRANS_MODE_UNKNOWN     0xFF
+
+/* DVBH signalling available values */
+#define TIMESLICING_PRESENT    0x01
+#define MPE_FEC_PRESENT                0x02
+
+/* tune state available */
+#define TUNE_STATUS_NOT_TUNED          0x00
+#define TUNE_STATUS_IDLE               0x01
+#define TUNE_STATUS_LOCKING            0x02
+#define TUNE_STATUS_SIGNAL_DVB_OK      0x03
+#define TUNE_STATUS_STREAM_DETECTED    0x04
+#define TUNE_STATUS_STREAM_TUNED       0x05
+#define TUNE_STATUS_ERROR              0xFF
+
+/* available TS FID filter types */
+#define TS_PID_TYPE_TS         0
+#define TS_PID_TYPE_PSI_SI     1
+#define TS_PID_TYPE_MPE                2
+
+/* number of echos available */
+#define MAX_ECHOS      15
+
+/* Context types */
+#define CONTEXT_LNA                    1010
+#define CONTEXT_ELNA_HYSTERESIS                4003
+#define CONTEXT_ELNA_GAIN              4004
+#define CONTEXT_MER_THRESHOLD          5005
+#define CONTEXT_MER_OFFSET             5006
+#define CONTEXT_IR_STATE               7000
+#define CONTEXT_TSOUT_MSB_FIRST                7004
+#define CONTEXT_TSOUT_FALLING_EDGE     7005
+
+/* Configuration modes */
+#define CFG_MODE_ON    0
+#define CFG_MODE_OFF   1
+#define CFG_MODE_AUTO  2
+
+struct as10x_tps {
+       uint8_t modulation;
+       uint8_t hierarchy;
+       uint8_t interleaving_mode;
+       uint8_t code_rate_HP;
+       uint8_t code_rate_LP;
+       uint8_t guard_interval;
+       uint8_t transmission_mode;
+       uint8_t DVBH_mask_HP;
+       uint8_t DVBH_mask_LP;
+       uint16_t cell_ID;
+} __packed;
+
+struct as10x_tune_args {
+       /* frequency */
+       uint32_t freq;
+       /* bandwidth */
+       uint8_t bandwidth;
+       /* hierarchy selection */
+       uint8_t hier_select;
+       /* constellation */
+       uint8_t modulation;
+       /* hierarchy */
+       uint8_t hierarchy;
+       /* interleaving mode */
+       uint8_t interleaving_mode;
+       /* code rate */
+       uint8_t code_rate;
+       /* guard interval */
+       uint8_t guard_interval;
+       /* transmission mode */
+       uint8_t transmission_mode;
+} __packed;
+
+struct as10x_tune_status {
+       /* tune status */
+       uint8_t tune_state;
+       /* signal strength */
+       int16_t signal_strength;
+       /* packet error rate 10^-4 */
+       uint16_t PER;
+       /* bit error rate 10^-4 */
+       uint16_t BER;
+} __packed;
+
+struct as10x_demod_stats {
+       /* frame counter */
+       uint32_t frame_count;
+       /* Bad frame counter */
+       uint32_t bad_frame_count;
+       /* Number of wrong bytes fixed by Reed-Solomon */
+       uint32_t bytes_fixed_by_rs;
+       /* Averaged MER */
+       uint16_t mer;
+       /* statistics calculation state indicator (started or not) */
+       uint8_t has_started;
+} __packed;
+
+struct as10x_ts_filter {
+       uint16_t pid;  /* valid PID value 0x00 : 0x2000 */
+       uint8_t  type; /* Red TS_PID_TYPE_<N> values */
+       uint8_t  idx;  /* index in filtering table */
+} __packed;
+
+struct as10x_register_value {
+       uint8_t mode;
+       union {
+               uint8_t  value8;   /* 8 bit value */
+               uint16_t value16;  /* 16 bit value */
+               uint32_t value32;  /* 32 bit value */
+       } __packed u;
+} __packed;
+
+struct as10x_register_addr {
+       /* register addr */
+       uint32_t addr;
+       /* register mode access */
+       uint8_t mode;
+};
+
+#endif
index 39a29dd29519cba8573fd7ce1837e46d7df1f73b..638c7aa0fb7e6ae90434d10d92c22879a89a860c 100644 (file)
@@ -639,12 +639,12 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe)
                err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
                return ret;
        }
-       deb_info("got firmware: %zd\n",fw->size);
+       deb_info("got firmware: %zu\n", fw->size);
 
        b = fw->data;
        for (i = 0; i < fw->size;) {
-               addr = le16_to_cpu( *( (u16 *)&b[i] ) );
-               len  = le16_to_cpu( *( (u16 *)&b[i+2] ) );
+               addr = le16_to_cpu(*((__le16 *)&b[i]));
+               len  = le16_to_cpu(*((__le16 *)&b[i+2]));
                deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
                if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
                        err("firmware download failed: %d\n",ret);
index 0f4657e01cdeaa07d8f5b9b2c3e58b237e6058a1..149fdca3fb44e33fd60cda6c44de66041019c86c 100644 (file)
@@ -65,7 +65,7 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe)
        }
 
        priv->delivery_system = SYS_DVBC_ANNEX_A;
-       priv->ber_running = 0; /* tune stops BER counter */
+       priv->ber_running = false; /* tune stops BER counter */
 
        /* program IF frequency */
        if (fe->ops.tuner_ops.get_if_frequency) {
@@ -168,7 +168,7 @@ int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber)
                        start_ber = 1;
                }
        } else {
-               priv->ber_running = 1;
+               priv->ber_running = true;
                start_ber = 1;
        }
 
index 51ef893126151071c511cd7f9e77242507f6065b..422e84bbb008ffe685fb149f529c27ce4957cc70 100644 (file)
@@ -564,10 +564,10 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe)
 
        /* check if we have a valid signal */
        if (status & FE_HAS_LOCK) {
-               priv->last_tune_failed = 0;
+               priv->last_tune_failed = false;
                return DVBFE_ALGO_SEARCH_SUCCESS;
        } else {
-               priv->last_tune_failed = 1;
+               priv->last_tune_failed = true;
                return DVBFE_ALGO_SEARCH_AGAIN;
        }
 
index 9b5a45b907bcfca70f8e31ace191be9447da865c..51401d036530fbfd42d021c293a2a979b43af9c9 100644 (file)
@@ -89,7 +89,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe)
        }
 
        priv->delivery_system = SYS_DVBT;
-       priv->ber_running = 0; /* tune stops BER counter */
+       priv->ber_running = false; /* tune stops BER counter */
 
        /* program IF frequency */
        if (fe->ops.tuner_ops.get_if_frequency) {
@@ -272,7 +272,7 @@ int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber)
                        start_ber = 1;
                }
        } else {
-               priv->ber_running = 1;
+               priv->ber_running = true;
                start_ber = 1;
        }
 
index 661760d60232aa928015ad0cccbbd25c7a6d4948..589134e951758c1ab984be32e1becf88d3631ea5 100644 (file)
@@ -2559,7 +2559,7 @@ static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
        dib7000p_write_word(state, 1288, reg_1288);
 }
 
-int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
+static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
 {
        struct dib7000p_state *state = fe->demodulator_priv;
        u16 reg_1287;
index 7ca7a21df18330649ad23c255349423e33288871..5ec221ffdfcae3a05e88e971f9795785c680752a 100644 (file)
@@ -2174,7 +2174,7 @@ int drxj_dap_atomic_read_reg32(struct i2c_device_addr *dev_addr,
                                     u32 addr,
                                     u32 *data, u32 flags)
 {
-       u8 buf[sizeof(*data)];
+       u8 buf[sizeof(*data)] = { 0 };
        int rc = -EIO;
        u32 word = 0;
 
@@ -4193,7 +4193,7 @@ int drxj_dap_scu_atomic_read_reg16(struct i2c_device_addr *dev_addr,
                                         u32 addr,
                                         u16 *data, u32 flags)
 {
-       u8 buf[2];
+       u8 buf[2] = { 0 };
        int rc = -EIO;
        u16 word = 0;
 
@@ -10667,7 +10667,7 @@ ctrl_sig_quality(struct drx_demod_instance *demod,
        enum drx_standard standard = ext_attr->standard;
        int rc;
        u32 ber, cnt, err, pkt;
-       u16 mer, strength;
+       u16 mer, strength = 0;
 
        rc = get_sig_strength(demod, &strength);
        if (rc < 0) {
@@ -11602,7 +11602,7 @@ static u16 drx_u_code_compute_crc(u8 *block_data, u16 nr_words)
        u32 carry = 0;
 
        while (i < nr_words) {
-               crc_word |= (u32)be16_to_cpu(*(u32 *)(block_data));
+               crc_word |= (u32)be16_to_cpu(*(__be16 *)(block_data));
                for (j = 0; j < 16; j++) {
                        crc_word <<= 1;
                        if (carry != 0)
@@ -11629,7 +11629,7 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
        int i;
        unsigned count = 2 * sizeof(u16);
        u32 mc_dev_type, mc_version, mc_base_version;
-       u16 mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data + sizeof(u16)));
+       u16 mc_nr_of_blks = be16_to_cpu(*(__be16 *)(mc_data + sizeof(u16)));
 
        /*
         * Scan microcode blocks first for version info
@@ -11647,13 +11647,13 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
                        goto eof;
 
                /* Process block header */
-               block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data + count));
+               block_hdr.addr = be32_to_cpu(*(__be32 *)(mc_data + count));
                count += sizeof(u32);
-               block_hdr.size = be16_to_cpu(*(u32 *)(mc_data + count));
+               block_hdr.size = be16_to_cpu(*(__be16 *)(mc_data + count));
                count += sizeof(u16);
-               block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data + count));
+               block_hdr.flags = be16_to_cpu(*(__be16 *)(mc_data + count));
                count += sizeof(u16);
-               block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data + count));
+               block_hdr.CRC = be16_to_cpu(*(__be16 *)(mc_data + count));
                count += sizeof(u16);
 
                pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
@@ -11667,7 +11667,7 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
                        if (block_hdr.addr + sizeof(u16) > size)
                                goto eof;
 
-                       auxtype = be16_to_cpu(*(u32 *)(auxblk));
+                       auxtype = be16_to_cpu(*(__be16 *)(auxblk));
 
                        /* Aux block. Check type */
                        if (DRX_ISMCVERTYPE(auxtype)) {
@@ -11675,11 +11675,11 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
                                        goto eof;
 
                                auxblk += sizeof(u16);
-                               mc_dev_type = be32_to_cpu(*(u32 *)(auxblk));
+                               mc_dev_type = be32_to_cpu(*(__be32 *)(auxblk));
                                auxblk += sizeof(u32);
-                               mc_version = be32_to_cpu(*(u32 *)(auxblk));
+                               mc_version = be32_to_cpu(*(__be32 *)(auxblk));
                                auxblk += sizeof(u32);
-                               mc_base_version = be32_to_cpu(*(u32 *)(auxblk));
+                               mc_base_version = be32_to_cpu(*(__be32 *)(auxblk));
 
                                DRX_ATTR_MCRECORD(demod).aux_type = auxtype;
                                DRX_ATTR_MCRECORD(demod).mc_dev_type = mc_dev_type;
@@ -11765,9 +11765,9 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod,
 
        mc_data = (void *)mc_data_init;
        /* Check data */
-       mc_magic_word = be16_to_cpu(*(u32 *)(mc_data));
+       mc_magic_word = be16_to_cpu(*(__be16 *)(mc_data));
        mc_data += sizeof(u16);
-       mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data));
+       mc_nr_of_blks = be16_to_cpu(*(__be16 *)(mc_data));
        mc_data += sizeof(u16);
 
        if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) {
@@ -11791,13 +11791,13 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod,
                u16 mc_block_nr_bytes = 0;
 
                /* Process block header */
-               block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data));
+               block_hdr.addr = be32_to_cpu(*(__be32 *)(mc_data));
                mc_data += sizeof(u32);
-               block_hdr.size = be16_to_cpu(*(u32 *)(mc_data));
+               block_hdr.size = be16_to_cpu(*(__be16 *)(mc_data));
                mc_data += sizeof(u16);
-               block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data));
+               block_hdr.flags = be16_to_cpu(*(__be16 *)(mc_data));
                mc_data += sizeof(u16);
-               block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data));
+               block_hdr.CRC = be16_to_cpu(*(__be16 *)(mc_data));
                mc_data += sizeof(u16);
 
                pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
index ae2276db77bc8ff448aeb50a4314e1723619b470..687e893d29fec6e0429e603832bc26eab3b2cbeb 100644 (file)
@@ -2628,10 +2628,11 @@ static int DRXD_init(struct drxd_state *state, const u8 *fw, u32 fw_size)
                        break;
 
                /* Apply I2c address patch to B1 */
-               if (!state->type_A && state->m_HiI2cPatch != NULL)
+               if (!state->type_A && state->m_HiI2cPatch != NULL) {
                        status = WriteTable(state, state->m_HiI2cPatch);
                        if (status < 0)
                                break;
+               }
 
                if (state->type_A) {
                        /* HI firmware patch for UIO readout,
@@ -2830,14 +2831,8 @@ static int drxd_read_status(struct dvb_frontend *fe, fe_status_t * status)
 static int drxd_init(struct dvb_frontend *fe)
 {
        struct drxd_state *state = fe->demodulator_priv;
-       int err = 0;
 
-/*     if (request_firmware(&state->fw, "drxd.fw", state->dev)<0) */
        return DRXD_init(state, NULL, 0);
-
-       err = DRXD_init(state, state->fw->data, state->fw->size);
-       release_firmware(state->fw);
-       return err;
 }
 
 static int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
index cce94a75b2e1f74c4dc05c0715f6320f130fe988..672195147d015778cefbfefd5fdbf1126e1e67be 100644 (file)
@@ -1028,7 +1028,7 @@ static int hi_command(struct drxk_state *state, u16 cmd, u16 *p_result)
                    ((state->m_hi_cfg_ctrl) &
                     SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) ==
                    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ);
-       if (powerdown_cmd == false) {
+       if (!powerdown_cmd) {
                /* Wait until command rdy */
                u32 retry_count = 0;
                u16 wait_cmd;
@@ -1129,7 +1129,7 @@ static int mpegts_configure_pins(struct drxk_state *state, bool mpeg_enable)
        if (status < 0)
                goto error;
 
-       if (mpeg_enable == false) {
+       if (!mpeg_enable) {
                /*  Set MPEG TS pads to inputmode */
                status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000);
                if (status < 0)
@@ -1190,7 +1190,7 @@ static int mpegts_configure_pins(struct drxk_state *state, bool mpeg_enable)
                if (status < 0)
                        goto error;
 
-               if (state->m_enable_parallel == true) {
+               if (state->m_enable_parallel) {
                        /* parallel -> enable MD1 to MD7 */
                        status = write16(state, SIO_PDR_MD1_CFG__A,
                                         sio_pdr_mdx_cfg);
@@ -1392,7 +1392,7 @@ static int dvbt_enable_ofdm_token_ring(struct drxk_state *state, bool enable)
 
        dprintk(1, "\n");
 
-       if (enable == false) {
+       if (!enable) {
                desired_ctrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF;
                desired_status = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN;
        }
@@ -2012,7 +2012,7 @@ static int mpegts_dto_setup(struct drxk_state *state,
                goto error;
        fec_oc_reg_mode &= (~FEC_OC_MODE_PARITY__M);
        fec_oc_reg_ipr_mode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
-       if (state->m_insert_rs_byte == true) {
+       if (state->m_insert_rs_byte) {
                /* enable parity symbol forward */
                fec_oc_reg_mode |= FEC_OC_MODE_PARITY__M;
                /* MVAL disable during parity bytes */
@@ -2023,7 +2023,7 @@ static int mpegts_dto_setup(struct drxk_state *state,
 
        /* Check serial or parallel output */
        fec_oc_reg_ipr_mode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
-       if (state->m_enable_parallel == false) {
+       if (!state->m_enable_parallel) {
                /* MPEG data output is serial -> set ipr_mode[0] */
                fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_SERIAL__M;
        }
@@ -2136,19 +2136,19 @@ static int mpegts_configure_polarity(struct drxk_state *state)
 
        /* Control selective inversion of output bits */
        fec_oc_reg_ipr_invert &= (~(invert_data_mask));
-       if (state->m_invert_data == true)
+       if (state->m_invert_data)
                fec_oc_reg_ipr_invert |= invert_data_mask;
        fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MERR__M));
-       if (state->m_invert_err == true)
+       if (state->m_invert_err)
                fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MERR__M;
        fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
-       if (state->m_invert_str == true)
+       if (state->m_invert_str)
                fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MSTRT__M;
        fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
-       if (state->m_invert_val == true)
+       if (state->m_invert_val)
                fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MVAL__M;
        fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
-       if (state->m_invert_clk == true)
+       if (state->m_invert_clk)
                fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MCLK__M;
 
        return write16(state, FEC_OC_IPR_INVERT__A, fec_oc_reg_ipr_invert);
@@ -2220,12 +2220,13 @@ static int set_agc_rf(struct drxk_state *state,
                }
 
                /* Set TOP, only if IF-AGC is in AUTO mode */
-               if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO)
+               if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO) {
                        status = write16(state,
                                         SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
                                         p_agc_cfg->top);
                        if (status < 0)
                                goto error;
+               }
 
                /* Cut-Off current */
                status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A,
@@ -3352,7 +3353,7 @@ static int dvbt_ctrl_set_inc_enable(struct drxk_state *state, bool *enabled)
        int status;
 
        dprintk(1, "\n");
-       if (*enabled == true)
+       if (*enabled)
                status = write16(state, IQM_CF_BYPASSDET__A, 0);
        else
                status = write16(state, IQM_CF_BYPASSDET__A, 1);
@@ -3368,7 +3369,7 @@ static int dvbt_ctrl_set_fr_enable(struct drxk_state *state, bool *enabled)
        int status;
 
        dprintk(1, "\n");
-       if (*enabled == true) {
+       if (*enabled) {
                /* write mask to 1 */
                status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A,
                                   DEFAULT_FR_THRES_8K);
@@ -6794,11 +6795,11 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
        state->enable_merr_cfg = config->enable_merr_cfg;
 
        if (config->dynamic_clk) {
-               state->m_dvbt_static_clk = 0;
-               state->m_dvbc_static_clk = 0;
+               state->m_dvbt_static_clk = false;
+               state->m_dvbc_static_clk = false;
        } else {
-               state->m_dvbt_static_clk = 1;
-               state->m_dvbc_static_clk = 1;
+               state->m_dvbt_static_clk = true;
+               state->m_dvbc_static_clk = true;
        }
 
 
index dfe0c2f7f1efc749b7b409cbc7bb00262e9eca37..81657e94c5a44dccb4ccea6e3164f02c67db05b5 100644 (file)
@@ -159,6 +159,7 @@ static int m88ds3103_wr_reg_val_tab(struct m88ds3103_priv *priv,
 {
        int ret, i, j;
        u8 buf[83];
+
        dev_dbg(&priv->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len);
 
        if (tab_len > 83) {
@@ -247,8 +248,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
        u8 u8tmp, u8tmp1, u8tmp2;
        u8 buf[2];
        u16 u16tmp, divide_ratio;
-       u32 tuner_frequency, target_mclk, ts_clk;
+       u32 tuner_frequency, target_mclk;
        s32 s32tmp;
+
        dev_dbg(&priv->i2c->dev,
                        "%s: delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n",
                        __func__, c->delivery_system,
@@ -316,9 +318,6 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
                                target_mclk = 144000;
                        break;
                case M88DS3103_TS_PARALLEL:
-               case M88DS3103_TS_PARALLEL_12:
-               case M88DS3103_TS_PARALLEL_16:
-               case M88DS3103_TS_PARALLEL_19_2:
                case M88DS3103_TS_CI:
                        if (c->symbol_rate < 18000000)
                                target_mclk = 96000;
@@ -352,33 +351,17 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
        switch (priv->cfg->ts_mode) {
        case M88DS3103_TS_SERIAL:
                u8tmp1 = 0x00;
-               ts_clk = 0;
-               u8tmp = 0x46;
+               u8tmp = 0x06;
                break;
        case M88DS3103_TS_SERIAL_D7:
                u8tmp1 = 0x20;
-               ts_clk = 0;
-               u8tmp = 0x46;
+               u8tmp = 0x06;
                break;
        case M88DS3103_TS_PARALLEL:
-               ts_clk = 24000;
-               u8tmp = 0x42;
-               break;
-       case M88DS3103_TS_PARALLEL_12:
-               ts_clk = 12000;
-               u8tmp = 0x42;
-               break;
-       case M88DS3103_TS_PARALLEL_16:
-               ts_clk = 16000;
-               u8tmp = 0x42;
-               break;
-       case M88DS3103_TS_PARALLEL_19_2:
-               ts_clk = 19200;
-               u8tmp = 0x42;
+               u8tmp = 0x02;
                break;
        case M88DS3103_TS_CI:
-               ts_clk = 6000;
-               u8tmp = 0x43;
+               u8tmp = 0x03;
                break;
        default:
                dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n", __func__);
@@ -386,6 +369,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
                goto err;
        }
 
+       if (priv->cfg->ts_clk_pol)
+               u8tmp |= 0x40;
+
        /* TS mode */
        ret = m88ds3103_wr_reg(priv, 0xfd, u8tmp);
        if (ret)
@@ -399,8 +385,8 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
                        goto err;
        }
 
-       if (ts_clk) {
-               divide_ratio = DIV_ROUND_UP(target_mclk, ts_clk);
+       if (priv->cfg->ts_clk) {
+               divide_ratio = DIV_ROUND_UP(target_mclk, priv->cfg->ts_clk);
                u8tmp1 = divide_ratio / 2;
                u8tmp2 = DIV_ROUND_UP(divide_ratio, 2);
        } else {
@@ -411,7 +397,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 
        dev_dbg(&priv->i2c->dev,
                        "%s: target_mclk=%d ts_clk=%d divide_ratio=%d\n",
-                       __func__, target_mclk, ts_clk, divide_ratio);
+                       __func__, target_mclk, priv->cfg->ts_clk, divide_ratio);
 
        u8tmp1--;
        u8tmp2--;
@@ -536,6 +522,7 @@ static int m88ds3103_init(struct dvb_frontend *fe)
        const struct firmware *fw = NULL;
        u8 *fw_file = M88DS3103_FIRMWARE;
        u8 u8tmp;
+
        dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
        /* set cold state by default */
@@ -648,6 +635,7 @@ static int m88ds3103_sleep(struct dvb_frontend *fe)
 {
        struct m88ds3103_priv *priv = fe->demodulator_priv;
        int ret;
+
        dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
        priv->delivery_system = SYS_UNDEFINED;
@@ -682,6 +670,7 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe)
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret;
        u8 buf[3];
+
        dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
        if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
@@ -857,6 +846,7 @@ static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr)
        u8 buf[3];
        u16 noise, signal;
        u32 noise_tot, signal_tot;
+
        dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
        /* reports SNR in resolution of 0.1 dB */
 
@@ -933,6 +923,7 @@ static int m88ds3103_read_ber(struct dvb_frontend *fe, u32 *ber)
        int ret;
        unsigned int utmp;
        u8 buf[3], u8tmp;
+
        dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
        switch (c->delivery_system) {
@@ -1013,6 +1004,7 @@ static int m88ds3103_set_tone(struct dvb_frontend *fe,
        struct m88ds3103_priv *priv = fe->demodulator_priv;
        int ret;
        u8 u8tmp, tone, reg_a1_mask;
+
        dev_dbg(&priv->i2c->dev, "%s: fe_sec_tone_mode=%d\n", __func__,
                        fe_sec_tone_mode);
 
@@ -1053,12 +1045,64 @@ err:
        return ret;
 }
 
+static int m88ds3103_set_voltage(struct dvb_frontend *fe,
+       fe_sec_voltage_t fe_sec_voltage)
+{
+       struct m88ds3103_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 u8tmp;
+       bool voltage_sel, voltage_dis;
+
+       dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__,
+                       fe_sec_voltage);
+
+       if (!priv->warm) {
+               ret = -EAGAIN;
+               goto err;
+       }
+
+       switch (fe_sec_voltage) {
+       case SEC_VOLTAGE_18:
+               voltage_sel = true;
+               voltage_dis = false;
+               break;
+       case SEC_VOLTAGE_13:
+               voltage_sel = false;
+               voltage_dis = false;
+               break;
+       case SEC_VOLTAGE_OFF:
+               voltage_sel = false;
+               voltage_dis = true;
+               break;
+       default:
+               dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_voltage\n",
+                               __func__);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* output pin polarity */
+       voltage_sel ^= priv->cfg->lnb_hv_pol;
+       voltage_dis ^= priv->cfg->lnb_en_pol;
+
+       u8tmp = voltage_dis << 1 | voltage_sel << 0;
+       ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0x03);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
 static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe,
                struct dvb_diseqc_master_cmd *diseqc_cmd)
 {
        struct m88ds3103_priv *priv = fe->demodulator_priv;
        int ret, i;
        u8 u8tmp;
+
        dev_dbg(&priv->i2c->dev, "%s: msg=%*ph\n", __func__,
                        diseqc_cmd->msg_len, diseqc_cmd->msg);
 
@@ -1130,6 +1174,7 @@ static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe,
        struct m88ds3103_priv *priv = fe->demodulator_priv;
        int ret, i;
        u8 u8tmp, burst;
+
        dev_dbg(&priv->i2c->dev, "%s: fe_sec_mini_cmd=%d\n", __func__,
                        fe_sec_mini_cmd);
 
@@ -1202,6 +1247,7 @@ static int m88ds3103_get_tune_settings(struct dvb_frontend *fe,
 static void m88ds3103_release(struct dvb_frontend *fe)
 {
        struct m88ds3103_priv *priv = fe->demodulator_priv;
+
        i2c_del_mux_adapter(priv->i2c_adapter);
        kfree(priv);
 }
@@ -1370,6 +1416,7 @@ static struct dvb_frontend_ops m88ds3103_ops = {
        .diseqc_send_burst = m88ds3103_diseqc_send_burst,
 
        .set_tone = m88ds3103_set_tone,
+       .set_voltage = m88ds3103_set_voltage,
 };
 
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
index bbb7e3aa56755f886db48ffb6e4c34897b31cb2e..9b3b4962da7c1653171c56d8f2f0dd6693a6c59d 100644 (file)
@@ -47,13 +47,22 @@ struct m88ds3103_config {
         */
 #define M88DS3103_TS_SERIAL             0 /* TS output pin D0, normal */
 #define M88DS3103_TS_SERIAL_D7          1 /* TS output pin D7 */
-#define M88DS3103_TS_PARALLEL           2 /* 24 MHz, normal */
-#define M88DS3103_TS_PARALLEL_12        3 /* 12 MHz */
-#define M88DS3103_TS_PARALLEL_16        4 /* 16 MHz */
-#define M88DS3103_TS_PARALLEL_19_2      5 /* 19.2 MHz */
-#define M88DS3103_TS_CI                 6 /* 6 MHz */
+#define M88DS3103_TS_PARALLEL           2 /* TS Parallel mode */
+#define M88DS3103_TS_CI                 3 /* TS CI Mode */
        u8 ts_mode;
 
+       /*
+        * TS clk in KHz
+        * Default: 0.
+        */
+       u32 ts_clk;
+
+       /*
+        * TS clk polarity.
+        * Default: 0. 1-active at falling edge; 0-active at rising edge.
+        */
+       u8 ts_clk_pol:1;
+
        /*
         * spectrum inversion
         * Default: 0
@@ -86,6 +95,22 @@ struct m88ds3103_config {
         * Default: none, must set
         */
        u8 agc;
+
+       /*
+        * LNB H/V pin polarity
+        * Default: 0.
+        * 1: pin high set to VOLTAGE_13, pin low to set VOLTAGE_18.
+        * 0: pin high set to VOLTAGE_18, pin low to set VOLTAGE_13.
+        */
+       u8 lnb_hv_pol:1;
+
+       /*
+        * LNB enable pin polarity
+        * Default: 0.
+        * 1: pin high to enable, pin low to disable.
+        * 0: pin high to disable, pin low to enable.
+        */
+       u8 lnb_en_pol:1;
 };
 
 /*
index 9ae40abfd71a170fe6940e372edefb1e0e558720..3ddea4471d2b6668f633a963115d02cdad067f24 100644 (file)
@@ -28,7 +28,7 @@
 #include "mb86a16.h"
 #include "mb86a16_priv.h"
 
-unsigned int verbose = 5;
+static unsigned int verbose = 5;
 module_param(verbose, int, 0644);
 
 #define ABS(x)         ((x) < 0 ? (-x) : (x))
@@ -115,9 +115,11 @@ static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val)
        };
        ret = i2c_transfer(state->i2c_adap, msg, 2);
        if (ret != 2) {
-               dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)",
+               dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=%i)",
                        reg, ret);
 
+               if (ret < 0)
+                       return ret;
                return -EREMOTEIO;
        }
        *val = b1[0];
index b931179c70a48e767848f2fdc43e37ed2aaba5bf..e6f165a5b90d7630a3543966c2b679db4128cf5c 100644 (file)
@@ -33,7 +33,7 @@ enum mb86a20s_bandwidth {
        MB86A20S_3SEG = 3,
 };
 
-u8 mb86a20s_subchannel[] = {
+static u8 mb86a20s_subchannel[] = {
        0xb0, 0xc0, 0xd0, 0xe0,
        0xf0, 0x00, 0x10, 0x20,
 };
@@ -1228,7 +1228,7 @@ struct linear_segments {
  * All tables below return a dB/1000 measurement
  */
 
-static struct linear_segments cnr_to_db_table[] = {
+static const struct linear_segments cnr_to_db_table[] = {
        { 19648,     0},
        { 18187,  1000},
        { 16534,  2000},
@@ -1262,7 +1262,7 @@ static struct linear_segments cnr_to_db_table[] = {
        {   788, 30000},
 };
 
-static struct linear_segments cnr_64qam_table[] = {
+static const struct linear_segments cnr_64qam_table[] = {
        { 3922688,     0},
        { 3920384,  1000},
        { 3902720,  2000},
@@ -1296,7 +1296,7 @@ static struct linear_segments cnr_64qam_table[] = {
        {  388864, 30000},
 };
 
-static struct linear_segments cnr_16qam_table[] = {
+static const struct linear_segments cnr_16qam_table[] = {
        { 5314816,     0},
        { 5219072,  1000},
        { 5118720,  2000},
@@ -1330,7 +1330,7 @@ static struct linear_segments cnr_16qam_table[] = {
        {   95744, 30000},
 };
 
-struct linear_segments cnr_qpsk_table[] = {
+static const struct linear_segments cnr_qpsk_table[] = {
        { 2834176,     0},
        { 2683648,  1000},
        { 2536960,  2000},
@@ -1364,7 +1364,7 @@ struct linear_segments cnr_qpsk_table[] = {
        {   11520, 30000},
 };
 
-static u32 interpolate_value(u32 value, struct linear_segments *segments,
+static u32 interpolate_value(u32 value, const struct linear_segments *segments,
                             unsigned len)
 {
        u64 tmp64;
@@ -1448,7 +1448,7 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe)
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u32 mer, cnr;
        int rc, val, layer;
-       struct linear_segments *segs;
+       const struct linear_segments *segs;
        unsigned segs_len;
 
        dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
index a74ac0ddb83310ab619870a0f465771ca451eb7a..2163490c1e6b23758cf8efcf3c14e60413e8ed45 100644 (file)
@@ -103,7 +103,7 @@ static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
 
        if (1 + count > sizeof(buf)) {
                printk(KERN_WARNING
-                      "mt312: write: len=%zd is too big!\n", count);
+                      "mt312: write: len=%zu is too big!\n", count);
                return -EINVAL;
        }
 
index 10cfc05791689323b0d4ab5b967eb22ff7e9e1db..873ea1da844b3b89940cff3a3082c9172b76b629 100644 (file)
@@ -111,7 +111,7 @@ static int or51211_load_firmware (struct dvb_frontend* fe,
        u8 tudata[585];
        int i;
 
-       dprintk("Firmware is %zd bytes\n",fw->size);
+       dprintk("Firmware is %zu bytes\n", fw->size);
 
        /* Get eprom data */
        tudata[0] = 17;
index fdbed35c87fa08472dbce4c2b016a7edd6231dd2..eb737cf29a36bf2487d97e6ae2462a15defe3e78 100644 (file)
@@ -936,7 +936,7 @@ static void rtl2832_i2c_gate_work(struct work_struct *work)
        if (ret != 1)
                goto err;
 
-       priv->i2c_gate_state = 0;
+       priv->i2c_gate_state = false;
 
        return;
 err:
index 023e0f49c786e732450b346ce50df9c7a1985e50..7bf98cf6bbe172715b3b2923fe771c35b5c5247b 100644 (file)
@@ -329,7 +329,7 @@ static int rtl2832_sdr_rd_reg_mask(struct rtl2832_sdr_state *s, u16 reg,
 static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf(
                struct rtl2832_sdr_state *s)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
        struct rtl2832_sdr_frame_buf *buf = NULL;
 
        spin_lock_irqsave(&s->queued_bufs_lock, flags);
@@ -365,17 +365,19 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
                dst_len = 0;
        }
 
-       /* calculate samping rate and output it in 10 seconds intervals */
+       /* calculate sample rate and output it in 10 seconds intervals */
        if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
-#define MSECS 10000UL
+               #define MSECS 10000UL
+               unsigned int msecs = jiffies_to_msecs(jiffies -
+                               s->jiffies_next + msecs_to_jiffies(MSECS));
                unsigned int samples = s->sample - s->sample_measured;
 
                s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
                s->sample_measured = s->sample;
                dev_dbg(&s->udev->dev,
-                               "slen=%d samples=%u msecs=%lu sampling rate=%lu\n",
-                               src_len, samples, MSECS,
-                               samples * 1000UL / MSECS);
+                               "slen=%u samples=%u msecs=%u sample rate=%lu\n",
+                               src_len, samples, msecs,
+                               samples * 1000UL / msecs);
        }
 
        /* total number of I+Q pairs */
@@ -394,8 +396,8 @@ static void rtl2832_sdr_urb_complete(struct urb *urb)
        struct rtl2832_sdr_frame_buf *fbuf;
 
        dev_dbg_ratelimited(&s->udev->dev,
-                       "%s: status=%d length=%d/%d errors=%d\n",
-                       __func__, urb->status, urb->actual_length,
+                       "status=%d length=%d/%d errors=%d\n",
+                       urb->status, urb->actual_length,
                        urb->transfer_buffer_length, urb->error_count);
 
        switch (urb->status) {
@@ -443,7 +445,7 @@ static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_state *s)
        int i;
 
        for (i = s->urbs_submitted - 1; i >= 0; i--) {
-               dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i);
+               dev_dbg(&s->udev->dev, "kill urb=%d\n", i);
                /* stop the URB */
                usb_kill_urb(s->urb_list[i]);
        }
@@ -457,7 +459,7 @@ static int rtl2832_sdr_submit_urbs(struct rtl2832_sdr_state *s)
        int i, ret;
 
        for (i = 0; i < s->urbs_initialized; i++) {
-               dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i);
+               dev_dbg(&s->udev->dev, "submit urb=%d\n", i);
                ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC);
                if (ret) {
                        dev_err(&s->udev->dev,
@@ -477,8 +479,7 @@ static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_state *s)
        if (s->flags & USB_STATE_URB_BUF) {
                while (s->buf_num) {
                        s->buf_num--;
-                       dev_dbg(&s->udev->dev, "%s: free buf=%d\n",
-                                       __func__, s->buf_num);
+                       dev_dbg(&s->udev->dev, "free buf=%d\n", s->buf_num);
                        usb_free_coherent(s->udev, s->buf_size,
                                          s->buf_list[s->buf_num],
                                          s->dma_addr[s->buf_num]);
@@ -494,24 +495,22 @@ static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_state *s)
        s->buf_num = 0;
        s->buf_size = BULK_BUFFER_SIZE;
 
-       dev_dbg(&s->udev->dev,
-                       "%s: all in all I will use %u bytes for streaming\n",
-                       __func__,  MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+       dev_dbg(&s->udev->dev, "all in all I will use %u bytes for streaming\n",
+                       MAX_BULK_BUFS * BULK_BUFFER_SIZE);
 
        for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) {
                s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev,
                                BULK_BUFFER_SIZE, GFP_ATOMIC,
                                &s->dma_addr[s->buf_num]);
                if (!s->buf_list[s->buf_num]) {
-                       dev_dbg(&s->udev->dev, "%s: alloc buf=%d failed\n",
-                                       __func__, s->buf_num);
+                       dev_dbg(&s->udev->dev, "alloc buf=%d failed\n",
+                                       s->buf_num);
                        rtl2832_sdr_free_stream_bufs(s);
                        return -ENOMEM;
                }
 
-               dev_dbg(&s->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
-                               __func__, s->buf_num,
-                               s->buf_list[s->buf_num],
+               dev_dbg(&s->udev->dev, "alloc buf=%d %p (dma %llu)\n",
+                               s->buf_num, s->buf_list[s->buf_num],
                                (long long)s->dma_addr[s->buf_num]);
                s->flags |= USB_STATE_URB_BUF;
        }
@@ -527,8 +526,7 @@ static int rtl2832_sdr_free_urbs(struct rtl2832_sdr_state *s)
 
        for (i = s->urbs_initialized - 1; i >= 0; i--) {
                if (s->urb_list[i]) {
-                       dev_dbg(&s->udev->dev, "%s: free urb=%d\n",
-                                       __func__, i);
+                       dev_dbg(&s->udev->dev, "free urb=%d\n", i);
                        /* free the URBs */
                        usb_free_urb(s->urb_list[i]);
                }
@@ -544,10 +542,10 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s)
 
        /* allocate the URBs */
        for (i = 0; i < MAX_BULK_BUFS; i++) {
-               dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+               dev_dbg(&s->udev->dev, "alloc urb=%d\n", i);
                s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
                if (!s->urb_list[i]) {
-                       dev_dbg(&s->udev->dev, "%s: failed\n", __func__);
+                       dev_dbg(&s->udev->dev, "failed\n");
                        for (j = 0; j < i; j++)
                                usb_free_urb(s->urb_list[j]);
                        return -ENOMEM;
@@ -570,9 +568,9 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s)
 /* Must be called with vb_queue_lock hold */
 static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        spin_lock_irqsave(&s->queued_bufs_lock, flags);
        while (!list_empty(&s->queued_bufs)) {
@@ -591,7 +589,7 @@ static void rtl2832_sdr_release_sec(struct dvb_frontend *fe)
 {
        struct rtl2832_sdr_state *s = fe->sec_priv;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        mutex_lock(&s->vb_queue_lock);
        mutex_lock(&s->v4l2_lock);
@@ -613,7 +611,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh,
 {
        struct rtl2832_sdr_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
        strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
@@ -631,15 +629,15 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq,
 {
        struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
 
-       dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
+       dev_dbg(&s->udev->dev, "nbuffers=%d\n", *nbuffers);
 
        /* Need at least 8 buffers */
        if (vq->num_buffers + *nbuffers < 8)
                *nbuffers = 8 - vq->num_buffers;
        *nplanes = 1;
        sizes[0] = PAGE_ALIGN(s->buffersize);
-       dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
-                       __func__, *nbuffers, sizes[0]);
+       dev_dbg(&s->udev->dev, "nbuffers=%d sizes[0]=%d\n",
+                       *nbuffers, sizes[0]);
        return 0;
 }
 
@@ -659,7 +657,7 @@ static void rtl2832_sdr_buf_queue(struct vb2_buffer *vb)
        struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue);
        struct rtl2832_sdr_frame_buf *buf =
                        container_of(vb, struct rtl2832_sdr_frame_buf, vb);
-       unsigned long flags = 0;
+       unsigned long flags;
 
        /* Check the device has not disconnected between prep and queuing */
        if (!s->udev) {
@@ -681,7 +679,7 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
        u64 u64tmp;
        u32 u32tmp;
 
-       dev_dbg(&s->udev->dev, "%s: f_adc=%u\n", __func__, s->f_adc);
+       dev_dbg(&s->udev->dev, "f_adc=%u\n", s->f_adc);
 
        if (!test_bit(POWER_ON, &s->flags))
                return 0;
@@ -715,8 +713,7 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
        u64tmp = -u64tmp;
        u32tmp = u64tmp & 0x3fffff;
 
-       dev_dbg(&s->udev->dev, "%s: f_if=%u if_ctl=%08x\n",
-                       __func__, f_if, u32tmp);
+       dev_dbg(&s->udev->dev, "f_if=%u if_ctl=%08x\n", f_if, u32tmp);
 
        buf[0] = (u32tmp >> 16) & 0xff;
        buf[1] = (u32tmp >>  8) & 0xff;
@@ -903,7 +900,7 @@ static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_state *s)
 {
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        /* PID filter */
        ret = rtl2832_sdr_wr_regs(s, 0x061, "\xe0", 1);
@@ -964,8 +961,8 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s)
        c->frequency = s->f_tuner;
        c->delivery_system = SYS_DVBT;
 
-       dev_dbg(&s->udev->dev, "%s: frequency=%u bandwidth=%d\n",
-                       __func__, c->frequency, c->bandwidth_hz);
+       dev_dbg(&s->udev->dev, "frequency=%u bandwidth=%d\n",
+                       c->frequency, c->bandwidth_hz);
 
        if (!test_bit(POWER_ON, &s->flags))
                return 0;
@@ -980,7 +977,7 @@ static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s)
 {
        struct dvb_frontend *fe = s->fe;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        if (fe->ops.tuner_ops.init)
                fe->ops.tuner_ops.init(fe);
@@ -992,7 +989,7 @@ static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_state *s)
 {
        struct dvb_frontend *fe = s->fe;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        if (fe->ops.tuner_ops.sleep)
                fe->ops.tuner_ops.sleep(fe);
@@ -1005,7 +1002,7 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
        struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        if (!s->udev)
                return -ENODEV;
@@ -1054,7 +1051,7 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
 {
        struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        mutex_lock(&s->v4l2_lock);
 
@@ -1088,8 +1085,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
 {
        struct rtl2832_sdr_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s: index=%d type=%d\n",
-                       __func__, v->index, v->type);
+       dev_dbg(&s->udev->dev, "index=%d type=%d\n", v->index, v->type);
 
        if (v->index == 0) {
                strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name));
@@ -1115,7 +1111,7 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
 {
        struct rtl2832_sdr_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        if (v->index > 1)
                return -EINVAL;
@@ -1127,8 +1123,8 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
 {
        struct rtl2832_sdr_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
-                       __func__, band->tuner, band->type, band->index);
+       dev_dbg(&s->udev->dev, "tuner=%d type=%d index=%d\n",
+                       band->tuner, band->type, band->index);
 
        if (band->tuner == 0) {
                if (band->index >= ARRAY_SIZE(bands_adc))
@@ -1153,8 +1149,8 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
        struct rtl2832_sdr_state *s = video_drvdata(file);
        int ret  = 0;
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
-                       __func__, f->tuner, f->type);
+       dev_dbg(&s->udev->dev, "tuner=%d type=%d\n",
+                       f->tuner, f->type);
 
        if (f->tuner == 0) {
                f->frequency = s->f_adc;
@@ -1175,8 +1171,8 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
        struct rtl2832_sdr_state *s = video_drvdata(file);
        int ret, band;
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
-                       __func__, f->tuner, f->type, f->frequency);
+       dev_dbg(&s->udev->dev, "tuner=%d type=%d frequency=%u\n",
+                       f->tuner, f->type, f->frequency);
 
        /* ADC band midpoints */
        #define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2)
@@ -1194,15 +1190,13 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
                                bands_adc[band].rangelow,
                                bands_adc[band].rangehigh);
 
-               dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
-                               __func__, s->f_adc);
+               dev_dbg(&s->udev->dev, "ADC frequency=%u Hz\n", s->f_adc);
                ret = rtl2832_sdr_set_adc(s);
        } else if (f->tuner == 1) {
                s->f_tuner = clamp_t(unsigned int, f->frequency,
                                bands_fm[0].rangelow,
                                bands_fm[0].rangehigh);
-               dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n",
-                               __func__, f->frequency);
+               dev_dbg(&s->udev->dev, "RF frequency=%u Hz\n", f->frequency);
 
                ret = rtl2832_sdr_set_tuner_freq(s);
        } else {
@@ -1217,7 +1211,7 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv,
 {
        struct rtl2832_sdr_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        if (f->index >= s->num_formats)
                return -EINVAL;
@@ -1233,7 +1227,7 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
 {
        struct rtl2832_sdr_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        f->fmt.sdr.pixelformat = s->pixelformat;
        f->fmt.sdr.buffersize = s->buffersize;
@@ -1250,7 +1244,7 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
        struct vb2_queue *q = &s->vb_queue;
        int i;
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+       dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n",
                        (char *)&f->fmt.sdr.pixelformat);
 
        if (vb2_is_busy(q))
@@ -1280,7 +1274,7 @@ static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv,
        struct rtl2832_sdr_state *s = video_drvdata(file);
        int i;
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+       dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n",
                        (char *)&f->fmt.sdr.pixelformat);
 
        memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
@@ -1354,8 +1348,8 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
        int ret;
 
        dev_dbg(&s->udev->dev,
-                       "%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
-                       __func__, ctrl->id, ctrl->name, ctrl->val,
+                       "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
+                       ctrl->id, ctrl->name, ctrl->val,
                        ctrl->minimum, ctrl->maximum, ctrl->step);
 
        switch (ctrl->id) {
@@ -1432,7 +1426,7 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
        s->pixelformat = formats[0].pixelformat;
        s->buffersize = formats[0].buffersize;
        s->num_formats = NUM_FORMATS;
-       if (rtl2832_sdr_emulated_fmt == false)
+       if (!rtl2832_sdr_emulated_fmt)
                s->num_formats -= 1;
 
        mutex_init(&s->v4l2_lock);
index 3a2d6c5aded6b450be22afe3e54443f254d78c95..98ddb49ad52b1a27a268ef6fabab3d3de97496e7 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Driver for Silicon Labs SI2165 DVB-C/-T Demodulator
+    Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator
 
     Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org>
 
@@ -44,9 +44,7 @@ struct si2165_state {
 
        struct si2165_config config;
 
-       /* chip revision */
-       u8 revcode;
-       /* chip type */
+       u8 chip_revcode;
        u8 chip_type;
 
        /* calculated by xtal and div settings */
@@ -312,7 +310,7 @@ static u32 si2165_get_fe_clk(struct si2165_state *state)
        return state->adc_clk;
 }
 
-static bool si2165_wait_init_done(struct si2165_state *state)
+static int si2165_wait_init_done(struct si2165_state *state)
 {
        int ret = -EINVAL;
        u8 val = 0;
@@ -407,7 +405,7 @@ static int si2165_upload_firmware(struct si2165_state *state)
        int ret;
 
        const struct firmware *fw = NULL;
-       u8 *fw_file = SI2165_FIRMWARE;
+       u8 *fw_file;
        const u8 *data;
        u32 len;
        u32 offset;
@@ -415,10 +413,20 @@ static int si2165_upload_firmware(struct si2165_state *state)
        u8 block_count;
        u16 crc_expected;
 
+       switch (state->chip_revcode) {
+       case 0x03: /* revision D */
+               fw_file = SI2165_FIRMWARE_REV_D;
+               break;
+       default:
+               dev_info(&state->i2c->dev, "%s: no firmware file for revision=%d\n",
+                       KBUILD_MODNAME, state->chip_revcode);
+               return 0;
+       }
+
        /* request the firmware, this will block and timeout */
        ret = request_firmware(&fw, fw_file, state->i2c->dev.parent);
        if (ret) {
-               dev_warn(&state->i2c->dev, "%s: firmare file '%s' not found\n",
+               dev_warn(&state->i2c->dev, "%s: firmware file '%s' not found\n",
                                KBUILD_MODNAME, fw_file);
                goto error;
        }
@@ -908,7 +916,7 @@ static void si2165_release(struct dvb_frontend *fe)
 
 static struct dvb_frontend_ops si2165_ops = {
        .info = {
-               .name = "Silicon Labs Si2165",
+               .name = "Silicon Labs ",
                .caps = FE_CAN_FEC_1_2 |
                        FE_CAN_FEC_2_3 |
                        FE_CAN_FEC_3_4 |
@@ -948,6 +956,8 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
        int n;
        int io_ret;
        u8 val;
+       char rev_char;
+       const char *chip_name;
 
        if (config == NULL || i2c == NULL)
                goto error;
@@ -984,7 +994,7 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
        if (val != state->config.chip_mode)
                goto error;
 
-       io_ret = si2165_readreg8(state, 0x0023 , &state->revcode);
+       io_ret = si2165_readreg8(state, 0x0023, &state->chip_revcode);
        if (io_ret < 0)
                goto error;
 
@@ -997,22 +1007,35 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
        if (io_ret < 0)
                goto error;
 
-       dev_info(&state->i2c->dev, "%s: hardware revision 0x%02x, chip type 0x%02x\n",
-                KBUILD_MODNAME, state->revcode, state->chip_type);
+       if (state->chip_revcode < 26)
+               rev_char = 'A' + state->chip_revcode;
+       else
+               rev_char = '?';
 
-       /* It is a guess that register 0x0118 (chip type?) can be used to
-        * differ between si2161, si2163 and si2165
-        * Only si2165 has been tested.
-        */
-       if (state->revcode == 0x03 && state->chip_type == 0x07) {
+       switch (state->chip_type) {
+       case 0x06:
+               chip_name = "Si2161";
+               state->has_dvbt = true;
+               break;
+       case 0x07:
+               chip_name = "Si2165";
                state->has_dvbt = true;
                state->has_dvbc = true;
-       } else {
-               dev_err(&state->i2c->dev, "%s: Unsupported chip.\n",
-                       KBUILD_MODNAME);
+               break;
+       default:
+               dev_err(&state->i2c->dev, "%s: Unsupported Silicon Labs chip (type %d, rev %d)\n",
+                       KBUILD_MODNAME, state->chip_type, state->chip_revcode);
                goto error;
        }
 
+       dev_info(&state->i2c->dev,
+               "%s: Detected Silicon Labs %s-%c (type %d, rev %d)\n",
+               KBUILD_MODNAME, chip_name, rev_char, state->chip_type,
+               state->chip_revcode);
+
+       strlcat(state->frontend.ops.info.name, chip_name,
+                       sizeof(state->frontend.ops.info.name));
+
        n = 0;
        if (state->has_dvbt) {
                state->frontend.ops.delsys[n++] = SYS_DVBT;
@@ -1037,4 +1060,4 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 MODULE_DESCRIPTION("Silicon Labs Si2165 DVB-C/-T Demodulator driver");
 MODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>");
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(SI2165_FIRMWARE);
+MODULE_FIRMWARE(SI2165_FIRMWARE_REV_D);
index d4cc93fe1096ea31f5d67d7820c845986f4184c4..2b70cf12cd797799eaa1c7bfd7299428a562446a 100644 (file)
@@ -18,6 +18,6 @@
 #ifndef _DVB_SI2165_PRIV
 #define _DVB_SI2165_PRIV
 
-#define SI2165_FIRMWARE "dvb-demod-si2165.fw"
+#define SI2165_FIRMWARE_REV_D "dvb-demod-si2165.fw"
 
 #endif /* _DVB_SI2165_PRIV */
index 8f81d979de30541b31fb6f56559ef2c56aeb62ea..1cd93be281ed4d42194d15d2535bd86dd5eb638d 100644 (file)
@@ -55,8 +55,7 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
                                break;
                }
 
-               dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n",
-                               __func__,
+               dev_dbg(&s->client->dev, "cmd execution took %d ms\n",
                                jiffies_to_msecs(jiffies) -
                                (jiffies_to_msecs(timeout) - TIMEOUT));
 
@@ -75,7 +74,7 @@ err_mutex_unlock:
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -150,12 +149,12 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
                c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
        }
 
-       dev_dbg(&s->client->dev, "%s: status=%02x args=%*ph\n",
-                       __func__, *status, cmd.rlen, cmd.args);
+       dev_dbg(&s->client->dev, "status=%02x args=%*ph\n",
+                       *status, cmd.rlen, cmd.args);
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -168,10 +167,10 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
        u8 bandwidth, delivery_system;
 
        dev_dbg(&s->client->dev,
-                       "%s: delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u\n",
-                       __func__, c->delivery_system, c->modulation,
+                       "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u, stream_id=%d\n",
+                       c->delivery_system, c->modulation,
                        c->frequency, c->bandwidth_hz, c->symbol_rate,
-                       c->inversion);
+                       c->inversion, c->stream_id);
 
        if (!s->active) {
                ret = -EAGAIN;
@@ -235,6 +234,18 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
        if (ret)
                goto err;
 
+       if (c->delivery_system == SYS_DVBT2) {
+               /* select PLP */
+               cmd.args[0] = 0x52;
+               cmd.args[1] = c->stream_id & 0xff;
+               cmd.args[2] = c->stream_id == NO_STREAM_ID_FILTER ? 0 : 1;
+               cmd.wlen = 3;
+               cmd.rlen = 1;
+               ret = si2168_cmd_execute(s, &cmd);
+               if (ret)
+                       goto err;
+       }
+
        memcpy(cmd.args, "\x51\x03", 2);
        cmd.wlen = 2;
        cmd.rlen = 12;
@@ -297,13 +308,6 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
        if (ret)
                goto err;
 
-       memcpy(cmd.args, "\x14\x00\x01\x10\x16\x00", 6);
-       cmd.wlen = 6;
-       cmd.rlen = 4;
-       ret = si2168_cmd_execute(s, &cmd);
-       if (ret)
-               goto err;
-
        memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x18", 6);
        cmd.wlen = 6;
        cmd.rlen = 4;
@@ -343,7 +347,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -357,8 +361,9 @@ static int si2168_init(struct dvb_frontend *fe)
        struct si2168_cmd cmd;
        unsigned int chip_id;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
+       /* initialize */
        memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13);
        cmd.wlen = 13;
        cmd.rlen = 0;
@@ -366,6 +371,26 @@ static int si2168_init(struct dvb_frontend *fe)
        if (ret)
                goto err;
 
+       if (s->fw_loaded) {
+               /* resume */
+               memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8);
+               cmd.wlen = 8;
+               cmd.rlen = 1;
+               ret = si2168_cmd_execute(s, &cmd);
+               if (ret)
+                       goto err;
+
+               memcpy(cmd.args, "\x85", 1);
+               cmd.wlen = 1;
+               cmd.rlen = 1;
+               ret = si2168_cmd_execute(s, &cmd);
+               if (ret)
+                       goto err;
+
+               goto warm;
+       }
+
+       /* power up */
        memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8);
        cmd.wlen = 8;
        cmd.rlen = 1;
@@ -400,16 +425,16 @@ static int si2168_init(struct dvb_frontend *fe)
                break;
        default:
                dev_err(&s->client->dev,
-                               "%s: unkown chip version Si21%d-%c%c%c\n",
-                               KBUILD_MODNAME, cmd.args[2], cmd.args[1],
+                               "unknown chip version Si21%d-%c%c%c\n",
+                               cmd.args[2], cmd.args[1],
                                cmd.args[3], cmd.args[4]);
                ret = -EINVAL;
                goto err;
        }
 
        /* cold state - try to download firmware */
-       dev_info(&s->client->dev, "%s: found a '%s' in cold state\n",
-                       KBUILD_MODNAME, si2168_ops.info.name);
+       dev_info(&s->client->dev, "found a '%s' in cold state\n",
+                       si2168_ops.info.name);
 
        /* request the firmware, this will block and timeout */
        ret = request_firmware(&fw, fw_file, &s->client->dev);
@@ -422,18 +447,18 @@ static int si2168_init(struct dvb_frontend *fe)
 
                if (ret == 0) {
                        dev_notice(&s->client->dev,
-                                       "%s: please install firmware file '%s'\n",
-                                       KBUILD_MODNAME, SI2168_B40_FIRMWARE);
+                                       "please install firmware file '%s'\n",
+                                       SI2168_B40_FIRMWARE);
                } else {
                        dev_err(&s->client->dev,
-                                       "%s: firmware file '%s' not found\n",
-                                       KBUILD_MODNAME, fw_file);
+                                       "firmware file '%s' not found\n",
+                                       fw_file);
                        goto err;
                }
        }
 
-       dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n",
-                       KBUILD_MODNAME, fw_file);
+       dev_info(&s->client->dev, "downloading firmware from file '%s'\n",
+                       fw_file);
 
        for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) {
                len = remaining;
@@ -446,8 +471,8 @@ static int si2168_init(struct dvb_frontend *fe)
                ret = si2168_cmd_execute(s, &cmd);
                if (ret) {
                        dev_err(&s->client->dev,
-                                       "%s: firmware download failed=%d\n",
-                                       KBUILD_MODNAME, ret);
+                                       "firmware download failed=%d\n",
+                                       ret);
                        goto err;
                }
        }
@@ -462,8 +487,20 @@ static int si2168_init(struct dvb_frontend *fe)
        if (ret)
                goto err;
 
-       dev_info(&s->client->dev, "%s: found a '%s' in warm state\n",
-                       KBUILD_MODNAME, si2168_ops.info.name);
+       /* set ts mode */
+       memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
+       cmd.args[4] |= s->ts_mode;
+       cmd.wlen = 6;
+       cmd.rlen = 4;
+       ret = si2168_cmd_execute(s, &cmd);
+       if (ret)
+               goto err;
+
+       s->fw_loaded = true;
+
+warm:
+       dev_info(&s->client->dev, "found a '%s' in warm state\n",
+                       si2168_ops.info.name);
 
        s->active = true;
 
@@ -472,7 +509,7 @@ err:
        if (fw)
                release_firmware(fw);
 
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -482,7 +519,7 @@ static int si2168_sleep(struct dvb_frontend *fe)
        int ret;
        struct si2168_cmd cmd;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
        s->active = false;
 
@@ -495,7 +532,7 @@ static int si2168_sleep(struct dvb_frontend *fe)
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -528,8 +565,7 @@ static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
        /* open tuner I2C gate */
        ret = __i2c_transfer(s->client->adapter, &gate_open_msg, 1);
        if (ret != 1) {
-               dev_warn(&s->client->dev, "%s: i2c write failed=%d\n",
-                               KBUILD_MODNAME, ret);
+               dev_warn(&s->client->dev, "i2c write failed=%d\n", ret);
                if (ret >= 0)
                        ret = -EREMOTEIO;
        } else {
@@ -553,8 +589,7 @@ static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
        /* close tuner I2C gate */
        ret = __i2c_transfer(s->client->adapter, &gate_close_msg, 1);
        if (ret != 1) {
-               dev_warn(&s->client->dev, "%s: i2c write failed=%d\n",
-                               KBUILD_MODNAME, ret);
+               dev_warn(&s->client->dev, "i2c write failed=%d\n", ret);
                if (ret >= 0)
                        ret = -EREMOTEIO;
        } else {
@@ -587,7 +622,8 @@ static const struct dvb_frontend_ops si2168_ops = {
                        FE_CAN_GUARD_INTERVAL_AUTO |
                        FE_CAN_HIERARCHY_AUTO |
                        FE_CAN_MUTE_TS |
-                       FE_CAN_2G_MODULATION
+                       FE_CAN_2G_MODULATION |
+                       FE_CAN_MULTISTREAM
        },
 
        .get_tune_settings = si2168_get_tune_settings,
@@ -607,12 +643,12 @@ static int si2168_probe(struct i2c_client *client,
        struct si2168 *s;
        int ret;
 
-       dev_dbg(&client->dev, "%s:\n", __func__);
+       dev_dbg(&client->dev, "\n");
 
        s = kzalloc(sizeof(struct si2168), GFP_KERNEL);
        if (!s) {
                ret = -ENOMEM;
-               dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+               dev_err(&client->dev, "kzalloc() failed\n");
                goto err;
        }
 
@@ -633,16 +669,17 @@ static int si2168_probe(struct i2c_client *client,
 
        *config->i2c_adapter = s->adapter;
        *config->fe = &s->fe;
+       s->ts_mode = config->ts_mode;
+       s->fw_loaded = false;
 
        i2c_set_clientdata(client, s);
 
        dev_info(&s->client->dev,
-                       "%s: Silicon Labs Si2168 successfully attached\n",
-                       KBUILD_MODNAME);
+                       "Silicon Labs Si2168 successfully attached\n");
        return 0;
 err:
        kfree(s);
-       dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -650,7 +687,7 @@ static int si2168_remove(struct i2c_client *client)
 {
        struct si2168 *s = i2c_get_clientdata(client);
 
-       dev_dbg(&client->dev, "%s:\n", __func__);
+       dev_dbg(&client->dev, "\n");
 
        i2c_del_mux_adapter(s->adapter);
 
index 3c5b5ab01796c69c2cf955e81756ccda08a3108e..e086d671945167046f18a62e4f6cac6131950bda 100644 (file)
@@ -34,6 +34,12 @@ struct si2168_config {
         * returned by driver
         */
        struct i2c_adapter **i2c_adapter;
+
+       /* TS mode */
+       u8 ts_mode;
 };
 
+#define SI2168_TS_PARALLEL     0x06
+#define SI2168_TS_SERIAL       0x03
+
 #endif
index ebbf502ec313cff28deecb7c2531ac8a04cbc75c..e13983ed4be1a077e3b04b896c46870e8aad7a60 100644 (file)
@@ -36,6 +36,8 @@ struct si2168 {
        fe_delivery_system_t delivery_system;
        fe_status_t fe_status;
        bool active;
+       bool fw_loaded;
+       u8 ts_mode;
 };
 
 /* firmare command struct */
index 73b47cc6a13b3b8c2f6ca85d0ee1d9eee71120c1..16850e2bf02fe37bccc4c54af466a43f5dd61b85 100644 (file)
@@ -236,6 +236,9 @@ static int si21_writeregs(struct si21xx_state *state, u8 reg1,
                                .len = len + 1
        };
 
+       if (len > sizeof(buf) - 1)
+               return -EINVAL;
+
        msg.buf[0] =  reg1;
        memcpy(msg.buf + 1, data, len);
 
diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c
new file mode 100644 (file)
index 0000000..9b684d5
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * CIMaX SP2/SP2HF (Atmel T90FJR) CI driver
+ *
+ * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi>
+ *
+ * Heavily based on CIMax2(R) SP2 driver in conjunction with NetUp Dual
+ * DVB-S2 CI card (cimax2) with following copyrights:
+ *
+ *  Copyright (C) 2009 NetUP Inc.
+ *  Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *  Copyright (C) 2009 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.
+ */
+
+#include "sp2_priv.h"
+
+static int sp2_read_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
+{
+       int ret;
+       struct i2c_client *client = s->client;
+       struct i2c_adapter *adap = client->adapter;
+       struct i2c_msg msg[] = {
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .buf = &reg,
+                       .len = 1
+               }, {
+                       .addr = client->addr,
+                       .flags  = I2C_M_RD,
+                       .buf = buf,
+                       .len = len
+               }
+       };
+
+       ret = i2c_transfer(adap, msg, 2);
+
+       if (ret != 2) {
+               dev_err(&client->dev, "i2c read error, reg = 0x%02x, status = %d\n",
+                               reg, ret);
+               if (ret < 0)
+                       return ret;
+               else
+                       return -EIO;
+       }
+
+       dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %02x\n",
+                               client->addr, reg, buf[0]);
+
+       return 0;
+}
+
+static int sp2_write_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
+{
+       int ret;
+       u8 buffer[35];
+       struct i2c_client *client = s->client;
+       struct i2c_adapter *adap = client->adapter;
+       struct i2c_msg msg = {
+               .addr = client->addr,
+               .flags = 0,
+               .buf = &buffer[0],
+               .len = len + 1
+       };
+
+       if ((len + 1) > sizeof(buffer)) {
+               dev_err(&client->dev, "i2c wr reg=%02x: len=%d is too big!\n",
+                               reg, len);
+               return -EINVAL;
+       }
+
+       buffer[0] = reg;
+       memcpy(&buffer[1], buf, len);
+
+       ret = i2c_transfer(adap, &msg, 1);
+
+       if (ret != 1) {
+               dev_err(&client->dev, "i2c write error, reg = 0x%02x, status = %d\n",
+                               reg, ret);
+               if (ret < 0)
+                       return ret;
+               else
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs,
+                       u8 read, int addr, u8 data)
+{
+       struct sp2 *s = en50221->data;
+       u8 store;
+       int mem, ret;
+       int (*ci_op_cam)(void*, u8, int, u8, int*) = s->ci_control;
+
+       dev_dbg(&s->client->dev, "slot=%d, acs=0x%02x, addr=0x%04x, data = 0x%02x",
+                       slot, acs, addr, data);
+
+       if (slot != 0)
+               return -EINVAL;
+
+       /*
+        * change module access type between IO space and attribute memory
+        * when needed
+        */
+       if (s->module_access_type != acs) {
+               ret = sp2_read_i2c(s, 0x00, &store, 1);
+
+               if (ret)
+                       return ret;
+
+               store &= ~(SP2_MOD_CTL_ACS1 | SP2_MOD_CTL_ACS0);
+               store |= acs;
+
+               ret = sp2_write_i2c(s, 0x00, &store, 1);
+               if (ret)
+                       return ret;
+       }
+
+       s->module_access_type = acs;
+
+       /* implementation of ci_op_cam is device specific */
+       if (ci_op_cam) {
+               ret = ci_op_cam(s->priv, read, addr, data, &mem);
+       } else {
+               dev_err(&s->client->dev, "callback not defined");
+               return -EINVAL;
+       }
+
+       if (ret)
+               return ret;
+
+       if (read) {
+               dev_dbg(&s->client->dev, "cam read, addr=0x%04x, data = 0x%04x",
+                               addr, mem);
+               return mem;
+       } else {
+               return 0;
+       }
+}
+
+int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+                               int slot, int addr)
+{
+       return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS,
+                       SP2_CI_RD, addr, 0);
+}
+
+int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+                               int slot, int addr, u8 data)
+{
+       return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS,
+                       SP2_CI_WR, addr, data);
+}
+
+int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221,
+                               int slot, u8 addr)
+{
+       return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS,
+                       SP2_CI_RD, addr, 0);
+}
+
+int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221,
+                               int slot, u8 addr, u8 data)
+{
+       return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS,
+                       SP2_CI_WR, addr, data);
+}
+
+int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct sp2 *s = en50221->data;
+       u8 buf;
+       int ret;
+
+       dev_dbg(&s->client->dev, "slot: %d\n", slot);
+
+       if (slot != 0)
+               return -EINVAL;
+
+       /* RST on */
+       buf = SP2_MOD_CTL_RST;
+       ret = sp2_write_i2c(s, 0x00, &buf, 1);
+
+       if (ret)
+               return ret;
+
+       usleep_range(500, 600);
+
+       /* RST off */
+       buf = 0x00;
+       ret = sp2_write_i2c(s, 0x00, &buf, 1);
+
+       if (ret)
+               return ret;
+
+       msleep(1000);
+
+       return 0;
+}
+
+int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct sp2 *s = en50221->data;
+
+       dev_dbg(&s->client->dev, "slot:%d\n", slot);
+
+       /* not implemented */
+       return 0;
+}
+
+int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct sp2 *s = en50221->data;
+       u8 buf;
+
+       dev_dbg(&s->client->dev, "slot:%d\n", slot);
+
+       if (slot != 0)
+               return -EINVAL;
+
+       sp2_read_i2c(s, 0x00, &buf, 1);
+
+       /* disable bypass and enable TS */
+       buf |= (SP2_MOD_CTL_TSOEN | SP2_MOD_CTL_TSIEN);
+       return sp2_write_i2c(s, 0, &buf, 1);
+}
+
+int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221,
+                               int slot, int open)
+{
+       struct sp2 *s = en50221->data;
+       u8 buf[2];
+       int ret;
+
+       dev_dbg(&s->client->dev, "slot:%d open:%d\n", slot, open);
+
+       /*
+        * CAM module INSERT/REMOVE processing. Slow operation because of i2c
+        * transfers. Throttle read to one per sec.
+        */
+       if (time_after(jiffies, s->next_status_checked_time)) {
+               ret = sp2_read_i2c(s, 0x00, buf, 1);
+               s->next_status_checked_time = jiffies + msecs_to_jiffies(1000);
+
+               if (ret)
+                       return 0;
+
+               if (buf[0] & SP2_MOD_CTL_DET)
+                       s->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
+                                       DVB_CA_EN50221_POLL_CAM_READY;
+               else
+                       s->status = 0;
+       }
+
+       return s->status;
+}
+
+int sp2_init(struct sp2 *s)
+{
+       int ret = 0;
+       u8 buf;
+       u8 cimax_init[34] = {
+               0x00, /* module A control*/
+               0x00, /* auto select mask high A */
+               0x00, /* auto select mask low A */
+               0x00, /* auto select pattern high A */
+               0x00, /* auto select pattern low A */
+               0x44, /* memory access time A, 600 ns */
+               0x00, /* invert input A */
+               0x00, /* RFU */
+               0x00, /* RFU */
+               0x00, /* module B control*/
+               0x00, /* auto select mask high B */
+               0x00, /* auto select mask low B */
+               0x00, /* auto select pattern high B */
+               0x00, /* auto select pattern low B */
+               0x44, /* memory access time B, 600 ns */
+               0x00, /* invert input B */
+               0x00, /* RFU */
+               0x00, /* RFU */
+               0x00, /* auto select mask high Ext */
+               0x00, /* auto select mask low Ext */
+               0x00, /* auto select pattern high Ext */
+               0x00, /* auto select pattern low Ext */
+               0x00, /* RFU */
+               0x02, /* destination - module A */
+               0x01, /* power control reg, VCC power on */
+               0x00, /* RFU */
+               0x00, /* int status read only */
+               0x00, /* Interrupt Mask Register */
+               0x05, /* EXTINT=active-high, INT=push-pull */
+               0x00, /* USCG1 */
+               0x04, /* ack active low */
+               0x00, /* LOCK = 0 */
+               0x22, /* unknown */
+               0x00, /* synchronization? */
+       };
+
+       dev_dbg(&s->client->dev, "\n");
+
+       s->ca.owner = THIS_MODULE;
+       s->ca.read_attribute_mem = sp2_ci_read_attribute_mem;
+       s->ca.write_attribute_mem = sp2_ci_write_attribute_mem;
+       s->ca.read_cam_control = sp2_ci_read_cam_control;
+       s->ca.write_cam_control = sp2_ci_write_cam_control;
+       s->ca.slot_reset = sp2_ci_slot_reset;
+       s->ca.slot_shutdown = sp2_ci_slot_shutdown;
+       s->ca.slot_ts_enable = sp2_ci_slot_ts_enable;
+       s->ca.poll_slot_status = sp2_ci_poll_slot_status;
+       s->ca.data = s;
+       s->module_access_type = 0;
+
+       /* initialize all regs */
+       ret = sp2_write_i2c(s, 0x00, &cimax_init[0], 34);
+       if (ret)
+               goto err;
+
+       /* lock registers */
+       buf = 1;
+       ret = sp2_write_i2c(s, 0x1f, &buf, 1);
+       if (ret)
+               goto err;
+
+       /* power on slots */
+       ret = sp2_write_i2c(s, 0x18, &buf, 1);
+       if (ret)
+               goto err;
+
+       ret = dvb_ca_en50221_init(s->dvb_adap, &s->ca, 0, 1);
+       if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       dev_dbg(&s->client->dev, "init failed=%d\n", ret);
+       return ret;
+}
+
+int sp2_exit(struct i2c_client *client)
+{
+       struct sp2 *s;
+
+       dev_dbg(&client->dev, "\n");
+
+       if (client == NULL)
+               return 0;
+
+       s = i2c_get_clientdata(client);
+       if (s == NULL)
+               return 0;
+
+       if (s->ca.data == NULL)
+               return 0;
+
+       dvb_ca_en50221_release(&s->ca);
+
+       return 0;
+}
+
+static int sp2_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct sp2_config *cfg = client->dev.platform_data;
+       struct sp2 *s;
+       int ret;
+
+       dev_dbg(&client->dev, "\n");
+
+       s = kzalloc(sizeof(struct sp2), GFP_KERNEL);
+       if (!s) {
+               ret = -ENOMEM;
+               dev_err(&client->dev, "kzalloc() failed\n");
+               goto err;
+       }
+
+       s->client = client;
+       s->dvb_adap = cfg->dvb_adap;
+       s->priv = cfg->priv;
+       s->ci_control = cfg->ci_control;
+
+       i2c_set_clientdata(client, s);
+
+       ret = sp2_init(s);
+       if (ret)
+               goto err;
+
+       dev_info(&s->client->dev, "CIMaX SP2 successfully attached\n");
+       return 0;
+err:
+       dev_dbg(&client->dev, "init failed=%d\n", ret);
+       kfree(s);
+
+       return ret;
+}
+
+static int sp2_remove(struct i2c_client *client)
+{
+       struct si2157 *s = i2c_get_clientdata(client);
+
+       dev_dbg(&client->dev, "\n");
+
+       sp2_exit(client);
+       if (s != NULL)
+               kfree(s);
+
+       return 0;
+}
+
+static const struct i2c_device_id sp2_id[] = {
+       {"sp2", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, sp2_id);
+
+static struct i2c_driver sp2_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "sp2",
+       },
+       .probe          = sp2_probe,
+       .remove         = sp2_remove,
+       .id_table       = sp2_id,
+};
+
+module_i2c_driver(sp2_driver);
+
+MODULE_DESCRIPTION("CIMaX SP2/HF CI driver");
+MODULE_AUTHOR("Olli Salonen <olli.salonen@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/sp2.h b/drivers/media/dvb-frontends/sp2.h
new file mode 100644 (file)
index 0000000..6cceea0
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * CIMaX SP2/HF CI driver
+ *
+ * Copyright (C) 2014 Olli Salonen <olli.salonen@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.
+ */
+
+#ifndef SP2_H
+#define SP2_H
+
+#include <linux/kconfig.h>
+#include "dvb_ca_en50221.h"
+
+/*
+ * I2C address
+ * 0x40 (port 0)
+ * 0x41 (port 1)
+ */
+struct sp2_config {
+       /* dvb_adapter to attach the ci to */
+       struct dvb_adapter *dvb_adap;
+
+       /* function ci_control handles the device specific ci ops */
+       void *ci_control;
+
+       /* priv is passed back to function ci_control */
+       void *priv;
+};
+
+extern int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+                                       int slot, int addr);
+extern int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+                                       int slot, int addr, u8 data);
+extern int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221,
+                                       int slot, u8 addr);
+extern int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221,
+                                       int slot, u8 addr, u8 data);
+extern int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot);
+extern int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot);
+extern int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot);
+extern int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221,
+                                       int slot, int open);
+
+#endif
diff --git a/drivers/media/dvb-frontends/sp2_priv.h b/drivers/media/dvb-frontends/sp2_priv.h
new file mode 100644 (file)
index 0000000..37fef7b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * CIMaX SP2/HF CI driver
+ *
+ * Copyright (C) 2014 Olli Salonen <olli.salonen@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.
+ */
+
+#ifndef SP2_PRIV_H
+#define SP2_PRIV_H
+
+#include "sp2.h"
+#include "dvb_frontend.h"
+
+/* state struct */
+struct sp2 {
+       int status;
+       struct i2c_client *client;
+       struct dvb_adapter *dvb_adap;
+       struct dvb_ca_en50221 ca;
+       int module_access_type;
+       unsigned long next_status_checked_time;
+       void *priv;
+       void *ci_control;
+};
+
+#define SP2_CI_ATTR_ACS                0x00
+#define SP2_CI_IO_ACS          0x04
+#define SP2_CI_WR              0
+#define SP2_CI_RD              1
+
+/* Module control register (0x00 module A, 0x09 module B) bits */
+#define SP2_MOD_CTL_DET                0x01
+#define SP2_MOD_CTL_AUTO       0x02
+#define SP2_MOD_CTL_ACS0       0x04
+#define SP2_MOD_CTL_ACS1       0x08
+#define SP2_MOD_CTL_HAD                0x10
+#define SP2_MOD_CTL_TSIEN      0x20
+#define SP2_MOD_CTL_TSOEN      0x40
+#define SP2_MOD_CTL_RST                0x80
+
+#endif
index 2aa8ef76eba259efba6490590f5201f0882e5805..57dc2abaa87bc7d5e0cf881d3b30e3065a6dfc26 100644 (file)
@@ -394,8 +394,7 @@ static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber)
        if (ret < 0)
                return -EIO;
 
-        tmp = ret << 6;
-
+       tmp = ret << 6;
        if (tmp >= 0x3FFF0)
                tmp = ~0;
 
index 59b6e661acc085bd99e6c11ff8dc8f58c88de35f..b31ff265ff248996507a0766739bb5e10392a239 100644 (file)
@@ -59,7 +59,6 @@ struct stv0367cab_state {
        int locked;                     /* channel found                */
        u32 freq_khz;                   /* found frequency (in kHz)     */
        u32 symbol_rate;                /* found symbol rate (in Bds)   */
-       enum stv0367cab_mod modulation; /* modulation                   */
        fe_spectral_inversion_t spect_inv; /* Spectrum Inversion        */
 };
 
@@ -554,7 +553,7 @@ static struct st_register def0367ter[STV0367TER_NBREGS] = {
 #define RF_LOOKUP_TABLE_SIZE  31
 #define RF_LOOKUP_TABLE2_SIZE 16
 /* RF Level (for RF AGC->AGC1) Lookup Table, depends on the board and tuner.*/
-s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = {
+static const s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = {
        {/*AGC1*/
                48, 50, 51, 53, 54, 56, 57, 58, 60, 61, 62, 63,
                64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
@@ -566,7 +565,7 @@ s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = {
        }
 };
 /* RF Level (for IF AGC->AGC2) Lookup Table, depends on the board and tuner.*/
-s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = {
+static const s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = {
        {/*AGC2*/
                28, 29, 31, 32, 34, 35, 36, 37,
                38, 39, 40, 41, 42, 43, 44, 45,
@@ -1935,8 +1934,6 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe)
        struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stv0367_state *state = fe->demodulator_priv;
        struct stv0367ter_state *ter_state = state->ter_state;
-
-       int error = 0;
        enum stv0367_ter_mode mode;
        int constell = 0,/* snr = 0,*/ Data = 0;
 
@@ -2020,7 +2017,7 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe)
 
        p->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD);
 
-       return error;
+       return 0;
 }
 
 static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr)
@@ -2999,7 +2996,6 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
 
        if (QAMFEC_Lock) {
                signalType = FE_CAB_DATAOK;
-               cab_state->modulation = p->modulation;
                cab_state->spect_inv = stv0367_readbits(state,
                                                        F367CAB_QUAD_INV);
 #if 0
@@ -3165,7 +3161,7 @@ static int stv0367cab_get_frontend(struct dvb_frontend *fe)
        case FE_CAB_MOD_QAM128:
                p->modulation = QAM_128;
                break;
-       case QAM_256:
+       case FE_CAB_MOD_QAM256:
                p->modulation = QAM_256;
                break;
        default:
index e5a87b57d8550c39d7519282d1e6469a3c939b84..2c88abfab5313b5976b14f31637794ffa1017ba0 100644 (file)
@@ -1270,7 +1270,6 @@ enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp,
                                        enum fe_stv0900_demod_mode LDPC_Mode,
                                        enum fe_stv0900_demod_num demod)
 {
-       enum fe_stv0900_error error = STV0900_NO_ERROR;
        s32 reg_ind;
 
        dprintk("%s\n", __func__);
@@ -1337,7 +1336,7 @@ enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp,
                break;
        }
 
-       return error;
+       return STV0900_NO_ERROR;
 }
 
 static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
@@ -1555,8 +1554,6 @@ static int stv0900_status(struct stv0900_internal *intp,
 static int stv0900_set_mis(struct stv0900_internal *intp,
                                enum fe_stv0900_demod_num demod, int mis)
 {
-       enum fe_stv0900_error error = STV0900_NO_ERROR;
-
        dprintk("%s\n", __func__);
 
        if (mis < 0 || mis > 255) {
@@ -1569,7 +1566,7 @@ static int stv0900_set_mis(struct stv0900_internal *intp,
                stv0900_write_reg(intp, ISIBITENA, 0xff);
        }
 
-       return error;
+       return STV0900_NO_ERROR;
 }
 
 
index 4ce1d260b3eba1b7e4acdce23345df8b2108e0f3..a0a7b1664c5339f36e97a296230dced6c4500dfb 100644 (file)
@@ -1733,9 +1733,10 @@ static void stv0900_set_search_standard(struct stv0900_internal *intp,
                break;
        case STV0900_SEARCH_DSS:
                dprintk("Search Standard = DSS\n");
-       case STV0900_SEARCH_DVBS2:
                break;
+       case STV0900_SEARCH_DVBS2:
                dprintk("Search Standard = DVBS2\n");
+               break;
        case STV0900_AUTO_SEARCH:
        default:
                dprintk("Search Standard = AUTO\n");
diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c
new file mode 100644 (file)
index 0000000..d9905fb
--- /dev/null
@@ -0,0 +1,840 @@
+/*
+ * Toshiba TC90522 Demodulator
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@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.
+ */
+
+/*
+ * NOTICE:
+ * This driver is incomplete and lacks init/config of the chips,
+ * as the necessary info is not disclosed.
+ * It assumes that users of this driver (such as a PCI bridge of
+ * DTV receiver cards) properly init and configure the chip
+ * via I2C *before* calling this driver's init() function.
+ *
+ * Currently, PT3 driver is the only one that uses this driver,
+ * and contains init/config code in its firmware.
+ * Thus some part of the code might be dependent on PT3 specific config.
+ */
+
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/dvb/frontend.h>
+#include "dvb_math.h"
+#include "tc90522.h"
+
+#define TC90522_I2C_THRU_REG 0xfe
+
+#define TC90522_MODULE_IDX(addr) (((u8)(addr) & 0x02U) >> 1)
+
+struct tc90522_state {
+       struct tc90522_config cfg;
+       struct dvb_frontend fe;
+       struct i2c_client *i2c_client;
+       struct i2c_adapter tuner_i2c;
+
+       bool lna;
+};
+
+struct reg_val {
+       u8 reg;
+       u8 val;
+};
+
+static int
+reg_write(struct tc90522_state *state, const struct reg_val *regs, int num)
+{
+       int i, ret;
+       struct i2c_msg msg;
+
+       ret = 0;
+       msg.addr = state->i2c_client->addr;
+       msg.flags = 0;
+       msg.len = 2;
+       for (i = 0; i < num; i++) {
+               msg.buf = (u8 *)&regs[i];
+               ret = i2c_transfer(state->i2c_client->adapter, &msg, 1);
+               if (ret == 0)
+                       ret = -EIO;
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static int reg_read(struct tc90522_state *state, u8 reg, u8 *val, u8 len)
+{
+       struct i2c_msg msgs[2] = {
+               {
+                       .addr = state->i2c_client->addr,
+                       .flags = 0,
+                       .buf = &reg,
+                       .len = 1,
+               },
+               {
+                       .addr = state->i2c_client->addr,
+                       .flags = I2C_M_RD,
+                       .buf = val,
+                       .len = len,
+               },
+       };
+       int ret;
+
+       ret = i2c_transfer(state->i2c_client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret == ARRAY_SIZE(msgs))
+               ret = 0;
+       else if (ret >= 0)
+               ret = -EIO;
+       return ret;
+}
+
+static struct tc90522_state *cfg_to_state(struct tc90522_config *c)
+{
+       return container_of(c, struct tc90522_state, cfg);
+}
+
+
+static int tc90522s_set_tsid(struct dvb_frontend *fe)
+{
+       struct reg_val set_tsid[] = {
+               { 0x8f, 00 },
+               { 0x90, 00 }
+       };
+
+       set_tsid[0].val = (fe->dtv_property_cache.stream_id & 0xff00) >> 8;
+       set_tsid[1].val = fe->dtv_property_cache.stream_id & 0xff;
+       return reg_write(fe->demodulator_priv, set_tsid, ARRAY_SIZE(set_tsid));
+}
+
+static int tc90522t_set_layers(struct dvb_frontend *fe)
+{
+       struct reg_val rv;
+       u8 laysel;
+
+       laysel = ~fe->dtv_property_cache.isdbt_layer_enabled & 0x07;
+       laysel = (laysel & 0x01) << 2 | (laysel & 0x02) | (laysel & 0x04) >> 2;
+       rv.reg = 0x71;
+       rv.val = laysel;
+       return reg_write(fe->demodulator_priv, &rv, 1);
+}
+
+/* frontend ops */
+
+static int tc90522s_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct tc90522_state *state;
+       int ret;
+       u8 reg;
+
+       state = fe->demodulator_priv;
+       ret = reg_read(state, 0xc3, &reg, 1);
+       if (ret < 0)
+               return ret;
+
+       *status = 0;
+       if (reg & 0x80) /* input level under min ? */
+               return 0;
+       *status |= FE_HAS_SIGNAL;
+
+       if (reg & 0x60) /* carrier? */
+               return 0;
+       *status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC;
+
+       if (reg & 0x10)
+               return 0;
+       if (reg_read(state, 0xc5, &reg, 1) < 0 || !(reg & 0x03))
+               return 0;
+       *status |= FE_HAS_LOCK;
+       return 0;
+}
+
+static int tc90522t_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct tc90522_state *state;
+       int ret;
+       u8 reg;
+
+       state = fe->demodulator_priv;
+       ret = reg_read(state, 0x96, &reg, 1);
+       if (ret < 0)
+               return ret;
+
+       *status = 0;
+       if (reg & 0xe0) {
+               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI
+                               | FE_HAS_SYNC | FE_HAS_LOCK;
+               return 0;
+       }
+
+       ret = reg_read(state, 0x80, &reg, 1);
+       if (ret < 0)
+               return ret;
+
+       if (reg & 0xf0)
+               return 0;
+       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
+       if (reg & 0x0c)
+               return 0;
+       *status |= FE_HAS_SYNC | FE_HAS_VITERBI;
+
+       if (reg & 0x02)
+               return 0;
+       *status |= FE_HAS_LOCK;
+       return 0;
+}
+
+static const fe_code_rate_t fec_conv_sat[] = {
+       FEC_NONE, /* unused */
+       FEC_1_2, /* for BPSK */
+       FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, /* for QPSK */
+       FEC_2_3, /* for 8PSK. (trellis code) */
+};
+
+static int tc90522s_get_frontend(struct dvb_frontend *fe)
+{
+       struct tc90522_state *state;
+       struct dtv_frontend_properties *c;
+       struct dtv_fe_stats *stats;
+       int ret, i;
+       int layers;
+       u8 val[10];
+       u32 cndat;
+
+       state = fe->demodulator_priv;
+       c = &fe->dtv_property_cache;
+       c->delivery_system = SYS_ISDBS;
+
+       layers = 0;
+       ret = reg_read(state, 0xe8, val, 3);
+       if (ret == 0) {
+               int slots;
+               u8 v;
+
+               /* high/single layer */
+               v = (val[0] & 0x70) >> 4;
+               c->modulation = (v == 7) ? PSK_8 : QPSK;
+               c->fec_inner = fec_conv_sat[v];
+               c->layer[0].fec = c->fec_inner;
+               c->layer[0].modulation = c->modulation;
+               c->layer[0].segment_count = val[1] & 0x3f; /* slots */
+
+               /* low layer */
+               v = (val[0] & 0x07);
+               c->layer[1].fec = fec_conv_sat[v];
+               if (v == 0)  /* no low layer */
+                       c->layer[1].segment_count = 0;
+               else
+                       c->layer[1].segment_count = val[2] & 0x3f; /* slots */
+               /* actually, BPSK if v==1, but not defined in fe_modulation_t */
+               c->layer[1].modulation = QPSK;
+               layers = (v > 0) ? 2 : 1;
+
+               slots =  c->layer[0].segment_count +  c->layer[1].segment_count;
+               c->symbol_rate = 28860000 * slots / 48;
+       }
+
+       /* statistics */
+
+       stats = &c->strength;
+       stats->len = 0;
+       /* let the connected tuner set RSSI property cache */
+       if (fe->ops.tuner_ops.get_rf_strength) {
+               u16 dummy;
+
+               fe->ops.tuner_ops.get_rf_strength(fe, &dummy);
+       }
+
+       stats = &c->cnr;
+       stats->len = 1;
+       stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       cndat = 0;
+       ret = reg_read(state, 0xbc, val, 2);
+       if (ret == 0)
+               cndat = val[0] << 8 | val[1];
+       if (cndat >= 3000) {
+               u32 p, p4;
+               s64 cn;
+
+               cndat -= 3000;  /* cndat: 4.12 fixed point float */
+               /*
+                * cnr[mdB] = -1634.6 * P^5 + 14341 * P^4 - 50259 * P^3
+                *                 + 88977 * P^2 - 89565 * P + 58857
+                *  (P = sqrt(cndat) / 64)
+                */
+               /* p := sqrt(cndat) << 8 = P << 14, 2.14 fixed  point float */
+               /* cn = cnr << 3 */
+               p = int_sqrt(cndat << 16);
+               p4 = cndat * cndat;
+               cn = div64_s64(-16346LL * p4 * p, 10) >> 35;
+               cn += (14341LL * p4) >> 21;
+               cn -= (50259LL * cndat * p) >> 23;
+               cn += (88977LL * cndat) >> 9;
+               cn -= (89565LL * p) >> 11;
+               cn += 58857  << 3;
+               stats->stat[0].svalue = cn >> 3;
+               stats->stat[0].scale = FE_SCALE_DECIBEL;
+       }
+
+       /* per-layer post viterbi BER (or PER? config dependent?) */
+       stats = &c->post_bit_error;
+       memset(stats, 0, sizeof(*stats));
+       stats->len = layers;
+       ret = reg_read(state, 0xeb, val, 10);
+       if (ret < 0)
+               for (i = 0; i < layers; i++)
+                       stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+       else {
+               for (i = 0; i < layers; i++) {
+                       stats->stat[i].scale = FE_SCALE_COUNTER;
+                       stats->stat[i].uvalue = val[i * 5] << 16
+                               | val[i * 5 + 1] << 8 | val[i * 5 + 2];
+               }
+       }
+       stats = &c->post_bit_count;
+       memset(stats, 0, sizeof(*stats));
+       stats->len = layers;
+       if (ret < 0)
+               for (i = 0; i < layers; i++)
+                       stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+       else {
+               for (i = 0; i < layers; i++) {
+                       stats->stat[i].scale = FE_SCALE_COUNTER;
+                       stats->stat[i].uvalue =
+                               val[i * 5 + 3] << 8 | val[i * 5 + 4];
+                       stats->stat[i].uvalue *= 204 * 8;
+               }
+       }
+
+       return 0;
+}
+
+
+static const fe_transmit_mode_t tm_conv[] = {
+       TRANSMISSION_MODE_2K,
+       TRANSMISSION_MODE_4K,
+       TRANSMISSION_MODE_8K,
+       0
+};
+
+static const fe_code_rate_t fec_conv_ter[] = {
+       FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, 0, 0, 0
+};
+
+static const fe_modulation_t mod_conv[] = {
+       DQPSK, QPSK, QAM_16, QAM_64, 0, 0, 0, 0
+};
+
+static int tc90522t_get_frontend(struct dvb_frontend *fe)
+{
+       struct tc90522_state *state;
+       struct dtv_frontend_properties *c;
+       struct dtv_fe_stats *stats;
+       int ret, i;
+       int layers;
+       u8 val[15], mode;
+       u32 cndat;
+
+       state = fe->demodulator_priv;
+       c = &fe->dtv_property_cache;
+       c->delivery_system = SYS_ISDBT;
+       c->bandwidth_hz = 6000000;
+       mode = 1;
+       ret = reg_read(state, 0xb0, val, 1);
+       if (ret == 0) {
+               mode = (val[0] & 0xc0) >> 2;
+               c->transmission_mode = tm_conv[mode];
+               c->guard_interval = (val[0] & 0x30) >> 4;
+       }
+
+       ret = reg_read(state, 0xb2, val, 6);
+       layers = 0;
+       if (ret == 0) {
+               u8 v;
+
+               c->isdbt_partial_reception = val[0] & 0x01;
+               c->isdbt_sb_mode = (val[0] & 0xc0) == 0x01;
+
+               /* layer A */
+               v = (val[2] & 0x78) >> 3;
+               if (v == 0x0f)
+                       c->layer[0].segment_count = 0;
+               else {
+                       layers++;
+                       c->layer[0].segment_count = v;
+                       c->layer[0].fec = fec_conv_ter[(val[1] & 0x1c) >> 2];
+                       c->layer[0].modulation = mod_conv[(val[1] & 0xe0) >> 5];
+                       v = (val[1] & 0x03) << 1 | (val[2] & 0x80) >> 7;
+                       c->layer[0].interleaving = v;
+               }
+
+               /* layer B */
+               v = (val[3] & 0x03) << 1 | (val[4] & 0xc0) >> 6;
+               if (v == 0x0f)
+                       c->layer[1].segment_count = 0;
+               else {
+                       layers++;
+                       c->layer[1].segment_count = v;
+                       c->layer[1].fec = fec_conv_ter[(val[3] & 0xe0) >> 5];
+                       c->layer[1].modulation = mod_conv[(val[2] & 0x07)];
+                       c->layer[1].interleaving = (val[3] & 0x1c) >> 2;
+               }
+
+               /* layer C */
+               v = (val[5] & 0x1e) >> 1;
+               if (v == 0x0f)
+                       c->layer[2].segment_count = 0;
+               else {
+                       layers++;
+                       c->layer[2].segment_count = v;
+                       c->layer[2].fec = fec_conv_ter[(val[4] & 0x07)];
+                       c->layer[2].modulation = mod_conv[(val[4] & 0x38) >> 3];
+                       c->layer[2].interleaving = (val[5] & 0xe0) >> 5;
+               }
+       }
+
+       /* statistics */
+
+       stats = &c->strength;
+       stats->len = 0;
+       /* let the connected tuner set RSSI property cache */
+       if (fe->ops.tuner_ops.get_rf_strength) {
+               u16 dummy;
+
+               fe->ops.tuner_ops.get_rf_strength(fe, &dummy);
+       }
+
+       stats = &c->cnr;
+       stats->len = 1;
+       stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       cndat = 0;
+       ret = reg_read(state, 0x8b, val, 3);
+       if (ret == 0)
+               cndat = val[0] << 16 | val[1] << 8 | val[2];
+       if (cndat != 0) {
+               u32 p, tmp;
+               s64 cn;
+
+               /*
+                * cnr[mdB] = 0.024 P^4 - 1.6 P^3 + 39.8 P^2 + 549.1 P + 3096.5
+                * (P = 10log10(5505024/cndat))
+                */
+               /* cn = cnr << 3 (61.3 fixed point float */
+               /* p = 10log10(5505024/cndat) << 24  (8.24 fixed point float)*/
+               p = intlog10(5505024) - intlog10(cndat);
+               p *= 10;
+
+               cn = 24772;
+               cn += div64_s64(43827LL * p, 10) >> 24;
+               tmp = p >> 8;
+               cn += div64_s64(3184LL * tmp * tmp, 10) >> 32;
+               tmp = p >> 13;
+               cn -= div64_s64(128LL * tmp * tmp * tmp, 10) >> 33;
+               tmp = p >> 18;
+               cn += div64_s64(192LL * tmp * tmp * tmp * tmp, 1000) >> 24;
+
+               stats->stat[0].svalue = cn >> 3;
+               stats->stat[0].scale = FE_SCALE_DECIBEL;
+       }
+
+       /* per-layer post viterbi BER (or PER? config dependent?) */
+       stats = &c->post_bit_error;
+       memset(stats, 0, sizeof(*stats));
+       stats->len = layers;
+       ret = reg_read(state, 0x9d, val, 15);
+       if (ret < 0)
+               for (i = 0; i < layers; i++)
+                       stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+       else {
+               for (i = 0; i < layers; i++) {
+                       stats->stat[i].scale = FE_SCALE_COUNTER;
+                       stats->stat[i].uvalue = val[i * 3] << 16
+                               | val[i * 3 + 1] << 8 | val[i * 3 + 2];
+               }
+       }
+       stats = &c->post_bit_count;
+       memset(stats, 0, sizeof(*stats));
+       stats->len = layers;
+       if (ret < 0)
+               for (i = 0; i < layers; i++)
+                       stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+       else {
+               for (i = 0; i < layers; i++) {
+                       stats->stat[i].scale = FE_SCALE_COUNTER;
+                       stats->stat[i].uvalue =
+                               val[9 + i * 2] << 8 | val[9 + i * 2 + 1];
+                       stats->stat[i].uvalue *= 204 * 8;
+               }
+       }
+
+       return 0;
+}
+
+static const struct reg_val reset_sat = { 0x03, 0x01 };
+static const struct reg_val reset_ter = { 0x01, 0x40 };
+
+static int tc90522_set_frontend(struct dvb_frontend *fe)
+{
+       struct tc90522_state *state;
+       int ret;
+
+       state = fe->demodulator_priv;
+
+       if (fe->ops.tuner_ops.set_params)
+               ret = fe->ops.tuner_ops.set_params(fe);
+       else
+               ret = -ENODEV;
+       if (ret < 0)
+               goto failed;
+
+       if (fe->ops.delsys[0] == SYS_ISDBS) {
+               ret = tc90522s_set_tsid(fe);
+               if (ret < 0)
+                       goto failed;
+               ret = reg_write(state, &reset_sat, 1);
+       } else {
+               ret = tc90522t_set_layers(fe);
+               if (ret < 0)
+                       goto failed;
+               ret = reg_write(state, &reset_ter, 1);
+       }
+       if (ret < 0)
+               goto failed;
+
+       return 0;
+
+failed:
+       dev_warn(&state->tuner_i2c.dev, "(%s) failed. [adap%d-fe%d]\n",
+                       __func__, fe->dvb->num, fe->id);
+       return ret;
+}
+
+static int tc90522_get_tune_settings(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *settings)
+{
+       if (fe->ops.delsys[0] == SYS_ISDBS) {
+               settings->min_delay_ms = 250;
+               settings->step_size = 1000;
+               settings->max_drift = settings->step_size * 2;
+       } else {
+               settings->min_delay_ms = 400;
+               settings->step_size = 142857;
+               settings->max_drift = settings->step_size;
+       }
+       return 0;
+}
+
+static int tc90522_set_if_agc(struct dvb_frontend *fe, bool on)
+{
+       struct reg_val agc_sat[] = {
+               { 0x0a, 0x00 },
+               { 0x10, 0x30 },
+               { 0x11, 0x00 },
+               { 0x03, 0x01 },
+       };
+       struct reg_val agc_ter[] = {
+               { 0x25, 0x00 },
+               { 0x23, 0x4c },
+               { 0x01, 0x40 },
+       };
+       struct tc90522_state *state;
+       struct reg_val *rv;
+       int num;
+
+       state = fe->demodulator_priv;
+       if (fe->ops.delsys[0] == SYS_ISDBS) {
+               agc_sat[0].val = on ? 0xff : 0x00;
+               agc_sat[1].val |= 0x80;
+               agc_sat[1].val |= on ? 0x01 : 0x00;
+               agc_sat[2].val |= on ? 0x40 : 0x00;
+               rv = agc_sat;
+               num = ARRAY_SIZE(agc_sat);
+       } else {
+               agc_ter[0].val = on ? 0x40 : 0x00;
+               agc_ter[1].val |= on ? 0x00 : 0x01;
+               rv = agc_ter;
+               num = ARRAY_SIZE(agc_ter);
+       }
+       return reg_write(state, rv, num);
+}
+
+static const struct reg_val sleep_sat = { 0x17, 0x01 };
+static const struct reg_val sleep_ter = { 0x03, 0x90 };
+
+static int tc90522_sleep(struct dvb_frontend *fe)
+{
+       struct tc90522_state *state;
+       int ret;
+
+       state = fe->demodulator_priv;
+       if (fe->ops.delsys[0] == SYS_ISDBS)
+               ret = reg_write(state, &sleep_sat, 1);
+       else {
+               ret = reg_write(state, &sleep_ter, 1);
+               if (ret == 0 && fe->ops.set_lna &&
+                   fe->dtv_property_cache.lna == LNA_AUTO) {
+                       fe->dtv_property_cache.lna = 0;
+                       ret = fe->ops.set_lna(fe);
+                       fe->dtv_property_cache.lna = LNA_AUTO;
+               }
+       }
+       if (ret < 0)
+               dev_warn(&state->tuner_i2c.dev,
+                       "(%s) failed. [adap%d-fe%d]\n",
+                       __func__, fe->dvb->num, fe->id);
+       return ret;
+}
+
+static const struct reg_val wakeup_sat = { 0x17, 0x00 };
+static const struct reg_val wakeup_ter = { 0x03, 0x80 };
+
+static int tc90522_init(struct dvb_frontend *fe)
+{
+       struct tc90522_state *state;
+       int ret;
+
+       /*
+        * Because the init sequence is not public,
+        * the parent device/driver should have init'ed the device before.
+        * just wake up the device here.
+        */
+
+       state = fe->demodulator_priv;
+       if (fe->ops.delsys[0] == SYS_ISDBS)
+               ret = reg_write(state, &wakeup_sat, 1);
+       else {
+               ret = reg_write(state, &wakeup_ter, 1);
+               if (ret == 0 && fe->ops.set_lna &&
+                   fe->dtv_property_cache.lna == LNA_AUTO) {
+                       fe->dtv_property_cache.lna = 1;
+                       ret = fe->ops.set_lna(fe);
+                       fe->dtv_property_cache.lna = LNA_AUTO;
+               }
+       }
+       if (ret < 0) {
+               dev_warn(&state->tuner_i2c.dev,
+                       "(%s) failed. [adap%d-fe%d]\n",
+                       __func__, fe->dvb->num, fe->id);
+               return ret;
+       }
+
+       /* prefer 'all-layers' to 'none' as a default */
+       if (fe->dtv_property_cache.isdbt_layer_enabled == 0)
+               fe->dtv_property_cache.isdbt_layer_enabled = 7;
+       return tc90522_set_if_agc(fe, true);
+}
+
+
+/*
+ * tuner I2C adapter functions
+ */
+
+static int
+tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+       struct tc90522_state *state;
+       struct i2c_msg *new_msgs;
+       int i, j;
+       int ret, rd_num;
+       u8 wbuf[256];
+       u8 *p, *bufend;
+
+       if (num <= 0)
+               return -EINVAL;
+
+       rd_num = 0;
+       for (i = 0; i < num; i++)
+               if (msgs[i].flags & I2C_M_RD)
+                       rd_num++;
+       new_msgs = kmalloc(sizeof(*new_msgs) * (num + rd_num), GFP_KERNEL);
+       if (!new_msgs)
+               return -ENOMEM;
+
+       state = i2c_get_adapdata(adap);
+       p = wbuf;
+       bufend = wbuf + sizeof(wbuf);
+       for (i = 0, j = 0; i < num; i++, j++) {
+               new_msgs[j].addr = state->i2c_client->addr;
+               new_msgs[j].flags = msgs[i].flags;
+
+               if (msgs[i].flags & I2C_M_RD) {
+                       new_msgs[j].flags &= ~I2C_M_RD;
+                       if (p + 2 > bufend)
+                               break;
+                       p[0] = TC90522_I2C_THRU_REG;
+                       p[1] = msgs[i].addr << 1 | 0x01;
+                       new_msgs[j].buf = p;
+                       new_msgs[j].len = 2;
+                       p += 2;
+                       j++;
+                       new_msgs[j].addr = state->i2c_client->addr;
+                       new_msgs[j].flags = msgs[i].flags;
+                       new_msgs[j].buf = msgs[i].buf;
+                       new_msgs[j].len = msgs[i].len;
+                       continue;
+               }
+
+               if (p + msgs[i].len + 2 > bufend)
+                       break;
+               p[0] = TC90522_I2C_THRU_REG;
+               p[1] = msgs[i].addr << 1;
+               memcpy(p + 2, msgs[i].buf, msgs[i].len);
+               new_msgs[j].buf = p;
+               new_msgs[j].len = msgs[i].len + 2;
+               p += new_msgs[j].len;
+       }
+
+       if (i < num)
+               ret = -ENOMEM;
+       else
+               ret = i2c_transfer(state->i2c_client->adapter, new_msgs, j);
+       if (ret >= 0 && ret < j)
+               ret = -EIO;
+       kfree(new_msgs);
+       return (ret == j) ? num : ret;
+}
+
+static u32 tc90522_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm tc90522_tuner_i2c_algo = {
+       .master_xfer   = &tc90522_master_xfer,
+       .functionality = &tc90522_functionality,
+};
+
+
+/*
+ * I2C driver functions
+ */
+
+static const struct dvb_frontend_ops tc90522_ops_sat = {
+       .delsys = { SYS_ISDBS },
+       .info = {
+               .name = "Toshiba TC90522 ISDB-S module",
+               .frequency_min =  950000,
+               .frequency_max = 2150000,
+               .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
+                       FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .init = tc90522_init,
+       .sleep = tc90522_sleep,
+       .set_frontend = tc90522_set_frontend,
+       .get_tune_settings = tc90522_get_tune_settings,
+
+       .get_frontend = tc90522s_get_frontend,
+       .read_status = tc90522s_read_status,
+};
+
+static const struct dvb_frontend_ops tc90522_ops_ter = {
+       .delsys = { SYS_ISDBT },
+       .info = {
+               .name = "Toshiba TC90522 ISDB-T module",
+               .frequency_min = 470000000,
+               .frequency_max = 770000000,
+               .frequency_stepsize = 142857,
+               .caps = FE_CAN_INVERSION_AUTO |
+                       FE_CAN_FEC_1_2  | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6  | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK     | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+                       FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
+                       FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .init = tc90522_init,
+       .sleep = tc90522_sleep,
+       .set_frontend = tc90522_set_frontend,
+       .get_tune_settings = tc90522_get_tune_settings,
+
+       .get_frontend = tc90522t_get_frontend,
+       .read_status = tc90522t_read_status,
+};
+
+
+static int tc90522_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct tc90522_state *state;
+       struct tc90522_config *cfg;
+       const struct dvb_frontend_ops *ops;
+       struct i2c_adapter *adap;
+       int ret;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+       state->i2c_client = client;
+
+       cfg = client->dev.platform_data;
+       memcpy(&state->cfg, cfg, sizeof(state->cfg));
+       cfg->fe = state->cfg.fe = &state->fe;
+       ops =  id->driver_data == 0 ? &tc90522_ops_sat : &tc90522_ops_ter;
+       memcpy(&state->fe.ops, ops, sizeof(*ops));
+       state->fe.demodulator_priv = state;
+
+       adap = &state->tuner_i2c;
+       adap->owner = THIS_MODULE;
+       adap->algo = &tc90522_tuner_i2c_algo;
+       adap->dev.parent = &client->dev;
+       strlcpy(adap->name, "tc90522_sub", sizeof(adap->name));
+       i2c_set_adapdata(adap, state);
+       ret = i2c_add_adapter(adap);
+       if (ret < 0)
+               goto err;
+       cfg->tuner_i2c = state->cfg.tuner_i2c = adap;
+
+       i2c_set_clientdata(client, &state->cfg);
+       dev_info(&client->dev, "Toshiba TC90522 attached.\n");
+       return 0;
+
+err:
+       kfree(state);
+       return ret;
+}
+
+static int tc90522_remove(struct i2c_client *client)
+{
+       struct tc90522_state *state;
+
+       state = cfg_to_state(i2c_get_clientdata(client));
+       i2c_del_adapter(&state->tuner_i2c);
+       kfree(state);
+       return 0;
+}
+
+
+static const struct i2c_device_id tc90522_id[] = {
+       { TC90522_I2C_DEV_SAT, 0 },
+       { TC90522_I2C_DEV_TER, 1 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, tc90522_id);
+
+static struct i2c_driver tc90522_driver = {
+       .driver = {
+               .name   = "tc90522",
+       },
+       .probe          = tc90522_probe,
+       .remove         = tc90522_remove,
+       .id_table       = tc90522_id,
+};
+
+module_i2c_driver(tc90522_driver);
+
+MODULE_DESCRIPTION("Toshiba TC90522 frontend");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/tc90522.h b/drivers/media/dvb-frontends/tc90522.h
new file mode 100644 (file)
index 0000000..b1cbddf
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Toshiba TC90522 Demodulator
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@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.
+ */
+
+/*
+ * The demod has 4 input (2xISDB-T and 2xISDB-S),
+ * and provides independent sub modules for each input.
+ * As the sub modules work in parallel and have the separate i2c addr's,
+ * this driver treats each sub module as one demod device.
+ */
+
+#ifndef TC90522_H
+#define TC90522_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/* I2C device types */
+#define TC90522_I2C_DEV_SAT "tc90522sat"
+#define TC90522_I2C_DEV_TER "tc90522ter"
+
+struct tc90522_config {
+       /* [OUT] frontend returned by driver */
+       struct dvb_frontend *fe;
+
+       /* [OUT] tuner I2C adapter returned by driver */
+       struct i2c_adapter *tuner_i2c;
+};
+
+#endif /* TC90522_H */
index 9619be5d48271827b28052c080f01fc5631224b7..4a19b85995f17f47018732e8c82a67847c15e0d6 100644 (file)
@@ -1037,7 +1037,7 @@ static int tda10071_init(struct dvb_frontend *fe)
                        ret = -EFAULT;
                        goto error;
                } else {
-                       priv->warm = 1;
+                       priv->warm = true;
                }
 
                cmd.args[0] = CMD_GET_FW_VERSION;
index 91b6b2e9b79228b6c497f7c7aba65dd36415f9da..ee09ec26c553ef7aa4e8387f4ba7bcab3948db37 100644 (file)
@@ -111,7 +111,7 @@ static int zl10039_write(struct zl10039_state *state,
 
        if (1 + count > sizeof(buf)) {
                printk(KERN_WARNING
-                      "%s: i2c wr reg=%04x: len=%zd is too big!\n",
+                      "%s: i2c wr reg=%04x: len=%zu is too big!\n",
                       KBUILD_MODNAME, reg, count);
                return -EINVAL;
        }
index d1a1a1324ef87018e030ba0aa149de3c79856085..251a556112a99586288f680e018103c0b9eef90c 100644 (file)
@@ -1157,6 +1157,10 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
                if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
                        dev_err(fdtv->device,
                                "invalid pmt_cmd_id %d\n", pmt_cmd_id);
+               if (program_info_length > sizeof(c->operand) - 4 - write_pos) {
+                       ret = -EINVAL;
+                       goto out;
+               }
 
                memcpy(&c->operand[write_pos], &msg[read_pos],
                       program_info_length);
@@ -1180,6 +1184,12 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
                                dev_err(fdtv->device, "invalid pmt_cmd_id %d "
                                        "at stream level\n", pmt_cmd_id);
 
+                       if (es_info_length > sizeof(c->operand) - 4 -
+                                            write_pos) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
                        memcpy(&c->operand[write_pos], &msg[read_pos],
                               es_info_length);
                        read_pos += es_info_length;
index 4466067643465563dfbe0db7057b2f50c4e9d2e3..2f04ce4b9118a43c39d2d8c8c5f6a7e1eb4ce6c7 100644 (file)
@@ -13,7 +13,7 @@
  * GNU General Public License for more details.
  */
 
-#ifndef ADV7343_REG_H
+#ifndef ADV7343_REGS_H
 #define ADV7343_REGS_H
 
 struct adv7343_std_info {
index de88b980a8370bea73e380da85eb33fe50610761..47795ff716882ba5fddb929529c94d0acf5a84bc 100644 (file)
@@ -1593,7 +1593,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
                        bt->height += hdmi_read16(sd, 0x0b, 0xfff);
                        bt->il_vfrontporch = hdmi_read16(sd, 0x2c, 0x1fff) / 2;
                        bt->il_vsync = hdmi_read16(sd, 0x30, 0x1fff) / 2;
-                       bt->vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2;
+                       bt->il_vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2;
                }
                adv7604_fill_optional_dv_timings_fields(sd, timings);
        } else {
index 0d554919cdd52726f52deda278414aa62bb6e47c..48b628bc6714ecae53144f4bf90fa64d0454c90e 100644 (file)
@@ -1435,6 +1435,8 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd,
 
        v4l2_dbg(1, debug, sd, "%s:\n", __func__);
 
+       memset(timings, 0, sizeof(struct v4l2_dv_timings));
+
        /* SDP block */
        if (state->mode == ADV7842_MODE_SDP)
                return -ENODATA;
@@ -1483,7 +1485,7 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd,
                                        hdmi_read(sd, 0x2d)) / 2;
                        bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x1f) * 256 +
                                        hdmi_read(sd, 0x31)) / 2;
-                       bt->vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 +
+                       bt->il_vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 +
                                        hdmi_read(sd, 0x35)) / 2;
                }
                adv7842_fill_optional_dv_timings_fields(sd, timings);
index c23de593c17d5572ff2123403ad6e4e006d21e55..d9ece4b2d047067dc19921e1e79a52fd80ad130e 100644 (file)
@@ -100,14 +100,14 @@ static int lm3560_enable_ctrl(struct lm3560_flash *flash,
        int rval;
 
        if (led_no == LM3560_LED0) {
-               if (on == true)
+               if (on)
                        rval = regmap_update_bits(flash->regmap,
                                                  REG_ENABLE, 0x08, 0x08);
                else
                        rval = regmap_update_bits(flash->regmap,
                                                  REG_ENABLE, 0x08, 0x00);
        } else {
-               if (on == true)
+               if (on)
                        rval = regmap_update_bits(flash->regmap,
                                                  REG_ENABLE, 0x10, 0x10);
                else
index cdd7c1b7259b008e873cc711294a3f0cecba422a..dd3db2458a4fc8fff9512b695c6b2b40651d5921 100644 (file)
@@ -19,6 +19,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-mediabus.h>
+#include <media/v4l2-image-sizes.h>
 #include <media/ov7670.h>
 
 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
@@ -29,19 +30,6 @@ static bool debug;
 module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-/*
- * Basic window sizes.  These probably belong somewhere more globally
- * useful.
- */
-#define VGA_WIDTH      640
-#define VGA_HEIGHT     480
-#define QVGA_WIDTH     320
-#define QVGA_HEIGHT    240
-#define CIF_WIDTH      352
-#define CIF_HEIGHT     288
-#define QCIF_WIDTH     176
-#define        QCIF_HEIGHT     144
-
 /*
  * The 7670 sits on i2c with ID 0x42
  */
index 564f05f2c9efbe54d569c5030c7152ddc2f0390f..0e461a6fd0654cb3d97ef52d72e9b7c586f044b2 100644 (file)
@@ -816,7 +816,7 @@ static void s5k5baf_hw_find_min_fiv(struct s5k5baf *state)
                                 "error setting frame interval: %d\n", err);
                        state->error = -EINVAL;
                }
-       };
+       }
        v4l2_err(&state->sd, "cannot find correct frame interval\n");
        state->error = -ERANGE;
 }
index 04e9e55018a5044ff194f4d72f3bc01314ff75c4..4024ea6f1371ad48c1bd744a8a662bd545c53eb1 100644 (file)
@@ -660,7 +660,7 @@ static const struct v4l2_subdev_ops saa6752hs_ops = {
 static int saa6752hs_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
-       struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
+       struct saa6752hs_state *h;
        struct v4l2_subdev *sd;
        struct v4l2_ctrl_handler *hdl;
        u8 addr = 0x13;
@@ -668,6 +668,8 @@ static int saa6752hs_probe(struct i2c_client *client,
 
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
+
+       h = devm_kzalloc(&client->dev, sizeof(*h), GFP_KERNEL);
        if (h == NULL)
                return -ENOMEM;
        sd = &h->sd;
@@ -752,7 +754,6 @@ static int saa6752hs_probe(struct i2c_client *client,
                int err = hdl->error;
 
                v4l2_ctrl_handler_free(hdl);
-               kfree(h);
                return err;
        }
        v4l2_ctrl_cluster(3, &h->video_bitrate_mode);
@@ -767,7 +768,6 @@ static int saa6752hs_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&to_state(sd)->hdl);
-       kfree(to_state(sd));
        return 0;
 }
 
index 62acb10630f9b2a1b12c114eddad10995308389e..932ed9be9ff3d756fb35948e8183e09faaa60c34 100644 (file)
@@ -31,8 +31,9 @@
 #include <linux/device.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
-#include <linux/slab.h>
 #include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/smiapp.h>
 #include <linux/v4l2-mediabus.h>
 #include <media/v4l2-device.h>
 
@@ -297,8 +298,9 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor)
        if (rval < 0)
                return rval;
 
-       *sensor->pixel_rate_parray->p_cur.p_s64 = pll->vt_pix_clk_freq_hz;
-       *sensor->pixel_rate_csi->p_cur.p_s64 = pll->pixel_rate_csi;
+       __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_parray,
+                                pll->vt_pix_clk_freq_hz);
+       __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_csi, pll->pixel_rate_csi);
 
        return 0;
 }
@@ -319,13 +321,7 @@ static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
                + sensor->vblank->val
                - sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
 
-       ctrl->maximum = max;
-       if (ctrl->default_value > max)
-               ctrl->default_value = max;
-       if (ctrl->val > max)
-               ctrl->val = max;
-       if (ctrl->cur.val > max)
-               ctrl->cur.val = max;
+       __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max);
 }
 
 /*
@@ -404,6 +400,14 @@ static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor)
                pixel_order_str[pixel_order]);
 }
 
+static const char * const smiapp_test_patterns[] = {
+       "Disabled",
+       "Solid Colour",
+       "Eight Vertical Colour Bars",
+       "Colour Bars With Fade to Grey",
+       "Pseudorandom Sequence (PN9)",
+};
+
 static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct smiapp_sensor *sensor =
@@ -477,6 +481,39 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
 
                return smiapp_pll_update(sensor);
 
+       case V4L2_CID_TEST_PATTERN: {
+               unsigned int i;
+
+               for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++)
+                       v4l2_ctrl_activate(
+                               sensor->test_data[i],
+                               ctrl->val ==
+                               V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR);
+
+               return smiapp_write(
+                       sensor, SMIAPP_REG_U16_TEST_PATTERN_MODE, ctrl->val);
+       }
+
+       case V4L2_CID_TEST_PATTERN_RED:
+               return smiapp_write(
+                       sensor, SMIAPP_REG_U16_TEST_DATA_RED, ctrl->val);
+
+       case V4L2_CID_TEST_PATTERN_GREENR:
+               return smiapp_write(
+                       sensor, SMIAPP_REG_U16_TEST_DATA_GREENR, ctrl->val);
+
+       case V4L2_CID_TEST_PATTERN_BLUE:
+               return smiapp_write(
+                       sensor, SMIAPP_REG_U16_TEST_DATA_BLUE, ctrl->val);
+
+       case V4L2_CID_TEST_PATTERN_GREENB:
+               return smiapp_write(
+                       sensor, SMIAPP_REG_U16_TEST_DATA_GREENB, ctrl->val);
+
+       case V4L2_CID_PIXEL_RATE:
+               /* For v4l2_ctrl_s_ctrl_int64() used internally. */
+               return 0;
+
        default:
                return -EINVAL;
        }
@@ -489,10 +526,10 @@ static const struct v4l2_ctrl_ops smiapp_ctrl_ops = {
 static int smiapp_init_controls(struct smiapp_sensor *sensor)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
-       unsigned int max;
+       unsigned int max, i;
        int rval;
 
-       rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7);
+       rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12);
        if (rval)
                return rval;
        sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
@@ -535,6 +572,20 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
                &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
                V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
 
+       v4l2_ctrl_new_std_menu_items(&sensor->pixel_array->ctrl_handler,
+                                    &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN,
+                                    ARRAY_SIZE(smiapp_test_patterns) - 1,
+                                    0, 0, smiapp_test_patterns);
+
+       for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) {
+               int max_value = (1 << sensor->csi_format->width) - 1;
+               sensor->test_data[i] =
+                       v4l2_ctrl_new_std(
+                               &sensor->pixel_array->ctrl_handler,
+                               &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i,
+                               0, max_value, 1, max_value);
+       }
+
        if (sensor->pixel_array->ctrl_handler.error) {
                dev_err(&client->dev,
                        "pixel array controls initialization failed (%d)\n",
@@ -782,36 +833,25 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor)
 {
        struct v4l2_ctrl *vblank = sensor->vblank;
        struct v4l2_ctrl *hblank = sensor->hblank;
+       int min, max;
 
-       vblank->minimum =
-               max_t(int,
-                     sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
-                     sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
-                     sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
-       vblank->maximum =
-               sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
+       min = max_t(int,
+                   sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
+                   sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
+                   sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
+       max = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
                sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height;
 
-       vblank->val = clamp_t(int, vblank->val,
-                             vblank->minimum, vblank->maximum);
-       vblank->default_value = vblank->minimum;
-       vblank->val = vblank->val;
-       vblank->cur.val = vblank->val;
-
-       hblank->minimum =
-               max_t(int,
-                     sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
-                     sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width,
-                     sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
-       hblank->maximum =
-               sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
+       __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min);
+
+       min = max_t(int,
+                   sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
+                   sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width,
+                   sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
+       max = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
                sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width;
 
-       hblank->val = clamp_t(int, hblank->val,
-                             hblank->minimum, hblank->maximum);
-       hblank->default_value = hblank->minimum;
-       hblank->val = hblank->val;
-       hblank->cur.val = hblank->val;
+       __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min);
 
        __smiapp_update_exposure_limits(sensor);
 }
@@ -1272,7 +1312,7 @@ static void smiapp_power_off(struct smiapp_sensor *sensor)
                clk_disable_unprepare(sensor->ext_clk);
        usleep_range(5000, 5000);
        regulator_disable(sensor->vana);
-       sensor->streaming = 0;
+       sensor->streaming = false;
 }
 
 static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
@@ -1462,13 +1502,13 @@ static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable)
                return 0;
 
        if (enable) {
-               sensor->streaming = 1;
+               sensor->streaming = true;
                rval = smiapp_start_streaming(sensor);
                if (rval < 0)
-                       sensor->streaming = 0;
+                       sensor->streaming = false;
        } else {
                rval = smiapp_stop_streaming(sensor);
-               sensor->streaming = 0;
+               sensor->streaming = false;
        }
 
        return rval;
@@ -1664,17 +1704,34 @@ static int smiapp_set_format(struct v4l2_subdev *subdev,
        if (fmt->pad == ssd->source_pad) {
                u32 code = fmt->format.code;
                int rval = __smiapp_get_format(subdev, fh, fmt);
+               bool range_changed = false;
+               unsigned int i;
 
                if (!rval && subdev == &sensor->src->sd) {
                        const struct smiapp_csi_data_format *csi_format =
                                smiapp_validate_csi_data_format(sensor, code);
-                       if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+
+                       if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+                               if (csi_format->width !=
+                                   sensor->csi_format->width)
+                                       range_changed = true;
+
                                sensor->csi_format = csi_format;
+                       }
+
                        fmt->format.code = csi_format->code;
                }
 
                mutex_unlock(&sensor->mutex);
-               return rval;
+               if (rval || !range_changed)
+                       return rval;
+
+               for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++)
+                       v4l2_ctrl_modify_range(
+                               sensor->test_data[i],
+                               0, (1 << sensor->csi_format->width) - 1, 1, 0);
+
+               return 0;
        }
 
        /* Sink pad. Width and height are changeable here. */
index 7cc5aae662fda5e0ef1ed6ba0b3534fafb4378c4..874b49ffd88f020e1e78ec2d39f7b8041559265e 100644 (file)
@@ -54,6 +54,8 @@
        (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000       \
                 + (clk) / 1000 - 1) / ((clk) / 1000))
 
+#define SMIAPP_COLOUR_COMPONENTS       4
+
 #include "smiapp-limits.h"
 
 struct smiapp_quirk;
@@ -241,6 +243,8 @@ struct smiapp_sensor {
        /* src controls */
        struct v4l2_ctrl *link_freq;
        struct v4l2_ctrl *pixel_rate_csi;
+       /* test pattern colour components */
+       struct v4l2_ctrl *test_data[SMIAPP_COLOUR_COMPONENTS];
 };
 
 #define to_smiapp_subdev(_sd)                          \
index 46f431a13782800c04198547ebf906394086e20c..996d7b4007a52a9c3360d8238ada92c08b3a750c 100644 (file)
@@ -29,6 +29,7 @@
 #include <media/soc_camera.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-image-sizes.h>
 
 /* you can check PLL/clock info */
 /* #define EXT_CLOCK 24000000 */
@@ -42,9 +43,6 @@
 #define MAX_WIDTH   2048
 #define MAX_HEIGHT  1536
 
-#define VGA_WIDTH   640
-#define VGA_HEIGHT  480
-
 /*
  * macro of read/write
  */
index 7f2b3c8926afbfade0fca5c58bea1e9356dc9d3b..970a04e1e56e694602f4a87261079646c517875f 100644 (file)
@@ -29,6 +29,7 @@
 #include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-subdev.h>
+#include <media/v4l2-image-sizes.h>
 
 /*
  * register offset
 #define SCAL0_ACTRL     0x08 /* Auto scaling factor control */
 #define SCAL1_2_ACTRL   0x04 /* Auto scaling factor control */
 
-#define VGA_WIDTH              640
-#define VGA_HEIGHT             480
-#define QVGA_WIDTH             320
-#define QVGA_HEIGHT            240
 #define OV772X_MAX_WIDTH       VGA_WIDTH
 #define OV772X_MAX_HEIGHT      VGA_HEIGHT
 
index ea76863dfdb44e22bb265d3ee6928a0611e60f63..ee9eb635d5403acbf88fb116b939e3f5cbc77152 100644 (file)
@@ -564,13 +564,13 @@ static int ov9740_set_res(struct i2c_client *client, u32 width, u32 height)
        u32 y_start;
        u32 x_end;
        u32 y_end;
-       bool scaling = 0;
+       bool scaling = false;
        u32 scale_input_x;
        u32 scale_input_y;
        int ret;
 
        if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT))
-               scaling = 1;
+               scaling = true;
 
        /*
         * Try to use as much of the sensor area as possible when supporting
index 72af644fa05127f89548b9782cee62367823d445..cf93021a650092d8dee0710c592ba6b00611769a 100644 (file)
@@ -293,7 +293,7 @@ static int tda7432_s_ctrl(struct v4l2_ctrl *ctrl)
                if (t->mute->val) {
                        lf |= TDA7432_MUTE;
                        lr |= TDA7432_MUTE;
-                       lf |= TDA7432_MUTE;
+                       rf |= TDA7432_MUTE;
                        rr |= TDA7432_MUTE;
                }
                /* Mute & update balance*/
index 11f2387e1dabe8235ec1857352068ca1a10848bc..51bac762638b7aca70ba204d86588a38eae997c4 100644 (file)
@@ -775,25 +775,20 @@ static int tvp7002_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
 static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable)
 {
        struct tvp7002 *device = to_tvp7002(sd);
-       int error = 0;
+       int error;
 
        if (device->streaming == enable)
                return 0;
 
-       if (enable) {
-               /* Set output state on (low impedance means stream on) */
-               error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00);
-               device->streaming = enable;
-       } else {
-               /* Set output state off (high impedance means stream off) */
-               error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x03);
-               if (error)
-                       v4l2_dbg(1, debug, sd, "Unable to stop streaming\n");
-
-               device->streaming = enable;
+       /* low impedance: on, high impedance: off */
+       error = tvp7002_write(sd, TVP7002_MISC_CTL_2, enable ? 0x00 : 0x03);
+       if (error) {
+               v4l2_dbg(1, debug, sd, "Fail to set streaming\n");
+               return error;
        }
 
-       return error;
+       device->streaming = enable;
+       return 0;
 }
 
 /*
index 23f4f65fccd7ac19b43bc33fb377bdf0cc9bd8af..373f2df524924aa8b754b428a57cc5915c4b7bb4 100644 (file)
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-mediabus.h>
+#include <media/v4l2-image-sizes.h>
 
 #include "vs6624_regs.h"
 
-#define VGA_WIDTH       640
-#define VGA_HEIGHT      480
-#define QVGA_WIDTH      320
-#define QVGA_HEIGHT     240
-#define QQVGA_WIDTH     160
-#define QQVGA_HEIGHT    120
-#define CIF_WIDTH       352
-#define CIF_HEIGHT      288
-#define QCIF_WIDTH      176
-#define QCIF_HEIGHT     144
-#define QQCIF_WIDTH     88
-#define QQCIF_HEIGHT    72
-
 #define MAX_FRAME_RATE  30
 
 struct vs6624 {
index 73a432934bd8d1ee8bad5c2e07689cca9ed1a1d3..7b39440192d61a7f91b0896c406beea751d8d515 100644 (file)
@@ -103,10 +103,8 @@ static long media_device_enum_entities(struct media_device *mdev,
                return -EINVAL;
 
        u_ent.id = ent->id;
-       if (ent->name) {
-               strncpy(u_ent.name, ent->name, sizeof(u_ent.name));
-               u_ent.name[sizeof(u_ent.name) - 1] = '\0';
-       }
+       if (ent->name)
+               strlcpy(u_ent.name, ent->name, sizeof(u_ent.name));
        u_ent.type = ent->type;
        u_ent.revision = ent->revision;
        u_ent.flags = ent->flags;
index 7acd19c881debe4de5e98e9658108489d4c98c10..ebf9626e5ae5a709f2cb76b3a1c173d7ddb106ba 100644 (file)
@@ -192,7 +192,6 @@ static int media_open(struct inode *inode, struct file *filp)
 static int media_release(struct inode *inode, struct file *filp)
 {
        struct media_devnode *mdev = media_devnode_data(filp);
-       int ret = 0;
 
        if (mdev->fops->release)
                mdev->fops->release(filp);
@@ -201,7 +200,7 @@ static int media_release(struct inode *inode, struct file *filp)
           return value is ignored. */
        put_device(&mdev->dev);
        filp->private_data = NULL;
-       return ret;
+       return 0;
 }
 
 static const struct file_operations media_devnode_fops = {
index 9bc105b3db1bcec5dbb775f591188d7ec34e1adf..e6b497528ceaca5dcc671ad7a92d080936a2a316 100644 (file)
@@ -629,11 +629,15 @@ static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count)
 {
        int y;
        int dw = 2 * dev->width;
-       char tmp[dw + 32]; /* using a temp buffer is faster than direct  */
+       char *tmp; /* using a temp buffer is faster than direct  */
        int cnt = 0;
        int len = 0;
        unsigned char r8 = 0x5;  /* value for reg8  */
 
+       tmp = kmalloc(dw + 32, GFP_KERNEL);
+       if (!tmp)
+               return 0;
+
        if (rgb555)
                r8 |= 0x20; /* else use untranslated rgb = 565 */
        mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */
@@ -664,6 +668,7 @@ static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count)
                        len += dt;
                }
        }
+       kfree(tmp);
        return len;
 }
 
index 5c16c9c2203ef4e1a9fdd931ec3ecff5c2dc498a..f8cec8e8cf8243902db375d52ae5745efafbbccb 100644 (file)
@@ -20,6 +20,7 @@ source "drivers/media/pci/ivtv/Kconfig"
 source "drivers/media/pci/zoran/Kconfig"
 source "drivers/media/pci/saa7146/Kconfig"
 source "drivers/media/pci/solo6x10/Kconfig"
+source "drivers/media/pci/tw68/Kconfig"
 endif
 
 if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
@@ -41,6 +42,7 @@ source "drivers/media/pci/b2c2/Kconfig"
 source "drivers/media/pci/pluto2/Kconfig"
 source "drivers/media/pci/dm1105/Kconfig"
 source "drivers/media/pci/pt1/Kconfig"
+source "drivers/media/pci/pt3/Kconfig"
 source "drivers/media/pci/mantis/Kconfig"
 source "drivers/media/pci/ngene/Kconfig"
 source "drivers/media/pci/ddbridge/Kconfig"
index e5b53fb569efaf038d4f86a010ec83e90c06d5e6..a12926e4b51f3afc44cba9a9199886d5a52e1fae 100644 (file)
@@ -7,10 +7,10 @@ obj-y        +=       ttpci/          \
                pluto2/         \
                dm1105/         \
                pt1/            \
+               pt3/            \
                mantis/         \
                ngene/          \
                ddbridge/       \
-               b2c2/           \
                saa7146/
 
 obj-$(CONFIG_VIDEO_IVTV) += ivtv/
@@ -22,6 +22,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_BT848) += bt8xx/
 obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
+obj-$(CONFIG_VIDEO_TW68) += tw68/
 obj-$(CONFIG_VIDEO_MEYE) += meye/
 obj-$(CONFIG_STA2X11_VIP) += sta2x11/
 obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/
index 970e542d3a51fabcc17f2be4e371b9ccdd55cc36..4a8176c09fc9429eea49c2e49e811618354c78b0 100644 (file)
@@ -1531,7 +1531,6 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
 {
        struct bttv_buffer *old;
        unsigned long flags;
-       int retval = 0;
 
        dprintk("switch_overlay: enter [new=%p]\n", new);
        if (new)
@@ -1551,7 +1550,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
        if (NULL == new)
                free_btres_lock(btv,fh,RESOURCE_OVERLAY);
        dprintk("switch_overlay: done\n");
-       return retval;
+       return 0;
 }
 
 /* ----------------------------------------------------------------------- */
@@ -3856,7 +3855,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
 
                                btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
                                                BT848_INT_MASK);
-                       };
+                       }
 
                        bttv_print_irqbits(stat,astat);
 
index 0e788fca992cf1e27579dd689a12cfc2b0da2f38..c22c4ae0684491266406fd0dea3001b992ae101f 100644 (file)
@@ -674,11 +674,9 @@ static int dst_ca_release(struct inode *inode, struct file *file)
 
 static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
 {
-       ssize_t bytes_read = 0;
-
        dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
 
-       return bytes_read;
+       return 0;
 }
 
 static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
index 180077c49123fe11159ec3cd8480995586cf7fbf..ffb6acdc575f65993f231d9f600f3ab0f7682883 100644 (file)
@@ -80,7 +80,7 @@ void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data,
        int period_elapsed = 0;
        int length;
 
-       dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zd\n", cxsc,
+       dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zu\n", cxsc,
                pcm_data, num_bytes);
 
        substream = cxsc->capture_pcm_substream;
index a1c1cec05f98e4693bdc3dacfa073a64adec1d32..c6c83445f8bfb93605990d6726b9d2755d0d4f24 100644 (file)
@@ -130,7 +130,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx)
                }
        }
        if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
-               CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+               CX18_INFO("loaded %s firmware (%zu bytes)\n", fn, fw->size);
        size = fw->size;
        release_firmware(fw);
        cx18_setup_page(cx, SCB_OFFSET);
@@ -164,7 +164,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
 
        apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
        while (offset + sizeof(seghdr) < fw->size) {
-               const u32 *shptr = src + offset / 4;
+               const __le32 *shptr = (__force __le32 *)src + offset / 4;
 
                seghdr.sync1 = le32_to_cpu(shptr[0]);
                seghdr.sync2 = le32_to_cpu(shptr[1]);
@@ -202,7 +202,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
                offset += seghdr.size;
        }
        if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
-               CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n",
+               CX18_INFO("loaded %s firmware V%08x (%zu bytes)\n",
                                fn, apu_version, fw->size);
        size = fw->size;
        release_firmware(fw);
index 8884537bd62f9bf4685ea1a48c89f970cbb6f8b7..2a247d264b87740f6af9bb23ee411a799beb1020 100644 (file)
@@ -364,7 +364,7 @@ int cx18_stream_alloc(struct cx18_stream *s)
                                        ((char __iomem *)cx->scb->cpu_mdl));
 
                CX18_ERR("Too many buffers, cannot fit in SCB area\n");
-               CX18_ERR("Max buffers = %zd\n",
+               CX18_ERR("Max buffers = %zu\n",
                        bufsz / sizeof(struct cx18_mdl_ent));
                return -ENOMEM;
        }
index e12c006e6e2dc3be8470e454f64c5a055258791c..f613314b360ba735a048cfec56cb3324075f3f69 100644 (file)
@@ -3,12 +3,11 @@ config VIDEO_CX23885
        depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND
        select SND_PCM
        select I2C_ALGOBIT
-       select VIDEO_BTCX
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
        depends on RC_CORE
-       select VIDEOBUF_DVB
-       select VIDEOBUF_DMA_SG
+       select VIDEOBUF2_DVB
+       select VIDEOBUF2_DMA_SG
        select VIDEO_CX25840
        select VIDEO_CX2341X
        select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT
@@ -32,12 +31,16 @@ config VIDEO_CX23885
        select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
        select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
        ---help---
          This is a video4linux driver for Conexant 23885 based
index 2a2cafb8cf5be31b48daf3c881aa50871e9a90fa..a2cbdcf15a8c48fde4cd79c43b33dd92c81a8def 100644 (file)
@@ -8,7 +8,6 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
 obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o
 
 ccflags-y += -Idrivers/media/i2c
-ccflags-y += -Idrivers/media/common
 ccflags-y += -Idrivers/media/tuners
 ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb-frontends
index 2926f7fadccdcdeba7ca6b3a5cd5e99ba84e4bb7..2bbbf545b0422d0eca0548e4e30989c22bc5a0dc 100644 (file)
  * 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.
  */
 
 /*
@@ -52,8 +48,8 @@
  * |  DATA7|  DATA6|  DATA5|  DATA4|  DATA3|  DATA2|  DATA1|  DATA0|
  * +-------+-------+-------+-------+-------+-------+-------+-------+
  */
-#include <media/videobuf-dma-sg.h>
-#include <media/videobuf-dvb.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
 #include "altera-ci.h"
 #include "dvb_ca_en50221.h"
 
index 4998c96caebee5cb8e3d38fa2962b7b8ec642839..5028f0cf83f43a87b7e93270c0d6fb8c277bb584 100644 (file)
  * 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_CI_H
 #define __ALTERA_CI_H
index 16fa7ea4d4aa7d472ff9f59f6b0131ead21c2902..631e4f24aea6424ef265fa1dcb8b4d81a5966eb3 100644 (file)
  * 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 "cx23885.h"
index 518744a4c8a5e41c82b8091bbee2f2d71166e6b6..565e958f6f8d2de35bfc15701961d387e8a8c68e 100644 (file)
  * 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 CIMAX2_H
index bf89fc88692eb1ac081b34fc24691737e08c3951..3948db386fb5624c7a67e73a08bc5454fcd05e88 100644 (file)
  *  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>
@@ -865,6 +861,11 @@ static int cx23885_api_cmd(struct cx23885_dev *dev,
        return err;
 }
 
+static int cx23885_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
+{
+       return cx23885_mbox_func(priv, cmd, in, out, data);
+}
+
 static int cx23885_find_mailbox(struct cx23885_dev *dev)
 {
        u32 signature[4] = {
@@ -941,7 +942,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
 
        if (firmware->size != CX23885_FIRM_IMAGE_SIZE) {
                printk(KERN_ERR "ERROR: Firmware size mismatch "
-                       "(have %zd, expected %d)\n",
+                       "(have %zu, expected %d)\n",
                        firmware->size, CX23885_FIRM_IMAGE_SIZE);
                release_firmware(firmware);
                return -1;
@@ -1033,12 +1034,12 @@ static void cx23885_codec_settings(struct cx23885_dev *dev)
        cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
                                dev->ts1.height, dev->ts1.width);
 
-       dev->mpeg_params.width = dev->ts1.width;
-       dev->mpeg_params.height = dev->ts1.height;
-       dev->mpeg_params.is_50hz =
+       dev->cxhdl.width = dev->ts1.width;
+       dev->cxhdl.height = dev->ts1.height;
+       dev->cxhdl.is_50hz =
                (dev->encodernorm.id & V4L2_STD_625_50) != 0;
 
-       cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params);
+       cx2341x_handler_setup(&dev->cxhdl);
 
        cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
        cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
@@ -1137,85 +1138,107 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
 
 /* ------------------------------------------------------------------ */
 
-static int bb_buf_setup(struct videobuf_queue *q,
-       unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+                          unsigned int *num_buffers, unsigned int *num_planes,
+                          unsigned int sizes[], void *alloc_ctxs[])
 {
-       struct cx23885_fh *fh = q->priv_data;
-
-       fh->dev->ts1.ts_packet_size  = mpeglinesize;
-       fh->dev->ts1.ts_packet_count = mpeglines;
-
-       *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
-       *count = mpegbufs;
+       struct cx23885_dev *dev = q->drv_priv;
 
+       dev->ts1.ts_packet_size  = mpeglinesize;
+       dev->ts1.ts_packet_count = mpeglines;
+       *num_planes = 1;
+       sizes[0] = mpeglinesize * mpeglines;
+       *num_buffers = mpegbufs;
        return 0;
 }
 
-static int bb_buf_prepare(struct videobuf_queue *q,
-       struct videobuf_buffer *vb, enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-       struct cx23885_fh *fh = q->priv_data;
-       return cx23885_buf_prepare(q, &fh->dev->ts1,
-               (struct cx23885_buffer *)vb,
-               field);
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer *buf =
+               container_of(vb, struct cx23885_buffer, vb);
+
+       return cx23885_buf_prepare(buf, &dev->ts1);
 }
 
-static void bb_buf_queue(struct videobuf_queue *q,
-       struct videobuf_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
 {
-       struct cx23885_fh *fh = q->priv_data;
-       cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb);
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+
+       cx23885_free_buffer(dev, buf);
+
+       dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
 }
 
-static void bb_buf_release(struct videobuf_queue *q,
-       struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
 {
-       cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
-}
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer   *buf = container_of(vb,
+               struct cx23885_buffer, vb);
 
-static struct videobuf_queue_ops cx23885_qops = {
-       .buf_setup    = bb_buf_setup,
-       .buf_prepare  = bb_buf_prepare,
-       .buf_queue    = bb_buf_queue,
-       .buf_release  = bb_buf_release,
-};
+       cx23885_buf_queue(&dev->ts1, buf);
+}
 
-/* ------------------------------------------------------------------ */
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct cx23885_dev *dev = q->drv_priv;
+       struct cx23885_dmaqueue *dmaq = &dev->ts1.mpegq;
+       unsigned long flags;
+       int ret;
+
+       ret = cx23885_initialize_codec(dev, 1);
+       if (ret == 0) {
+               struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
+
+               cx23885_start_dma(&dev->ts1, dmaq, buf);
+               return 0;
+       }
+       spin_lock_irqsave(&dev->slock, flags);
+       while (!list_empty(&dmaq->active)) {
+               struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
 
-static const u32 *ctrl_classes[] = {
-       cx2341x_mpeg_ctrls,
-       NULL
-};
+               list_del(&buf->queue);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+       }
+       spin_unlock_irqrestore(&dev->slock, flags);
+       return ret;
+}
 
-static int cx23885_queryctrl(struct cx23885_dev *dev,
-       struct v4l2_queryctrl *qctrl)
+static void cx23885_stop_streaming(struct vb2_queue *q)
 {
-       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
-       if (qctrl->id == 0)
-               return -EINVAL;
+       struct cx23885_dev *dev = q->drv_priv;
 
-       /* MPEG V4L2 controls */
-       if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
-               qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+       /* stop mpeg capture */
+       cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+                       CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+                       CX23885_RAW_BITS_NONE);
 
-       return 0;
+       msleep(500);
+       cx23885_417_check_encoder(dev);
+       cx23885_cancel_buffers(&dev->ts1);
 }
 
-static int cx23885_querymenu(struct cx23885_dev *dev,
-       struct v4l2_querymenu *qmenu)
-{
-       struct v4l2_queryctrl qctrl;
+static struct vb2_ops cx23885_qops = {
+       .queue_setup    = queue_setup,
+       .buf_prepare  = buffer_prepare,
+       .buf_finish = buffer_finish,
+       .buf_queue    = buffer_queue,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+       .start_streaming = cx23885_start_streaming,
+       .stop_streaming = cx23885_stop_streaming,
+};
 
-       qctrl.id = qmenu->id;
-       cx23885_queryctrl(dev, &qctrl);
-       return v4l2_ctrl_query_menu(qmenu, &qctrl,
-               cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
-}
+/* ------------------------------------------------------------------ */
 
 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        *id = dev->tvnorm;
        return 0;
@@ -1223,29 +1246,26 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        unsigned int i;
+       int ret;
 
        for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
                if (id & cx23885_tvnorms[i].id)
                        break;
        if (i == ARRAY_SIZE(cx23885_tvnorms))
                return -EINVAL;
-       dev->encodernorm = cx23885_tvnorms[i];
 
-       /* Have the drier core notify the subdevices */
-       mutex_lock(&dev->lock);
-       cx23885_set_tvnorm(dev, id);
-       mutex_unlock(&dev->lock);
-
-       return 0;
+       ret = cx23885_set_tvnorm(dev, id);
+       if (!ret)
+               dev->encodernorm = cx23885_tvnorms[i];
+       return ret;
 }
 
 static int vidioc_enum_input(struct file *file, void *priv,
        struct v4l2_input *i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        dprintk(1, "%s()\n", __func__);
        return cx23885_enum_input(dev, i);
 }
@@ -1263,8 +1283,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *t)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
@@ -1281,8 +1300,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_s_tuner(struct file *file, void *priv,
                                const struct v4l2_tuner *t)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
@@ -1296,8 +1314,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
@@ -1315,27 +1332,10 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        return cx23885_set_frequency(file, priv, f);
 }
 
-static int vidioc_g_ctrl(struct file *file, void *priv,
-       struct v4l2_control *ctl)
-{
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
-       return cx23885_get_control(dev, ctl);
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-       struct v4l2_control *ctl)
-{
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
-       return cx23885_set_control(dev, ctl);
-}
-
 static int vidioc_querycap(struct file *file, void  *priv,
                                struct v4l2_capability *cap)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        struct cx23885_tsport  *tsport = &dev->ts1;
 
        strlcpy(cap->driver, dev->name, sizeof(cap->driver));
@@ -1368,8 +1368,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
@@ -1378,285 +1377,63 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        f->fmt.pix.colorspace   = 0;
        f->fmt.pix.width        = dev->ts1.width;
        f->fmt.pix.height       = dev->ts1.height;
-       f->fmt.pix.field        = fh->mpegq.field;
-       dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
-               dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+       f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
+       dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n",
+               dev->ts1.width, dev->ts1.height);
        return 0;
 }
 
 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
        f->fmt.pix.sizeimage    =
                dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
        f->fmt.pix.colorspace   = 0;
-       dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
-               dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+       f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
+       dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
+               dev->ts1.width, dev->ts1.height);
        return 0;
 }
 
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
        f->fmt.pix.sizeimage    =
                dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
        f->fmt.pix.colorspace   = 0;
+       f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
        dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
                f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
        return 0;
 }
 
-static int vidioc_reqbufs(struct file *file, void *priv,
-                               struct v4l2_requestbuffers *p)
-{
-       struct cx23885_fh  *fh  = file->private_data;
-
-       return videobuf_reqbufs(&fh->mpegq, p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
-                               struct v4l2_buffer *p)
-{
-       struct cx23885_fh  *fh  = file->private_data;
-
-       return videobuf_querybuf(&fh->mpegq, p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv,
-                               struct v4l2_buffer *p)
-{
-       struct cx23885_fh  *fh  = file->private_data;
-
-       return videobuf_qbuf(&fh->mpegq, p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
-       struct cx23885_fh  *fh  = priv;
-
-       return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK);
-}
-
-
-static int vidioc_streamon(struct file *file, void *priv,
-                               enum v4l2_buf_type i)
-{
-       struct cx23885_fh  *fh  = file->private_data;
-
-       return videobuf_streamon(&fh->mpegq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx23885_fh  *fh  = file->private_data;
-
-       return videobuf_streamoff(&fh->mpegq);
-}
-
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
-                               struct v4l2_ext_controls *f)
-{
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
-
-       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-       return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
-}
-
-static int vidioc_s_ext_ctrls(struct file *file, void *priv,
-                               struct v4l2_ext_controls *f)
-{
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
-       struct cx2341x_mpeg_params p;
-       int err;
-
-       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-
-       p = dev->mpeg_params;
-       err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
-
-       if (err == 0) {
-               err = cx2341x_update(dev, cx23885_mbox_func,
-                       &dev->mpeg_params, &p);
-               dev->mpeg_params = p;
-       }
-       return err;
-}
-
-static int vidioc_try_ext_ctrls(struct file *file, void *priv,
-                               struct v4l2_ext_controls *f)
-{
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
-       struct cx2341x_mpeg_params p;
-       int err;
-
-       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-
-       p = dev->mpeg_params;
-       err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
-       return err;
-}
-
 static int vidioc_log_status(struct file *file, void *priv)
 {
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        char name[32 + 2];
 
        snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO
-               "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
        call_all(dev, core, log_status);
-       cx2341x_log_status(&dev->mpeg_params, name);
-       printk(KERN_INFO
-               "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
+       v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name);
        return 0;
 }
 
-static int vidioc_querymenu(struct file *file, void *priv,
-                               struct v4l2_querymenu *a)
-{
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
-
-       return cx23885_querymenu(dev, a);
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-                               struct v4l2_queryctrl *c)
-{
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
-
-       return cx23885_queryctrl(dev, c);
-}
-
-static int mpeg_open(struct file *file)
-{
-       struct cx23885_dev *dev = video_drvdata(file);
-       struct cx23885_fh *fh;
-
-       dprintk(2, "%s()\n", __func__);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (!fh)
-               return -ENOMEM;
-
-       file->private_data = fh;
-       fh->dev      = dev;
-
-       videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops,
-                           &dev->pci->dev, &dev->ts1.slock,
-                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                           V4L2_FIELD_INTERLACED,
-                           sizeof(struct cx23885_buffer),
-                           fh, NULL);
-       return 0;
-}
-
-static int mpeg_release(struct file *file)
-{
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-
-       dprintk(2, "%s()\n", __func__);
-
-       /* FIXME: Review this crap */
-       /* Shut device down on last close */
-       if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
-               if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
-                       /* stop mpeg capture */
-                       cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
-                               CX23885_END_NOW, CX23885_MPEG_CAPTURE,
-                               CX23885_RAW_BITS_NONE);
-
-                       msleep(500);
-                       cx23885_417_check_encoder(dev);
-
-                       cx23885_cancel_buffers(&fh->dev->ts1);
-               }
-       }
-
-       if (fh->mpegq.streaming)
-               videobuf_streamoff(&fh->mpegq);
-       if (fh->mpegq.reading)
-               videobuf_read_stop(&fh->mpegq);
-
-       videobuf_mmap_free(&fh->mpegq);
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static ssize_t mpeg_read(struct file *file, char __user *data,
-       size_t count, loff_t *ppos)
-{
-       struct cx23885_fh *fh = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-
-       dprintk(2, "%s()\n", __func__);
-
-       /* Deal w/ A/V decoder * and mpeg encoder sync issues. */
-       /* Start mpeg encoder on first read. */
-       if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
-               if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
-                       if (cx23885_initialize_codec(dev, 1) < 0)
-                               return -EINVAL;
-               }
-       }
-
-       return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
-                                   file->f_flags & O_NONBLOCK);
-}
-
-static unsigned int mpeg_poll(struct file *file,
-       struct poll_table_struct *wait)
-{
-       struct cx23885_fh *fh = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-
-       dprintk(2, "%s\n", __func__);
-
-       return videobuf_poll_stream(file, &fh->mpegq, wait);
-}
-
-static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct cx23885_fh *fh = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-
-       dprintk(2, "%s()\n", __func__);
-
-       return videobuf_mmap_mapper(&fh->mpegq, vma);
-}
-
 static struct v4l2_file_operations mpeg_fops = {
        .owner         = THIS_MODULE,
-       .open          = mpeg_open,
-       .release       = mpeg_release,
-       .read          = mpeg_read,
-       .poll          = mpeg_poll,
-       .mmap          = mpeg_mmap,
-       .ioctl         = video_ioctl2,
+       .open           = v4l2_fh_open,
+       .release        = vb2_fop_release,
+       .read           = vb2_fop_read,
+       .poll           = vb2_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = vb2_fop_mmap,
 };
 
 static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
@@ -1669,25 +1446,19 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
        .vidioc_s_tuner          = vidioc_s_tuner,
        .vidioc_g_frequency      = vidioc_g_frequency,
        .vidioc_s_frequency      = vidioc_s_frequency,
-       .vidioc_s_ctrl           = vidioc_s_ctrl,
-       .vidioc_g_ctrl           = vidioc_g_ctrl,
        .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_reqbufs          = vidioc_reqbufs,
-       .vidioc_querybuf         = vidioc_querybuf,
-       .vidioc_qbuf             = vidioc_qbuf,
-       .vidioc_dqbuf            = vidioc_dqbuf,
-       .vidioc_streamon         = vidioc_streamon,
-       .vidioc_streamoff        = vidioc_streamoff,
-       .vidioc_g_ext_ctrls      = vidioc_g_ext_ctrls,
-       .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
-       .vidioc_try_ext_ctrls    = vidioc_try_ext_ctrls,
+       .vidioc_reqbufs       = vb2_ioctl_reqbufs,
+       .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf      = vb2_ioctl_querybuf,
+       .vidioc_qbuf          = vb2_ioctl_qbuf,
+       .vidioc_dqbuf         = vb2_ioctl_dqbuf,
+       .vidioc_streamon      = vb2_ioctl_streamon,
+       .vidioc_streamoff     = vb2_ioctl_streamoff,
        .vidioc_log_status       = vidioc_log_status,
-       .vidioc_querymenu        = vidioc_querymenu,
-       .vidioc_queryctrl        = vidioc_queryctrl,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_chip_info      = cx23885_g_chip_info,
        .vidioc_g_register       = cx23885_g_register,
@@ -1711,6 +1482,7 @@ void cx23885_417_unregister(struct cx23885_dev *dev)
                        video_unregister_device(dev->v4l_device);
                else
                        video_device_release(dev->v4l_device);
+               v4l2_ctrl_handler_free(&dev->cxhdl.hdl);
                dev->v4l_device = NULL;
        }
 }
@@ -1742,6 +1514,7 @@ int cx23885_417_register(struct cx23885_dev *dev)
        /* FIXME: Port1 hardcoded here */
        int err = -ENODEV;
        struct cx23885_tsport *tsport = &dev->ts1;
+       struct vb2_queue *q;
 
        dprintk(1, "%s()\n", __func__);
 
@@ -1757,14 +1530,36 @@ int cx23885_417_register(struct cx23885_dev *dev)
                tsport->height = 576;
 
        tsport->width = 720;
-       cx2341x_fill_defaults(&dev->mpeg_params);
-
-       dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+       dev->cxhdl.port = CX2341X_PORT_SERIAL;
+       err = cx2341x_handler_init(&dev->cxhdl, 50);
+       if (err)
+               return err;
+       dev->cxhdl.priv = dev;
+       dev->cxhdl.func = cx23885_api_func;
+       cx2341x_handler_set_50hz(&dev->cxhdl, tsport->height == 576);
+       v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL);
 
        /* Allocate and initialize V4L video device */
        dev->v4l_device = cx23885_video_dev_alloc(tsport,
                dev->pci, &cx23885_mpeg_template, "mpeg");
+       q = &dev->vb2_mpegq;
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+       q->gfp_flags = GFP_DMA32;
+       q->min_buffers_needed = 2;
+       q->drv_priv = dev;
+       q->buf_struct_size = sizeof(struct cx23885_buffer);
+       q->ops = &cx23885_qops;
+       q->mem_ops = &vb2_dma_sg_memops;
+       q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       q->lock = &dev->lock;
+
+       err = vb2_queue_init(q);
+       if (err < 0)
+               return err;
        video_set_drvdata(dev->v4l_device, dev);
+       dev->v4l_device->lock = &dev->lock;
+       dev->v4l_device->queue = q;
        err = video_register_device(dev->v4l_device,
                VFL_TYPE_GRABBER, -1);
        if (err < 0) {
index 554798dcedd09b3a1ad86961b2fd5fde691df254..ae7c2e89ad1cd6b9aebe8f0baea24d76e9065b79 100644 (file)
  *  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>
@@ -84,6 +80,82 @@ MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]");
 #define AUD_INT_MCHG_IRQ        (1 << 21)
 #define GP_COUNT_CONTROL_RESET 0x3
 
+static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages)
+{
+       struct cx23885_audio_buffer *buf = chip->buf;
+       struct page *pg;
+       int i;
+
+       buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
+       if (NULL == buf->vaddr) {
+               dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
+               return -ENOMEM;
+       }
+
+       dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
+                               (unsigned long)buf->vaddr,
+                               nr_pages << PAGE_SHIFT);
+
+       memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);
+       buf->nr_pages = nr_pages;
+
+       buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist));
+       if (NULL == buf->sglist)
+               goto vzalloc_err;
+
+       sg_init_table(buf->sglist, buf->nr_pages);
+       for (i = 0; i < buf->nr_pages; i++) {
+               pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE);
+               if (NULL == pg)
+                       goto vmalloc_to_page_err;
+               sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0);
+       }
+       return 0;
+
+vmalloc_to_page_err:
+       vfree(buf->sglist);
+       buf->sglist = NULL;
+vzalloc_err:
+       vfree(buf->vaddr);
+       buf->vaddr = NULL;
+       return -ENOMEM;
+}
+
+static int cx23885_alsa_dma_map(struct cx23885_audio_dev *dev)
+{
+       struct cx23885_audio_buffer *buf = dev->buf;
+
+       buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist,
+                       buf->nr_pages, PCI_DMA_FROMDEVICE);
+
+       if (0 == buf->sglen) {
+               pr_warn("%s: cx23885_alsa_map_sg failed\n", __func__);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int cx23885_alsa_dma_unmap(struct cx23885_audio_dev *dev)
+{
+       struct cx23885_audio_buffer *buf = dev->buf;
+
+       if (!buf->sglen)
+               return 0;
+
+       dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE);
+       buf->sglen = 0;
+       return 0;
+}
+
+static int cx23885_alsa_dma_free(struct cx23885_audio_buffer *buf)
+{
+       vfree(buf->sglist);
+       buf->sglist = NULL;
+       vfree(buf->vaddr);
+       buf->vaddr = NULL;
+       return 0;
+}
+
 /*
  * BOARD Specific: Sets audio DMA
  */
@@ -198,15 +270,18 @@ int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask)
 
 static int dsp_buffer_free(struct cx23885_audio_dev *chip)
 {
+       struct cx23885_riscmem *risc;
+
        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);
+       cx23885_alsa_dma_unmap(chip);
+       cx23885_alsa_dma_free(chip->buf);
+       risc = &chip->buf->risc;
+       pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma);
        kfree(chip->buf);
 
-       chip->dma_risc = NULL;
+       chip->buf = NULL;
        chip->dma_size = 0;
 
        return 0;
@@ -289,6 +364,7 @@ static int snd_cx23885_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
+
 /*
  * hw_params callback
  */
@@ -296,8 +372,6 @@ 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;
 
@@ -318,19 +392,18 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
                return -ENOMEM;
 
        buf->bpl = chip->period_size;
+       chip->buf = buf;
 
-       dma = &buf->dma;
-       videobuf_dma_init(dma);
-       ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
+       ret = cx23885_alsa_dma_init(chip,
                        (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
        if (ret < 0)
                goto error;
 
-       ret = videobuf_dma_map(&chip->pci->dev, dma);
+       ret = cx23885_alsa_dma_map(chip);
        if (ret < 0)
                goto error;
 
-       ret = cx23885_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+       ret = cx23885_risc_databuffer(chip->pci, &buf->risc, buf->sglist,
                                   chip->period_size, chip->num_periods, 1);
        if (ret < 0)
                goto error;
@@ -340,10 +413,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
        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_area = chip->buf->vaddr;
        substream->runtime->dma_bytes = chip->dma_size;
        substream->runtime->dma_addr = 0;
 
@@ -351,6 +421,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
 
 error:
        kfree(buf);
+       chip->buf = NULL;
        return ret;
 }
 
index c443b7ac5adfeb29806fd0cc345ac9b8d64c0c16..877dad89107ec5348cb0e21323122af8202f8365 100644 (file)
  *  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 "cx23885.h"
index d2915c3e53a29d87ed9ea220c482d4434e9e33e7..97f232f8efb918fdb238c36ddff56c3a85ff0634 100644 (file)
  *  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 _CX23885_AV_H_
index c2b6080071908722706cd335917e6c99b4064dee..88c257d1161b1629294150e9bb9bc49bf887f52e 100644 (file)
  *  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>
@@ -679,6 +675,11 @@ struct cx23885_board cx23885_boards[] = {
                        .amux   = CX25840_AUDIO7,
                } },
        },
+       [CX23885_BOARD_DVBSKY_T9580] = {
+               .name           = "DVBSky T9580",
+               .portb          = CX23885_MPEG_DVB,
+               .portc          = CX23885_MPEG_DVB,
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -934,6 +935,10 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x18ac,
                .subdevice = 0xdb98,
                .card      = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2,
+       }, {
+               .subvendor = 0x4254,
+               .subdevice = 0x9580,
+               .card      = CX23885_BOARD_DVBSKY_T9580,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1528,6 +1533,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                cx_set(GP0_IO, 0x00040004);
                mdelay(60);
                break;
+       case CX23885_BOARD_DVBSKY_T9580:
+               /* enable GPIO3-18 pins */
+               cx_write(MC417_CTL, 0x00000037);
+               cx23885_gpio_enable(dev, GPIO_2 | GPIO_11, 1);
+               cx23885_gpio_clear(dev, GPIO_2 | GPIO_11);
+               mdelay(100);
+               cx23885_gpio_set(dev, GPIO_2 | GPIO_11);
+               break;
        }
 }
 
@@ -1851,6 +1864,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
                break;
+       case CX23885_BOARD_DVBSKY_T9580:
+               ts1->gen_ctrl_val  = 0x5; /* Parallel */
+               ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               ts2->gen_ctrl_val  = 0x8; /* Serial bus */
+               ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -1913,6 +1934,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_AVERMEDIA_HC81R:
        case CX23885_BOARD_TBS_6980:
        case CX23885_BOARD_TBS_6981:
+       case CX23885_BOARD_DVBSKY_T9580:
                dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
                                &dev->i2c_bus[2].i2c_adap,
                                "cx25840", 0x88 >> 1, NULL);
@@ -1970,5 +1992,3 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        }
        }
 }
-
-/* ------------------------------------------------------------------ */
index edcd79db1e4ebc5d8ba6319b2ccb3c900a3024b4..331eddac7222ae7f62fb757148f90c8881b5ef4c 100644 (file)
  *  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>
@@ -420,39 +416,23 @@ static int cx23885_risc_decode(u32 risc)
        return incr[risc >> 28] ? incr[risc >> 28] : 1;
 }
 
-void cx23885_wakeup(struct cx23885_tsport *port,
+static void cx23885_wakeup(struct cx23885_tsport *port,
                           struct cx23885_dmaqueue *q, u32 count)
 {
        struct cx23885_dev *dev = port->dev;
        struct cx23885_buffer *buf;
-       int bc;
-
-       for (bc = 0;; bc++) {
-               if (list_empty(&q->active))
-                       break;
-               buf = list_entry(q->active.next,
-                                struct cx23885_buffer, vb.queue);
-
-               /* count comes from the hw and is is 16bit wide --
-                * this trick handles wrap-arounds correctly for
-                * up to 32767 buffers in flight... */
-               if ((s16) (count - buf->count) < 0)
-                       break;
 
-               v4l2_get_timestamp(&buf->vb.ts);
-               dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
-                       count, buf->count);
-               buf->vb.state = VIDEOBUF_DONE;
-               list_del(&buf->vb.queue);
-               wake_up(&buf->vb.done);
-       }
        if (list_empty(&q->active))
-               del_timer(&q->timeout);
-       else
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-       if (bc != 1)
-               printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n",
-                      __func__, bc);
+               return;
+       buf = list_entry(q->active.next,
+                        struct cx23885_buffer, queue);
+
+       v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+       buf->vb.v4l2_buf.sequence = q->count++;
+       dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index,
+               count, q->count);
+       list_del(&buf->queue);
+       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
 }
 
 int cx23885_sram_channel_setup(struct cx23885_dev *dev,
@@ -482,8 +462,8 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
                lines = 6;
        BUG_ON(lines < 2);
 
-       cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       cx_write(8 + 4, 8);
+       cx_write(8 + 0, RISC_JUMP | RISC_CNT_RESET);
+       cx_write(8 + 4, 12);
        cx_write(8 + 8, 0);
 
        /* write CDT */
@@ -590,7 +570,7 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev,
 }
 
 static void cx23885_risc_disasm(struct cx23885_tsport *port,
-                               struct btcx_riscmem *risc)
+                               struct cx23885_riscmem *risc)
 {
        struct cx23885_dev *dev = port->dev;
        unsigned int i, j, n;
@@ -699,10 +679,6 @@ static int get_resources(struct cx23885_dev *dev)
        return -EBUSY;
 }
 
-static void cx23885_timeout(unsigned long data);
-int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-                               u32 reg, u32 mask, u32 value);
-
 static int cx23885_init_tsport(struct cx23885_dev *dev,
        struct cx23885_tsport *port, int portno)
 {
@@ -719,11 +695,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev,
        port->nr = portno;
 
        INIT_LIST_HEAD(&port->mpegq.active);
-       INIT_LIST_HEAD(&port->mpegq.queued);
-       port->mpegq.timeout.function = cx23885_timeout;
-       port->mpegq.timeout.data = (unsigned long)port;
-       init_timer(&port->mpegq.timeout);
-
        mutex_init(&port->frontends.lock);
        INIT_LIST_HEAD(&port->frontends.felist);
        port->frontends.active_fe_id = 0;
@@ -776,9 +747,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev,
                BUG();
        }
 
-       cx23885_risc_stopper(dev->pci, &port->mpegq.stopper,
-                    port->reg_dma_ctl, port->dma_ctl_val, 0x00);
-
        return 0;
 }
 
@@ -1089,11 +1057,18 @@ 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 lpi)
+                              unsigned int lines,  unsigned int lpi, bool jump)
 {
        struct scatterlist *sg;
        unsigned int line, todo, sol;
 
+
+       if (jump) {
+               *(rp++) = cpu_to_le32(RISC_JUMP);
+               *(rp++) = cpu_to_le32(0);
+               *(rp++) = cpu_to_le32(0); /* bits 63-32 */
+       }
+
        /* sync instruction */
        if (sync_line != NO_SYNC_LINE)
                *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
@@ -1146,14 +1121,13 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
        return rp;
 }
 
-int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_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)
@@ -1168,19 +1142,20 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
        /* 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;
+       instructions += 5;
+       risc->size = instructions * 12;
+       risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
+       if (risc->cpu == NULL)
+               return -ENOMEM;
 
        /* write risc instructions */
        rp = risc->cpu;
        if (UNSET != top_offset)
                rp = cx23885_risc_field(rp, sglist, top_offset, 0,
-                                       bpl, padding, lines, 0);
+                                       bpl, padding, lines, 0, true);
        if (UNSET != bottom_offset)
                rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
-                                       bpl, padding, lines, 0);
+                                       bpl, padding, lines, 0, UNSET == top_offset);
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
@@ -1189,14 +1164,13 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 }
 
 int cx23885_risc_databuffer(struct pci_dev *pci,
-                                  struct btcx_riscmem *risc,
+                                  struct cx23885_riscmem *risc,
                                   struct scatterlist *sglist,
                                   unsigned int bpl,
                                   unsigned int lines, unsigned int lpi)
 {
        u32 instructions;
        __le32 *rp;
-       int rc;
 
        /* estimate risc mem: worst case is one write per page border +
           one write per scan line + syncs + jump (all 2 dwords).  Here
@@ -1204,16 +1178,17 @@ int cx23885_risc_databuffer(struct pci_dev *pci,
           than PAGE_SIZE */
        /* Jump and write need an extra dword */
        instructions  = 1 + (bpl * lines) / PAGE_SIZE + lines;
-       instructions += 1;
+       instructions += 4;
 
-       rc = btcx_riscmem_alloc(pci, risc, instructions*12);
-       if (rc < 0)
-               return rc;
+       risc->size = instructions * 12;
+       risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
+       if (risc->cpu == NULL)
+               return -ENOMEM;
 
        /* write risc instructions */
        rp = risc->cpu;
        rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE,
-                               bpl, 0, lines, lpi);
+                               bpl, 0, lines, lpi, lpi == 0);
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
@@ -1221,14 +1196,13 @@ int cx23885_risc_databuffer(struct pci_dev *pci,
        return 0;
 }
 
-int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+int cx23885_risc_vbibuffer(struct pci_dev *pci, struct cx23885_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)
@@ -1243,22 +1217,23 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
        /* 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;
+       instructions += 5;
+       risc->size = instructions * 12;
+       risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
+       if (risc->cpu == NULL)
+               return -ENOMEM;
        /* 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);
+               rp = cx23885_risc_field(rp, sglist, top_offset, 0,
+                                       bpl, padding, lines, 0, true);
 
        if (UNSET != bottom_offset)
-               rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207,
-                                       bpl, padding, lines, 0);
+               rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
+                                       bpl, padding, lines, 0, UNSET == top_offset);
 
 
 
@@ -1269,38 +1244,12 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 }
 
 
-int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-                               u32 reg, u32 mask, u32 value)
+void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf)
 {
-       __le32 *rp;
-       int rc;
-
-       rc = btcx_riscmem_alloc(pci, risc, 4*16);
-       if (rc < 0)
-               return rc;
-
-       /* write risc instructions */
-       rp = risc->cpu;
-       *(rp++) = cpu_to_le32(RISC_WRITECR  | RISC_IRQ2);
-       *(rp++) = cpu_to_le32(reg);
-       *(rp++) = cpu_to_le32(value);
-       *(rp++) = cpu_to_le32(mask);
-       *(rp++) = cpu_to_le32(RISC_JUMP);
-       *(rp++) = cpu_to_le32(risc->dma);
-       *(rp++) = cpu_to_le32(0); /* bits 63-32 */
-       return 0;
-}
-
-void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
-{
-       struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+       struct cx23885_riscmem *risc = &buf->risc;
 
        BUG_ON(in_interrupt());
-       videobuf_waiton(q, &buf->vb, 0, 0);
-       videobuf_dma_unmap(q->dev, dma);
-       videobuf_dma_free(dma);
-       btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
-       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+       pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
 }
 
 static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
@@ -1355,7 +1304,7 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
                port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
 }
 
-static int cx23885_start_dma(struct cx23885_tsport *port,
+int cx23885_start_dma(struct cx23885_tsport *port,
                             struct cx23885_dmaqueue *q,
                             struct cx23885_buffer   *buf)
 {
@@ -1363,7 +1312,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
        u32 reg;
 
        dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__,
-               buf->vb.width, buf->vb.height, buf->vb.field);
+               dev->width, dev->height, dev->field);
 
        /* Stop the fifo and risc engine for this port */
        cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
@@ -1379,7 +1328,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
        }
 
        /* write TS length to chip */
-       cx_write(port->reg_lngth, buf->vb.width);
+       cx_write(port->reg_lngth, port->ts_packet_size);
 
        if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
                (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) {
@@ -1408,7 +1357,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
        /* NOTE: this is 2 (reserved) for portb, does it matter? */
        /* reset counter to zero */
        cx_write(port->reg_gpcnt_ctl, 3);
-       q->count = 1;
+       q->count = 0;
 
        /* Set VIDB pins to input */
        if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
@@ -1497,134 +1446,83 @@ static int cx23885_stop_dma(struct cx23885_tsport *port)
        return 0;
 }
 
-int cx23885_restart_queue(struct cx23885_tsport *port,
-                               struct cx23885_dmaqueue *q)
-{
-       struct cx23885_dev *dev = port->dev;
-       struct cx23885_buffer *buf;
-
-       dprintk(5, "%s()\n", __func__);
-       if (list_empty(&q->active)) {
-               struct cx23885_buffer *prev;
-               prev = NULL;
-
-               dprintk(5, "%s() queue is empty\n", __func__);
-
-               for (;;) {
-                       if (list_empty(&q->queued))
-                               return 0;
-                       buf = list_entry(q->queued.next, struct cx23885_buffer,
-                                        vb.queue);
-                       if (NULL == prev) {
-                               list_move_tail(&buf->vb.queue, &q->active);
-                               cx23885_start_dma(port, q, buf);
-                               buf->vb.state = VIDEOBUF_ACTIVE;
-                               buf->count    = q->count++;
-                               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-                               dprintk(5, "[%p/%d] restart_queue - f/active\n",
-                                       buf, buf->vb.i);
-
-                       } else if (prev->vb.width  == buf->vb.width  &&
-                                  prev->vb.height == buf->vb.height &&
-                                  prev->fmt       == buf->fmt) {
-                               list_move_tail(&buf->vb.queue, &q->active);
-                               buf->vb.state = VIDEOBUF_ACTIVE;
-                               buf->count    = q->count++;
-                               prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-                               /* 64 bit bits 63-32 */
-                               prev->risc.jmp[2] = cpu_to_le32(0);
-                               dprintk(5, "[%p/%d] restart_queue - m/active\n",
-                                       buf, buf->vb.i);
-                       } else {
-                               return 0;
-                       }
-                       prev = buf;
-               }
-               return 0;
-       }
-
-       buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
-       dprintk(2, "restart_queue [%p/%d]: restart dma\n",
-               buf, buf->vb.i);
-       cx23885_start_dma(port, q, buf);
-       list_for_each_entry(buf, &q->active, vb.queue)
-               buf->count = q->count++;
-       mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-       return 0;
-}
-
 /* ------------------------------------------------------------------ */
 
-int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
-                       struct cx23885_buffer *buf, enum v4l2_field field)
+int cx23885_buf_prepare(struct cx23885_buffer *buf, struct cx23885_tsport *port)
 {
        struct cx23885_dev *dev = port->dev;
        int size = port->ts_packet_size * port->ts_packet_count;
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb, 0);
        int rc;
 
        dprintk(1, "%s: %p\n", __func__, buf);
-       if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+       if (vb2_plane_size(&buf->vb, 0) < size)
                return -EINVAL;
+       vb2_set_plane_payload(&buf->vb, 0, size);
 
-       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-               buf->vb.width  = port->ts_packet_size;
-               buf->vb.height = port->ts_packet_count;
-               buf->vb.size   = size;
-               buf->vb.field  = field /*V4L2_FIELD_TOP*/;
-
-               rc = videobuf_iolock(q, &buf->vb, NULL);
-               if (0 != rc)
-                       goto fail;
-               cx23885_risc_databuffer(dev->pci, &buf->risc,
-                                       videobuf_to_dma(&buf->vb)->sglist,
-                                       buf->vb.width, buf->vb.height, 0);
-       }
-       buf->vb.state = VIDEOBUF_PREPARED;
-       return 0;
+       rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+       if (!rc)
+               return -EIO;
 
- fail:
-       cx23885_free_buffer(q, buf);
-       return rc;
+       cx23885_risc_databuffer(dev->pci, &buf->risc,
+                               sgt->sgl,
+                               port->ts_packet_size, port->ts_packet_count, 0);
+       return 0;
 }
 
+/*
+ * The risc program for each buffer works as follows: it starts with a simple
+ * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
+ * the initial JUMP).
+ *
+ * This is the risc program of the first buffer to be queued if the active list
+ * is empty and it just keeps DMAing this buffer without generating any
+ * interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the code for that buffer
+ * will generate an interrupt which signals that the previous buffer has been
+ * DMAed successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
 void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
 {
        struct cx23885_buffer    *prev;
        struct cx23885_dev *dev = port->dev;
        struct cx23885_dmaqueue  *cx88q = &port->mpegq;
+       unsigned long flags;
 
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
+       buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+       buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
        buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
 
+       spin_lock_irqsave(&dev->slock, flags);
        if (list_empty(&cx88q->active)) {
-               dprintk(1, "queue is empty - first active\n");
-               list_add_tail(&buf->vb.queue, &cx88q->active);
-               cx23885_start_dma(port, cx88q, buf);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count    = cx88q->count++;
-               mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
+               list_add_tail(&buf->queue, &cx88q->active);
                dprintk(1, "[%p/%d] %s - first active\n",
-                       buf, buf->vb.i, __func__);
+                       buf, buf->vb.v4l2_buf.index, __func__);
        } else {
-               dprintk(1, "queue is not empty - append to active\n");
+               buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
                prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
-                                 vb.queue);
-               list_add_tail(&buf->vb.queue, &cx88q->active);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count    = cx88q->count++;
+                                 queue);
+               list_add_tail(&buf->queue, &cx88q->active);
                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-               prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
                dprintk(1, "[%p/%d] %s - append to active\n",
-                        buf, buf->vb.i, __func__);
+                        buf, buf->vb.v4l2_buf.index, __func__);
        }
+       spin_unlock_irqrestore(&dev->slock, flags);
 }
 
 /* ----------------------------------------------------------- */
 
-static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
-                             int restart)
+static void do_cancel_buffers(struct cx23885_tsport *port, char *reason)
 {
        struct cx23885_dev *dev = port->dev;
        struct cx23885_dmaqueue *q = &port->mpegq;
@@ -1634,16 +1532,11 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
        spin_lock_irqsave(&port->slock, flags);
        while (!list_empty(&q->active)) {
                buf = list_entry(q->active.next, struct cx23885_buffer,
-                                vb.queue);
-               list_del(&buf->vb.queue);
-               buf->vb.state = VIDEOBUF_ERROR;
-               wake_up(&buf->vb.done);
+                                queue);
+               list_del(&buf->queue);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
                dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
-                       buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
-       }
-       if (restart) {
-               dprintk(1, "restarting queue\n");
-               cx23885_restart_queue(port, q);
+                       buf, buf->vb.v4l2_buf.index, reason, (unsigned long)buf->risc.dma);
        }
        spin_unlock_irqrestore(&port->slock, flags);
 }
@@ -1651,27 +1544,10 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
 void cx23885_cancel_buffers(struct cx23885_tsport *port)
 {
        struct cx23885_dev *dev = port->dev;
-       struct cx23885_dmaqueue *q = &port->mpegq;
-
-       dprintk(1, "%s()\n", __func__);
-       del_timer_sync(&q->timeout);
-       cx23885_stop_dma(port);
-       do_cancel_buffers(port, "cancel", 0);
-}
-
-static void cx23885_timeout(unsigned long data)
-{
-       struct cx23885_tsport *port = (struct cx23885_tsport *)data;
-       struct cx23885_dev *dev = port->dev;
 
        dprintk(1, "%s()\n", __func__);
-
-       if (debug > 5)
-               cx23885_sram_channel_dump(dev,
-                       &dev->sram_channels[port->sram_chno]);
-
        cx23885_stop_dma(port);
-       do_cancel_buffers(port, "timeout", 1);
+       do_cancel_buffers(port, "cancel");
 }
 
 int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
@@ -1721,11 +1597,6 @@ int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
                spin_lock(&port->slock);
                cx23885_wakeup(port, &port->mpegq, count);
                spin_unlock(&port->slock);
-       } else if (status & VID_B_MSK_RISCI2) {
-               dprintk(7, "        VID_B_MSK_RISCI2\n");
-               spin_lock(&port->slock);
-               cx23885_restart_queue(port, &port->mpegq);
-               spin_unlock(&port->slock);
        }
        if (status) {
                cx_write(port->reg_ts_int_stat, status);
@@ -1777,14 +1648,6 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
                cx23885_wakeup(port, &port->mpegq, count);
                spin_unlock(&port->slock);
 
-       } else if (status & VID_BC_MSK_RISCI2) {
-
-               dprintk(7, " (RISCI2            0x%08x)\n", VID_BC_MSK_RISCI2);
-
-               spin_lock(&port->slock);
-               cx23885_restart_queue(port, &port->mpegq);
-               spin_unlock(&port->slock);
-
        }
        if (status) {
                cx_write(port->reg_ts_int_stat, status);
@@ -2087,6 +1950,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
                           const struct pci_device_id *pci_id)
 {
        struct cx23885_dev *dev;
+       struct v4l2_ctrl_handler *hdl;
        int err;
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -2097,6 +1961,14 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
        if (err < 0)
                goto fail_free;
 
+       hdl = &dev->ctrl_handler;
+       v4l2_ctrl_handler_init(hdl, 6);
+       if (hdl->error) {
+               err = hdl->error;
+               goto fail_ctrl;
+       }
+       dev->v4l2_dev.ctrl_handler = hdl;
+
        /* Prepare to handle notifications from subdevices */
        cx23885_v4l2_dev_notify_init(dev);
 
@@ -2104,12 +1976,12 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
        dev->pci = pci_dev;
        if (pci_enable_device(pci_dev)) {
                err = -EIO;
-               goto fail_unreg;
+               goto fail_ctrl;
        }
 
        if (cx23885_dev_setup(dev) < 0) {
                err = -EINVAL;
-               goto fail_unreg;
+               goto fail_ctrl;
        }
 
        /* print pci info */
@@ -2157,7 +2029,8 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
 
 fail_irq:
        cx23885_dev_unregister(dev);
-fail_unreg:
+fail_ctrl:
+       v4l2_ctrl_handler_free(hdl);
        v4l2_device_unregister(&dev->v4l2_dev);
 fail_free:
        kfree(dev);
@@ -2180,6 +2053,7 @@ static void cx23885_finidev(struct pci_dev *pci_dev)
        free_irq(pci_dev->irq, dev);
 
        cx23885_dev_unregister(dev);
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
        v4l2_device_unregister(v4l2_dev);
        kfree(dev);
 }
index 968fecc32f9cad35413945e0af9f7ce9edbde5bb..13734b8c791724e8a84dc27cd5949aeaf6a3b1ca 100644 (file)
  *  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 "a8293.h"
 #include "mb86a20s.h"
 #include "si2165.h"
+#include "si2168.h"
+#include "si2157.h"
+#include "m88ds3103.h"
+#include "m88ts2022.h"
 
 static unsigned int debug;
 
@@ -91,59 +91,95 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 /* ------------------------------------------------------------------ */
 
-static int dvb_buf_setup(struct videobuf_queue *q,
-                        unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+                          unsigned int *num_buffers, unsigned int *num_planes,
+                          unsigned int sizes[], void *alloc_ctxs[])
 {
-       struct cx23885_tsport *port = q->priv_data;
+       struct cx23885_tsport *port = q->drv_priv;
 
        port->ts_packet_size  = 188 * 4;
        port->ts_packet_count = 32;
-
-       *size  = port->ts_packet_size * port->ts_packet_count;
-       *count = 32;
+       *num_planes = 1;
+       sizes[0] = port->ts_packet_size * port->ts_packet_count;
+       *num_buffers = 32;
        return 0;
 }
 
-static int dvb_buf_prepare(struct videobuf_queue *q,
-                          struct videobuf_buffer *vb, enum v4l2_field field)
+
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-       struct cx23885_tsport *port = q->priv_data;
-       return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field);
+       struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer *buf =
+               container_of(vb, struct cx23885_buffer, vb);
+
+       return cx23885_buf_prepare(buf, port);
 }
 
-static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
 {
-       struct cx23885_tsport *port = q->priv_data;
-       cx23885_buf_queue(port, (struct cx23885_buffer *)vb);
+       struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
+       struct cx23885_dev *dev = port->dev;
+       struct cx23885_buffer *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+
+       cx23885_free_buffer(dev, buf);
+
+       dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
 }
 
-static void dvb_buf_release(struct videobuf_queue *q,
-                           struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
 {
-       cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
+       struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer   *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+
+       cx23885_buf_queue(port, buf);
 }
 
 static void cx23885_dvb_gate_ctrl(struct cx23885_tsport  *port, int open)
 {
-       struct videobuf_dvb_frontends *f;
-       struct videobuf_dvb_frontend *fe;
+       struct vb2_dvb_frontends *f;
+       struct vb2_dvb_frontend *fe;
 
        f = &port->frontends;
 
        if (f->gate <= 1) /* undefined or fe0 */
-               fe = videobuf_dvb_get_frontend(f, 1);
+               fe = vb2_dvb_get_frontend(f, 1);
        else
-               fe = videobuf_dvb_get_frontend(f, f->gate);
+               fe = vb2_dvb_get_frontend(f, f->gate);
 
        if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
                fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
 }
 
-static struct videobuf_queue_ops dvb_qops = {
-       .buf_setup    = dvb_buf_setup,
-       .buf_prepare  = dvb_buf_prepare,
-       .buf_queue    = dvb_buf_queue,
-       .buf_release  = dvb_buf_release,
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct cx23885_tsport *port = q->drv_priv;
+       struct cx23885_dmaqueue *dmaq = &port->mpegq;
+       struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
+
+       cx23885_start_dma(port, dmaq, buf);
+       return 0;
+}
+
+static void cx23885_stop_streaming(struct vb2_queue *q)
+{
+       struct cx23885_tsport *port = q->drv_priv;
+
+       cx23885_cancel_buffers(port);
+}
+
+static struct vb2_ops dvb_qops = {
+       .queue_setup    = queue_setup,
+       .buf_prepare  = buffer_prepare,
+       .buf_finish = buffer_finish,
+       .buf_queue    = buffer_queue,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+       .start_streaming = cx23885_start_streaming,
+       .stop_streaming = cx23885_stop_streaming,
 };
 
 static struct s5h1409_config hauppauge_generic_config = {
@@ -551,6 +587,35 @@ static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
        return 0;
 }
 
+static int dvbsky_t9580_set_voltage(struct dvb_frontend *fe,
+                                       fe_sec_voltage_t voltage)
+{
+       struct cx23885_tsport *port = fe->dvb->priv;
+       struct cx23885_dev *dev = port->dev;
+
+       cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1);
+
+       switch (voltage) {
+       case SEC_VOLTAGE_13:
+               cx23885_gpio_set(dev, GPIO_1);
+               cx23885_gpio_clear(dev, GPIO_0);
+               break;
+       case SEC_VOLTAGE_18:
+               cx23885_gpio_set(dev, GPIO_1);
+               cx23885_gpio_set(dev, GPIO_0);
+               break;
+       case SEC_VOLTAGE_OFF:
+               cx23885_gpio_clear(dev, GPIO_1);
+               cx23885_gpio_clear(dev, GPIO_0);
+               break;
+       }
+
+       /* call the frontend set_voltage function */
+       port->fe_set_voltage(fe, voltage);
+
+       return 0;
+}
+
 static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *p = &fe->dtv_property_cache;
@@ -715,6 +780,19 @@ static const struct si2165_config hauppauge_hvr4400_si2165_config = {
        .ref_freq_Hz    = 16000000,
 };
 
+static const struct m88ds3103_config dvbsky_t9580_m88ds3103_config = {
+       .i2c_addr = 0x68,
+       .clock = 27000000,
+       .i2c_wr_max = 33,
+       .clock_out = 0,
+       .ts_mode = M88DS3103_TS_PARALLEL,
+       .ts_clk = 16000,
+       .ts_clk_pol = 1,
+       .lnb_en_pol = 1,
+       .lnb_hv_pol = 0,
+       .agc = 0x99,
+};
+
 static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
 {
        struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -863,16 +941,23 @@ static int dvb_register(struct cx23885_tsport *port)
        struct dib7000p_ops dib7000p_ops;
        struct cx23885_dev *dev = port->dev;
        struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
-       struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
+       struct vb2_dvb_frontend *fe0, *fe1 = NULL;
+       struct si2168_config si2168_config;
+       struct si2157_config si2157_config;
+       struct m88ts2022_config m88ts2022_config;
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client_demod;
+       struct i2c_client *client_tuner;
        int mfe_shared = 0; /* bus not shared by default */
        int ret;
 
        /* Get the first frontend */
-       fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+       fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
        if (!fe0)
                return -EINVAL;
 
-       /* init struct videobuf_dvb */
+       /* init struct vb2_dvb */
        fe0->dvb.name = dev->name;
 
        /* multi-frontend gate control is undefined or defaults to fe0 */
@@ -1392,7 +1477,7 @@ static int dvb_register(struct cx23885_tsport *port)
                        fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
                }
                /* MFE frontend 2 */
-               fe1 = videobuf_dvb_get_frontend(&port->frontends, 2);
+               fe1 = vb2_dvb_get_frontend(&port->frontends, 2);
                if (fe1 == NULL)
                        goto frontend_detach;
                /* DVB-C init */
@@ -1491,7 +1576,7 @@ static int dvb_register(struct cx23885_tsport *port)
                                        &hauppauge_hvr4400_si2165_config,
                                        &i2c_bus->i2c_adap);
                        if (fe0->dvb.frontend != NULL) {
-                               fe0->dvb.frontend->ops.i2c_gate_ctrl = 0;
+                               fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
                                if (!dvb_attach(tda18271_attach,
                                                fe0->dvb.frontend,
                                                0x60, &i2c_bus2->i2c_adap,
@@ -1501,6 +1586,97 @@ static int dvb_register(struct cx23885_tsport *port)
                        break;
                }
                break;
+       case CX23885_BOARD_DVBSKY_T9580:
+               i2c_bus = &dev->i2c_bus[0];
+               i2c_bus2 = &dev->i2c_bus[1];
+               switch (port->nr) {
+               /* port b - satellite */
+               case 1:
+                       /* attach frontend */
+                       fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+                                       &dvbsky_t9580_m88ds3103_config,
+                                       &i2c_bus2->i2c_adap, &adapter);
+                       if (fe0->dvb.frontend == NULL)
+                               break;
+
+                       /* attach tuner */
+                       m88ts2022_config.fe = fe0->dvb.frontend;
+                       m88ts2022_config.clock = 27000000;
+                       memset(&info, 0, sizeof(struct i2c_board_info));
+                       strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+                       info.addr = 0x60;
+                       info.platform_data = &m88ts2022_config;
+                       request_module(info.type);
+                       client_tuner = i2c_new_device(adapter, &info);
+                       if (client_tuner == NULL ||
+                                       client_tuner->dev.driver == NULL)
+                               goto frontend_detach;
+                       if (!try_module_get(client_tuner->dev.driver->owner)) {
+                               i2c_unregister_device(client_tuner);
+                               goto frontend_detach;
+                       }
+
+                       /* delegate signal strength measurement to tuner */
+                       fe0->dvb.frontend->ops.read_signal_strength =
+                               fe0->dvb.frontend->ops.tuner_ops.get_rf_strength;
+
+                       /*
+                        * for setting the voltage we need to set GPIOs on
+                        * the card.
+                        */
+                       port->fe_set_voltage =
+                               fe0->dvb.frontend->ops.set_voltage;
+                       fe0->dvb.frontend->ops.set_voltage =
+                               dvbsky_t9580_set_voltage;
+
+                       port->i2c_client_tuner = client_tuner;
+
+                       break;
+               /* port c - terrestrial/cable */
+               case 2:
+                       /* attach frontend */
+                       si2168_config.i2c_adapter = &adapter;
+                       si2168_config.fe = &fe0->dvb.frontend;
+                       si2168_config.ts_mode = SI2168_TS_SERIAL;
+                       memset(&info, 0, sizeof(struct i2c_board_info));
+                       strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+                       info.addr = 0x64;
+                       info.platform_data = &si2168_config;
+                       request_module(info.type);
+                       client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
+                       if (client_demod == NULL ||
+                                       client_demod->dev.driver == NULL)
+                               goto frontend_detach;
+                       if (!try_module_get(client_demod->dev.driver->owner)) {
+                               i2c_unregister_device(client_demod);
+                               goto frontend_detach;
+                       }
+                       port->i2c_client_demod = client_demod;
+
+                       /* attach tuner */
+                       si2157_config.fe = fe0->dvb.frontend;
+                       memset(&info, 0, sizeof(struct i2c_board_info));
+                       strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+                       info.addr = 0x60;
+                       info.platform_data = &si2157_config;
+                       request_module(info.type);
+                       client_tuner = i2c_new_device(adapter, &info);
+                       if (client_tuner == NULL ||
+                                       client_tuner->dev.driver == NULL) {
+                               module_put(client_demod->dev.driver->owner);
+                               i2c_unregister_device(client_demod);
+                               goto frontend_detach;
+                       }
+                       if (!try_module_get(client_tuner->dev.driver->owner)) {
+                               i2c_unregister_device(client_tuner);
+                               module_put(client_demod->dev.driver->owner);
+                               i2c_unregister_device(client_demod);
+                               goto frontend_detach;
+                       }
+                       port->i2c_client_tuner = client_tuner;
+                       break;
+               }
+               break;
        default:
                printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
                        " isn't supported yet\n",
@@ -1532,7 +1708,7 @@ static int dvb_register(struct cx23885_tsport *port)
                fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
 
        /* register everything */
-       ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+       ret = vb2_dvb_register_bus(&port->frontends, THIS_MODULE, port,
                                        &dev->pci->dev, adapter_nr, mfe_shared);
        if (ret)
                goto frontend_detach;
@@ -1575,20 +1751,36 @@ static int dvb_register(struct cx23885_tsport *port)
                memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
                break;
                }
+       case CX23885_BOARD_DVBSKY_T9580: {
+               u8 eeprom[256]; /* 24C02 i2c eeprom */
+
+               if (port->nr > 2)
+                       break;
+
+               /* Read entire EEPROM */
+               dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+               tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
+                               sizeof(eeprom));
+               printk(KERN_INFO "DVBSky T9580 port %d MAC address: %pM\n",
+                       port->nr, eeprom + 0xc0 + (port->nr-1) * 8);
+               memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 +
+                       (port->nr-1) * 8, 6);
+               break;
+               }
        }
 
        return ret;
 
 frontend_detach:
        port->gate_ctrl = NULL;
-       videobuf_dvb_dealloc_frontends(&port->frontends);
+       vb2_dvb_dealloc_frontends(&port->frontends);
        return -EINVAL;
 }
 
 int cx23885_dvb_register(struct cx23885_tsport *port)
 {
 
-       struct videobuf_dvb_frontend *fe0;
+       struct vb2_dvb_frontend *fe0;
        struct cx23885_dev *dev = port->dev;
        int err, i;
 
@@ -1605,13 +1797,15 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
                port->num_frontends);
 
        for (i = 1; i <= port->num_frontends; i++) {
-               if (videobuf_dvb_alloc_frontend(
+               struct vb2_queue *q;
+
+               if (vb2_dvb_alloc_frontend(
                        &port->frontends, i) == NULL) {
                        printk(KERN_ERR "%s() failed to alloc\n", __func__);
                        return -ENOMEM;
                }
 
-               fe0 = videobuf_dvb_get_frontend(&port->frontends, i);
+               fe0 = vb2_dvb_get_frontend(&port->frontends, i);
                if (!fe0)
                        err = -EINVAL;
 
@@ -1627,10 +1821,21 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
                /* dvb stuff */
                /* We have to init the queue for each frontend on a port. */
                printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name);
-               videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
-                           &dev->pci->dev, &port->slock,
-                           V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
-                           sizeof(struct cx23885_buffer), port, NULL);
+               q = &fe0->dvb.dvbq;
+               q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+               q->gfp_flags = GFP_DMA32;
+               q->min_buffers_needed = 2;
+               q->drv_priv = port;
+               q->buf_struct_size = sizeof(struct cx23885_buffer);
+               q->ops = &dvb_qops;
+               q->mem_ops = &vb2_dma_sg_memops;
+               q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               q->lock = &dev->lock;
+
+               err = vb2_queue_init(q);
+               if (err < 0)
+                       return err;
        }
        err = dvb_register(port);
        if (err != 0)
@@ -1642,18 +1847,27 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
 
 int cx23885_dvb_unregister(struct cx23885_tsport *port)
 {
-       struct videobuf_dvb_frontend *fe0;
-
-       /* FIXME: in an error condition where the we have
-        * an expected number of frontends (attach problem)
-        * then this might not clean up correctly, if 1
-        * is invalid.
-        * This comment only applies to future boards IF they
-        * implement MFE support.
-        */
-       fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+       struct vb2_dvb_frontend *fe0;
+       struct i2c_client *client;
+
+       /* remove I2C client for tuner */
+       client = port->i2c_client_tuner;
+       if (client) {
+               module_put(client->dev.driver->owner);
+               i2c_unregister_device(client);
+       }
+
+       /* remove I2C client for demodulator */
+       client = port->i2c_client_demod;
+       if (client) {
+               module_put(client->dev.driver->owner);
+               i2c_unregister_device(client);
+       }
+
+       fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
+
        if (fe0 && fe0->dvb.frontend)
-               videobuf_dvb_unregister_bus(&port->frontends);
+               vb2_dvb_unregister_bus(&port->frontends);
 
        switch (port->dev->board) {
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
@@ -1668,4 +1882,3 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
 
        return 0;
 }
-
index 5444cc526008706d1a6b7a4c87e4aa0da923a22f..6f817d8732da8ca6a19ed7f742b78d85f66c4da9 100644 (file)
  * 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 "cx23885.h"
index 4887314339cbfa9071db9a898e985fae2495a9c8..fd71306af6e2f8facfc64964a8c05eb88fe3c146 100644 (file)
  *  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>
@@ -386,11 +382,3 @@ void cx23885_av_clk(struct cx23885_dev *dev, int enable)
 
        i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);
 }
-
-/* ----------------------------------------------------------------------- */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 1940c18e186cfbb6d0fbac1b579bdee75a040231..9d37fe6616913f268cd52499f3c7d089831aeb1c 100644 (file)
  *  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/slab.h>
index 87dc44e69977e2d38fb9c168711a0bf04c54f671..6199c7e86e83133779d1c07f7055599aab4a21de 100644 (file)
  *  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 _CX23885_INPUT_H_
index 271d69d1ca8c7c0a4c0796151353e97c4961ab3e..d2cdd40f79f54611b9b6aa46ad7a0d5a9b00d9f0 100644 (file)
  *  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 "cx23885.h"
@@ -28,7 +24,7 @@
 int cx23885_g_chip_info(struct file *file, void *fh,
                         struct v4l2_dbg_chip_info *chip)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (chip->match.addr > 1)
                return -EINVAL;
@@ -64,7 +60,7 @@ static int cx23417_g_register(struct cx23885_dev *dev,
 int cx23885_g_register(struct file *file, void *fh,
                       struct v4l2_dbg_register *reg)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (reg->match.addr > 1)
                return -EINVAL;
@@ -96,7 +92,7 @@ static int cx23417_s_register(struct cx23885_dev *dev,
 int cx23885_s_register(struct file *file, void *fh,
                       const struct v4l2_dbg_register *reg)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (reg->match.addr > 1)
                return -EINVAL;
index 92d9f077436679d0402b416a70384e9775923f96..cc5dbb6c1afccc54cc43deaf2db4c1abd4b1d56a 100644 (file)
  *  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 _CX23885_IOCTL_H_
index bfef193592916dd46ed734dac478ac03e1eab653..89dc4cc3e1cea427d3aef91201548e38e91e9cda 100644 (file)
  *  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 <media/v4l2-device.h>
index 0c9d8bda9e2895d1640c96c6b89e16cb95f499ec..8e93d1f10ae0d89398e6c5b9421d332ddec55c83 100644 (file)
  *  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 _CX23885_IR_H_
index a99936e0cbc270c5d9fe5ad29eeafd0101c4304d..2d3cbafe24023420162a9a947234e0924aa7aaf7 100644 (file)
  *  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 _CX23885_REG_H_
index a1154f035bc185daa692f6ac5443a5067ff46169..a7c6ef8f3ea3a7f1e96ce9a7642e3056ea27543c 100644 (file)
  *  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>
@@ -42,33 +38,32 @@ 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)
+#define VBI_NTSC_LINE_COUNT 12
+#define VBI_PAL_LINE_COUNT 18
 
 
 int cx23885_vbi_fmt(struct file *file, void *priv,
        struct v4l2_format *f)
 {
-       struct cx23885_fh *fh = priv;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
+       f->fmt.vbi.sampling_rate = 27000000;
+       f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+       f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+       f->fmt.vbi.offset = 0;
+       f->fmt.vbi.flags = 0;
        if (dev->tvnorm & V4L2_STD_525_60) {
                /* ntsc */
-               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.count[0] = 17;
-               f->fmt.vbi.start[1] = 263 + 10 + 1;
-               f->fmt.vbi.count[1] = 17;
+               f->fmt.vbi.start[0] = V4L2_VBI_ITU_525_F1_START + 9;
+               f->fmt.vbi.start[1] = V4L2_VBI_ITU_525_F2_START + 9;
+               f->fmt.vbi.count[0] = VBI_NTSC_LINE_COUNT;
+               f->fmt.vbi.count[1] = VBI_NTSC_LINE_COUNT;
        } 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;
+               f->fmt.vbi.start[0] = V4L2_VBI_ITU_625_F1_START + 5;
+               f->fmt.vbi.start[1] = V4L2_VBI_ITU_625_F2_START + 5;
+               f->fmt.vbi.count[0] = VBI_PAL_LINE_COUNT;
+               f->fmt.vbi.count[1] = VBI_PAL_LINE_COUNT;
        }
 
        return 0;
@@ -94,15 +89,6 @@ int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status)
                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;
 }
 
@@ -114,13 +100,13 @@ static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
 
        /* setup fifo + format */
        cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02],
-                               buf->vb.width, buf->risc.dma);
+                               VBI_LINE_LENGTH, 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;
+       q->count = 0;
 
        /* enable irq */
        cx23885_irq_add_enable(dev, 0x01);
@@ -133,163 +119,153 @@ static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
        return 0;
 }
 
+/* ------------------------------------------------------------------ */
 
-int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
-                            struct cx23885_dmaqueue *q)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+                          unsigned int *num_buffers, unsigned int *num_planes,
+                          unsigned int sizes[], void *alloc_ctxs[])
 {
-       struct cx23885_buffer *buf;
-       struct list_head *item;
-
-       if (list_empty(&q->active))
-               return 0;
-
-       buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
-       dprintk(2, "restart_queue [%p/%d]: restart dma\n",
-               buf, buf->vb.i);
-       cx23885_start_vbi_dma(dev, q, buf);
-       list_for_each(item, &q->active) {
-               buf = list_entry(item, struct cx23885_buffer, vb.queue);
-               buf->count = q->count++;
-       }
-       mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
+       struct cx23885_dev *dev = q->drv_priv;
+       unsigned lines = VBI_PAL_LINE_COUNT;
+
+       if (dev->tvnorm & V4L2_STD_525_60)
+               lines = VBI_NTSC_LINE_COUNT;
+       *num_planes = 1;
+       sizes[0] = lines * VBI_LINE_LENGTH * 2;
        return 0;
 }
 
-void cx23885_vbi_timeout(unsigned long data)
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-       struct cx23885_dev *dev = (struct cx23885_dev *)data;
-       struct cx23885_dmaqueue *q = &dev->vbiq;
-       struct cx23885_buffer *buf;
-       unsigned long flags;
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+       unsigned lines = VBI_PAL_LINE_COUNT;
+       int ret;
 
-       /* Stop the VBI engine */
-       cx_clear(VID_A_DMA_CTL, 0x22);
+       if (dev->tvnorm & V4L2_STD_525_60)
+               lines = VBI_NTSC_LINE_COUNT;
 
-       spin_lock_irqsave(&dev->slock, flags);
-       while (!list_empty(&q->active)) {
-               buf = list_entry(q->active.next, struct cx23885_buffer,
-                       vb.queue);
-               list_del(&buf->vb.queue);
-               buf->vb.state = VIDEOBUF_ERROR;
-               wake_up(&buf->vb.done);
-               printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name,
-                      buf, buf->vb.i, (unsigned long)buf->risc.dma);
-       }
-       cx23885_restart_vbi_queue(dev, q);
-       spin_unlock_irqrestore(&dev->slock, flags);
-}
+       if (vb2_plane_size(vb, 0) < lines * VBI_LINE_LENGTH * 2)
+               return -EINVAL;
+       vb2_set_plane_payload(vb, 0, lines * VBI_LINE_LENGTH * 2);
 
-/* ------------------------------------------------------------------ */
-#define VBI_LINE_LENGTH 1440
-#define VBI_LINE_COUNT 17
+       ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+       if (!ret)
+               return -EIO;
 
-static int
-vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
-{
-       *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
-       if (0 == *count)
-               *count = vbibufs;
-       if (*count < 2)
-               *count = 2;
-       if (*count > 32)
-               *count = 32;
+       cx23885_risc_vbibuffer(dev->pci, &buf->risc,
+                        sgt->sgl,
+                        0, VBI_LINE_LENGTH * lines,
+                        VBI_LINE_LENGTH, 0,
+                        lines);
        return 0;
 }
 
-static int
-vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-           enum v4l2_field field)
+static void buffer_finish(struct vb2_buffer *vb)
 {
-       struct cx23885_fh *fh  = q->priv_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
        struct cx23885_buffer *buf = container_of(vb,
                struct cx23885_buffer, vb);
-       struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
-       unsigned int size;
-       int rc;
-
-       size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
-       if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
-               return -EINVAL;
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
 
-       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-               buf->vb.width  = VBI_LINE_LENGTH;
-               buf->vb.height = VBI_LINE_COUNT;
-               buf->vb.size   = size;
-               buf->vb.field  = V4L2_FIELD_SEQ_TB;
-
-               rc = videobuf_iolock(q, &buf->vb, NULL);
-               if (0 != rc)
-                       goto fail;
-               cx23885_risc_vbibuffer(dev->pci, &buf->risc,
-                                dma->sglist,
-                                0, buf->vb.width * buf->vb.height,
-                                buf->vb.width, 0,
-                                buf->vb.height);
-       }
-       buf->vb.state = VIDEOBUF_PREPARED;
-       return 0;
+       cx23885_free_buffer(vb->vb2_queue->drv_priv, buf);
 
- fail:
-       cx23885_free_buffer(q, buf);
-       return rc;
+       dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
 }
 
-static void
-vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+/*
+ * The risc program for each buffer works as follows: it starts with a simple
+ * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
+ * the initial JUMP).
+ *
+ * This is the risc program of the first buffer to be queued if the active list
+ * is empty and it just keeps DMAing this buffer without generating any
+ * interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the code for that buffer
+ * will generate an interrupt which signals that the previous buffer has been
+ * DMAed successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
+static void buffer_queue(struct vb2_buffer *vb)
 {
-       struct cx23885_buffer   *buf =
-               container_of(vb, struct cx23885_buffer, vb);
-       struct cx23885_buffer   *prev;
-       struct cx23885_fh       *fh   = vq->priv_data;
-       struct cx23885_dev      *dev  = fh->dev;
-       struct cx23885_dmaqueue *q    = &dev->vbiq;
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb);
+       struct cx23885_buffer *prev;
+       struct cx23885_dmaqueue *q = &dev->vbiq;
+       unsigned long flags;
+
+       buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+       buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
        buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
 
        if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx23885_start_vbi_dma(dev, q, buf);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count    = q->count++;
-               mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
+               spin_lock_irqsave(&dev->slock, flags);
+               list_add_tail(&buf->queue, &q->active);
+               spin_unlock_irqrestore(&dev->slock, flags);
                dprintk(2, "[%p/%d] vbi_queue - first active\n",
-                       buf, buf->vb.i);
+                       buf, buf->vb.v4l2_buf.index);
 
        } else {
+               buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
                prev = list_entry(q->active.prev, struct cx23885_buffer,
-                       vb.queue);
-               list_add_tail(&buf->vb.queue, &q->active);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count    = q->count++;
+                       queue);
+               spin_lock_irqsave(&dev->slock, flags);
+               list_add_tail(&buf->queue, &q->active);
+               spin_unlock_irqrestore(&dev->slock, flags);
                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-               prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */
                dprintk(2, "[%p/%d] buffer_queue - append to active\n",
-                       buf, buf->vb.i);
+                       buf, buf->vb.v4l2_buf.index);
        }
 }
 
-static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
 {
-       struct cx23885_buffer *buf =
-               container_of(vb, struct cx23885_buffer, vb);
+       struct cx23885_dev *dev = q->drv_priv;
+       struct cx23885_dmaqueue *dmaq = &dev->vbiq;
+       struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
 
-       cx23885_free_buffer(q, buf);
+       cx23885_start_vbi_dma(dev, dmaq, buf);
+       return 0;
 }
 
-struct videobuf_queue_ops cx23885_vbi_qops = {
-       .buf_setup    = vbi_setup,
-       .buf_prepare  = vbi_prepare,
-       .buf_queue    = vbi_queue,
-       .buf_release  = vbi_release,
-};
+static void cx23885_stop_streaming(struct vb2_queue *q)
+{
+       struct cx23885_dev *dev = q->drv_priv;
+       struct cx23885_dmaqueue *dmaq = &dev->vbiq;
+       unsigned long flags;
 
-/* ------------------------------------------------------------------ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+       cx_clear(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */
+       spin_lock_irqsave(&dev->slock, flags);
+       while (!list_empty(&dmaq->active)) {
+               struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
+
+               list_del(&buf->queue);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+       spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+
+struct vb2_ops cx23885_vbi_qops = {
+       .queue_setup    = queue_setup,
+       .buf_prepare  = buffer_prepare,
+       .buf_finish = buffer_finish,
+       .buf_queue    = buffer_queue,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+       .start_streaming = cx23885_start_streaming,
+       .stop_streaming = cx23885_stop_streaming,
+};
index 91e4cb457296ccdef2b1b777e6f8594341a71a1d..682a4f95df6bd09f062d0c58e7ac3185b158db6f 100644 (file)
  *  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>
@@ -35,6 +31,7 @@
 #include "cx23885-video.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 #include "cx23885-ioctl.h"
 #include "tuner-xc2028.h"
 
@@ -48,15 +45,12 @@ MODULE_LICENSE("GPL");
 
 static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
 static unsigned int vbi_nr[]   = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
 
 module_param_array(video_nr, int, NULL, 0444);
 module_param_array(vbi_nr,   int, NULL, 0444);
-module_param_array(radio_nr, int, NULL, 0444);
 
 MODULE_PARM_DESC(video_nr, "video device numbers");
 MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
-MODULE_PARM_DESC(radio_nr, "radio device numbers");
 
 static unsigned int video_debug;
 module_param(video_debug, int, 0644);
@@ -79,77 +73,14 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
 /* static data                                                         */
 
 #define FORMAT_FLAGS_PACKED       0x01
-#if 0
-static struct cx23885_fmt formats[] = {
-       {
-               .name     = "8 bpp, gray",
-               .fourcc   = V4L2_PIX_FMT_GREY,
-               .depth    = 8,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "15 bpp RGB, le",
-               .fourcc   = V4L2_PIX_FMT_RGB555,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "15 bpp RGB, be",
-               .fourcc   = V4L2_PIX_FMT_RGB555X,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "16 bpp RGB, le",
-               .fourcc   = V4L2_PIX_FMT_RGB565,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "16 bpp RGB, be",
-               .fourcc   = V4L2_PIX_FMT_RGB565X,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "24 bpp RGB, le",
-               .fourcc   = V4L2_PIX_FMT_BGR24,
-               .depth    = 24,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "32 bpp RGB, le",
-               .fourcc   = V4L2_PIX_FMT_BGR32,
-               .depth    = 32,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "32 bpp RGB, be",
-               .fourcc   = V4L2_PIX_FMT_RGB32,
-               .depth    = 32,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "4:2:2, packed, YUYV",
-               .fourcc   = V4L2_PIX_FMT_YUYV,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "4:2:2, packed, UYVY",
-               .fourcc   = V4L2_PIX_FMT_UYVY,
-               .depth    = 16,
-               .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)
 {
@@ -158,163 +89,27 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
        for (i = 0; i < ARRAY_SIZE(formats); i++)
                if (formats[i].fourcc == fourcc)
                        return formats+i;
-
-       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;
 }
 
 /* ------------------------------------------------------------------- */
 
-static const struct v4l2_queryctrl no_ctl = {
-       .name  = "42",
-       .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-
-static struct cx23885_ctrl cx23885_ctls[] = {
-       /* --- video --- */
-       {
-               .v = {
-                       .id            = V4L2_CID_BRIGHTNESS,
-                       .name          = "Brightness",
-                       .minimum       = 0x00,
-                       .maximum       = 0xff,
-                       .step          = 1,
-                       .default_value = 0x7f,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 128,
-               .reg                   = LUMA_CTRL,
-               .mask                  = 0x00ff,
-               .shift                 = 0,
-       }, {
-               .v = {
-                       .id            = V4L2_CID_CONTRAST,
-                       .name          = "Contrast",
-                       .minimum       = 0,
-                       .maximum       = 0x7f,
-                       .step          = 1,
-                       .default_value = 0x3f,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 0,
-               .reg                   = LUMA_CTRL,
-               .mask                  = 0xff00,
-               .shift                 = 8,
-       }, {
-               .v = {
-                       .id            = V4L2_CID_HUE,
-                       .name          = "Hue",
-                       .minimum       = -127,
-                       .maximum       = 128,
-                       .step          = 1,
-                       .default_value = 0x0,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 128,
-               .reg                   = CHROMA_CTRL,
-               .mask                  = 0xff0000,
-               .shift                 = 16,
-       }, {
-               /* strictly, this only describes only U saturation.
-                * V saturation is handled specially through code.
-                */
-               .v = {
-                       .id            = V4L2_CID_SATURATION,
-                       .name          = "Saturation",
-                       .minimum       = 0,
-                       .maximum       = 0x7f,
-                       .step          = 1,
-                       .default_value = 0x3f,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 0,
-               .reg                   = CHROMA_CTRL,
-               .mask                  = 0x00ff,
-               .shift                 = 0,
-       }, {
-       /* --- audio --- */
-               .v = {
-                       .id            = V4L2_CID_AUDIO_MUTE,
-                       .name          = "Mute",
-                       .minimum       = 0,
-                       .maximum       = 1,
-                       .default_value = 1,
-                       .type          = V4L2_CTRL_TYPE_BOOLEAN,
-               },
-               .reg                   = PATH1_CTL1,
-               .mask                  = (0x1f << 24),
-               .shift                 = 24,
-       }, {
-               .v = {
-                       .id            = V4L2_CID_AUDIO_VOLUME,
-                       .name          = "Volume",
-                       .minimum       = 0,
-                       .maximum       = 65535,
-                       .step          = 65535 / 100,
-                       .default_value = 65535,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .reg                   = PATH1_VOL_CTL,
-               .mask                  = 0xff,
-               .shift                 = 0,
-       }
-};
-static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
-
-/* Must be sorted from low to high control ID! */
-static const u32 cx23885_user_ctrls[] = {
-       V4L2_CID_USER_CLASS,
-       V4L2_CID_BRIGHTNESS,
-       V4L2_CID_CONTRAST,
-       V4L2_CID_SATURATION,
-       V4L2_CID_HUE,
-       V4L2_CID_AUDIO_VOLUME,
-       V4L2_CID_AUDIO_MUTE,
-       0
-};
-
-static const u32 *ctrl_classes[] = {
-       cx23885_user_ctrls,
-       NULL
-};
-
 void cx23885_video_wakeup(struct cx23885_dev *dev,
        struct cx23885_dmaqueue *q, u32 count)
 {
        struct cx23885_buffer *buf;
-       int bc;
-
-       for (bc = 0;; bc++) {
-               if (list_empty(&q->active))
-                       break;
-               buf = list_entry(q->active.next,
-                                struct cx23885_buffer, vb.queue);
-
-               /* count comes from the hw and is is 16bit wide --
-                * this trick handles wrap-arounds correctly for
-                * up to 32767 buffers in flight... */
-               if ((s16) (count - buf->count) < 0)
-                       break;
-
-               v4l2_get_timestamp(&buf->vb.ts);
-               dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
-                       count, buf->count);
-               buf->vb.state = VIDEOBUF_DONE;
-               list_del(&buf->vb.queue);
-               wake_up(&buf->vb.done);
-       }
+
        if (list_empty(&q->active))
-               del_timer(&q->timeout);
-       else
-               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-       if (bc != 1)
-               printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
-                       __func__, bc);
+               return;
+       buf = list_entry(q->active.next,
+                       struct cx23885_buffer, queue);
+
+       buf->vb.v4l2_buf.sequence = q->count++;
+       v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+       dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index,
+                       count, q->count);
+       list_del(&buf->queue);
+       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
 }
 
 int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
@@ -324,6 +119,12 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
                (unsigned int)norm,
                v4l2_norm_to_name(norm));
 
+       if (dev->tvnorm != norm) {
+               if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
+                   vb2_is_busy(&dev->vb2_mpegq))
+                       return -EBUSY;
+       }
+
        dev->tvnorm = norm;
 
        call_all(dev, video, s_std, norm);
@@ -345,79 +146,13 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
        *vfd = *template;
        vfd->v4l2_dev = &dev->v4l2_dev;
        vfd->release = video_device_release;
+       vfd->lock = &dev->lock;
        snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
                 cx23885_boards[dev->board].name, type);
        video_set_drvdata(vfd, dev);
        return vfd;
 }
 
-static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
-{
-       int i;
-
-       if (qctrl->id < V4L2_CID_BASE ||
-           qctrl->id >= V4L2_CID_LASTP1)
-               return -EINVAL;
-       for (i = 0; i < CX23885_CTLS; i++)
-               if (cx23885_ctls[i].v.id == qctrl->id)
-                       break;
-       if (i == CX23885_CTLS) {
-               *qctrl = no_ctl;
-               return 0;
-       }
-       *qctrl = cx23885_ctls[i].v;
-       return 0;
-}
-
-/* ------------------------------------------------------------------- */
-/* resource management                                                 */
-
-static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
-       unsigned int bit)
-{
-       dprintk(1, "%s()\n", __func__);
-       if (fh->resources & bit)
-               /* have it already allocated */
-               return 1;
-
-       /* is it free? */
-       mutex_lock(&dev->lock);
-       if (dev->resources & bit) {
-               /* no, someone else uses it */
-               mutex_unlock(&dev->lock);
-               return 0;
-       }
-       /* it's free, grab it */
-       fh->resources  |= bit;
-       dev->resources |= bit;
-       dprintk(1, "res: get %d\n", bit);
-       mutex_unlock(&dev->lock);
-       return 1;
-}
-
-static int res_check(struct cx23885_fh *fh, unsigned int bit)
-{
-       return fh->resources & bit;
-}
-
-static int res_locked(struct cx23885_dev *dev, unsigned int bit)
-{
-       return dev->resources & bit;
-}
-
-static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
-       unsigned int bits)
-{
-       BUG_ON((fh->resources & bits) != bits);
-       dprintk(1, "%s()\n", __func__);
-
-       mutex_lock(&dev->lock);
-       fh->resources  &= ~bits;
-       dev->resources &= ~bits;
-       dprintk(1, "res: put %d\n", bits);
-       mutex_unlock(&dev->lock);
-}
-
 int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data)
 {
        /* 8 bit registers, 8 bit values */
@@ -567,7 +302,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev,
 
        /* reset counter */
        cx_write(VID_A_GPCNT_CTL, 3);
-       q->count = 1;
+       q->count = 0;
 
        /* enable irq */
        cx23885_irq_add_enable(dev, 0x01);
@@ -580,479 +315,206 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev,
        return 0;
 }
 
-
-static int cx23885_restart_video_queue(struct cx23885_dev *dev,
-                              struct cx23885_dmaqueue *q)
-{
-       struct cx23885_buffer *buf, *prev;
-       struct list_head *item;
-       dprintk(1, "%s()\n", __func__);
-
-       if (!list_empty(&q->active)) {
-               buf = list_entry(q->active.next, struct cx23885_buffer,
-                       vb.queue);
-               dprintk(2, "restart_queue [%p/%d]: restart dma\n",
-                       buf, buf->vb.i);
-               cx23885_start_video_dma(dev, q, buf);
-               list_for_each(item, &q->active) {
-                       buf = list_entry(item, struct cx23885_buffer,
-                               vb.queue);
-                       buf->count    = q->count++;
-               }
-               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-               return 0;
-       }
-
-       prev = NULL;
-       for (;;) {
-               if (list_empty(&q->queued))
-                       return 0;
-               buf = list_entry(q->queued.next, struct cx23885_buffer,
-                       vb.queue);
-               if (NULL == prev) {
-                       list_move_tail(&buf->vb.queue, &q->active);
-                       cx23885_start_video_dma(dev, q, buf);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count    = q->count++;
-                       mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-                       dprintk(2, "[%p/%d] restart_queue - first active\n",
-                               buf, buf->vb.i);
-
-               } else if (prev->vb.width  == buf->vb.width  &&
-                          prev->vb.height == buf->vb.height &&
-                          prev->fmt       == buf->fmt) {
-                       list_move_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count    = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-                       prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
-                       dprintk(2, "[%p/%d] restart_queue - move to active\n",
-                               buf, buf->vb.i);
-               } else {
-                       return 0;
-               }
-               prev = buf;
-       }
-}
-
-static int buffer_setup(struct videobuf_queue *q, unsigned int *count,
-       unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+                          unsigned int *num_buffers, unsigned int *num_planes,
+                          unsigned int sizes[], void *alloc_ctxs[])
 {
-       struct cx23885_fh *fh = q->priv_data;
+       struct cx23885_dev *dev = q->drv_priv;
 
-       *size = fh->fmt->depth*fh->width*fh->height >> 3;
-       if (0 == *count)
-               *count = 32;
-       if (*size * *count > vid_limit * 1024 * 1024)
-               *count = (vid_limit * 1024 * 1024) / *size;
+       *num_planes = 1;
+       sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3;
        return 0;
 }
 
-static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-              enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-       struct cx23885_fh *fh  = q->priv_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
        struct cx23885_buffer *buf =
                container_of(vb, struct cx23885_buffer, vb);
-       int rc, init_buffer = 0;
        u32 line0_offset, line1_offset;
-       struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
        int field_tff;
+       int ret;
 
-       BUG_ON(NULL == fh->fmt);
-       if (fh->width  < 48 || fh->width  > norm_maxw(dev->tvnorm) ||
-           fh->height < 32 || fh->height > norm_maxh(dev->tvnorm))
-               return -EINVAL;
-       buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
-       if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+       buf->bpl = (dev->width * dev->fmt->depth) >> 3;
+
+       if (vb2_plane_size(vb, 0) < dev->height * buf->bpl)
                return -EINVAL;
+       vb2_set_plane_payload(vb, 0, dev->height * buf->bpl);
 
-       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;
-               init_buffer = 1;
-       }
+       ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+       if (!ret)
+               return -EIO;
 
-       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-               init_buffer = 1;
-               rc = videobuf_iolock(q, &buf->vb, NULL);
-               if (0 != rc)
-                       goto fail;
-       }
+       switch (dev->field) {
+       case V4L2_FIELD_TOP:
+               cx23885_risc_buffer(dev->pci, &buf->risc,
+                               sgt->sgl, 0, UNSET,
+                               buf->bpl, 0, dev->height);
+               break;
+       case V4L2_FIELD_BOTTOM:
+               cx23885_risc_buffer(dev->pci, &buf->risc,
+                               sgt->sgl, UNSET, 0,
+                               buf->bpl, 0, dev->height);
+               break;
+       case V4L2_FIELD_INTERLACED:
+               if (dev->tvnorm & V4L2_STD_525_60)
+                       /* NTSC or  */
+                       field_tff = 1;
+               else
+                       field_tff = 0;
+
+               if (cx23885_boards[dev->board].force_bff)
+                       /* PAL / SECAM OR 888 in NTSC MODE */
+                       field_tff = 0;
 
-       if (init_buffer) {
-               buf->bpl = buf->vb.width * buf->fmt->depth >> 3;
-               switch (buf->vb.field) {
-               case V4L2_FIELD_TOP:
-                       cx23885_risc_buffer(dev->pci, &buf->risc,
-                                        dma->sglist, 0, UNSET,
-                                        buf->bpl, 0, buf->vb.height);
-                       break;
-               case V4L2_FIELD_BOTTOM:
-                       cx23885_risc_buffer(dev->pci, &buf->risc,
-                                        dma->sglist, UNSET, 0,
-                                        buf->bpl, 0, buf->vb.height);
-                       break;
-               case V4L2_FIELD_INTERLACED:
-                       if (dev->tvnorm & V4L2_STD_NTSC)
-                               /* NTSC or  */
-                               field_tff = 1;
-                       else
-                               field_tff = 0;
-
-                       if (cx23885_boards[dev->board].force_bff)
-                               /* PAL / SECAM OR 888 in NTSC MODE */
-                               field_tff = 0;
-
-                       if (field_tff) {
-                               /* cx25840 transmits NTSC bottom field first */
-                               dprintk(1, "%s() Creating TFF/NTSC risc\n",
+               if (field_tff) {
+                       /* cx25840 transmits NTSC bottom field first */
+                       dprintk(1, "%s() Creating TFF/NTSC risc\n",
                                        __func__);
-                               line0_offset = buf->bpl;
-                               line1_offset = 0;
-                       } else {
-                               /* All other formats are top field first */
-                               dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n",
+                       line0_offset = buf->bpl;
+                       line1_offset = 0;
+               } else {
+                       /* All other formats are top field first */
+                       dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n",
                                        __func__);
-                               line0_offset = 0;
-                               line1_offset = buf->bpl;
-                       }
-                       cx23885_risc_buffer(dev->pci, &buf->risc,
-                                       dma->sglist, line0_offset,
-                                       line1_offset,
-                                       buf->bpl, buf->bpl,
-                                       buf->vb.height >> 1);
-                       break;
-               case V4L2_FIELD_SEQ_TB:
-                       cx23885_risc_buffer(dev->pci, &buf->risc,
-                                        dma->sglist,
-                                        0, buf->bpl * (buf->vb.height >> 1),
-                                        buf->bpl, 0,
-                                        buf->vb.height >> 1);
-                       break;
-               case V4L2_FIELD_SEQ_BT:
-                       cx23885_risc_buffer(dev->pci, &buf->risc,
-                                        dma->sglist,
-                                        buf->bpl * (buf->vb.height >> 1), 0,
-                                        buf->bpl, 0,
-                                        buf->vb.height >> 1);
-                       break;
-               default:
-                       BUG();
+                       line0_offset = 0;
+                       line1_offset = buf->bpl;
                }
+               cx23885_risc_buffer(dev->pci, &buf->risc,
+                               sgt->sgl, line0_offset,
+                               line1_offset,
+                               buf->bpl, buf->bpl,
+                               dev->height >> 1);
+               break;
+       case V4L2_FIELD_SEQ_TB:
+               cx23885_risc_buffer(dev->pci, &buf->risc,
+                               sgt->sgl,
+                               0, buf->bpl * (dev->height >> 1),
+                               buf->bpl, 0,
+                               dev->height >> 1);
+               break;
+       case V4L2_FIELD_SEQ_BT:
+               cx23885_risc_buffer(dev->pci, &buf->risc,
+                               sgt->sgl,
+                               buf->bpl * (dev->height >> 1), 0,
+                               buf->bpl, 0,
+                               dev->height >> 1);
+               break;
+       default:
+               BUG();
        }
-       dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
-               buf, buf->vb.i,
-               fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
+       dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
+               buf, buf->vb.v4l2_buf.index,
+               dev->width, dev->height, dev->fmt->depth, dev->fmt->name,
                (unsigned long)buf->risc.dma);
-
-       buf->vb.state = VIDEOBUF_PREPARED;
        return 0;
+}
+
+static void buffer_finish(struct vb2_buffer *vb)
+{
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+
+       cx23885_free_buffer(vb->vb2_queue->drv_priv, buf);
 
- fail:
-       cx23885_free_buffer(q, buf);
-       return rc;
+       dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
 }
 
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+/*
+ * The risc program for each buffer works as follows: it starts with a simple
+ * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
+ * the initial JUMP).
+ *
+ * This is the risc program of the first buffer to be queued if the active list
+ * is empty and it just keeps DMAing this buffer without generating any
+ * interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the code for that buffer
+ * will generate an interrupt which signals that the previous buffer has been
+ * DMAed successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
+static void buffer_queue(struct vb2_buffer *vb)
 {
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
        struct cx23885_buffer   *buf = container_of(vb,
                struct cx23885_buffer, vb);
        struct cx23885_buffer   *prev;
-       struct cx23885_fh       *fh   = vq->priv_data;
-       struct cx23885_dev      *dev  = fh->dev;
        struct cx23885_dmaqueue *q    = &dev->vidq;
+       unsigned long flags;
 
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+       /* add jump to start */
+       buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+       buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
        buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
 
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
-                       buf, buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx23885_start_video_dma(dev, q, buf);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count    = q->count++;
-               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+       spin_lock_irqsave(&dev->slock, flags);
+       if (list_empty(&q->active)) {
+               list_add_tail(&buf->queue, &q->active);
                dprintk(2, "[%p/%d] buffer_queue - first active\n",
-                       buf, buf->vb.i);
-
+                       buf, buf->vb.v4l2_buf.index);
        } else {
+               buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
                prev = list_entry(q->active.prev, struct cx23885_buffer,
-                       vb.queue);
-               if (prev->vb.width  == buf->vb.width  &&
-                   prev->vb.height == buf->vb.height &&
-                   prev->fmt       == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count    = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2, "[%p/%d] buffer_queue - append to active\n",
-                               buf, buf->vb.i);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n",
-                               buf, buf->vb.i);
-               }
-       }
-}
-
-static void buffer_release(struct videobuf_queue *q,
-       struct videobuf_buffer *vb)
-{
-       struct cx23885_buffer *buf = container_of(vb,
-               struct cx23885_buffer, vb);
-
-       cx23885_free_buffer(q, buf);
-}
-
-static struct videobuf_queue_ops cx23885_video_qops = {
-       .buf_setup    = buffer_setup,
-       .buf_prepare  = buffer_prepare,
-       .buf_queue    = buffer_queue,
-       .buf_release  = buffer_release,
-};
-
-static struct videobuf_queue *get_queue(struct cx23885_fh *fh)
-{
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               return &fh->vidq;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               return &fh->vbiq;
-       default:
-               BUG();
-               return NULL;
-       }
-}
-
-static int get_resource(struct cx23885_fh *fh)
-{
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               return RESOURCE_VIDEO;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               return RESOURCE_VBI;
-       default:
-               BUG();
-               return 0;
+                       queue);
+               list_add_tail(&buf->queue, &q->active);
+               prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+               dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+                               buf, buf->vb.v4l2_buf.index);
        }
+       spin_unlock_irqrestore(&dev->slock, flags);
 }
 
-static int video_open(struct file *file)
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
 {
-       struct video_device *vdev = video_devdata(file);
-       struct cx23885_dev *dev = video_drvdata(file);
-       struct cx23885_fh *fh;
-       enum v4l2_buf_type type = 0;
-       int radio = 0;
-
-       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;
-       }
-
-       dprintk(1, "open dev=%s radio=%d type=%s\n",
-               video_device_node_name(vdev), radio, v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       file->private_data = fh;
-       fh->dev      = dev;
-       fh->radio    = radio;
-       fh->type     = type;
-       fh->width    = 320;
-       fh->height   = 240;
-       fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops,
-                           &dev->pci->dev, &dev->slock,
-                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                           V4L2_FIELD_INTERLACED,
-                           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");
+       struct cx23885_dev *dev = q->drv_priv;
+       struct cx23885_dmaqueue *dmaq = &dev->vidq;
+       struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
 
+       cx23885_start_video_dma(dev, dmaq, buf);
        return 0;
 }
 
-static ssize_t video_read(struct file *file, char __user *data,
-       size_t count, loff_t *ppos)
+static void cx23885_stop_streaming(struct vb2_queue *q)
 {
-       struct cx23885_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (res_locked(fh->dev, RESOURCE_VIDEO))
-                       return -EBUSY;
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               if (!res_get(fh->dev, fh, RESOURCE_VBI))
-                       return -EBUSY;
-               return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,
-                                           file->f_flags & O_NONBLOCK);
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-       struct poll_table_struct *wait)
-{
-       struct cx23885_fh *fh = file->private_data;
-       struct cx23885_buffer *buf;
-       unsigned int rc = POLLERR;
-
-       if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
-               if (!res_get(fh->dev, fh, RESOURCE_VBI))
-                       return POLLERR;
-               return videobuf_poll_stream(file, &fh->vbiq, wait);
-       }
-
-       mutex_lock(&fh->vidq.vb_lock);
-       if (res_check(fh, RESOURCE_VIDEO)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       goto done;
-               buf = list_entry(fh->vidq.stream.next,
-                       struct cx23885_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx23885_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       goto done;
-       }
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE ||
-           buf->vb.state == VIDEOBUF_ERROR)
-               rc =  POLLIN|POLLRDNORM;
-       else
-               rc = 0;
-done:
-       mutex_unlock(&fh->vidq.vb_lock);
-       return rc;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx23885_fh *fh = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-
-       /* turn off overlay */
-       if (res_check(fh, RESOURCE_OVERLAY)) {
-               /* FIXME */
-               res_free(dev, fh, RESOURCE_OVERLAY);
-       }
+       struct cx23885_dev *dev = q->drv_priv;
+       struct cx23885_dmaqueue *dmaq = &dev->vidq;
+       unsigned long flags;
 
-       /* stop video capture */
-       if (res_check(fh, RESOURCE_VIDEO)) {
-               videobuf_queue_cancel(&fh->vidq);
-               res_free(dev, fh, RESOURCE_VIDEO);
-       }
-       if (fh->vidq.read_buf) {
-               buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
+       cx_clear(VID_A_DMA_CTL, 0x11);
+       spin_lock_irqsave(&dev->slock, flags);
+       while (!list_empty(&dmaq->active)) {
+               struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
 
-       /* stop vbi capture */
-       if (res_check(fh, RESOURCE_VBI)) {
-               if (fh->vbiq.streaming)
-                       videobuf_streamoff(&fh->vbiq);
-               if (fh->vbiq.reading)
-                       videobuf_read_stop(&fh->vbiq);
-               res_free(dev, fh, RESOURCE_VBI);
+               list_del(&buf->queue);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
        }
-
-       videobuf_mmap_free(&fh->vidq);
-       videobuf_mmap_free(&fh->vbiq);
-
-       file->private_data = NULL;
-       kfree(fh);
-
-       /* We are not putting the tuner to sleep here on exit, because
-        * we want to use the mpeg encoder in another session to capture
-        * tuner video. Closing this will result in no video to the encoder.
-        */
-
-       return 0;
-}
-
-static int video_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct cx23885_fh *fh = file->private_data;
-
-       return videobuf_mmap_mapper(get_queue(fh), vma);
-}
-
-/* ------------------------------------------------------------------ */
-/* VIDEO CTRL IOCTLS                                                  */
-
-int cx23885_get_control(struct cx23885_dev *dev,
-       struct v4l2_control *ctl)
-{
-       dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
-       call_all(dev, core, g_ctrl, ctl);
-       return 0;
-}
-
-int cx23885_set_control(struct cx23885_dev *dev,
-       struct v4l2_control *ctl)
-{
-       dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__);
-       call_all(dev, core, s_ctrl, ctl);
-
-       return 0;
+       spin_unlock_irqrestore(&dev->slock, flags);
 }
 
-static void init_controls(struct cx23885_dev *dev)
-{
-       struct v4l2_control ctrl;
-       int i;
-
-       for (i = 0; i < CX23885_CTLS; i++) {
-               ctrl.id = cx23885_ctls[i].v.id;
-               ctrl.value = cx23885_ctls[i].v.default_value;
-
-               cx23885_set_control(dev, &ctrl);
-       }
-}
+static struct vb2_ops cx23885_video_qops = {
+       .queue_setup    = queue_setup,
+       .buf_prepare  = buffer_prepare,
+       .buf_finish = buffer_finish,
+       .buf_queue    = buffer_queue,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+       .start_streaming = cx23885_start_streaming,
+       .stop_streaming = cx23885_stop_streaming,
+};
 
 /* ------------------------------------------------------------------ */
 /* VIDEO IOCTLS                                                       */
@@ -1060,16 +522,17 @@ static void init_controls(struct cx23885_dev *dev)
 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        struct v4l2_format *f)
 {
-       struct cx23885_fh *fh   = priv;
+       struct cx23885_dev *dev = video_drvdata(file);
 
-       f->fmt.pix.width        = fh->width;
-       f->fmt.pix.height       = fh->height;
-       f->fmt.pix.field        = fh->vidq.field;
-       f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+       f->fmt.pix.width        = dev->width;
+       f->fmt.pix.height       = dev->height;
+       f->fmt.pix.field        = dev->field;
+       f->fmt.pix.pixelformat  = dev->fmt->fourcc;
        f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * fh->fmt->depth) >> 3;
+               (f->fmt.pix.width * dev->fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
                f->fmt.pix.height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
 
        return 0;
 }
@@ -1077,7 +540,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        struct v4l2_format *f)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        struct cx23885_fmt *fmt;
        enum v4l2_field   field;
        unsigned int      maxw, maxh;
@@ -1102,9 +565,12 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                maxh = maxh / 2;
                break;
        case V4L2_FIELD_INTERLACED:
+       case V4L2_FIELD_SEQ_TB:
+       case V4L2_FIELD_SEQ_BT:
                break;
        default:
-               return -EINVAL;
+               field = V4L2_FIELD_INTERLACED;
+               break;
        }
 
        f->fmt.pix.field = field;
@@ -1114,6 +580,7 @@ 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;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 
        return 0;
 }
@@ -1121,8 +588,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        struct v4l2_format *f)
 {
-       struct cx23885_fh *fh = priv;
-       struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        struct v4l2_mbus_framefmt mbus_fmt;
        int err;
 
@@ -1131,34 +597,44 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 
        if (0 != err)
                return err;
-       fh->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->width      = f->fmt.pix.width;
-       fh->height     = f->fmt.pix.height;
-       fh->vidq.field = f->fmt.pix.field;
+
+       if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
+           vb2_is_busy(&dev->vb2_mpegq))
+               return -EBUSY;
+
+       dev->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
+       dev->width      = f->fmt.pix.width;
+       dev->height     = f->fmt.pix.height;
+       dev->field      = f->fmt.pix.field;
        dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
-               fh->width, fh->height, fh->vidq.field);
+               dev->width, dev->height, dev->field);
        v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
        call_all(dev, video, s_mbus_fmt, &mbus_fmt);
        v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
+       /* s_mbus_fmt overwrites f->fmt.pix.field, restore it */
+       f->fmt.pix.field = dev->field;
        return 0;
 }
 
 static int vidioc_querycap(struct file *file, void  *priv,
        struct v4l2_capability *cap)
 {
-       struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
 
        strcpy(cap->driver, "cx23885");
        strlcpy(cap->card, cx23885_boards[dev->board].name,
                sizeof(cap->card));
        sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
-       cap->capabilities =
-               V4L2_CAP_VIDEO_CAPTURE |
-               V4L2_CAP_READWRITE     |
-               V4L2_CAP_STREAMING     |
-               V4L2_CAP_VBI_CAPTURE;
+       cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO;
        if (dev->tuner_type != TUNER_ABSENT)
-               cap->capabilities |= V4L2_CAP_TUNER;
+               cap->device_caps |= V4L2_CAP_TUNER;
+       if (vdev->vfl_type == VFL_TYPE_VBI)
+               cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
+       else
+               cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+       cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE |
+               V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
 
@@ -1175,85 +651,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
        return 0;
 }
 
-static int vidioc_reqbufs(struct file *file, void *priv,
-       struct v4l2_requestbuffers *p)
-{
-       struct cx23885_fh *fh = priv;
-       return videobuf_reqbufs(get_queue(fh), p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
-       struct v4l2_buffer *p)
-{
-       struct cx23885_fh *fh = priv;
-       return videobuf_querybuf(get_queue(fh), p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv,
-       struct v4l2_buffer *p)
-{
-       struct cx23885_fh *fh = priv;
-       return videobuf_qbuf(get_queue(fh), p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv,
-       struct v4l2_buffer *p)
-{
-       struct cx23885_fh *fh = priv;
-       return videobuf_dqbuf(get_queue(fh), p,
-                               file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_streamon(struct file *file, void *priv,
-       enum v4l2_buf_type i)
-{
-       struct cx23885_fh *fh = priv;
-       struct cx23885_dev *dev = fh->dev;
-       dprintk(1, "%s()\n", __func__);
-
-       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));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx23885_fh *fh = priv;
-       struct cx23885_dev *dev = fh->dev;
-       int err, res;
-       dprintk(1, "%s()\n", __func__);
-
-       if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
-               (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = get_resource(fh);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       res_free(dev, fh, res);
-       return 0;
-}
-
 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        dprintk(1, "%s()\n", __func__);
 
        *id = dev->tvnorm;
@@ -1262,14 +662,10 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        dprintk(1, "%s()\n", __func__);
 
-       mutex_lock(&dev->lock);
-       cx23885_set_tvnorm(dev, tvnorms);
-       mutex_unlock(&dev->lock);
-
-       return 0;
+       return cx23885_set_tvnorm(dev, tvnorms);
 }
 
 int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
@@ -1299,16 +695,16 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
        i->index = n;
        i->type  = V4L2_INPUT_TYPE_CAMERA;
        strcpy(i->name, iname[INPUT(n)->type]);
+       i->std = CX23885_NORMS;
        if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) ||
                (CX23885_VMUX_CABLE == INPUT(n)->type)) {
                i->type = V4L2_INPUT_TYPE_TUNER;
-               i->std = CX23885_NORMS;
+               i->audioset = 4;
+       } else {
+               /* Two selectable audio inputs for non-tv inputs */
+               i->audioset = 3;
        }
 
-       /* Two selectable audio inputs for non-tv inputs */
-       if (INPUT(n)->type != CX23885_VMUX_TELEVISION)
-               i->audioset = 0x3;
-
        if (dev->input == n) {
                /* enum'd input matches our configured input.
                 * Ask the video decoder to process the call
@@ -1324,14 +720,14 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
 static int vidioc_enum_input(struct file *file, void *priv,
                                struct v4l2_input *i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        dprintk(1, "%s()\n", __func__);
        return cx23885_enum_input(dev, i);
 }
 
 int cx23885_get_input(struct file *file, void *priv, unsigned int *i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        *i = dev->input;
        dprintk(1, "%s() returns %d\n", __func__, *i);
@@ -1345,7 +741,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 
 int cx23885_set_input(struct file *file, void *priv, unsigned int i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        dprintk(1, "%s(%d)\n", __func__, i);
 
@@ -1357,13 +753,11 @@ int cx23885_set_input(struct file *file, void *priv, unsigned int i)
        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;
 }
 
@@ -1374,39 +768,32 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 
 static int vidioc_log_status(struct file *file, void *priv)
 {
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
-       printk(KERN_INFO
-               "%s/0: ============  START LOG STATUS  ============\n",
-               dev->name);
        call_all(dev, core, log_status);
-       printk(KERN_INFO
-               "%s/0: =============  END LOG STATUS  =============\n",
-               dev->name);
        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;
+       struct cx23885_dev *dev = video_drvdata(file);
        static const char *iname[] = {
                [0] = "Baseband L/R 1",
                [1] = "Baseband L/R 2",
+               [2] = "TV",
        };
        unsigned int n;
        dprintk(1, "%s()\n", __func__);
 
        n = i->index;
-       if (n >= 2)
+       if (n >= 3)
                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;
+       i->capability = V4L2_AUDCAP_STEREO;
        return 0;
 
 }
@@ -1420,9 +807,13 @@ static int vidioc_enum_audinput(struct file *file, void *priv,
 static int vidioc_g_audinput(struct file *file, void *priv,
        struct v4l2_audio *i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
-       i->index = dev->audinput;
+       if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) ||
+               (CX23885_VMUX_CABLE == INPUT(dev->input)->type))
+               i->index = 2;
+       else
+               i->index = dev->audinput;
        dprintk(1, "%s(input=%d)\n", __func__, i->index);
 
        return cx23885_query_audinput(file, priv, i);
@@ -1431,8 +822,13 @@ static int vidioc_g_audinput(struct file *file, void *priv,
 static int vidioc_s_audinput(struct file *file, void *priv,
        const struct v4l2_audio *i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-       if (i->index >= 2)
+       struct cx23885_dev *dev = video_drvdata(file);
+
+       if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) ||
+               (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) {
+               return i->index != 2 ? -EINVAL : 0;
+       }
+       if (i->index > 1)
                return -EINVAL;
 
        dprintk(1, "%s(%d)\n", __func__, i->index);
@@ -1445,35 +841,10 @@ static int vidioc_s_audinput(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-                               struct v4l2_queryctrl *qctrl)
-{
-       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
-       if (unlikely(qctrl->id == 0))
-               return -EINVAL;
-       return cx23885_ctrl_query(qctrl);
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctl)
-{
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
-       return cx23885_get_control(dev, ctl);
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctl)
-{
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
-       return cx23885_set_control(dev, ctl);
-}
-
 static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *t)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
@@ -1489,7 +860,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_s_tuner(struct file *file, void *priv,
                                const struct v4l2_tuner *t)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
@@ -1504,14 +875,12 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct cx23885_fh *fh = priv;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
 
-       /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
-       f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       f->type = V4L2_TUNER_ANALOG_TV;
        f->frequency = dev->freq;
 
        call_all(dev, tuner, g_frequency, f);
@@ -1521,20 +890,23 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 
 static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency *f)
 {
-       struct v4l2_control ctrl;
+       struct v4l2_ctrl *mute;
+       int old_mute_val = 1;
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
        if (unlikely(f->tuner != 0))
                return -EINVAL;
 
-       mutex_lock(&dev->lock);
        dev->freq = f->frequency;
 
        /* I need to mute audio here */
-       ctrl.id = V4L2_CID_AUDIO_MUTE;
-       ctrl.value = 1;
-       cx23885_set_control(dev, &ctrl);
+       mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE);
+       if (mute) {
+               old_mute_val = v4l2_ctrl_g_ctrl(mute);
+               if (!old_mute_val)
+                       v4l2_ctrl_s_ctrl(mute, 1);
+       }
 
        call_all(dev, tuner, s_frequency, f);
 
@@ -1542,10 +914,8 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency
        msleep(100);
 
        /* I need to unmute audio here */
-       ctrl.value = 0;
-       cx23885_set_control(dev, &ctrl);
-
-       mutex_unlock(&dev->lock);
+       if (old_mute_val == 0)
+               v4l2_ctrl_s_ctrl(mute, old_mute_val);
 
        return 0;
 }
@@ -1553,8 +923,9 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency
 static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
        const struct v4l2_frequency *f)
 {
-       struct v4l2_control ctrl;
-       struct videobuf_dvb_frontend *vfe;
+       struct v4l2_ctrl *mute;
+       int old_mute_val = 1;
+       struct vb2_dvb_frontend *vfe;
        struct dvb_frontend *fe;
 
        struct analog_parameters params = {
@@ -1564,21 +935,22 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
                .frequency = f->frequency
        };
 
-       mutex_lock(&dev->lock);
        dev->freq = f->frequency;
 
        /* I need to mute audio here */
-       ctrl.id = V4L2_CID_AUDIO_MUTE;
-       ctrl.value = 1;
-       cx23885_set_control(dev, &ctrl);
+       mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE);
+       if (mute) {
+               old_mute_val = v4l2_ctrl_g_ctrl(mute);
+               if (!old_mute_val)
+                       v4l2_ctrl_s_ctrl(mute, 1);
+       }
 
        /* If HVR1850 */
        dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__,
                params.frequency, f->tuner, params.std);
 
-       vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1);
+       vfe = vb2_dvb_get_frontend(&dev->ts2.frontends, 1);
        if (!vfe) {
-               mutex_unlock(&dev->lock);
                return -EINVAL;
        }
 
@@ -1600,10 +972,8 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
        msleep(100);
 
        /* I need to unmute audio here */
-       ctrl.value = 0;
-       cx23885_set_control(dev, &ctrl);
-
-       mutex_unlock(&dev->lock);
+       if (old_mute_val == 0)
+               v4l2_ctrl_s_ctrl(mute, old_mute_val);
 
        return 0;
 }
@@ -1611,8 +981,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
 int cx23885_set_frequency(struct file *file, void *priv,
        const struct v4l2_frequency *f)
 {
-       struct cx23885_fh *fh = priv;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        int ret;
 
        switch (dev->board) {
@@ -1636,28 +1005,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 
 /* ----------------------------------------------------------- */
 
-static void cx23885_vid_timeout(unsigned long data)
-{
-       struct cx23885_dev *dev = (struct cx23885_dev *)data;
-       struct cx23885_dmaqueue *q = &dev->vidq;
-       struct cx23885_buffer *buf;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->slock, flags);
-       while (!list_empty(&q->active)) {
-               buf = list_entry(q->active.next,
-                       struct cx23885_buffer, vb.queue);
-               list_del(&buf->vb.queue);
-               buf->vb.state = VIDEOBUF_ERROR;
-               wake_up(&buf->vb.done);
-               printk(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n",
-                       dev->name, buf, buf->vb.i,
-                       (unsigned long)buf->risc.dma);
-       }
-       cx23885_restart_video_queue(dev, q);
-       spin_unlock_irqrestore(&dev->slock, flags);
-}
-
 int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
 {
        u32 mask, count;
@@ -1702,13 +1049,6 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
                spin_unlock(&dev->slock);
                handled++;
        }
-       if (status & VID_BC_MSK_RISCI2) {
-               dprintk(2, "stopper video\n");
-               spin_lock(&dev->slock);
-               cx23885_restart_video_queue(dev, &dev->vidq);
-               spin_unlock(&dev->slock);
-               handled++;
-       }
 
        /* Allow the VBI framework to process it's payload */
        handled += cx23885_vbi_irq(dev, status);
@@ -1721,12 +1061,12 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
 
 static const struct v4l2_file_operations video_fops = {
        .owner         = THIS_MODULE,
-       .open          = video_open,
-       .release       = video_release,
-       .read          = video_read,
-       .poll          = video_poll,
-       .mmap          = video_mmap,
-       .ioctl         = video_ioctl2,
+       .open           = v4l2_fh_open,
+       .release        = vb2_fop_release,
+       .read           = vb2_fop_read,
+       .poll           = vb2_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = vb2_fop_mmap,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -1738,21 +1078,19 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_g_fmt_vbi_cap     = cx23885_vbi_fmt,
        .vidioc_try_fmt_vbi_cap   = cx23885_vbi_fmt,
        .vidioc_s_fmt_vbi_cap     = cx23885_vbi_fmt,
-       .vidioc_reqbufs       = vidioc_reqbufs,
-       .vidioc_querybuf      = vidioc_querybuf,
-       .vidioc_qbuf          = vidioc_qbuf,
-       .vidioc_dqbuf         = vidioc_dqbuf,
+       .vidioc_reqbufs       = vb2_ioctl_reqbufs,
+       .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf      = vb2_ioctl_querybuf,
+       .vidioc_qbuf          = vb2_ioctl_qbuf,
+       .vidioc_dqbuf         = vb2_ioctl_dqbuf,
+       .vidioc_streamon      = vb2_ioctl_streamon,
+       .vidioc_streamoff     = vb2_ioctl_streamoff,
        .vidioc_s_std         = vidioc_s_std,
        .vidioc_g_std         = vidioc_g_std,
        .vidioc_enum_input    = vidioc_enum_input,
        .vidioc_g_input       = vidioc_g_input,
        .vidioc_s_input       = vidioc_s_input,
        .vidioc_log_status    = vidioc_log_status,
-       .vidioc_queryctrl     = vidioc_queryctrl,
-       .vidioc_g_ctrl        = vidioc_g_ctrl,
-       .vidioc_s_ctrl        = vidioc_s_ctrl,
-       .vidioc_streamon      = vidioc_streamon,
-       .vidioc_streamoff     = vidioc_streamoff,
        .vidioc_g_tuner       = vidioc_g_tuner,
        .vidioc_s_tuner       = vidioc_s_tuner,
        .vidioc_g_frequency   = vidioc_g_frequency,
@@ -1765,6 +1103,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_enumaudio     = vidioc_enum_audinput,
        .vidioc_g_audio       = vidioc_g_audinput,
        .vidioc_s_audio       = vidioc_s_audinput,
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 static struct video_device cx23885_vbi_template;
@@ -1775,14 +1115,6 @@ static struct video_device cx23885_video_template = {
        .tvnorms              = CX23885_NORMS,
 };
 
-static const struct v4l2_file_operations radio_fops = {
-       .owner         = THIS_MODULE,
-       .open          = video_open,
-       .release       = video_release,
-       .ioctl         = video_ioctl2,
-};
-
-
 void cx23885_video_unregister(struct cx23885_dev *dev)
 {
        dprintk(1, "%s()\n", __func__);
@@ -1794,7 +1126,6 @@ void cx23885_video_unregister(struct cx23885_dev *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))
@@ -1802,8 +1133,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev)
                else
                        video_device_release(dev->video_dev);
                dev->video_dev = NULL;
-
-               btcx_riscmem_free(dev->pci, &dev->vidq.stopper);
        }
 
        if (dev->audio_dev)
@@ -1812,6 +1141,7 @@ void cx23885_video_unregister(struct cx23885_dev *dev)
 
 int cx23885_video_register(struct cx23885_dev *dev)
 {
+       struct vb2_queue *q;
        int err;
 
        dprintk(1, "%s()\n", __func__);
@@ -1822,24 +1152,16 @@ int cx23885_video_register(struct cx23885_dev *dev)
        strcpy(cx23885_vbi_template.name, "cx23885-vbi");
 
        dev->tvnorm = V4L2_STD_NTSC_M;
+       dev->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
+       dev->field = V4L2_FIELD_INTERLACED;
+       dev->width = 720;
+       dev->height = norm_maxh(dev->tvnorm);
 
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
-       INIT_LIST_HEAD(&dev->vidq.queued);
-       dev->vidq.timeout.function = cx23885_vid_timeout;
-       dev->vidq.timeout.data = (unsigned long)dev;
-       init_timer(&dev->vidq.timeout);
-       cx23885_risc_stopper(dev->pci, &dev->vidq.stopper,
-               VID_A_DMA_CTL, 0x11, 0x00);
 
        /* 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);
 
@@ -1893,9 +1215,49 @@ int cx23885_video_register(struct cx23885_dev *dev)
                }
        }
 
+       /* initial device configuration */
+       mutex_lock(&dev->lock);
+       cx23885_set_tvnorm(dev, dev->tvnorm);
+       cx23885_video_mux(dev, 0);
+       cx23885_audio_mux(dev, 0);
+       mutex_unlock(&dev->lock);
+
+       q = &dev->vb2_vidq;
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+       q->gfp_flags = GFP_DMA32;
+       q->min_buffers_needed = 2;
+       q->drv_priv = dev;
+       q->buf_struct_size = sizeof(struct cx23885_buffer);
+       q->ops = &cx23885_video_qops;
+       q->mem_ops = &vb2_dma_sg_memops;
+       q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       q->lock = &dev->lock;
+
+       err = vb2_queue_init(q);
+       if (err < 0)
+               goto fail_unreg;
+
+       q = &dev->vb2_vbiq;
+       q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+       q->gfp_flags = GFP_DMA32;
+       q->min_buffers_needed = 2;
+       q->drv_priv = dev;
+       q->buf_struct_size = sizeof(struct cx23885_buffer);
+       q->ops = &cx23885_vbi_qops;
+       q->mem_ops = &vb2_dma_sg_memops;
+       q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       q->lock = &dev->lock;
+
+       err = vb2_queue_init(q);
+       if (err < 0)
+               goto fail_unreg;
+
        /* register Video device */
        dev->video_dev = cx23885_vdev_init(dev, dev->pci,
                &cx23885_video_template, "video");
+       dev->video_dev->queue = &dev->vb2_vidq;
        err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER,
                                    video_nr[dev->nr]);
        if (err < 0) {
@@ -1909,6 +1271,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
        /* register VBI device */
        dev->vbi_dev = cx23885_vdev_init(dev, dev->pci,
                &cx23885_vbi_template, "vbi");
+       dev->vbi_dev->queue = &dev->vb2_vbiq;
        err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
                                    vbi_nr[dev->nr]);
        if (err < 0) {
@@ -1922,18 +1285,9 @@ int cx23885_video_register(struct cx23885_dev *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;
 
 fail_unreg:
        cx23885_video_unregister(dev);
        return err;
 }
-
index c961a2b0de0ffa8c51ecffe0cbebb89085f3d330..291e8f3189f0ce1def25c2896dd5eaf1f8bbd696 100644 (file)
  *  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 _CX23885_VIDEO_H_
index 0e086c03da672ae241f0501aa72b85cd9f3b79f1..6c35e61159696ad4be7ee930d42a74e4636b98a1 100644 (file)
  *  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/pci.h>
 #include <linux/slab.h>
 
 #include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
 #include <media/tuner.h>
 #include <media/tveeprom.h>
-#include <media/videobuf-dma-sg.h>
-#include <media/videobuf-dvb.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-dvb.h>
 #include <media/rc-core.h>
 
-#include "btcx-risc.h"
 #include "cx23885-reg.h"
 #include "media/cx2341x.h"
 
 #include <linux/mutex.h>
 
-#define CX23885_VERSION "0.0.3"
+#define CX23885_VERSION "0.0.4"
 
 #define UNSET (-1U)
 
@@ -46,9 +43,6 @@
 /* Max number of inputs by card */
 #define MAX_CX23885_INPUT 8
 #define INPUT(nr) (&cx23885_boards[dev->board].input[nr])
-#define RESOURCE_OVERLAY       1
-#define RESOURCE_VIDEO         2
-#define RESOURCE_VBI           4
 
 #define BUFFER_TIMEOUT     (HZ)  /* 0.5 seconds */
 
@@ -98,6 +92,7 @@
 #define CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200 42
 #define CX23885_BOARD_HAUPPAUGE_IMPACTVCBE     43
 #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2 44
+#define CX23885_BOARD_DVBSKY_T9580             45
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
@@ -131,14 +126,6 @@ struct cx23885_fmt {
        u32   cxformat;
 };
 
-struct cx23885_ctrl {
-       struct v4l2_queryctrl v;
-       u32                   off;
-       u32                   reg;
-       u32                   mask;
-       u32                   shift;
-};
-
 struct cx23885_tvnorm {
        char            *name;
        v4l2_std_id     id;
@@ -146,30 +133,6 @@ struct cx23885_tvnorm {
        u32             cxoformat;
 };
 
-struct cx23885_fh {
-       struct cx23885_dev         *dev;
-       enum v4l2_buf_type         type;
-       int                        radio;
-       u32                        resources;
-
-       /* video overlay */
-       struct v4l2_window         win;
-       struct v4l2_clip           *clips;
-       unsigned int               nclips;
-
-       /* video capture */
-       struct cx23885_fmt         *fmt;
-       unsigned int               width, height;
-
-       /* vbi capture */
-       struct videobuf_queue      vidq;
-       struct videobuf_queue      vbiq;
-
-       /* MPEG Encoder specifics ONLY */
-       struct videobuf_queue      mpegq;
-       atomic_t                   v4l_reading;
-};
-
 enum cx23885_itype {
        CX23885_VMUX_COMPOSITE1 = 1,
        CX23885_VMUX_COMPOSITE2,
@@ -189,14 +152,22 @@ enum cx23885_src_sel_type {
        CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO
 };
 
+struct cx23885_riscmem {
+       unsigned int   size;
+       __le32         *cpu;
+       __le32         *jmp;
+       dma_addr_t     dma;
+};
+
 /* buffer for one video frame */
 struct cx23885_buffer {
        /* common v4l buffer stuff -- must be first */
-       struct videobuf_buffer vb;
+       struct vb2_buffer vb;
+       struct list_head queue;
 
        /* cx23885 specific */
        unsigned int           bpl;
-       struct btcx_riscmem    risc;
+       struct cx23885_riscmem risc;
        struct cx23885_fmt     *fmt;
        u32                    count;
 };
@@ -268,9 +239,6 @@ struct cx23885_i2c {
 
 struct cx23885_dmaqueue {
        struct list_head       active;
-       struct list_head       queued;
-       struct timer_list      timeout;
-       struct btcx_riscmem    stopper;
        u32                    count;
 };
 
@@ -280,7 +248,7 @@ struct cx23885_tsport {
        int                        nr;
        int                        sram_chno;
 
-       struct videobuf_dvb_frontends frontends;
+       struct vb2_dvb_frontends   frontends;
 
        /* dma queues */
        struct cx23885_dmaqueue    mpegq;
@@ -326,7 +294,12 @@ struct cx23885_tsport {
        /* Workaround for a temp dvb_frontend that the tuner can attached to */
        struct dvb_frontend analog_fe;
 
+       struct i2c_client *i2c_client_demod;
+       struct i2c_client *i2c_client_tuner;
+
        int (*set_frontend)(struct dvb_frontend *fe);
+       int (*fe_set_voltage)(struct dvb_frontend *fe,
+                               fe_sec_voltage_t voltage);
 };
 
 struct cx23885_kernel_ir {
@@ -339,8 +312,11 @@ struct cx23885_kernel_ir {
 
 struct cx23885_audio_buffer {
        unsigned int            bpl;
-       struct btcx_riscmem     risc;
-       struct videobuf_dmabuf  dma;
+       struct cx23885_riscmem  risc;
+       void                    *vaddr;
+       struct scatterlist      *sglist;
+       int                     sglen;
+       int                     nr_pages;
 };
 
 struct cx23885_audio_dev {
@@ -358,8 +334,6 @@ struct cx23885_audio_dev {
        unsigned int            period_size;
        unsigned int            num_periods;
 
-       struct videobuf_dmabuf  *dma_risc;
-
        struct cx23885_audio_buffer   *buf;
 
        struct snd_pcm_substream *substream;
@@ -368,6 +342,7 @@ struct cx23885_audio_dev {
 struct cx23885_dev {
        atomic_t                   refcount;
        struct v4l2_device         v4l2_dev;
+       struct v4l2_ctrl_handler   ctrl_handler;
 
        /* pci stuff */
        struct pci_dev             *pci;
@@ -407,7 +382,6 @@ struct cx23885_dev {
        } bridge;
 
        /* Analog video */
-       u32                        resources;
        unsigned int               input;
        unsigned int               audinput; /* Selectable audio input */
        u32                        tvaudio;
@@ -417,7 +391,6 @@ struct cx23885_dev {
        unsigned int               tuner_bus;
        unsigned int               radio_type;
        unsigned char              radio_addr;
-       unsigned int               has_radio;
        struct v4l2_subdev         *sd_cx25840;
        struct work_struct         cx25840_work;
 
@@ -435,17 +408,24 @@ struct cx23885_dev {
        u32                        freq;
        struct video_device        *video_dev;
        struct video_device        *vbi_dev;
-       struct video_device        *radio_dev;
+
+       /* video capture */
+       struct cx23885_fmt         *fmt;
+       unsigned int               width, height;
+       unsigned                   field;
 
        struct cx23885_dmaqueue    vidq;
+       struct vb2_queue           vb2_vidq;
        struct cx23885_dmaqueue    vbiq;
+       struct vb2_queue           vb2_vbiq;
+
        spinlock_t                 slock;
 
        /* MPEG Encoder ONLY settings */
        u32                        cx23417_mailbox;
-       struct cx2341x_mpeg_params mpeg_params;
+       struct cx2341x_handler     cxhdl;
        struct video_device        *v4l_device;
-       atomic_t                   v4l_reader_count;
+       struct vb2_queue           vb2_mpegq;
        struct cx23885_tvnorm      encodernorm;
 
        /* Analog raw audio */
@@ -521,26 +501,21 @@ extern int cx23885_sram_channel_setup(struct cx23885_dev *dev,
 extern void cx23885_sram_channel_dump(struct cx23885_dev *dev,
        struct sram_channel *ch);
 
-extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-       u32 reg, u32 mask, u32 value);
-
-extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+extern int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
        struct scatterlist *sglist,
        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,
+       struct cx23885_riscmem *risc, struct scatterlist *sglist,
        unsigned int top_offset, unsigned int bottom_offset,
        unsigned int bpl, unsigned int padding, unsigned int lines);
 
+int cx23885_start_dma(struct cx23885_tsport *port,
+                            struct cx23885_dmaqueue *q,
+                            struct cx23885_buffer   *buf);
 void cx23885_cancel_buffers(struct cx23885_tsport *port);
 
-extern int cx23885_restart_queue(struct cx23885_tsport *port,
-                               struct cx23885_dmaqueue *q);
-
-extern void cx23885_wakeup(struct cx23885_tsport *port,
-                          struct cx23885_dmaqueue *q, u32 count);
 
 extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask);
 extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask);
@@ -574,13 +549,11 @@ extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev);
 extern int cx23885_dvb_register(struct cx23885_tsport *port);
 extern int cx23885_dvb_unregister(struct cx23885_tsport *port);
 
-extern int cx23885_buf_prepare(struct videobuf_queue *q,
-                              struct cx23885_tsport *port,
-                              struct cx23885_buffer *buf,
-                              enum v4l2_field field);
+extern int cx23885_buf_prepare(struct cx23885_buffer *buf,
+                              struct cx23885_tsport *port);
 extern void cx23885_buf_queue(struct cx23885_tsport *port,
                              struct cx23885_buffer *buf);
-extern void cx23885_free_buffer(struct videobuf_queue *q,
+extern void cx23885_free_buffer(struct cx23885_dev *dev,
                                struct cx23885_buffer *buf);
 
 /* ----------------------------------------------------------- */
@@ -595,8 +568,6 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i);
 int cx23885_set_input(struct file *file, void *priv, unsigned int i);
 int cx23885_get_input(struct file *file, void *priv, unsigned int *i);
 int cx23885_set_frequency(struct file *file, void *priv, const struct v4l2_frequency *f);
-int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
-int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
 int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
 
 /* ----------------------------------------------------------- */
@@ -604,9 +575,7 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
 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 struct vb2_ops cx23885_vbi_qops;
 extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status);
 
 /* cx23885-i2c.c                                                */
@@ -638,7 +607,7 @@ extern struct cx23885_audio_dev *cx23885_audio_register(
 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 cx23885_riscmem *risc,
                                   struct scatterlist *sglist,
                                   unsigned int bpl,
                                   unsigned int lines,
@@ -649,15 +618,10 @@ extern int cx23885_risc_databuffer(struct pci_dev *pci,
 
 static inline unsigned int norm_maxw(v4l2_std_id norm)
 {
-       return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+       return (norm & V4L2_STD_525_60) ? 720 : 768;
 }
 
 static inline unsigned int norm_maxh(v4l2_std_id norm)
 {
-       return (norm & V4L2_STD_625_50) ? 576 : 480;
-}
-
-static inline unsigned int norm_swidth(v4l2_std_id norm)
-{
-       return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+       return (norm & V4L2_STD_525_60) ? 480 : 576;
 }
index c2ff5fc01157c51e72ca2147a73f447f20be2e86..c1aa888af705434148f3915c42b70a07a01d361b 100644 (file)
  *  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/kfifo.h>
index d2de41caaf1d6e902354adfacb6e8611cc7948d3..ff74a93575d681fee7a83856ab53b775cb7db04e 100644 (file)
  *  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 _CX23888_IR_H_
index 98a48f500684ce1f6256763a0d9c6cceef11c868..b6542ee4385b1dab71a644c965d4d090ded69f97 100644 (file)
  * 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.
  */
 
 #
index 13926e18febae16fdad84acd7bbdefd61f266f4b..90cac5b655d5dbbe6d05ff3fee79a3b8d5377373 100644 (file)
  * 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 NETUP_EEPROM_H
index 0044fef7ca24e2adac4d08f55f6d32bc9b08ed5d..76d9487aafc85c8c07bc8cb1dae59efd10fb2d10 100644 (file)
  * 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 "cx23885.h"
index d26ae4b1590ece5c745576466ca32a49ed96bd76..daaa212adfbab900c8a8801b99d40fa64a1b343e 100644 (file)
@@ -17,9 +17,5 @@
  * 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.
  */
 extern void netup_initialize(struct cx23885_dev *dev);
index 1f43be0b04c8e91dc5012275d3d040eb0bd92a2d..a664997e1958dccdba7fbf6315d1d5b4606ca084 100644 (file)
@@ -330,8 +330,9 @@ int cx25821_write_frame(struct cx25821_channel *chan,
 
        if (frame_size - curpos < count)
                count = frame_size - curpos;
-       memcpy((char *)out->_data_buf_virt_addr + frame_offset + curpos,
-                       data, count);
+       if (copy_from_user((__force char *)out->_data_buf_virt_addr + frame_offset + curpos,
+                               data, count))
+               return -EFAULT;
        curpos += count;
        if (curpos == frame_size) {
                out->_frame_count++;
index e18a7ace08b1b1a41667e10e5eb47d31f07deb91..851754bf1291475f6dc1c383401d753edb864edf 100644 (file)
@@ -78,19 +78,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE2,
                        .vmux   = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE3,
                        .vmux   = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE4,
                        .vmux   = 3,
-               }},
+               } },
        },
        [CX88_BOARD_HAUPPAUGE] = {
                .name           = "Hauppauge WinTV 34xxx models",
@@ -99,23 +99,23 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xff00,  // internal decoder
-               },{
+               }, {
                        .type   = CX88_VMUX_DEBUG,
                        .vmux   = 0,
                        .gpio0  = 0xff01,  // mono from tuner chip
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xff02,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xff02,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0xff01,
@@ -127,13 +127,13 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-               }},
+               } },
        },
        [CX88_BOARD_PIXELVIEW] = {
                .name           = "PixelView",
@@ -141,17 +141,17 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xff00,  // internal decoder
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-               }},
+               } },
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0xff10,
@@ -164,19 +164,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x03ff,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x03fe,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x03fe,
-               }},
+               } },
        },
        [CX88_BOARD_WINFAST2000XP_EXPERT] = {
                .name           = "Leadtek Winfast 2000XP Expert",
@@ -185,28 +185,28 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00F5e700,
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x00F5e700,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00F5c700,
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x00F5c700,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00F5c700,
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x00F5c700,
                        .gpio3  = 0x02000000,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x00F5d700,
@@ -222,19 +222,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio1  = 0xe09f,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio1  = 0xe05f,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio1  = 0xe05f,
-               }},
+               } },
                .radio = {
                        .gpio1  = 0xe0df,
                        .type   = CX88_RADIO,
@@ -249,25 +249,25 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x000040bf,
                        .gpio1  = 0x000080c0,
                        .gpio2  = 0x0000ff40,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x000040bf,
                        .gpio1  = 0x000080c0,
                        .gpio2  = 0x0000ff40,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x000040bf,
                        .gpio1  = 0x000080c0,
                        .gpio2  = 0x0000ff40,
-               }},
+               } },
                .radio = {
                         .type   = CX88_RADIO,
                         .vmux   = 3,
@@ -283,14 +283,14 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0035e700,
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x0035e700,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
 
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
@@ -298,14 +298,14 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x0035c700,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0035c700,
                        .gpio1  = 0x0035c700,
                        .gpio2  = 0x02000000,
                        .gpio3  = 0x02000000,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0035d700,
@@ -322,22 +322,22 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0000bde2,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0000bde6,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0000bde6,
                        .audioroute = 1,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0000bd62,
@@ -351,16 +351,16 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE2,
                        .vmux   = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-               }},
+               } },
        },
        [CX88_BOARD_PROLINK_PLAYTVPVR] = {
                .name           = "Prolink PlayTV PVR",
@@ -369,19 +369,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xbff0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xbff3,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xbff3,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0xbff0,
@@ -394,16 +394,16 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0000fde6,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
                        .audioroute = 1,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0000fde2,
@@ -417,22 +417,22 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00000fbf,
                        .gpio2  = 0x0000fc08,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00000fbf,
                        .gpio2  = 0x0000fc68,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00000fbf,
                        .gpio2  = 0x0000fc68,
-               }},
+               } },
        },
        [CX88_BOARD_KWORLD_DVB_T] = {
                .name           = "KWorld/VStream XPert DVB-T",
@@ -440,17 +440,17 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
@@ -459,15 +459,15 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x000027df,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x000027df,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_KWORLD_LTV883] = {
@@ -476,23 +476,23 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x07f8,
-               },{
+               }, {
                        .type   = CX88_VMUX_DEBUG,
                        .vmux   = 0,
                        .gpio0  = 0x07f9,  // mono from tuner chip
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x000007fa,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x000007fa,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x000007f8,
@@ -521,23 +521,23 @@ static const struct cx88_board cx88_boards[] = {
                    0 - normal RF
                    1 - high RF
                */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0f0d,
-               },{
+               }, {
                        .type   = CX88_VMUX_CABLE,
                        .vmux   = 0,
                        .gpio0  = 0x0f05,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0f00,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0f00,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
@@ -546,10 +546,10 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_CONEXANT_DVB_T1] = {
@@ -558,10 +558,10 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_PROVIDEO_PV259] = {
@@ -570,11 +570,11 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .audioroute = 1,
-               }},
+               } },
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
@@ -583,15 +583,15 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x000027df,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x000027df,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_DNTV_LIVE_DVB_T] = {
@@ -600,17 +600,17 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00000700,
                        .gpio2  = 0x00000101,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00000700,
                        .gpio2  = 0x00000101,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_PCHDTV_HD3000] = {
@@ -632,19 +632,19 @@ static const struct cx88_board cx88_boards[] = {
                 *
                 * GPIO[16] = Remote control input
                 */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00008484,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00008400,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00008400,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x00008404,
@@ -659,25 +659,25 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xed1a,
                        .gpio2  = 0x00ff,
-               },{
+               }, {
                        .type   = CX88_VMUX_DEBUG,
                        .vmux   = 0,
                        .gpio0  = 0xff01,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xff02,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xed92,
                        .gpio2  = 0x00ff,
-               }},
+               } },
                .radio = {
                         .type   = CX88_RADIO,
                         .gpio0  = 0xed96,
@@ -692,22 +692,22 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00009d80,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00009d76,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00009d76,
                        .audioroute = 1,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x00009d00,
@@ -722,19 +722,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 1,
                        .gpio1  = 0x0000e03f,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 2,
                        .gpio1  = 0x0000e07f,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 3,
                        .gpio1  = 0x0000e07f,
-               }}
+               } }
        },
        [CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = {
                .name           = "PixelView PlayTV Ultra Pro (Stereo)",
@@ -745,19 +745,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                /* Some variants use a tda9874 and so need the tvaudio module. */
                .audio_chip     = CX88_AUDIO_TVAUDIO,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xbf61,  /* internal decoder */
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xbf63,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xbf63,
-               }},
+               } },
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0xbf60,
@@ -770,19 +770,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x97ed,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x97e9,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x97e9,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
@@ -791,32 +791,32 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
                .name           = "TerraTec Cinergy 1400 DVB-T",
                .tuner_type     = TUNER_ABSENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
@@ -826,19 +826,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x87fd,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x87f9,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x87f9,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = {
@@ -848,22 +848,22 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 0,
                        .gpio0  = 0x0000cd73,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 1,
                        .gpio0  = 0x0000cd73,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 3,
                        .gpio0  = 0x0000cdb3,
                        .audioroute = 1,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .vmux   = 2,
@@ -876,21 +876,21 @@ static const struct cx88_board cx88_boards[] = {
                 /* Alexander Wold <awold@bigfoot.com> */
                 .name           = "Kworld V-Stream Xpert DVD",
                 .tuner_type     = UNSET,
-                .input          = {{
+                .input          = { {
                         .type   = CX88_VMUX_COMPOSITE1,
                         .vmux   = 1,
                         .gpio0  = 0x03000000,
                         .gpio1  = 0x01000000,
                         .gpio2  = 0x02000000,
                         .gpio3  = 0x00100000,
-                },{
+                }, {
                         .type   = CX88_VMUX_SVIDEO,
                         .vmux   = 2,
                         .gpio0  = 0x03000000,
                         .gpio1  = 0x01000000,
                         .gpio2  = 0x02000000,
                         .gpio3  = 0x00100000,
-                }},
+                } },
        },
        [CX88_BOARD_ATI_HDTVWONDER] = {
                .name           = "ATI HDTV Wonder",
@@ -898,28 +898,28 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00000ff7,
                        .gpio1  = 0x000000ff,
                        .gpio2  = 0x00000001,
                        .gpio3  = 0x00000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00000ffe,
                        .gpio1  = 0x000000ff,
                        .gpio2  = 0x00000001,
                        .gpio3  = 0x00000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00000ffe,
                        .gpio1  = 0x000000ff,
                        .gpio2  = 0x00000001,
                        .gpio3  = 0x00000000,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_WINFAST_DTV1000] = {
@@ -928,16 +928,16 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_AVERTV_303] = {
@@ -947,28 +947,28 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00ff,
                        .gpio1  = 0xe09f,
                        .gpio2  = 0x0010,
                        .gpio3  = 0x0000,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00ff,
                        .gpio1  = 0xe05f,
                        .gpio2  = 0x0010,
                        .gpio3  = 0x0000,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00ff,
                        .gpio1  = 0xe05f,
                        .gpio2  = 0x0010,
                        .gpio3  = 0x0000,
-               }},
+               } },
        },
        [CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = {
                .name           = "Hauppauge Nova-S-Plus DVB-S",
@@ -978,22 +978,22 @@ static const struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .audio_chip     = CX88_AUDIO_WM8775,
                .i2sinputcntl   = 2,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                        /* 2: Line-In */
                        .audioroute = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        /* 2: Line-In */
                        .audioroute = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        /* 2: Line-In */
                        .audioroute = 2,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = {
@@ -1002,10 +1002,10 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_KWORLD_DVBS_100] = {
@@ -1015,22 +1015,22 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .audio_chip = CX88_AUDIO_WM8775,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                        /* 2: Line-In */
                        .audioroute = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        /* 2: Line-In */
                        .audioroute = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        /* 2: Line-In */
                        .audioroute = 2,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_HAUPPAUGE_HVR1100] = {
@@ -1040,16 +1040,16 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-               }},
+               } },
                /* fixme: Add radio support */
                .mpeg           = CX88_MPEG_DVB,
        },
@@ -1060,13 +1060,13 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-               }},
+               } },
                /* fixme: Add radio support */
                .mpeg           = CX88_MPEG_DVB,
        },
@@ -1078,19 +1078,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
                                  TDA9887_PORT2_ACTIVE,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xf80808,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xf80808,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xf80808,
-               }},
+               } },
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0xf80808,
@@ -1106,17 +1106,17 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = {
@@ -1125,15 +1125,15 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x000067df,
-                },{
+                }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x000067df,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
@@ -1142,22 +1142,22 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x3de2,
                        .gpio2  = 0x00ff,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x3de6,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x3de6,
                        .audioroute = 1,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x3de6,
@@ -1171,19 +1171,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0000a75f,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0000a75b,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0000a75b,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_PCHDTV_HD5500] = {
@@ -1193,19 +1193,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x87fd,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x87f9,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x87f9,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_KWORLD_MCE200_DELUXE] = {
@@ -1217,11 +1217,11 @@ static const struct cx88_board cx88_boards[] = {
                .tda9887_conf   = TDA9887_PRESENT,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0000BDE6
-               }},
+               } },
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
        [CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
@@ -1233,11 +1233,11 @@ static const struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
                                  TDA9887_PORT2_ACTIVE,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x5da6,
-               }},
+               } },
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
        [CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
@@ -1246,19 +1246,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0788,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x078b,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x078b,
-               }},
+               } },
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0x074a,
@@ -1271,7 +1271,7 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00017304,
@@ -1299,7 +1299,7 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio1  = 0x0000b207,
                        .gpio2  = 0x0001d701,
                        .gpio3  = 0x02000000,
-               }},
+               } },
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0x00015702,
@@ -1316,35 +1316,35 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00017300,
                        .gpio1  = 0x00008207,
                        .gpio2  = 0x00000000,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00018300,
                        .gpio1  = 0x0000f207,
                        .gpio2  = 0x00017304,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00018301,
                        .gpio1  = 0x0000f207,
                        .gpio2  = 0x00017304,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00018301,
                        .gpio1  = 0x0000f207,
                        .gpio2  = 0x00017304,
                        .gpio3  = 0x02000000,
-               }},
+               } },
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0x00015702,
@@ -1360,13 +1360,13 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type    = UNSET,
                .tuner_addr    = ADDR_UNSET,
                .radio_addr    = ADDR_UNSET,
-               .input  = {{
+               .input  = { {
                        .type  = CX88_VMUX_DVB,
                        .vmux  = 0,
-               },{
+               }, {
                        .type  = CX88_VMUX_COMPOSITE1,
                        .vmux  = 1,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_HAUPPAUGE_HVR3000] = {
@@ -1377,25 +1377,25 @@ static const struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .audio_chip     = CX88_AUDIO_WM8775,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x84bf,
                        /* 1: TV Audio / FM Mono */
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x84bf,
                        /* 2: Line-In */
                        .audioroute = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x84bf,
                        /* 2: Line-In */
                        .audioroute = 2,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x84bf,
@@ -1411,19 +1411,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0709,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x070b,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x070b,
-               }},
+               } },
        },
        [CX88_BOARD_TE_DTV_250_OEM_SWANN] = {
                .name           = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM",
@@ -1431,28 +1431,28 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x003fffff,
                        .gpio1  = 0x00e00000,
                        .gpio2  = 0x003fffff,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x003fffff,
                        .gpio1  = 0x00e00000,
                        .gpio2  = 0x003fffff,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x003fffff,
                        .gpio1  = 0x00e00000,
                        .gpio2  = 0x003fffff,
                        .gpio3  = 0x02000000,
-               }},
+               } },
        },
        [CX88_BOARD_HAUPPAUGE_HVR1300] = {
                .name           = "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder",
@@ -1465,25 +1465,25 @@ static const struct cx88_board cx88_boards[] = {
                /*
                 * gpio0 as reported by Mike Crash <mike AT mikecrash.com>
                 */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xef88,
                        /* 1: TV Audio / FM Mono */
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xef88,
                        /* 2: Line-In */
                        .audioroute = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xef88,
                        /* 2: Line-In */
                        .audioroute = 2,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
                .radio = {
                        .type   = CX88_RADIO,
@@ -1510,19 +1510,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DEBUG,
                        .vmux   = 3,
                        .gpio0  = 0x04ff,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x07fa,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x07fa,
-               }},
+               } },
        },
        [CX88_BOARD_PINNACLE_PCTV_HD_800i] = {
                .name           = "Pinnacle PCTV HD 800i",
@@ -1530,24 +1530,24 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x04fb,
                        .gpio1  = 0x10ff,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x04fb,
                        .gpio1  = 0x10ef,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x04fb,
                        .gpio1  = 0x10ef,
                        .audioroute = 1,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = {
@@ -1557,7 +1557,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x000027df, /* Unconfirmed */
@@ -1815,19 +1815,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x10df,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x16d9,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x16d9,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_PROLINK_PV_8000GT] = {
@@ -1967,7 +1967,7 @@ static const struct cx88_board cx88_boards[] = {
                 * 3: Line-In Expansion
                 * 4: FM Stereo
                 */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xc4bf,
@@ -2001,7 +2001,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2013,7 +2013,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2025,7 +2025,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2037,7 +2037,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2049,7 +2049,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2061,7 +2061,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2073,7 +2073,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                        .gpio0  = 0x8080,
@@ -2086,7 +2086,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2098,7 +2098,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2110,7 +2110,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2170,7 +2170,7 @@ static const struct cx88_board cx88_boards[] = {
                 * 13: audio source (0=tuner audio,1=line in)
                 * 14: FM (0=on,1=off ???)
                 */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0400,       /* pin 2 = 0 */
@@ -2211,7 +2211,7 @@ static const struct cx88_board cx88_boards[] = {
                 * 13: audio source (0=tuner audio,1=line in)
                 * 14: FM (0=on,1=off ???)
                 */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0400,       /* pin 2 = 0 */
@@ -2229,7 +2229,7 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio0  = 0x0400,       /* pin 2 = 0 */
                        .gpio1  = 0x6060,       /* pin 13 = 1, pin 14 = 1 */
                        .gpio2  = 0x0000,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0400,       /* pin 2 = 0 */
@@ -2252,7 +2252,7 @@ static const struct cx88_board cx88_boards[] = {
                 *  14: 0: FM radio
                 *  16: 0: RF input is cable
                 */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0403,
@@ -2280,7 +2280,7 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio1  = 0xF0F7,
                        .gpio2  = 0x0101,
                        .gpio3  = 0x0000,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0403,
@@ -2308,7 +2308,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                       .type   = CX88_VMUX_DVB,
                       .vmux   = 0,
                } },
@@ -2324,19 +2324,19 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x0070,
                .subdevice = 0x3400,
                .card      = CX88_BOARD_HAUPPAUGE,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x3401,
                .card      = CX88_BOARD_HAUPPAUGE,
-       },{
+       }, {
                .subvendor = 0x14c7,
                .subdevice = 0x0106,
                .card      = CX88_BOARD_GDI,
-       },{
+       }, {
                .subvendor = 0x14c7,
                .subdevice = 0x0107, /* with mpeg encoder */
                .card      = CX88_BOARD_GDI,
-       },{
+       }, {
                .subvendor = PCI_VENDOR_ID_ATI,
                .subdevice = 0x00f8,
                .card      = CX88_BOARD_ATI_WONDER_PRO,
@@ -2348,176 +2348,176 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x107d,
                .subdevice = 0x6611,
                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x6613,    /* NTSC */
                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x6620,
                .card      = CX88_BOARD_WINFAST_DV2000,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x663b,
                .card      = CX88_BOARD_LEADTEK_PVR2000,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x663c,
                .card      = CX88_BOARD_LEADTEK_PVR2000,
-       },{
+       }, {
                .subvendor = 0x1461,
                .subdevice = 0x000b,
                .card      = CX88_BOARD_AVERTV_STUDIO_303,
-       },{
+       }, {
                .subvendor = 0x1462,
                .subdevice = 0x8606,
                .card      = CX88_BOARD_MSI_TVANYWHERE_MASTER,
-       },{
+       }, {
                .subvendor = 0x10fc,
                .subdevice = 0xd003,
                .card      = CX88_BOARD_IODATA_GVVCP3PCI,
-       },{
+       }, {
                .subvendor = 0x1043,
                .subdevice = 0x4823,  /* with mpeg encoder */
                .card      = CX88_BOARD_ASUS_PVR_416,
-       },{
+       }, {
                .subvendor = 0x17de,
                .subdevice = 0x08a6,
                .card      = CX88_BOARD_KWORLD_DVB_T,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xd810,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xd820,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb00,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9002,
                .card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-       },{
+       }, {
                .subvendor = 0x14f1,
                .subdevice = 0x0187,
                .card      = CX88_BOARD_CONEXANT_DVB_T1,
-       },{
+       }, {
                .subvendor = 0x1540,
                .subdevice = 0x2580,
                .card      = CX88_BOARD_PROVIDEO_PV259,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb10,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
-       },{
+       }, {
                .subvendor = 0x1554,
                .subdevice = 0x4811,
                .card      = CX88_BOARD_PIXELVIEW,
-       },{
+       }, {
                .subvendor = 0x7063,
                .subdevice = 0x3000, /* HD-3000 card */
                .card      = CX88_BOARD_PCHDTV_HD3000,
-       },{
+       }, {
                .subvendor = 0x17de,
                .subdevice = 0xa8a6,
                .card      = CX88_BOARD_DNTV_LIVE_DVB_T,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x2801,
                .card      = CX88_BOARD_HAUPPAUGE_ROSLYN,
-       },{
+       }, {
                .subvendor = 0x14f1,
                .subdevice = 0x0342,
                .card      = CX88_BOARD_DIGITALLOGIC_MEC,
-       },{
+       }, {
                .subvendor = 0x10fc,
                .subdevice = 0xd035,
                .card      = CX88_BOARD_IODATA_GVBCTV7E,
-       },{
+       }, {
                .subvendor = 0x1421,
                .subdevice = 0x0334,
                .card      = CX88_BOARD_ADSTECH_DVB_T_PCI,
-       },{
+       }, {
                .subvendor = 0x153b,
                .subdevice = 0x1166,
                .card      = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xd500,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD,
-       },{
+       }, {
                .subvendor = 0x1461,
                .subdevice = 0x8011,
                .card      = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550,
-       },{
+       }, {
                .subvendor = PCI_VENDOR_ID_ATI,
                .subdevice = 0xa101,
                .card      = CX88_BOARD_ATI_HDTVWONDER,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x665f,
                .card      = CX88_BOARD_WINFAST_DTV1000,
-       },{
+       }, {
                .subvendor = 0x1461,
                .subdevice = 0x000a,
                .card      = CX88_BOARD_AVERTV_303,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9200,
                .card      = CX88_BOARD_HAUPPAUGE_NOVASE2_S1,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9201,
                .card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9202,
                .card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
-       },{
+       }, {
                .subvendor = 0x17de,
                .subdevice = 0x08b2,
                .card      = CX88_BOARD_KWORLD_DVBS_100,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9400,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1100,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9402,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1100,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9800,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9802,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9001,
                .card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-       },{
+       }, {
                .subvendor = 0x1822,
                .subdevice = 0x0025,
                .card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
-       },{
+       }, {
                .subvendor = 0x17de,
                .subdevice = 0x08a1,
                .card      = CX88_BOARD_KWORLD_DVB_T_CX22702,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb50,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb54,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
                /* Re-branded DViCO: DigitalNow DVB-T Dual */
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb11,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
@@ -2530,55 +2530,55 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x17de,
                .subdevice = 0x0840,
                .card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
-       },{
+       }, {
                .subvendor = 0x1421,
                .subdevice = 0x0305,
                .card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb40,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb44,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
-       },{
+       }, {
                .subvendor = 0x7063,
                .subdevice = 0x5500,
                .card      = CX88_BOARD_PCHDTV_HD5500,
-       },{
+       }, {
                .subvendor = 0x17de,
                .subdevice = 0x0841,
                .card      = CX88_BOARD_KWORLD_MCE200_DELUXE,
-       },{
+       }, {
                .subvendor = 0x1822,
                .subdevice = 0x0019,
                .card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
-       },{
+       }, {
                .subvendor = 0x1554,
                .subdevice = 0x4813,
                .card      = CX88_BOARD_PIXELVIEW_PLAYTV_P7000,
-       },{
+       }, {
                .subvendor = 0x14f1,
                .subdevice = 0x0842,
                .card      = CX88_BOARD_NPGTECH_REALTV_TOP10FM,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x665e,
                .card      = CX88_BOARD_WINFAST_DTV2000H,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x6f2b,
                .card      = CX88_BOARD_WINFAST_DTV2000H_J,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
-       },{
+       }, {
                .subvendor = 0x14f1,
                .subdevice = 0x0084,
                .card      = CX88_BOARD_GENIATECH_DVBS,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x1404,
                .card      = CX88_BOARD_HAUPPAUGE_HVR3000,
@@ -2590,60 +2590,60 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x18ac,
                .subdevice = 0xdccd,
                .card      = CX88_BOARD_SAMSUNG_SMT_7020,
-       },{
+       }, {
                .subvendor = 0x1461,
                .subdevice = 0xc111, /* AverMedia M150-D */
                /* This board is known to work with the ASUS PVR416 config */
                .card      = CX88_BOARD_ASUS_PVR_416,
-       },{
+       }, {
                .subvendor = 0xc180,
                .subdevice = 0xc980,
                .card      = CX88_BOARD_TE_DTV_250_OEM_SWANN,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9600,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1300,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9601,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1300,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9602,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1300,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x6632,
                .card      = CX88_BOARD_LEADTEK_PVR2000,
-       },{
+       }, {
                .subvendor = 0x12ab,
                .subdevice = 0x2300, /* Club3D Zap TV2100 */
                .card      = CX88_BOARD_KWORLD_DVB_T_CX22702,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9000,
                .card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x1400,
                .card      = CX88_BOARD_HAUPPAUGE_HVR3000,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x1401,
                .card      = CX88_BOARD_HAUPPAUGE_HVR3000,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x1402,
                .card      = CX88_BOARD_HAUPPAUGE_HVR3000,
-       },{
+       }, {
                .subvendor = 0x1421,
                .subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
                .card      = CX88_BOARD_KWORLD_DVBS_100,
-       },{
+       }, {
                .subvendor = 0x1421,
                .subdevice = 0x0390,
                .card      = CX88_BOARD_ADSTECH_PTV_390,
-       },{
+       }, {
                .subvendor = 0x11bd,
                .subdevice = 0x0051,
                .card      = CX88_BOARD_PINNACLE_PCTV_HD_800i,
index ed8cb9037b6f30f0876ea377c42db799a8dd0e51..ce27e6d4f16ea21df367c0e59930d2446ea82798 100644 (file)
@@ -696,7 +696,6 @@ static struct videobuf_queue *get_queue(struct file *file)
                return &fh->vbiq;
        default:
                BUG();
-               return NULL;
        }
 }
 
@@ -711,7 +710,6 @@ static int get_resource(struct file *file)
                return RESOURCE_VBI;
        default:
                BUG();
-               return 0;
        }
 }
 
@@ -812,7 +810,6 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
                                            file->f_flags & O_NONBLOCK);
        default:
                BUG();
-               return 0;
        }
 }
 
index da8f848be3b801cfee8ac6a1bba76b8de3da584f..c82e855a0814c87cf03782f1521915276686569a 100644 (file)
@@ -149,7 +149,7 @@ static u32 ddb_i2c_functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_EMUL;
 }
 
-struct i2c_algorithm ddb_i2c_algo = {
+static struct i2c_algorithm ddb_i2c_algo = {
        .master_xfer   = ddb_i2c_master_xfer,
        .functionality = ddb_i2c_functionality,
 };
@@ -266,7 +266,7 @@ static void io_free(struct pci_dev *pdev, u8 **vbuf,
        for (i = 0; i < num; i++) {
                if (vbuf[i]) {
                        pci_free_consistent(pdev, size, vbuf[i], pbuf[i]);
-                       vbuf[i] = 0;
+                       vbuf[i] = NULL;
                }
        }
 }
@@ -440,7 +440,7 @@ static u32 ddb_output_free(struct ddb_output *output)
 }
 
 static ssize_t ddb_output_write(struct ddb_output *output,
-                               const u8 *buf, size_t count)
+                               const __user u8 *buf, size_t count)
 {
        struct ddb *dev = output->port->dev;
        u32 idx, off, stat = output->stat;
@@ -506,7 +506,7 @@ static u32 ddb_input_avail(struct ddb_input *input)
        return 0;
 }
 
-static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
+static ssize_t ddb_input_read(struct ddb_input *input, __user u8 *buf, size_t count)
 {
        struct ddb *dev = input->port->dev;
        u32 left = count;
@@ -849,7 +849,7 @@ static int dvb_input_attach(struct ddb_input *input)
                return ret;
        input->attached = 4;
 
-       input->fe = 0;
+       input->fe = NULL;
        switch (port->type) {
        case DDB_TUNER_DVBS_ST:
                if (demod_attach_stv0900(input, 0) < 0)
@@ -895,7 +895,7 @@ static int dvb_input_attach(struct ddb_input *input)
 /****************************************************************************/
 /****************************************************************************/
 
-static ssize_t ts_write(struct file *file, const char *buf,
+static ssize_t ts_write(struct file *file, const __user char *buf,
                        size_t count, loff_t *ppos)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -920,7 +920,7 @@ static ssize_t ts_write(struct file *file, const char *buf,
        return (left == count) ? -EAGAIN : (count - left);
 }
 
-static ssize_t ts_read(struct file *file, char *buf,
+static ssize_t ts_read(struct file *file, __user char *buf,
                       size_t count, loff_t *ppos)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -975,11 +975,9 @@ static const struct file_operations ci_fops = {
        .open    = dvb_generic_open,
        .release = dvb_generic_release,
        .poll    = ts_poll,
-       .mmap    = 0,
 };
 
 static struct dvb_device dvbdev_ci = {
-       .priv    = 0,
        .readers = -1,
        .writers = -1,
        .users   = -1,
@@ -1038,7 +1036,7 @@ static void output_tasklet(unsigned long data)
 }
 
 
-struct cxd2099_cfg cxd_cfg = {
+static struct cxd2099_cfg cxd_cfg = {
        .bitrate =  62000,
        .adr     =  0x40,
        .polarity = 1,
@@ -1127,7 +1125,7 @@ static void ddb_ports_detach(struct ddb *dev)
                                ddb_output_stop(port->output);
                                dvb_ca_en50221_release(port->en);
                                kfree(port->en);
-                               port->en = 0;
+                               port->en = NULL;
                                dvb_unregister_adapter(&port->output->adap);
                        }
                        break;
@@ -1413,9 +1411,9 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
 #define DDB_MAGIC 'd'
 
 struct ddb_flashio {
-       __u8 *write_buf;
+       __user __u8 *write_buf;
        __u32 write_len;
-       __u8 *read_buf;
+       __user __u8 *read_buf;
        __u32 read_len;
 };
 
@@ -1439,7 +1437,7 @@ static int ddb_open(struct inode *inode, struct file *file)
 static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct ddb *dev = file->private_data;
-       void *parg = (void *)arg;
+       __user void *parg = (__user void *)arg;
        int res;
 
        switch (cmd) {
@@ -1558,7 +1556,7 @@ static void ddb_remove(struct pci_dev *pdev)
        ddb_device_destroy(dev);
 
        ddb_unmap(dev);
-       pci_set_drvdata(pdev, 0);
+       pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
 }
 
@@ -1637,7 +1635,7 @@ fail1:
 fail:
        printk(KERN_ERR "fail\n");
        ddb_unmap(dev);
-       pci_set_drvdata(pdev, 0);
+       pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
        return -1;
 }
index 8b1b41d2a52d4d465b233d57755fc724d5f9ab56..be87fbd9045646214f61aeda2f573ba1e62b1462 100644 (file)
@@ -156,7 +156,7 @@ struct ddb_port {
 
 struct ddb {
        struct pci_dev        *pdev;
-       unsigned char         *regs;
+       unsigned char __iomem *regs;
        struct ddb_port        port[DDB_MAX_PORT];
        struct ddb_i2c         i2c[DDB_MAX_I2C];
        struct ddb_input       input[DDB_MAX_INPUT];
@@ -173,12 +173,10 @@ struct ddb {
 /****************************************************************************/
 
 #define ddbwritel(_val, _adr)        writel((_val), \
-                                    (char *) (dev->regs+(_adr)))
-#define ddbreadl(_adr)               readl((char *) (dev->regs+(_adr)))
-#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *)      \
-                                    (dev->regs+(_adr)), (_src), (_count))
-#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \
-                                      (dev->regs+(_adr)), (_count))
+                                    dev->regs+(_adr))
+#define ddbreadl(_adr)               readl(dev->regs+(_adr))
+#define ddbcpyto(_adr, _src, _count) memcpy_toio(dev->regs+(_adr), (_src), (_count))
+#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), dev->regs+(_adr), (_count))
 
 /****************************************************************************/
 
index e8826c535ccdb2980fc6e931831f2826bcb51161..ed11716731e95cdb6a51ce90b7df6c4de267e44d 100644 (file)
@@ -614,7 +614,7 @@ static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 
 static void dm1105_set_dma_addr(struct dm1105_dev *dev)
 {
-       dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr));
+       dm_writel(DM1105_STADR, (__force u32)cpu_to_le32(dev->dma_addr));
 }
 
 static int dm1105_dma_map(struct dm1105_dev *dev)
index 7a9b98bc208bc252ae9d1dc334fabb48bf39c5f5..7bf9cbca4fa64fe3e63c3d17ea7432e661069e85 100644 (file)
@@ -81,7 +81,7 @@ static void ivtv_alsa_announce_pcm_data(struct snd_ivtv_card *itvsc,
        int period_elapsed = 0;
        int length;
 
-       dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zd\n", itvsc,
+       dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zu\n", itvsc,
                pcm_data, num_bytes);
 
        substream = itvsc->capture_pcm_substream;
index ed73edd2bcd308e310197ac3ff9bff2559905bd5..4b0e758a7bce38d68deab9d55a1445e21fee201e 100644 (file)
@@ -65,7 +65,7 @@ retry:
                           the wrong file was sometimes loaded. So we check filesizes to
                           see if at least the right-sized file was loaded. If not, then we
                           retry. */
-                       IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+                       IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zu)\n", fn, size, fw->size);
                        release_firmware(fw);
                        retries--;
                        goto retry;
@@ -76,7 +76,7 @@ retry:
                        dst++;
                        src++;
                }
-               IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
+               IVTV_INFO("Loaded %s firmware (%zu bytes)\n", fn, fw->size);
                release_firmware(fw);
                return size;
        }
index 19a7c9b990a393b93adb27818d069560f1027bda..ab6d5d25aa6fdd1a757814c18318dc5881e47a41 100644 (file)
@@ -192,11 +192,11 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
                if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
                    s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
                        s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET);
-                       write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET);
+                       write_dec_sync(DMA_MAGIC_COOKIE, offset - IVTV_DECODER_OFFSET);
                }
                else {
                        s->pending_backup = read_enc(offset);
-                       write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset);
+                       write_enc_sync(DMA_MAGIC_COOKIE, offset);
                }
                s->pending_offset = offset;
        }
@@ -275,13 +275,11 @@ static void dma_post(struct ivtv_stream *s)
 
                if (x == 0 && ivtv_use_dma(s)) {
                        offset = s->dma_last_offset;
-                       if (u32buf[offset / 4] != DMA_MAGIC_COOKIE)
+                       if (le32_to_cpu(u32buf[offset / 4]) != DMA_MAGIC_COOKIE)
                        {
-                               for (offset = 0; offset < 64; offset++) {
-                                       if (u32buf[offset] == DMA_MAGIC_COOKIE) {
+                               for (offset = 0; offset < 64; offset++)
+                                       if (le32_to_cpu(u32buf[offset]) == DMA_MAGIC_COOKIE)
                                                break;
-                                       }
-                               }
                                offset *= 4;
                                if (offset == 256) {
                                        IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name);
index 68a29f8bdf732b1e7bad70cba5afb5f365c86e6e..1032db6bb789548633cf9c62cac0d8b7307fe1a7 100644 (file)
@@ -34,7 +34,7 @@
 #include "mantis_dvb.h"
 #include "hopper_vp3028.h"
 
-struct zl10353_config hopper_vp3028_config = {
+static struct zl10353_config hopper_vp3028_config = {
        .demod_address  = 0x0f,
 };
 
index f2410cf0a6bf0ec980b475f8785d5afb7a58ec52..8ff448bb792d796f6a58273ca247a34487f7e459 100644 (file)
@@ -127,7 +127,7 @@ struct mantis_pci {
        u32                     last_block;
        u8                      *buf_cpu;
        dma_addr_t              buf_dma;
-       u32                     *risc_cpu;
+       __le32                  *risc_cpu;
        dma_addr_t              risc_dma;
 
        struct tasklet_struct   tasklet;
index 115003e8d19d453f30a2db59664d3a561c614116..12a6adb2bd7e167cc575abc04588ca018a4b39b7 100644 (file)
@@ -35,7 +35,7 @@
 #include "mantis_vp1033.h"
 #include "mantis_reg.h"
 
-u8 lgtdqcs001f_inittab[] = {
+static u8 lgtdqcs001f_inittab[] = {
        0x01, 0x15,
        0x02, 0x30,
        0x03, 0x00,
@@ -150,7 +150,7 @@ static int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe,
        return 0;
 }
 
-struct stv0299_config lgtdqcs001f_config = {
+static struct stv0299_config lgtdqcs001f_config = {
        .demod_address          = 0x68,
        .inittab                = lgtdqcs001f_inittab,
        .mclk                   = 88000000UL,
index 430ae84ce528dd99545b061929928233950dc845..7c1bd167225c28b3bf6c9819e7294e7e197a833d 100644 (file)
@@ -36,7 +36,7 @@
 #include "mantis_vp1034.h"
 #include "mantis_reg.h"
 
-struct mb86a16_config vp1034_mb86a16_config = {
+static struct mb86a16_config vp1034_mb86a16_config = {
        .demod_address  = 0x08,
        .set_voltage    = vp1034_set_voltage,
 };
index 07a20748b707ef5356bd40fac96dc891d974716e..7082fcbc94a1001d6412b3b704673c807144f8c1 100644 (file)
@@ -263,7 +263,7 @@ static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = {
        { 0xffff                        , 0xff },
 };
 
-struct stb0899_config vp1041_stb0899_config = {
+static struct stb0899_config vp1041_stb0899_config = {
        .init_dev               = vp1041_stb0899_s1_init_1,
        .init_s2_demod          = stb0899_s2_init_2,
        .init_s1_demod          = vp1041_stb0899_s1_init_3,
@@ -300,7 +300,7 @@ struct stb0899_config vp1041_stb0899_config = {
        .tuner_set_rfsiggain    = NULL,
 };
 
-struct stb6100_config vp1041_stb6100_config = {
+static struct stb6100_config vp1041_stb6100_config = {
        .tuner_address  = 0x60,
        .refclock       = 27000000,
 };
index 1ca6837fbe468a8da8f82fe7818a4240880e5004..8d48b5abe04a5eb42d3eb0586b85e6884751ca9f 100644 (file)
 #define MANTIS_MODEL_NAME      "VP-2033"
 #define MANTIS_DEV_TYPE                "DVB-C"
 
-struct tda1002x_config vp2033_tda1002x_cu1216_config = {
+static struct tda1002x_config vp2033_tda1002x_cu1216_config = {
        .demod_address = 0x18 >> 1,
        .invert = 1,
 };
 
-struct tda10023_config vp2033_tda10023_cu1216_config = {
+static struct tda10023_config vp2033_tda10023_cu1216_config = {
        .demod_address = 0x18 >> 1,
        .invert = 1,
 };
index d480741afd786dc3e13420077d43f4567f38e666..8dd17d7c08819b83dedf4110571223daa12f1025 100644 (file)
 #define MANTIS_MODEL_NAME      "VP-2040"
 #define MANTIS_DEV_TYPE                "DVB-C"
 
-struct tda1002x_config vp2040_tda1002x_cu1216_config = {
+static struct tda1002x_config vp2040_tda1002x_cu1216_config = {
        .demod_address  = 0x18 >> 1,
        .invert         = 1,
 };
 
-struct tda10023_config vp2040_tda10023_cu1216_config = {
+static struct tda10023_config vp2040_tda10023_cu1216_config = {
        .demod_address  = 0x18 >> 1,
        .invert         = 1,
 };
index c09308cd3ac677e0d53ace29e525039e3482dc04..5c1dd925bdd5000ed61dd59c6bcd24c76d5717c0 100644 (file)
 #include "mantis_dvb.h"
 #include "mantis_vp3030.h"
 
-struct zl10353_config mantis_vp3030_config = {
+static struct zl10353_config mantis_vp3030_config = {
        .demod_address          = 0x0f,
 };
 
-struct tda665x_config env57h12d5_config = {
+static struct tda665x_config env57h12d5_config = {
        .name                   = "ENV57H12D5 (ET-50DT)",
        .addr                   = 0x60,
        .frequency_min          =  47000000,
index 9e82d2105d5365659be6dd7560927066f6427235..039bed3cc919d2f5624e1635327e126abdfca064 100644 (file)
@@ -696,7 +696,7 @@ static struct ngene_info ngene_info_m780 = {
        .demod_attach   = { NULL, demod_attach_lg330x },
 
        /* Ensure these are NULL else the frame will call them (as funcs) */
-       .tuner_attach   = { 0, 0, 0, 0 },
+       .tuner_attach   = { NULL, NULL, NULL, NULL },
        .fe_config      = { NULL, &aver_m780 },
        .avf            = { 0 },
 
index 4930b55fd5f4f855399ebb6c828daece0c579ce8..e29bc3af4bafe3ad25a8e059c9d0697b12940874 100644 (file)
@@ -57,15 +57,13 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 #define dprintk        if (debug) printk
 
-#define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
-#define ngwritel(dat, adr)         writel((dat), (char *)(dev->iomem + (adr)))
-#define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
+#define ngwriteb(dat, adr)         writeb((dat), dev->iomem + (adr))
+#define ngwritel(dat, adr)         writel((dat), dev->iomem + (adr))
+#define ngwriteb(dat, adr)         writeb((dat), dev->iomem + (adr))
 #define ngreadl(adr)               readl(dev->iomem + (adr))
 #define ngreadb(adr)               readb(dev->iomem + (adr))
-#define ngcpyto(adr, src, count)   memcpy_toio((char *) \
-                                  (dev->iomem + (adr)), (src), (count))
-#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \
-                                  (dev->iomem + (adr)), (count))
+#define ngcpyto(adr, src, count)   memcpy_toio(dev->iomem + (adr), (src), (count))
+#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), dev->iomem + (adr), (count))
 
 /****************************************************************************/
 /* nGene interrupt handler **************************************************/
@@ -1592,7 +1590,7 @@ static void cxd_detach(struct ngene *dev)
 
        dvb_ca_en50221_release(ci->en);
        kfree(ci->en);
-       ci->en = 0;
+       ci->en = NULL;
 }
 
 /***********************************/
index fcb16a615aab002768f80b3e7d6c5cf66ac5f123..59bb2858c8d0127c8779f3323b8f1d1a25b832e2 100644 (file)
@@ -47,7 +47,7 @@
 /* COMMAND API interface ****************************************************/
 /****************************************************************************/
 
-static ssize_t ts_write(struct file *file, const char *buf,
+static ssize_t ts_write(struct file *file, const char __user *buf,
                        size_t count, loff_t *ppos)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -59,12 +59,12 @@ static ssize_t ts_write(struct file *file, const char *buf,
                                     (&dev->tsout_rbuf) >= count) < 0)
                return 0;
 
-       dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count);
+       dvb_ringbuffer_write_user(&dev->tsout_rbuf, buf, count);
 
        return count;
 }
 
-static ssize_t ts_read(struct file *file, char *buf,
+static ssize_t ts_read(struct file *file, char __user *buf,
                       size_t count, loff_t *ppos)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -97,7 +97,6 @@ static const struct file_operations ci_fops = {
 };
 
 struct dvb_device ngene_dvbdev_ci = {
-       .priv    = 0,
        .readers = -1,
        .writers = -1,
        .users   = -1,
index 22c39ff6bfa0e90c278d08c0cbc84d156c8e5732..51e2fbd18b1b1532cd3d7c1ef83c3b258c75219d 100644 (file)
@@ -737,7 +737,7 @@ typedef void (tx_cb_t)(struct ngene *, u32);
 struct ngene {
        int                   nr;
        struct pci_dev       *pci_dev;
-       unsigned char        *iomem;
+       unsigned char __iomem *iomem;
 
        /*struct i2c_adapter  i2c_adapter;*/
 
diff --git a/drivers/media/pci/pt3/Kconfig b/drivers/media/pci/pt3/Kconfig
new file mode 100644 (file)
index 0000000..16c208a
--- /dev/null
@@ -0,0 +1,10 @@
+config DVB_PT3
+       tristate "Earthsoft PT3 cards"
+       depends on DVB_CORE && PCI && I2C
+       select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_QM1D1C0042 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_MXL301RF if MEDIA_SUBDRV_AUTOSELECT
+       help
+         Support for Earthsoft PT3 PCIe cards.
+
+         Say Y or M if you own such a device and want to use it.
diff --git a/drivers/media/pci/pt3/Makefile b/drivers/media/pci/pt3/Makefile
new file mode 100644 (file)
index 0000000..396f146
--- /dev/null
@@ -0,0 +1,8 @@
+
+earth-pt3-objs += pt3.o pt3_i2c.o pt3_dma.o
+
+obj-$(CONFIG_DVB_PT3) += earth-pt3.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/tuners
diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c
new file mode 100644 (file)
index 0000000..1fdeac1
--- /dev/null
@@ -0,0 +1,876 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@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.
+ */
+
+#include <linux/freezer.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
+#include "pt3.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static bool one_adapter;
+module_param(one_adapter, bool, 0444);
+MODULE_PARM_DESC(one_adapter, "Place FE's together under one adapter.");
+
+static int num_bufs = 4;
+module_param(num_bufs, int, 0444);
+MODULE_PARM_DESC(num_bufs, "Number of DMA buffer (188KiB) per FE.");
+
+
+static const struct i2c_algorithm pt3_i2c_algo = {
+       .master_xfer   = &pt3_i2c_master_xfer,
+       .functionality = &pt3_i2c_functionality,
+};
+
+static const struct pt3_adap_config adap_conf[PT3_NUM_FE] = {
+       {
+               .demod_info = {
+                       I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x11),
+               },
+               .tuner_info = {
+                       I2C_BOARD_INFO("qm1d1c0042", 0x63),
+               },
+               .tuner_cfg.qm1d1c0042 = {
+                       .lpf = 1,
+               },
+               .init_freq = 1049480 - 300,
+       },
+       {
+               .demod_info = {
+                       I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x10),
+               },
+               .tuner_info = {
+                       I2C_BOARD_INFO("mxl301rf", 0x62),
+               },
+               .init_freq = 515142857,
+       },
+       {
+               .demod_info = {
+                       I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x13),
+               },
+               .tuner_info = {
+                       I2C_BOARD_INFO("qm1d1c0042", 0x60),
+               },
+               .tuner_cfg.qm1d1c0042 = {
+                       .lpf = 1,
+               },
+               .init_freq = 1049480 + 300,
+       },
+       {
+               .demod_info = {
+                       I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x12),
+               },
+               .tuner_info = {
+                       I2C_BOARD_INFO("mxl301rf", 0x61),
+               },
+               .init_freq = 521142857,
+       },
+};
+
+
+struct reg_val {
+       u8 reg;
+       u8 val;
+};
+
+static int
+pt3_demod_write(struct pt3_adapter *adap, const struct reg_val *data, int num)
+{
+       struct i2c_msg msg;
+       int i, ret;
+
+       ret = 0;
+       msg.addr = adap->i2c_demod->addr;
+       msg.flags = 0;
+       msg.len = 2;
+       for (i = 0; i < num; i++) {
+               msg.buf = (u8 *)&data[i];
+               ret = i2c_transfer(adap->i2c_demod->adapter, &msg, 1);
+               if (ret == 0)
+                       ret = -EREMOTE;
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static inline void pt3_lnb_ctrl(struct pt3_board *pt3, bool on)
+{
+       iowrite32((on ? 0x0f : 0x0c), pt3->regs[0] + REG_SYSTEM_W);
+}
+
+static inline struct pt3_adapter *pt3_find_adapter(struct dvb_frontend *fe)
+{
+       struct pt3_board *pt3;
+       int i;
+
+       if (one_adapter) {
+               pt3 = fe->dvb->priv;
+               for (i = 0; i < PT3_NUM_FE; i++)
+                       if (pt3->adaps[i]->fe == fe)
+                               return pt3->adaps[i];
+       }
+       return container_of(fe->dvb, struct pt3_adapter, dvb_adap);
+}
+
+/*
+ * all 4 tuners in PT3 are packaged in a can module (Sharp VA4M6JC2103).
+ * it seems that they share the power lines and Amp power line and
+ * adaps[3] controls those powers.
+ */
+static int
+pt3_set_tuner_power(struct pt3_board *pt3, bool tuner_on, bool amp_on)
+{
+       struct reg_val rv = { 0x1e, 0x99 };
+
+       if (tuner_on)
+               rv.val |= 0x40;
+       if (amp_on)
+               rv.val |= 0x04;
+       return pt3_demod_write(pt3->adaps[PT3_NUM_FE - 1], &rv, 1);
+}
+
+static int pt3_set_lna(struct dvb_frontend *fe)
+{
+       struct pt3_adapter *adap;
+       struct pt3_board *pt3;
+       u32 val;
+       int ret;
+
+       /* LNA is shared btw. 2 TERR-tuners */
+
+       adap = pt3_find_adapter(fe);
+       val = fe->dtv_property_cache.lna;
+       if (val == LNA_AUTO || val == adap->cur_lna)
+               return 0;
+
+       pt3 = adap->dvb_adap.priv;
+       if (mutex_lock_interruptible(&pt3->lock))
+               return -ERESTARTSYS;
+       if (val)
+               pt3->lna_on_cnt++;
+       else
+               pt3->lna_on_cnt--;
+
+       if (val && pt3->lna_on_cnt <= 1) {
+               pt3->lna_on_cnt = 1;
+               ret = pt3_set_tuner_power(pt3, true, true);
+       } else if (!val && pt3->lna_on_cnt <= 0) {
+               pt3->lna_on_cnt = 0;
+               ret = pt3_set_tuner_power(pt3, true, false);
+       } else
+               ret = 0;
+       mutex_unlock(&pt3->lock);
+       adap->cur_lna = (val != 0);
+       return ret;
+}
+
+static int pt3_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+       struct pt3_adapter *adap;
+       struct pt3_board *pt3;
+       bool on;
+
+       /* LNB power is shared btw. 2 SAT-tuners */
+
+       adap = pt3_find_adapter(fe);
+       on = (volt != SEC_VOLTAGE_OFF);
+       if (on == adap->cur_lnb)
+               return 0;
+       adap->cur_lnb = on;
+       pt3 = adap->dvb_adap.priv;
+       if (mutex_lock_interruptible(&pt3->lock))
+               return -ERESTARTSYS;
+       if (on)
+               pt3->lnb_on_cnt++;
+       else
+               pt3->lnb_on_cnt--;
+
+       if (on && pt3->lnb_on_cnt <= 1) {
+               pt3->lnb_on_cnt = 1;
+               pt3_lnb_ctrl(pt3, true);
+       } else if (!on && pt3->lnb_on_cnt <= 0) {
+               pt3->lnb_on_cnt = 0;
+               pt3_lnb_ctrl(pt3, false);
+       }
+       mutex_unlock(&pt3->lock);
+       return 0;
+}
+
+/* register values used in pt3_fe_init() */
+
+static const struct reg_val init0_sat[] = {
+       { 0x03, 0x01 },
+       { 0x1e, 0x10 },
+};
+static const struct reg_val init0_ter[] = {
+       { 0x01, 0x40 },
+       { 0x1c, 0x10 },
+};
+static const struct reg_val cfg_sat[] = {
+       { 0x1c, 0x15 },
+       { 0x1f, 0x04 },
+};
+static const struct reg_val cfg_ter[] = {
+       { 0x1d, 0x01 },
+};
+
+/*
+ * pt3_fe_init: initialize demod sub modules and ISDB-T tuners all at once.
+ *
+ * As for demod IC (TC90522) and ISDB-T tuners (MxL301RF),
+ * the i2c sequences for init'ing them are not public and hidden in a ROM,
+ * and include the board specific configurations as well.
+ * They are stored in a lump and cannot be taken out / accessed separately,
+ * thus cannot be moved to the FE/tuner driver.
+ */
+static int pt3_fe_init(struct pt3_board *pt3)
+{
+       int i, ret;
+       struct dvb_frontend *fe;
+
+       pt3_i2c_reset(pt3);
+       ret = pt3_init_all_demods(pt3);
+       if (ret < 0) {
+               dev_warn(&pt3->pdev->dev, "Failed to init demod chips.");
+               return ret;
+       }
+
+       /* additional config? */
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               fe = pt3->adaps[i]->fe;
+
+               if (fe->ops.delsys[0] == SYS_ISDBS)
+                       ret = pt3_demod_write(pt3->adaps[i],
+                                             init0_sat, ARRAY_SIZE(init0_sat));
+               else
+                       ret = pt3_demod_write(pt3->adaps[i],
+                                             init0_ter, ARRAY_SIZE(init0_ter));
+               if (ret < 0) {
+                       dev_warn(&pt3->pdev->dev,
+                                "demod[%d] faild in init sequence0.", i);
+                       return ret;
+               }
+               ret = fe->ops.init(fe);
+               if (ret < 0)
+                       return ret;
+       }
+
+       usleep_range(2000, 4000);
+       ret = pt3_set_tuner_power(pt3, true, false);
+       if (ret < 0) {
+               dev_warn(&pt3->pdev->dev, "Failed to control tuner module.");
+               return ret;
+       }
+
+       /* output pin configuration */
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               fe = pt3->adaps[i]->fe;
+               if (fe->ops.delsys[0] == SYS_ISDBS)
+                       ret = pt3_demod_write(pt3->adaps[i],
+                                               cfg_sat, ARRAY_SIZE(cfg_sat));
+               else
+                       ret = pt3_demod_write(pt3->adaps[i],
+                                               cfg_ter, ARRAY_SIZE(cfg_ter));
+               if (ret < 0) {
+                       dev_warn(&pt3->pdev->dev,
+                                "demod[%d] faild in init sequence1.", i);
+                       return ret;
+               }
+       }
+       usleep_range(4000, 6000);
+
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               fe = pt3->adaps[i]->fe;
+               if (fe->ops.delsys[0] != SYS_ISDBS)
+                       continue;
+               /* init and wake-up ISDB-S tuners */
+               ret = fe->ops.tuner_ops.init(fe);
+               if (ret < 0) {
+                       dev_warn(&pt3->pdev->dev,
+                                "Failed to init SAT-tuner[%d].", i);
+                       return ret;
+               }
+       }
+       ret = pt3_init_all_mxl301rf(pt3);
+       if (ret < 0) {
+               dev_warn(&pt3->pdev->dev, "Failed to init TERR-tuners.");
+               return ret;
+       }
+
+       ret = pt3_set_tuner_power(pt3, true, true);
+       if (ret < 0) {
+               dev_warn(&pt3->pdev->dev, "Failed to control tuner module.");
+               return ret;
+       }
+
+       /* Wake up all tuners and make an initial tuning,
+        * in order to avoid interference among the tuners in the module,
+        * according to the doc from the manufacturer.
+        */
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               fe = pt3->adaps[i]->fe;
+               ret = 0;
+               if (fe->ops.delsys[0] == SYS_ISDBT)
+                       ret = fe->ops.tuner_ops.init(fe);
+               /* set only when called from pt3_probe(), not resume() */
+               if (ret == 0 && fe->dtv_property_cache.frequency == 0) {
+                       fe->dtv_property_cache.frequency =
+                                               adap_conf[i].init_freq;
+                       ret = fe->ops.tuner_ops.set_params(fe);
+               }
+               if (ret < 0) {
+                       dev_warn(&pt3->pdev->dev,
+                                "Failed in initial tuning of tuner[%d].", i);
+                       return ret;
+               }
+       }
+
+       /* and sleep again, waiting to be opened by users. */
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               fe = pt3->adaps[i]->fe;
+               if (fe->ops.tuner_ops.sleep)
+                       ret = fe->ops.tuner_ops.sleep(fe);
+               if (ret < 0)
+                       break;
+               if (fe->ops.sleep)
+                       ret = fe->ops.sleep(fe);
+               if (ret < 0)
+                       break;
+               if (fe->ops.delsys[0] == SYS_ISDBS)
+                       fe->ops.set_voltage = &pt3_set_voltage;
+               else
+                       fe->ops.set_lna = &pt3_set_lna;
+       }
+       if (i < PT3_NUM_FE) {
+               dev_warn(&pt3->pdev->dev, "FE[%d] failed to standby.", i);
+               return ret;
+       }
+       return 0;
+}
+
+
+static int pt3_attach_fe(struct pt3_board *pt3, int i)
+{
+       struct i2c_board_info info;
+       struct tc90522_config cfg;
+       struct i2c_client *cl;
+       struct dvb_adapter *dvb_adap;
+       int ret;
+
+       info = adap_conf[i].demod_info;
+       cfg = adap_conf[i].demod_cfg;
+       cfg.tuner_i2c = NULL;
+       info.platform_data = &cfg;
+
+       ret = -ENODEV;
+       request_module("tc90522");
+       cl = i2c_new_device(&pt3->i2c_adap, &info);
+       if (!cl || !cl->dev.driver)
+               return -ENODEV;
+       pt3->adaps[i]->i2c_demod = cl;
+       if (!try_module_get(cl->dev.driver->owner))
+               goto err_demod_i2c_unregister_device;
+
+       if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, sizeof(cl->name))) {
+               struct qm1d1c0042_config tcfg;
+
+               tcfg = adap_conf[i].tuner_cfg.qm1d1c0042;
+               tcfg.fe = cfg.fe;
+               info = adap_conf[i].tuner_info;
+               info.platform_data = &tcfg;
+               request_module("qm1d1c0042");
+               cl = i2c_new_device(cfg.tuner_i2c, &info);
+       } else {
+               struct mxl301rf_config tcfg;
+
+               tcfg = adap_conf[i].tuner_cfg.mxl301rf;
+               tcfg.fe = cfg.fe;
+               info = adap_conf[i].tuner_info;
+               info.platform_data = &tcfg;
+               request_module("mxl301rf");
+               cl = i2c_new_device(cfg.tuner_i2c, &info);
+       }
+       if (!cl || !cl->dev.driver)
+               goto err_demod_module_put;
+       pt3->adaps[i]->i2c_tuner = cl;
+       if (!try_module_get(cl->dev.driver->owner))
+               goto err_tuner_i2c_unregister_device;
+
+       dvb_adap = &pt3->adaps[one_adapter ? 0 : i]->dvb_adap;
+       ret = dvb_register_frontend(dvb_adap, cfg.fe);
+       if (ret < 0)
+               goto err_tuner_module_put;
+       pt3->adaps[i]->fe = cfg.fe;
+       return 0;
+
+err_tuner_module_put:
+       module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner);
+err_tuner_i2c_unregister_device:
+       i2c_unregister_device(pt3->adaps[i]->i2c_tuner);
+err_demod_module_put:
+       module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner);
+err_demod_i2c_unregister_device:
+       i2c_unregister_device(pt3->adaps[i]->i2c_demod);
+
+       return ret;
+}
+
+
+static int pt3_fetch_thread(void *data)
+{
+       struct pt3_adapter *adap = data;
+       ktime_t delay;
+       bool was_frozen;
+
+#define PT3_INITIAL_BUF_DROPS 4
+#define PT3_FETCH_DELAY 10
+#define PT3_FETCH_DELAY_DELTA 2
+
+       pt3_init_dmabuf(adap);
+       adap->num_discard = PT3_INITIAL_BUF_DROPS;
+
+       dev_dbg(adap->dvb_adap.device,
+               "PT3: [%s] started.\n", adap->thread->comm);
+       set_freezable();
+       while (!kthread_freezable_should_stop(&was_frozen)) {
+               if (was_frozen)
+                       adap->num_discard = PT3_INITIAL_BUF_DROPS;
+
+               pt3_proc_dma(adap);
+
+               delay = ktime_set(0, PT3_FETCH_DELAY * NSEC_PER_MSEC);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               freezable_schedule_hrtimeout_range(&delay,
+                                       PT3_FETCH_DELAY_DELTA * NSEC_PER_MSEC,
+                                       HRTIMER_MODE_REL);
+       }
+       dev_dbg(adap->dvb_adap.device,
+               "PT3: [%s] exited.\n", adap->thread->comm);
+       adap->thread = NULL;
+       return 0;
+}
+
+static int pt3_start_streaming(struct pt3_adapter *adap)
+{
+       struct task_struct *thread;
+
+       /* start fetching thread */
+       thread = kthread_run(pt3_fetch_thread, adap, "pt3-ad%i-dmx%i",
+                               adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+       if (IS_ERR(thread)) {
+               int ret = PTR_ERR(thread);
+
+               dev_warn(adap->dvb_adap.device,
+                       "PT3 (adap:%d, dmx:%d): failed to start kthread.\n",
+                       adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+               return ret;
+       }
+       adap->thread = thread;
+
+       return pt3_start_dma(adap);
+}
+
+static int pt3_stop_streaming(struct pt3_adapter *adap)
+{
+       int ret;
+
+       ret = pt3_stop_dma(adap);
+       if (ret)
+               dev_warn(adap->dvb_adap.device,
+                       "PT3: failed to stop streaming of adap:%d/FE:%d\n",
+                       adap->dvb_adap.num, adap->fe->id);
+
+       /* kill the fetching thread */
+       ret = kthread_stop(adap->thread);
+       return ret;
+}
+
+static int pt3_start_feed(struct dvb_demux_feed *feed)
+{
+       struct pt3_adapter *adap;
+
+       if (signal_pending(current))
+               return -EINTR;
+
+       adap = container_of(feed->demux, struct pt3_adapter, demux);
+       adap->num_feeds++;
+       if (adap->thread)
+               return 0;
+       if (adap->num_feeds != 1) {
+               dev_warn(adap->dvb_adap.device,
+                       "%s: unmatched start/stop_feed in adap:%i/dmx:%i.\n",
+                       __func__, adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+               adap->num_feeds = 1;
+       }
+
+       return pt3_start_streaming(adap);
+
+}
+
+static int pt3_stop_feed(struct dvb_demux_feed *feed)
+{
+       struct pt3_adapter *adap;
+
+       adap = container_of(feed->demux, struct pt3_adapter, demux);
+
+       adap->num_feeds--;
+       if (adap->num_feeds > 0 || !adap->thread)
+               return 0;
+       adap->num_feeds = 0;
+
+       return pt3_stop_streaming(adap);
+}
+
+
+static int pt3_alloc_adapter(struct pt3_board *pt3, int index)
+{
+       int ret;
+       struct pt3_adapter *adap;
+       struct dvb_adapter *da;
+
+       adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+       if (!adap) {
+               dev_err(&pt3->pdev->dev, "failed to alloc mem for adapter.\n");
+               return -ENOMEM;
+       }
+       pt3->adaps[index] = adap;
+       adap->adap_idx = index;
+
+       if (index == 0 || !one_adapter) {
+               ret = dvb_register_adapter(&adap->dvb_adap, "PT3 DVB",
+                               THIS_MODULE, &pt3->pdev->dev, adapter_nr);
+               if (ret < 0) {
+                       dev_err(&pt3->pdev->dev,
+                               "failed to register adapter dev.\n");
+                       goto err_mem;
+               }
+               da = &adap->dvb_adap;
+       } else
+               da = &pt3->adaps[0]->dvb_adap;
+
+       adap->dvb_adap.priv = pt3;
+       adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+       adap->demux.priv = adap;
+       adap->demux.feednum = 256;
+       adap->demux.filternum = 256;
+       adap->demux.start_feed = pt3_start_feed;
+       adap->demux.stop_feed = pt3_stop_feed;
+       ret = dvb_dmx_init(&adap->demux);
+       if (ret < 0) {
+               dev_err(&pt3->pdev->dev, "failed to init dmx dev.\n");
+               goto err_adap;
+       }
+
+       adap->dmxdev.filternum = 256;
+       adap->dmxdev.demux = &adap->demux.dmx;
+       ret = dvb_dmxdev_init(&adap->dmxdev, da);
+       if (ret < 0) {
+               dev_err(&pt3->pdev->dev, "failed to init dmxdev.\n");
+               goto err_demux;
+       }
+
+       ret = pt3_alloc_dmabuf(adap);
+       if (ret) {
+               dev_err(&pt3->pdev->dev, "failed to alloc DMA buffers.\n");
+               goto err_dmabuf;
+       }
+
+       return 0;
+
+err_dmabuf:
+       pt3_free_dmabuf(adap);
+       dvb_dmxdev_release(&adap->dmxdev);
+err_demux:
+       dvb_dmx_release(&adap->demux);
+err_adap:
+       if (index == 0 || !one_adapter)
+               dvb_unregister_adapter(da);
+err_mem:
+       kfree(adap);
+       pt3->adaps[index] = NULL;
+       return ret;
+}
+
+static void pt3_cleanup_adapter(struct pt3_board *pt3, int index)
+{
+       struct pt3_adapter *adap;
+       struct dmx_demux *dmx;
+
+       adap = pt3->adaps[index];
+       if (adap == NULL)
+               return;
+
+       /* stop demux kthread */
+       if (adap->thread)
+               pt3_stop_streaming(adap);
+
+       dmx = &adap->demux.dmx;
+       dmx->close(dmx);
+       if (adap->fe) {
+               adap->fe->callback = NULL;
+               if (adap->fe->frontend_priv)
+                       dvb_unregister_frontend(adap->fe);
+               if (adap->i2c_tuner) {
+                       module_put(adap->i2c_tuner->dev.driver->owner);
+                       i2c_unregister_device(adap->i2c_tuner);
+               }
+               if (adap->i2c_demod) {
+                       module_put(adap->i2c_demod->dev.driver->owner);
+                       i2c_unregister_device(adap->i2c_demod);
+               }
+       }
+       pt3_free_dmabuf(adap);
+       dvb_dmxdev_release(&adap->dmxdev);
+       dvb_dmx_release(&adap->demux);
+       if (index == 0 || !one_adapter)
+               dvb_unregister_adapter(&adap->dvb_adap);
+       kfree(adap);
+       pt3->adaps[index] = NULL;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int pt3_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct pt3_board *pt3 = pci_get_drvdata(pdev);
+       int i;
+       struct pt3_adapter *adap;
+
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               adap = pt3->adaps[i];
+               if (adap->num_feeds > 0)
+                       pt3_stop_dma(adap);
+               dvb_frontend_suspend(adap->fe);
+               pt3_free_dmabuf(adap);
+       }
+
+       pt3_lnb_ctrl(pt3, false);
+       pt3_set_tuner_power(pt3, false, false);
+       return 0;
+}
+
+static int pt3_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct pt3_board *pt3 = pci_get_drvdata(pdev);
+       int i, ret;
+       struct pt3_adapter *adap;
+
+       ret = pt3_fe_init(pt3);
+       if (ret)
+               return ret;
+
+       if (pt3->lna_on_cnt > 0)
+               pt3_set_tuner_power(pt3, true, true);
+       if (pt3->lnb_on_cnt > 0)
+               pt3_lnb_ctrl(pt3, true);
+
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               adap = pt3->adaps[i];
+               dvb_frontend_resume(adap->fe);
+               ret = pt3_alloc_dmabuf(adap);
+               if (ret) {
+                       dev_err(&pt3->pdev->dev, "failed to alloc DMA bufs.\n");
+                       continue;
+               }
+               if (adap->num_feeds > 0)
+                       pt3_start_dma(adap);
+       }
+
+       return 0;
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
+
+static void pt3_remove(struct pci_dev *pdev)
+{
+       struct pt3_board *pt3;
+       int i;
+
+       pt3 = pci_get_drvdata(pdev);
+       for (i = PT3_NUM_FE - 1; i >= 0; i--)
+               pt3_cleanup_adapter(pt3, i);
+       i2c_del_adapter(&pt3->i2c_adap);
+       kfree(pt3->i2c_buf);
+       pci_iounmap(pt3->pdev, pt3->regs[0]);
+       pci_iounmap(pt3->pdev, pt3->regs[1]);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       kfree(pt3);
+}
+
+static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       u8 rev;
+       u32 ver;
+       int i, ret;
+       struct pt3_board *pt3;
+       struct i2c_adapter *i2c;
+
+       if (pci_read_config_byte(pdev, PCI_REVISION_ID, &rev) || rev != 1)
+               return -ENODEV;
+
+       ret = pci_enable_device(pdev);
+       if (ret < 0)
+               return -ENODEV;
+       pci_set_master(pdev);
+
+       ret = pci_request_regions(pdev, DRV_NAME);
+       if (ret < 0)
+               goto err_disable_device;
+
+       ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+       if (ret == 0)
+               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+       else {
+               ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+               if (ret == 0)
+                       dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+               else {
+                       dev_err(&pdev->dev, "Failed to set DMA mask.\n");
+                       goto err_release_regions;
+               }
+               dev_info(&pdev->dev, "Use 32bit DMA.\n");
+       }
+
+       pt3 = kzalloc(sizeof(*pt3), GFP_KERNEL);
+       if (!pt3) {
+               dev_err(&pdev->dev, "Failed to alloc mem for this dev.\n");
+               ret = -ENOMEM;
+               goto err_release_regions;
+       }
+       pci_set_drvdata(pdev, pt3);
+       pt3->pdev = pdev;
+       mutex_init(&pt3->lock);
+       pt3->regs[0] = pci_ioremap_bar(pdev, 0);
+       pt3->regs[1] = pci_ioremap_bar(pdev, 2);
+       if (pt3->regs[0] == NULL || pt3->regs[1] == NULL) {
+               dev_err(&pdev->dev, "Failed to ioremap.\n");
+               ret = -ENOMEM;
+               goto err_kfree;
+       }
+
+       ver = ioread32(pt3->regs[0] + REG_VERSION);
+       if ((ver >> 16) != 0x0301) {
+               dev_warn(&pdev->dev, "PT%d, I/F-ver.:%d not supported",
+                       ver >> 24, (ver & 0x00ff0000) >> 16);
+               ret = -ENODEV;
+               goto err_iounmap;
+       }
+
+       pt3->num_bufs = clamp_val(num_bufs, MIN_DATA_BUFS, MAX_DATA_BUFS);
+
+       pt3->i2c_buf = kmalloc(sizeof(*pt3->i2c_buf), GFP_KERNEL);
+       if (pt3->i2c_buf == NULL) {
+               dev_err(&pdev->dev, "Failed to alloc mem for i2c.\n");
+               ret = -ENOMEM;
+               goto err_iounmap;
+       }
+       i2c = &pt3->i2c_adap;
+       i2c->owner = THIS_MODULE;
+       i2c->algo = &pt3_i2c_algo;
+       i2c->algo_data = NULL;
+       i2c->dev.parent = &pdev->dev;
+       strlcpy(i2c->name, DRV_NAME, sizeof(i2c->name));
+       i2c_set_adapdata(i2c, pt3);
+       ret = i2c_add_adapter(i2c);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to add i2c adapter.\n");
+               goto err_i2cbuf;
+       }
+
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               ret = pt3_alloc_adapter(pt3, i);
+               if (ret < 0)
+                       break;
+
+               ret = pt3_attach_fe(pt3, i);
+               if (ret < 0)
+                       break;
+       }
+       if (i < PT3_NUM_FE) {
+               dev_err(&pdev->dev, "Failed to create FE%d.\n", i);
+               goto err_cleanup_adapters;
+       }
+
+       ret = pt3_fe_init(pt3);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to init frontends.\n");
+               i = PT3_NUM_FE - 1;
+               goto err_cleanup_adapters;
+       }
+
+       dev_info(&pdev->dev,
+               "successfully init'ed PT%d (fw:0x%02x, I/F:0x%02x).\n",
+               ver >> 24, (ver >> 8) & 0xff, (ver >> 16) & 0xff);
+       return 0;
+
+err_cleanup_adapters:
+       while (i >= 0)
+               pt3_cleanup_adapter(pt3, i--);
+       i2c_del_adapter(i2c);
+err_i2cbuf:
+       kfree(pt3->i2c_buf);
+err_iounmap:
+       if (pt3->regs[0])
+               pci_iounmap(pdev, pt3->regs[0]);
+       if (pt3->regs[1])
+               pci_iounmap(pdev, pt3->regs[1]);
+err_kfree:
+       kfree(pt3);
+err_release_regions:
+       pci_release_regions(pdev);
+err_disable_device:
+       pci_disable_device(pdev);
+       return ret;
+
+}
+
+static const struct pci_device_id pt3_id_table[] = {
+       { PCI_DEVICE_SUB(0x1172, 0x4c15, 0xee8d, 0x0368) },
+       { },
+};
+MODULE_DEVICE_TABLE(pci, pt3_id_table);
+
+static SIMPLE_DEV_PM_OPS(pt3_pm_ops, pt3_suspend, pt3_resume);
+
+static struct pci_driver pt3_driver = {
+       .name           = DRV_NAME,
+       .probe          = pt3_probe,
+       .remove         = pt3_remove,
+       .id_table       = pt3_id_table,
+
+       .driver.pm      = &pt3_pm_ops,
+};
+
+module_pci_driver(pt3_driver);
+
+MODULE_DESCRIPTION("Earthsoft PT3 Driver");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/pt3/pt3.h b/drivers/media/pci/pt3/pt3.h
new file mode 100644 (file)
index 0000000..1b3f2ad
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@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.
+ */
+
+#ifndef PT3_H
+#define PT3_H
+
+#include <linux/atomic.h>
+#include <linux/types.h>
+
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dmxdev.h"
+
+#include "tc90522.h"
+#include "mxl301rf.h"
+#include "qm1d1c0042.h"
+
+#define DRV_NAME KBUILD_MODNAME
+
+#define PT3_NUM_FE 4
+
+/*
+ * register index of the FPGA chip
+ */
+#define REG_VERSION    0x00
+#define REG_BUS                0x04
+#define REG_SYSTEM_W   0x08
+#define REG_SYSTEM_R   0x0c
+#define REG_I2C_W      0x10
+#define REG_I2C_R      0x14
+#define REG_RAM_W      0x18
+#define REG_RAM_R      0x1c
+#define REG_DMA_BASE   0x40    /* regs for FE[i] = REG_DMA_BASE + 0x18 * i */
+#define OFST_DMA_DESC_L        0x00
+#define OFST_DMA_DESC_H        0x04
+#define OFST_DMA_CTL   0x08
+#define OFST_TS_CTL    0x0c
+#define OFST_STATUS    0x10
+#define OFST_TS_ERR    0x14
+
+/*
+ * internal buffer for I2C
+ */
+#define PT3_I2C_MAX 4091
+struct pt3_i2cbuf {
+       u8  data[PT3_I2C_MAX];
+       u8  tmp;
+       u32 num_cmds;
+};
+
+/*
+ * DMA things
+ */
+#define TS_PACKET_SZ  188
+/* DMA transfers must not cross 4GiB, so use one page / transfer */
+#define DATA_XFER_SZ   4096
+#define DATA_BUF_XFERS 47
+/* (num_bufs * DATA_BUF_SZ) % TS_PACKET_SZ must be 0 */
+#define DATA_BUF_SZ    (DATA_BUF_XFERS * DATA_XFER_SZ)
+#define MAX_DATA_BUFS  16
+#define MIN_DATA_BUFS   2
+
+#define DESCS_IN_PAGE (PAGE_SIZE / sizeof(struct xfer_desc))
+#define MAX_NUM_XFERS (MAX_DATA_BUFS * DATA_BUF_XFERS)
+#define MAX_DESC_BUFS DIV_ROUND_UP(MAX_NUM_XFERS, DESCS_IN_PAGE)
+
+/* DMA transfer description.
+ * device is passed a pointer to this struct, dma-reads it,
+ * and gets the DMA buffer ring for storing TS data.
+ */
+struct xfer_desc {
+       u32 addr_l; /* bus address of target data buffer */
+       u32 addr_h;
+       u32 size;
+       u32 next_l; /* bus adddress of the next xfer_desc */
+       u32 next_h;
+};
+
+/* A DMA mapping of a page containing xfer_desc's */
+struct xfer_desc_buffer {
+       dma_addr_t b_addr;
+       struct xfer_desc *descs; /* PAGE_SIZE (xfer_desc[DESCS_IN_PAGE]) */
+};
+
+/* A DMA mapping of a data buffer */
+struct dma_data_buffer {
+       dma_addr_t b_addr;
+       u8 *data; /* size: u8[PAGE_SIZE] */
+};
+
+/*
+ * device things
+ */
+struct pt3_adap_config {
+       struct i2c_board_info demod_info;
+       struct tc90522_config demod_cfg;
+
+       struct i2c_board_info tuner_info;
+       union tuner_config {
+               struct qm1d1c0042_config qm1d1c0042;
+               struct mxl301rf_config   mxl301rf;
+       } tuner_cfg;
+       u32 init_freq;
+};
+
+struct pt3_adapter {
+       struct dvb_adapter  dvb_adap;  /* dvb_adap.priv => struct pt3_board */
+       int adap_idx;
+
+       struct dvb_demux    demux;
+       struct dmxdev       dmxdev;
+       struct dvb_frontend *fe;
+       struct i2c_client   *i2c_demod;
+       struct i2c_client   *i2c_tuner;
+
+       /* data fetch thread */
+       struct task_struct *thread;
+       int num_feeds;
+
+       bool cur_lna;
+       bool cur_lnb; /* current LNB power status (on/off) */
+
+       /* items below are for DMA */
+       struct dma_data_buffer buffer[MAX_DATA_BUFS];
+       int buf_idx;
+       int buf_ofs;
+       int num_bufs;  /* == pt3_board->num_bufs */
+       int num_discard; /* how many access units to discard initially */
+
+       struct xfer_desc_buffer desc_buf[MAX_DESC_BUFS];
+       int num_desc_bufs;  /* == num_bufs * DATA_BUF_XFERS / DESCS_IN_PAGE */
+};
+
+
+struct pt3_board {
+       struct pci_dev *pdev;
+       void __iomem *regs[2];
+       /* regs[0]: registers, regs[1]: internal memory, used for I2C */
+
+       struct mutex lock;
+
+       /* LNB power shared among sat-FEs */
+       int lnb_on_cnt; /* LNB power on count */
+
+       /* LNA shared among terr-FEs */
+       int lna_on_cnt; /* booster enabled count */
+
+       int num_bufs;  /* number of DMA buffers allocated/mapped per FE */
+
+       struct i2c_adapter i2c_adap;
+       struct pt3_i2cbuf *i2c_buf;
+
+       struct pt3_adapter *adaps[PT3_NUM_FE];
+};
+
+
+/*
+ * prototypes
+ */
+extern int  pt3_alloc_dmabuf(struct pt3_adapter *adap);
+extern void pt3_init_dmabuf(struct pt3_adapter *adap);
+extern void pt3_free_dmabuf(struct pt3_adapter *adap);
+extern int  pt3_start_dma(struct pt3_adapter *adap);
+extern int  pt3_stop_dma(struct pt3_adapter *adap);
+extern int  pt3_proc_dma(struct pt3_adapter *adap);
+
+extern int  pt3_i2c_master_xfer(struct i2c_adapter *adap,
+                               struct i2c_msg *msgs, int num);
+extern u32  pt3_i2c_functionality(struct i2c_adapter *adap);
+extern void pt3_i2c_reset(struct pt3_board *pt3);
+extern int  pt3_init_all_demods(struct pt3_board *pt3);
+extern int  pt3_init_all_mxl301rf(struct pt3_board *pt3);
+#endif /* PT3_H */
diff --git a/drivers/media/pci/pt3/pt3_dma.c b/drivers/media/pci/pt3/pt3_dma.c
new file mode 100644 (file)
index 0000000..f0ce904
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@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.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include "pt3.h"
+
+#define PT3_ACCESS_UNIT (TS_PACKET_SZ * 128)
+#define PT3_BUF_CANARY  (0x74)
+
+static u32 get_dma_base(int idx)
+{
+       int i;
+
+       i = (idx == 1 || idx == 2) ? 3 - idx : idx;
+       return REG_DMA_BASE + 0x18 * i;
+}
+
+int pt3_stop_dma(struct pt3_adapter *adap)
+{
+       struct pt3_board *pt3 = adap->dvb_adap.priv;
+       u32 base;
+       u32 stat;
+       int retry;
+
+       base = get_dma_base(adap->adap_idx);
+       stat = ioread32(pt3->regs[0] + base + OFST_STATUS);
+       if (!(stat & 0x01))
+               return 0;
+
+       iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL);
+       for (retry = 0; retry < 5; retry++) {
+               stat = ioread32(pt3->regs[0] + base + OFST_STATUS);
+               if (!(stat & 0x01))
+                       return 0;
+               msleep(50);
+       }
+       return -EIO;
+}
+
+int pt3_start_dma(struct pt3_adapter *adap)
+{
+       struct pt3_board *pt3 = adap->dvb_adap.priv;
+       u32 base = get_dma_base(adap->adap_idx);
+
+       iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL);
+       iowrite32(lower_32_bits(adap->desc_buf[0].b_addr),
+                       pt3->regs[0] + base + OFST_DMA_DESC_L);
+       iowrite32(upper_32_bits(adap->desc_buf[0].b_addr),
+                       pt3->regs[0] + base + OFST_DMA_DESC_H);
+       iowrite32(0x01, pt3->regs[0] + base + OFST_DMA_CTL);
+       return 0;
+}
+
+
+static u8 *next_unit(struct pt3_adapter *adap, int *idx, int *ofs)
+{
+       *ofs += PT3_ACCESS_UNIT;
+       if (*ofs >= DATA_BUF_SZ) {
+               *ofs -= DATA_BUF_SZ;
+               (*idx)++;
+               if (*idx == adap->num_bufs)
+                       *idx = 0;
+       }
+       return &adap->buffer[*idx].data[*ofs];
+}
+
+int pt3_proc_dma(struct pt3_adapter *adap)
+{
+       int idx, ofs;
+
+       idx = adap->buf_idx;
+       ofs = adap->buf_ofs;
+
+       if (adap->buffer[idx].data[ofs] == PT3_BUF_CANARY)
+               return 0;
+
+       while (*next_unit(adap, &idx, &ofs) != PT3_BUF_CANARY) {
+               u8 *p;
+
+               p = &adap->buffer[adap->buf_idx].data[adap->buf_ofs];
+               if (adap->num_discard > 0)
+                       adap->num_discard--;
+               else if (adap->buf_ofs + PT3_ACCESS_UNIT > DATA_BUF_SZ) {
+                       dvb_dmx_swfilter_packets(&adap->demux, p,
+                               (DATA_BUF_SZ - adap->buf_ofs) / TS_PACKET_SZ);
+                       dvb_dmx_swfilter_packets(&adap->demux,
+                               adap->buffer[idx].data, ofs / TS_PACKET_SZ);
+               } else
+                       dvb_dmx_swfilter_packets(&adap->demux, p,
+                               PT3_ACCESS_UNIT / TS_PACKET_SZ);
+
+               *p = PT3_BUF_CANARY;
+               adap->buf_idx = idx;
+               adap->buf_ofs = ofs;
+       }
+       return 0;
+}
+
+void pt3_init_dmabuf(struct pt3_adapter *adap)
+{
+       int idx, ofs;
+       u8 *p;
+
+       idx = 0;
+       ofs = 0;
+       p = adap->buffer[0].data;
+       /* mark the whole buffers as "not written yet" */
+       while (idx < adap->num_bufs) {
+               p[ofs] = PT3_BUF_CANARY;
+               ofs += PT3_ACCESS_UNIT;
+               if (ofs >= DATA_BUF_SZ) {
+                       ofs -= DATA_BUF_SZ;
+                       idx++;
+                       p = adap->buffer[idx].data;
+               }
+       }
+       adap->buf_idx = 0;
+       adap->buf_ofs = 0;
+}
+
+void pt3_free_dmabuf(struct pt3_adapter *adap)
+{
+       struct pt3_board *pt3;
+       int i;
+
+       pt3 = adap->dvb_adap.priv;
+       for (i = 0; i < adap->num_bufs; i++)
+               dma_free_coherent(&pt3->pdev->dev, DATA_BUF_SZ,
+                       adap->buffer[i].data, adap->buffer[i].b_addr);
+       adap->num_bufs = 0;
+
+       for (i = 0; i < adap->num_desc_bufs; i++)
+               dma_free_coherent(&pt3->pdev->dev, PAGE_SIZE,
+                       adap->desc_buf[i].descs, adap->desc_buf[i].b_addr);
+       adap->num_desc_bufs = 0;
+}
+
+
+int pt3_alloc_dmabuf(struct pt3_adapter *adap)
+{
+       struct pt3_board *pt3;
+       void *p;
+       int i, j;
+       int idx, ofs;
+       int num_desc_bufs;
+       dma_addr_t data_addr, desc_addr;
+       struct xfer_desc *d;
+
+       pt3 = adap->dvb_adap.priv;
+       adap->num_bufs = 0;
+       adap->num_desc_bufs = 0;
+       for (i = 0; i < pt3->num_bufs; i++) {
+               p = dma_alloc_coherent(&pt3->pdev->dev, DATA_BUF_SZ,
+                                       &adap->buffer[i].b_addr, GFP_KERNEL);
+               if (p == NULL)
+                       goto failed;
+               adap->buffer[i].data = p;
+               adap->num_bufs++;
+       }
+       pt3_init_dmabuf(adap);
+
+       /* build circular-linked pointers (xfer_desc) to the data buffers*/
+       idx = 0;
+       ofs = 0;
+       num_desc_bufs =
+               DIV_ROUND_UP(adap->num_bufs * DATA_BUF_XFERS, DESCS_IN_PAGE);
+       for (i = 0; i < num_desc_bufs; i++) {
+               p = dma_alloc_coherent(&pt3->pdev->dev, PAGE_SIZE,
+                                       &desc_addr, GFP_KERNEL);
+               if (p == NULL)
+                       goto failed;
+               adap->num_desc_bufs++;
+               adap->desc_buf[i].descs = p;
+               adap->desc_buf[i].b_addr = desc_addr;
+
+               if (i > 0) {
+                       d = &adap->desc_buf[i - 1].descs[DESCS_IN_PAGE - 1];
+                       d->next_l = lower_32_bits(desc_addr);
+                       d->next_h = upper_32_bits(desc_addr);
+               }
+               for (j = 0; j < DESCS_IN_PAGE; j++) {
+                       data_addr = adap->buffer[idx].b_addr + ofs;
+                       d = &adap->desc_buf[i].descs[j];
+                       d->addr_l = lower_32_bits(data_addr);
+                       d->addr_h = upper_32_bits(data_addr);
+                       d->size = DATA_XFER_SZ;
+
+                       desc_addr += sizeof(struct xfer_desc);
+                       d->next_l = lower_32_bits(desc_addr);
+                       d->next_h = upper_32_bits(desc_addr);
+
+                       ofs += DATA_XFER_SZ;
+                       if (ofs >= DATA_BUF_SZ) {
+                               ofs -= DATA_BUF_SZ;
+                               idx++;
+                               if (idx >= adap->num_bufs) {
+                                       desc_addr = adap->desc_buf[0].b_addr;
+                                       d->next_l = lower_32_bits(desc_addr);
+                                       d->next_h = upper_32_bits(desc_addr);
+                                       return 0;
+                               }
+                       }
+               }
+       }
+       return 0;
+
+failed:
+       pt3_free_dmabuf(adap);
+       return -ENOMEM;
+}
diff --git a/drivers/media/pci/pt3/pt3_i2c.c b/drivers/media/pci/pt3/pt3_i2c.c
new file mode 100644 (file)
index 0000000..ec6a8a2
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@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.
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+
+#include "pt3.h"
+
+#define PT3_I2C_BASE  2048
+#define PT3_CMD_ADDR_NORMAL 0
+#define PT3_CMD_ADDR_INIT_DEMOD  4096
+#define PT3_CMD_ADDR_INIT_TUNER  (4096 + 2042)
+
+/* masks for I2C status register */
+#define STAT_SEQ_RUNNING 0x1
+#define STAT_SEQ_ERROR   0x6
+#define STAT_NO_SEQ      0x8
+
+#define PT3_I2C_RUN   (1 << 16)
+#define PT3_I2C_RESET (1 << 17)
+
+enum ctl_cmd {
+       I_END,
+       I_ADDRESS,
+       I_CLOCK_L,
+       I_CLOCK_H,
+       I_DATA_L,
+       I_DATA_H,
+       I_RESET,
+       I_SLEEP,
+       I_DATA_L_NOP  = 0x08,
+       I_DATA_H_NOP  = 0x0c,
+       I_DATA_H_READ = 0x0d,
+       I_DATA_H_ACK0 = 0x0e,
+       I_DATA_H_ACK1 = 0x0f,
+};
+
+
+static void cmdbuf_add(struct pt3_i2cbuf *cbuf, enum ctl_cmd cmd)
+{
+       int buf_idx;
+
+       if ((cbuf->num_cmds % 2) == 0)
+               cbuf->tmp = cmd;
+       else {
+               cbuf->tmp |= cmd << 4;
+               buf_idx = cbuf->num_cmds / 2;
+               if (buf_idx < ARRAY_SIZE(cbuf->data))
+                       cbuf->data[buf_idx] = cbuf->tmp;
+       }
+       cbuf->num_cmds++;
+}
+
+static void put_end(struct pt3_i2cbuf *cbuf)
+{
+       cmdbuf_add(cbuf, I_END);
+       if (cbuf->num_cmds % 2)
+               cmdbuf_add(cbuf, I_END);
+}
+
+static void put_start(struct pt3_i2cbuf *cbuf)
+{
+       cmdbuf_add(cbuf, I_DATA_H);
+       cmdbuf_add(cbuf, I_CLOCK_H);
+       cmdbuf_add(cbuf, I_DATA_L);
+       cmdbuf_add(cbuf, I_CLOCK_L);
+}
+
+static void put_byte_write(struct pt3_i2cbuf *cbuf, u8 val)
+{
+       u8 mask;
+
+       mask = 0x80;
+       for (mask = 0x80; mask > 0; mask >>= 1)
+               cmdbuf_add(cbuf, (val & mask) ? I_DATA_H_NOP : I_DATA_L_NOP);
+       cmdbuf_add(cbuf, I_DATA_H_ACK0);
+}
+
+static void put_byte_read(struct pt3_i2cbuf *cbuf, u32 size)
+{
+       int i, j;
+
+       for (i = 0; i < size; i++) {
+               for (j = 0; j < 8; j++)
+                       cmdbuf_add(cbuf, I_DATA_H_READ);
+               cmdbuf_add(cbuf, (i == size - 1) ? I_DATA_H_NOP : I_DATA_L_NOP);
+       }
+}
+
+static void put_stop(struct pt3_i2cbuf *cbuf)
+{
+       cmdbuf_add(cbuf, I_DATA_L);
+       cmdbuf_add(cbuf, I_CLOCK_H);
+       cmdbuf_add(cbuf, I_DATA_H);
+}
+
+
+/* translates msgs to internal commands for bit-banging */
+static void translate(struct pt3_i2cbuf *cbuf, struct i2c_msg *msgs, int num)
+{
+       int i, j;
+       bool rd;
+
+       cbuf->num_cmds = 0;
+       for (i = 0; i < num; i++) {
+               rd = !!(msgs[i].flags & I2C_M_RD);
+               put_start(cbuf);
+               put_byte_write(cbuf, msgs[i].addr << 1 | rd);
+               if (rd)
+                       put_byte_read(cbuf, msgs[i].len);
+               else
+                       for (j = 0; j < msgs[i].len; j++)
+                               put_byte_write(cbuf, msgs[i].buf[j]);
+       }
+       if (num > 0) {
+               put_stop(cbuf);
+               put_end(cbuf);
+       }
+}
+
+static int wait_i2c_result(struct pt3_board *pt3, u32 *result, int max_wait)
+{
+       int i;
+       u32 v;
+
+       for (i = 0; i < max_wait; i++) {
+               v = ioread32(pt3->regs[0] + REG_I2C_R);
+               if (!(v & STAT_SEQ_RUNNING))
+                       break;
+               usleep_range(500, 750);
+       }
+       if (i >= max_wait)
+               return -EIO;
+       if (result)
+               *result = v;
+       return 0;
+}
+
+/* send [pre-]translated i2c msgs stored at addr */
+static int send_i2c_cmd(struct pt3_board *pt3, u32 addr)
+{
+       u32 ret;
+
+       /* make sure that previous transactions had finished */
+       if (wait_i2c_result(pt3, NULL, 50)) {
+               dev_warn(&pt3->pdev->dev, "(%s) prev. transaction stalled\n",
+                               __func__);
+               return -EIO;
+       }
+
+       iowrite32(PT3_I2C_RUN | addr, pt3->regs[0] + REG_I2C_W);
+       usleep_range(200, 300);
+       /* wait for the current transaction to finish */
+       if (wait_i2c_result(pt3, &ret, 500) || (ret & STAT_SEQ_ERROR)) {
+               dev_warn(&pt3->pdev->dev, "(%s) failed.\n", __func__);
+               return -EIO;
+       }
+       return 0;
+}
+
+
+/* init commands for each demod are combined into one transaction
+ *  and hidden in ROM with the address PT3_CMD_ADDR_INIT_DEMOD.
+ */
+int  pt3_init_all_demods(struct pt3_board *pt3)
+{
+       ioread32(pt3->regs[0] + REG_I2C_R);
+       return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_DEMOD);
+}
+
+/* init commands for two ISDB-T tuners are hidden in ROM. */
+int  pt3_init_all_mxl301rf(struct pt3_board *pt3)
+{
+       usleep_range(1000, 2000);
+       return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_TUNER);
+}
+
+void pt3_i2c_reset(struct pt3_board *pt3)
+{
+       iowrite32(PT3_I2C_RESET, pt3->regs[0] + REG_I2C_W);
+}
+
+/*
+ * I2C algorithm
+ */
+int
+pt3_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+       struct pt3_board *pt3;
+       struct pt3_i2cbuf *cbuf;
+       int i;
+       void __iomem *p;
+
+       pt3 = i2c_get_adapdata(adap);
+       cbuf = pt3->i2c_buf;
+
+       for (i = 0; i < num; i++)
+               if (msgs[i].flags & I2C_M_RECV_LEN) {
+                       dev_warn(&pt3->pdev->dev,
+                               "(%s) I2C_M_RECV_LEN not supported.\n",
+                               __func__);
+                       return -EINVAL;
+               }
+
+       translate(cbuf, msgs, num);
+       memcpy_toio(pt3->regs[1] + PT3_I2C_BASE + PT3_CMD_ADDR_NORMAL / 2,
+                       cbuf->data, cbuf->num_cmds);
+
+       if (send_i2c_cmd(pt3, PT3_CMD_ADDR_NORMAL) < 0)
+               return -EIO;
+
+       p = pt3->regs[1] + PT3_I2C_BASE;
+       for (i = 0; i < num; i++)
+               if ((msgs[i].flags & I2C_M_RD) && msgs[i].len > 0) {
+                       memcpy_fromio(msgs[i].buf, p, msgs[i].len);
+                       p += msgs[i].len;
+               }
+
+       return num;
+}
+
+u32 pt3_i2c_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C;
+}
index 18ae75546302daf04f66c0d3d213046bb092b1d0..b44e0d70907e2d876facc467e42608fc7fcb5760 100644 (file)
@@ -63,3 +63,11 @@ config VIDEO_SAA7134_DVB
 
          To compile this driver as a module, choose M here: the
          module will be called saa7134-dvb.
+
+config VIDEO_SAA7134_GO7007
+       tristate "go7007 support for saa7134 based TV cards"
+       depends on VIDEO_SAA7134
+       depends on VIDEO_GO7007
+       ---help---
+         Enables saa7134 driver support for boards with go7007
+         MPEG encoder (WIS Voyager or compatible).
index 58de9b085689bc101b01b2641db9e8f91f5a1b1c..09c43da675883058a581c96da0fe031feb73aa1f 100644 (file)
@@ -5,6 +5,7 @@ saa7134-y +=    saa7134-video.o
 saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o
 
 obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o
+obj-$(CONFIG_VIDEO_SAA7134_GO7007) += saa7134-go7007.o
 
 obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
 
@@ -14,3 +15,4 @@ ccflags-y += -I$(srctree)/drivers/media/i2c
 ccflags-y += -I$(srctree)/drivers/media/tuners
 ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+ccflags-y += -I$(srctree)/drivers/media/usb/go7007
index 6e4bdb90aa92e63c13d0d00c5bba90b4b4f09325..3ca078057755bd9a9384ca5f3c4886e7e35345d6 100644 (file)
@@ -5827,6 +5827,29 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x0000800,
                },
        },
+       [SAA7134_BOARD_WIS_VOYAGER] = {
+               .name           = "WIS Voyager or compatible",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_GO7007,
+               .inputs         = { {
+                       .name = name_comp1,
+                       .vmux = 0,
+                       .amux = LINE2,
+               }, {
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 6,
+               .amux = LINE1,
+               } },
+       },
 
 };
 
@@ -7079,6 +7102,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
                .subdevice    = 0x2055, /* AverTV Satellite Hybrid+FM A706 */
                .driver_data  = SAA7134_BOARD_AVERMEDIA_A706,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1905, /* WIS */
+               .subdevice    = 0x7007,
+               .driver_data  = SAA7134_BOARD_WIS_VOYAGER,
        }, {
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
index 9ff03a69ced46f3bda31d10c7ac527c04064b68d..236ed725f933c141386d7f430747062a9ef7f473 100644 (file)
@@ -160,6 +160,8 @@ static void request_module_async(struct work_struct *work){
                request_module("saa7134-empress");
        if (card_is_dvb(dev))
                request_module("saa7134-dvb");
+       if (card_is_go7007(dev))
+               request_module("saa7134-go7007");
        if (alsa) {
                if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130)
                        request_module("saa7134-alsa");
@@ -563,8 +565,12 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id)
                        saa7134_irq_vbi_done(dev,status);
 
                if ((report & SAA7134_IRQ_REPORT_DONE_RA2) &&
-                   card_has_mpeg(dev))
-                       saa7134_irq_ts_done(dev,status);
+                   card_has_mpeg(dev)) {
+                       if (dev->mops->irq_ts_done != NULL)
+                               dev->mops->irq_ts_done(dev, status);
+                       else
+                               saa7134_irq_ts_done(dev, status);
+               }
 
                if (report & SAA7134_IRQ_REPORT_GPIO16) {
                        switch (dev->has_remote) {
diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c
new file mode 100644 (file)
index 0000000..54e650b
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <asm/byteorder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+#include "go7007-priv.h"
+
+/*#define GO7007_HPI_DEBUG*/
+
+enum hpi_address {
+       HPI_ADDR_VIDEO_BUFFER = 0xe4,
+       HPI_ADDR_INIT_BUFFER = 0xea,
+       HPI_ADDR_INTR_RET_VALUE = 0xee,
+       HPI_ADDR_INTR_RET_DATA = 0xec,
+       HPI_ADDR_INTR_STATUS = 0xf4,
+       HPI_ADDR_INTR_WR_PARAM = 0xf6,
+       HPI_ADDR_INTR_WR_INDEX = 0xf8,
+};
+
+enum gpio_command {
+       GPIO_COMMAND_RESET = 0x00, /* 000b */
+       GPIO_COMMAND_REQ1  = 0x04, /* 001b */
+       GPIO_COMMAND_WRITE = 0x20, /* 010b */
+       GPIO_COMMAND_REQ2  = 0x24, /* 011b */
+       GPIO_COMMAND_READ  = 0x80, /* 100b */
+       GPIO_COMMAND_VIDEO = 0x84, /* 101b */
+       GPIO_COMMAND_IDLE  = 0xA0, /* 110b */
+       GPIO_COMMAND_ADDR  = 0xA4, /* 111b */
+};
+
+struct saa7134_go7007 {
+       struct v4l2_subdev sd;
+       struct saa7134_dev *dev;
+       u8 *top;
+       u8 *bottom;
+       dma_addr_t top_dma;
+       dma_addr_t bottom_dma;
+};
+
+static inline struct saa7134_go7007 *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct saa7134_go7007, sd);
+}
+
+static const struct go7007_board_info board_voyager = {
+       .flags           = 0,
+       .sensor_flags    = GO7007_SENSOR_656 |
+                               GO7007_SENSOR_VALID_ENABLE |
+                               GO7007_SENSOR_TV |
+                               GO7007_SENSOR_VBI,
+       .audio_flags    = GO7007_AUDIO_I2S_MODE_1 |
+                               GO7007_AUDIO_WORD_16,
+       .audio_rate      = 48000,
+       .audio_bclk_div  = 8,
+       .audio_main_div  = 2,
+       .hpi_buffer_cap  = 7,
+       .num_inputs      = 1,
+       .inputs          = {
+               {
+                       .name           = "SAA7134",
+               },
+       },
+};
+
+/********************* Driver for GPIO HPI interface *********************/
+
+static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data)
+{
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+       /* Write HPI address */
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       /* Write low byte */
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       /* Write high byte */
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       return 0;
+}
+
+static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data)
+{
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+       /* Write HPI address */
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+       /* Read low byte */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       *data = saa_readb(SAA7134_GPIO_GPSTATUS0);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       /* Read high byte */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8;
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       return 0;
+}
+
+static int saa7134_go7007_interface_reset(struct go7007 *go)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+       u16 intr_val, intr_data;
+       int count = 20;
+
+       saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */
+       saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4);
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET);
+       msleep(1);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+       msleep(10);
+
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+       saa_readb(SAA7134_GPIO_GPSTATUS2);
+       /*pr_debug("status is %s\n", saa_readb(SAA7134_GPIO_GPSTATUS2) & 0x40 ? "OK" : "not OK"); */
+
+       /* enter command mode...(?) */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+
+       do {
+               saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+               saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+               saa_readb(SAA7134_GPIO_GPSTATUS2);
+               /*pr_info("gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */
+       } while (--count > 0);
+
+       /* Wait for an interrupt to indicate successful hardware reset */
+       if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
+                       (intr_val & ~0x1) != 0x55aa) {
+               pr_err("saa7134-go7007: unable to reset the GO7007\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+       int i;
+       u16 status_reg;
+
+#ifdef GO7007_HPI_DEBUG
+       pr_debug("saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data);
+#endif
+
+       for (i = 0; i < 100; ++i) {
+               gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+               if (!(status_reg & 0x0010))
+                       break;
+               msleep(10);
+       }
+       if (i == 100) {
+               pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n",
+                       status_reg);
+               return -1;
+       }
+       gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data);
+       gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr);
+
+       return 0;
+}
+
+static int saa7134_go7007_read_interrupt(struct go7007 *go)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+
+       /* XXX we need to wait if there is no interrupt available */
+       go->interrupt_available = 1;
+       gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value);
+       gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data);
+#ifdef GO7007_HPI_DEBUG
+       pr_debug("saa7134-go7007: ReadInterrupt: %04x %04x\n",
+                       go->interrupt_value, go->interrupt_data);
+#endif
+       return 0;
+}
+
+static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev,
+                                               unsigned long status)
+{
+       struct go7007 *go = video_get_drvdata(dev->empress_dev);
+       struct saa7134_go7007 *saa = go->hpi_context;
+
+       if (!vb2_is_streaming(&go->vidq))
+               return;
+       if (0 != (status & 0x000f0000))
+               pr_debug("saa7134-go7007: irq: lost %ld\n",
+                               (status >> 16) & 0x0f);
+       if (status & 0x100000) {
+               dma_sync_single_for_cpu(&dev->pci->dev,
+                                       saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+               go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE);
+               saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma);
+       } else {
+               dma_sync_single_for_cpu(&dev->pci->dev,
+                                       saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+               go7007_parse_video_stream(go, saa->top, PAGE_SIZE);
+               saa_writel(SAA7134_RS_BA1(5), saa->top_dma);
+       }
+}
+
+static int saa7134_go7007_stream_start(struct go7007 *go)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+
+       saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top),
+                       0, PAGE_SIZE, DMA_FROM_DEVICE);
+       if (dma_mapping_error(&dev->pci->dev, saa->top_dma))
+               return -ENOMEM;
+       saa->bottom_dma = dma_map_page(&dev->pci->dev,
+                       virt_to_page(saa->bottom),
+                       0, PAGE_SIZE, DMA_FROM_DEVICE);
+       if (dma_mapping_error(&dev->pci->dev, saa->bottom_dma)) {
+               dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+                               DMA_FROM_DEVICE);
+               return -ENOMEM;
+       }
+
+       saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000);
+       saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200);
+
+       /* Set HPI interface for video */
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+       /* Enable TS interface */
+       saa_writeb(SAA7134_TS_PARALLEL, 0xe6);
+
+       /* Reset TS interface */
+       saa_setb(SAA7134_TS_SERIAL1, 0x01);
+       saa_clearb(SAA7134_TS_SERIAL1, 0x01);
+
+       /* Set up transfer block size */
+       saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1);
+       saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1);
+       saa_writeb(SAA7134_TS_DMA1, 0);
+       saa_writeb(SAA7134_TS_DMA2, 0);
+
+       /* Enable video streaming mode */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO);
+
+       saa_writel(SAA7134_RS_BA1(5), saa->top_dma);
+       saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma);
+       saa_writel(SAA7134_RS_PITCH(5), 128);
+       saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX);
+
+       /* Enable TS FIFO */
+       saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+       /* Enable DMA IRQ */
+       saa_setl(SAA7134_IRQ1,
+                       SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+       return 0;
+}
+
+static int saa7134_go7007_stream_stop(struct go7007 *go)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev;
+
+       if (!saa)
+               return -EINVAL;
+       dev = saa->dev;
+       if (!dev)
+               return -EINVAL;
+
+       /* Shut down TS FIFO */
+       saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+       /* Disable DMA IRQ */
+       saa_clearl(SAA7134_IRQ1,
+                       SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+       /* Disable TS interface */
+       saa_clearb(SAA7134_TS_PARALLEL, 0x80);
+
+       dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+                       DMA_FROM_DEVICE);
+       dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE,
+                       DMA_FROM_DEVICE);
+
+       return 0;
+}
+
+static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+       u16 status_reg;
+       int i;
+
+#ifdef GO7007_HPI_DEBUG
+       pr_debug("saa7134-go7007: DownloadBuffer sending %d bytes\n", len);
+#endif
+
+       while (len > 0) {
+               i = len > 64 ? 64 : len;
+               saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+               saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER);
+               saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+               saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+               while (i-- > 0) {
+                       saa_writeb(SAA7134_GPIO_GPSTATUS0, *data);
+                       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+                       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+                       ++data;
+                       --len;
+               }
+               for (i = 0; i < 100; ++i) {
+                       gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+                       if (!(status_reg & 0x0002))
+                               break;
+               }
+               if (i == 100) {
+                       pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n",
+                              status_reg);
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+static struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
+       .interface_reset        = saa7134_go7007_interface_reset,
+       .write_interrupt        = saa7134_go7007_write_interrupt,
+       .read_interrupt         = saa7134_go7007_read_interrupt,
+       .stream_start           = saa7134_go7007_stream_start,
+       .stream_stop            = saa7134_go7007_stream_stop,
+       .send_firmware          = saa7134_go7007_send_firmware,
+};
+MODULE_FIRMWARE("go7007/go7007tv.bin");
+
+/* --------------------------------------------------------------------------*/
+
+static int saa7134_go7007_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+#if 0
+       struct saa7134_go7007 *saa = to_state(sd);
+       struct saa7134_dev *dev = saa->dev;
+
+       return saa7134_s_std_internal(dev, NULL, norm);
+#else
+       return 0;
+#endif
+}
+
+static const struct v4l2_subdev_video_ops saa7134_go7007_video_ops = {
+       .s_std = saa7134_go7007_s_std,
+};
+
+static const struct v4l2_subdev_ops saa7134_go7007_sd_ops = {
+       .video = &saa7134_go7007_video_ops,
+};
+
+/* --------------------------------------------------------------------------*/
+
+
+/********************* Add/remove functions *********************/
+
+static int saa7134_go7007_init(struct saa7134_dev *dev)
+{
+       struct go7007 *go;
+       struct saa7134_go7007 *saa;
+       struct v4l2_subdev *sd;
+
+       pr_debug("saa7134-go7007: probing new SAA713X board\n");
+
+       go = go7007_alloc(&board_voyager, &dev->pci->dev);
+       if (go == NULL)
+               return -ENOMEM;
+
+       saa = kzalloc(sizeof(struct saa7134_go7007), GFP_KERNEL);
+       if (saa == NULL) {
+               kfree(go);
+               return -ENOMEM;
+       }
+
+       go->board_id = GO7007_BOARDID_PCI_VOYAGER;
+       snprintf(go->bus_info, sizeof(go->bus_info), "PCI:%s", pci_name(dev->pci));
+       strlcpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name));
+       go->hpi_ops = &saa7134_go7007_hpi_ops;
+       go->hpi_context = saa;
+       saa->dev = dev;
+
+       /* Init the subdevice interface */
+       sd = &saa->sd;
+       v4l2_subdev_init(sd, &saa7134_go7007_sd_ops);
+       v4l2_set_subdevdata(sd, saa);
+       strncpy(sd->name, "saa7134-go7007", sizeof(sd->name));
+
+       /* Allocate a couple pages for receiving the compressed stream */
+       saa->top = (u8 *)get_zeroed_page(GFP_KERNEL);
+       if (!saa->top)
+               goto allocfail;
+       saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL);
+       if (!saa->bottom)
+               goto allocfail;
+
+       /* Boot the GO7007 */
+       if (go7007_boot_encoder(go, go->board_info->flags &
+                                       GO7007_BOARD_USE_ONBOARD_I2C) < 0)
+               goto allocfail;
+
+       /* Do any final GO7007 initialization, then register the
+        * V4L2 and ALSA interfaces */
+       if (go7007_register_encoder(go, go->board_info->num_i2c_devs) < 0)
+               goto allocfail;
+
+       /* Register the subdevice interface with the go7007 device */
+       if (v4l2_device_register_subdev(&go->v4l2_dev, sd) < 0)
+               pr_info("saa7134-go7007: register subdev failed\n");
+
+       dev->empress_dev = &go->vdev;
+
+       go->status = STATUS_ONLINE;
+       return 0;
+
+allocfail:
+       if (saa->top)
+               free_page((unsigned long)saa->top);
+       if (saa->bottom)
+               free_page((unsigned long)saa->bottom);
+       kfree(saa);
+       kfree(go);
+       return -ENOMEM;
+}
+
+static int saa7134_go7007_fini(struct saa7134_dev *dev)
+{
+       struct go7007 *go;
+       struct saa7134_go7007 *saa;
+
+       if (NULL == dev->empress_dev)
+               return 0;
+
+       go = video_get_drvdata(dev->empress_dev);
+       if (go->audio_enabled)
+               go7007_snd_remove(go);
+
+       saa = go->hpi_context;
+       go->status = STATUS_SHUTDOWN;
+       free_page((unsigned long)saa->top);
+       free_page((unsigned long)saa->bottom);
+       v4l2_device_unregister_subdev(&saa->sd);
+       kfree(saa);
+       video_unregister_device(&go->vdev);
+
+       v4l2_device_put(&go->v4l2_dev);
+       dev->empress_dev = NULL;
+
+       return 0;
+}
+
+static struct saa7134_mpeg_ops saa7134_go7007_ops = {
+       .type          = SAA7134_MPEG_GO7007,
+       .init          = saa7134_go7007_init,
+       .fini          = saa7134_go7007_fini,
+       .irq_ts_done   = saa7134_go7007_irq_ts_done,
+};
+
+static int __init saa7134_go7007_mod_init(void)
+{
+       return saa7134_ts_register(&saa7134_go7007_ops);
+}
+
+static void __exit saa7134_go7007_mod_cleanup(void)
+{
+       saa7134_ts_unregister(&saa7134_go7007_ops);
+}
+
+module_init(saa7134_go7007_mod_init);
+module_exit(saa7134_go7007_mod_cleanup);
+
+MODULE_LICENSE("GPL v2");
index c06dbe17a87f03303dc72b2e2500dc037c87ad4d..4f0b1012e4f39d308b445ae198ce30231509a8f1 100644 (file)
@@ -43,7 +43,7 @@ MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
 
 /* ------------------------------------------------------------------ */
 
-#define VBI_LINE_COUNT     16
+#define VBI_LINE_COUNT     17
 #define VBI_LINE_LENGTH  2048
 #define VBI_SCALE       0x200
 
index 0cfa2ca6a32ad2c1e3a03a952792fdcb590cc146..fc4a427cb51fed9bea0cf9ec16bab44e5408ec70 100644 (file)
@@ -201,7 +201,7 @@ static struct saa7134_format formats[] = {
                .video_v_start = 24,    \
                .video_v_stop  = 311,   \
                .vbi_v_start_0 = 7,     \
-               .vbi_v_stop_0  = 22,    \
+               .vbi_v_stop_0  = 23,    \
                .vbi_v_start_1 = 319,   \
                .src_timing    = 4
 
index e47edd4b57ce30c2c8fee0fdba8153bc1f37eaed..1a82dd07205b9dfb2b1457939d0be7027937873a 100644 (file)
@@ -338,6 +338,7 @@ struct saa7134_card_ir {
 #define SAA7134_BOARD_ASUSTeK_PS3_100      190
 #define SAA7134_BOARD_HAWELL_HW_9004V1      191
 #define SAA7134_BOARD_AVERMEDIA_A706           192
+#define SAA7134_BOARD_WIS_VOYAGER           193
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
@@ -368,6 +369,7 @@ enum saa7134_mpeg_type {
        SAA7134_MPEG_UNUSED,
        SAA7134_MPEG_EMPRESS,
        SAA7134_MPEG_DVB,
+       SAA7134_MPEG_GO7007,
 };
 
 enum saa7134_mpeg_ts_type {
@@ -407,6 +409,7 @@ struct saa7134_board {
 #define card_has_radio(dev)   (NULL != saa7134_boards[dev->board].radio.name)
 #define card_is_empress(dev)  (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg)
 #define card_is_dvb(dev)      (SAA7134_MPEG_DVB     == saa7134_boards[dev->board].mpeg)
+#define card_is_go7007(dev)   (SAA7134_MPEG_GO7007  == saa7134_boards[dev->board].mpeg)
 #define card_has_mpeg(dev)    (SAA7134_MPEG_UNUSED  != saa7134_boards[dev->board].mpeg)
 #define card(dev)             (saa7134_boards[dev->board])
 #define card_in(dev,n)        (saa7134_boards[dev->board].inputs[n])
@@ -522,6 +525,8 @@ struct saa7134_mpeg_ops {
        int                        (*init)(struct saa7134_dev *dev);
        int                        (*fini)(struct saa7134_dev *dev);
        void                       (*signal_change)(struct saa7134_dev *dev);
+       void                       (*irq_ts_done)(struct saa7134_dev *dev,
+                                                 unsigned long status);
 };
 
 /* global device status */
index e042963d377d0c8dc9b7c6d94225f1ccb5983549..4f3b1dd18ba4db4335ab87c34b02fc1ea5f2e012 100644 (file)
@@ -680,7 +680,6 @@ static int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val)
 int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
 {
        struct saa7164_dev *dev = port->dev;
-       int ret = 0;
        u8 agc_disable;
 
        dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std);
@@ -733,7 +732,7 @@ int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
        saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */
        msleep(100);
 
-       return ret;
+       return 0;
 }
 
 /* Ensure the dif is in the correct state for the operating mode
index 1bf06970ca3e8e180cb6a2f20d732c983af820b2..cc1be8a7a4510259b9dcb271f02f85325c3d7826 100644 (file)
@@ -52,7 +52,7 @@ unsigned int saa_debug;
 module_param_named(debug, saa_debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
 
-unsigned int fw_debug;
+static unsigned int fw_debug;
 module_param(fw_debug, int, 0644);
 MODULE_PARM_DESC(fw_debug, "Firmware debug level def:2");
 
@@ -72,7 +72,7 @@ static unsigned int card[]  = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card, "card type");
 
-unsigned int print_histogram = 64;
+static unsigned int print_histogram = 64;
 module_param(print_histogram, int, 0644);
 MODULE_PARM_DESC(print_histogram, "print histogram values once");
 
@@ -80,7 +80,7 @@ unsigned int crc_checking = 1;
 module_param(crc_checking, int, 0644);
 MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers");
 
-unsigned int guard_checking = 1;
+static unsigned int guard_checking = 1;
 module_param(guard_checking, int, 0644);
 MODULE_PARM_DESC(guard_checking,
        "enable dma sanity checking for buffer overruns");
index d9e06a6bf1ebc1a7de4b498361bac87f9cabe9d4..0fb91dc7ca73529eda55bb894287cbdc084e8fd0 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_SOLO6X10
        tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)"
        depends on PCI && VIDEO_DEV && SND && I2C
+       depends on HAS_DMA
        select BITREVERSE
        select FONT_SUPPORT
        select FONT_8x16
index 5ea9cac03968ee6d1b87d17f129cc4a8d37c85dc..11c98f0625e49bfaecf6e26cb5ade05b50796e25 100644 (file)
@@ -172,7 +172,7 @@ static void solo_vout_config(struct solo_dev *solo_dev)
 static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
                               u16 val, int reg_size)
 {
-       u16 *buf;
+       __le16 *buf;
        const int n = 64, size = n * sizeof(*buf);
        int i, ret = 0;
 
@@ -211,7 +211,7 @@ int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
 {
        const unsigned size = sizeof(u16) * 64;
        u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
-       u16 *buf;
+       __le16 *buf;
        int x, y;
        int ret = 0;
 
index af40b3aba41006cc4565555845c34a177dfe42df..da25ce4a69526187520ffa790f8fe6e50e04aba7 100644 (file)
@@ -100,7 +100,7 @@ unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en)
        return retval;
 }
 
-unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc)
+__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc)
 {
        int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
        unsigned short retval = 0;
@@ -117,11 +117,11 @@ unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc)
 
        solo_eeprom_reg_write(solo_dev, ~EE_CS);
 
-       return retval;
+       return (__force __be16)retval;
 }
 
 int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
-                     unsigned short data)
+                     __be16 data)
 {
        int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN);
        unsigned int retval;
@@ -130,7 +130,7 @@ int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
        solo_eeprom_cmd(solo_dev, write_cmd);
 
        for (i = 15; i >= 0; i--) {
-               unsigned int dataval = (data >> i) & 1;
+               unsigned int dataval = ((__force unsigned)data >> i) & 1;
 
                solo_eeprom_reg_write(solo_dev, EE_ENB);
                solo_eeprom_reg_write(solo_dev,
index c6154b00fcbd9250e4b9b50bfb0ded1b56701731..72017b7f0a753d1161dcced8ffe5fa3cc3679503 100644 (file)
@@ -394,9 +394,9 @@ int solo_osd_print(struct solo_enc_dev *solo_enc);
 
 /* EEPROM commands */
 unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en);
-unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc);
+__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc);
 int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
-                     unsigned short data);
+                     __be16 data);
 
 /* JPEG Qp functions */
 void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch,
index 03130157db83c28001d2d3ac2986117869f8bc7b..f6f30abc088ba26e4ce547b7f2cf9bac12122be7 100644 (file)
@@ -1,6 +1,7 @@
 config STA2X11_VIP
        tristate "STA2X11 VIP Video For Linux"
        depends on STA2X11
+       depends on HAS_DMA
        select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT
        select VIDEOBUF2_DMA_CONTIG
        depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
index 365bd21301baa494744238eea568fea16ec29e5d..22450f583da1750e743b27aeb1fa4b7ce7f805f8 100644 (file)
@@ -152,7 +152,7 @@ struct sta2x11_vip {
        int tcount, bcount;
        int overflow;
 
-       void *iomem;    /* I/O Memory */
+       void __iomem *iomem;    /* I/O Memory */
        struct vip_config *config;
 };
 
index 0dcb8cd7767698d101860c111f65751c3951461e..7b83151ed6c48dd665a021c43438e61b453f2cce 100644 (file)
@@ -1,8 +1,12 @@
+config DVB_AV7110_IR
+       bool
+
 config DVB_AV7110
        tristate "AV7110 cards"
        depends on DVB_CORE && PCI && I2C
        select TTPCI_EEPROM
        select VIDEO_SAA7146_VV
+       select DVB_AV7110_IR if INPUT_EVDEV=y || INPUT_EVDEV=DVB_AV7110
        depends on VIDEO_DEV    # dependencies of VIDEO_SAA7146_VV
        select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
index 98905963ff085c0b0e265b7bf26ae0d892aa6a83..49f71b1eaf14b529689f82e658d44a09b285ddbf 100644 (file)
@@ -5,7 +5,7 @@
 
 dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o
 
-ifdef CONFIG_INPUT_EVDEV
+ifdef CONFIG_DVB_AV7110_IR
 dvb-ttpci-objs += av7110_ir.o
 endif
 
index f38329d29daa8c41a83823deb0d2f87de7a079ff..c1f0617a69733df52b924668457a955ab39806f1 100644 (file)
@@ -235,7 +235,7 @@ static void recover_arm(struct av7110 *av7110)
 
        restart_feeds(av7110);
 
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
        av7110_check_ir_config(av7110, true);
 #endif
 }
@@ -268,7 +268,7 @@ static int arm_thread(void *data)
                if (!av7110->arm_ready)
                        continue;
 
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
                av7110_check_ir_config(av7110, false);
 #endif
 
@@ -2725,7 +2725,7 @@ static int av7110_attach(struct saa7146_dev* dev,
 
        mutex_init(&av7110->ioctl_mutex);
 
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
        av7110_ir_init(av7110);
 #endif
        printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
@@ -2768,7 +2768,7 @@ static int av7110_detach(struct saa7146_dev* saa)
        struct av7110 *av7110 = saa->ext_priv;
        dprintk(4, "%p\n", av7110);
 
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
        av7110_ir_exit(av7110);
 #endif
        if (budgetpatch || av7110->full_ts) {
diff --git a/drivers/media/pci/tw68/Kconfig b/drivers/media/pci/tw68/Kconfig
new file mode 100644 (file)
index 0000000..5425ba1
--- /dev/null
@@ -0,0 +1,10 @@
+config VIDEO_TW68
+       tristate "Techwell tw68x Video For Linux"
+       depends on VIDEO_DEV && PCI && VIDEO_V4L2
+       select I2C_ALGOBIT
+       select VIDEOBUF2_DMA_SG
+       ---help---
+         Support for Techwell tw68xx based frame grabber boards.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tw68.
diff --git a/drivers/media/pci/tw68/Makefile b/drivers/media/pci/tw68/Makefile
new file mode 100644 (file)
index 0000000..3d02f28
--- /dev/null
@@ -0,0 +1,3 @@
+tw68-objs := tw68-core.o tw68-video.o tw68-risc.o
+
+obj-$(CONFIG_VIDEO_TW68) += tw68.o
diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c
new file mode 100644 (file)
index 0000000..a6fb48c
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ *  tw68-core.c
+ *  Core functions for the Techwell 68xx driver
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) 2009  William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  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.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
+#include <linux/sound.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm.h>
+
+#include <media/v4l2-dev.h>
+#include "tw68.h"
+#include "tw68-reg.h"
+
+MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards");
+MODULE_AUTHOR("William M. Brack");
+MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
+MODULE_LICENSE("GPL");
+
+static unsigned int latency = UNSET;
+module_param(latency, int, 0444);
+MODULE_PARM_DESC(latency, "pci latency timer");
+
+static unsigned int video_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "video device number");
+
+static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
+
+static atomic_t tw68_instance = ATOMIC_INIT(0);
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * Please add any new PCI IDs to: http://pci-ids.ucw.cz.  This keeps
+ * the PCI ID database up to date.  Note that the entries must be
+ * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs.
+ */
+static const struct pci_device_id tw68_pci_tbl[] = {
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6800)},
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6801)},
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6804)},
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_1)},
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_2)},
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_3)},
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_4)},
+       {0,}
+};
+
+/* ------------------------------------------------------------------ */
+
+
+/*
+ * The device is given a "soft reset". According to the specifications,
+ * after this "all register content remain unchanged", so we also write
+ * to all specified registers manually as well (mostly to manufacturer's
+ * specified reset values)
+ */
+static int tw68_hw_init1(struct tw68_dev *dev)
+{
+       /* Assure all interrupts are disabled */
+       tw_writel(TW68_INTMASK, 0);             /* 020 */
+       /* Clear any pending interrupts */
+       tw_writel(TW68_INTSTAT, 0xffffffff);    /* 01C */
+       /* Stop risc processor, set default buffer level */
+       tw_writel(TW68_DMAC, 0x1600);
+
+       tw_writeb(TW68_ACNTL, 0x80);    /* 218  soft reset */
+       msleep(100);
+
+       tw_writeb(TW68_INFORM, 0x40);   /* 208  mux0, 27mhz xtal */
+       tw_writeb(TW68_OPFORM, 0x04);   /* 20C  analog line-lock */
+       tw_writeb(TW68_HSYNC, 0);       /* 210  color-killer high sens */
+       tw_writeb(TW68_ACNTL, 0x42);    /* 218  int vref #2, chroma adc off */
+
+       tw_writeb(TW68_CROP_HI, 0x02);  /* 21C  Hactive m.s. bits */
+       tw_writeb(TW68_VDELAY_LO, 0x12);/* 220  Mfg specified reset value */
+       tw_writeb(TW68_VACTIVE_LO, 0xf0);
+       tw_writeb(TW68_HDELAY_LO, 0x0f);
+       tw_writeb(TW68_HACTIVE_LO, 0xd0);
+
+       tw_writeb(TW68_CNTRL1, 0xcd);   /* 230  Wide Chroma BPF B/W
+                                        *      Secam reduction, Adap comb for
+                                        *      NTSC, Op Mode 1 */
+
+       tw_writeb(TW68_VSCALE_LO, 0);   /* 234 */
+       tw_writeb(TW68_SCALE_HI, 0x11); /* 238 */
+       tw_writeb(TW68_HSCALE_LO, 0);   /* 23c */
+       tw_writeb(TW68_BRIGHT, 0);      /* 240 */
+       tw_writeb(TW68_CONTRAST, 0x5c); /* 244 */
+       tw_writeb(TW68_SHARPNESS, 0x51);/* 248 */
+       tw_writeb(TW68_SAT_U, 0x80);    /* 24C */
+       tw_writeb(TW68_SAT_V, 0x80);    /* 250 */
+       tw_writeb(TW68_HUE, 0x00);      /* 254 */
+
+       /* TODO - Check that none of these are set by control defaults */
+       tw_writeb(TW68_SHARP2, 0x53);   /* 258  Mfg specified reset val */
+       tw_writeb(TW68_VSHARP, 0x80);   /* 25C  Sharpness Coring val 8 */
+       tw_writeb(TW68_CORING, 0x44);   /* 260  CTI and Vert Peak coring */
+       tw_writeb(TW68_CNTRL2, 0x00);   /* 268  No power saving enabled */
+       tw_writeb(TW68_SDT, 0x07);      /* 270  Enable shadow reg, auto-det */
+       tw_writeb(TW68_SDTR, 0x7f);     /* 274  All stds recog, don't start */
+       tw_writeb(TW68_CLMPG, 0x50);    /* 280  Clamp end at 40 sys clocks */
+       tw_writeb(TW68_IAGC, 0x22);     /* 284  Mfg specified reset val */
+       tw_writeb(TW68_AGCGAIN, 0xf0);  /* 288  AGC gain when loop disabled */
+       tw_writeb(TW68_PEAKWT, 0xd8);   /* 28C  White peak threshold */
+       tw_writeb(TW68_CLMPL, 0x3c);    /* 290  Y channel clamp level */
+/*     tw_writeb(TW68_SYNCT, 0x38);*/  /* 294  Sync amplitude */
+       tw_writeb(TW68_SYNCT, 0x30);    /* 294  Sync amplitude */
+       tw_writeb(TW68_MISSCNT, 0x44);  /* 298  Horiz sync, VCR detect sens */
+       tw_writeb(TW68_PCLAMP, 0x28);   /* 29C  Clamp pos from PLL sync */
+       /* Bit DETV of VCNTL1 helps sync multi cams/chip board */
+       tw_writeb(TW68_VCNTL1, 0x04);   /* 2A0 */
+       tw_writeb(TW68_VCNTL2, 0);      /* 2A4 */
+       tw_writeb(TW68_CKILL, 0x68);    /* 2A8  Mfg specified reset val */
+       tw_writeb(TW68_COMB, 0x44);     /* 2AC  Mfg specified reset val */
+       tw_writeb(TW68_LDLY, 0x30);     /* 2B0  Max positive luma delay */
+       tw_writeb(TW68_MISC1, 0x14);    /* 2B4  Mfg specified reset val */
+       tw_writeb(TW68_LOOP, 0xa5);     /* 2B8  Mfg specified reset val */
+       tw_writeb(TW68_MISC2, 0xe0);    /* 2BC  Enable colour killer */
+       tw_writeb(TW68_MVSN, 0);        /* 2C0 */
+       tw_writeb(TW68_CLMD, 0x05);     /* 2CC  slice level auto, clamp med. */
+       tw_writeb(TW68_IDCNTL, 0);      /* 2D0  Writing zero to this register
+                                        *      selects NTSC ID detection,
+                                        *      but doesn't change the
+                                        *      sensitivity (which has a reset
+                                        *      value of 1E).  Since we are
+                                        *      not doing auto-detection, it
+                                        *      has no real effect */
+       tw_writeb(TW68_CLCNTL1, 0);     /* 2D4 */
+       tw_writel(TW68_VBIC, 0x03);     /* 010 */
+       tw_writel(TW68_CAP_CTL, 0x03);  /* 040  Enable both even & odd flds */
+       tw_writel(TW68_DMAC, 0x2000);   /* patch set had 0x2080 */
+       tw_writel(TW68_TESTREG, 0);     /* 02C */
+
+       /*
+        * Some common boards, especially inexpensive single-chip models,
+        * use the GPIO bits 0-3 to control an on-board video-output mux.
+        * For these boards, we need to set up the GPIO register into
+        * "normal" mode, set bits 0-3 as output, and then set those bits
+        * zero.
+        *
+        * Eventually, it would be nice if we could identify these boards
+        * uniquely, and only do this initialisation if the board has been
+        * identify.  For the moment, however, it shouldn't hurt anything
+        * to do these steps.
+        */
+       tw_writel(TW68_GPIOC, 0);       /* Set the GPIO to "normal", no ints */
+       tw_writel(TW68_GPOE, 0x0f);     /* Set bits 0-3 to "output" */
+       tw_writel(TW68_GPDATA, 0);      /* Set all bits to low state */
+
+       /* Initialize the device control structures */
+       mutex_init(&dev->lock);
+       spin_lock_init(&dev->slock);
+
+       /* Initialize any subsystems */
+       tw68_video_init1(dev);
+       return 0;
+}
+
+static irqreturn_t tw68_irq(int irq, void *dev_id)
+{
+       struct tw68_dev *dev = dev_id;
+       u32 status, orig;
+       int loop;
+
+       status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask;
+       /* Check if anything to do */
+       if (0 == status)
+               return IRQ_NONE;        /* Nope - return */
+       for (loop = 0; loop < 10; loop++) {
+               if (status & dev->board_virqmask)       /* video interrupt */
+                       tw68_irq_video_done(dev, status);
+               status = tw_readl(TW68_INTSTAT) & dev->pci_irqmask;
+               if (0 == status)
+                       return IRQ_HANDLED;
+       }
+       dev_dbg(&dev->pci->dev, "%s: **** INTERRUPT NOT HANDLED - clearing mask (orig 0x%08x, cur 0x%08x)",
+                       dev->name, orig, tw_readl(TW68_INTSTAT));
+       dev_dbg(&dev->pci->dev, "%s: pci_irqmask 0x%08x; board_virqmask 0x%08x ****\n",
+                       dev->name, dev->pci_irqmask, dev->board_virqmask);
+       tw_clearl(TW68_INTMASK, dev->pci_irqmask);
+       return IRQ_HANDLED;
+}
+
+static int tw68_initdev(struct pci_dev *pci_dev,
+                                    const struct pci_device_id *pci_id)
+{
+       struct tw68_dev *dev;
+       int vidnr = -1;
+       int err;
+
+       dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev), GFP_KERNEL);
+       if (NULL == dev)
+               return -ENOMEM;
+
+       dev->instance = v4l2_device_set_name(&dev->v4l2_dev, "tw68",
+                                               &tw68_instance);
+
+       err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
+       if (err)
+               return err;
+
+       /* pci init */
+       dev->pci = pci_dev;
+       if (pci_enable_device(pci_dev)) {
+               err = -EIO;
+               goto fail1;
+       }
+
+       dev->name = dev->v4l2_dev.name;
+
+       if (UNSET != latency) {
+               pr_info("%s: setting pci latency timer to %d\n",
+                      dev->name, latency);
+               pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
+       }
+
+       /* print pci info */
+       pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+       pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+       pr_info("%s: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n",
+               dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+               dev->pci_lat, (u64)pci_resource_start(pci_dev, 0));
+       pci_set_master(pci_dev);
+       if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) {
+               pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
+               err = -EIO;
+               goto fail1;
+       }
+
+       switch (pci_id->device) {
+       case PCI_DEVICE_ID_6800:        /* TW6800 */
+               dev->vdecoder = TW6800;
+               dev->board_virqmask = TW68_VID_INTS;
+               break;
+       case PCI_DEVICE_ID_6801:        /* Video decoder for TW6802 */
+               dev->vdecoder = TW6801;
+               dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
+               break;
+       case PCI_DEVICE_ID_6804:        /* Video decoder for TW6804 */
+               dev->vdecoder = TW6804;
+               dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
+               break;
+       default:
+               dev->vdecoder = TWXXXX; /* To be announced */
+               dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
+               break;
+       }
+
+       /* get mmio */
+       if (!request_mem_region(pci_resource_start(pci_dev, 0),
+                               pci_resource_len(pci_dev, 0),
+                               dev->name)) {
+               err = -EBUSY;
+               pr_err("%s: can't get MMIO memory @ 0x%llx\n",
+                       dev->name,
+                       (unsigned long long)pci_resource_start(pci_dev, 0));
+               goto fail1;
+       }
+       dev->lmmio = ioremap(pci_resource_start(pci_dev, 0),
+                            pci_resource_len(pci_dev, 0));
+       dev->bmmio = (__u8 __iomem *)dev->lmmio;
+       if (NULL == dev->lmmio) {
+               err = -EIO;
+               pr_err("%s: can't ioremap() MMIO memory\n",
+                      dev->name);
+               goto fail2;
+       }
+       /* initialize hardware #1 */
+       /* Then do any initialisation wanted before interrupts are on */
+       tw68_hw_init1(dev);
+
+       /* get irq */
+       err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq,
+                         IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+       if (err < 0) {
+               pr_err("%s: can't get IRQ %d\n",
+                      dev->name, pci_dev->irq);
+               goto fail3;
+       }
+
+       /*
+        *  Now do remainder of initialisation, first for
+        *  things unique for this card, then for general board
+        */
+       if (dev->instance < TW68_MAXBOARDS)
+               vidnr = video_nr[dev->instance];
+       /* initialise video function first */
+       err = tw68_video_init2(dev, vidnr);
+       if (err < 0) {
+               pr_err("%s: can't register video device\n",
+                      dev->name);
+               goto fail4;
+       }
+       tw_setl(TW68_INTMASK, dev->pci_irqmask);
+
+       pr_info("%s: registered device %s\n",
+              dev->name, video_device_node_name(&dev->vdev));
+
+       return 0;
+
+fail4:
+       video_unregister_device(&dev->vdev);
+fail3:
+       iounmap(dev->lmmio);
+fail2:
+       release_mem_region(pci_resource_start(pci_dev, 0),
+                          pci_resource_len(pci_dev, 0));
+fail1:
+       v4l2_device_unregister(&dev->v4l2_dev);
+       return err;
+}
+
+static void tw68_finidev(struct pci_dev *pci_dev)
+{
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct tw68_dev *dev =
+               container_of(v4l2_dev, struct tw68_dev, v4l2_dev);
+
+       /* shutdown subsystems */
+       tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
+       tw_writel(TW68_INTMASK, 0);
+
+       /* unregister */
+       video_unregister_device(&dev->vdev);
+       v4l2_ctrl_handler_free(&dev->hdl);
+
+       /* release resources */
+       iounmap(dev->lmmio);
+       release_mem_region(pci_resource_start(pci_dev, 0),
+                          pci_resource_len(pci_dev, 0));
+
+       v4l2_device_unregister(&dev->v4l2_dev);
+}
+
+#ifdef CONFIG_PM
+
+static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state)
+{
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct tw68_dev *dev = container_of(v4l2_dev,
+                               struct tw68_dev, v4l2_dev);
+
+       tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
+       dev->pci_irqmask &= ~TW68_VID_INTS;
+       tw_writel(TW68_INTMASK, 0);
+
+       synchronize_irq(pci_dev->irq);
+
+       pci_save_state(pci_dev);
+       pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+       vb2_discard_done(&dev->vidq);
+
+       return 0;
+}
+
+static int tw68_resume(struct pci_dev *pci_dev)
+{
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct tw68_dev *dev = container_of(v4l2_dev,
+                                           struct tw68_dev, v4l2_dev);
+       struct tw68_buf *buf;
+       unsigned long flags;
+
+       pci_set_power_state(pci_dev, PCI_D0);
+       pci_restore_state(pci_dev);
+
+       /* Do things that are done in tw68_initdev ,
+               except of initializing memory structures.*/
+
+       msleep(100);
+
+       tw68_set_tvnorm_hw(dev);
+
+       /*resume unfinished buffer(s)*/
+       spin_lock_irqsave(&dev->slock, flags);
+       buf = container_of(dev->active.next, struct tw68_buf, list);
+
+       tw68_video_start_dma(dev, buf);
+
+       spin_unlock_irqrestore(&dev->slock, flags);
+
+       return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+
+static struct pci_driver tw68_pci_driver = {
+       .name     = "tw68",
+       .id_table = tw68_pci_tbl,
+       .probe    = tw68_initdev,
+       .remove   = tw68_finidev,
+#ifdef CONFIG_PM
+       .suspend  = tw68_suspend,
+       .resume   = tw68_resume
+#endif
+};
+
+module_pci_driver(tw68_pci_driver);
diff --git a/drivers/media/pci/tw68/tw68-reg.h b/drivers/media/pci/tw68/tw68-reg.h
new file mode 100644 (file)
index 0000000..f60b3a8
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ *  tw68-reg.h - TW68xx register offsets
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  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.
+*/
+
+#ifndef _TW68_REG_H_
+#define _TW68_REG_H_
+
+/* ---------------------------------------------------------------------- */
+#define        TW68_DMAC               0x000
+#define        TW68_DMAP_SA            0x004
+#define        TW68_DMAP_EXE           0x008
+#define        TW68_DMAP_PP            0x00c
+#define        TW68_VBIC               0x010
+#define        TW68_SBUSC              0x014
+#define        TW68_SBUSSD             0x018
+#define        TW68_INTSTAT            0x01C
+#define        TW68_INTMASK            0x020
+#define        TW68_GPIOC              0x024
+#define        TW68_GPOE               0x028
+#define        TW68_TESTREG            0x02C
+#define        TW68_SBUSRD             0x030
+#define        TW68_SBUS_TRIG          0x034
+#define        TW68_CAP_CTL            0x040
+#define        TW68_SUBSYS             0x054
+#define        TW68_I2C_RST            0x064
+#define        TW68_VBIINST            0x06C
+/* define bits in FIFO and DMAP Control reg */
+#define        TW68_DMAP_EN            (1 << 0)
+#define        TW68_FIFO_EN            (1 << 1)
+/* define the Interrupt Status Register bits */
+#define        TW68_SBDONE             (1 << 0)
+#define        TW68_DMAPI              (1 << 1)
+#define        TW68_GPINT              (1 << 2)
+#define        TW68_FFOF               (1 << 3)
+#define        TW68_FDMIS              (1 << 4)
+#define        TW68_DMAPERR            (1 << 5)
+#define        TW68_PABORT             (1 << 6)
+#define        TW68_SBDONE2            (1 << 12)
+#define        TW68_SBERR2             (1 << 13)
+#define        TW68_PPERR              (1 << 14)
+#define        TW68_FFERR              (1 << 15)
+#define        TW68_DET50              (1 << 16)
+#define        TW68_FLOCK              (1 << 17)
+#define        TW68_CCVALID            (1 << 18)
+#define        TW68_VLOCK              (1 << 19)
+#define        TW68_FIELD              (1 << 20)
+#define        TW68_SLOCK              (1 << 21)
+#define        TW68_HLOCK              (1 << 22)
+#define        TW68_VDLOSS             (1 << 23)
+#define        TW68_SBERR              (1 << 24)
+/* define the i2c control register bits */
+#define        TW68_SBMODE             (0)
+#define        TW68_WREN               (1)
+#define        TW68_SSCLK              (6)
+#define        TW68_SSDAT              (7)
+#define        TW68_SBCLK              (8)
+#define        TW68_WDLEN              (16)
+#define        TW68_RDLEN              (20)
+#define        TW68_SBRW               (24)
+#define        TW68_SBDEV              (25)
+
+#define        TW68_SBMODE_B           (1 << TW68_SBMODE)
+#define        TW68_WREN_B             (1 << TW68_WREN)
+#define        TW68_SSCLK_B            (1 << TW68_SSCLK)
+#define        TW68_SSDAT_B            (1 << TW68_SSDAT)
+#define        TW68_SBRW_B             (1 << TW68_SBRW)
+
+#define        TW68_GPDATA             0x100
+#define        TW68_STATUS1            0x204
+#define        TW68_INFORM             0x208
+#define        TW68_OPFORM             0x20C
+#define        TW68_HSYNC              0x210
+#define        TW68_ACNTL              0x218
+#define        TW68_CROP_HI            0x21C
+#define        TW68_VDELAY_LO          0x220
+#define        TW68_VACTIVE_LO         0x224
+#define        TW68_HDELAY_LO          0x228
+#define        TW68_HACTIVE_LO         0x22C
+#define        TW68_CNTRL1             0x230
+#define        TW68_VSCALE_LO          0x234
+#define        TW68_SCALE_HI           0x238
+#define        TW68_HSCALE_LO          0x23C
+#define        TW68_BRIGHT             0x240
+#define        TW68_CONTRAST           0x244
+#define        TW68_SHARPNESS          0x248
+#define        TW68_SAT_U              0x24C
+#define        TW68_SAT_V              0x250
+#define        TW68_HUE                0x254
+#define        TW68_SHARP2             0x258
+#define        TW68_VSHARP             0x25C
+#define        TW68_CORING             0x260
+#define        TW68_VBICNTL            0x264
+#define        TW68_CNTRL2             0x268
+#define        TW68_CC_DATA            0x26C
+#define        TW68_SDT                0x270
+#define        TW68_SDTR               0x274
+#define        TW68_RESERV2            0x278
+#define        TW68_RESERV3            0x27C
+#define        TW68_CLMPG              0x280
+#define        TW68_IAGC               0x284
+#define        TW68_AGCGAIN            0x288
+#define        TW68_PEAKWT             0x28C
+#define        TW68_CLMPL              0x290
+#define        TW68_SYNCT              0x294
+#define        TW68_MISSCNT            0x298
+#define        TW68_PCLAMP             0x29C
+#define        TW68_VCNTL1             0x2A0
+#define        TW68_VCNTL2             0x2A4
+#define        TW68_CKILL              0x2A8
+#define        TW68_COMB               0x2AC
+#define        TW68_LDLY               0x2B0
+#define        TW68_MISC1              0x2B4
+#define        TW68_LOOP               0x2B8
+#define        TW68_MISC2              0x2BC
+#define        TW68_MVSN               0x2C0
+#define        TW68_STATUS2            0x2C4
+#define        TW68_HFREF              0x2C8
+#define        TW68_CLMD               0x2CC
+#define        TW68_IDCNTL             0x2D0
+#define        TW68_CLCNTL1            0x2D4
+
+/* Audio */
+#define        TW68_ACKI1              0x300
+#define        TW68_ACKI2              0x304
+#define        TW68_ACKI3              0x308
+#define        TW68_ACKN1              0x30C
+#define        TW68_ACKN2              0x310
+#define        TW68_ACKN3              0x314
+#define        TW68_SDIV               0x318
+#define        TW68_LRDIV              0x31C
+#define        TW68_ACCNTL             0x320
+
+#define        TW68_VSCTL              0x3B8
+#define        TW68_CHROMAGVAL         0x3BC
+
+#define        TW68_F2CROP_HI          0x3DC
+#define        TW68_F2VDELAY_LO        0x3E0
+#define        TW68_F2VACTIVE_LO       0x3E4
+#define        TW68_F2HDELAY_LO        0x3E8
+#define        TW68_F2HACTIVE_LO       0x3EC
+#define        TW68_F2CNT              0x3F0
+#define        TW68_F2VSCALE_LO        0x3F4
+#define        TW68_F2SCALE_HI         0x3F8
+#define        TW68_F2HSCALE_LO        0x3FC
+
+#define        RISC_INT_BIT            0x08000000
+#define        RISC_SYNCO              0xC0000000
+#define        RISC_SYNCE              0xD0000000
+#define        RISC_JUMP               0xB0000000
+#define        RISC_LINESTART          0x90000000
+#define        RISC_INLINE             0xA0000000
+
+#define VideoFormatNTSC                 0
+#define VideoFormatNTSCJapan    0
+#define VideoFormatPALBDGHI     1
+#define VideoFormatSECAM        2
+#define VideoFormatNTSC443      3
+#define VideoFormatPALM                 4
+#define VideoFormatPALN                 5
+#define VideoFormatPALNC        5
+#define VideoFormatPAL60        6
+#define VideoFormatAuto                 7
+
+#define ColorFormatRGB32        0x00
+#define ColorFormatRGB24        0x10
+#define ColorFormatRGB16        0x20
+#define ColorFormatRGB15        0x30
+#define ColorFormatYUY2                 0x40
+#define ColorFormatBSWAP         0x04
+#define ColorFormatWSWAP         0x08
+#define ColorFormatGamma         0x80
+#endif
diff --git a/drivers/media/pci/tw68/tw68-risc.c b/drivers/media/pci/tw68/tw68-risc.c
new file mode 100644 (file)
index 0000000..7439db2
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *  tw68_risc.c
+ *  Part of the device driver for Techwell 68xx based cards
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) 2009  William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  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.
+ */
+
+#include "tw68.h"
+
+/**
+ *  @rp                pointer to current risc program position
+ *  @sglist    pointer to "scatter-gather list" of buffer pointers
+ *  @offset    offset to target memory buffer
+ *  @sync_line 0 -> no sync, 1 -> odd sync, 2 -> even sync
+ *  @bpl       number of bytes per scan line
+ *  @padding   number of bytes of padding to add
+ *  @lines     number of lines in field
+ *  @jump      insert a jump at the start
+ */
+static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist,
+                           unsigned int offset, u32 sync_line,
+                           unsigned int bpl, unsigned int padding,
+                           unsigned int lines, bool jump)
+{
+       struct scatterlist *sg;
+       unsigned int line, todo, done;
+
+       if (jump) {
+               *(rp++) = cpu_to_le32(RISC_JUMP);
+               *(rp++) = 0;
+       }
+
+       /* sync instruction */
+       if (sync_line == 1)
+               *(rp++) = cpu_to_le32(RISC_SYNCO);
+       else
+               *(rp++) = cpu_to_le32(RISC_SYNCE);
+       *(rp++) = 0;
+
+       /* scan lines */
+       sg = sglist;
+       for (line = 0; line < lines; line++) {
+               /* calculate next starting position */
+               while (offset && offset >= sg_dma_len(sg)) {
+                       offset -= sg_dma_len(sg);
+                       sg = sg_next(sg);
+               }
+               if (bpl <= sg_dma_len(sg) - offset) {
+                       /* fits into current chunk */
+                       *(rp++) = cpu_to_le32(RISC_LINESTART |
+                                             /* (offset<<12) |*/  bpl);
+                       *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
+                       offset += bpl;
+               } else {
+                       /*
+                        * scanline needs to be split.  Put the start in
+                        * whatever memory remains using RISC_LINESTART,
+                        * then the remainder into following addresses
+                        * given by the scatter-gather list.
+                        */
+                       todo = bpl;     /* one full line to be done */
+                       /* first fragment */
+                       done = (sg_dma_len(sg) - offset);
+                       *(rp++) = cpu_to_le32(RISC_LINESTART |
+                                               (7 << 24) |
+                                               done);
+                       *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
+                       todo -= done;
+                       sg = sg_next(sg);
+                       /* succeeding fragments have no offset */
+                       while (todo > sg_dma_len(sg)) {
+                               *(rp++) = cpu_to_le32(RISC_INLINE |
+                                               (done << 12) |
+                                               sg_dma_len(sg));
+                               *(rp++) = cpu_to_le32(sg_dma_address(sg));
+                               todo -= sg_dma_len(sg);
+                               sg = sg_next(sg);
+                               done += sg_dma_len(sg);
+                       }
+                       if (todo) {
+                               /* final chunk - offset 0, count 'todo' */
+                               *(rp++) = cpu_to_le32(RISC_INLINE |
+                                                       (done << 12) |
+                                                       todo);
+                               *(rp++) = cpu_to_le32(sg_dma_address(sg));
+                       }
+                       offset = todo;
+               }
+               offset += padding;
+       }
+
+       return rp;
+}
+
+/**
+ * tw68_risc_buffer
+ *
+ *     This routine is called by tw68-video.  It allocates
+ *     memory for the dma controller "program" and then fills in that
+ *     memory with the appropriate "instructions".
+ *
+ *     @pci_dev        structure with info about the pci
+ *                     slot which our device is in.
+ *     @risc           structure with info about the memory
+ *                     used for our controller program.
+ *     @sglist         scatter-gather list entry
+ *     @top_offset     offset within the risc program area for the
+ *                     first odd frame line
+ *     @bottom_offset  offset within the risc program area for the
+ *                     first even frame line
+ *     @bpl            number of data bytes per scan line
+ *     @padding        number of extra bytes to add at end of line
+ *     @lines          number of scan lines
+ */
+int tw68_risc_buffer(struct pci_dev *pci,
+                       struct tw68_buf *buf,
+                       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;
+
+       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 + 2 jumps (all 2 dwords).
+        * Padding can cause next bpl to start close to a page border.
+        * First DMA region may be smaller than PAGE_SIZE
+        */
+       instructions  = fields * (1 + (((bpl + padding) * lines) /
+                        PAGE_SIZE) + lines) + 4;
+       buf->size = instructions * 8;
+       buf->cpu = pci_alloc_consistent(pci, buf->size, &buf->dma);
+       if (buf->cpu == NULL)
+               return -ENOMEM;
+
+       /* write risc instructions */
+       rp = buf->cpu;
+       if (UNSET != top_offset)        /* generates SYNCO */
+               rp = tw68_risc_field(rp, sglist, top_offset, 1,
+                                    bpl, padding, lines, true);
+       if (UNSET != bottom_offset)     /* generates SYNCE */
+               rp = tw68_risc_field(rp, sglist, bottom_offset, 2,
+                                    bpl, padding, lines, top_offset == UNSET);
+
+       /* save pointer to jmp instruction address */
+       buf->jmp = rp;
+       buf->cpu[1] = cpu_to_le32(buf->dma + 8);
+       /* assure risc buffer hasn't overflowed */
+       BUG_ON((buf->jmp - buf->cpu + 2) * sizeof(buf->cpu[0]) > buf->size);
+       return 0;
+}
+
+#if 0
+/* ------------------------------------------------------------------ */
+/* debug helper code                                                  */
+
+static void tw68_risc_decode(u32 risc, u32 addr)
+{
+#define        RISC_OP(reg)    (((reg) >> 28) & 7)
+       static struct instr_details {
+               char *name;
+               u8 has_data_type;
+               u8 has_byte_info;
+               u8 has_addr;
+       } instr[8] = {
+               [RISC_OP(RISC_SYNCO)]     = {"syncOdd", 0, 0, 0},
+               [RISC_OP(RISC_SYNCE)]     = {"syncEven", 0, 0, 0},
+               [RISC_OP(RISC_JUMP)]      = {"jump", 0, 0, 1},
+               [RISC_OP(RISC_LINESTART)] = {"lineStart", 1, 1, 1},
+               [RISC_OP(RISC_INLINE)]    = {"inline", 1, 1, 1},
+       };
+       u32 p;
+
+       p = RISC_OP(risc);
+       if (!(risc & 0x80000000) || !instr[p].name) {
+               pr_debug("0x%08x [ INVALID ]\n", risc);
+               return;
+       }
+       pr_debug("0x%08x %-9s IRQ=%d",
+               risc, instr[p].name, (risc >> 27) & 1);
+       if (instr[p].has_data_type)
+               pr_debug(" Type=%d", (risc >> 24) & 7);
+       if (instr[p].has_byte_info)
+               pr_debug(" Start=0x%03x Count=%03u",
+                       (risc >> 12) & 0xfff, risc & 0xfff);
+       if (instr[p].has_addr)
+               pr_debug(" StartAddr=0x%08x", addr);
+       pr_debug("\n");
+}
+
+void tw68_risc_program_dump(struct tw68_core *core, struct tw68_buf *buf)
+{
+       const __le32 *addr;
+
+       pr_debug("%s: risc_program_dump: risc=%p, buf->cpu=0x%p, buf->jmp=0x%p\n",
+                 core->name, buf, buf->cpu, buf->jmp);
+       for (addr = buf->cpu; addr <= buf->jmp; addr += 2)
+               tw68_risc_decode(*addr, *(addr+1));
+}
+#endif
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c
new file mode 100644 (file)
index 0000000..5c94ac7
--- /dev/null
@@ -0,0 +1,1051 @@
+/*
+ *  tw68 functions to handle video data
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) 2009  William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "tw68.h"
+#include "tw68-reg.h"
+
+/* ------------------------------------------------------------------ */
+/* data structs for video                                             */
+/*
+ * FIXME -
+ * Note that the saa7134 has formats, e.g. YUV420, which are classified
+ * as "planar".  These affect overlay mode, and are flagged with a field
+ * ".planar" in the format.  Do we need to implement this in this driver?
+ */
+static const struct tw68_format formats[] = {
+       {
+               .name           = "15 bpp RGB, le",
+               .fourcc         = V4L2_PIX_FMT_RGB555,
+               .depth          = 16,
+               .twformat       = ColorFormatRGB15,
+       }, {
+               .name           = "15 bpp RGB, be",
+               .fourcc         = V4L2_PIX_FMT_RGB555X,
+               .depth          = 16,
+               .twformat       = ColorFormatRGB15 | ColorFormatBSWAP,
+       }, {
+               .name           = "16 bpp RGB, le",
+               .fourcc         = V4L2_PIX_FMT_RGB565,
+               .depth          = 16,
+               .twformat       = ColorFormatRGB16,
+       }, {
+               .name           = "16 bpp RGB, be",
+               .fourcc         = V4L2_PIX_FMT_RGB565X,
+               .depth          = 16,
+               .twformat       = ColorFormatRGB16 | ColorFormatBSWAP,
+       }, {
+               .name           = "24 bpp RGB, le",
+               .fourcc         = V4L2_PIX_FMT_BGR24,
+               .depth          = 24,
+               .twformat       = ColorFormatRGB24,
+       }, {
+               .name           = "24 bpp RGB, be",
+               .fourcc         = V4L2_PIX_FMT_RGB24,
+               .depth          = 24,
+               .twformat       = ColorFormatRGB24 | ColorFormatBSWAP,
+       }, {
+               .name           = "32 bpp RGB, le",
+               .fourcc         = V4L2_PIX_FMT_BGR32,
+               .depth          = 32,
+               .twformat       = ColorFormatRGB32,
+       }, {
+               .name           = "32 bpp RGB, be",
+               .fourcc         = V4L2_PIX_FMT_RGB32,
+               .depth          = 32,
+               .twformat       = ColorFormatRGB32 | ColorFormatBSWAP |
+                                 ColorFormatWSWAP,
+       }, {
+               .name           = "4:2:2 packed, YUYV",
+               .fourcc         = V4L2_PIX_FMT_YUYV,
+               .depth          = 16,
+               .twformat       = ColorFormatYUY2,
+       }, {
+               .name           = "4:2:2 packed, UYVY",
+               .fourcc         = V4L2_PIX_FMT_UYVY,
+               .depth          = 16,
+               .twformat       = ColorFormatYUY2 | ColorFormatBSWAP,
+       }
+};
+#define FORMATS ARRAY_SIZE(formats)
+
+#define NORM_625_50                    \
+               .h_delay        = 3,    \
+               .h_delay0       = 133,  \
+               .h_start        = 0,    \
+               .h_stop         = 719,  \
+               .v_delay        = 24,   \
+               .vbi_v_start_0  = 7,    \
+               .vbi_v_stop_0   = 22,   \
+               .video_v_start  = 24,   \
+               .video_v_stop   = 311,  \
+               .vbi_v_start_1  = 319
+
+#define NORM_525_60                    \
+               .h_delay        = 8,    \
+               .h_delay0       = 138,  \
+               .h_start        = 0,    \
+               .h_stop         = 719,  \
+               .v_delay        = 22,   \
+               .vbi_v_start_0  = 10,   \
+               .vbi_v_stop_0   = 21,   \
+               .video_v_start  = 22,   \
+               .video_v_stop   = 262,  \
+               .vbi_v_start_1  = 273
+
+/*
+ * The following table is searched by tw68_s_std, first for a specific
+ * match, then for an entry which contains the desired id.  The table
+ * entries should therefore be ordered in ascending order of specificity.
+ */
+static const struct tw68_tvnorm tvnorms[] = {
+       {
+               .name           = "PAL", /* autodetect */
+               .id             = V4L2_STD_PAL,
+               NORM_625_50,
+
+               .sync_control   = 0x18,
+               .luma_control   = 0x40,
+               .chroma_ctrl1   = 0x81,
+               .chroma_gain    = 0x2a,
+               .chroma_ctrl2   = 0x06,
+               .vgate_misc     = 0x1c,
+               .format         = VideoFormatPALBDGHI,
+       }, {
+               .name           = "NTSC",
+               .id             = V4L2_STD_NTSC,
+               NORM_525_60,
+
+               .sync_control   = 0x59,
+               .luma_control   = 0x40,
+               .chroma_ctrl1   = 0x89,
+               .chroma_gain    = 0x2a,
+               .chroma_ctrl2   = 0x0e,
+               .vgate_misc     = 0x18,
+               .format         = VideoFormatNTSC,
+       }, {
+               .name           = "SECAM",
+               .id             = V4L2_STD_SECAM,
+               NORM_625_50,
+
+               .sync_control   = 0x18,
+               .luma_control   = 0x1b,
+               .chroma_ctrl1   = 0xd1,
+               .chroma_gain    = 0x80,
+               .chroma_ctrl2   = 0x00,
+               .vgate_misc     = 0x1c,
+               .format         = VideoFormatSECAM,
+       }, {
+               .name           = "PAL-M",
+               .id             = V4L2_STD_PAL_M,
+               NORM_525_60,
+
+               .sync_control   = 0x59,
+               .luma_control   = 0x40,
+               .chroma_ctrl1   = 0xb9,
+               .chroma_gain    = 0x2a,
+               .chroma_ctrl2   = 0x0e,
+               .vgate_misc     = 0x18,
+               .format         = VideoFormatPALM,
+       }, {
+               .name           = "PAL-Nc",
+               .id             = V4L2_STD_PAL_Nc,
+               NORM_625_50,
+
+               .sync_control   = 0x18,
+               .luma_control   = 0x40,
+               .chroma_ctrl1   = 0xa1,
+               .chroma_gain    = 0x2a,
+               .chroma_ctrl2   = 0x06,
+               .vgate_misc     = 0x1c,
+               .format         = VideoFormatPALNC,
+       }, {
+               .name           = "PAL-60",
+               .id             = V4L2_STD_PAL_60,
+               .h_delay        = 186,
+               .h_start        = 0,
+               .h_stop         = 719,
+               .v_delay        = 26,
+               .video_v_start  = 23,
+               .video_v_stop   = 262,
+               .vbi_v_start_0  = 10,
+               .vbi_v_stop_0   = 21,
+               .vbi_v_start_1  = 273,
+
+               .sync_control   = 0x18,
+               .luma_control   = 0x40,
+               .chroma_ctrl1   = 0x81,
+               .chroma_gain    = 0x2a,
+               .chroma_ctrl2   = 0x06,
+               .vgate_misc     = 0x1c,
+               .format         = VideoFormatPAL60,
+       }
+};
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+static const struct tw68_format *format_by_fourcc(unsigned int fourcc)
+{
+       unsigned int i;
+
+       for (i = 0; i < FORMATS; i++)
+               if (formats[i].fourcc == fourcc)
+                       return formats+i;
+       return NULL;
+}
+
+
+/* ------------------------------------------------------------------ */
+/*
+ * Note that the cropping rectangles are described in terms of a single
+ * frame, i.e. line positions are only 1/2 the interlaced equivalent
+ */
+static void set_tvnorm(struct tw68_dev *dev, const struct tw68_tvnorm *norm)
+{
+       if (norm != dev->tvnorm) {
+               dev->width = 720;
+               dev->height = (norm->id & V4L2_STD_525_60) ? 480 : 576;
+               dev->tvnorm = norm;
+               tw68_set_tvnorm_hw(dev);
+       }
+}
+
+/*
+ * tw68_set_scale
+ *
+ * Scaling and Cropping for video decoding
+ *
+ * We are working with 3 values for horizontal and vertical - scale,
+ * delay and active.
+ *
+ * HACTIVE represent the actual number of pixels in the "usable" image,
+ * before scaling.  HDELAY represents the number of pixels skipped
+ * between the start of the horizontal sync and the start of the image.
+ * HSCALE is calculated using the formula
+ *     HSCALE = (HACTIVE / (#pixels desired)) * 256
+ *
+ * The vertical registers are similar, except based upon the total number
+ * of lines in the image, and the first line of the image (i.e. ignoring
+ * vertical sync and VBI).
+ *
+ * Note that the number of bytes reaching the FIFO (and hence needing
+ * to be processed by the DMAP program) is completely dependent upon
+ * these values, especially HSCALE.
+ *
+ * Parameters:
+ *     @dev            pointer to the device structure, needed for
+ *                     getting current norm (as well as debug print)
+ *     @width          actual image width (from user buffer)
+ *     @height         actual image height
+ *     @field          indicates Top, Bottom or Interlaced
+ */
+static int tw68_set_scale(struct tw68_dev *dev, unsigned int width,
+                         unsigned int height, enum v4l2_field field)
+{
+       const struct tw68_tvnorm *norm = dev->tvnorm;
+       /* set individually for debugging clarity */
+       int hactive, hdelay, hscale;
+       int vactive, vdelay, vscale;
+       int comb;
+
+       if (V4L2_FIELD_HAS_BOTH(field)) /* if field is interlaced */
+               height /= 2;            /* we must set for 1-frame */
+
+       pr_debug("%s: width=%d, height=%d, both=%d\n"
+                "  tvnorm h_delay=%d, h_start=%d, h_stop=%d, "
+                "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__,
+               width, height, V4L2_FIELD_HAS_BOTH(field),
+               norm->h_delay, norm->h_start, norm->h_stop,
+               norm->v_delay, norm->video_v_start,
+               norm->video_v_stop);
+
+       switch (dev->vdecoder) {
+       case TW6800:
+               hdelay = norm->h_delay0;
+               break;
+       default:
+               hdelay = norm->h_delay;
+               break;
+       }
+
+       hdelay += norm->h_start;
+       hactive = norm->h_stop - norm->h_start + 1;
+
+       hscale = (hactive * 256) / (width);
+
+       vdelay = norm->v_delay;
+       vactive = ((norm->id & V4L2_STD_525_60) ? 524 : 624) / 2 - norm->video_v_start;
+       vscale = (vactive * 256) / height;
+
+       pr_debug("%s: %dx%d [%s%s,%s]\n", __func__,
+               width, height,
+               V4L2_FIELD_HAS_TOP(field)    ? "T" : "",
+               V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
+               v4l2_norm_to_name(dev->tvnorm->id));
+       pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; "
+               "vactive=%d, vdelay=%d, vscale=%d\n", __func__,
+               hactive, hdelay, hscale, vactive, vdelay, vscale);
+
+       comb =  ((vdelay & 0x300)  >> 2) |
+               ((vactive & 0x300) >> 4) |
+               ((hdelay & 0x300)  >> 6) |
+               ((hactive & 0x300) >> 8);
+       pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, "
+               "VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n",
+               __func__, comb, vdelay, vactive, hdelay, hactive);
+       tw_writeb(TW68_CROP_HI, comb);
+       tw_writeb(TW68_VDELAY_LO, vdelay & 0xff);
+       tw_writeb(TW68_VACTIVE_LO, vactive & 0xff);
+       tw_writeb(TW68_HDELAY_LO, hdelay & 0xff);
+       tw_writeb(TW68_HACTIVE_LO, hactive & 0xff);
+
+       comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8);
+       pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, "
+               "HSCALE_LO=%02x\n", __func__, comb, vscale, hscale);
+       tw_writeb(TW68_SCALE_HI, comb);
+       tw_writeb(TW68_VSCALE_LO, vscale);
+       tw_writeb(TW68_HSCALE_LO, hscale);
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf)
+{
+       /* Set cropping and scaling */
+       tw68_set_scale(dev, dev->width, dev->height, dev->field);
+       /*
+        *  Set start address for RISC program.  Note that if the DMAP
+        *  processor is currently running, it must be stopped before
+        *  a new address can be set.
+        */
+       tw_clearl(TW68_DMAC, TW68_DMAP_EN);
+       tw_writel(TW68_DMAP_SA, buf->dma);
+       /* Clear any pending interrupts */
+       tw_writel(TW68_INTSTAT, dev->board_virqmask);
+       /* Enable the risc engine and the fifo */
+       tw_andorl(TW68_DMAC, 0xff, dev->fmt->twformat |
+               ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN);
+       dev->pci_irqmask |= dev->board_virqmask;
+       tw_setl(TW68_INTMASK, dev->pci_irqmask);
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+/* calc max # of buffers from size (must not exceed the 4MB virtual
+ * address space per DMA channel) */
+static int tw68_buffer_count(unsigned int size, unsigned int count)
+{
+       unsigned int maxcount;
+
+       maxcount = (4 * 1024 * 1024) / roundup(size, PAGE_SIZE);
+       if (count > maxcount)
+               count = maxcount;
+       return count;
+}
+
+/* ------------------------------------------------------------- */
+/* vb2 queue operations                                          */
+
+static int tw68_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+                          unsigned int *num_buffers, unsigned int *num_planes,
+                          unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct tw68_dev *dev = vb2_get_drv_priv(q);
+       unsigned tot_bufs = q->num_buffers + *num_buffers;
+
+       sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3;
+       /*
+        * We allow create_bufs, but only if the sizeimage is the same as the
+        * current sizeimage. The tw68_buffer_count calculation becomes quite
+        * difficult otherwise.
+        */
+       if (fmt && fmt->fmt.pix.sizeimage < sizes[0])
+               return -EINVAL;
+       *num_planes = 1;
+       if (tot_bufs < 2)
+               tot_bufs = 2;
+       tot_bufs = tw68_buffer_count(sizes[0], tot_bufs);
+       *num_buffers = tot_bufs - q->num_buffers;
+
+       return 0;
+}
+
+/*
+ * The risc program for each buffers works as follows: it starts with a simple
+ * 'JUMP to addr + 8', which is effectively a NOP. Then the program to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 8 (skipping
+ * the initial JUMP).
+ *
+ * This is the program of the first buffer to be queued if the active list is
+ * empty and it just keeps DMAing this buffer without generating any interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the program generates an
+ * interrupt as well which signals that the previous buffer has been DMAed
+ * successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
+static void tw68_buf_queue(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct tw68_dev *dev = vb2_get_drv_priv(vq);
+       struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
+       struct tw68_buf *prev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->slock, flags);
+
+       /* append a 'JUMP to start of buffer' to the buffer risc program */
+       buf->jmp[0] = cpu_to_le32(RISC_JUMP);
+       buf->jmp[1] = cpu_to_le32(buf->dma + 8);
+
+       if (!list_empty(&dev->active)) {
+               prev = list_entry(dev->active.prev, struct tw68_buf, list);
+               buf->cpu[0] |= cpu_to_le32(RISC_INT_BIT);
+               prev->jmp[1] = cpu_to_le32(buf->dma);
+       }
+       list_add_tail(&buf->list, &dev->active);
+       spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+/*
+ * buffer_prepare
+ *
+ * Set the ancilliary information into the buffer structure.  This
+ * includes generating the necessary risc program if it hasn't already
+ * been done for the current buffer format.
+ * The structure fh contains the details of the format requested by the
+ * user - type, width, height and #fields.  This is compared with the
+ * last format set for the current buffer.  If they differ, the risc
+ * code (which controls the filling of the buffer) is (re-)generated.
+ */
+static int tw68_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct tw68_dev *dev = vb2_get_drv_priv(vq);
+       struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
+       struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);
+       unsigned size, bpl;
+       int rc;
+
+       size = (dev->width * dev->height * dev->fmt->depth) >> 3;
+       if (vb2_plane_size(vb, 0) < size)
+               return -EINVAL;
+       vb2_set_plane_payload(vb, 0, size);
+
+       rc = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+       if (!rc)
+               return -EIO;
+
+       bpl = (dev->width * dev->fmt->depth) >> 3;
+       switch (dev->field) {
+       case V4L2_FIELD_TOP:
+               tw68_risc_buffer(dev->pci, buf, dma->sgl,
+                                0, UNSET, bpl, 0, dev->height);
+               break;
+       case V4L2_FIELD_BOTTOM:
+               tw68_risc_buffer(dev->pci, buf, dma->sgl,
+                                UNSET, 0, bpl, 0, dev->height);
+               break;
+       case V4L2_FIELD_SEQ_TB:
+               tw68_risc_buffer(dev->pci, buf, dma->sgl,
+                                0, bpl * (dev->height >> 1),
+                                bpl, 0, dev->height >> 1);
+               break;
+       case V4L2_FIELD_SEQ_BT:
+               tw68_risc_buffer(dev->pci, buf, dma->sgl,
+                                bpl * (dev->height >> 1), 0,
+                                bpl, 0, dev->height >> 1);
+               break;
+       case V4L2_FIELD_INTERLACED:
+       default:
+               tw68_risc_buffer(dev->pci, buf, dma->sgl,
+                                0, bpl, bpl, bpl, dev->height >> 1);
+               break;
+       }
+       return 0;
+}
+
+static void tw68_buf_finish(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct tw68_dev *dev = vb2_get_drv_priv(vq);
+       struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);
+       struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
+
+       dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+
+       pci_free_consistent(dev->pci, buf->size, buf->cpu, buf->dma);
+}
+
+static int tw68_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct tw68_dev *dev = vb2_get_drv_priv(q);
+       struct tw68_buf *buf =
+               container_of(dev->active.next, struct tw68_buf, list);
+
+       dev->seqnr = 0;
+       tw68_video_start_dma(dev, buf);
+       return 0;
+}
+
+static void tw68_stop_streaming(struct vb2_queue *q)
+{
+       struct tw68_dev *dev = vb2_get_drv_priv(q);
+
+       /* Stop risc & fifo */
+       tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
+       while (!list_empty(&dev->active)) {
+               struct tw68_buf *buf =
+                       container_of(dev->active.next, struct tw68_buf, list);
+
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+}
+
+static struct vb2_ops tw68_video_qops = {
+       .queue_setup    = tw68_queue_setup,
+       .buf_queue      = tw68_buf_queue,
+       .buf_prepare    = tw68_buf_prepare,
+       .buf_finish     = tw68_buf_finish,
+       .start_streaming = tw68_start_streaming,
+       .stop_streaming = tw68_stop_streaming,
+       .wait_prepare   = vb2_ops_wait_prepare,
+       .wait_finish    = vb2_ops_wait_finish,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int tw68_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct tw68_dev *dev =
+               container_of(ctrl->handler, struct tw68_dev, hdl);
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               tw_writeb(TW68_BRIGHT, ctrl->val);
+               break;
+       case V4L2_CID_HUE:
+               tw_writeb(TW68_HUE, ctrl->val);
+               break;
+       case V4L2_CID_CONTRAST:
+               tw_writeb(TW68_CONTRAST, ctrl->val);
+               break;
+       case V4L2_CID_SATURATION:
+               tw_writeb(TW68_SAT_U, ctrl->val);
+               tw_writeb(TW68_SAT_V, ctrl->val);
+               break;
+       case V4L2_CID_COLOR_KILLER:
+               if (ctrl->val)
+                       tw_andorb(TW68_MISC2, 0xe0, 0xe0);
+               else
+                       tw_andorb(TW68_MISC2, 0xe0, 0x00);
+               break;
+       case V4L2_CID_CHROMA_AGC:
+               if (ctrl->val)
+                       tw_andorb(TW68_LOOP, 0x30, 0x20);
+               else
+                       tw_andorb(TW68_LOOP, 0x30, 0x00);
+               break;
+       }
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * Note that this routine returns what is stored in the fh structure, and
+ * does not interrogate any of the device registers.
+ */
+static int tw68_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       f->fmt.pix.width        = dev->width;
+       f->fmt.pix.height       = dev->height;
+       f->fmt.pix.field        = dev->field;
+       f->fmt.pix.pixelformat  = dev->fmt->fourcc;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * (dev->fmt->depth)) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
+       f->fmt.pix.priv = 0;
+       return 0;
+}
+
+static int tw68_try_fmt_vid_cap(struct file *file, void *priv,
+                                               struct v4l2_format *f)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+       const struct tw68_format *fmt;
+       enum v4l2_field field;
+       unsigned int maxh;
+
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (NULL == fmt)
+               return -EINVAL;
+
+       field = f->fmt.pix.field;
+       maxh  = (dev->tvnorm->id & V4L2_STD_525_60) ? 480 : 576;
+
+       switch (field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+               break;
+       case V4L2_FIELD_INTERLACED:
+       case V4L2_FIELD_SEQ_BT:
+       case V4L2_FIELD_SEQ_TB:
+               maxh = maxh * 2;
+               break;
+       default:
+               field = (f->fmt.pix.height > maxh / 2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_BOTTOM;
+               break;
+       }
+
+       f->fmt.pix.field = field;
+       if (f->fmt.pix.width  < 48)
+               f->fmt.pix.width  = 48;
+       if (f->fmt.pix.height < 32)
+               f->fmt.pix.height = 32;
+       if (f->fmt.pix.width > 720)
+               f->fmt.pix.width = 720;
+       if (f->fmt.pix.height > maxh)
+               f->fmt.pix.height = maxh;
+       f->fmt.pix.width &= ~0x03;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * (fmt->depth)) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       return 0;
+}
+
+/*
+ * Note that tw68_s_fmt_vid_cap sets the information into the fh structure,
+ * and it will be used for all future new buffers.  However, there could be
+ * some number of buffers on the "active" chain which will be filled before
+ * the change takes place.
+ */
+static int tw68_s_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+       int err;
+
+       err = tw68_try_fmt_vid_cap(file, priv, f);
+       if (0 != err)
+               return err;
+
+       dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       dev->width = f->fmt.pix.width;
+       dev->height = f->fmt.pix.height;
+       dev->field = f->fmt.pix.field;
+       return 0;
+}
+
+static int tw68_enum_input(struct file *file, void *priv,
+                                       struct v4l2_input *i)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+       unsigned int n;
+
+       n = i->index;
+       if (n >= TW68_INPUT_MAX)
+               return -EINVAL;
+       i->index = n;
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+       snprintf(i->name, sizeof(i->name), "Composite %d", n);
+
+       /* If the query is for the current input, get live data */
+       if (n == dev->input) {
+               int v1 = tw_readb(TW68_STATUS1);
+               int v2 = tw_readb(TW68_MVSN);
+
+               if (0 != (v1 & (1 << 7)))
+                       i->status |= V4L2_IN_ST_NO_SYNC;
+               if (0 != (v1 & (1 << 6)))
+                       i->status |= V4L2_IN_ST_NO_H_LOCK;
+               if (0 != (v1 & (1 << 2)))
+                       i->status |= V4L2_IN_ST_NO_SIGNAL;
+               if (0 != (v1 & 1 << 1))
+                       i->status |= V4L2_IN_ST_NO_COLOR;
+               if (0 != (v2 & (1 << 2)))
+                       i->status |= V4L2_IN_ST_MACROVISION;
+       }
+       i->std = video_devdata(file)->tvnorms;
+       return 0;
+}
+
+static int tw68_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       *i = dev->input;
+       return 0;
+}
+
+static int tw68_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       if (i >= TW68_INPUT_MAX)
+               return -EINVAL;
+       dev->input = i;
+       tw_andorb(TW68_INFORM, 0x03 << 2, dev->input << 2);
+       return 0;
+}
+
+static int tw68_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       strcpy(cap->driver, "tw68");
+       strlcpy(cap->card, "Techwell Capture Card",
+               sizeof(cap->card));
+       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+       cap->device_caps =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_READWRITE |
+               V4L2_CAP_STREAMING;
+
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int tw68_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+       unsigned int i;
+
+       if (vb2_is_busy(&dev->vidq))
+               return -EBUSY;
+
+       /* Look for match on complete norm id (may have mult bits) */
+       for (i = 0; i < TVNORMS; i++) {
+               if (id == tvnorms[i].id)
+                       break;
+       }
+
+       /* If no exact match, look for norm which contains this one */
+       if (i == TVNORMS) {
+               for (i = 0; i < TVNORMS; i++)
+                       if (id & tvnorms[i].id)
+                               break;
+       }
+       /* If still not matched, give up */
+       if (i == TVNORMS)
+               return -EINVAL;
+
+       set_tvnorm(dev, &tvnorms[i]);   /* do the actual setting */
+       return 0;
+}
+
+static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       *id = dev->tvnorm->id;
+       return 0;
+}
+
+static int tw68_enum_fmt_vid_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (f->index >= FORMATS)
+               return -EINVAL;
+
+       strlcpy(f->description, formats[f->index].name,
+               sizeof(f->description));
+
+       f->pixelformat = formats[f->index].fourcc;
+
+       return 0;
+}
+
+/*
+ * Used strictly for internal development and debugging, this routine
+ * prints out the current register contents for the tw68xx device.
+ */
+static void tw68_dump_regs(struct tw68_dev *dev)
+{
+       unsigned char line[80];
+       int i, j, k;
+       unsigned char *cptr;
+
+       pr_info("Full dump of TW68 registers:\n");
+       /* First we do the PCI regs, 8 4-byte regs per line */
+       for (i = 0; i < 0x100; i += 32) {
+               cptr = line;
+               cptr += sprintf(cptr, "%03x  ", i);
+               /* j steps through the next 4 words */
+               for (j = i; j < i + 16; j += 4)
+                       cptr += sprintf(cptr, "%08x ", tw_readl(j));
+               *cptr++ = ' ';
+               for (; j < i + 32; j += 4)
+                       cptr += sprintf(cptr, "%08x ", tw_readl(j));
+               *cptr++ = '\n';
+               *cptr = 0;
+               pr_info("%s", line);
+       }
+       /* Next the control regs, which are single-byte, address mod 4 */
+       while (i < 0x400) {
+               cptr = line;
+               cptr += sprintf(cptr, "%03x ", i);
+               /* Print out 4 groups of 4 bytes */
+               for (j = 0; j < 4; j++) {
+                       for (k = 0; k < 4; k++) {
+                               cptr += sprintf(cptr, "%02x ",
+                                       tw_readb(i));
+                               i += 4;
+                       }
+                       *cptr++ = ' ';
+               }
+               *cptr++ = '\n';
+               *cptr = 0;
+               pr_info("%s", line);
+       }
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       tw68_dump_regs(dev);
+       return v4l2_ctrl_log_status(file, priv);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+                             struct v4l2_dbg_register *reg)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       if (reg->size == 1)
+               reg->val = tw_readb(reg->reg);
+       else
+               reg->val = tw_readl(reg->reg);
+       return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+                               const struct v4l2_dbg_register *reg)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       if (reg->size == 1)
+               tw_writeb(reg->reg, reg->val);
+       else
+               tw_writel(reg->reg & 0xffff, reg->val);
+       return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops tw68_ctrl_ops = {
+       .s_ctrl = tw68_s_ctrl,
+};
+
+static const struct v4l2_file_operations video_fops = {
+       .owner                  = THIS_MODULE,
+       .open                   = v4l2_fh_open,
+       .release                = vb2_fop_release,
+       .read                   = vb2_fop_read,
+       .poll                   = vb2_fop_poll,
+       .mmap                   = vb2_fop_mmap,
+       .unlocked_ioctl         = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+       .vidioc_querycap                = tw68_querycap,
+       .vidioc_enum_fmt_vid_cap        = tw68_enum_fmt_vid_cap,
+       .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
+       .vidioc_create_bufs             = vb2_ioctl_create_bufs,
+       .vidioc_querybuf                = vb2_ioctl_querybuf,
+       .vidioc_qbuf                    = vb2_ioctl_qbuf,
+       .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
+       .vidioc_s_std                   = tw68_s_std,
+       .vidioc_g_std                   = tw68_g_std,
+       .vidioc_enum_input              = tw68_enum_input,
+       .vidioc_g_input                 = tw68_g_input,
+       .vidioc_s_input                 = tw68_s_input,
+       .vidioc_streamon                = vb2_ioctl_streamon,
+       .vidioc_streamoff               = vb2_ioctl_streamoff,
+       .vidioc_g_fmt_vid_cap           = tw68_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap         = tw68_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap           = tw68_s_fmt_vid_cap,
+       .vidioc_log_status              = vidioc_log_status,
+       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register              = vidioc_g_register,
+       .vidioc_s_register              = vidioc_s_register,
+#endif
+};
+
+static struct video_device tw68_video_template = {
+       .name                   = "tw68_video",
+       .fops                   = &video_fops,
+       .ioctl_ops              = &video_ioctl_ops,
+       .release                = video_device_release_empty,
+       .tvnorms                = TW68_NORMS,
+};
+
+/* ------------------------------------------------------------------ */
+/* exported stuff                                                     */
+void tw68_set_tvnorm_hw(struct tw68_dev *dev)
+{
+       tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format);
+}
+
+int tw68_video_init1(struct tw68_dev *dev)
+{
+       struct v4l2_ctrl_handler *hdl = &dev->hdl;
+
+       v4l2_ctrl_handler_init(hdl, 6);
+       v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS, -128, 127, 1, 20);
+       v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+                       V4L2_CID_CONTRAST, 0, 255, 1, 100);
+       v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+                       V4L2_CID_SATURATION, 0, 255, 1, 128);
+       /* NTSC only */
+       v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+                       V4L2_CID_HUE, -128, 127, 1, 0);
+       v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+                       V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+                       V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);
+       if (hdl->error) {
+               v4l2_ctrl_handler_free(hdl);
+               return hdl->error;
+       }
+       dev->v4l2_dev.ctrl_handler = hdl;
+       v4l2_ctrl_handler_setup(hdl);
+       return 0;
+}
+
+int tw68_video_init2(struct tw68_dev *dev, int video_nr)
+{
+       int ret;
+
+       set_tvnorm(dev, &tvnorms[0]);
+
+       dev->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+       dev->width    = 720;
+       dev->height   = 576;
+       dev->field    = V4L2_FIELD_INTERLACED;
+
+       INIT_LIST_HEAD(&dev->active);
+       dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF;
+       dev->vidq.ops = &tw68_video_qops;
+       dev->vidq.mem_ops = &vb2_dma_sg_memops;
+       dev->vidq.drv_priv = dev;
+       dev->vidq.gfp_flags = __GFP_DMA32;
+       dev->vidq.buf_struct_size = sizeof(struct tw68_buf);
+       dev->vidq.lock = &dev->lock;
+       dev->vidq.min_buffers_needed = 2;
+       ret = vb2_queue_init(&dev->vidq);
+       if (ret)
+               return ret;
+       dev->vdev = tw68_video_template;
+       dev->vdev.v4l2_dev = &dev->v4l2_dev;
+       dev->vdev.lock = &dev->lock;
+       dev->vdev.queue = &dev->vidq;
+       video_set_drvdata(&dev->vdev, dev);
+       return video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr);
+}
+
+/*
+ * tw68_irq_video_done
+ */
+void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status)
+{
+       __u32 reg;
+
+       /* reset interrupts handled by this routine */
+       tw_writel(TW68_INTSTAT, status);
+       /*
+        * Check most likely first
+        *
+        * DMAPI shows we have reached the end of the risc code
+        * for the current buffer.
+        */
+       if (status & TW68_DMAPI) {
+               struct tw68_buf *buf;
+
+               spin_lock(&dev->slock);
+               buf = list_entry(dev->active.next, struct tw68_buf, list);
+               list_del(&buf->list);
+               spin_unlock(&dev->slock);
+               v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+               buf->vb.v4l2_buf.field = dev->field;
+               buf->vb.v4l2_buf.sequence = dev->seqnr++;
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+               status &= ~(TW68_DMAPI);
+               if (0 == status)
+                       return;
+       }
+       if (status & (TW68_VLOCK | TW68_HLOCK))
+               dev_dbg(&dev->pci->dev, "Lost sync\n");
+       if (status & TW68_PABORT)
+               dev_err(&dev->pci->dev, "PABORT interrupt\n");
+       if (status & TW68_DMAPERR)
+               dev_err(&dev->pci->dev, "DMAPERR interrupt\n");
+       /*
+        * On TW6800, FDMIS is apparently generated if video input is switched
+        * during operation.  Therefore, it is not enabled for that chip.
+        */
+       if (status & TW68_FDMIS)
+               dev_dbg(&dev->pci->dev, "FDMIS interrupt\n");
+       if (status & TW68_FFOF) {
+               /* probably a logic error */
+               reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN;
+               tw_clearl(TW68_DMAC, TW68_FIFO_EN);
+               dev_dbg(&dev->pci->dev, "FFOF interrupt\n");
+               tw_setl(TW68_DMAC, reg);
+       }
+       if (status & TW68_FFERR)
+               dev_dbg(&dev->pci->dev, "FFERR interrupt\n");
+}
diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h
new file mode 100644 (file)
index 0000000..2c8abe2
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ *  tw68 driver common header file
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) 2009  William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  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.
+ */
+
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/videodev2.h>
+#include <linux/notifier.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "tw68-reg.h"
+
+#define        UNSET   (-1U)
+
+/* system vendor and device ID's */
+#define        PCI_VENDOR_ID_TECHWELL  0x1797
+#define        PCI_DEVICE_ID_6800      0x6800
+#define        PCI_DEVICE_ID_6801      0x6801
+#define        PCI_DEVICE_ID_AUDIO2    0x6802
+#define        PCI_DEVICE_ID_TS3       0x6803
+#define        PCI_DEVICE_ID_6804      0x6804
+#define        PCI_DEVICE_ID_AUDIO5    0x6805
+#define        PCI_DEVICE_ID_TS6       0x6806
+
+/* tw6816 based cards */
+#define        PCI_DEVICE_ID_6816_1   0x6810
+#define        PCI_DEVICE_ID_6816_2   0x6811
+#define        PCI_DEVICE_ID_6816_3   0x6812
+#define        PCI_DEVICE_ID_6816_4   0x6813
+
+#define TW68_NORMS ( \
+       V4L2_STD_NTSC    | V4L2_STD_PAL       | V4L2_STD_SECAM    | \
+       V4L2_STD_PAL_M   | V4L2_STD_PAL_Nc    | V4L2_STD_PAL_60)
+
+#define        TW68_VID_INTS   (TW68_FFERR | TW68_PABORT | TW68_DMAPERR | \
+                        TW68_FFOF   | TW68_DMAPI)
+/* TW6800 chips have trouble with these, so we don't set them for that chip */
+#define        TW68_VID_INTSX  (TW68_FDMIS | TW68_HLOCK | TW68_VLOCK)
+
+#define        TW68_I2C_INTS   (TW68_SBERR | TW68_SBDONE | TW68_SBERR2  | \
+                        TW68_SBDONE2)
+
+enum tw68_decoder_type {
+       TW6800,
+       TW6801,
+       TW6804,
+       TWXXXX,
+};
+
+/* ----------------------------------------------------------- */
+/* static data                                                 */
+
+struct tw68_tvnorm {
+       char            *name;
+       v4l2_std_id     id;
+
+       /* video decoder */
+       u32     sync_control;
+       u32     luma_control;
+       u32     chroma_ctrl1;
+       u32     chroma_gain;
+       u32     chroma_ctrl2;
+       u32     vgate_misc;
+
+       /* video scaler */
+       u32     h_delay;
+       u32     h_delay0;       /* for TW6800 */
+       u32     h_start;
+       u32     h_stop;
+       u32     v_delay;
+       u32     video_v_start;
+       u32     video_v_stop;
+       u32     vbi_v_start_0;
+       u32     vbi_v_stop_0;
+       u32     vbi_v_start_1;
+
+       /* Techwell specific */
+       u32     format;
+};
+
+struct tw68_format {
+       char    *name;
+       u32     fourcc;
+       u32     depth;
+       u32     twformat;
+};
+
+/* ----------------------------------------------------------- */
+/* card configuration                                    */
+
+#define TW68_BOARD_NOAUTO              UNSET
+#define TW68_BOARD_UNKNOWN             0
+#define        TW68_BOARD_GENERIC_6802         1
+
+#define        TW68_MAXBOARDS                  16
+#define        TW68_INPUT_MAX                  4
+
+/* ----------------------------------------------------------- */
+/* device / file handle status                                 */
+
+#define        BUFFER_TIMEOUT  msecs_to_jiffies(500)   /* 0.5 seconds */
+
+struct tw68_dev;       /* forward delclaration */
+
+/* buffer for one video/vbi/ts frame */
+struct tw68_buf {
+       struct vb2_buffer vb;
+       struct list_head list;
+
+       unsigned int   size;
+       __le32         *cpu;
+       __le32         *jmp;
+       dma_addr_t     dma;
+};
+
+struct tw68_fmt {
+       char                    *name;
+       u32                     fourcc; /* v4l2 format id */
+       int                     depth;
+       int                     flags;
+       u32                     twformat;
+};
+
+/* global device status */
+struct tw68_dev {
+       struct mutex            lock;
+       spinlock_t              slock;
+       u16                     instance;
+       struct v4l2_device      v4l2_dev;
+
+       /* various device info */
+       enum tw68_decoder_type  vdecoder;
+       struct video_device     vdev;
+       struct v4l2_ctrl_handler hdl;
+
+       /* pci i/o */
+       char                    *name;
+       struct pci_dev          *pci;
+       unsigned char           pci_rev, pci_lat;
+       u32                     __iomem *lmmio;
+       u8                      __iomem *bmmio;
+       u32                     pci_irqmask;
+       /* The irq mask to be used will depend upon the chip type */
+       u32                     board_virqmask;
+
+       /* video capture */
+       const struct tw68_format *fmt;
+       unsigned                width, height;
+       unsigned                seqnr;
+       unsigned                field;
+       struct vb2_queue        vidq;
+       struct list_head        active;
+
+       /* various v4l controls */
+       const struct tw68_tvnorm *tvnorm;       /* video */
+
+       int                     input;
+};
+
+/* ----------------------------------------------------------- */
+
+#define tw_readl(reg)          readl(dev->lmmio + ((reg) >> 2))
+#define        tw_readb(reg)           readb(dev->bmmio + (reg))
+#define tw_writel(reg, value)  writel((value), dev->lmmio + ((reg) >> 2))
+#define        tw_writeb(reg, value)   writeb((value), dev->bmmio + (reg))
+
+#define tw_andorl(reg, mask, value) \
+               writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
+               ((value) & (mask)), dev->lmmio+((reg)>>2))
+#define        tw_andorb(reg, mask, value) \
+               writeb((readb(dev->bmmio + (reg)) & ~(mask)) |\
+               ((value) & (mask)), dev->bmmio+(reg))
+#define tw_setl(reg, bit)      tw_andorl((reg), (bit), (bit))
+#define        tw_setb(reg, bit)       tw_andorb((reg), (bit), (bit))
+#define        tw_clearl(reg, bit)     \
+               writel((readl(dev->lmmio + ((reg) >> 2)) & ~(bit)), \
+               dev->lmmio + ((reg) >> 2))
+#define        tw_clearb(reg, bit)     \
+               writeb((readb(dev->bmmio+(reg)) & ~(bit)), \
+               dev->bmmio + (reg))
+
+#define tw_wait(us) { udelay(us); }
+
+/* ----------------------------------------------------------- */
+/* tw68-video.c                                                */
+
+void tw68_set_tvnorm_hw(struct tw68_dev *dev);
+
+int tw68_video_init1(struct tw68_dev *dev);
+int tw68_video_init2(struct tw68_dev *dev, int video_nr);
+void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status);
+int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf);
+
+/* ----------------------------------------------------------- */
+/* tw68-risc.c                                                 */
+
+int tw68_risc_buffer(struct pci_dev *pci, struct tw68_buf *buf,
+       struct scatterlist *sglist, unsigned int top_offset,
+       unsigned int bottom_offset, unsigned int bpl,
+       unsigned int padding, unsigned int lines);
index bf34b93f23ee84fee373057778b1692059b58a84..b6801e035ea451c59800a95456425c249e14dd83 100644 (file)
@@ -682,7 +682,7 @@ set_videobus_dir (struct zoran *zr,
        switch (zr->card.type) {
        case LML33:
        case LML33R10:
-               if (lml33dpath == 0)
+               if (!lml33dpath)
                        GPIO(zr, 5, val);
                else
                        GPIO(zr, 5, 1);
index 6d86646d97433e2436435d52884e2e92ed1c2e33..bee9074ebc138b28a0b12bc38c398d720eadb463 100644 (file)
@@ -56,7 +56,8 @@ config VIDEO_VIU
 
 config VIDEO_TIMBERDALE
        tristate "Support for timberdale Video In/LogiWIN"
-       depends on MFD_TIMBERDALE && VIDEO_V4L2 && I2C && DMADEVICES
+       depends on VIDEO_V4L2 && I2C && DMADEVICES
+       depends on MFD_TIMBERDALE || COMPILE_TEST
        select DMA_ENGINE
        select TIMB_DMA
        select VIDEO_ADV7180
@@ -74,7 +75,8 @@ config VIDEO_VINO
 
 config VIDEO_M32R_AR
        tristate "AR devices"
-       depends on M32R && VIDEO_V4L2
+       depends on VIDEO_V4L2
+       depends on M32R || COMPILE_TEST
        ---help---
          This is a video4linux driver for the Renesas AR (Artificial Retina)
          camera module.
@@ -94,6 +96,7 @@ config VIDEO_M32R_AR_M64278
 config VIDEO_OMAP3
        tristate "OMAP 3 Camera support"
        depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3
+       depends on HAS_DMA
        select ARM_DMA_USE_IOMMU
        select OMAP_IOMMU
        select VIDEOBUF2_DMA_CONTIG
@@ -109,7 +112,9 @@ config VIDEO_OMAP3_DEBUG
 config VIDEO_S3C_CAMIF
        tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver"
        depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
-       depends on (ARCH_S3C64XX || PLAT_S3C24XX) && PM_RUNTIME
+       depends on PM_RUNTIME
+       depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera
@@ -140,6 +145,7 @@ if V4L_MEM2MEM_DRIVERS
 config VIDEO_CODA
        tristate "Chips&Media Coda multi-standard codec IP"
        depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MXC
+       depends on HAS_DMA
        select SRAM
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
@@ -151,6 +157,7 @@ config VIDEO_CODA
 config VIDEO_MEM2MEM_DEINTERLACE
        tristate "Deinterlace support"
        depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        help
@@ -158,7 +165,9 @@ config VIDEO_MEM2MEM_DEINTERLACE
 
 config VIDEO_SAMSUNG_S5P_G2D
        tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS)
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        default n
@@ -168,7 +177,9 @@ config VIDEO_SAMSUNG_S5P_G2D
 
 config VIDEO_SAMSUNG_S5P_JPEG
        tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS)
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        ---help---
@@ -177,7 +188,9 @@ config VIDEO_SAMSUNG_S5P_JPEG
 
 config VIDEO_SAMSUNG_S5P_MFC
        tristate "Samsung S5P MFC Video Codec"
-       depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS)
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        default n
        help
@@ -185,7 +198,9 @@ config VIDEO_SAMSUNG_S5P_MFC
 
 config VIDEO_MX2_EMMAPRP
        tristate "MX2 eMMa-PrP support"
-       depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on SOC_IMX27 || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        help
@@ -195,7 +210,9 @@ config VIDEO_MX2_EMMAPRP
 
 config VIDEO_SAMSUNG_EXYNOS_GSC
        tristate "Samsung Exynos G-Scaler driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_EXYNOS5
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on ARCH_EXYNOS5 || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        help
@@ -204,6 +221,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC
 config VIDEO_SH_VEU
        tristate "SuperH VEU mem2mem video processing driver"
        depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        help
@@ -213,6 +231,7 @@ config VIDEO_SH_VEU
 config VIDEO_RENESAS_VSP1
        tristate "Renesas VSP1 Video Processing Engine"
        depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA
+       depends on ARCH_SHMOBILE || COMPILE_TEST
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          This is a V4L2 driver for the Renesas VSP1 video processing engine.
@@ -222,7 +241,9 @@ config VIDEO_RENESAS_VSP1
 
 config VIDEO_TI_VPE
        tristate "TI VPE (Video Processing Engine) driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && SOC_DRA7XX
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on SOC_DRA7XX || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        default n
@@ -243,19 +264,8 @@ menuconfig V4L_TEST_DRIVERS
        depends on MEDIA_CAMERA_SUPPORT
 
 if V4L_TEST_DRIVERS
-config VIDEO_VIVI
-       tristate "Virtual Video Driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
-       select FONT_SUPPORT
-       select FONT_8x16
-       select VIDEOBUF2_VMALLOC
-       default n
-       ---help---
-         Enables a virtual video driver. This device shows a color bar
-         and a timestamp, as a real device would generate by using V4L2
-         api.
-         Say Y here if you want to test video apps or debug V4L devices.
-         In doubt, say N.
+
+source "drivers/media/platform/vivid/Kconfig"
 
 config VIDEO_MEM2MEM_TESTDEV
        tristate "Virtual test device for mem2mem framework"
index e5269da91906bd0dea8760e361bb1d599d48b626..579046bc276fd23298b8c298ef1a1d0da8c1fdea 100644 (file)
@@ -15,14 +15,14 @@ obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/
 obj-$(CONFIG_VIDEO_OMAP3)      += omap3isp/
 
 obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o
-obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 
+obj-$(CONFIG_VIDEO_VIVID)              += vivid/
 obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
 
 obj-$(CONFIG_VIDEO_TI_VPE)             += ti-vpe/
 
 obj-$(CONFIG_VIDEO_MX2_EMMAPRP)                += mx2_emmaprp.o
-obj-$(CONFIG_VIDEO_CODA)               += coda.o
+obj-$(CONFIG_VIDEO_CODA)               += coda/
 
 obj-$(CONFIG_VIDEO_SH_VEU)             += sh_veu.o
 
@@ -47,8 +47,6 @@ obj-$(CONFIG_SOC_CAMERA)              += soc_camera/
 
 obj-$(CONFIG_VIDEO_RENESAS_VSP1)       += vsp1/
 
-obj-y  += davinci/
-
-obj-$(CONFIG_ARCH_OMAP)        += omap/
+obj-y  += omap/
 
 ccflags-y += -I$(srctree)/drivers/media/i2c
index cc239972fa2c32283c4a9f523b2a6ba28d494adf..68fa90151b8f40f22146244ba1935cf7489ebdf6 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_BLACKFIN_CAPTURE
        tristate "Blackfin Video Capture Driver"
        depends on VIDEO_V4L2 && BLACKFIN && I2C
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        help
          V4L2 bridge driver for Blackfin video capture device.
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
deleted file mode 100644 (file)
index 3a6d1d2..0000000
+++ /dev/null
@@ -1,3933 +0,0 @@
-/*
- * Coda multi-standard codec IP
- *
- * Copyright (C) 2012 Vista Silicon S.L.
- *    Javier Martin, <javier.martin@vista-silicon.com>
- *    Xavier Duret
- *
- * 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/clk.h>
-#include <linux/debugfs.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/genalloc.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/kfifo.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/of.h>
-#include <linux/platform_data/coda.h>
-#include <linux/reset.h>
-
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/videobuf2-core.h>
-#include <media/videobuf2-dma-contig.h>
-
-#include "coda.h"
-
-#define CODA_NAME              "coda"
-
-#define CODADX6_MAX_INSTANCES  4
-
-#define CODA_PARA_BUF_SIZE     (10 * 1024)
-#define CODA_ISRAM_SIZE        (2048 * 2)
-
-#define CODA7_PS_BUF_SIZE      0x28000
-#define CODA9_PS_SAVE_SIZE     (512 * 1024)
-
-#define CODA_MAX_FRAMEBUFFERS  8
-
-#define CODA_MAX_FRAME_SIZE    0x100000
-#define FMO_SLICE_SAVE_BUF_SIZE         (32)
-#define CODA_DEFAULT_GAMMA             4096
-#define CODA9_DEFAULT_GAMMA            24576   /* 0.75 * 32768 */
-
-#define MIN_W 176
-#define MIN_H 144
-
-#define S_ALIGN                1 /* multiple of 2 */
-#define W_ALIGN                1 /* multiple of 2 */
-#define H_ALIGN                1 /* multiple of 2 */
-
-#define fh_to_ctx(__fh)        container_of(__fh, struct coda_ctx, fh)
-
-static int coda_debug;
-module_param(coda_debug, int, 0644);
-MODULE_PARM_DESC(coda_debug, "Debug level (0-1)");
-
-enum {
-       V4L2_M2M_SRC = 0,
-       V4L2_M2M_DST = 1,
-};
-
-enum coda_inst_type {
-       CODA_INST_ENCODER,
-       CODA_INST_DECODER,
-};
-
-enum coda_product {
-       CODA_DX6 = 0xf001,
-       CODA_7541 = 0xf012,
-       CODA_960 = 0xf020,
-};
-
-struct coda_fmt {
-       char *name;
-       u32 fourcc;
-};
-
-struct coda_codec {
-       u32 mode;
-       u32 src_fourcc;
-       u32 dst_fourcc;
-       u32 max_w;
-       u32 max_h;
-};
-
-struct coda_devtype {
-       char                    *firmware;
-       enum coda_product       product;
-       struct coda_codec       *codecs;
-       unsigned int            num_codecs;
-       size_t                  workbuf_size;
-       size_t                  tempbuf_size;
-       size_t                  iram_size;
-};
-
-/* Per-queue, driver-specific private data */
-struct coda_q_data {
-       unsigned int            width;
-       unsigned int            height;
-       unsigned int            bytesperline;
-       unsigned int            sizeimage;
-       unsigned int            fourcc;
-       struct v4l2_rect        rect;
-};
-
-struct coda_aux_buf {
-       void                    *vaddr;
-       dma_addr_t              paddr;
-       u32                     size;
-       struct debugfs_blob_wrapper blob;
-       struct dentry           *dentry;
-};
-
-struct coda_dev {
-       struct v4l2_device      v4l2_dev;
-       struct video_device     vfd;
-       struct platform_device  *plat_dev;
-       const struct coda_devtype *devtype;
-
-       void __iomem            *regs_base;
-       struct clk              *clk_per;
-       struct clk              *clk_ahb;
-       struct reset_control    *rstc;
-
-       struct coda_aux_buf     codebuf;
-       struct coda_aux_buf     tempbuf;
-       struct coda_aux_buf     workbuf;
-       struct gen_pool         *iram_pool;
-       struct coda_aux_buf     iram;
-
-       spinlock_t              irqlock;
-       struct mutex            dev_mutex;
-       struct mutex            coda_mutex;
-       struct workqueue_struct *workqueue;
-       struct v4l2_m2m_dev     *m2m_dev;
-       struct vb2_alloc_ctx    *alloc_ctx;
-       struct list_head        instances;
-       unsigned long           instance_mask;
-       struct dentry           *debugfs_root;
-};
-
-struct coda_params {
-       u8                      rot_mode;
-       u8                      h264_intra_qp;
-       u8                      h264_inter_qp;
-       u8                      h264_min_qp;
-       u8                      h264_max_qp;
-       u8                      h264_deblk_enabled;
-       u8                      h264_deblk_alpha;
-       u8                      h264_deblk_beta;
-       u8                      mpeg4_intra_qp;
-       u8                      mpeg4_inter_qp;
-       u8                      gop_size;
-       int                     intra_refresh;
-       int                     codec_mode;
-       int                     codec_mode_aux;
-       enum v4l2_mpeg_video_multi_slice_mode slice_mode;
-       u32                     framerate;
-       u16                     bitrate;
-       u32                     slice_max_bits;
-       u32                     slice_max_mb;
-};
-
-struct coda_iram_info {
-       u32             axi_sram_use;
-       phys_addr_t     buf_bit_use;
-       phys_addr_t     buf_ip_ac_dc_use;
-       phys_addr_t     buf_dbk_y_use;
-       phys_addr_t     buf_dbk_c_use;
-       phys_addr_t     buf_ovl_use;
-       phys_addr_t     buf_btp_use;
-       phys_addr_t     search_ram_paddr;
-       int             search_ram_size;
-       int             remaining;
-       phys_addr_t     next_paddr;
-};
-
-struct gdi_tiled_map {
-       int xy2ca_map[16];
-       int xy2ba_map[16];
-       int xy2ra_map[16];
-       int rbc2axi_map[32];
-       int xy2rbc_config;
-       int map_type;
-#define GDI_LINEAR_FRAME_MAP 0
-};
-
-struct coda_timestamp {
-       struct list_head        list;
-       u32                     sequence;
-       struct v4l2_timecode    timecode;
-       struct timeval          timestamp;
-};
-
-struct coda_ctx {
-       struct coda_dev                 *dev;
-       struct mutex                    buffer_mutex;
-       struct list_head                list;
-       struct work_struct              pic_run_work;
-       struct work_struct              seq_end_work;
-       struct completion               completion;
-       int                             aborting;
-       int                             initialized;
-       int                             streamon_out;
-       int                             streamon_cap;
-       u32                             isequence;
-       u32                             qsequence;
-       u32                             osequence;
-       u32                             sequence_offset;
-       struct coda_q_data              q_data[2];
-       enum coda_inst_type             inst_type;
-       struct coda_codec               *codec;
-       enum v4l2_colorspace            colorspace;
-       struct coda_params              params;
-       struct v4l2_ctrl_handler        ctrls;
-       struct v4l2_fh                  fh;
-       int                             gopcounter;
-       int                             runcounter;
-       char                            vpu_header[3][64];
-       int                             vpu_header_size[3];
-       struct kfifo                    bitstream_fifo;
-       struct mutex                    bitstream_mutex;
-       struct coda_aux_buf             bitstream;
-       bool                            hold;
-       struct coda_aux_buf             parabuf;
-       struct coda_aux_buf             psbuf;
-       struct coda_aux_buf             slicebuf;
-       struct coda_aux_buf             internal_frames[CODA_MAX_FRAMEBUFFERS];
-       u32                             frame_types[CODA_MAX_FRAMEBUFFERS];
-       struct coda_timestamp           frame_timestamps[CODA_MAX_FRAMEBUFFERS];
-       u32                             frame_errors[CODA_MAX_FRAMEBUFFERS];
-       struct list_head                timestamp_list;
-       struct coda_aux_buf             workbuf;
-       int                             num_internal_frames;
-       int                             idx;
-       int                             reg_idx;
-       struct coda_iram_info           iram_info;
-       struct gdi_tiled_map            tiled_map;
-       u32                             bit_stream_param;
-       u32                             frm_dis_flg;
-       u32                             frame_mem_ctrl;
-       int                             display_idx;
-       struct dentry                   *debugfs_entry;
-};
-
-static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff,
-                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 };
-static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 };
-
-static inline void coda_write(struct coda_dev *dev, u32 data, u32 reg)
-{
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
-       writel(data, dev->regs_base + reg);
-}
-
-static inline unsigned int coda_read(struct coda_dev *dev, u32 reg)
-{
-       u32 data;
-       data = readl(dev->regs_base + reg);
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
-       return data;
-}
-
-static inline unsigned long coda_isbusy(struct coda_dev *dev)
-{
-       return coda_read(dev, CODA_REG_BIT_BUSY);
-}
-
-static inline int coda_is_initialized(struct coda_dev *dev)
-{
-       return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0);
-}
-
-static int coda_wait_timeout(struct coda_dev *dev)
-{
-       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-
-       while (coda_isbusy(dev)) {
-               if (time_after(jiffies, timeout))
-                       return -ETIMEDOUT;
-       }
-       return 0;
-}
-
-static void coda_command_async(struct coda_ctx *ctx, int cmd)
-{
-       struct coda_dev *dev = ctx->dev;
-
-       if (dev->devtype->product == CODA_960 ||
-           dev->devtype->product == CODA_7541) {
-               /* Restore context related registers to CODA */
-               coda_write(dev, ctx->bit_stream_param,
-                               CODA_REG_BIT_BIT_STREAM_PARAM);
-               coda_write(dev, ctx->frm_dis_flg,
-                               CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
-               coda_write(dev, ctx->frame_mem_ctrl,
-                               CODA_REG_BIT_FRAME_MEM_CTRL);
-               coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
-       }
-
-       if (dev->devtype->product == CODA_960) {
-               coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR);
-               coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
-       }
-
-       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
-
-       coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
-       coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
-       coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD);
-
-       coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
-}
-
-static int coda_command_sync(struct coda_ctx *ctx, int cmd)
-{
-       struct coda_dev *dev = ctx->dev;
-
-       coda_command_async(ctx, cmd);
-       return coda_wait_timeout(dev);
-}
-
-static int coda_hw_reset(struct coda_ctx *ctx)
-{
-       struct coda_dev *dev = ctx->dev;
-       unsigned long timeout;
-       unsigned int idx;
-       int ret;
-
-       if (!dev->rstc)
-               return -ENOENT;
-
-       idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX);
-
-       timeout = jiffies + msecs_to_jiffies(100);
-       coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL);
-       while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) {
-               if (time_after(jiffies, timeout))
-                       return -ETIME;
-               cpu_relax();
-       }
-
-       ret = reset_control_reset(dev->rstc);
-       if (ret < 0)
-               return ret;
-
-       coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL);
-       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
-       coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
-       ret = coda_wait_timeout(dev);
-       coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX);
-
-       return ret;
-}
-
-static struct coda_q_data *get_q_data(struct coda_ctx *ctx,
-                                        enum v4l2_buf_type type)
-{
-       switch (type) {
-       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-               return &(ctx->q_data[V4L2_M2M_SRC]);
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               return &(ctx->q_data[V4L2_M2M_DST]);
-       default:
-               return NULL;
-       }
-}
-
-/*
- * Array of all formats supported by any version of Coda:
- */
-static struct coda_fmt coda_formats[] = {
-       {
-               .name = "YUV 4:2:0 Planar, YCbCr",
-               .fourcc = V4L2_PIX_FMT_YUV420,
-       },
-       {
-               .name = "YUV 4:2:0 Planar, YCrCb",
-               .fourcc = V4L2_PIX_FMT_YVU420,
-       },
-       {
-               .name = "H264 Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_H264,
-       },
-       {
-               .name = "MPEG4 Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_MPEG4,
-       },
-};
-
-#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \
-       { mode, src_fourcc, dst_fourcc, max_w, max_h }
-
-/*
- * Arrays of codecs supported by each given version of Coda:
- *  i.MX27 -> codadx6
- *  i.MX5x -> coda7
- *  i.MX6  -> coda960
- * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants
- */
-static struct coda_codec codadx6_codecs[] = {
-       CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,  720, 576),
-       CODA_CODEC(CODADX6_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576),
-};
-
-static struct coda_codec coda7_codecs[] = {
-       CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1280, 720),
-       CODA_CODEC(CODA7_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1280, 720),
-       CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1080),
-       CODA_CODEC(CODA7_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1080),
-};
-
-static struct coda_codec coda9_codecs[] = {
-       CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1920, 1080),
-       CODA_CODEC(CODA9_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1920, 1080),
-       CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1080),
-       CODA_CODEC(CODA9_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1080),
-};
-
-static bool coda_format_is_yuv(u32 fourcc)
-{
-       switch (fourcc) {
-       case V4L2_PIX_FMT_YUV420:
-       case V4L2_PIX_FMT_YVU420:
-               return true;
-       default:
-               return false;
-       }
-}
-
-/*
- * Normalize all supported YUV 4:2:0 formats to the value used in the codec
- * tables.
- */
-static u32 coda_format_normalize_yuv(u32 fourcc)
-{
-       return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc;
-}
-
-static struct coda_codec *coda_find_codec(struct coda_dev *dev, int src_fourcc,
-                                         int dst_fourcc)
-{
-       struct coda_codec *codecs = dev->devtype->codecs;
-       int num_codecs = dev->devtype->num_codecs;
-       int k;
-
-       src_fourcc = coda_format_normalize_yuv(src_fourcc);
-       dst_fourcc = coda_format_normalize_yuv(dst_fourcc);
-       if (src_fourcc == dst_fourcc)
-               return NULL;
-
-       for (k = 0; k < num_codecs; k++) {
-               if (codecs[k].src_fourcc == src_fourcc &&
-                   codecs[k].dst_fourcc == dst_fourcc)
-                       break;
-       }
-
-       if (k == num_codecs)
-               return NULL;
-
-       return &codecs[k];
-}
-
-static void coda_get_max_dimensions(struct coda_dev *dev,
-                                   struct coda_codec *codec,
-                                   int *max_w, int *max_h)
-{
-       struct coda_codec *codecs = dev->devtype->codecs;
-       int num_codecs = dev->devtype->num_codecs;
-       unsigned int w, h;
-       int k;
-
-       if (codec) {
-               w = codec->max_w;
-               h = codec->max_h;
-       } else {
-               for (k = 0, w = 0, h = 0; k < num_codecs; k++) {
-                       w = max(w, codecs[k].max_w);
-                       h = max(h, codecs[k].max_h);
-               }
-       }
-
-       if (max_w)
-               *max_w = w;
-       if (max_h)
-               *max_h = h;
-}
-
-static char *coda_product_name(int product)
-{
-       static char buf[9];
-
-       switch (product) {
-       case CODA_DX6:
-               return "CodaDx6";
-       case CODA_7541:
-               return "CODA7541";
-       case CODA_960:
-               return "CODA960";
-       default:
-               snprintf(buf, sizeof(buf), "(0x%04x)", product);
-               return buf;
-       }
-}
-
-/*
- * V4L2 ioctl() operations.
- */
-static int coda_querycap(struct file *file, void *priv,
-                        struct v4l2_capability *cap)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-
-       strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
-       strlcpy(cap->card, coda_product_name(ctx->dev->devtype->product),
-               sizeof(cap->card));
-       strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info));
-       /*
-        * This is only a mem-to-mem video device. The capture and output
-        * device capability flags are left only for backward compatibility
-        * and are scheduled for removal.
-        */
-       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
-                          V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
-       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
-       return 0;
-}
-
-static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
-                       enum v4l2_buf_type type, int src_fourcc)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       struct coda_codec *codecs = ctx->dev->devtype->codecs;
-       struct coda_fmt *formats = coda_formats;
-       struct coda_fmt *fmt;
-       int num_codecs = ctx->dev->devtype->num_codecs;
-       int num_formats = ARRAY_SIZE(coda_formats);
-       int i, k, num = 0;
-
-       for (i = 0; i < num_formats; i++) {
-               /* Both uncompressed formats are always supported */
-               if (coda_format_is_yuv(formats[i].fourcc) &&
-                   !coda_format_is_yuv(src_fourcc)) {
-                       if (num == f->index)
-                               break;
-                       ++num;
-                       continue;
-               }
-               /* Compressed formats may be supported, check the codec list */
-               for (k = 0; k < num_codecs; k++) {
-                       /* if src_fourcc is set, only consider matching codecs */
-                       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                           formats[i].fourcc == codecs[k].dst_fourcc &&
-                           (!src_fourcc || src_fourcc == codecs[k].src_fourcc))
-                               break;
-                       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-                           formats[i].fourcc == codecs[k].src_fourcc)
-                               break;
-               }
-               if (k < num_codecs) {
-                       if (num == f->index)
-                               break;
-                       ++num;
-               }
-       }
-
-       if (i < num_formats) {
-               fmt = &formats[i];
-               strlcpy(f->description, fmt->name, sizeof(f->description));
-               f->pixelformat = fmt->fourcc;
-               if (!coda_format_is_yuv(fmt->fourcc))
-                       f->flags |= V4L2_FMT_FLAG_COMPRESSED;
-               return 0;
-       }
-
-       /* Format not found */
-       return -EINVAL;
-}
-
-static int coda_enum_fmt_vid_cap(struct file *file, void *priv,
-                                struct v4l2_fmtdesc *f)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       struct vb2_queue *src_vq;
-       struct coda_q_data *q_data_src;
-
-       /* If the source format is already fixed, only list matching formats */
-       src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       if (vb2_is_streaming(src_vq)) {
-               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-
-               return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                               q_data_src->fourcc);
-       }
-
-       return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0);
-}
-
-static int coda_enum_fmt_vid_out(struct file *file, void *priv,
-                                struct v4l2_fmtdesc *f)
-{
-       return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0);
-}
-
-static int coda_g_fmt(struct file *file, void *priv,
-                     struct v4l2_format *f)
-{
-       struct coda_q_data *q_data;
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-
-       q_data = get_q_data(ctx, f->type);
-       if (!q_data)
-               return -EINVAL;
-
-       f->fmt.pix.field        = V4L2_FIELD_NONE;
-       f->fmt.pix.pixelformat  = q_data->fourcc;
-       f->fmt.pix.width        = q_data->width;
-       f->fmt.pix.height       = q_data->height;
-       f->fmt.pix.bytesperline = q_data->bytesperline;
-
-       f->fmt.pix.sizeimage    = q_data->sizeimage;
-       f->fmt.pix.colorspace   = ctx->colorspace;
-
-       return 0;
-}
-
-static int coda_try_fmt(struct coda_ctx *ctx, struct coda_codec *codec,
-                       struct v4l2_format *f)
-{
-       struct coda_dev *dev = ctx->dev;
-       struct coda_q_data *q_data;
-       unsigned int max_w, max_h;
-       enum v4l2_field field;
-
-       field = f->fmt.pix.field;
-       if (field == V4L2_FIELD_ANY)
-               field = V4L2_FIELD_NONE;
-       else if (V4L2_FIELD_NONE != field)
-               return -EINVAL;
-
-       /* V4L2 specification suggests the driver corrects the format struct
-        * if any of the dimensions is unsupported */
-       f->fmt.pix.field = field;
-
-       coda_get_max_dimensions(dev, codec, &max_w, &max_h);
-       v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w, W_ALIGN,
-                             &f->fmt.pix.height, MIN_H, max_h, H_ALIGN,
-                             S_ALIGN);
-
-       switch (f->fmt.pix.pixelformat) {
-       case V4L2_PIX_FMT_YUV420:
-       case V4L2_PIX_FMT_YVU420:
-       case V4L2_PIX_FMT_H264:
-       case V4L2_PIX_FMT_MPEG4:
-       case V4L2_PIX_FMT_JPEG:
-               break;
-       default:
-               q_data = get_q_data(ctx, f->type);
-               if (!q_data)
-                       return -EINVAL;
-               f->fmt.pix.pixelformat = q_data->fourcc;
-       }
-
-       switch (f->fmt.pix.pixelformat) {
-       case V4L2_PIX_FMT_YUV420:
-       case V4L2_PIX_FMT_YVU420:
-               /* Frame stride must be multiple of 8, but 16 for h.264 */
-               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
-               f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
-                                       f->fmt.pix.height * 3 / 2;
-               break;
-       case V4L2_PIX_FMT_H264:
-       case V4L2_PIX_FMT_MPEG4:
-       case V4L2_PIX_FMT_JPEG:
-               f->fmt.pix.bytesperline = 0;
-               f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
-               break;
-       default:
-               BUG();
-       }
-
-       return 0;
-}
-
-static int coda_try_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       struct coda_codec *codec;
-       struct vb2_queue *src_vq;
-       int ret;
-
-       /*
-        * If the source format is already fixed, try to find a codec that
-        * converts to the given destination format
-        */
-       src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       if (vb2_is_streaming(src_vq)) {
-               struct coda_q_data *q_data_src;
-
-               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-               codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
-                                       f->fmt.pix.pixelformat);
-               if (!codec)
-                       return -EINVAL;
-       } else {
-               /* Otherwise determine codec by encoded format, if possible */
-               codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
-                                       f->fmt.pix.pixelformat);
-       }
-
-       f->fmt.pix.colorspace = ctx->colorspace;
-
-       ret = coda_try_fmt(ctx, codec, f);
-       if (ret < 0)
-               return ret;
-
-       /* The h.264 decoder only returns complete 16x16 macroblocks */
-       if (codec && codec->src_fourcc == V4L2_PIX_FMT_H264) {
-               f->fmt.pix.width = f->fmt.pix.width;
-               f->fmt.pix.height = round_up(f->fmt.pix.height, 16);
-               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
-               f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
-                                      f->fmt.pix.height * 3 / 2;
-       }
-
-       return 0;
-}
-
-static int coda_try_fmt_vid_out(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       struct coda_codec *codec;
-
-       /* Determine codec by encoded format, returns NULL if raw or invalid */
-       codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat,
-                               V4L2_PIX_FMT_YUV420);
-
-       if (!f->fmt.pix.colorspace)
-               f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
-
-       return coda_try_fmt(ctx, codec, f);
-}
-
-static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
-{
-       struct coda_q_data *q_data;
-       struct vb2_queue *vq;
-
-       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
-       if (!vq)
-               return -EINVAL;
-
-       q_data = get_q_data(ctx, f->type);
-       if (!q_data)
-               return -EINVAL;
-
-       if (vb2_is_busy(vq)) {
-               v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
-               return -EBUSY;
-       }
-
-       q_data->fourcc = f->fmt.pix.pixelformat;
-       q_data->width = f->fmt.pix.width;
-       q_data->height = f->fmt.pix.height;
-       q_data->bytesperline = f->fmt.pix.bytesperline;
-       q_data->sizeimage = f->fmt.pix.sizeimage;
-       q_data->rect.left = 0;
-       q_data->rect.top = 0;
-       q_data->rect.width = f->fmt.pix.width;
-       q_data->rect.height = f->fmt.pix.height;
-
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-               "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
-               f->type, q_data->width, q_data->height, q_data->fourcc);
-
-       return 0;
-}
-
-static int coda_s_fmt_vid_cap(struct file *file, void *priv,
-                             struct v4l2_format *f)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       int ret;
-
-       ret = coda_try_fmt_vid_cap(file, priv, f);
-       if (ret)
-               return ret;
-
-       return coda_s_fmt(ctx, f);
-}
-
-static int coda_s_fmt_vid_out(struct file *file, void *priv,
-                             struct v4l2_format *f)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       int ret;
-
-       ret = coda_try_fmt_vid_out(file, priv, f);
-       if (ret)
-               return ret;
-
-       ret = coda_s_fmt(ctx, f);
-       if (ret)
-               ctx->colorspace = f->fmt.pix.colorspace;
-
-       return ret;
-}
-
-static int coda_qbuf(struct file *file, void *priv,
-                    struct v4l2_buffer *buf)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-
-       return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf);
-}
-
-static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
-                                     struct v4l2_buffer *buf)
-{
-       struct vb2_queue *src_vq;
-
-       src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-
-       return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) &&
-               (buf->sequence == (ctx->qsequence - 1)));
-}
-
-static int coda_dqbuf(struct file *file, void *priv,
-                     struct v4l2_buffer *buf)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       int ret;
-
-       ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf);
-
-       /* If this is the last capture buffer, emit an end-of-stream event */
-       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-           coda_buf_is_end_of_stream(ctx, buf)) {
-               const struct v4l2_event eos_event = {
-                       .type = V4L2_EVENT_EOS
-               };
-
-               v4l2_event_queue_fh(&ctx->fh, &eos_event);
-       }
-
-       return ret;
-}
-
-static int coda_g_selection(struct file *file, void *fh,
-                           struct v4l2_selection *s)
-{
-       struct coda_ctx *ctx = fh_to_ctx(fh);
-       struct coda_q_data *q_data;
-       struct v4l2_rect r, *rsel;
-
-       q_data = get_q_data(ctx, s->type);
-       if (!q_data)
-               return -EINVAL;
-
-       r.left = 0;
-       r.top = 0;
-       r.width = q_data->width;
-       r.height = q_data->height;
-       rsel = &q_data->rect;
-
-       switch (s->target) {
-       case V4L2_SEL_TGT_CROP_DEFAULT:
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-               rsel = &r;
-               /* fallthrough */
-       case V4L2_SEL_TGT_CROP:
-               if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-                       return -EINVAL;
-               break;
-       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
-       case V4L2_SEL_TGT_COMPOSE_PADDED:
-               rsel = &r;
-               /* fallthrough */
-       case V4L2_SEL_TGT_COMPOSE:
-       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
-               if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       s->r = *rsel;
-
-       return 0;
-}
-
-static int coda_try_decoder_cmd(struct file *file, void *fh,
-                               struct v4l2_decoder_cmd *dc)
-{
-       if (dc->cmd != V4L2_DEC_CMD_STOP)
-               return -EINVAL;
-
-       if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
-               return -EINVAL;
-
-       if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
-               return -EINVAL;
-
-       return 0;
-}
-
-static int coda_decoder_cmd(struct file *file, void *fh,
-                           struct v4l2_decoder_cmd *dc)
-{
-       struct coda_ctx *ctx = fh_to_ctx(fh);
-       struct coda_dev *dev = ctx->dev;
-       int ret;
-
-       ret = coda_try_decoder_cmd(file, fh, dc);
-       if (ret < 0)
-               return ret;
-
-       /* Ignore decoder stop command silently in encoder context */
-       if (ctx->inst_type != CODA_INST_DECODER)
-               return 0;
-
-       /* Set the strem-end flag on this context */
-       ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
-
-       if ((dev->devtype->product == CODA_960) &&
-           coda_isbusy(dev) &&
-           (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
-               /* If this context is currently running, update the hardware flag */
-               coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM);
-       }
-       ctx->hold = false;
-       v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
-
-       return 0;
-}
-
-static int coda_subscribe_event(struct v4l2_fh *fh,
-                               const struct v4l2_event_subscription *sub)
-{
-       switch (sub->type) {
-       case V4L2_EVENT_EOS:
-               return v4l2_event_subscribe(fh, sub, 0, NULL);
-       default:
-               return v4l2_ctrl_subscribe_event(fh, sub);
-       }
-}
-
-static const struct v4l2_ioctl_ops coda_ioctl_ops = {
-       .vidioc_querycap        = coda_querycap,
-
-       .vidioc_enum_fmt_vid_cap = coda_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap   = coda_g_fmt,
-       .vidioc_try_fmt_vid_cap = coda_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap   = coda_s_fmt_vid_cap,
-
-       .vidioc_enum_fmt_vid_out = coda_enum_fmt_vid_out,
-       .vidioc_g_fmt_vid_out   = coda_g_fmt,
-       .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out,
-       .vidioc_s_fmt_vid_out   = coda_s_fmt_vid_out,
-
-       .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
-       .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
-
-       .vidioc_qbuf            = coda_qbuf,
-       .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
-       .vidioc_dqbuf           = coda_dqbuf,
-       .vidioc_create_bufs     = v4l2_m2m_ioctl_create_bufs,
-
-       .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
-       .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
-
-       .vidioc_g_selection     = coda_g_selection,
-
-       .vidioc_try_decoder_cmd = coda_try_decoder_cmd,
-       .vidioc_decoder_cmd     = coda_decoder_cmd,
-
-       .vidioc_subscribe_event = coda_subscribe_event,
-       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static int coda_start_decoding(struct coda_ctx *ctx);
-
-static inline int coda_get_bitstream_payload(struct coda_ctx *ctx)
-{
-       return kfifo_len(&ctx->bitstream_fifo);
-}
-
-static void coda_kfifo_sync_from_device(struct coda_ctx *ctx)
-{
-       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
-       struct coda_dev *dev = ctx->dev;
-       u32 rd_ptr;
-
-       rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
-       kfifo->out = (kfifo->in & ~kfifo->mask) |
-                     (rd_ptr - ctx->bitstream.paddr);
-       if (kfifo->out > kfifo->in)
-               kfifo->out -= kfifo->mask + 1;
-}
-
-static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx)
-{
-       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
-       struct coda_dev *dev = ctx->dev;
-       u32 rd_ptr, wr_ptr;
-
-       rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask);
-       coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
-       wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
-       coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
-}
-
-static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx)
-{
-       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
-       struct coda_dev *dev = ctx->dev;
-       u32 wr_ptr;
-
-       wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
-       coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
-}
-
-static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf)
-{
-       u32 src_size = vb2_get_plane_payload(src_buf, 0);
-       u32 n;
-
-       n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size);
-       if (n < src_size)
-               return -ENOSPC;
-
-       dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr,
-                                  ctx->bitstream.size, DMA_TO_DEVICE);
-
-       src_buf->v4l2_buf.sequence = ctx->qsequence++;
-
-       return 0;
-}
-
-static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
-                                    struct vb2_buffer *src_buf)
-{
-       int ret;
-
-       if (coda_get_bitstream_payload(ctx) +
-           vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size)
-               return false;
-
-       if (vb2_plane_vaddr(src_buf, 0) == NULL) {
-               v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n");
-               return true;
-       }
-
-       ret = coda_bitstream_queue(ctx, src_buf);
-       if (ret < 0) {
-               v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n");
-               return false;
-       }
-       /* Sync read pointer to device */
-       if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
-               coda_kfifo_sync_to_device_write(ctx);
-
-       ctx->hold = false;
-
-       return true;
-}
-
-static void coda_fill_bitstream(struct coda_ctx *ctx)
-{
-       struct vb2_buffer *src_buf;
-       struct coda_timestamp *ts;
-
-       while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
-               src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
-
-               if (coda_bitstream_try_queue(ctx, src_buf)) {
-                       /*
-                        * Source buffer is queued in the bitstream ringbuffer;
-                        * queue the timestamp and mark source buffer as done
-                        */
-                       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
-
-                       ts = kmalloc(sizeof(*ts), GFP_KERNEL);
-                       if (ts) {
-                               ts->sequence = src_buf->v4l2_buf.sequence;
-                               ts->timecode = src_buf->v4l2_buf.timecode;
-                               ts->timestamp = src_buf->v4l2_buf.timestamp;
-                               list_add_tail(&ts->list, &ctx->timestamp_list);
-                       }
-
-                       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
-               } else {
-                       break;
-               }
-       }
-}
-
-static void coda_set_gdi_regs(struct coda_ctx *ctx)
-{
-       struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
-       struct coda_dev *dev = ctx->dev;
-       int i;
-
-       for (i = 0; i < 16; i++)
-               coda_write(dev, tiled_map->xy2ca_map[i],
-                               CODA9_GDI_XY2_CAS_0 + 4 * i);
-       for (i = 0; i < 4; i++)
-               coda_write(dev, tiled_map->xy2ba_map[i],
-                               CODA9_GDI_XY2_BA_0 + 4 * i);
-       for (i = 0; i < 16; i++)
-               coda_write(dev, tiled_map->xy2ra_map[i],
-                               CODA9_GDI_XY2_RAS_0 + 4 * i);
-       coda_write(dev, tiled_map->xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG);
-       for (i = 0; i < 32; i++)
-               coda_write(dev, tiled_map->rbc2axi_map[i],
-                               CODA9_GDI_RBC2_AXI_0 + 4 * i);
-}
-
-/*
- * Mem-to-mem operations.
- */
-static int coda_prepare_decode(struct coda_ctx *ctx)
-{
-       struct vb2_buffer *dst_buf;
-       struct coda_dev *dev = ctx->dev;
-       struct coda_q_data *q_data_dst;
-       u32 stridey, height;
-       u32 picture_y, picture_cb, picture_cr;
-
-       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-
-       if (ctx->params.rot_mode & CODA_ROT_90) {
-               stridey = q_data_dst->height;
-               height = q_data_dst->width;
-       } else {
-               stridey = q_data_dst->width;
-               height = q_data_dst->height;
-       }
-
-       /* Try to copy source buffer contents into the bitstream ringbuffer */
-       mutex_lock(&ctx->bitstream_mutex);
-       coda_fill_bitstream(ctx);
-       mutex_unlock(&ctx->bitstream_mutex);
-
-       if (coda_get_bitstream_payload(ctx) < 512 &&
-           (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                        "bitstream payload: %d, skipping\n",
-                        coda_get_bitstream_payload(ctx));
-               v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
-               return -EAGAIN;
-       }
-
-       /* Run coda_start_decoding (again) if not yet initialized */
-       if (!ctx->initialized) {
-               int ret = coda_start_decoding(ctx);
-               if (ret < 0) {
-                       v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
-                       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
-                       return -EAGAIN;
-               } else {
-                       ctx->initialized = 1;
-               }
-       }
-
-       if (dev->devtype->product == CODA_960)
-               coda_set_gdi_regs(ctx);
-
-       /* Set rotator output */
-       picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
-       if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) {
-               /* Switch Cr and Cb for YVU420 format */
-               picture_cr = picture_y + stridey * height;
-               picture_cb = picture_cr + stridey / 2 * height / 2;
-       } else {
-               picture_cb = picture_y + stridey * height;
-               picture_cr = picture_cb + stridey / 2 * height / 2;
-       }
-
-       if (dev->devtype->product == CODA_960) {
-               /*
-                * The CODA960 seems to have an internal list of buffers with
-                * 64 entries that includes the registered frame buffers as
-                * well as the rotator buffer output.
-                * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames.
-                */
-               coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index,
-                               CODA9_CMD_DEC_PIC_ROT_INDEX);
-               coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y);
-               coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB);
-               coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR);
-               coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE);
-       } else {
-               coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y);
-               coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB);
-               coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR);
-               coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE);
-       }
-       coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
-                       CODA_CMD_DEC_PIC_ROT_MODE);
-
-       switch (dev->devtype->product) {
-       case CODA_DX6:
-               /* TBD */
-       case CODA_7541:
-               coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION);
-               break;
-       case CODA_960:
-               coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); /* 'hardcode to use interrupt disable mode'? */
-               break;
-       }
-
-       coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM);
-
-       coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START);
-       coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE);
-
-       return 0;
-}
-
-static void coda_prepare_encode(struct coda_ctx *ctx)
-{
-       struct coda_q_data *q_data_src, *q_data_dst;
-       struct vb2_buffer *src_buf, *dst_buf;
-       struct coda_dev *dev = ctx->dev;
-       int force_ipicture;
-       int quant_param = 0;
-       u32 picture_y, picture_cb, picture_cr;
-       u32 pic_stream_buffer_addr, pic_stream_buffer_size;
-       u32 dst_fourcc;
-
-       src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
-       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-       dst_fourcc = q_data_dst->fourcc;
-
-       src_buf->v4l2_buf.sequence = ctx->osequence;
-       dst_buf->v4l2_buf.sequence = ctx->osequence;
-       ctx->osequence++;
-
-       /*
-        * Workaround coda firmware BUG that only marks the first
-        * frame as IDR. This is a problem for some decoders that can't
-        * recover when a frame is lost.
-        */
-       if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) {
-               src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
-               src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
-       } else {
-               src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
-               src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
-       }
-
-       if (dev->devtype->product == CODA_960)
-               coda_set_gdi_regs(ctx);
-
-       /*
-        * Copy headers at the beginning of the first frame for H.264 only.
-        * In MPEG4 they are already copied by the coda.
-        */
-       if (src_buf->v4l2_buf.sequence == 0) {
-               pic_stream_buffer_addr =
-                       vb2_dma_contig_plane_dma_addr(dst_buf, 0) +
-                       ctx->vpu_header_size[0] +
-                       ctx->vpu_header_size[1] +
-                       ctx->vpu_header_size[2];
-               pic_stream_buffer_size = CODA_MAX_FRAME_SIZE -
-                       ctx->vpu_header_size[0] -
-                       ctx->vpu_header_size[1] -
-                       ctx->vpu_header_size[2];
-               memcpy(vb2_plane_vaddr(dst_buf, 0),
-                      &ctx->vpu_header[0][0], ctx->vpu_header_size[0]);
-               memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0],
-                      &ctx->vpu_header[1][0], ctx->vpu_header_size[1]);
-               memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] +
-                       ctx->vpu_header_size[1], &ctx->vpu_header[2][0],
-                       ctx->vpu_header_size[2]);
-       } else {
-               pic_stream_buffer_addr =
-                       vb2_dma_contig_plane_dma_addr(dst_buf, 0);
-               pic_stream_buffer_size = CODA_MAX_FRAME_SIZE;
-       }
-
-       if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
-               force_ipicture = 1;
-               switch (dst_fourcc) {
-               case V4L2_PIX_FMT_H264:
-                       quant_param = ctx->params.h264_intra_qp;
-                       break;
-               case V4L2_PIX_FMT_MPEG4:
-                       quant_param = ctx->params.mpeg4_intra_qp;
-                       break;
-               default:
-                       v4l2_warn(&ctx->dev->v4l2_dev,
-                               "cannot set intra qp, fmt not supported\n");
-                       break;
-               }
-       } else {
-               force_ipicture = 0;
-               switch (dst_fourcc) {
-               case V4L2_PIX_FMT_H264:
-                       quant_param = ctx->params.h264_inter_qp;
-                       break;
-               case V4L2_PIX_FMT_MPEG4:
-                       quant_param = ctx->params.mpeg4_inter_qp;
-                       break;
-               default:
-                       v4l2_warn(&ctx->dev->v4l2_dev,
-                               "cannot set inter qp, fmt not supported\n");
-                       break;
-               }
-       }
-
-       /* submit */
-       coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_ENC_PIC_ROT_MODE);
-       coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
-
-
-       picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0);
-       switch (q_data_src->fourcc) {
-       case V4L2_PIX_FMT_YVU420:
-               /* Switch Cb and Cr for YVU420 format */
-               picture_cr = picture_y + q_data_src->bytesperline *
-                               q_data_src->height;
-               picture_cb = picture_cr + q_data_src->bytesperline / 2 *
-                               q_data_src->height / 2;
-               break;
-       case V4L2_PIX_FMT_YUV420:
-       default:
-               picture_cb = picture_y + q_data_src->bytesperline *
-                               q_data_src->height;
-               picture_cr = picture_cb + q_data_src->bytesperline / 2 *
-                               q_data_src->height / 2;
-               break;
-       }
-
-       if (dev->devtype->product == CODA_960) {
-               coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX);
-               coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE);
-               coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC);
-
-               coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y);
-               coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB);
-               coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR);
-       } else {
-               coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
-               coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
-               coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR);
-       }
-       coda_write(dev, force_ipicture << 1 & 0x2,
-                  CODA_CMD_ENC_PIC_OPTION);
-
-       coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
-       coda_write(dev, pic_stream_buffer_size / 1024,
-                  CODA_CMD_ENC_PIC_BB_SIZE);
-
-       if (!ctx->streamon_out) {
-               /* After streamoff on the output side, set the stream end flag */
-               ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
-               coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM);
-       }
-}
-
-static void coda_device_run(void *m2m_priv)
-{
-       struct coda_ctx *ctx = m2m_priv;
-       struct coda_dev *dev = ctx->dev;
-
-       queue_work(dev->workqueue, &ctx->pic_run_work);
-}
-
-static void coda_free_framebuffers(struct coda_ctx *ctx);
-static void coda_free_context_buffers(struct coda_ctx *ctx);
-
-static void coda_seq_end_work(struct work_struct *work)
-{
-       struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work);
-       struct coda_dev *dev = ctx->dev;
-
-       mutex_lock(&ctx->buffer_mutex);
-       mutex_lock(&dev->coda_mutex);
-
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__);
-       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
-               v4l2_err(&dev->v4l2_dev,
-                        "CODA_COMMAND_SEQ_END failed\n");
-       }
-
-       kfifo_init(&ctx->bitstream_fifo,
-               ctx->bitstream.vaddr, ctx->bitstream.size);
-
-       coda_free_framebuffers(ctx);
-       coda_free_context_buffers(ctx);
-
-       mutex_unlock(&dev->coda_mutex);
-       mutex_unlock(&ctx->buffer_mutex);
-}
-
-static void coda_finish_decode(struct coda_ctx *ctx);
-static void coda_finish_encode(struct coda_ctx *ctx);
-
-static void coda_pic_run_work(struct work_struct *work)
-{
-       struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work);
-       struct coda_dev *dev = ctx->dev;
-       int ret;
-
-       mutex_lock(&ctx->buffer_mutex);
-       mutex_lock(&dev->coda_mutex);
-
-       if (ctx->inst_type == CODA_INST_DECODER) {
-               ret = coda_prepare_decode(ctx);
-               if (ret < 0) {
-                       mutex_unlock(&dev->coda_mutex);
-                       mutex_unlock(&ctx->buffer_mutex);
-                       /* job_finish scheduled by prepare_decode */
-                       return;
-               }
-       } else {
-               coda_prepare_encode(ctx);
-       }
-
-       if (dev->devtype->product != CODA_DX6)
-               coda_write(dev, ctx->iram_info.axi_sram_use,
-                               CODA7_REG_BIT_AXI_SRAM_USE);
-
-       if (ctx->inst_type == CODA_INST_DECODER)
-               coda_kfifo_sync_to_device_full(ctx);
-       coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
-
-       if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) {
-               dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n");
-
-               ctx->hold = true;
-
-               coda_hw_reset(ctx);
-       } else if (!ctx->aborting) {
-               if (ctx->inst_type == CODA_INST_DECODER)
-                       coda_finish_decode(ctx);
-               else
-                       coda_finish_encode(ctx);
-       }
-
-       if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out))
-               queue_work(dev->workqueue, &ctx->seq_end_work);
-
-       mutex_unlock(&dev->coda_mutex);
-       mutex_unlock(&ctx->buffer_mutex);
-
-       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
-}
-
-static int coda_job_ready(void *m2m_priv)
-{
-       struct coda_ctx *ctx = m2m_priv;
-
-       /*
-        * For both 'P' and 'key' frame cases 1 picture
-        * and 1 frame are needed. In the decoder case,
-        * the compressed frame can be in the bitstream.
-        */
-       if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
-           ctx->inst_type != CODA_INST_DECODER) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "not ready: not enough video buffers.\n");
-               return 0;
-       }
-
-       if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "not ready: not enough video capture buffers.\n");
-               return 0;
-       }
-
-       if (ctx->hold ||
-           ((ctx->inst_type == CODA_INST_DECODER) &&
-            (coda_get_bitstream_payload(ctx) < 512) &&
-            !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "%d: not ready: not enough bitstream data.\n",
-                        ctx->idx);
-               return 0;
-       }
-
-       if (ctx->aborting) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "not ready: aborting\n");
-               return 0;
-       }
-
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                       "job ready\n");
-       return 1;
-}
-
-static void coda_job_abort(void *priv)
-{
-       struct coda_ctx *ctx = priv;
-
-       ctx->aborting = 1;
-
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                "Aborting task\n");
-}
-
-static void coda_lock(void *m2m_priv)
-{
-       struct coda_ctx *ctx = m2m_priv;
-       struct coda_dev *pcdev = ctx->dev;
-       mutex_lock(&pcdev->dev_mutex);
-}
-
-static void coda_unlock(void *m2m_priv)
-{
-       struct coda_ctx *ctx = m2m_priv;
-       struct coda_dev *pcdev = ctx->dev;
-       mutex_unlock(&pcdev->dev_mutex);
-}
-
-static struct v4l2_m2m_ops coda_m2m_ops = {
-       .device_run     = coda_device_run,
-       .job_ready      = coda_job_ready,
-       .job_abort      = coda_job_abort,
-       .lock           = coda_lock,
-       .unlock         = coda_unlock,
-};
-
-static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type)
-{
-       struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
-       int luma_map, chro_map, i;
-
-       memset(tiled_map, 0, sizeof(*tiled_map));
-
-       luma_map = 64;
-       chro_map = 64;
-       tiled_map->map_type = tiled_map_type;
-       for (i = 0; i < 16; i++)
-               tiled_map->xy2ca_map[i] = luma_map << 8 | chro_map;
-       for (i = 0; i < 4; i++)
-               tiled_map->xy2ba_map[i] = luma_map << 8 | chro_map;
-       for (i = 0; i < 16; i++)
-               tiled_map->xy2ra_map[i] = luma_map << 8 | chro_map;
-
-       if (tiled_map_type == GDI_LINEAR_FRAME_MAP) {
-               tiled_map->xy2rbc_config = 0;
-       } else {
-               dev_err(&ctx->dev->plat_dev->dev, "invalid map type: %d\n",
-                       tiled_map_type);
-               return;
-       }
-}
-
-static void set_default_params(struct coda_ctx *ctx)
-{
-       int max_w;
-       int max_h;
-
-       ctx->codec = &ctx->dev->devtype->codecs[0];
-       max_w = ctx->codec->max_w;
-       max_h = ctx->codec->max_h;
-
-       ctx->params.codec_mode = CODA_MODE_INVALID;
-       ctx->colorspace = V4L2_COLORSPACE_REC709;
-       ctx->params.framerate = 30;
-       ctx->aborting = 0;
-
-       /* Default formats for output and input queues */
-       ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc;
-       ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc;
-       ctx->q_data[V4L2_M2M_SRC].width = max_w;
-       ctx->q_data[V4L2_M2M_SRC].height = max_h;
-       ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w;
-       ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
-       ctx->q_data[V4L2_M2M_DST].width = max_w;
-       ctx->q_data[V4L2_M2M_DST].height = max_h;
-       ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
-       ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
-       ctx->q_data[V4L2_M2M_SRC].rect.width = max_w;
-       ctx->q_data[V4L2_M2M_SRC].rect.height = max_h;
-       ctx->q_data[V4L2_M2M_DST].rect.width = max_w;
-       ctx->q_data[V4L2_M2M_DST].rect.height = max_h;
-
-       if (ctx->dev->devtype->product == CODA_960)
-               coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP);
-}
-
-/*
- * Queue operations
- */
-static int coda_queue_setup(struct vb2_queue *vq,
-                               const struct v4l2_format *fmt,
-                               unsigned int *nbuffers, unsigned int *nplanes,
-                               unsigned int sizes[], void *alloc_ctxs[])
-{
-       struct coda_ctx *ctx = vb2_get_drv_priv(vq);
-       struct coda_q_data *q_data;
-       unsigned int size;
-
-       q_data = get_q_data(ctx, vq->type);
-       size = q_data->sizeimage;
-
-       *nplanes = 1;
-       sizes[0] = size;
-
-       alloc_ctxs[0] = ctx->dev->alloc_ctx;
-
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                "get %d buffer(s) of size %d each.\n", *nbuffers, size);
-
-       return 0;
-}
-
-static int coda_buf_prepare(struct vb2_buffer *vb)
-{
-       struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       struct coda_q_data *q_data;
-
-       q_data = get_q_data(ctx, vb->vb2_queue->type);
-
-       if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
-               v4l2_warn(&ctx->dev->v4l2_dev,
-                         "%s data will not fit into plane (%lu < %lu)\n",
-                         __func__, vb2_plane_size(vb, 0),
-                         (long)q_data->sizeimage);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static void coda_buf_queue(struct vb2_buffer *vb)
-{
-       struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       struct coda_dev *dev = ctx->dev;
-       struct coda_q_data *q_data;
-
-       q_data = get_q_data(ctx, vb->vb2_queue->type);
-
-       /*
-        * In the decoder case, immediately try to copy the buffer into the
-        * bitstream ringbuffer and mark it as ready to be dequeued.
-        */
-       if (q_data->fourcc == V4L2_PIX_FMT_H264 &&
-           vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               /*
-                * For backwards compatibility, queuing an empty buffer marks
-                * the stream end
-                */
-               if (vb2_get_plane_payload(vb, 0) == 0) {
-                       ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
-                       if ((dev->devtype->product == CODA_960) &&
-                           coda_isbusy(dev) &&
-                           (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
-                               /* if this decoder instance is running, set the stream end flag */
-                               coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM);
-                       }
-               }
-               mutex_lock(&ctx->bitstream_mutex);
-               v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
-               coda_fill_bitstream(ctx);
-               mutex_unlock(&ctx->bitstream_mutex);
-       } else {
-               v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
-       }
-}
-
-static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
-{
-       struct coda_dev *dev = ctx->dev;
-       u32 *p = ctx->parabuf.vaddr;
-
-       if (dev->devtype->product == CODA_DX6)
-               p[index] = value;
-       else
-               p[index ^ 1] = value;
-}
-
-static int coda_alloc_aux_buf(struct coda_dev *dev,
-                             struct coda_aux_buf *buf, size_t size,
-                             const char *name, struct dentry *parent)
-{
-       buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr,
-                                       GFP_KERNEL);
-       if (!buf->vaddr)
-               return -ENOMEM;
-
-       buf->size = size;
-
-       if (name && parent) {
-               buf->blob.data = buf->vaddr;
-               buf->blob.size = size;
-               buf->dentry = debugfs_create_blob(name, 0644, parent, &buf->blob);
-               if (!buf->dentry)
-                       dev_warn(&dev->plat_dev->dev,
-                                "failed to create debugfs entry %s\n", name);
-       }
-
-       return 0;
-}
-
-static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
-                                        struct coda_aux_buf *buf, size_t size,
-                                        const char *name)
-{
-       return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry);
-}
-
-static void coda_free_aux_buf(struct coda_dev *dev,
-                             struct coda_aux_buf *buf)
-{
-       if (buf->vaddr) {
-               dma_free_coherent(&dev->plat_dev->dev, buf->size,
-                                 buf->vaddr, buf->paddr);
-               buf->vaddr = NULL;
-               buf->size = 0;
-       }
-       debugfs_remove(buf->dentry);
-}
-
-static void coda_free_framebuffers(struct coda_ctx *ctx)
-{
-       int i;
-
-       for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++)
-               coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]);
-}
-
-static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc)
-{
-       struct coda_dev *dev = ctx->dev;
-       int width, height;
-       dma_addr_t paddr;
-       int ysize;
-       int ret;
-       int i;
-
-       if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
-            ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) {
-               width = round_up(q_data->width, 16);
-               height = round_up(q_data->height, 16);
-       } else {
-               width = round_up(q_data->width, 8);
-               height = q_data->height;
-       }
-       ysize = width * height;
-
-       /* Allocate frame buffers */
-       for (i = 0; i < ctx->num_internal_frames; i++) {
-               size_t size;
-               char *name;
-
-               size = ysize + ysize / 2;
-               if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
-                   dev->devtype->product != CODA_DX6)
-                       size += ysize / 4;
-               name = kasprintf(GFP_KERNEL, "fb%d", i);
-               ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i],
-                                            size, name);
-               kfree(name);
-               if (ret < 0) {
-                       coda_free_framebuffers(ctx);
-                       return ret;
-               }
-       }
-
-       /* Register frame buffers in the parameter buffer */
-       for (i = 0; i < ctx->num_internal_frames; i++) {
-               paddr = ctx->internal_frames[i].paddr;
-               coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */
-               coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */
-               coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */
-
-               /* mvcol buffer for h.264 */
-               if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
-                   dev->devtype->product != CODA_DX6)
-                       coda_parabuf_write(ctx, 96 + i,
-                                          ctx->internal_frames[i].paddr +
-                                          ysize + ysize/4 + ysize/4);
-       }
-
-       /* mvcol buffer for mpeg4 */
-       if ((dev->devtype->product != CODA_DX6) &&
-           (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4))
-               coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr +
-                                           ysize + ysize/4 + ysize/4);
-
-       return 0;
-}
-
-static int coda_h264_padding(int size, char *p)
-{
-       int nal_size;
-       int diff;
-
-       diff = size - (size & ~0x7);
-       if (diff == 0)
-               return 0;
-
-       nal_size = coda_filler_size[diff];
-       memcpy(p, coda_filler_nal, nal_size);
-
-       /* Add rbsp stop bit and trailing at the end */
-       *(p + nal_size - 1) = 0x80;
-
-       return nal_size;
-}
-
-static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size)
-{
-       phys_addr_t ret;
-
-       size = round_up(size, 1024);
-       if (size > iram->remaining)
-               return 0;
-       iram->remaining -= size;
-
-       ret = iram->next_paddr;
-       iram->next_paddr += size;
-
-       return ret;
-}
-
-static void coda_setup_iram(struct coda_ctx *ctx)
-{
-       struct coda_iram_info *iram_info = &ctx->iram_info;
-       struct coda_dev *dev = ctx->dev;
-       int mb_width;
-       int dbk_bits;
-       int bit_bits;
-       int ip_bits;
-
-       memset(iram_info, 0, sizeof(*iram_info));
-       iram_info->next_paddr = dev->iram.paddr;
-       iram_info->remaining = dev->iram.size;
-
-       switch (dev->devtype->product) {
-       case CODA_7541:
-               dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE;
-               bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
-               ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
-               break;
-       case CODA_960:
-               dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE;
-               bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
-               ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
-               break;
-       default: /* CODA_DX6 */
-               return;
-       }
-
-       if (ctx->inst_type == CODA_INST_ENCODER) {
-               struct coda_q_data *q_data_src;
-
-               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-               mb_width = DIV_ROUND_UP(q_data_src->width, 16);
-
-               /* Prioritize in case IRAM is too small for everything */
-               if (dev->devtype->product == CODA_7541) {
-                       iram_info->search_ram_size = round_up(mb_width * 16 *
-                                                             36 + 2048, 1024);
-                       iram_info->search_ram_paddr = coda_iram_alloc(iram_info,
-                                                       iram_info->search_ram_size);
-                       if (!iram_info->search_ram_paddr) {
-                               pr_err("IRAM is smaller than the search ram size\n");
-                               goto out;
-                       }
-                       iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE |
-                                                  CODA7_USE_ME_ENABLE;
-               }
-
-               /* Only H.264BP and H.263P3 are considered */
-               iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 64 * mb_width);
-               iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 64 * mb_width);
-               if (!iram_info->buf_dbk_c_use)
-                       goto out;
-               iram_info->axi_sram_use |= dbk_bits;
-
-               iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width);
-               if (!iram_info->buf_bit_use)
-                       goto out;
-               iram_info->axi_sram_use |= bit_bits;
-
-               iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width);
-               if (!iram_info->buf_ip_ac_dc_use)
-                       goto out;
-               iram_info->axi_sram_use |= ip_bits;
-
-               /* OVL and BTP disabled for encoder */
-       } else if (ctx->inst_type == CODA_INST_DECODER) {
-               struct coda_q_data *q_data_dst;
-
-               q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-               mb_width = DIV_ROUND_UP(q_data_dst->width, 16);
-
-               iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 128 * mb_width);
-               iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 128 * mb_width);
-               if (!iram_info->buf_dbk_c_use)
-                       goto out;
-               iram_info->axi_sram_use |= dbk_bits;
-
-               iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width);
-               if (!iram_info->buf_bit_use)
-                       goto out;
-               iram_info->axi_sram_use |= bit_bits;
-
-               iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width);
-               if (!iram_info->buf_ip_ac_dc_use)
-                       goto out;
-               iram_info->axi_sram_use |= ip_bits;
-
-               /* OVL and BTP unused as there is no VC1 support yet */
-       }
-
-out:
-       if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE))
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "IRAM smaller than needed\n");
-
-       if (dev->devtype->product == CODA_7541) {
-               /* TODO - Enabling these causes picture errors on CODA7541 */
-               if (ctx->inst_type == CODA_INST_DECODER) {
-                       /* fw 1.4.50 */
-                       iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
-                                                    CODA7_USE_IP_ENABLE);
-               } else {
-                       /* fw 13.4.29 */
-                       iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
-                                                    CODA7_USE_HOST_DBK_ENABLE |
-                                                    CODA7_USE_IP_ENABLE |
-                                                    CODA7_USE_DBK_ENABLE);
-               }
-       }
-}
-
-static void coda_free_context_buffers(struct coda_ctx *ctx)
-{
-       struct coda_dev *dev = ctx->dev;
-
-       coda_free_aux_buf(dev, &ctx->slicebuf);
-       coda_free_aux_buf(dev, &ctx->psbuf);
-       if (dev->devtype->product != CODA_DX6)
-               coda_free_aux_buf(dev, &ctx->workbuf);
-}
-
-static int coda_alloc_context_buffers(struct coda_ctx *ctx,
-                                     struct coda_q_data *q_data)
-{
-       struct coda_dev *dev = ctx->dev;
-       size_t size;
-       int ret;
-
-       if (dev->devtype->product == CODA_DX6)
-               return 0;
-
-       if (ctx->psbuf.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n");
-               return -EBUSY;
-       }
-       if (ctx->slicebuf.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n");
-               return -EBUSY;
-       }
-       if (ctx->workbuf.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
-               ret = -EBUSY;
-               return -ENOMEM;
-       }
-
-       if (q_data->fourcc == V4L2_PIX_FMT_H264) {
-               /* worst case slice size */
-               size = (DIV_ROUND_UP(q_data->width, 16) *
-                       DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512;
-               ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf");
-               if (ret < 0) {
-                       v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer",
-                                ctx->slicebuf.size);
-                       return ret;
-               }
-       }
-
-       if (dev->devtype->product == CODA_7541) {
-               ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf");
-               if (ret < 0) {
-                       v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer");
-                       goto err;
-               }
-       }
-
-       size = dev->devtype->workbuf_size;
-       if (dev->devtype->product == CODA_960 &&
-           q_data->fourcc == V4L2_PIX_FMT_H264)
-               size += CODA9_PS_SAVE_SIZE;
-       ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf");
-       if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer",
-                        ctx->workbuf.size);
-               goto err;
-       }
-
-       return 0;
-
-err:
-       coda_free_context_buffers(ctx);
-       return ret;
-}
-
-static int coda_start_decoding(struct coda_ctx *ctx)
-{
-       struct coda_q_data *q_data_src, *q_data_dst;
-       u32 bitstream_buf, bitstream_size;
-       struct coda_dev *dev = ctx->dev;
-       int width, height;
-       u32 src_fourcc;
-       u32 val;
-       int ret;
-
-       /* Start decoding */
-       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-       bitstream_buf = ctx->bitstream.paddr;
-       bitstream_size = ctx->bitstream.size;
-       src_fourcc = q_data_src->fourcc;
-
-       coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
-
-       /* Update coda bitstream read and write pointers from kfifo */
-       coda_kfifo_sync_to_device_full(ctx);
-
-       ctx->display_idx = -1;
-       ctx->frm_dis_flg = 0;
-       coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
-
-       coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE,
-                       CODA_REG_BIT_BIT_STREAM_PARAM);
-
-       coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START);
-       coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE);
-       val = 0;
-       if ((dev->devtype->product == CODA_7541) ||
-           (dev->devtype->product == CODA_960))
-               val |= CODA_REORDER_ENABLE;
-       coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
-
-       ctx->params.codec_mode = ctx->codec->mode;
-       if (dev->devtype->product == CODA_960 &&
-           src_fourcc == V4L2_PIX_FMT_MPEG4)
-               ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4;
-       else
-               ctx->params.codec_mode_aux = 0;
-       if (src_fourcc == V4L2_PIX_FMT_H264) {
-               if (dev->devtype->product == CODA_7541) {
-                       coda_write(dev, ctx->psbuf.paddr,
-                                       CODA_CMD_DEC_SEQ_PS_BB_START);
-                       coda_write(dev, (CODA7_PS_BUF_SIZE / 1024),
-                                       CODA_CMD_DEC_SEQ_PS_BB_SIZE);
-               }
-               if (dev->devtype->product == CODA_960) {
-                       coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN);
-                       coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE);
-               }
-       }
-       if (dev->devtype->product != CODA_960) {
-               coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE);
-       }
-
-       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
-               v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
-               coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
-               return -ETIMEDOUT;
-       }
-
-       /* Update kfifo out pointer from coda bitstream read pointer */
-       coda_kfifo_sync_from_device(ctx);
-
-       coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
-
-       if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) {
-               v4l2_err(&dev->v4l2_dev,
-                       "CODA_COMMAND_SEQ_INIT failed, error code = %d\n",
-                       coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON));
-               return -EAGAIN;
-       }
-
-       val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE);
-       if (dev->devtype->product == CODA_DX6) {
-               width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK;
-               height = val & CODADX6_PICHEIGHT_MASK;
-       } else {
-               width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK;
-               height = val & CODA7_PICHEIGHT_MASK;
-       }
-
-       if (width > q_data_dst->width || height > q_data_dst->height) {
-               v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n",
-                        width, height, q_data_dst->width, q_data_dst->height);
-               return -EINVAL;
-       }
-
-       width = round_up(width, 16);
-       height = round_up(height, 16);
-
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n",
-                __func__, ctx->idx, width, height);
-
-       ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED);
-       if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) {
-               v4l2_err(&dev->v4l2_dev,
-                        "not enough framebuffers to decode (%d < %d)\n",
-                        CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames);
-               return -EINVAL;
-       }
-
-       if (src_fourcc == V4L2_PIX_FMT_H264) {
-               u32 left_right;
-               u32 top_bottom;
-
-               left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT);
-               top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM);
-
-               q_data_dst->rect.left = (left_right >> 10) & 0x3ff;
-               q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff;
-               q_data_dst->rect.width = width - q_data_dst->rect.left -
-                                        (left_right & 0x3ff);
-               q_data_dst->rect.height = height - q_data_dst->rect.top -
-                                         (top_bottom & 0x3ff);
-       }
-
-       ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
-       if (ret < 0)
-               return ret;
-
-       /* Tell the decoder how many frame buffers we allocated. */
-       coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
-       coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE);
-
-       if (dev->devtype->product != CODA_DX6) {
-               /* Set secondary AXI IRAM */
-               coda_setup_iram(ctx);
-
-               coda_write(dev, ctx->iram_info.buf_bit_use,
-                               CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
-               coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
-                               CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
-               coda_write(dev, ctx->iram_info.buf_dbk_y_use,
-                               CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
-               coda_write(dev, ctx->iram_info.buf_dbk_c_use,
-                               CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
-               coda_write(dev, ctx->iram_info.buf_ovl_use,
-                               CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
-               if (dev->devtype->product == CODA_960)
-                       coda_write(dev, ctx->iram_info.buf_btp_use,
-                                       CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
-       }
-
-       if (dev->devtype->product == CODA_960) {
-               coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY);
-
-               coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE);
-               coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET |
-                               32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
-                               8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET |
-                               8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET,
-                               CODA9_CMD_SET_FRAME_CACHE_CONFIG);
-       }
-
-       if (src_fourcc == V4L2_PIX_FMT_H264) {
-               coda_write(dev, ctx->slicebuf.paddr,
-                               CODA_CMD_SET_FRAME_SLICE_BB_START);
-               coda_write(dev, ctx->slicebuf.size / 1024,
-                               CODA_CMD_SET_FRAME_SLICE_BB_SIZE);
-       }
-
-       if (dev->devtype->product == CODA_7541) {
-               int max_mb_x = 1920 / 16;
-               int max_mb_y = 1088 / 16;
-               int max_mb_num = max_mb_x * max_mb_y;
-
-               coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
-                               CODA7_CMD_SET_FRAME_MAX_DEC_SIZE);
-       } else if (dev->devtype->product == CODA_960) {
-               int max_mb_x = 1920 / 16;
-               int max_mb_y = 1088 / 16;
-               int max_mb_num = max_mb_x * max_mb_y;
-
-               coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
-                               CODA9_CMD_SET_FRAME_MAX_DEC_SIZE);
-       }
-
-       if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
-               v4l2_err(&ctx->dev->v4l2_dev,
-                        "CODA_COMMAND_SET_FRAME_BUF timeout\n");
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
-                             int header_code, u8 *header, int *size)
-{
-       struct coda_dev *dev = ctx->dev;
-       size_t bufsize;
-       int ret;
-       int i;
-
-       if (dev->devtype->product == CODA_960)
-               memset(vb2_plane_vaddr(buf, 0), 0, 64);
-
-       coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0),
-                  CODA_CMD_ENC_HEADER_BB_START);
-       bufsize = vb2_plane_size(buf, 0);
-       if (dev->devtype->product == CODA_960)
-               bufsize /= 1024;
-       coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE);
-       coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE);
-       ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER);
-       if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
-               return ret;
-       }
-
-       if (dev->devtype->product == CODA_960) {
-               for (i = 63; i > 0; i--)
-                       if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0)
-                               break;
-               *size = i + 1;
-       } else {
-               *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
-                       coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
-       }
-       memcpy(header, vb2_plane_vaddr(buf, 0), *size);
-
-       return 0;
-}
-
-static int coda_start_encoding(struct coda_ctx *ctx);
-
-static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
-{
-       struct coda_ctx *ctx = vb2_get_drv_priv(q);
-       struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev;
-       struct coda_dev *dev = ctx->dev;
-       struct coda_q_data *q_data_src, *q_data_dst;
-       u32 dst_fourcc;
-       int ret = 0;
-
-       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               if (q_data_src->fourcc == V4L2_PIX_FMT_H264) {
-                       if (coda_get_bitstream_payload(ctx) < 512)
-                               return -EINVAL;
-               } else {
-                       if (count < 1)
-                               return -EINVAL;
-               }
-
-               ctx->streamon_out = 1;
-
-               if (coda_format_is_yuv(q_data_src->fourcc))
-                       ctx->inst_type = CODA_INST_ENCODER;
-               else
-                       ctx->inst_type = CODA_INST_DECODER;
-       } else {
-               if (count < 1)
-                       return -EINVAL;
-
-               ctx->streamon_cap = 1;
-       }
-
-       /* Don't start the coda unless both queues are on */
-       if (!(ctx->streamon_out & ctx->streamon_cap))
-               return 0;
-
-       /* Allow decoder device_run with no new buffers queued */
-       if (ctx->inst_type == CODA_INST_DECODER)
-               v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
-
-       ctx->gopcounter = ctx->params.gop_size - 1;
-       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-       dst_fourcc = q_data_dst->fourcc;
-
-       ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
-                                    q_data_dst->fourcc);
-       if (!ctx->codec) {
-               v4l2_err(v4l2_dev, "couldn't tell instance type.\n");
-               return -EINVAL;
-       }
-
-       /* Allocate per-instance buffers */
-       ret = coda_alloc_context_buffers(ctx, q_data_src);
-       if (ret < 0)
-               return ret;
-
-       if (ctx->inst_type == CODA_INST_DECODER) {
-               mutex_lock(&dev->coda_mutex);
-               ret = coda_start_decoding(ctx);
-               mutex_unlock(&dev->coda_mutex);
-               if (ret == -EAGAIN)
-                       return 0;
-               else if (ret < 0)
-                       return ret;
-       } else {
-               ret = coda_start_encoding(ctx);
-       }
-
-       ctx->initialized = 1;
-       return ret;
-}
-
-static int coda_start_encoding(struct coda_ctx *ctx)
-{
-       struct coda_dev *dev = ctx->dev;
-       struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
-       struct coda_q_data *q_data_src, *q_data_dst;
-       u32 bitstream_buf, bitstream_size;
-       struct vb2_buffer *buf;
-       int gamma, ret, value;
-       u32 dst_fourcc;
-
-       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-       dst_fourcc = q_data_dst->fourcc;
-
-       buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-       bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
-       bitstream_size = q_data_dst->sizeimage;
-
-       if (!coda_is_initialized(dev)) {
-               v4l2_err(v4l2_dev, "coda is not initialized.\n");
-               return -EFAULT;
-       }
-
-       mutex_lock(&dev->coda_mutex);
-
-       coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
-       coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
-       coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
-       switch (dev->devtype->product) {
-       case CODA_DX6:
-               coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
-                       CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
-               break;
-       case CODA_960:
-               coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
-               /* fallthrough */
-       case CODA_7541:
-               coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
-                       CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
-               break;
-       }
-
-       value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL);
-       value &= ~(1 << 2 | 0x7 << 9);
-       ctx->frame_mem_ctrl = value;
-       coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL);
-
-       if (dev->devtype->product == CODA_DX6) {
-               /* Configure the coda */
-               coda_write(dev, dev->iram.paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR);
-       }
-
-       /* Could set rotation here if needed */
-       switch (dev->devtype->product) {
-       case CODA_DX6:
-               value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET;
-               value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
-               break;
-       case CODA_7541:
-               if (dst_fourcc == V4L2_PIX_FMT_H264) {
-                       value = (round_up(q_data_src->width, 16) &
-                                CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
-                       value |= (round_up(q_data_src->height, 16) &
-                                 CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
-                       break;
-               }
-               /* fallthrough */
-       case CODA_960:
-               value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
-               value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
-       }
-       coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
-       coda_write(dev, ctx->params.framerate,
-                  CODA_CMD_ENC_SEQ_SRC_F_RATE);
-
-       ctx->params.codec_mode = ctx->codec->mode;
-       switch (dst_fourcc) {
-       case V4L2_PIX_FMT_MPEG4:
-               if (dev->devtype->product == CODA_960)
-                       coda_write(dev, CODA9_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
-               else
-                       coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
-               coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
-               break;
-       case V4L2_PIX_FMT_H264:
-               if (dev->devtype->product == CODA_960)
-                       coda_write(dev, CODA9_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
-               else
-                       coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
-               if (ctx->params.h264_deblk_enabled) {
-                       value = ((ctx->params.h264_deblk_alpha &
-                                 CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
-                                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
-                               ((ctx->params.h264_deblk_beta &
-                                 CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
-                                CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET);
-               } else {
-                       value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET;
-               }
-               coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
-               break;
-       default:
-               v4l2_err(v4l2_dev,
-                        "dst format (0x%08x) invalid.\n", dst_fourcc);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       switch (ctx->params.slice_mode) {
-       case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
-               value = 0;
-               break;
-       case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
-               value  = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET;
-               value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET;
-               value |=  1 & CODA_SLICING_MODE_MASK;
-               break;
-       case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
-               value  = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET;
-               value |= (0 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET;
-               value |=  1 & CODA_SLICING_MODE_MASK;
-               break;
-       }
-       coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
-       value = ctx->params.gop_size & CODA_GOP_SIZE_MASK;
-       coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
-
-       if (ctx->params.bitrate) {
-               /* Rate control enabled */
-               value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET;
-               value |=  1 & CODA_RATECONTROL_ENABLE_MASK;
-               if (dev->devtype->product == CODA_960)
-                       value |= BIT(31); /* disable autoskip */
-       } else {
-               value = 0;
-       }
-       coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA);
-
-       coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE);
-       coda_write(dev, ctx->params.intra_refresh,
-                  CODA_CMD_ENC_SEQ_INTRA_REFRESH);
-
-       coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START);
-       coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE);
-
-
-       value = 0;
-       if (dev->devtype->product == CODA_960)
-               gamma = CODA9_DEFAULT_GAMMA;
-       else
-               gamma = CODA_DEFAULT_GAMMA;
-       if (gamma > 0) {
-               coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET,
-                          CODA_CMD_ENC_SEQ_RC_GAMMA);
-       }
-
-       if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) {
-               coda_write(dev,
-                          ctx->params.h264_min_qp << CODA_QPMIN_OFFSET |
-                          ctx->params.h264_max_qp << CODA_QPMAX_OFFSET,
-                          CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX);
-       }
-       if (dev->devtype->product == CODA_960) {
-               if (ctx->params.h264_max_qp)
-                       value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET;
-               if (CODA_DEFAULT_GAMMA > 0)
-                       value |= 1 << CODA9_OPTION_GAMMA_OFFSET;
-       } else {
-               if (CODA_DEFAULT_GAMMA > 0) {
-                       if (dev->devtype->product == CODA_DX6)
-                               value |= 1 << CODADX6_OPTION_GAMMA_OFFSET;
-                       else
-                               value |= 1 << CODA7_OPTION_GAMMA_OFFSET;
-               }
-               if (ctx->params.h264_min_qp)
-                       value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET;
-               if (ctx->params.h264_max_qp)
-                       value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET;
-       }
-       coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
-
-       coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE);
-
-       coda_setup_iram(ctx);
-
-       if (dst_fourcc == V4L2_PIX_FMT_H264) {
-               switch (dev->devtype->product) {
-               case CODA_DX6:
-                       value = FMO_SLICE_SAVE_BUF_SIZE << 7;
-                       coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO);
-                       break;
-               case CODA_7541:
-                       coda_write(dev, ctx->iram_info.search_ram_paddr,
-                                       CODA7_CMD_ENC_SEQ_SEARCH_BASE);
-                       coda_write(dev, ctx->iram_info.search_ram_size,
-                                       CODA7_CMD_ENC_SEQ_SEARCH_SIZE);
-                       break;
-               case CODA_960:
-                       coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION);
-                       coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT);
-               }
-       }
-
-       ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT);
-       if (ret < 0) {
-               v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
-               goto out;
-       }
-
-       if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) {
-               v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n");
-               ret = -EFAULT;
-               goto out;
-       }
-
-       if (dev->devtype->product == CODA_960)
-               ctx->num_internal_frames = 4;
-       else
-               ctx->num_internal_frames = 2;
-       ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
-       if (ret < 0) {
-               v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
-               goto out;
-       }
-
-       coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
-       coda_write(dev, q_data_src->bytesperline,
-                       CODA_CMD_SET_FRAME_BUF_STRIDE);
-       if (dev->devtype->product == CODA_7541) {
-               coda_write(dev, q_data_src->bytesperline,
-                               CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
-       }
-       if (dev->devtype->product != CODA_DX6) {
-               coda_write(dev, ctx->iram_info.buf_bit_use,
-                               CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
-               coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
-                               CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
-               coda_write(dev, ctx->iram_info.buf_dbk_y_use,
-                               CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
-               coda_write(dev, ctx->iram_info.buf_dbk_c_use,
-                               CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
-               coda_write(dev, ctx->iram_info.buf_ovl_use,
-                               CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
-               if (dev->devtype->product == CODA_960) {
-                       coda_write(dev, ctx->iram_info.buf_btp_use,
-                                       CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
-
-                       /* FIXME */
-                       coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A);
-                       coda_write(dev, ctx->internal_frames[3].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B);
-               }
-       }
-
-       ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF);
-       if (ret < 0) {
-               v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
-               goto out;
-       }
-
-       /* Save stream headers */
-       buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-       switch (dst_fourcc) {
-       case V4L2_PIX_FMT_H264:
-               /*
-                * Get SPS in the first frame and copy it to an
-                * intermediate buffer.
-                */
-               ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS,
-                                        &ctx->vpu_header[0][0],
-                                        &ctx->vpu_header_size[0]);
-               if (ret < 0)
-                       goto out;
-
-               /*
-                * Get PPS in the first frame and copy it to an
-                * intermediate buffer.
-                */
-               ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS,
-                                        &ctx->vpu_header[1][0],
-                                        &ctx->vpu_header_size[1]);
-               if (ret < 0)
-                       goto out;
-
-               /*
-                * Length of H.264 headers is variable and thus it might not be
-                * aligned for the coda to append the encoded frame. In that is
-                * the case a filler NAL must be added to header 2.
-                */
-               ctx->vpu_header_size[2] = coda_h264_padding(
-                                       (ctx->vpu_header_size[0] +
-                                        ctx->vpu_header_size[1]),
-                                        ctx->vpu_header[2]);
-               break;
-       case V4L2_PIX_FMT_MPEG4:
-               /*
-                * Get VOS in the first frame and copy it to an
-                * intermediate buffer
-                */
-               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS,
-                                        &ctx->vpu_header[0][0],
-                                        &ctx->vpu_header_size[0]);
-               if (ret < 0)
-                       goto out;
-
-               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS,
-                                        &ctx->vpu_header[1][0],
-                                        &ctx->vpu_header_size[1]);
-               if (ret < 0)
-                       goto out;
-
-               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL,
-                                        &ctx->vpu_header[2][0],
-                                        &ctx->vpu_header_size[2]);
-               if (ret < 0)
-                       goto out;
-               break;
-       default:
-               /* No more formats need to save headers at the moment */
-               break;
-       }
-
-out:
-       mutex_unlock(&dev->coda_mutex);
-       return ret;
-}
-
-static void coda_stop_streaming(struct vb2_queue *q)
-{
-       struct coda_ctx *ctx = vb2_get_drv_priv(q);
-       struct coda_dev *dev = ctx->dev;
-
-       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                        "%s: output\n", __func__);
-               ctx->streamon_out = 0;
-
-               if (ctx->inst_type == CODA_INST_DECODER &&
-                   coda_isbusy(dev) && ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX)) {
-                       /* if this decoder instance is running, set the stream end flag */
-                       if (dev->devtype->product == CODA_960) {
-                               u32 val = coda_read(dev, CODA_REG_BIT_BIT_STREAM_PARAM);
-
-                               val |= CODA_BIT_STREAM_END_FLAG;
-                               coda_write(dev, val, CODA_REG_BIT_BIT_STREAM_PARAM);
-                               ctx->bit_stream_param = val;
-                       }
-               }
-               ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
-
-               ctx->isequence = 0;
-       } else {
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                        "%s: capture\n", __func__);
-               ctx->streamon_cap = 0;
-
-               ctx->osequence = 0;
-               ctx->sequence_offset = 0;
-       }
-
-       if (!ctx->streamon_out && !ctx->streamon_cap) {
-               struct coda_timestamp *ts;
-
-               while (!list_empty(&ctx->timestamp_list)) {
-                       ts = list_first_entry(&ctx->timestamp_list,
-                                             struct coda_timestamp, list);
-                       list_del(&ts->list);
-                       kfree(ts);
-               }
-               kfifo_init(&ctx->bitstream_fifo,
-                       ctx->bitstream.vaddr, ctx->bitstream.size);
-               ctx->runcounter = 0;
-       }
-}
-
-static struct vb2_ops coda_qops = {
-       .queue_setup            = coda_queue_setup,
-       .buf_prepare            = coda_buf_prepare,
-       .buf_queue              = coda_buf_queue,
-       .start_streaming        = coda_start_streaming,
-       .stop_streaming         = coda_stop_streaming,
-       .wait_prepare           = vb2_ops_wait_prepare,
-       .wait_finish            = vb2_ops_wait_finish,
-};
-
-static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct coda_ctx *ctx =
-                       container_of(ctrl->handler, struct coda_ctx, ctrls);
-
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
-
-       switch (ctrl->id) {
-       case V4L2_CID_HFLIP:
-               if (ctrl->val)
-                       ctx->params.rot_mode |= CODA_MIR_HOR;
-               else
-                       ctx->params.rot_mode &= ~CODA_MIR_HOR;
-               break;
-       case V4L2_CID_VFLIP:
-               if (ctrl->val)
-                       ctx->params.rot_mode |= CODA_MIR_VER;
-               else
-                       ctx->params.rot_mode &= ~CODA_MIR_VER;
-               break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE:
-               ctx->params.bitrate = ctrl->val / 1000;
-               break;
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               ctx->params.gop_size = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
-               ctx->params.h264_intra_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
-               ctx->params.h264_inter_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
-               ctx->params.h264_min_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
-               ctx->params.h264_max_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
-               ctx->params.h264_deblk_alpha = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
-               ctx->params.h264_deblk_beta = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
-               ctx->params.h264_deblk_enabled = (ctrl->val ==
-                               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
-               break;
-       case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
-               ctx->params.mpeg4_intra_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
-               ctx->params.mpeg4_inter_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
-               ctx->params.slice_mode = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
-               ctx->params.slice_max_mb = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
-               ctx->params.slice_max_bits = ctrl->val * 8;
-               break;
-       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
-               break;
-       case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
-               ctx->params.intra_refresh = ctrl->val;
-               break;
-       default:
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                       "Invalid control, id=%d, val=%d\n",
-                       ctrl->id, ctrl->val);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static struct v4l2_ctrl_ops coda_ctrl_ops = {
-       .s_ctrl = coda_s_ctrl,
-};
-
-static int coda_ctrls_setup(struct coda_ctx *ctx)
-{
-       v4l2_ctrl_handler_init(&ctx->ctrls, 9);
-
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_HFLIP, 0, 1, 1, 0);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_VFLIP, 0, 1, 1, 0);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25);
-       if (ctx->dev->devtype->product != CODA_960) {
-               v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-                       V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12);
-       }
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0);
-       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
-               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0,
-               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2);
-       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
-               V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0,
-               V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, 500);
-       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_HEADER_MODE,
-               V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
-               (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE),
-               V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 1920 * 1088 / 256, 1, 0);
-
-       if (ctx->ctrls.error) {
-               v4l2_err(&ctx->dev->v4l2_dev, "control initialization error (%d)",
-                       ctx->ctrls.error);
-               return -EINVAL;
-       }
-
-       return v4l2_ctrl_handler_setup(&ctx->ctrls);
-}
-
-static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
-                     struct vb2_queue *dst_vq)
-{
-       struct coda_ctx *ctx = priv;
-       int ret;
-
-       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-       src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
-       src_vq->drv_priv = ctx;
-       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
-       src_vq->ops = &coda_qops;
-       src_vq->mem_ops = &vb2_dma_contig_memops;
-       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       src_vq->lock = &ctx->dev->dev_mutex;
-
-       ret = vb2_queue_init(src_vq);
-       if (ret)
-               return ret;
-
-       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
-       dst_vq->drv_priv = ctx;
-       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
-       dst_vq->ops = &coda_qops;
-       dst_vq->mem_ops = &vb2_dma_contig_memops;
-       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       dst_vq->lock = &ctx->dev->dev_mutex;
-
-       return vb2_queue_init(dst_vq);
-}
-
-static int coda_next_free_instance(struct coda_dev *dev)
-{
-       int idx = ffz(dev->instance_mask);
-
-       if ((idx < 0) ||
-           (dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES))
-               return -EBUSY;
-
-       return idx;
-}
-
-static int coda_open(struct file *file)
-{
-       struct coda_dev *dev = video_drvdata(file);
-       struct coda_ctx *ctx = NULL;
-       char *name;
-       int ret;
-       int idx;
-
-       ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
-
-       idx = coda_next_free_instance(dev);
-       if (idx < 0) {
-               ret = idx;
-               goto err_coda_max;
-       }
-       set_bit(idx, &dev->instance_mask);
-
-       name = kasprintf(GFP_KERNEL, "context%d", idx);
-       ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root);
-       kfree(name);
-
-       init_completion(&ctx->completion);
-       INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
-       INIT_WORK(&ctx->seq_end_work, coda_seq_end_work);
-       v4l2_fh_init(&ctx->fh, video_devdata(file));
-       file->private_data = &ctx->fh;
-       v4l2_fh_add(&ctx->fh);
-       ctx->dev = dev;
-       ctx->idx = idx;
-       switch (dev->devtype->product) {
-       case CODA_7541:
-       case CODA_960:
-               ctx->reg_idx = 0;
-               break;
-       default:
-               ctx->reg_idx = idx;
-       }
-
-       /* Power up and upload firmware if necessary */
-       ret = pm_runtime_get_sync(&dev->plat_dev->dev);
-       if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret);
-               goto err_pm_get;
-       }
-
-       ret = clk_prepare_enable(dev->clk_per);
-       if (ret)
-               goto err_clk_per;
-
-       ret = clk_prepare_enable(dev->clk_ahb);
-       if (ret)
-               goto err_clk_ahb;
-
-       set_default_params(ctx);
-       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
-                                        &coda_queue_init);
-       if (IS_ERR(ctx->fh.m2m_ctx)) {
-               ret = PTR_ERR(ctx->fh.m2m_ctx);
-
-               v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n",
-                        __func__, ret);
-               goto err_ctx_init;
-       }
-
-       ret = coda_ctrls_setup(ctx);
-       if (ret) {
-               v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n");
-               goto err_ctrls_setup;
-       }
-
-       ctx->fh.ctrl_handler = &ctx->ctrls;
-
-       ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE,
-                                    "parabuf");
-       if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
-               goto err_dma_alloc;
-       }
-
-       ctx->bitstream.size = CODA_MAX_FRAME_SIZE;
-       ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev,
-                       ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL);
-       if (!ctx->bitstream.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "failed to allocate bitstream ringbuffer");
-               ret = -ENOMEM;
-               goto err_dma_writecombine;
-       }
-       kfifo_init(&ctx->bitstream_fifo,
-               ctx->bitstream.vaddr, ctx->bitstream.size);
-       mutex_init(&ctx->bitstream_mutex);
-       mutex_init(&ctx->buffer_mutex);
-       INIT_LIST_HEAD(&ctx->timestamp_list);
-
-       coda_lock(ctx);
-       list_add(&ctx->list, &dev->instances);
-       coda_unlock(ctx);
-
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n",
-                ctx->idx, ctx);
-
-       return 0;
-
-err_dma_writecombine:
-       coda_free_context_buffers(ctx);
-       if (ctx->dev->devtype->product == CODA_DX6)
-               coda_free_aux_buf(dev, &ctx->workbuf);
-       coda_free_aux_buf(dev, &ctx->parabuf);
-err_dma_alloc:
-       v4l2_ctrl_handler_free(&ctx->ctrls);
-err_ctrls_setup:
-       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
-err_ctx_init:
-       clk_disable_unprepare(dev->clk_ahb);
-err_clk_ahb:
-       clk_disable_unprepare(dev->clk_per);
-err_clk_per:
-       pm_runtime_put_sync(&dev->plat_dev->dev);
-err_pm_get:
-       v4l2_fh_del(&ctx->fh);
-       v4l2_fh_exit(&ctx->fh);
-       clear_bit(ctx->idx, &dev->instance_mask);
-err_coda_max:
-       kfree(ctx);
-       return ret;
-}
-
-static int coda_release(struct file *file)
-{
-       struct coda_dev *dev = video_drvdata(file);
-       struct coda_ctx *ctx = fh_to_ctx(file->private_data);
-
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
-                ctx);
-
-       debugfs_remove_recursive(ctx->debugfs_entry);
-
-       /* If this instance is running, call .job_abort and wait for it to end */
-       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
-
-       /* In case the instance was not running, we still need to call SEQ_END */
-       if (ctx->initialized) {
-               queue_work(dev->workqueue, &ctx->seq_end_work);
-               flush_work(&ctx->seq_end_work);
-       }
-
-       coda_free_framebuffers(ctx);
-
-       coda_lock(ctx);
-       list_del(&ctx->list);
-       coda_unlock(ctx);
-
-       dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
-               ctx->bitstream.vaddr, ctx->bitstream.paddr);
-       coda_free_context_buffers(ctx);
-       if (ctx->dev->devtype->product == CODA_DX6)
-               coda_free_aux_buf(dev, &ctx->workbuf);
-
-       coda_free_aux_buf(dev, &ctx->parabuf);
-       v4l2_ctrl_handler_free(&ctx->ctrls);
-       clk_disable_unprepare(dev->clk_ahb);
-       clk_disable_unprepare(dev->clk_per);
-       pm_runtime_put_sync(&dev->plat_dev->dev);
-       v4l2_fh_del(&ctx->fh);
-       v4l2_fh_exit(&ctx->fh);
-       clear_bit(ctx->idx, &dev->instance_mask);
-       kfree(ctx);
-
-       return 0;
-}
-
-static const struct v4l2_file_operations coda_fops = {
-       .owner          = THIS_MODULE,
-       .open           = coda_open,
-       .release        = coda_release,
-       .poll           = v4l2_m2m_fop_poll,
-       .unlocked_ioctl = video_ioctl2,
-       .mmap           = v4l2_m2m_fop_mmap,
-};
-
-static void coda_finish_decode(struct coda_ctx *ctx)
-{
-       struct coda_dev *dev = ctx->dev;
-       struct coda_q_data *q_data_src;
-       struct coda_q_data *q_data_dst;
-       struct vb2_buffer *dst_buf;
-       struct coda_timestamp *ts;
-       int width, height;
-       int decoded_idx;
-       int display_idx;
-       u32 src_fourcc;
-       int success;
-       u32 err_mb;
-       u32 val;
-
-       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-
-       /* Update kfifo out pointer from coda bitstream read pointer */
-       coda_kfifo_sync_from_device(ctx);
-
-       /*
-        * in stream-end mode, the read pointer can overshoot the write pointer
-        * by up to 512 bytes
-        */
-       if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
-               if (coda_get_bitstream_payload(ctx) >= 0x100000 - 512)
-                       kfifo_init(&ctx->bitstream_fifo,
-                               ctx->bitstream.vaddr, ctx->bitstream.size);
-       }
-
-       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       src_fourcc = q_data_src->fourcc;
-
-       val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS);
-       if (val != 1)
-               pr_err("DEC_PIC_SUCCESS = %d\n", val);
-
-       success = val & 0x1;
-       if (!success)
-               v4l2_err(&dev->v4l2_dev, "decode failed\n");
-
-       if (src_fourcc == V4L2_PIX_FMT_H264) {
-               if (val & (1 << 3))
-                       v4l2_err(&dev->v4l2_dev,
-                                "insufficient PS buffer space (%d bytes)\n",
-                                ctx->psbuf.size);
-               if (val & (1 << 2))
-                       v4l2_err(&dev->v4l2_dev,
-                                "insufficient slice buffer space (%d bytes)\n",
-                                ctx->slicebuf.size);
-       }
-
-       val = coda_read(dev, CODA_RET_DEC_PIC_SIZE);
-       width = (val >> 16) & 0xffff;
-       height = val & 0xffff;
-
-       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-
-       /* frame crop information */
-       if (src_fourcc == V4L2_PIX_FMT_H264) {
-               u32 left_right;
-               u32 top_bottom;
-
-               left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT);
-               top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM);
-
-               if (left_right == 0xffffffff && top_bottom == 0xffffffff) {
-                       /* Keep current crop information */
-               } else {
-                       struct v4l2_rect *rect = &q_data_dst->rect;
-
-                       rect->left = left_right >> 16 & 0xffff;
-                       rect->top = top_bottom >> 16 & 0xffff;
-                       rect->width = width - rect->left -
-                                     (left_right & 0xffff);
-                       rect->height = height - rect->top -
-                                      (top_bottom & 0xffff);
-               }
-       } else {
-               /* no cropping */
-       }
-
-       err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB);
-       if (err_mb > 0)
-               v4l2_err(&dev->v4l2_dev,
-                        "errors in %d macroblocks\n", err_mb);
-
-       if (dev->devtype->product == CODA_7541) {
-               val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
-               if (val == 0) {
-                       /* not enough bitstream data */
-                       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                                "prescan failed: %d\n", val);
-                       ctx->hold = true;
-                       return;
-               }
-       }
-
-       ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
-
-       /*
-        * The previous display frame was copied out by the rotator,
-        * now it can be overwritten again
-        */
-       if (ctx->display_idx >= 0 &&
-           ctx->display_idx < ctx->num_internal_frames) {
-               ctx->frm_dis_flg &= ~(1 << ctx->display_idx);
-               coda_write(dev, ctx->frm_dis_flg,
-                               CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
-       }
-
-       /*
-        * The index of the last decoded frame, not necessarily in
-        * display order, and the index of the next display frame.
-        * The latter could have been decoded in a previous run.
-        */
-       decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX);
-       display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX);
-
-       if (decoded_idx == -1) {
-               /* no frame was decoded, but we might have a display frame */
-               if (display_idx >= 0 && display_idx < ctx->num_internal_frames)
-                       ctx->sequence_offset++;
-               else if (ctx->display_idx < 0)
-                       ctx->hold = true;
-       } else if (decoded_idx == -2) {
-               /* no frame was decoded, we still return the remaining buffers */
-       } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
-               v4l2_err(&dev->v4l2_dev,
-                        "decoded frame index out of range: %d\n", decoded_idx);
-       } else {
-               ts = list_first_entry(&ctx->timestamp_list,
-                                     struct coda_timestamp, list);
-               list_del(&ts->list);
-               val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
-               val -= ctx->sequence_offset;
-               if (val != (ts->sequence & 0xffff)) {
-                       v4l2_err(&dev->v4l2_dev,
-                                "sequence number mismatch (%d(%d) != %d)\n",
-                                val, ctx->sequence_offset, ts->sequence);
-               }
-               ctx->frame_timestamps[decoded_idx] = *ts;
-               kfree(ts);
-
-               val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7;
-               if (val == 0)
-                       ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME;
-               else if (val == 1)
-                       ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME;
-               else
-                       ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME;
-
-               ctx->frame_errors[decoded_idx] = err_mb;
-       }
-
-       if (display_idx == -1) {
-               /*
-                * no more frames to be decoded, but there could still
-                * be rotator output to dequeue
-                */
-               ctx->hold = true;
-       } else if (display_idx == -3) {
-               /* possibly prescan failure */
-       } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) {
-               v4l2_err(&dev->v4l2_dev,
-                        "presentation frame index out of range: %d\n",
-                        display_idx);
-       }
-
-       /* If a frame was copied out, return it */
-       if (ctx->display_idx >= 0 &&
-           ctx->display_idx < ctx->num_internal_frames) {
-               dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-               dst_buf->v4l2_buf.sequence = ctx->osequence++;
-
-               dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
-                                            V4L2_BUF_FLAG_PFRAME |
-                                            V4L2_BUF_FLAG_BFRAME);
-               dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx];
-               ts = &ctx->frame_timestamps[ctx->display_idx];
-               dst_buf->v4l2_buf.timecode = ts->timecode;
-               dst_buf->v4l2_buf.timestamp = ts->timestamp;
-
-               vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2);
-
-               v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ?
-                                 VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
-
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                       "job finished: decoding frame (%d) (%s)\n",
-                       dst_buf->v4l2_buf.sequence,
-                       (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
-                       "KEYFRAME" : "PFRAME");
-       } else {
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                       "job finished: no frame decoded\n");
-       }
-
-       /* The rotator will copy the current display frame next time */
-       ctx->display_idx = display_idx;
-}
-
-static void coda_finish_encode(struct coda_ctx *ctx)
-{
-       struct vb2_buffer *src_buf, *dst_buf;
-       struct coda_dev *dev = ctx->dev;
-       u32 wr_ptr, start_ptr;
-
-       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
-       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-
-       /* Get results from the coda */
-       start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
-       wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
-
-       /* Calculate bytesused field */
-       if (dst_buf->v4l2_buf.sequence == 0) {
-               vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr +
-                                       ctx->vpu_header_size[0] +
-                                       ctx->vpu_header_size[1] +
-                                       ctx->vpu_header_size[2]);
-       } else {
-               vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr);
-       }
-
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n",
-                wr_ptr - start_ptr);
-
-       coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
-       coda_read(dev, CODA_RET_ENC_PIC_FLAG);
-
-       if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) {
-               dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
-               dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
-       } else {
-               dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
-               dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
-       }
-
-       dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
-       dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-       dst_buf->v4l2_buf.flags |=
-               src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-       dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
-
-       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
-
-       dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-       v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
-
-       ctx->gopcounter--;
-       if (ctx->gopcounter < 0)
-               ctx->gopcounter = ctx->params.gop_size - 1;
-
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-               "job finished: encoding frame (%d) (%s)\n",
-               dst_buf->v4l2_buf.sequence,
-               (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
-               "KEYFRAME" : "PFRAME");
-}
-
-static irqreturn_t coda_irq_handler(int irq, void *data)
-{
-       struct coda_dev *dev = data;
-       struct coda_ctx *ctx;
-
-       /* read status register to attend the IRQ */
-       coda_read(dev, CODA_REG_BIT_INT_STATUS);
-       coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
-                     CODA_REG_BIT_INT_CLEAR);
-
-       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
-       if (ctx == NULL) {
-               v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n");
-               mutex_unlock(&dev->coda_mutex);
-               return IRQ_HANDLED;
-       }
-
-       if (ctx->aborting) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "task has been aborted\n");
-       }
-
-       if (coda_isbusy(ctx->dev)) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "coda is still busy!!!!\n");
-               return IRQ_NONE;
-       }
-
-       complete(&ctx->completion);
-
-       return IRQ_HANDLED;
-}
-
-static u32 coda_supported_firmwares[] = {
-       CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
-       CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
-       CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5),
-};
-
-static bool coda_firmware_supported(u32 vernum)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++)
-               if (vernum == coda_supported_firmwares[i])
-                       return true;
-       return false;
-}
-
-static int coda_hw_init(struct coda_dev *dev)
-{
-       u32 data;
-       u16 *p;
-       int i, ret;
-
-       ret = clk_prepare_enable(dev->clk_per);
-       if (ret)
-               goto err_clk_per;
-
-       ret = clk_prepare_enable(dev->clk_ahb);
-       if (ret)
-               goto err_clk_ahb;
-
-       if (dev->rstc)
-               reset_control_reset(dev->rstc);
-
-       /*
-        * Copy the first CODA_ISRAM_SIZE in the internal SRAM.
-        * The 16-bit chars in the code buffer are in memory access
-        * order, re-sort them to CODA order for register download.
-        * Data in this SRAM survives a reboot.
-        */
-       p = (u16 *)dev->codebuf.vaddr;
-       if (dev->devtype->product == CODA_DX6) {
-               for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++)  {
-                       data = CODA_DOWN_ADDRESS_SET(i) |
-                               CODA_DOWN_DATA_SET(p[i ^ 1]);
-                       coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
-               }
-       } else {
-               for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) {
-                       data = CODA_DOWN_ADDRESS_SET(i) |
-                               CODA_DOWN_DATA_SET(p[round_down(i, 4) +
-                                                       3 - (i % 4)]);
-                       coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
-               }
-       }
-
-       /* Clear registers */
-       for (i = 0; i < 64; i++)
-               coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4);
-
-       /* Tell the BIT where to find everything it needs */
-       if (dev->devtype->product == CODA_960 ||
-           dev->devtype->product == CODA_7541) {
-               coda_write(dev, dev->tempbuf.paddr,
-                               CODA_REG_BIT_TEMP_BUF_ADDR);
-               coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
-       } else {
-               coda_write(dev, dev->workbuf.paddr,
-                             CODA_REG_BIT_WORK_BUF_ADDR);
-       }
-       coda_write(dev, dev->codebuf.paddr,
-                     CODA_REG_BIT_CODE_BUF_ADDR);
-       coda_write(dev, 0, CODA_REG_BIT_CODE_RUN);
-
-       /* Set default values */
-       switch (dev->devtype->product) {
-       case CODA_DX6:
-               coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
-               break;
-       default:
-               coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
-       }
-       if (dev->devtype->product == CODA_960)
-               coda_write(dev, 1 << 12, CODA_REG_BIT_FRAME_MEM_CTRL);
-       else
-               coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL);
-
-       if (dev->devtype->product != CODA_DX6)
-               coda_write(dev, 0, CODA7_REG_BIT_AXI_SRAM_USE);
-
-       coda_write(dev, CODA_INT_INTERRUPT_ENABLE,
-                     CODA_REG_BIT_INT_ENABLE);
-
-       /* Reset VPU and start processor */
-       data = coda_read(dev, CODA_REG_BIT_CODE_RESET);
-       data |= CODA_REG_RESET_ENABLE;
-       coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
-       udelay(10);
-       data &= ~CODA_REG_RESET_ENABLE;
-       coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
-       coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
-
-       clk_disable_unprepare(dev->clk_ahb);
-       clk_disable_unprepare(dev->clk_per);
-
-       return 0;
-
-err_clk_ahb:
-       clk_disable_unprepare(dev->clk_per);
-err_clk_per:
-       return ret;
-}
-
-static int coda_check_firmware(struct coda_dev *dev)
-{
-       u16 product, major, minor, release;
-       u32 data;
-       int ret;
-
-       ret = clk_prepare_enable(dev->clk_per);
-       if (ret)
-               goto err_clk_per;
-
-       ret = clk_prepare_enable(dev->clk_ahb);
-       if (ret)
-               goto err_clk_ahb;
-
-       coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM);
-       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
-       coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX);
-       coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD);
-       coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND);
-       if (coda_wait_timeout(dev)) {
-               v4l2_err(&dev->v4l2_dev, "firmware get command error\n");
-               ret = -EIO;
-               goto err_run_cmd;
-       }
-
-       if (dev->devtype->product == CODA_960) {
-               data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV);
-               v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n",
-                         data);
-       }
-
-       /* Check we are compatible with the loaded firmware */
-       data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM);
-       product = CODA_FIRMWARE_PRODUCT(data);
-       major = CODA_FIRMWARE_MAJOR(data);
-       minor = CODA_FIRMWARE_MINOR(data);
-       release = CODA_FIRMWARE_RELEASE(data);
-
-       clk_disable_unprepare(dev->clk_per);
-       clk_disable_unprepare(dev->clk_ahb);
-
-       if (product != dev->devtype->product) {
-               v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s,"
-                        " Version: %u.%u.%u\n",
-                        coda_product_name(dev->devtype->product),
-                        coda_product_name(product), major, minor, release);
-               return -EINVAL;
-       }
-
-       v4l2_info(&dev->v4l2_dev, "Initialized %s.\n",
-                 coda_product_name(product));
-
-       if (coda_firmware_supported(data)) {
-               v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n",
-                         major, minor, release);
-       } else {
-               v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: "
-                         "%u.%u.%u\n", major, minor, release);
-       }
-
-       return 0;
-
-err_run_cmd:
-       clk_disable_unprepare(dev->clk_ahb);
-err_clk_ahb:
-       clk_disable_unprepare(dev->clk_per);
-err_clk_per:
-       return ret;
-}
-
-static void coda_fw_callback(const struct firmware *fw, void *context)
-{
-       struct coda_dev *dev = context;
-       struct platform_device *pdev = dev->plat_dev;
-       int ret;
-
-       if (!fw) {
-               v4l2_err(&dev->v4l2_dev, "firmware request failed\n");
-               return;
-       }
-
-       /* allocate auxiliary per-device code buffer for the BIT processor */
-       ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf",
-                                dev->debugfs_root);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to allocate code buffer\n");
-               return;
-       }
-
-       /* Copy the whole firmware image to the code buffer */
-       memcpy(dev->codebuf.vaddr, fw->data, fw->size);
-       release_firmware(fw);
-
-       if (pm_runtime_enabled(&pdev->dev) && pdev->dev.pm_domain) {
-               /*
-                * Enabling power temporarily will cause coda_hw_init to be
-                * called via coda_runtime_resume by the pm domain.
-                */
-               ret = pm_runtime_get_sync(&dev->plat_dev->dev);
-               if (ret < 0) {
-                       v4l2_err(&dev->v4l2_dev, "failed to power on: %d\n",
-                                ret);
-                       return;
-               }
-
-               ret = coda_check_firmware(dev);
-               if (ret < 0)
-                       return;
-
-               pm_runtime_put_sync(&dev->plat_dev->dev);
-       } else {
-               /*
-                * If runtime pm is disabled or pm_domain is not set,
-                * initialize once manually.
-                */
-               ret = coda_hw_init(dev);
-               if (ret < 0) {
-                       v4l2_err(&dev->v4l2_dev, "HW initialization failed\n");
-                       return;
-               }
-
-               ret = coda_check_firmware(dev);
-               if (ret < 0)
-                       return;
-       }
-
-       dev->vfd.fops   = &coda_fops,
-       dev->vfd.ioctl_ops      = &coda_ioctl_ops;
-       dev->vfd.release        = video_device_release_empty,
-       dev->vfd.lock   = &dev->dev_mutex;
-       dev->vfd.v4l2_dev       = &dev->v4l2_dev;
-       dev->vfd.vfl_dir        = VFL_DIR_M2M;
-       snprintf(dev->vfd.name, sizeof(dev->vfd.name), "%s", CODA_NAME);
-       video_set_drvdata(&dev->vfd, dev);
-
-       dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
-       if (IS_ERR(dev->alloc_ctx)) {
-               v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n");
-               return;
-       }
-
-       dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops);
-       if (IS_ERR(dev->m2m_dev)) {
-               v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
-               goto rel_ctx;
-       }
-
-       ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, 0);
-       if (ret) {
-               v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
-               goto rel_m2m;
-       }
-       v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video%d\n",
-                 dev->vfd.num);
-
-       return;
-
-rel_m2m:
-       v4l2_m2m_release(dev->m2m_dev);
-rel_ctx:
-       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
-}
-
-static int coda_firmware_request(struct coda_dev *dev)
-{
-       char *fw = dev->devtype->firmware;
-
-       dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
-               coda_product_name(dev->devtype->product));
-
-       return request_firmware_nowait(THIS_MODULE, true,
-               fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback);
-}
-
-enum coda_platform {
-       CODA_IMX27,
-       CODA_IMX53,
-       CODA_IMX6Q,
-       CODA_IMX6DL,
-};
-
-static const struct coda_devtype coda_devdata[] = {
-       [CODA_IMX27] = {
-               .firmware     = "v4l-codadx6-imx27.bin",
-               .product      = CODA_DX6,
-               .codecs       = codadx6_codecs,
-               .num_codecs   = ARRAY_SIZE(codadx6_codecs),
-               .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024,
-               .iram_size    = 0xb000,
-       },
-       [CODA_IMX53] = {
-               .firmware     = "v4l-coda7541-imx53.bin",
-               .product      = CODA_7541,
-               .codecs       = coda7_codecs,
-               .num_codecs   = ARRAY_SIZE(coda7_codecs),
-               .workbuf_size = 128 * 1024,
-               .tempbuf_size = 304 * 1024,
-               .iram_size    = 0x14000,
-       },
-       [CODA_IMX6Q] = {
-               .firmware     = "v4l-coda960-imx6q.bin",
-               .product      = CODA_960,
-               .codecs       = coda9_codecs,
-               .num_codecs   = ARRAY_SIZE(coda9_codecs),
-               .workbuf_size = 80 * 1024,
-               .tempbuf_size = 204 * 1024,
-               .iram_size    = 0x21000,
-       },
-       [CODA_IMX6DL] = {
-               .firmware     = "v4l-coda960-imx6dl.bin",
-               .product      = CODA_960,
-               .codecs       = coda9_codecs,
-               .num_codecs   = ARRAY_SIZE(coda9_codecs),
-               .workbuf_size = 80 * 1024,
-               .tempbuf_size = 204 * 1024,
-               .iram_size    = 0x20000,
-       },
-};
-
-static struct platform_device_id coda_platform_ids[] = {
-       { .name = "coda-imx27", .driver_data = CODA_IMX27 },
-       { .name = "coda-imx53", .driver_data = CODA_IMX53 },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, coda_platform_ids);
-
-#ifdef CONFIG_OF
-static const struct of_device_id coda_dt_ids[] = {
-       { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] },
-       { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] },
-       { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] },
-       { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, coda_dt_ids);
-#endif
-
-static int coda_probe(struct platform_device *pdev)
-{
-       const struct of_device_id *of_id =
-                       of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev);
-       const struct platform_device_id *pdev_id;
-       struct coda_platform_data *pdata = pdev->dev.platform_data;
-       struct device_node *np = pdev->dev.of_node;
-       struct gen_pool *pool;
-       struct coda_dev *dev;
-       struct resource *res;
-       int ret, irq;
-
-       dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL);
-       if (!dev) {
-               dev_err(&pdev->dev, "Not enough memory for %s\n",
-                       CODA_NAME);
-               return -ENOMEM;
-       }
-
-       spin_lock_init(&dev->irqlock);
-       INIT_LIST_HEAD(&dev->instances);
-
-       dev->plat_dev = pdev;
-       dev->clk_per = devm_clk_get(&pdev->dev, "per");
-       if (IS_ERR(dev->clk_per)) {
-               dev_err(&pdev->dev, "Could not get per clock\n");
-               return PTR_ERR(dev->clk_per);
-       }
-
-       dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
-       if (IS_ERR(dev->clk_ahb)) {
-               dev_err(&pdev->dev, "Could not get ahb clock\n");
-               return PTR_ERR(dev->clk_ahb);
-       }
-
-       /* Get  memory for physical registers */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(dev->regs_base))
-               return PTR_ERR(dev->regs_base);
-
-       /* IRQ */
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "failed to get irq resource\n");
-               return irq;
-       }
-
-       ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
-                       IRQF_ONESHOT, dev_name(&pdev->dev), dev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
-               return ret;
-       }
-
-       dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL);
-       if (IS_ERR(dev->rstc)) {
-               ret = PTR_ERR(dev->rstc);
-               if (ret == -ENOENT || ret == -ENOSYS) {
-                       dev->rstc = NULL;
-               } else {
-                       dev_err(&pdev->dev, "failed get reset control: %d\n", ret);
-                       return ret;
-               }
-       }
-
-       /* Get IRAM pool from device tree or platform data */
-       pool = of_get_named_gen_pool(np, "iram", 0);
-       if (!pool && pdata)
-               pool = dev_get_gen_pool(pdata->iram_dev);
-       if (!pool) {
-               dev_err(&pdev->dev, "iram pool not available\n");
-               return -ENOMEM;
-       }
-       dev->iram_pool = pool;
-
-       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-       if (ret)
-               return ret;
-
-       mutex_init(&dev->dev_mutex);
-       mutex_init(&dev->coda_mutex);
-
-       pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
-
-       if (of_id) {
-               dev->devtype = of_id->data;
-       } else if (pdev_id) {
-               dev->devtype = &coda_devdata[pdev_id->driver_data];
-       } else {
-               v4l2_device_unregister(&dev->v4l2_dev);
-               return -EINVAL;
-       }
-
-       dev->debugfs_root = debugfs_create_dir("coda", NULL);
-       if (!dev->debugfs_root)
-               dev_warn(&pdev->dev, "failed to create debugfs root\n");
-
-       /* allocate auxiliary per-device buffers for the BIT processor */
-       if (dev->devtype->product == CODA_DX6) {
-               ret = coda_alloc_aux_buf(dev, &dev->workbuf,
-                                        dev->devtype->workbuf_size, "workbuf",
-                                        dev->debugfs_root);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "failed to allocate work buffer\n");
-                       v4l2_device_unregister(&dev->v4l2_dev);
-                       return ret;
-               }
-       }
-
-       if (dev->devtype->tempbuf_size) {
-               ret = coda_alloc_aux_buf(dev, &dev->tempbuf,
-                                        dev->devtype->tempbuf_size, "tempbuf",
-                                        dev->debugfs_root);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "failed to allocate temp buffer\n");
-                       v4l2_device_unregister(&dev->v4l2_dev);
-                       return ret;
-               }
-       }
-
-       dev->iram.size = dev->devtype->iram_size;
-       dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size,
-                                            &dev->iram.paddr);
-       if (!dev->iram.vaddr) {
-               dev_err(&pdev->dev, "unable to alloc iram\n");
-               return -ENOMEM;
-       }
-
-       dev->iram.blob.data = dev->iram.vaddr;
-       dev->iram.blob.size = dev->iram.size;
-       dev->iram.dentry = debugfs_create_blob("iram", 0644, dev->debugfs_root,
-                                              &dev->iram.blob);
-
-       dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
-       if (!dev->workqueue) {
-               dev_err(&pdev->dev, "unable to alloc workqueue\n");
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(pdev, dev);
-
-       pm_runtime_enable(&pdev->dev);
-
-       return coda_firmware_request(dev);
-}
-
-static int coda_remove(struct platform_device *pdev)
-{
-       struct coda_dev *dev = platform_get_drvdata(pdev);
-
-       video_unregister_device(&dev->vfd);
-       if (dev->m2m_dev)
-               v4l2_m2m_release(dev->m2m_dev);
-       pm_runtime_disable(&pdev->dev);
-       if (dev->alloc_ctx)
-               vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
-       v4l2_device_unregister(&dev->v4l2_dev);
-       destroy_workqueue(dev->workqueue);
-       if (dev->iram.vaddr)
-               gen_pool_free(dev->iram_pool, (unsigned long)dev->iram.vaddr,
-                             dev->iram.size);
-       coda_free_aux_buf(dev, &dev->codebuf);
-       coda_free_aux_buf(dev, &dev->tempbuf);
-       coda_free_aux_buf(dev, &dev->workbuf);
-       debugfs_remove_recursive(dev->debugfs_root);
-       return 0;
-}
-
-#ifdef CONFIG_PM_RUNTIME
-static int coda_runtime_resume(struct device *dev)
-{
-       struct coda_dev *cdev = dev_get_drvdata(dev);
-       int ret = 0;
-
-       if (dev->pm_domain) {
-               ret = coda_hw_init(cdev);
-               if (ret)
-                       v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n");
-       }
-
-       return ret;
-}
-#endif
-
-static const struct dev_pm_ops coda_pm_ops = {
-       SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL)
-};
-
-static struct platform_driver coda_driver = {
-       .probe  = coda_probe,
-       .remove = coda_remove,
-       .driver = {
-               .name   = CODA_NAME,
-               .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(coda_dt_ids),
-               .pm     = &coda_pm_ops,
-       },
-       .id_table = coda_platform_ids,
-};
-
-module_platform_driver(coda_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
-MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver");
diff --git a/drivers/media/platform/coda.h b/drivers/media/platform/coda.h
deleted file mode 100644 (file)
index c791275..0000000
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * linux/drivers/media/platform/coda/coda_regs.h
- *
- * Copyright (C) 2012 Vista Silicon SL
- *    Javier Martin <javier.martin@vista-silicon.com>
- *    Xavier Duret
- *
- * 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.
- */
-
-#ifndef _REGS_CODA_H_
-#define _REGS_CODA_H_
-
-/* HW registers */
-#define CODA_REG_BIT_CODE_RUN                  0x000
-#define                CODA_REG_RUN_ENABLE             (1 << 0)
-#define CODA_REG_BIT_CODE_DOWN                 0x004
-#define                CODA_DOWN_ADDRESS_SET(x)        (((x) & 0xffff) << 16)
-#define                CODA_DOWN_DATA_SET(x)           ((x) & 0xffff)
-#define CODA_REG_BIT_HOST_IN_REQ               0x008
-#define CODA_REG_BIT_INT_CLEAR                 0x00c
-#define                CODA_REG_BIT_INT_CLEAR_SET      0x1
-#define CODA_REG_BIT_INT_STATUS                0x010
-#define CODA_REG_BIT_CODE_RESET                0x014
-#define                CODA_REG_RESET_ENABLE           (1 << 0)
-#define CODA_REG_BIT_CUR_PC                    0x018
-#define CODA9_REG_BIT_SW_RESET                 0x024
-#define                CODA9_SW_RESET_BPU_CORE   0x008
-#define                CODA9_SW_RESET_BPU_BUS    0x010
-#define                CODA9_SW_RESET_VCE_CORE   0x020
-#define                CODA9_SW_RESET_VCE_BUS    0x040
-#define                CODA9_SW_RESET_GDI_CORE   0x080
-#define                CODA9_SW_RESET_GDI_BUS    0x100
-#define CODA9_REG_BIT_SW_RESET_STATUS          0x034
-
-/* Static SW registers */
-#define CODA_REG_BIT_CODE_BUF_ADDR             0x100
-#define CODA_REG_BIT_WORK_BUF_ADDR             0x104
-#define CODA_REG_BIT_PARA_BUF_ADDR             0x108
-#define CODA_REG_BIT_STREAM_CTRL               0x10c
-#define                CODA7_STREAM_BUF_PIC_RESET      (1 << 4)
-#define                CODADX6_STREAM_BUF_PIC_RESET    (1 << 3)
-#define                CODA7_STREAM_BUF_PIC_FLUSH      (1 << 3)
-#define                CODADX6_STREAM_BUF_PIC_FLUSH    (1 << 2)
-#define                CODA7_STREAM_BUF_DYNALLOC_EN    (1 << 5)
-#define                CODADX6_STREAM_BUF_DYNALLOC_EN  (1 << 4)
-#define                CODADX6_STREAM_CHKDIS_OFFSET    (1 << 1)
-#define                CODA7_STREAM_SEL_64BITS_ENDIAN  (1 << 1)
-#define                CODA_STREAM_ENDIAN_SELECT       (1 << 0)
-#define CODA_REG_BIT_FRAME_MEM_CTRL            0x110
-#define                CODA_FRAME_CHROMA_INTERLEAVE    (1 << 2)
-#define                CODA_IMAGE_ENDIAN_SELECT        (1 << 0)
-#define CODA_REG_BIT_BIT_STREAM_PARAM          0x114
-#define                CODA_BIT_STREAM_END_FLAG        (1 << 2)
-#define                CODA_BIT_DEC_SEQ_INIT_ESCAPE    (1 << 0)
-#define CODA_REG_BIT_TEMP_BUF_ADDR             0x118
-#define CODA_REG_BIT_RD_PTR(x)                 (0x120 + 8 * (x))
-#define CODA_REG_BIT_WR_PTR(x)                 (0x124 + 8 * (x))
-#define CODA_REG_BIT_FRM_DIS_FLG(x)            (0x150 + 4 * (x))
-#define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR   0x140
-#define CODA7_REG_BIT_AXI_SRAM_USE             0x140
-#define                CODA9_USE_HOST_BTP_ENABLE       (1 << 13)
-#define                CODA9_USE_HOST_OVL_ENABLE       (1 << 12)
-#define                CODA7_USE_HOST_ME_ENABLE        (1 << 11)
-#define                CODA9_USE_HOST_DBK_ENABLE       (3 << 10)
-#define                CODA7_USE_HOST_OVL_ENABLE       (1 << 10)
-#define                CODA7_USE_HOST_DBK_ENABLE       (1 << 9)
-#define                CODA9_USE_HOST_IP_ENABLE        (1 << 9)
-#define                CODA7_USE_HOST_IP_ENABLE        (1 << 8)
-#define                CODA9_USE_HOST_BIT_ENABLE       (1 << 8)
-#define                CODA7_USE_HOST_BIT_ENABLE       (1 << 7)
-#define                CODA9_USE_BTP_ENABLE            (1 << 5)
-#define                CODA7_USE_ME_ENABLE             (1 << 4)
-#define                CODA9_USE_OVL_ENABLE            (1 << 4)
-#define                CODA7_USE_OVL_ENABLE            (1 << 3)
-#define                CODA9_USE_DBK_ENABLE            (3 << 2)
-#define                CODA7_USE_DBK_ENABLE            (1 << 2)
-#define                CODA7_USE_IP_ENABLE             (1 << 1)
-#define                CODA7_USE_BIT_ENABLE            (1 << 0)
-
-#define CODA_REG_BIT_BUSY                      0x160
-#define                CODA_REG_BIT_BUSY_FLAG          1
-#define CODA_REG_BIT_RUN_COMMAND               0x164
-#define                CODA_COMMAND_SEQ_INIT           1
-#define                CODA_COMMAND_SEQ_END            2
-#define                CODA_COMMAND_PIC_RUN            3
-#define                CODA_COMMAND_SET_FRAME_BUF      4
-#define                CODA_COMMAND_ENCODE_HEADER      5
-#define                CODA_COMMAND_ENC_PARA_SET       6
-#define                CODA_COMMAND_DEC_PARA_SET       7
-#define                CODA_COMMAND_DEC_BUF_FLUSH      8
-#define                CODA_COMMAND_RC_CHANGE_PARAMETER 9
-#define                CODA_COMMAND_FIRMWARE_GET       0xf
-#define CODA_REG_BIT_RUN_INDEX                 0x168
-#define                CODA_INDEX_SET(x)               ((x) & 0x3)
-#define CODA_REG_BIT_RUN_COD_STD               0x16c
-#define                CODADX6_MODE_DECODE_MP4         0
-#define                CODADX6_MODE_ENCODE_MP4         1
-#define                CODADX6_MODE_DECODE_H264        2
-#define                CODADX6_MODE_ENCODE_H264        3
-#define                CODA7_MODE_DECODE_H264          0
-#define                CODA7_MODE_DECODE_VC1           1
-#define                CODA7_MODE_DECODE_MP2           2
-#define                CODA7_MODE_DECODE_MP4           3
-#define                CODA7_MODE_DECODE_DV3           3
-#define                CODA7_MODE_DECODE_RV            4
-#define                CODA7_MODE_DECODE_MJPG          5
-#define                CODA7_MODE_ENCODE_H264          8
-#define                CODA7_MODE_ENCODE_MP4           11
-#define                CODA7_MODE_ENCODE_MJPG          13
-#define                CODA9_MODE_DECODE_H264          0
-#define                CODA9_MODE_DECODE_VC1           1
-#define                CODA9_MODE_DECODE_MP2           2
-#define                CODA9_MODE_DECODE_MP4           3
-#define                CODA9_MODE_DECODE_DV3           3
-#define                CODA9_MODE_DECODE_RV            4
-#define                CODA9_MODE_DECODE_AVS           5
-#define                CODA9_MODE_DECODE_MJPG          6
-#define                CODA9_MODE_DECODE_VPX           7
-#define                CODA9_MODE_ENCODE_H264          8
-#define                CODA9_MODE_ENCODE_MP4           11
-#define                CODA9_MODE_ENCODE_MJPG          13
-#define        CODA_MODE_INVALID               0xffff
-#define CODA_REG_BIT_INT_ENABLE                0x170
-#define                CODA_INT_INTERRUPT_ENABLE       (1 << 3)
-#define CODA_REG_BIT_INT_REASON                        0x174
-#define CODA7_REG_BIT_RUN_AUX_STD              0x178
-#define                CODA_MP4_AUX_MPEG4              0
-#define                CODA_MP4_AUX_DIVX3              1
-#define                CODA_VPX_AUX_THO                0
-#define                CODA_VPX_AUX_VP6                1
-#define                CODA_VPX_AUX_VP8                2
-#define                CODA_H264_AUX_AVC               0
-#define                CODA_H264_AUX_MVC               1
-
-/*
- * Commands' mailbox:
- * registers with offsets in the range 0x180-0x1d0
- * have different meaning depending on the command being
- * issued.
- */
-
-/* Decoder Sequence Initialization */
-#define CODA_CMD_DEC_SEQ_BB_START              0x180
-#define CODA_CMD_DEC_SEQ_BB_SIZE               0x184
-#define CODA_CMD_DEC_SEQ_OPTION                        0x188
-#define                CODA_REORDER_ENABLE                     (1 << 1)
-#define                CODADX6_QP_REPORT                       (1 << 0)
-#define                CODA7_MP4_DEBLK_ENABLE                  (1 << 0)
-#define CODA_CMD_DEC_SEQ_SRC_SIZE              0x18c
-#define CODA_CMD_DEC_SEQ_START_BYTE            0x190
-#define CODA_CMD_DEC_SEQ_PS_BB_START           0x194
-#define CODA_CMD_DEC_SEQ_PS_BB_SIZE            0x198
-#define CODA_CMD_DEC_SEQ_MP4_ASP_CLASS         0x19c
-#define CODA_CMD_DEC_SEQ_X264_MV_EN            0x19c
-#define CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE                0x1a0
-
-#define CODA7_RET_DEC_SEQ_ASPECT               0x1b0
-#define CODA9_RET_DEC_SEQ_BITRATE              0x1b4
-#define CODA_RET_DEC_SEQ_SUCCESS               0x1c0
-#define CODA_RET_DEC_SEQ_SRC_FMT               0x1c4 /* SRC_SIZE on CODA7 */
-#define CODA_RET_DEC_SEQ_SRC_SIZE              0x1c4
-#define CODA_RET_DEC_SEQ_SRC_F_RATE            0x1c8
-#define CODA9_RET_DEC_SEQ_ASPECT               0x1c8
-#define CODA_RET_DEC_SEQ_FRAME_NEED            0x1cc
-#define CODA_RET_DEC_SEQ_FRAME_DELAY           0x1d0
-#define CODA_RET_DEC_SEQ_INFO                  0x1d4
-#define CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT       0x1d8
-#define CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM       0x1dc
-#define CODA_RET_DEC_SEQ_NEXT_FRAME_NUM                0x1e0
-#define CODA_RET_DEC_SEQ_ERR_REASON            0x1e0
-#define CODA_RET_DEC_SEQ_FRATE_NR              0x1e4
-#define CODA_RET_DEC_SEQ_FRATE_DR              0x1e8
-#define CODA_RET_DEC_SEQ_JPG_PARA              0x1e4
-#define CODA_RET_DEC_SEQ_JPG_THUMB_IND         0x1e8
-#define CODA9_RET_DEC_SEQ_HEADER_REPORT                0x1ec
-
-/* Decoder Picture Run */
-#define CODA_CMD_DEC_PIC_ROT_MODE              0x180
-#define CODA_CMD_DEC_PIC_ROT_ADDR_Y            0x184
-#define CODA9_CMD_DEC_PIC_ROT_INDEX            0x184
-#define CODA_CMD_DEC_PIC_ROT_ADDR_CB           0x188
-#define CODA9_CMD_DEC_PIC_ROT_ADDR_Y           0x188
-#define CODA_CMD_DEC_PIC_ROT_ADDR_CR           0x18c
-#define CODA9_CMD_DEC_PIC_ROT_ADDR_CB          0x18c
-#define CODA_CMD_DEC_PIC_ROT_STRIDE            0x190
-#define CODA9_CMD_DEC_PIC_ROT_ADDR_CR          0x190
-#define CODA9_CMD_DEC_PIC_ROT_STRIDE           0x1b8
-
-#define CODA_CMD_DEC_PIC_OPTION                        0x194
-#define                CODA_PRE_SCAN_EN                        (1 << 0)
-#define                CODA_PRE_SCAN_MODE_DECODE               (0 << 1)
-#define                CODA_PRE_SCAN_MODE_RETURN               (1 << 1)
-#define                CODA_IFRAME_SEARCH_EN                   (1 << 2)
-#define                CODA_SKIP_FRAME_MODE                    (0x3 << 3)
-#define CODA_CMD_DEC_PIC_SKIP_NUM              0x198
-#define CODA_CMD_DEC_PIC_CHUNK_SIZE            0x19c
-#define CODA_CMD_DEC_PIC_BB_START              0x1a0
-#define CODA_CMD_DEC_PIC_START_BYTE            0x1a4
-#define CODA_RET_DEC_PIC_SIZE                  0x1bc
-#define CODA_RET_DEC_PIC_FRAME_NUM             0x1c0
-#define CODA_RET_DEC_PIC_FRAME_IDX             0x1c4
-#define CODA_RET_DEC_PIC_ERR_MB                        0x1c8
-#define CODA_RET_DEC_PIC_TYPE                  0x1cc
-#define                CODA_PIC_TYPE_MASK                      0x7
-#define                CODA_PIC_TYPE_MASK_VC1                  0x3f
-#define                CODA9_PIC_TYPE_FIRST_MASK               (0x7 << 3)
-#define                CODA9_PIC_TYPE_IDR_MASK                 (0x3 << 6)
-#define                CODA7_PIC_TYPE_H264_NPF_MASK            (0x3 << 16)
-#define                CODA7_PIC_TYPE_INTERLACED               (1 << 18)
-#define CODA_RET_DEC_PIC_POST                  0x1d0
-#define CODA_RET_DEC_PIC_MVC_REPORT            0x1d0
-#define CODA_RET_DEC_PIC_OPTION                        0x1d4
-#define CODA_RET_DEC_PIC_SUCCESS               0x1d8
-#define CODA_RET_DEC_PIC_CUR_IDX               0x1dc
-#define CODA_RET_DEC_PIC_CROP_LEFT_RIGHT       0x1e0
-#define CODA_RET_DEC_PIC_CROP_TOP_BOTTOM       0x1e4
-#define CODA_RET_DEC_PIC_FRAME_NEED            0x1ec
-
-#define CODA9_RET_DEC_PIC_VP8_PIC_REPORT       0x1e8
-#define CODA9_RET_DEC_PIC_ASPECT               0x1f0
-#define CODA9_RET_DEC_PIC_VP8_SCALE_INFO       0x1f0
-#define CODA9_RET_DEC_PIC_FRATE_NR             0x1f4
-#define CODA9_RET_DEC_PIC_FRATE_DR             0x1f8
-
-/* Encoder Sequence Initialization */
-#define CODA_CMD_ENC_SEQ_BB_START                              0x180
-#define CODA_CMD_ENC_SEQ_BB_SIZE                               0x184
-#define CODA_CMD_ENC_SEQ_OPTION                                0x188
-#define                CODA7_OPTION_AVCINTRA16X16ONLY_OFFSET           9
-#define                CODA9_OPTION_MVC_PREFIX_NAL_OFFSET              9
-#define                CODA7_OPTION_GAMMA_OFFSET                       8
-#define                CODA9_OPTION_MVC_PARASET_REFRESH_OFFSET         8
-#define                CODA7_OPTION_RCQPMAX_OFFSET                     7
-#define                CODA9_OPTION_GAMMA_OFFSET                       7
-#define                CODADX6_OPTION_GAMMA_OFFSET                     7
-#define                CODA7_OPTION_RCQPMIN_OFFSET                     6
-#define                CODA9_OPTION_RCQPMAX_OFFSET                     6
-#define                CODA_OPTION_LIMITQP_OFFSET                      6
-#define                CODA_OPTION_RCINTRAQP_OFFSET                    5
-#define                CODA_OPTION_FMO_OFFSET                          4
-#define                CODA9_OPTION_MVC_INTERVIEW_OFFSET               4
-#define                CODA_OPTION_AVC_AUD_OFFSET                      2
-#define                CODA_OPTION_SLICEREPORT_OFFSET                  1
-#define CODA_CMD_ENC_SEQ_COD_STD                               0x18c
-#define                CODA_STD_MPEG4                                  0
-#define                CODA9_STD_H264                                  0
-#define                CODA_STD_H263                                   1
-#define                CODA_STD_H264                                   2
-#define                CODA_STD_MJPG                                   3
-#define                CODA9_STD_MPEG4                                 3
-
-#define CODA_CMD_ENC_SEQ_SRC_SIZE                              0x190
-#define                CODA7_PICWIDTH_OFFSET                           16
-#define                CODA7_PICWIDTH_MASK                             0xffff
-#define                CODADX6_PICWIDTH_OFFSET                         10
-#define                CODADX6_PICWIDTH_MASK                           0x3ff
-#define                CODA_PICHEIGHT_OFFSET                           0
-#define                CODADX6_PICHEIGHT_MASK                          0x3ff
-#define                CODA7_PICHEIGHT_MASK                            0xffff
-#define CODA_CMD_ENC_SEQ_SRC_F_RATE                            0x194
-#define CODA_CMD_ENC_SEQ_MP4_PARA                              0x198
-#define                CODA_MP4PARAM_VERID_OFFSET                      6
-#define                CODA_MP4PARAM_VERID_MASK                        0x01
-#define                CODA_MP4PARAM_INTRADCVLCTHR_OFFSET              2
-#define                CODA_MP4PARAM_INTRADCVLCTHR_MASK                0x07
-#define                CODA_MP4PARAM_REVERSIBLEVLCENABLE_OFFSET        1
-#define                CODA_MP4PARAM_REVERSIBLEVLCENABLE_MASK          0x01
-#define                CODA_MP4PARAM_DATAPARTITIONENABLE_OFFSET        0
-#define                CODA_MP4PARAM_DATAPARTITIONENABLE_MASK          0x01
-#define CODA_CMD_ENC_SEQ_263_PARA                              0x19c
-#define                CODA_263PARAM_ANNEXJENABLE_OFFSET               2
-#define                CODA_263PARAM_ANNEXJENABLE_MASK         0x01
-#define                CODA_263PARAM_ANNEXKENABLE_OFFSET               1
-#define                CODA_263PARAM_ANNEXKENABLE_MASK         0x01
-#define                CODA_263PARAM_ANNEXTENABLE_OFFSET               0
-#define                CODA_263PARAM_ANNEXTENABLE_MASK         0x01
-#define CODA_CMD_ENC_SEQ_264_PARA                              0x1a0
-#define                CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET      12
-#define                CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK        0x0f
-#define                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET     8
-#define                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK       0x0f
-#define                CODA_264PARAM_DISABLEDEBLK_OFFSET               6
-#define                CODA_264PARAM_DISABLEDEBLK_MASK         0x01
-#define                CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET   5
-#define                CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK     0x01
-#define                CODA_264PARAM_CHROMAQPOFFSET_OFFSET             0
-#define                CODA_264PARAM_CHROMAQPOFFSET_MASK               0x1f
-#define CODA_CMD_ENC_SEQ_SLICE_MODE                            0x1a4
-#define                CODA_SLICING_SIZE_OFFSET                        2
-#define                CODA_SLICING_SIZE_MASK                          0x3fffffff
-#define                CODA_SLICING_UNIT_OFFSET                        1
-#define                CODA_SLICING_UNIT_MASK                          0x01
-#define                CODA_SLICING_MODE_OFFSET                        0
-#define                CODA_SLICING_MODE_MASK                          0x01
-#define CODA_CMD_ENC_SEQ_GOP_SIZE                              0x1a8
-#define                CODA_GOP_SIZE_OFFSET                            0
-#define                CODA_GOP_SIZE_MASK                              0x3f
-#define CODA_CMD_ENC_SEQ_RC_PARA                               0x1ac
-#define                CODA_RATECONTROL_AUTOSKIP_OFFSET                31
-#define                CODA_RATECONTROL_AUTOSKIP_MASK                  0x01
-#define                CODA_RATECONTROL_INITIALDELAY_OFFSET            16
-#define                CODA_RATECONTROL_INITIALDELAY_MASK              0x7f
-#define                CODA_RATECONTROL_BITRATE_OFFSET         1
-#define                CODA_RATECONTROL_BITRATE_MASK                   0x7f
-#define                CODA_RATECONTROL_ENABLE_OFFSET                  0
-#define                CODA_RATECONTROL_ENABLE_MASK                    0x01
-#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE                           0x1b0
-#define CODA_CMD_ENC_SEQ_INTRA_REFRESH                         0x1b4
-#define CODADX6_CMD_ENC_SEQ_FMO                                        0x1b8
-#define                CODA_FMOPARAM_TYPE_OFFSET                       4
-#define                CODA_FMOPARAM_TYPE_MASK                         1
-#define                CODA_FMOPARAM_SLICENUM_OFFSET                   0
-#define                CODA_FMOPARAM_SLICENUM_MASK                     0x0f
-#define CODADX6_CMD_ENC_SEQ_INTRA_QP                           0x1bc
-#define CODA7_CMD_ENC_SEQ_SEARCH_BASE                          0x1b8
-#define CODA7_CMD_ENC_SEQ_SEARCH_SIZE                          0x1bc
-#define CODA7_CMD_ENC_SEQ_INTRA_QP                             0x1c4
-#define CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX                         0x1c8
-#define                CODA_QPMIN_OFFSET                               8
-#define                CODA_QPMIN_MASK                                 0x3f
-#define                CODA_QPMAX_OFFSET                               0
-#define                CODA_QPMAX_MASK                                 0x3f
-#define CODA_CMD_ENC_SEQ_RC_GAMMA                              0x1cc
-#define                CODA_GAMMA_OFFSET                               0
-#define                CODA_GAMMA_MASK                                 0xffff
-#define CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE                      0x1d0
-#define CODA9_CMD_ENC_SEQ_INTRA_WEIGHT                         0x1d4
-#define CODA9_CMD_ENC_SEQ_ME_OPTION                            0x1d8
-#define CODA_RET_ENC_SEQ_SUCCESS                               0x1c0
-
-/* Encoder Picture Run */
-#define CODA9_CMD_ENC_PIC_SRC_INDEX            0x180
-#define CODA9_CMD_ENC_PIC_SRC_STRIDE           0x184
-#define CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC       0x1a4
-#define CODA9_CMD_ENC_PIC_SRC_ADDR_Y           0x1a8
-#define CODA9_CMD_ENC_PIC_SRC_ADDR_CB          0x1ac
-#define CODA9_CMD_ENC_PIC_SRC_ADDR_CR          0x1b0
-#define CODA_CMD_ENC_PIC_SRC_ADDR_Y    0x180
-#define CODA_CMD_ENC_PIC_SRC_ADDR_CB   0x184
-#define CODA_CMD_ENC_PIC_SRC_ADDR_CR   0x188
-#define CODA_CMD_ENC_PIC_QS            0x18c
-#define CODA_CMD_ENC_PIC_ROT_MODE      0x190
-#define                CODA_ROT_MIR_ENABLE                             (1 << 4)
-#define                CODA_ROT_0                                      (0x0 << 0)
-#define                CODA_ROT_90                                     (0x1 << 0)
-#define                CODA_ROT_180                                    (0x2 << 0)
-#define                CODA_ROT_270                                    (0x3 << 0)
-#define                CODA_MIR_NONE                                   (0x0 << 2)
-#define                CODA_MIR_VER                                    (0x1 << 2)
-#define                CODA_MIR_HOR                                    (0x2 << 2)
-#define                CODA_MIR_VER_HOR                                (0x3 << 2)
-#define CODA_CMD_ENC_PIC_OPTION                0x194
-#define                CODA_FORCE_IPICTURE                             BIT(1)
-#define                CODA_REPORT_MB_INFO                             BIT(3)
-#define                CODA_REPORT_MV_INFO                             BIT(4)
-#define                CODA_REPORT_SLICE_INFO                          BIT(5)
-#define CODA_CMD_ENC_PIC_BB_START      0x198
-#define CODA_CMD_ENC_PIC_BB_SIZE       0x19c
-#define CODA_RET_ENC_FRAME_NUM         0x1c0
-#define CODA_RET_ENC_PIC_TYPE          0x1c4
-#define CODA_RET_ENC_PIC_FRAME_IDX     0x1c8
-#define CODA_RET_ENC_PIC_SLICE_NUM     0x1cc
-#define CODA_RET_ENC_PIC_FLAG          0x1d0
-#define CODA_RET_ENC_PIC_SUCCESS       0x1d8
-
-/* Set Frame Buffer */
-#define CODA_CMD_SET_FRAME_BUF_NUM             0x180
-#define CODA_CMD_SET_FRAME_BUF_STRIDE          0x184
-#define CODA_CMD_SET_FRAME_SLICE_BB_START      0x188
-#define CODA_CMD_SET_FRAME_SLICE_BB_SIZE       0x18c
-#define CODA9_CMD_SET_FRAME_SUBSAMP_A          0x188
-#define CODA9_CMD_SET_FRAME_SUBSAMP_B          0x18c
-#define CODA7_CMD_SET_FRAME_AXI_BIT_ADDR       0x190
-#define CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR    0x194
-#define CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR      0x198
-#define CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR      0x19c
-#define CODA7_CMD_SET_FRAME_AXI_OVL_ADDR       0x1a0
-#define CODA7_CMD_SET_FRAME_MAX_DEC_SIZE       0x1a4
-#define CODA9_CMD_SET_FRAME_AXI_BTP_ADDR       0x1a4
-#define CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE  0x1a8
-#define CODA9_CMD_SET_FRAME_CACHE_SIZE         0x1a8
-#define CODA9_CMD_SET_FRAME_CACHE_CONFIG       0x1ac
-#define                CODA9_CACHE_BYPASS_OFFSET               28
-#define                CODA9_CACHE_DUALCONF_OFFSET             26
-#define                CODA9_CACHE_PAGEMERGE_OFFSET            24
-#define                CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET     16
-#define                CODA9_CACHE_CB_BUFFER_SIZE_OFFSET       8
-#define                CODA9_CACHE_CR_BUFFER_SIZE_OFFSET       0
-#define CODA9_CMD_SET_FRAME_SUBSAMP_A_MVC      0x1b0
-#define CODA9_CMD_SET_FRAME_SUBSAMP_B_MVC      0x1b4
-#define CODA9_CMD_SET_FRAME_DP_BUF_BASE                0x1b0
-#define CODA9_CMD_SET_FRAME_DP_BUF_SIZE                0x1b4
-#define CODA9_CMD_SET_FRAME_MAX_DEC_SIZE       0x1b8
-#define CODA9_CMD_SET_FRAME_DELAY              0x1bc
-
-/* Encoder Header */
-#define CODA_CMD_ENC_HEADER_CODE       0x180
-#define                CODA_GAMMA_OFFSET       0
-#define                CODA_HEADER_H264_SPS    0
-#define                CODA_HEADER_H264_PPS    1
-#define                CODA_HEADER_MP4V_VOL    0
-#define                CODA_HEADER_MP4V_VOS    1
-#define                CODA_HEADER_MP4V_VIS    2
-#define                CODA9_HEADER_FRAME_CROP (1 << 3)
-#define CODA_CMD_ENC_HEADER_BB_START   0x184
-#define CODA_CMD_ENC_HEADER_BB_SIZE    0x188
-#define CODA9_CMD_ENC_HEADER_FRAME_CROP_H      0x18c
-#define CODA9_CMD_ENC_HEADER_FRAME_CROP_V      0x190
-
-/* Get Version */
-#define CODA_CMD_FIRMWARE_VERNUM               0x1c0
-#define                CODA_FIRMWARE_PRODUCT(x)        (((x) >> 16) & 0xffff)
-#define                CODA_FIRMWARE_MAJOR(x)          (((x) >> 12) & 0x0f)
-#define                CODA_FIRMWARE_MINOR(x)          (((x) >> 8) & 0x0f)
-#define                CODA_FIRMWARE_RELEASE(x)        ((x) & 0xff)
-#define                CODA_FIRMWARE_VERNUM(product, major, minor, release)    \
-                       ((product) << 16 | ((major) << 12) |            \
-                       ((minor) << 8) | (release))
-#define CODA9_CMD_FIRMWARE_CODE_REV            0x1c4
-
-#define CODA9_GDMA_BASE                                0x1000
-#define CODA9_GDI_WPROT_ERR_CLR                        (CODA9_GDMA_BASE + 0x0a0)
-#define CODA9_GDI_WPROT_RGN_EN                 (CODA9_GDMA_BASE + 0x0ac)
-
-#define CODA9_GDI_BUS_CTRL                     (CODA9_GDMA_BASE + 0x0f0)
-#define CODA9_GDI_BUS_STATUS                   (CODA9_GDMA_BASE + 0x0f4)
-
-#define CODA9_GDI_XY2_CAS_0                    (CODA9_GDMA_BASE + 0x800)
-#define CODA9_GDI_XY2_CAS_F                    (CODA9_GDMA_BASE + 0x83c)
-
-#define CODA9_GDI_XY2_BA_0                     (CODA9_GDMA_BASE + 0x840)
-#define CODA9_GDI_XY2_BA_1                     (CODA9_GDMA_BASE + 0x844)
-#define CODA9_GDI_XY2_BA_2                     (CODA9_GDMA_BASE + 0x848)
-#define CODA9_GDI_XY2_BA_3                     (CODA9_GDMA_BASE + 0x84c)
-
-#define CODA9_GDI_XY2_RAS_0                    (CODA9_GDMA_BASE + 0x850)
-#define CODA9_GDI_XY2_RAS_F                    (CODA9_GDMA_BASE + 0x88c)
-
-#define CODA9_GDI_XY2_RBC_CONFIG               (CODA9_GDMA_BASE + 0x890)
-#define CODA9_GDI_RBC2_AXI_0                   (CODA9_GDMA_BASE + 0x8a0)
-#define CODA9_GDI_RBC2_AXI_1F                  (CODA9_GDMA_BASE + 0x91c)
-
-#endif
diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile
new file mode 100644 (file)
index 0000000..3543291
--- /dev/null
@@ -0,0 +1,3 @@
+coda-objs := coda-common.o coda-bit.o coda-h264.o
+
+obj-$(CONFIG_VIDEO_CODA) += coda.o
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
new file mode 100644 (file)
index 0000000..9b8ea8b
--- /dev/null
@@ -0,0 +1,1861 @@
+/*
+ * Coda multi-standard codec IP - BIT processor functions
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix
+ *
+ * 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/clk.h>
+#include <linux/irqreturn.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "coda.h"
+
+#define CODA7_PS_BUF_SIZE      0x28000
+#define CODA9_PS_SAVE_SIZE     (512 * 1024)
+
+#define CODA_DEFAULT_GAMMA     4096
+#define CODA9_DEFAULT_GAMMA    24576   /* 0.75 * 32768 */
+
+static inline int coda_is_initialized(struct coda_dev *dev)
+{
+       return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0;
+}
+
+static inline unsigned long coda_isbusy(struct coda_dev *dev)
+{
+       return coda_read(dev, CODA_REG_BIT_BUSY);
+}
+
+static int coda_wait_timeout(struct coda_dev *dev)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+       while (coda_isbusy(dev)) {
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+       }
+       return 0;
+}
+
+static void coda_command_async(struct coda_ctx *ctx, int cmd)
+{
+       struct coda_dev *dev = ctx->dev;
+
+       if (dev->devtype->product == CODA_960 ||
+           dev->devtype->product == CODA_7541) {
+               /* Restore context related registers to CODA */
+               coda_write(dev, ctx->bit_stream_param,
+                               CODA_REG_BIT_BIT_STREAM_PARAM);
+               coda_write(dev, ctx->frm_dis_flg,
+                               CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+               coda_write(dev, ctx->frame_mem_ctrl,
+                               CODA_REG_BIT_FRAME_MEM_CTRL);
+               coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
+       }
+
+       if (dev->devtype->product == CODA_960) {
+               coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR);
+               coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
+       }
+
+       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+
+       coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
+       coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
+       coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD);
+
+       coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
+}
+
+static int coda_command_sync(struct coda_ctx *ctx, int cmd)
+{
+       struct coda_dev *dev = ctx->dev;
+
+       coda_command_async(ctx, cmd);
+       return coda_wait_timeout(dev);
+}
+
+int coda_hw_reset(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+       unsigned long timeout;
+       unsigned int idx;
+       int ret;
+
+       if (!dev->rstc)
+               return -ENOENT;
+
+       idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX);
+
+       if (dev->devtype->product == CODA_960) {
+               timeout = jiffies + msecs_to_jiffies(100);
+               coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL);
+               while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) {
+                       if (time_after(jiffies, timeout))
+                               return -ETIME;
+                       cpu_relax();
+               }
+       }
+
+       ret = reset_control_reset(dev->rstc);
+       if (ret < 0)
+               return ret;
+
+       if (dev->devtype->product == CODA_960)
+               coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL);
+       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+       coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
+       ret = coda_wait_timeout(dev);
+       coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX);
+
+       return ret;
+}
+
+static void coda_kfifo_sync_from_device(struct coda_ctx *ctx)
+{
+       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
+       struct coda_dev *dev = ctx->dev;
+       u32 rd_ptr;
+
+       rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+       kfifo->out = (kfifo->in & ~kfifo->mask) |
+                     (rd_ptr - ctx->bitstream.paddr);
+       if (kfifo->out > kfifo->in)
+               kfifo->out -= kfifo->mask + 1;
+}
+
+static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx)
+{
+       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
+       struct coda_dev *dev = ctx->dev;
+       u32 rd_ptr, wr_ptr;
+
+       rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask);
+       coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+       wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
+       coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+}
+
+static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx)
+{
+       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
+       struct coda_dev *dev = ctx->dev;
+       u32 wr_ptr;
+
+       wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
+       coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+}
+
+static int coda_bitstream_queue(struct coda_ctx *ctx,
+                               struct vb2_buffer *src_buf)
+{
+       u32 src_size = vb2_get_plane_payload(src_buf, 0);
+       u32 n;
+
+       n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0),
+                    src_size);
+       if (n < src_size)
+               return -ENOSPC;
+
+       dma_sync_single_for_device(&ctx->dev->plat_dev->dev,
+                                  ctx->bitstream.paddr, ctx->bitstream.size,
+                                  DMA_TO_DEVICE);
+
+       src_buf->v4l2_buf.sequence = ctx->qsequence++;
+
+       return 0;
+}
+
+static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
+                                    struct vb2_buffer *src_buf)
+{
+       int ret;
+
+       if (coda_get_bitstream_payload(ctx) +
+           vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size)
+               return false;
+
+       if (vb2_plane_vaddr(src_buf, 0) == NULL) {
+               v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n");
+               return true;
+       }
+
+       ret = coda_bitstream_queue(ctx, src_buf);
+       if (ret < 0) {
+               v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n");
+               return false;
+       }
+       /* Sync read pointer to device */
+       if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
+               coda_kfifo_sync_to_device_write(ctx);
+
+       ctx->hold = false;
+
+       return true;
+}
+
+void coda_fill_bitstream(struct coda_ctx *ctx)
+{
+       struct vb2_buffer *src_buf;
+       struct coda_timestamp *ts;
+
+       while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
+               src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+
+               if (coda_bitstream_try_queue(ctx, src_buf)) {
+                       /*
+                        * Source buffer is queued in the bitstream ringbuffer;
+                        * queue the timestamp and mark source buffer as done
+                        */
+                       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+
+                       ts = kmalloc(sizeof(*ts), GFP_KERNEL);
+                       if (ts) {
+                               ts->sequence = src_buf->v4l2_buf.sequence;
+                               ts->timecode = src_buf->v4l2_buf.timecode;
+                               ts->timestamp = src_buf->v4l2_buf.timestamp;
+                               list_add_tail(&ts->list, &ctx->timestamp_list);
+                       }
+
+                       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+               } else {
+                       break;
+               }
+       }
+}
+
+void coda_bit_stream_end_flag(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+
+       ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+
+       /* If this context is currently running, update the hardware flag */
+       if ((dev->devtype->product == CODA_960) &&
+           coda_isbusy(dev) &&
+           (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
+               coda_write(dev, ctx->bit_stream_param,
+                          CODA_REG_BIT_BIT_STREAM_PARAM);
+       }
+}
+
+static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
+{
+       struct coda_dev *dev = ctx->dev;
+       u32 *p = ctx->parabuf.vaddr;
+
+       if (dev->devtype->product == CODA_DX6)
+               p[index] = value;
+       else
+               p[index ^ 1] = value;
+}
+
+static void coda_free_framebuffers(struct coda_ctx *ctx)
+{
+       int i;
+
+       for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++)
+               coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]);
+}
+
+static int coda_alloc_framebuffers(struct coda_ctx *ctx,
+                                  struct coda_q_data *q_data, u32 fourcc)
+{
+       struct coda_dev *dev = ctx->dev;
+       int width, height;
+       dma_addr_t paddr;
+       int ysize;
+       int ret;
+       int i;
+
+       if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
+            ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) {
+               width = round_up(q_data->width, 16);
+               height = round_up(q_data->height, 16);
+       } else {
+               width = round_up(q_data->width, 8);
+               height = q_data->height;
+       }
+       ysize = width * height;
+
+       /* Allocate frame buffers */
+       for (i = 0; i < ctx->num_internal_frames; i++) {
+               size_t size;
+               char *name;
+
+               size = ysize + ysize / 2;
+               if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
+                   dev->devtype->product != CODA_DX6)
+                       size += ysize / 4;
+               name = kasprintf(GFP_KERNEL, "fb%d", i);
+               ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i],
+                                            size, name);
+               kfree(name);
+               if (ret < 0) {
+                       coda_free_framebuffers(ctx);
+                       return ret;
+               }
+       }
+
+       /* Register frame buffers in the parameter buffer */
+       for (i = 0; i < ctx->num_internal_frames; i++) {
+               paddr = ctx->internal_frames[i].paddr;
+               /* Start addresses of Y, Cb, Cr planes */
+               coda_parabuf_write(ctx, i * 3 + 0, paddr);
+               coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize);
+               coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize / 4);
+
+               /* mvcol buffer for h.264 */
+               if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
+                   dev->devtype->product != CODA_DX6)
+                       coda_parabuf_write(ctx, 96 + i,
+                                          ctx->internal_frames[i].paddr +
+                                          ysize + ysize/4 + ysize/4);
+       }
+
+       /* mvcol buffer for mpeg4 */
+       if ((dev->devtype->product != CODA_DX6) &&
+           (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4))
+               coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr +
+                                           ysize + ysize/4 + ysize/4);
+
+       return 0;
+}
+
+static void coda_free_context_buffers(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+
+       coda_free_aux_buf(dev, &ctx->slicebuf);
+       coda_free_aux_buf(dev, &ctx->psbuf);
+       if (dev->devtype->product != CODA_DX6)
+               coda_free_aux_buf(dev, &ctx->workbuf);
+}
+
+static int coda_alloc_context_buffers(struct coda_ctx *ctx,
+                                     struct coda_q_data *q_data)
+{
+       struct coda_dev *dev = ctx->dev;
+       size_t size;
+       int ret;
+
+       if (dev->devtype->product == CODA_DX6)
+               return 0;
+
+       if (ctx->psbuf.vaddr) {
+               v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n");
+               return -EBUSY;
+       }
+       if (ctx->slicebuf.vaddr) {
+               v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n");
+               return -EBUSY;
+       }
+       if (ctx->workbuf.vaddr) {
+               v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
+               ret = -EBUSY;
+               return -ENOMEM;
+       }
+
+       if (q_data->fourcc == V4L2_PIX_FMT_H264) {
+               /* worst case slice size */
+               size = (DIV_ROUND_UP(q_data->width, 16) *
+                       DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512;
+               ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size,
+                                            "slicebuf");
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "failed to allocate %d byte slice buffer",
+                                ctx->slicebuf.size);
+                       return ret;
+               }
+       }
+
+       if (dev->devtype->product == CODA_7541) {
+               ret = coda_alloc_context_buf(ctx, &ctx->psbuf,
+                                            CODA7_PS_BUF_SIZE, "psbuf");
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "failed to allocate psmem buffer");
+                       goto err;
+               }
+       }
+
+       size = dev->devtype->workbuf_size;
+       if (dev->devtype->product == CODA_960 &&
+           q_data->fourcc == V4L2_PIX_FMT_H264)
+               size += CODA9_PS_SAVE_SIZE;
+       ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf");
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev,
+                        "failed to allocate %d byte context buffer",
+                        ctx->workbuf.size);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       coda_free_context_buffers(ctx);
+       return ret;
+}
+
+static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
+                             int header_code, u8 *header, int *size)
+{
+       struct coda_dev *dev = ctx->dev;
+       size_t bufsize;
+       int ret;
+       int i;
+
+       if (dev->devtype->product == CODA_960)
+               memset(vb2_plane_vaddr(buf, 0), 0, 64);
+
+       coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0),
+                  CODA_CMD_ENC_HEADER_BB_START);
+       bufsize = vb2_plane_size(buf, 0);
+       if (dev->devtype->product == CODA_960)
+               bufsize /= 1024;
+       coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE);
+       coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE);
+       ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+               return ret;
+       }
+
+       if (dev->devtype->product == CODA_960) {
+               for (i = 63; i > 0; i--)
+                       if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0)
+                               break;
+               *size = i + 1;
+       } else {
+               *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
+                       coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+       }
+       memcpy(header, vb2_plane_vaddr(buf, 0), *size);
+
+       return 0;
+}
+
+static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size)
+{
+       phys_addr_t ret;
+
+       size = round_up(size, 1024);
+       if (size > iram->remaining)
+               return 0;
+       iram->remaining -= size;
+
+       ret = iram->next_paddr;
+       iram->next_paddr += size;
+
+       return ret;
+}
+
+static void coda_setup_iram(struct coda_ctx *ctx)
+{
+       struct coda_iram_info *iram_info = &ctx->iram_info;
+       struct coda_dev *dev = ctx->dev;
+       int w64, w128;
+       int mb_width;
+       int dbk_bits;
+       int bit_bits;
+       int ip_bits;
+
+       memset(iram_info, 0, sizeof(*iram_info));
+       iram_info->next_paddr = dev->iram.paddr;
+       iram_info->remaining = dev->iram.size;
+
+       if (!dev->iram.vaddr)
+               return;
+
+       switch (dev->devtype->product) {
+       case CODA_7541:
+               dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE;
+               bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
+               ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
+               break;
+       case CODA_960:
+               dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE;
+               bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
+               ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
+               break;
+       default: /* CODA_DX6 */
+               return;
+       }
+
+       if (ctx->inst_type == CODA_INST_ENCODER) {
+               struct coda_q_data *q_data_src;
+
+               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+               mb_width = DIV_ROUND_UP(q_data_src->width, 16);
+               w128 = mb_width * 128;
+               w64 = mb_width * 64;
+
+               /* Prioritize in case IRAM is too small for everything */
+               if (dev->devtype->product == CODA_7541) {
+                       iram_info->search_ram_size = round_up(mb_width * 16 *
+                                                             36 + 2048, 1024);
+                       iram_info->search_ram_paddr = coda_iram_alloc(iram_info,
+                                               iram_info->search_ram_size);
+                       if (!iram_info->search_ram_paddr) {
+                               pr_err("IRAM is smaller than the search ram size\n");
+                               goto out;
+                       }
+                       iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE |
+                                                  CODA7_USE_ME_ENABLE;
+               }
+
+               /* Only H.264BP and H.263P3 are considered */
+               iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64);
+               iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64);
+               if (!iram_info->buf_dbk_c_use)
+                       goto out;
+               iram_info->axi_sram_use |= dbk_bits;
+
+               iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128);
+               if (!iram_info->buf_bit_use)
+                       goto out;
+               iram_info->axi_sram_use |= bit_bits;
+
+               iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128);
+               if (!iram_info->buf_ip_ac_dc_use)
+                       goto out;
+               iram_info->axi_sram_use |= ip_bits;
+
+               /* OVL and BTP disabled for encoder */
+       } else if (ctx->inst_type == CODA_INST_DECODER) {
+               struct coda_q_data *q_data_dst;
+
+               q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+               mb_width = DIV_ROUND_UP(q_data_dst->width, 16);
+               w128 = mb_width * 128;
+
+               iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128);
+               iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128);
+               if (!iram_info->buf_dbk_c_use)
+                       goto out;
+               iram_info->axi_sram_use |= dbk_bits;
+
+               iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128);
+               if (!iram_info->buf_bit_use)
+                       goto out;
+               iram_info->axi_sram_use |= bit_bits;
+
+               iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128);
+               if (!iram_info->buf_ip_ac_dc_use)
+                       goto out;
+               iram_info->axi_sram_use |= ip_bits;
+
+               /* OVL and BTP unused as there is no VC1 support yet */
+       }
+
+out:
+       if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE))
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "IRAM smaller than needed\n");
+
+       if (dev->devtype->product == CODA_7541) {
+               /* TODO - Enabling these causes picture errors on CODA7541 */
+               if (ctx->inst_type == CODA_INST_DECODER) {
+                       /* fw 1.4.50 */
+                       iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
+                                                    CODA7_USE_IP_ENABLE);
+               } else {
+                       /* fw 13.4.29 */
+                       iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
+                                                    CODA7_USE_HOST_DBK_ENABLE |
+                                                    CODA7_USE_IP_ENABLE |
+                                                    CODA7_USE_DBK_ENABLE);
+               }
+       }
+}
+
+static u32 coda_supported_firmwares[] = {
+       CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
+       CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
+       CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5),
+};
+
+static bool coda_firmware_supported(u32 vernum)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++)
+               if (vernum == coda_supported_firmwares[i])
+                       return true;
+       return false;
+}
+
+int coda_check_firmware(struct coda_dev *dev)
+{
+       u16 product, major, minor, release;
+       u32 data;
+       int ret;
+
+       ret = clk_prepare_enable(dev->clk_per);
+       if (ret)
+               goto err_clk_per;
+
+       ret = clk_prepare_enable(dev->clk_ahb);
+       if (ret)
+               goto err_clk_ahb;
+
+       coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM);
+       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+       coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX);
+       coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD);
+       coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND);
+       if (coda_wait_timeout(dev)) {
+               v4l2_err(&dev->v4l2_dev, "firmware get command error\n");
+               ret = -EIO;
+               goto err_run_cmd;
+       }
+
+       if (dev->devtype->product == CODA_960) {
+               data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV);
+               v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n",
+                         data);
+       }
+
+       /* Check we are compatible with the loaded firmware */
+       data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM);
+       product = CODA_FIRMWARE_PRODUCT(data);
+       major = CODA_FIRMWARE_MAJOR(data);
+       minor = CODA_FIRMWARE_MINOR(data);
+       release = CODA_FIRMWARE_RELEASE(data);
+
+       clk_disable_unprepare(dev->clk_per);
+       clk_disable_unprepare(dev->clk_ahb);
+
+       if (product != dev->devtype->product) {
+               v4l2_err(&dev->v4l2_dev,
+                        "Wrong firmware. Hw: %s, Fw: %s, Version: %u.%u.%u\n",
+                        coda_product_name(dev->devtype->product),
+                        coda_product_name(product), major, minor, release);
+               return -EINVAL;
+       }
+
+       v4l2_info(&dev->v4l2_dev, "Initialized %s.\n",
+                 coda_product_name(product));
+
+       if (coda_firmware_supported(data)) {
+               v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n",
+                         major, minor, release);
+       } else {
+               v4l2_warn(&dev->v4l2_dev,
+                         "Unsupported firmware version: %u.%u.%u\n",
+                         major, minor, release);
+       }
+
+       return 0;
+
+err_run_cmd:
+       clk_disable_unprepare(dev->clk_ahb);
+err_clk_ahb:
+       clk_disable_unprepare(dev->clk_per);
+err_clk_per:
+       return ret;
+}
+
+/*
+ * Encoder context operations
+ */
+
+static int coda_start_encoding(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+       struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+       struct coda_q_data *q_data_src, *q_data_dst;
+       u32 bitstream_buf, bitstream_size;
+       struct vb2_buffer *buf;
+       int gamma, ret, value;
+       u32 dst_fourcc;
+
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       dst_fourcc = q_data_dst->fourcc;
+
+       /* Allocate per-instance buffers */
+       ret = coda_alloc_context_buffers(ctx, q_data_src);
+       if (ret < 0)
+               return ret;
+
+       buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+       bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
+       bitstream_size = q_data_dst->sizeimage;
+
+       if (!coda_is_initialized(dev)) {
+               v4l2_err(v4l2_dev, "coda is not initialized.\n");
+               return -EFAULT;
+       }
+
+       mutex_lock(&dev->coda_mutex);
+
+       coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
+       coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+       coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
+                       CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+               break;
+       case CODA_960:
+               coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
+               /* fallthrough */
+       case CODA_7541:
+               coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
+                       CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+               break;
+       }
+
+       value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL);
+       value &= ~(1 << 2 | 0x7 << 9);
+       ctx->frame_mem_ctrl = value;
+       coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL);
+
+       if (dev->devtype->product == CODA_DX6) {
+               /* Configure the coda */
+               coda_write(dev, dev->iram.paddr,
+                          CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR);
+       }
+
+       /* Could set rotation here if needed */
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               value = (q_data_src->width & CODADX6_PICWIDTH_MASK)
+                       << CODADX6_PICWIDTH_OFFSET;
+               value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK)
+                        << CODA_PICHEIGHT_OFFSET;
+               break;
+       case CODA_7541:
+               if (dst_fourcc == V4L2_PIX_FMT_H264) {
+                       value = (round_up(q_data_src->width, 16) &
+                                CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
+                       value |= (round_up(q_data_src->height, 16) &
+                                CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
+                       break;
+               }
+               /* fallthrough */
+       case CODA_960:
+               value = (q_data_src->width & CODA7_PICWIDTH_MASK)
+                       << CODA7_PICWIDTH_OFFSET;
+               value |= (q_data_src->height & CODA7_PICHEIGHT_MASK)
+                        << CODA_PICHEIGHT_OFFSET;
+       }
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
+       coda_write(dev, ctx->params.framerate,
+                  CODA_CMD_ENC_SEQ_SRC_F_RATE);
+
+       ctx->params.codec_mode = ctx->codec->mode;
+       switch (dst_fourcc) {
+       case V4L2_PIX_FMT_MPEG4:
+               if (dev->devtype->product == CODA_960)
+                       coda_write(dev, CODA9_STD_MPEG4,
+                                  CODA_CMD_ENC_SEQ_COD_STD);
+               else
+                       coda_write(dev, CODA_STD_MPEG4,
+                                  CODA_CMD_ENC_SEQ_COD_STD);
+               coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
+               break;
+       case V4L2_PIX_FMT_H264:
+               if (dev->devtype->product == CODA_960)
+                       coda_write(dev, CODA9_STD_H264,
+                                  CODA_CMD_ENC_SEQ_COD_STD);
+               else
+                       coda_write(dev, CODA_STD_H264,
+                                  CODA_CMD_ENC_SEQ_COD_STD);
+               if (ctx->params.h264_deblk_enabled) {
+                       value = ((ctx->params.h264_deblk_alpha &
+                                 CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
+                                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
+                               ((ctx->params.h264_deblk_beta &
+                                 CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
+                                CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET);
+               } else {
+                       value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET;
+               }
+               coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
+               break;
+       default:
+               v4l2_err(v4l2_dev,
+                        "dst format (0x%08x) invalid.\n", dst_fourcc);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       switch (ctx->params.slice_mode) {
+       case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+               value = 0;
+               break;
+       case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+               value  = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK)
+                        << CODA_SLICING_SIZE_OFFSET;
+               value |= (1 & CODA_SLICING_UNIT_MASK)
+                        << CODA_SLICING_UNIT_OFFSET;
+               value |=  1 & CODA_SLICING_MODE_MASK;
+               break;
+       case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+               value  = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK)
+                        << CODA_SLICING_SIZE_OFFSET;
+               value |= (0 & CODA_SLICING_UNIT_MASK)
+                        << CODA_SLICING_UNIT_OFFSET;
+               value |=  1 & CODA_SLICING_MODE_MASK;
+               break;
+       }
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
+       value = ctx->params.gop_size & CODA_GOP_SIZE_MASK;
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
+
+       if (ctx->params.bitrate) {
+               /* Rate control enabled */
+               value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK)
+                       << CODA_RATECONTROL_BITRATE_OFFSET;
+               value |=  1 & CODA_RATECONTROL_ENABLE_MASK;
+               if (dev->devtype->product == CODA_960)
+                       value |= BIT(31); /* disable autoskip */
+       } else {
+               value = 0;
+       }
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA);
+
+       coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE);
+       coda_write(dev, ctx->params.intra_refresh,
+                  CODA_CMD_ENC_SEQ_INTRA_REFRESH);
+
+       coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START);
+       coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE);
+
+
+       value = 0;
+       if (dev->devtype->product == CODA_960)
+               gamma = CODA9_DEFAULT_GAMMA;
+       else
+               gamma = CODA_DEFAULT_GAMMA;
+       if (gamma > 0) {
+               coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET,
+                          CODA_CMD_ENC_SEQ_RC_GAMMA);
+       }
+
+       if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) {
+               coda_write(dev,
+                          ctx->params.h264_min_qp << CODA_QPMIN_OFFSET |
+                          ctx->params.h264_max_qp << CODA_QPMAX_OFFSET,
+                          CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX);
+       }
+       if (dev->devtype->product == CODA_960) {
+               if (ctx->params.h264_max_qp)
+                       value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET;
+               if (CODA_DEFAULT_GAMMA > 0)
+                       value |= 1 << CODA9_OPTION_GAMMA_OFFSET;
+       } else {
+               if (CODA_DEFAULT_GAMMA > 0) {
+                       if (dev->devtype->product == CODA_DX6)
+                               value |= 1 << CODADX6_OPTION_GAMMA_OFFSET;
+                       else
+                               value |= 1 << CODA7_OPTION_GAMMA_OFFSET;
+               }
+               if (ctx->params.h264_min_qp)
+                       value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET;
+               if (ctx->params.h264_max_qp)
+                       value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET;
+       }
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
+
+       coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE);
+
+       coda_setup_iram(ctx);
+
+       if (dst_fourcc == V4L2_PIX_FMT_H264) {
+               switch (dev->devtype->product) {
+               case CODA_DX6:
+                       value = FMO_SLICE_SAVE_BUF_SIZE << 7;
+                       coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO);
+                       break;
+               case CODA_7541:
+                       coda_write(dev, ctx->iram_info.search_ram_paddr,
+                                       CODA7_CMD_ENC_SEQ_SEARCH_BASE);
+                       coda_write(dev, ctx->iram_info.search_ram_size,
+                                       CODA7_CMD_ENC_SEQ_SEARCH_SIZE);
+                       break;
+               case CODA_960:
+                       coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION);
+                       coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT);
+               }
+       }
+
+       ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT);
+       if (ret < 0) {
+               v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
+               goto out;
+       }
+
+       if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) {
+               v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n");
+               ret = -EFAULT;
+               goto out;
+       }
+
+       if (dev->devtype->product == CODA_960)
+               ctx->num_internal_frames = 4;
+       else
+               ctx->num_internal_frames = 2;
+       ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
+       if (ret < 0) {
+               v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
+               goto out;
+       }
+
+       coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
+       coda_write(dev, q_data_src->bytesperline,
+                       CODA_CMD_SET_FRAME_BUF_STRIDE);
+       if (dev->devtype->product == CODA_7541) {
+               coda_write(dev, q_data_src->bytesperline,
+                               CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
+       }
+       if (dev->devtype->product != CODA_DX6) {
+               coda_write(dev, ctx->iram_info.buf_bit_use,
+                               CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
+               coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
+                               CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
+               coda_write(dev, ctx->iram_info.buf_dbk_y_use,
+                               CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
+               coda_write(dev, ctx->iram_info.buf_dbk_c_use,
+                               CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
+               coda_write(dev, ctx->iram_info.buf_ovl_use,
+                               CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
+               if (dev->devtype->product == CODA_960) {
+                       coda_write(dev, ctx->iram_info.buf_btp_use,
+                                       CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
+
+                       /* FIXME */
+                       coda_write(dev, ctx->internal_frames[2].paddr,
+                                  CODA9_CMD_SET_FRAME_SUBSAMP_A);
+                       coda_write(dev, ctx->internal_frames[3].paddr,
+                                  CODA9_CMD_SET_FRAME_SUBSAMP_B);
+               }
+       }
+
+       ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF);
+       if (ret < 0) {
+               v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
+               goto out;
+       }
+
+       /* Save stream headers */
+       buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+       switch (dst_fourcc) {
+       case V4L2_PIX_FMT_H264:
+               /*
+                * Get SPS in the first frame and copy it to an
+                * intermediate buffer.
+                */
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS,
+                                        &ctx->vpu_header[0][0],
+                                        &ctx->vpu_header_size[0]);
+               if (ret < 0)
+                       goto out;
+
+               /*
+                * Get PPS in the first frame and copy it to an
+                * intermediate buffer.
+                */
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS,
+                                        &ctx->vpu_header[1][0],
+                                        &ctx->vpu_header_size[1]);
+               if (ret < 0)
+                       goto out;
+
+               /*
+                * Length of H.264 headers is variable and thus it might not be
+                * aligned for the coda to append the encoded frame. In that is
+                * the case a filler NAL must be added to header 2.
+                */
+               ctx->vpu_header_size[2] = coda_h264_padding(
+                                       (ctx->vpu_header_size[0] +
+                                        ctx->vpu_header_size[1]),
+                                        ctx->vpu_header[2]);
+               break;
+       case V4L2_PIX_FMT_MPEG4:
+               /*
+                * Get VOS in the first frame and copy it to an
+                * intermediate buffer
+                */
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS,
+                                        &ctx->vpu_header[0][0],
+                                        &ctx->vpu_header_size[0]);
+               if (ret < 0)
+                       goto out;
+
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS,
+                                        &ctx->vpu_header[1][0],
+                                        &ctx->vpu_header_size[1]);
+               if (ret < 0)
+                       goto out;
+
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL,
+                                        &ctx->vpu_header[2][0],
+                                        &ctx->vpu_header_size[2]);
+               if (ret < 0)
+                       goto out;
+               break;
+       default:
+               /* No more formats need to save headers at the moment */
+               break;
+       }
+
+out:
+       mutex_unlock(&dev->coda_mutex);
+       return ret;
+}
+
+static int coda_prepare_encode(struct coda_ctx *ctx)
+{
+       struct coda_q_data *q_data_src, *q_data_dst;
+       struct vb2_buffer *src_buf, *dst_buf;
+       struct coda_dev *dev = ctx->dev;
+       int force_ipicture;
+       int quant_param = 0;
+       u32 picture_y, picture_cb, picture_cr;
+       u32 pic_stream_buffer_addr, pic_stream_buffer_size;
+       u32 dst_fourcc;
+
+       src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       dst_fourcc = q_data_dst->fourcc;
+
+       src_buf->v4l2_buf.sequence = ctx->osequence;
+       dst_buf->v4l2_buf.sequence = ctx->osequence;
+       ctx->osequence++;
+
+       /*
+        * Workaround coda firmware BUG that only marks the first
+        * frame as IDR. This is a problem for some decoders that can't
+        * recover when a frame is lost.
+        */
+       if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) {
+               src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+               src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+       } else {
+               src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+               src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+       }
+
+       if (dev->devtype->product == CODA_960)
+               coda_set_gdi_regs(ctx);
+
+       /*
+        * Copy headers at the beginning of the first frame for H.264 only.
+        * In MPEG4 they are already copied by the coda.
+        */
+       if (src_buf->v4l2_buf.sequence == 0) {
+               pic_stream_buffer_addr =
+                       vb2_dma_contig_plane_dma_addr(dst_buf, 0) +
+                       ctx->vpu_header_size[0] +
+                       ctx->vpu_header_size[1] +
+                       ctx->vpu_header_size[2];
+               pic_stream_buffer_size = CODA_MAX_FRAME_SIZE -
+                       ctx->vpu_header_size[0] -
+                       ctx->vpu_header_size[1] -
+                       ctx->vpu_header_size[2];
+               memcpy(vb2_plane_vaddr(dst_buf, 0),
+                      &ctx->vpu_header[0][0], ctx->vpu_header_size[0]);
+               memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0],
+                      &ctx->vpu_header[1][0], ctx->vpu_header_size[1]);
+               memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] +
+                       ctx->vpu_header_size[1], &ctx->vpu_header[2][0],
+                       ctx->vpu_header_size[2]);
+       } else {
+               pic_stream_buffer_addr =
+                       vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+               pic_stream_buffer_size = CODA_MAX_FRAME_SIZE;
+       }
+
+       if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
+               force_ipicture = 1;
+               switch (dst_fourcc) {
+               case V4L2_PIX_FMT_H264:
+                       quant_param = ctx->params.h264_intra_qp;
+                       break;
+               case V4L2_PIX_FMT_MPEG4:
+                       quant_param = ctx->params.mpeg4_intra_qp;
+                       break;
+               default:
+                       v4l2_warn(&ctx->dev->v4l2_dev,
+                               "cannot set intra qp, fmt not supported\n");
+                       break;
+               }
+       } else {
+               force_ipicture = 0;
+               switch (dst_fourcc) {
+               case V4L2_PIX_FMT_H264:
+                       quant_param = ctx->params.h264_inter_qp;
+                       break;
+               case V4L2_PIX_FMT_MPEG4:
+                       quant_param = ctx->params.mpeg4_inter_qp;
+                       break;
+               default:
+                       v4l2_warn(&ctx->dev->v4l2_dev,
+                               "cannot set inter qp, fmt not supported\n");
+                       break;
+               }
+       }
+
+       /* submit */
+       coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
+                  CODA_CMD_ENC_PIC_ROT_MODE);
+       coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
+
+
+       picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+       switch (q_data_src->fourcc) {
+       case V4L2_PIX_FMT_YVU420:
+               /* Switch Cb and Cr for YVU420 format */
+               picture_cr = picture_y + q_data_src->bytesperline *
+                               q_data_src->height;
+               picture_cb = picture_cr + q_data_src->bytesperline / 2 *
+                               q_data_src->height / 2;
+               break;
+       case V4L2_PIX_FMT_YUV420:
+       default:
+               picture_cb = picture_y + q_data_src->bytesperline *
+                               q_data_src->height;
+               picture_cr = picture_cb + q_data_src->bytesperline / 2 *
+                               q_data_src->height / 2;
+               break;
+       }
+
+       if (dev->devtype->product == CODA_960) {
+               coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX);
+               coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE);
+               coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC);
+
+               coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y);
+               coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB);
+               coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR);
+       } else {
+               coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
+               coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
+               coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR);
+       }
+       coda_write(dev, force_ipicture << 1 & 0x2,
+                  CODA_CMD_ENC_PIC_OPTION);
+
+       coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
+       coda_write(dev, pic_stream_buffer_size / 1024,
+                  CODA_CMD_ENC_PIC_BB_SIZE);
+
+       if (!ctx->streamon_out) {
+               /* After streamoff on the output side, set stream end flag */
+               ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+               coda_write(dev, ctx->bit_stream_param,
+                          CODA_REG_BIT_BIT_STREAM_PARAM);
+       }
+
+       if (dev->devtype->product != CODA_DX6)
+               coda_write(dev, ctx->iram_info.axi_sram_use,
+                               CODA7_REG_BIT_AXI_SRAM_USE);
+
+       coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
+
+       return 0;
+}
+
+static void coda_finish_encode(struct coda_ctx *ctx)
+{
+       struct vb2_buffer *src_buf, *dst_buf;
+       struct coda_dev *dev = ctx->dev;
+       u32 wr_ptr, start_ptr;
+
+       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+       /* Get results from the coda */
+       start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
+       wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+
+       /* Calculate bytesused field */
+       if (dst_buf->v4l2_buf.sequence == 0) {
+               vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr +
+                                       ctx->vpu_header_size[0] +
+                                       ctx->vpu_header_size[1] +
+                                       ctx->vpu_header_size[2]);
+       } else {
+               vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr);
+       }
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n",
+                wr_ptr - start_ptr);
+
+       coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
+       coda_read(dev, CODA_RET_ENC_PIC_FLAG);
+
+       if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) {
+               dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+               dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+       } else {
+               dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+               dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+       }
+
+       dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
+       dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+       dst_buf->v4l2_buf.flags |=
+               src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+       dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
+
+       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+
+       dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+       v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+
+       ctx->gopcounter--;
+       if (ctx->gopcounter < 0)
+               ctx->gopcounter = ctx->params.gop_size - 1;
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+               "job finished: encoding frame (%d) (%s)\n",
+               dst_buf->v4l2_buf.sequence,
+               (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
+               "KEYFRAME" : "PFRAME");
+}
+
+static void coda_seq_end_work(struct work_struct *work)
+{
+       struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work);
+       struct coda_dev *dev = ctx->dev;
+
+       mutex_lock(&ctx->buffer_mutex);
+       mutex_lock(&dev->coda_mutex);
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx,
+                __func__);
+       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
+               v4l2_err(&dev->v4l2_dev,
+                        "CODA_COMMAND_SEQ_END failed\n");
+       }
+
+       kfifo_init(&ctx->bitstream_fifo,
+               ctx->bitstream.vaddr, ctx->bitstream.size);
+
+       coda_free_framebuffers(ctx);
+       coda_free_context_buffers(ctx);
+
+       mutex_unlock(&dev->coda_mutex);
+       mutex_unlock(&ctx->buffer_mutex);
+}
+
+static void coda_bit_release(struct coda_ctx *ctx)
+{
+       coda_free_framebuffers(ctx);
+       coda_free_context_buffers(ctx);
+}
+
+const struct coda_context_ops coda_bit_encode_ops = {
+       .queue_init = coda_encoder_queue_init,
+       .start_streaming = coda_start_encoding,
+       .prepare_run = coda_prepare_encode,
+       .finish_run = coda_finish_encode,
+       .seq_end_work = coda_seq_end_work,
+       .release = coda_bit_release,
+};
+
+/*
+ * Decoder context operations
+ */
+
+static int __coda_start_decoding(struct coda_ctx *ctx)
+{
+       struct coda_q_data *q_data_src, *q_data_dst;
+       u32 bitstream_buf, bitstream_size;
+       struct coda_dev *dev = ctx->dev;
+       int width, height;
+       u32 src_fourcc;
+       u32 val;
+       int ret;
+
+       /* Start decoding */
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       bitstream_buf = ctx->bitstream.paddr;
+       bitstream_size = ctx->bitstream.size;
+       src_fourcc = q_data_src->fourcc;
+
+       /* Allocate per-instance buffers */
+       ret = coda_alloc_context_buffers(ctx, q_data_src);
+       if (ret < 0)
+               return ret;
+
+       coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
+
+       /* Update coda bitstream read and write pointers from kfifo */
+       coda_kfifo_sync_to_device_full(ctx);
+
+       ctx->display_idx = -1;
+       ctx->frm_dis_flg = 0;
+       coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+
+       coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE,
+                       CODA_REG_BIT_BIT_STREAM_PARAM);
+
+       coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START);
+       coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE);
+       val = 0;
+       if ((dev->devtype->product == CODA_7541) ||
+           (dev->devtype->product == CODA_960))
+               val |= CODA_REORDER_ENABLE;
+       coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
+
+       ctx->params.codec_mode = ctx->codec->mode;
+       if (dev->devtype->product == CODA_960 &&
+           src_fourcc == V4L2_PIX_FMT_MPEG4)
+               ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4;
+       else
+               ctx->params.codec_mode_aux = 0;
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               if (dev->devtype->product == CODA_7541) {
+                       coda_write(dev, ctx->psbuf.paddr,
+                                       CODA_CMD_DEC_SEQ_PS_BB_START);
+                       coda_write(dev, (CODA7_PS_BUF_SIZE / 1024),
+                                       CODA_CMD_DEC_SEQ_PS_BB_SIZE);
+               }
+               if (dev->devtype->product == CODA_960) {
+                       coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN);
+                       coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE);
+               }
+       }
+       if (dev->devtype->product != CODA_960)
+               coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE);
+
+       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
+               v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
+               coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
+               return -ETIMEDOUT;
+       }
+
+       /* Update kfifo out pointer from coda bitstream read pointer */
+       coda_kfifo_sync_from_device(ctx);
+
+       coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
+
+       if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) {
+               v4l2_err(&dev->v4l2_dev,
+                       "CODA_COMMAND_SEQ_INIT failed, error code = %d\n",
+                       coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON));
+               return -EAGAIN;
+       }
+
+       val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE);
+       if (dev->devtype->product == CODA_DX6) {
+               width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK;
+               height = val & CODADX6_PICHEIGHT_MASK;
+       } else {
+               width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK;
+               height = val & CODA7_PICHEIGHT_MASK;
+       }
+
+       if (width > q_data_dst->width || height > q_data_dst->height) {
+               v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n",
+                        width, height, q_data_dst->width, q_data_dst->height);
+               return -EINVAL;
+       }
+
+       width = round_up(width, 16);
+       height = round_up(height, 16);
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n",
+                __func__, ctx->idx, width, height);
+
+       ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED);
+       if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) {
+               v4l2_err(&dev->v4l2_dev,
+                        "not enough framebuffers to decode (%d < %d)\n",
+                        CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames);
+               return -EINVAL;
+       }
+
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               u32 left_right;
+               u32 top_bottom;
+
+               left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT);
+               top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM);
+
+               q_data_dst->rect.left = (left_right >> 10) & 0x3ff;
+               q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff;
+               q_data_dst->rect.width = width - q_data_dst->rect.left -
+                                        (left_right & 0x3ff);
+               q_data_dst->rect.height = height - q_data_dst->rect.top -
+                                         (top_bottom & 0x3ff);
+       }
+
+       ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n");
+               return ret;
+       }
+
+       /* Tell the decoder how many frame buffers we allocated. */
+       coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
+       coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE);
+
+       if (dev->devtype->product != CODA_DX6) {
+               /* Set secondary AXI IRAM */
+               coda_setup_iram(ctx);
+
+               coda_write(dev, ctx->iram_info.buf_bit_use,
+                               CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
+               coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
+                               CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
+               coda_write(dev, ctx->iram_info.buf_dbk_y_use,
+                               CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
+               coda_write(dev, ctx->iram_info.buf_dbk_c_use,
+                               CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
+               coda_write(dev, ctx->iram_info.buf_ovl_use,
+                               CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
+               if (dev->devtype->product == CODA_960)
+                       coda_write(dev, ctx->iram_info.buf_btp_use,
+                                       CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
+       }
+
+       if (dev->devtype->product == CODA_960) {
+               coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY);
+
+               coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE);
+               coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET |
+                               32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
+                               8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET |
+                               8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET,
+                               CODA9_CMD_SET_FRAME_CACHE_CONFIG);
+       }
+
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               coda_write(dev, ctx->slicebuf.paddr,
+                               CODA_CMD_SET_FRAME_SLICE_BB_START);
+               coda_write(dev, ctx->slicebuf.size / 1024,
+                               CODA_CMD_SET_FRAME_SLICE_BB_SIZE);
+       }
+
+       if (dev->devtype->product == CODA_7541) {
+               int max_mb_x = 1920 / 16;
+               int max_mb_y = 1088 / 16;
+               int max_mb_num = max_mb_x * max_mb_y;
+
+               coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
+                               CODA7_CMD_SET_FRAME_MAX_DEC_SIZE);
+       } else if (dev->devtype->product == CODA_960) {
+               int max_mb_x = 1920 / 16;
+               int max_mb_y = 1088 / 16;
+               int max_mb_num = max_mb_x * max_mb_y;
+
+               coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
+                               CODA9_CMD_SET_FRAME_MAX_DEC_SIZE);
+       }
+
+       if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                        "CODA_COMMAND_SET_FRAME_BUF timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int coda_start_decoding(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+       int ret;
+
+       mutex_lock(&dev->coda_mutex);
+       ret = __coda_start_decoding(ctx);
+       mutex_unlock(&dev->coda_mutex);
+
+       return ret;
+}
+
+static int coda_prepare_decode(struct coda_ctx *ctx)
+{
+       struct vb2_buffer *dst_buf;
+       struct coda_dev *dev = ctx->dev;
+       struct coda_q_data *q_data_dst;
+       u32 stridey, height;
+       u32 picture_y, picture_cb, picture_cr;
+
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+       if (ctx->params.rot_mode & CODA_ROT_90) {
+               stridey = q_data_dst->height;
+               height = q_data_dst->width;
+       } else {
+               stridey = q_data_dst->width;
+               height = q_data_dst->height;
+       }
+
+       /* Try to copy source buffer contents into the bitstream ringbuffer */
+       mutex_lock(&ctx->bitstream_mutex);
+       coda_fill_bitstream(ctx);
+       mutex_unlock(&ctx->bitstream_mutex);
+
+       if (coda_get_bitstream_payload(ctx) < 512 &&
+           (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                        "bitstream payload: %d, skipping\n",
+                        coda_get_bitstream_payload(ctx));
+               v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+               return -EAGAIN;
+       }
+
+       /* Run coda_start_decoding (again) if not yet initialized */
+       if (!ctx->initialized) {
+               int ret = __coda_start_decoding(ctx);
+
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
+                       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+                       return -EAGAIN;
+               } else {
+                       ctx->initialized = 1;
+               }
+       }
+
+       if (dev->devtype->product == CODA_960)
+               coda_set_gdi_regs(ctx);
+
+       /* Set rotator output */
+       picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+       if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) {
+               /* Switch Cr and Cb for YVU420 format */
+               picture_cr = picture_y + stridey * height;
+               picture_cb = picture_cr + stridey / 2 * height / 2;
+       } else {
+               picture_cb = picture_y + stridey * height;
+               picture_cr = picture_cb + stridey / 2 * height / 2;
+       }
+
+       if (dev->devtype->product == CODA_960) {
+               /*
+                * The CODA960 seems to have an internal list of buffers with
+                * 64 entries that includes the registered frame buffers as
+                * well as the rotator buffer output.
+                * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames.
+                */
+               coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index,
+                               CODA9_CMD_DEC_PIC_ROT_INDEX);
+               coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y);
+               coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB);
+               coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR);
+               coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE);
+       } else {
+               coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y);
+               coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB);
+               coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR);
+               coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE);
+       }
+       coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
+                       CODA_CMD_DEC_PIC_ROT_MODE);
+
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               /* TBD */
+       case CODA_7541:
+               coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION);
+               break;
+       case CODA_960:
+               /* 'hardcode to use interrupt disable mode'? */
+               coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION);
+               break;
+       }
+
+       coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM);
+
+       coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START);
+       coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE);
+
+       if (dev->devtype->product != CODA_DX6)
+               coda_write(dev, ctx->iram_info.axi_sram_use,
+                               CODA7_REG_BIT_AXI_SRAM_USE);
+
+       coda_kfifo_sync_to_device_full(ctx);
+
+       coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
+
+       return 0;
+}
+
+static void coda_finish_decode(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+       struct coda_q_data *q_data_src;
+       struct coda_q_data *q_data_dst;
+       struct vb2_buffer *dst_buf;
+       struct coda_timestamp *ts;
+       int width, height;
+       int decoded_idx;
+       int display_idx;
+       u32 src_fourcc;
+       int success;
+       u32 err_mb;
+       u32 val;
+
+       /* Update kfifo out pointer from coda bitstream read pointer */
+       coda_kfifo_sync_from_device(ctx);
+
+       /*
+        * in stream-end mode, the read pointer can overshoot the write pointer
+        * by up to 512 bytes
+        */
+       if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
+               if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512)
+                       kfifo_init(&ctx->bitstream_fifo,
+                               ctx->bitstream.vaddr, ctx->bitstream.size);
+       }
+
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       src_fourcc = q_data_src->fourcc;
+
+       val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS);
+       if (val != 1)
+               pr_err("DEC_PIC_SUCCESS = %d\n", val);
+
+       success = val & 0x1;
+       if (!success)
+               v4l2_err(&dev->v4l2_dev, "decode failed\n");
+
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               if (val & (1 << 3))
+                       v4l2_err(&dev->v4l2_dev,
+                                "insufficient PS buffer space (%d bytes)\n",
+                                ctx->psbuf.size);
+               if (val & (1 << 2))
+                       v4l2_err(&dev->v4l2_dev,
+                                "insufficient slice buffer space (%d bytes)\n",
+                                ctx->slicebuf.size);
+       }
+
+       val = coda_read(dev, CODA_RET_DEC_PIC_SIZE);
+       width = (val >> 16) & 0xffff;
+       height = val & 0xffff;
+
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+       /* frame crop information */
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               u32 left_right;
+               u32 top_bottom;
+
+               left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT);
+               top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM);
+
+               if (left_right == 0xffffffff && top_bottom == 0xffffffff) {
+                       /* Keep current crop information */
+               } else {
+                       struct v4l2_rect *rect = &q_data_dst->rect;
+
+                       rect->left = left_right >> 16 & 0xffff;
+                       rect->top = top_bottom >> 16 & 0xffff;
+                       rect->width = width - rect->left -
+                                     (left_right & 0xffff);
+                       rect->height = height - rect->top -
+                                      (top_bottom & 0xffff);
+               }
+       } else {
+               /* no cropping */
+       }
+
+       err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB);
+       if (err_mb > 0)
+               v4l2_err(&dev->v4l2_dev,
+                        "errors in %d macroblocks\n", err_mb);
+
+       if (dev->devtype->product == CODA_7541) {
+               val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
+               if (val == 0) {
+                       /* not enough bitstream data */
+                       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                                "prescan failed: %d\n", val);
+                       ctx->hold = true;
+                       return;
+               }
+       }
+
+       ctx->frm_dis_flg = coda_read(dev,
+                                    CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+
+       /*
+        * The previous display frame was copied out by the rotator,
+        * now it can be overwritten again
+        */
+       if (ctx->display_idx >= 0 &&
+           ctx->display_idx < ctx->num_internal_frames) {
+               ctx->frm_dis_flg &= ~(1 << ctx->display_idx);
+               coda_write(dev, ctx->frm_dis_flg,
+                               CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+       }
+
+       /*
+        * The index of the last decoded frame, not necessarily in
+        * display order, and the index of the next display frame.
+        * The latter could have been decoded in a previous run.
+        */
+       decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX);
+       display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX);
+
+       if (decoded_idx == -1) {
+               /* no frame was decoded, but we might have a display frame */
+               if (display_idx >= 0 && display_idx < ctx->num_internal_frames)
+                       ctx->sequence_offset++;
+               else if (ctx->display_idx < 0)
+                       ctx->hold = true;
+       } else if (decoded_idx == -2) {
+               /* no frame was decoded, we still return remaining buffers */
+       } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
+               v4l2_err(&dev->v4l2_dev,
+                        "decoded frame index out of range: %d\n", decoded_idx);
+       } else {
+               val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
+               val -= ctx->sequence_offset;
+               mutex_lock(&ctx->bitstream_mutex);
+               if (!list_empty(&ctx->timestamp_list)) {
+                       ts = list_first_entry(&ctx->timestamp_list,
+                                             struct coda_timestamp, list);
+                       list_del(&ts->list);
+                       if (val != (ts->sequence & 0xffff)) {
+                               v4l2_err(&dev->v4l2_dev,
+                                        "sequence number mismatch (%d(%d) != %d)\n",
+                                        val, ctx->sequence_offset,
+                                        ts->sequence);
+                       }
+                       ctx->frame_timestamps[decoded_idx] = *ts;
+                       kfree(ts);
+               } else {
+                       v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n");
+                       memset(&ctx->frame_timestamps[decoded_idx], 0,
+                              sizeof(struct coda_timestamp));
+                       ctx->frame_timestamps[decoded_idx].sequence = val;
+               }
+               mutex_unlock(&ctx->bitstream_mutex);
+
+               val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7;
+               if (val == 0)
+                       ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME;
+               else if (val == 1)
+                       ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME;
+               else
+                       ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME;
+
+               ctx->frame_errors[decoded_idx] = err_mb;
+       }
+
+       if (display_idx == -1) {
+               /*
+                * no more frames to be decoded, but there could still
+                * be rotator output to dequeue
+                */
+               ctx->hold = true;
+       } else if (display_idx == -3) {
+               /* possibly prescan failure */
+       } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) {
+               v4l2_err(&dev->v4l2_dev,
+                        "presentation frame index out of range: %d\n",
+                        display_idx);
+       }
+
+       /* If a frame was copied out, return it */
+       if (ctx->display_idx >= 0 &&
+           ctx->display_idx < ctx->num_internal_frames) {
+               dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+               dst_buf->v4l2_buf.sequence = ctx->osequence++;
+
+               dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
+                                            V4L2_BUF_FLAG_PFRAME |
+                                            V4L2_BUF_FLAG_BFRAME);
+               dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx];
+               ts = &ctx->frame_timestamps[ctx->display_idx];
+               dst_buf->v4l2_buf.timecode = ts->timecode;
+               dst_buf->v4l2_buf.timestamp = ts->timestamp;
+
+               vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2);
+
+               v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ?
+                                 VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                       "job finished: decoding frame (%d) (%s)\n",
+                       dst_buf->v4l2_buf.sequence,
+                       (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
+                       "KEYFRAME" : "PFRAME");
+       } else {
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                       "job finished: no frame decoded\n");
+       }
+
+       /* The rotator will copy the current display frame next time */
+       ctx->display_idx = display_idx;
+}
+
+const struct coda_context_ops coda_bit_decode_ops = {
+       .queue_init = coda_decoder_queue_init,
+       .start_streaming = coda_start_decoding,
+       .prepare_run = coda_prepare_decode,
+       .finish_run = coda_finish_decode,
+       .seq_end_work = coda_seq_end_work,
+       .release = coda_bit_release,
+};
+
+irqreturn_t coda_irq_handler(int irq, void *data)
+{
+       struct coda_dev *dev = data;
+       struct coda_ctx *ctx;
+
+       /* read status register to attend the IRQ */
+       coda_read(dev, CODA_REG_BIT_INT_STATUS);
+       coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
+                     CODA_REG_BIT_INT_CLEAR);
+
+       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+       if (ctx == NULL) {
+               v4l2_err(&dev->v4l2_dev,
+                        "Instance released before the end of transaction\n");
+               mutex_unlock(&dev->coda_mutex);
+               return IRQ_HANDLED;
+       }
+
+       if (ctx->aborting) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "task has been aborted\n");
+       }
+
+       if (coda_isbusy(ctx->dev)) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "coda is still busy!!!!\n");
+               return IRQ_NONE;
+       }
+
+       complete(&ctx->completion);
+
+       return IRQ_HANDLED;
+}
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
new file mode 100644 (file)
index 0000000..ced4760
--- /dev/null
@@ -0,0 +1,2052 @@
+/*
+ * Coda multi-standard codec IP
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ *
+ * 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/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/genalloc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kfifo.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/of.h>
+#include <linux/platform_data/coda.h>
+#include <linux/reset.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "coda.h"
+
+#define CODA_NAME              "coda"
+
+#define CODADX6_MAX_INSTANCES  4
+
+#define CODA_PARA_BUF_SIZE     (10 * 1024)
+#define CODA_ISRAM_SIZE        (2048 * 2)
+
+#define MIN_W 176
+#define MIN_H 144
+
+#define S_ALIGN                1 /* multiple of 2 */
+#define W_ALIGN                1 /* multiple of 2 */
+#define H_ALIGN                1 /* multiple of 2 */
+
+#define fh_to_ctx(__fh)        container_of(__fh, struct coda_ctx, fh)
+
+int coda_debug;
+module_param(coda_debug, int, 0644);
+MODULE_PARM_DESC(coda_debug, "Debug level (0-2)");
+
+struct coda_fmt {
+       char *name;
+       u32 fourcc;
+};
+
+void coda_write(struct coda_dev *dev, u32 data, u32 reg)
+{
+       v4l2_dbg(2, coda_debug, &dev->v4l2_dev,
+                "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
+       writel(data, dev->regs_base + reg);
+}
+
+unsigned int coda_read(struct coda_dev *dev, u32 reg)
+{
+       u32 data;
+
+       data = readl(dev->regs_base + reg);
+       v4l2_dbg(2, coda_debug, &dev->v4l2_dev,
+                "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
+       return data;
+}
+
+/*
+ * Array of all formats supported by any version of Coda:
+ */
+static const struct coda_fmt coda_formats[] = {
+       {
+               .name = "YUV 4:2:0 Planar, YCbCr",
+               .fourcc = V4L2_PIX_FMT_YUV420,
+       },
+       {
+               .name = "YUV 4:2:0 Planar, YCrCb",
+               .fourcc = V4L2_PIX_FMT_YVU420,
+       },
+       {
+               .name = "H264 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_H264,
+       },
+       {
+               .name = "MPEG4 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_MPEG4,
+       },
+};
+
+#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \
+       { mode, src_fourcc, dst_fourcc, max_w, max_h }
+
+/*
+ * Arrays of codecs supported by each given version of Coda:
+ *  i.MX27 -> codadx6
+ *  i.MX5x -> coda7
+ *  i.MX6  -> coda960
+ * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants
+ */
+static const struct coda_codec codadx6_codecs[] = {
+       CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,  720, 576),
+       CODA_CODEC(CODADX6_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576),
+};
+
+static const struct coda_codec coda7_codecs[] = {
+       CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1280, 720),
+       CODA_CODEC(CODA7_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1280, 720),
+       CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1088),
+       CODA_CODEC(CODA7_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1088),
+};
+
+static const struct coda_codec coda9_codecs[] = {
+       CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1920, 1088),
+       CODA_CODEC(CODA9_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1920, 1088),
+       CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1088),
+       CODA_CODEC(CODA9_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1088),
+};
+
+static bool coda_format_is_yuv(u32 fourcc)
+{
+       switch (fourcc) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               return true;
+       default:
+               return false;
+       }
+}
+
+/*
+ * Normalize all supported YUV 4:2:0 formats to the value used in the codec
+ * tables.
+ */
+static u32 coda_format_normalize_yuv(u32 fourcc)
+{
+       return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc;
+}
+
+static const struct coda_codec *coda_find_codec(struct coda_dev *dev,
+                                               int src_fourcc, int dst_fourcc)
+{
+       const struct coda_codec *codecs = dev->devtype->codecs;
+       int num_codecs = dev->devtype->num_codecs;
+       int k;
+
+       src_fourcc = coda_format_normalize_yuv(src_fourcc);
+       dst_fourcc = coda_format_normalize_yuv(dst_fourcc);
+       if (src_fourcc == dst_fourcc)
+               return NULL;
+
+       for (k = 0; k < num_codecs; k++) {
+               if (codecs[k].src_fourcc == src_fourcc &&
+                   codecs[k].dst_fourcc == dst_fourcc)
+                       break;
+       }
+
+       if (k == num_codecs)
+               return NULL;
+
+       return &codecs[k];
+}
+
+static void coda_get_max_dimensions(struct coda_dev *dev,
+                                   const struct coda_codec *codec,
+                                   int *max_w, int *max_h)
+{
+       const struct coda_codec *codecs = dev->devtype->codecs;
+       int num_codecs = dev->devtype->num_codecs;
+       unsigned int w, h;
+       int k;
+
+       if (codec) {
+               w = codec->max_w;
+               h = codec->max_h;
+       } else {
+               for (k = 0, w = 0, h = 0; k < num_codecs; k++) {
+                       w = max(w, codecs[k].max_w);
+                       h = max(h, codecs[k].max_h);
+               }
+       }
+
+       if (max_w)
+               *max_w = w;
+       if (max_h)
+               *max_h = h;
+}
+
+const char *coda_product_name(int product)
+{
+       static char buf[9];
+
+       switch (product) {
+       case CODA_DX6:
+               return "CodaDx6";
+       case CODA_7541:
+               return "CODA7541";
+       case CODA_960:
+               return "CODA960";
+       default:
+               snprintf(buf, sizeof(buf), "(0x%04x)", product);
+               return buf;
+       }
+}
+
+/*
+ * V4L2 ioctl() operations.
+ */
+static int coda_querycap(struct file *file, void *priv,
+                        struct v4l2_capability *cap)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, coda_product_name(ctx->dev->devtype->product),
+               sizeof(cap->card));
+       strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info));
+       cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+       return 0;
+}
+
+static int coda_enum_fmt(struct file *file, void *priv,
+                        struct v4l2_fmtdesc *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       const struct coda_codec *codecs = ctx->dev->devtype->codecs;
+       const struct coda_fmt *formats = coda_formats;
+       const struct coda_fmt *fmt;
+       int num_codecs = ctx->dev->devtype->num_codecs;
+       int num_formats = ARRAY_SIZE(coda_formats);
+       int i, k, num = 0;
+       bool yuv;
+
+       if (ctx->inst_type == CODA_INST_ENCODER)
+               yuv = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       else
+               yuv = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+       for (i = 0; i < num_formats; i++) {
+               /* Skip either raw or compressed formats */
+               if (yuv != coda_format_is_yuv(formats[i].fourcc))
+                       continue;
+               /* All uncompressed formats are always supported */
+               if (yuv) {
+                       if (num == f->index)
+                               break;
+                       ++num;
+                       continue;
+               }
+               /* Compressed formats may be supported, check the codec list */
+               for (k = 0; k < num_codecs; k++) {
+                       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+                           formats[i].fourcc == codecs[k].dst_fourcc)
+                               break;
+                       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+                           formats[i].fourcc == codecs[k].src_fourcc)
+                               break;
+               }
+               if (k < num_codecs) {
+                       if (num == f->index)
+                               break;
+                       ++num;
+               }
+       }
+
+       if (i < num_formats) {
+               fmt = &formats[i];
+               strlcpy(f->description, fmt->name, sizeof(f->description));
+               f->pixelformat = fmt->fourcc;
+               if (!yuv)
+                       f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+               return 0;
+       }
+
+       /* Format not found */
+       return -EINVAL;
+}
+
+static int coda_g_fmt(struct file *file, void *priv,
+                     struct v4l2_format *f)
+{
+       struct coda_q_data *q_data;
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       q_data = get_q_data(ctx, f->type);
+       if (!q_data)
+               return -EINVAL;
+
+       f->fmt.pix.field        = V4L2_FIELD_NONE;
+       f->fmt.pix.pixelformat  = q_data->fourcc;
+       f->fmt.pix.width        = q_data->width;
+       f->fmt.pix.height       = q_data->height;
+       f->fmt.pix.bytesperline = q_data->bytesperline;
+
+       f->fmt.pix.sizeimage    = q_data->sizeimage;
+       f->fmt.pix.colorspace   = ctx->colorspace;
+
+       return 0;
+}
+
+static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
+                       struct v4l2_format *f)
+{
+       struct coda_dev *dev = ctx->dev;
+       struct coda_q_data *q_data;
+       unsigned int max_w, max_h;
+       enum v4l2_field field;
+
+       field = f->fmt.pix.field;
+       if (field == V4L2_FIELD_ANY)
+               field = V4L2_FIELD_NONE;
+       else if (V4L2_FIELD_NONE != field)
+               return -EINVAL;
+
+       /* V4L2 specification suggests the driver corrects the format struct
+        * if any of the dimensions is unsupported */
+       f->fmt.pix.field = field;
+
+       coda_get_max_dimensions(dev, codec, &max_w, &max_h);
+       v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w, W_ALIGN,
+                             &f->fmt.pix.height, MIN_H, max_h, H_ALIGN,
+                             S_ALIGN);
+
+       switch (f->fmt.pix.pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_H264:
+       case V4L2_PIX_FMT_MPEG4:
+       case V4L2_PIX_FMT_JPEG:
+               break;
+       default:
+               q_data = get_q_data(ctx, f->type);
+               if (!q_data)
+                       return -EINVAL;
+               f->fmt.pix.pixelformat = q_data->fourcc;
+       }
+
+       switch (f->fmt.pix.pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               /* Frame stride must be multiple of 8, but 16 for h.264 */
+               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
+               f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+                                       f->fmt.pix.height * 3 / 2;
+               break;
+       case V4L2_PIX_FMT_H264:
+       case V4L2_PIX_FMT_MPEG4:
+       case V4L2_PIX_FMT_JPEG:
+               f->fmt.pix.bytesperline = 0;
+               f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
+               break;
+       default:
+               BUG();
+       }
+
+       return 0;
+}
+
+static int coda_try_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       const struct coda_codec *codec = NULL;
+       struct vb2_queue *src_vq;
+       int ret;
+
+       /*
+        * If the source format is already fixed, try to find a codec that
+        * converts to the given destination format
+        */
+       src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       if (vb2_is_streaming(src_vq)) {
+               struct coda_q_data *q_data_src;
+
+               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+               codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
+                                       f->fmt.pix.pixelformat);
+               if (!codec)
+                       return -EINVAL;
+
+               f->fmt.pix.width = q_data_src->width;
+               f->fmt.pix.height = q_data_src->height;
+       } else {
+               /* Otherwise determine codec by encoded format, if possible */
+               codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
+                                       f->fmt.pix.pixelformat);
+       }
+
+       f->fmt.pix.colorspace = ctx->colorspace;
+
+       ret = coda_try_fmt(ctx, codec, f);
+       if (ret < 0)
+               return ret;
+
+       /* The h.264 decoder only returns complete 16x16 macroblocks */
+       if (codec && codec->src_fourcc == V4L2_PIX_FMT_H264) {
+               f->fmt.pix.width = f->fmt.pix.width;
+               f->fmt.pix.height = round_up(f->fmt.pix.height, 16);
+               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
+               f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+                                      f->fmt.pix.height * 3 / 2;
+       }
+
+       return 0;
+}
+
+static int coda_try_fmt_vid_out(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       const struct coda_codec *codec = NULL;
+
+       /* Determine codec by encoded format, returns NULL if raw or invalid */
+       if (ctx->inst_type == CODA_INST_DECODER) {
+               codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat,
+                                       V4L2_PIX_FMT_YUV420);
+               if (!codec)
+                       codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264,
+                                               V4L2_PIX_FMT_YUV420);
+               if (!codec)
+                       return -EINVAL;
+       }
+
+       if (!f->fmt.pix.colorspace)
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+       return coda_try_fmt(ctx, codec, f);
+}
+
+static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
+{
+       struct coda_q_data *q_data;
+       struct vb2_queue *vq;
+
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       q_data = get_q_data(ctx, f->type);
+       if (!q_data)
+               return -EINVAL;
+
+       if (vb2_is_busy(vq)) {
+               v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+               return -EBUSY;
+       }
+
+       q_data->fourcc = f->fmt.pix.pixelformat;
+       q_data->width = f->fmt.pix.width;
+       q_data->height = f->fmt.pix.height;
+       q_data->bytesperline = f->fmt.pix.bytesperline;
+       q_data->sizeimage = f->fmt.pix.sizeimage;
+       q_data->rect.left = 0;
+       q_data->rect.top = 0;
+       q_data->rect.width = f->fmt.pix.width;
+       q_data->rect.height = f->fmt.pix.height;
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+               "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
+               f->type, q_data->width, q_data->height, q_data->fourcc);
+
+       return 0;
+}
+
+static int coda_s_fmt_vid_cap(struct file *file, void *priv,
+                             struct v4l2_format *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       int ret;
+
+       ret = coda_try_fmt_vid_cap(file, priv, f);
+       if (ret)
+               return ret;
+
+       return coda_s_fmt(ctx, f);
+}
+
+static int coda_s_fmt_vid_out(struct file *file, void *priv,
+                             struct v4l2_format *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       struct v4l2_format f_cap;
+       int ret;
+
+       ret = coda_try_fmt_vid_out(file, priv, f);
+       if (ret)
+               return ret;
+
+       ret = coda_s_fmt(ctx, f);
+       if (ret)
+               return ret;
+
+       ctx->colorspace = f->fmt.pix.colorspace;
+
+       f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       coda_g_fmt(file, priv, &f_cap);
+       f_cap.fmt.pix.width = f->fmt.pix.width;
+       f_cap.fmt.pix.height = f->fmt.pix.height;
+
+       ret = coda_try_fmt_vid_cap(file, priv, &f_cap);
+       if (ret)
+               return ret;
+
+       return coda_s_fmt(ctx, &f_cap);
+}
+
+static int coda_qbuf(struct file *file, void *priv,
+                    struct v4l2_buffer *buf)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf);
+}
+
+static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
+                                     struct v4l2_buffer *buf)
+{
+       struct vb2_queue *src_vq;
+
+       src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+       return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) &&
+               (buf->sequence == (ctx->qsequence - 1)));
+}
+
+static int coda_dqbuf(struct file *file, void *priv,
+                     struct v4l2_buffer *buf)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       int ret;
+
+       ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf);
+
+       /* If this is the last capture buffer, emit an end-of-stream event */
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           coda_buf_is_end_of_stream(ctx, buf)) {
+               const struct v4l2_event eos_event = {
+                       .type = V4L2_EVENT_EOS
+               };
+
+               v4l2_event_queue_fh(&ctx->fh, &eos_event);
+       }
+
+       return ret;
+}
+
+static int coda_g_selection(struct file *file, void *fh,
+                           struct v4l2_selection *s)
+{
+       struct coda_ctx *ctx = fh_to_ctx(fh);
+       struct coda_q_data *q_data;
+       struct v4l2_rect r, *rsel;
+
+       q_data = get_q_data(ctx, s->type);
+       if (!q_data)
+               return -EINVAL;
+
+       r.left = 0;
+       r.top = 0;
+       r.width = q_data->width;
+       r.height = q_data->height;
+       rsel = &q_data->rect;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               rsel = &r;
+               /* fallthrough */
+       case V4L2_SEL_TGT_CROP:
+               if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+                       return -EINVAL;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+       case V4L2_SEL_TGT_COMPOSE_PADDED:
+               rsel = &r;
+               /* fallthrough */
+       case V4L2_SEL_TGT_COMPOSE:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+               if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       s->r = *rsel;
+
+       return 0;
+}
+
+static int coda_try_decoder_cmd(struct file *file, void *fh,
+                               struct v4l2_decoder_cmd *dc)
+{
+       if (dc->cmd != V4L2_DEC_CMD_STOP)
+               return -EINVAL;
+
+       if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
+               return -EINVAL;
+
+       if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int coda_decoder_cmd(struct file *file, void *fh,
+                           struct v4l2_decoder_cmd *dc)
+{
+       struct coda_ctx *ctx = fh_to_ctx(fh);
+       int ret;
+
+       ret = coda_try_decoder_cmd(file, fh, dc);
+       if (ret < 0)
+               return ret;
+
+       /* Ignore decoder stop command silently in encoder context */
+       if (ctx->inst_type != CODA_INST_DECODER)
+               return 0;
+
+       /* Set the stream-end flag on this context */
+       coda_bit_stream_end_flag(ctx);
+       ctx->hold = false;
+       v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
+
+       return 0;
+}
+
+static int coda_subscribe_event(struct v4l2_fh *fh,
+                               const struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_EOS:
+               return v4l2_event_subscribe(fh, sub, 0, NULL);
+       default:
+               return v4l2_ctrl_subscribe_event(fh, sub);
+       }
+}
+
+static const struct v4l2_ioctl_ops coda_ioctl_ops = {
+       .vidioc_querycap        = coda_querycap,
+
+       .vidioc_enum_fmt_vid_cap = coda_enum_fmt,
+       .vidioc_g_fmt_vid_cap   = coda_g_fmt,
+       .vidioc_try_fmt_vid_cap = coda_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap   = coda_s_fmt_vid_cap,
+
+       .vidioc_enum_fmt_vid_out = coda_enum_fmt,
+       .vidioc_g_fmt_vid_out   = coda_g_fmt,
+       .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out,
+       .vidioc_s_fmt_vid_out   = coda_s_fmt_vid_out,
+
+       .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
+       .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
+
+       .vidioc_qbuf            = coda_qbuf,
+       .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
+       .vidioc_dqbuf           = coda_dqbuf,
+       .vidioc_create_bufs     = v4l2_m2m_ioctl_create_bufs,
+
+       .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
+       .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
+
+       .vidioc_g_selection     = coda_g_selection,
+
+       .vidioc_try_decoder_cmd = coda_try_decoder_cmd,
+       .vidioc_decoder_cmd     = coda_decoder_cmd,
+
+       .vidioc_subscribe_event = coda_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+void coda_set_gdi_regs(struct coda_ctx *ctx)
+{
+       struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
+       struct coda_dev *dev = ctx->dev;
+       int i;
+
+       for (i = 0; i < 16; i++)
+               coda_write(dev, tiled_map->xy2ca_map[i],
+                               CODA9_GDI_XY2_CAS_0 + 4 * i);
+       for (i = 0; i < 4; i++)
+               coda_write(dev, tiled_map->xy2ba_map[i],
+                               CODA9_GDI_XY2_BA_0 + 4 * i);
+       for (i = 0; i < 16; i++)
+               coda_write(dev, tiled_map->xy2ra_map[i],
+                               CODA9_GDI_XY2_RAS_0 + 4 * i);
+       coda_write(dev, tiled_map->xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG);
+       for (i = 0; i < 32; i++)
+               coda_write(dev, tiled_map->rbc2axi_map[i],
+                               CODA9_GDI_RBC2_AXI_0 + 4 * i);
+}
+
+/*
+ * Mem-to-mem operations.
+ */
+
+static void coda_device_run(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+       struct coda_dev *dev = ctx->dev;
+
+       queue_work(dev->workqueue, &ctx->pic_run_work);
+}
+
+static void coda_pic_run_work(struct work_struct *work)
+{
+       struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work);
+       struct coda_dev *dev = ctx->dev;
+       int ret;
+
+       mutex_lock(&ctx->buffer_mutex);
+       mutex_lock(&dev->coda_mutex);
+
+       ret = ctx->ops->prepare_run(ctx);
+       if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) {
+               mutex_unlock(&dev->coda_mutex);
+               mutex_unlock(&ctx->buffer_mutex);
+               /* job_finish scheduled by prepare_decode */
+               return;
+       }
+
+       if (!wait_for_completion_timeout(&ctx->completion,
+                                        msecs_to_jiffies(1000))) {
+               dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n");
+
+               ctx->hold = true;
+
+               coda_hw_reset(ctx);
+       } else if (!ctx->aborting) {
+               ctx->ops->finish_run(ctx);
+       }
+
+       if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out))
+               queue_work(dev->workqueue, &ctx->seq_end_work);
+
+       mutex_unlock(&dev->coda_mutex);
+       mutex_unlock(&ctx->buffer_mutex);
+
+       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static int coda_job_ready(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+
+       /*
+        * For both 'P' and 'key' frame cases 1 picture
+        * and 1 frame are needed. In the decoder case,
+        * the compressed frame can be in the bitstream.
+        */
+       if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
+           ctx->inst_type != CODA_INST_DECODER) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "not ready: not enough video buffers.\n");
+               return 0;
+       }
+
+       if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "not ready: not enough video capture buffers.\n");
+               return 0;
+       }
+
+       if (ctx->hold ||
+           ((ctx->inst_type == CODA_INST_DECODER) &&
+            (coda_get_bitstream_payload(ctx) < 512) &&
+            !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "%d: not ready: not enough bitstream data.\n",
+                        ctx->idx);
+               return 0;
+       }
+
+       if (ctx->aborting) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "not ready: aborting\n");
+               return 0;
+       }
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                       "job ready\n");
+       return 1;
+}
+
+static void coda_job_abort(void *priv)
+{
+       struct coda_ctx *ctx = priv;
+
+       ctx->aborting = 1;
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                "Aborting task\n");
+}
+
+static void coda_lock(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+       struct coda_dev *pcdev = ctx->dev;
+
+       mutex_lock(&pcdev->dev_mutex);
+}
+
+static void coda_unlock(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+       struct coda_dev *pcdev = ctx->dev;
+
+       mutex_unlock(&pcdev->dev_mutex);
+}
+
+static const struct v4l2_m2m_ops coda_m2m_ops = {
+       .device_run     = coda_device_run,
+       .job_ready      = coda_job_ready,
+       .job_abort      = coda_job_abort,
+       .lock           = coda_lock,
+       .unlock         = coda_unlock,
+};
+
+static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type)
+{
+       struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
+       int luma_map, chro_map, i;
+
+       memset(tiled_map, 0, sizeof(*tiled_map));
+
+       luma_map = 64;
+       chro_map = 64;
+       tiled_map->map_type = tiled_map_type;
+       for (i = 0; i < 16; i++)
+               tiled_map->xy2ca_map[i] = luma_map << 8 | chro_map;
+       for (i = 0; i < 4; i++)
+               tiled_map->xy2ba_map[i] = luma_map << 8 | chro_map;
+       for (i = 0; i < 16; i++)
+               tiled_map->xy2ra_map[i] = luma_map << 8 | chro_map;
+
+       if (tiled_map_type == GDI_LINEAR_FRAME_MAP) {
+               tiled_map->xy2rbc_config = 0;
+       } else {
+               dev_err(&ctx->dev->plat_dev->dev, "invalid map type: %d\n",
+                       tiled_map_type);
+               return;
+       }
+}
+
+static void set_default_params(struct coda_ctx *ctx)
+{
+       u32 src_fourcc, dst_fourcc;
+       int max_w;
+       int max_h;
+
+       if (ctx->inst_type == CODA_INST_ENCODER) {
+               src_fourcc = V4L2_PIX_FMT_YUV420;
+               dst_fourcc = V4L2_PIX_FMT_H264;
+       } else {
+               src_fourcc = V4L2_PIX_FMT_H264;
+               dst_fourcc = V4L2_PIX_FMT_YUV420;
+       }
+       ctx->codec = coda_find_codec(ctx->dev, src_fourcc, dst_fourcc);
+       max_w = ctx->codec->max_w;
+       max_h = ctx->codec->max_h;
+
+       ctx->params.codec_mode = ctx->codec->mode;
+       ctx->colorspace = V4L2_COLORSPACE_REC709;
+       ctx->params.framerate = 30;
+       ctx->aborting = 0;
+
+       /* Default formats for output and input queues */
+       ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc;
+       ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc;
+       ctx->q_data[V4L2_M2M_SRC].width = max_w;
+       ctx->q_data[V4L2_M2M_SRC].height = max_h;
+       ctx->q_data[V4L2_M2M_DST].width = max_w;
+       ctx->q_data[V4L2_M2M_DST].height = max_h;
+       if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) {
+               ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w;
+               ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
+               ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
+               ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
+       } else {
+               ctx->q_data[V4L2_M2M_SRC].bytesperline = 0;
+               ctx->q_data[V4L2_M2M_SRC].sizeimage = CODA_MAX_FRAME_SIZE;
+               ctx->q_data[V4L2_M2M_DST].bytesperline = max_w;
+               ctx->q_data[V4L2_M2M_DST].sizeimage = (max_w * max_h * 3) / 2;
+       }
+       ctx->q_data[V4L2_M2M_SRC].rect.width = max_w;
+       ctx->q_data[V4L2_M2M_SRC].rect.height = max_h;
+       ctx->q_data[V4L2_M2M_DST].rect.width = max_w;
+       ctx->q_data[V4L2_M2M_DST].rect.height = max_h;
+
+       if (ctx->dev->devtype->product == CODA_960)
+               coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP);
+}
+
+/*
+ * Queue operations
+ */
+static int coda_queue_setup(struct vb2_queue *vq,
+                               const struct v4l2_format *fmt,
+                               unsigned int *nbuffers, unsigned int *nplanes,
+                               unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(vq);
+       struct coda_q_data *q_data;
+       unsigned int size;
+
+       q_data = get_q_data(ctx, vq->type);
+       size = q_data->sizeimage;
+
+       *nplanes = 1;
+       sizes[0] = size;
+
+       alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                "get %d buffer(s) of size %d each.\n", *nbuffers, size);
+
+       return 0;
+}
+
+static int coda_buf_prepare(struct vb2_buffer *vb)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct coda_q_data *q_data;
+
+       q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+       if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+               v4l2_warn(&ctx->dev->v4l2_dev,
+                         "%s data will not fit into plane (%lu < %lu)\n",
+                         __func__, vb2_plane_size(vb, 0),
+                         (long)q_data->sizeimage);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void coda_buf_queue(struct vb2_buffer *vb)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct coda_q_data *q_data;
+
+       q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+       /*
+        * In the decoder case, immediately try to copy the buffer into the
+        * bitstream ringbuffer and mark it as ready to be dequeued.
+        */
+       if (q_data->fourcc == V4L2_PIX_FMT_H264 &&
+           vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               /*
+                * For backwards compatibility, queuing an empty buffer marks
+                * the stream end
+                */
+               if (vb2_get_plane_payload(vb, 0) == 0)
+                       coda_bit_stream_end_flag(ctx);
+               mutex_lock(&ctx->bitstream_mutex);
+               v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
+               if (vb2_is_streaming(vb->vb2_queue))
+                       coda_fill_bitstream(ctx);
+               mutex_unlock(&ctx->bitstream_mutex);
+       } else {
+               v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
+       }
+}
+
+int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
+                      size_t size, const char *name, struct dentry *parent)
+{
+       buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr,
+                                       GFP_KERNEL);
+       if (!buf->vaddr) {
+               v4l2_err(&dev->v4l2_dev,
+                        "Failed to allocate %s buffer of size %u\n",
+                        name, size);
+               return -ENOMEM;
+       }
+
+       buf->size = size;
+
+       if (name && parent) {
+               buf->blob.data = buf->vaddr;
+               buf->blob.size = size;
+               buf->dentry = debugfs_create_blob(name, 0644, parent,
+                                                 &buf->blob);
+               if (!buf->dentry)
+                       dev_warn(&dev->plat_dev->dev,
+                                "failed to create debugfs entry %s\n", name);
+       }
+
+       return 0;
+}
+
+void coda_free_aux_buf(struct coda_dev *dev,
+                      struct coda_aux_buf *buf)
+{
+       if (buf->vaddr) {
+               dma_free_coherent(&dev->plat_dev->dev, buf->size,
+                                 buf->vaddr, buf->paddr);
+               buf->vaddr = NULL;
+               buf->size = 0;
+       }
+       debugfs_remove(buf->dentry);
+}
+
+static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(q);
+       struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev;
+       struct coda_q_data *q_data_src, *q_data_dst;
+       struct vb2_buffer *buf;
+       u32 dst_fourcc;
+       int ret = 0;
+
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               if (q_data_src->fourcc == V4L2_PIX_FMT_H264) {
+                       /* copy the buffers that where queued before streamon */
+                       mutex_lock(&ctx->bitstream_mutex);
+                       coda_fill_bitstream(ctx);
+                       mutex_unlock(&ctx->bitstream_mutex);
+
+                       if (coda_get_bitstream_payload(ctx) < 512) {
+                               ret = -EINVAL;
+                               goto err;
+                       }
+               } else {
+                       if (count < 1) {
+                               ret = -EINVAL;
+                               goto err;
+                       }
+               }
+
+               ctx->streamon_out = 1;
+       } else {
+               if (count < 1) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               ctx->streamon_cap = 1;
+       }
+
+       /* Don't start the coda unless both queues are on */
+       if (!(ctx->streamon_out & ctx->streamon_cap))
+               return 0;
+
+       /* Allow decoder device_run with no new buffers queued */
+       if (ctx->inst_type == CODA_INST_DECODER)
+               v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
+
+       ctx->gopcounter = ctx->params.gop_size - 1;
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       dst_fourcc = q_data_dst->fourcc;
+
+       ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
+                                    q_data_dst->fourcc);
+       if (!ctx->codec) {
+               v4l2_err(v4l2_dev, "couldn't tell instance type.\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = ctx->ops->start_streaming(ctx);
+       if (ctx->inst_type == CODA_INST_DECODER) {
+               if (ret == -EAGAIN)
+                       return 0;
+               else if (ret < 0)
+                       goto err;
+       }
+
+       ctx->initialized = 1;
+       return ret;
+
+err:
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+                       v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED);
+       } else {
+               while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx)))
+                       v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED);
+       }
+       return ret;
+}
+
+static void coda_stop_streaming(struct vb2_queue *q)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(q);
+       struct coda_dev *dev = ctx->dev;
+       struct vb2_buffer *buf;
+
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                        "%s: output\n", __func__);
+               ctx->streamon_out = 0;
+
+               coda_bit_stream_end_flag(ctx);
+
+               ctx->isequence = 0;
+
+               while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+                       v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+       } else {
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                        "%s: capture\n", __func__);
+               ctx->streamon_cap = 0;
+
+               ctx->osequence = 0;
+               ctx->sequence_offset = 0;
+
+               while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx)))
+                       v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+       }
+
+       if (!ctx->streamon_out && !ctx->streamon_cap) {
+               struct coda_timestamp *ts;
+
+               mutex_lock(&ctx->bitstream_mutex);
+               while (!list_empty(&ctx->timestamp_list)) {
+                       ts = list_first_entry(&ctx->timestamp_list,
+                                             struct coda_timestamp, list);
+                       list_del(&ts->list);
+                       kfree(ts);
+               }
+               mutex_unlock(&ctx->bitstream_mutex);
+               kfifo_init(&ctx->bitstream_fifo,
+                       ctx->bitstream.vaddr, ctx->bitstream.size);
+               ctx->runcounter = 0;
+       }
+}
+
+static const struct vb2_ops coda_qops = {
+       .queue_setup            = coda_queue_setup,
+       .buf_prepare            = coda_buf_prepare,
+       .buf_queue              = coda_buf_queue,
+       .start_streaming        = coda_start_streaming,
+       .stop_streaming         = coda_stop_streaming,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+};
+
+static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct coda_ctx *ctx =
+                       container_of(ctrl->handler, struct coda_ctx, ctrls);
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
+
+       switch (ctrl->id) {
+       case V4L2_CID_HFLIP:
+               if (ctrl->val)
+                       ctx->params.rot_mode |= CODA_MIR_HOR;
+               else
+                       ctx->params.rot_mode &= ~CODA_MIR_HOR;
+               break;
+       case V4L2_CID_VFLIP:
+               if (ctrl->val)
+                       ctx->params.rot_mode |= CODA_MIR_VER;
+               else
+                       ctx->params.rot_mode &= ~CODA_MIR_VER;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               ctx->params.bitrate = ctrl->val / 1000;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               ctx->params.gop_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+               ctx->params.h264_intra_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+               ctx->params.h264_inter_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+               ctx->params.h264_min_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+               ctx->params.h264_max_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+               ctx->params.h264_deblk_alpha = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+               ctx->params.h264_deblk_beta = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+               ctx->params.h264_deblk_enabled = (ctrl->val ==
+                               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+               ctx->params.mpeg4_intra_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+               ctx->params.mpeg4_inter_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+               ctx->params.slice_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+               ctx->params.slice_max_mb = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+               ctx->params.slice_max_bits = ctrl->val * 8;
+               break;
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+               break;
+       case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+               ctx->params.intra_refresh = ctrl->val;
+               break;
+       default:
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                       "Invalid control, id=%d, val=%d\n",
+                       ctrl->id, ctrl->val);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops coda_ctrl_ops = {
+       .s_ctrl = coda_s_ctrl,
+};
+
+static int coda_ctrls_setup(struct coda_ctx *ctx)
+{
+       v4l2_ctrl_handler_init(&ctx->ctrls, 9);
+
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_VFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25);
+       if (ctx->dev->devtype->product != CODA_960) {
+               v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+                       V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12);
+       }
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0);
+       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0,
+               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2);
+       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+               V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0,
+               V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1,
+               500);
+       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+               V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+               (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE),
+               V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0,
+               1920 * 1088 / 256, 1, 0);
+
+       if (ctx->ctrls.error) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                       "control initialization error (%d)",
+                       ctx->ctrls.error);
+               return -EINVAL;
+       }
+
+       return v4l2_ctrl_handler_setup(&ctx->ctrls);
+}
+
+static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq)
+{
+       vq->drv_priv = ctx;
+       vq->ops = &coda_qops;
+       vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       vq->lock = &ctx->dev->dev_mutex;
+
+       return vb2_queue_init(vq);
+}
+
+int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq,
+                           struct vb2_queue *dst_vq)
+{
+       int ret;
+
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+
+       ret = coda_queue_init(priv, src_vq);
+       if (ret)
+               return ret;
+
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+       return coda_queue_init(priv, dst_vq);
+}
+
+int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
+                           struct vb2_queue *dst_vq)
+{
+       int ret;
+
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+
+       ret = coda_queue_init(priv, src_vq);
+       if (ret)
+               return ret;
+
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+       return coda_queue_init(priv, dst_vq);
+}
+
+static int coda_next_free_instance(struct coda_dev *dev)
+{
+       int idx = ffz(dev->instance_mask);
+
+       if ((idx < 0) ||
+           (dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES))
+               return -EBUSY;
+
+       return idx;
+}
+
+static int coda_open(struct file *file, enum coda_inst_type inst_type,
+                    const struct coda_context_ops *ctx_ops)
+{
+       struct coda_dev *dev = video_drvdata(file);
+       struct coda_ctx *ctx = NULL;
+       char *name;
+       int ret;
+       int idx;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       idx = coda_next_free_instance(dev);
+       if (idx < 0) {
+               ret = idx;
+               goto err_coda_max;
+       }
+       set_bit(idx, &dev->instance_mask);
+
+       name = kasprintf(GFP_KERNEL, "context%d", idx);
+       ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root);
+       kfree(name);
+
+       ctx->inst_type = inst_type;
+       ctx->ops = ctx_ops;
+       init_completion(&ctx->completion);
+       INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
+       INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work);
+       v4l2_fh_init(&ctx->fh, video_devdata(file));
+       file->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+       ctx->dev = dev;
+       ctx->idx = idx;
+       switch (dev->devtype->product) {
+       case CODA_7541:
+       case CODA_960:
+               ctx->reg_idx = 0;
+               break;
+       default:
+               ctx->reg_idx = idx;
+       }
+
+       /* Power up and upload firmware if necessary */
+       ret = pm_runtime_get_sync(&dev->plat_dev->dev);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret);
+               goto err_pm_get;
+       }
+
+       ret = clk_prepare_enable(dev->clk_per);
+       if (ret)
+               goto err_clk_per;
+
+       ret = clk_prepare_enable(dev->clk_ahb);
+       if (ret)
+               goto err_clk_ahb;
+
+       set_default_params(ctx);
+       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+                                           ctx->ops->queue_init);
+       if (IS_ERR(ctx->fh.m2m_ctx)) {
+               ret = PTR_ERR(ctx->fh.m2m_ctx);
+
+               v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n",
+                        __func__, ret);
+               goto err_ctx_init;
+       }
+
+       ret = coda_ctrls_setup(ctx);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n");
+               goto err_ctrls_setup;
+       }
+
+       ctx->fh.ctrl_handler = &ctx->ctrls;
+
+       ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE,
+                                    "parabuf");
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
+               goto err_dma_alloc;
+       }
+
+       ctx->bitstream.size = CODA_MAX_FRAME_SIZE;
+       ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev,
+                       ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL);
+       if (!ctx->bitstream.vaddr) {
+               v4l2_err(&dev->v4l2_dev,
+                        "failed to allocate bitstream ringbuffer");
+               ret = -ENOMEM;
+               goto err_dma_writecombine;
+       }
+       kfifo_init(&ctx->bitstream_fifo,
+               ctx->bitstream.vaddr, ctx->bitstream.size);
+       mutex_init(&ctx->bitstream_mutex);
+       mutex_init(&ctx->buffer_mutex);
+       INIT_LIST_HEAD(&ctx->timestamp_list);
+
+       coda_lock(ctx);
+       list_add(&ctx->list, &dev->instances);
+       coda_unlock(ctx);
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n",
+                ctx->idx, ctx);
+
+       return 0;
+
+err_dma_writecombine:
+       if (ctx->dev->devtype->product == CODA_DX6)
+               coda_free_aux_buf(dev, &ctx->workbuf);
+       coda_free_aux_buf(dev, &ctx->parabuf);
+err_dma_alloc:
+       v4l2_ctrl_handler_free(&ctx->ctrls);
+err_ctrls_setup:
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+err_ctx_init:
+       clk_disable_unprepare(dev->clk_ahb);
+err_clk_ahb:
+       clk_disable_unprepare(dev->clk_per);
+err_clk_per:
+       pm_runtime_put_sync(&dev->plat_dev->dev);
+err_pm_get:
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       clear_bit(ctx->idx, &dev->instance_mask);
+err_coda_max:
+       kfree(ctx);
+       return ret;
+}
+
+static int coda_encoder_open(struct file *file)
+{
+       return coda_open(file, CODA_INST_ENCODER, &coda_bit_encode_ops);
+}
+
+static int coda_decoder_open(struct file *file)
+{
+       return coda_open(file, CODA_INST_DECODER, &coda_bit_decode_ops);
+}
+
+static int coda_release(struct file *file)
+{
+       struct coda_dev *dev = video_drvdata(file);
+       struct coda_ctx *ctx = fh_to_ctx(file->private_data);
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
+                ctx);
+
+       debugfs_remove_recursive(ctx->debugfs_entry);
+
+       /* If this instance is running, call .job_abort and wait for it to end */
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+       /* In case the instance was not running, we still need to call SEQ_END */
+       if (ctx->initialized) {
+               queue_work(dev->workqueue, &ctx->seq_end_work);
+               flush_work(&ctx->seq_end_work);
+       }
+
+       coda_lock(ctx);
+       list_del(&ctx->list);
+       coda_unlock(ctx);
+
+       dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
+               ctx->bitstream.vaddr, ctx->bitstream.paddr);
+       if (ctx->dev->devtype->product == CODA_DX6)
+               coda_free_aux_buf(dev, &ctx->workbuf);
+
+       coda_free_aux_buf(dev, &ctx->parabuf);
+       v4l2_ctrl_handler_free(&ctx->ctrls);
+       clk_disable_unprepare(dev->clk_ahb);
+       clk_disable_unprepare(dev->clk_per);
+       pm_runtime_put_sync(&dev->plat_dev->dev);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       clear_bit(ctx->idx, &dev->instance_mask);
+       if (ctx->ops->release)
+               ctx->ops->release(ctx);
+       kfree(ctx);
+
+       return 0;
+}
+
+static const struct v4l2_file_operations coda_encoder_fops = {
+       .owner          = THIS_MODULE,
+       .open           = coda_encoder_open,
+       .release        = coda_release,
+       .poll           = v4l2_m2m_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = v4l2_m2m_fop_mmap,
+};
+
+static const struct v4l2_file_operations coda_decoder_fops = {
+       .owner          = THIS_MODULE,
+       .open           = coda_decoder_open,
+       .release        = coda_release,
+       .poll           = v4l2_m2m_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = v4l2_m2m_fop_mmap,
+};
+
+static int coda_hw_init(struct coda_dev *dev)
+{
+       u32 data;
+       u16 *p;
+       int i, ret;
+
+       ret = clk_prepare_enable(dev->clk_per);
+       if (ret)
+               goto err_clk_per;
+
+       ret = clk_prepare_enable(dev->clk_ahb);
+       if (ret)
+               goto err_clk_ahb;
+
+       if (dev->rstc)
+               reset_control_reset(dev->rstc);
+
+       /*
+        * Copy the first CODA_ISRAM_SIZE in the internal SRAM.
+        * The 16-bit chars in the code buffer are in memory access
+        * order, re-sort them to CODA order for register download.
+        * Data in this SRAM survives a reboot.
+        */
+       p = (u16 *)dev->codebuf.vaddr;
+       if (dev->devtype->product == CODA_DX6) {
+               for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++)  {
+                       data = CODA_DOWN_ADDRESS_SET(i) |
+                               CODA_DOWN_DATA_SET(p[i ^ 1]);
+                       coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
+               }
+       } else {
+               for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) {
+                       data = CODA_DOWN_ADDRESS_SET(i) |
+                               CODA_DOWN_DATA_SET(p[round_down(i, 4) +
+                                                       3 - (i % 4)]);
+                       coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
+               }
+       }
+
+       /* Clear registers */
+       for (i = 0; i < 64; i++)
+               coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4);
+
+       /* Tell the BIT where to find everything it needs */
+       if (dev->devtype->product == CODA_960 ||
+           dev->devtype->product == CODA_7541) {
+               coda_write(dev, dev->tempbuf.paddr,
+                               CODA_REG_BIT_TEMP_BUF_ADDR);
+               coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
+       } else {
+               coda_write(dev, dev->workbuf.paddr,
+                             CODA_REG_BIT_WORK_BUF_ADDR);
+       }
+       coda_write(dev, dev->codebuf.paddr,
+                     CODA_REG_BIT_CODE_BUF_ADDR);
+       coda_write(dev, 0, CODA_REG_BIT_CODE_RUN);
+
+       /* Set default values */
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH,
+                          CODA_REG_BIT_STREAM_CTRL);
+               break;
+       default:
+               coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH,
+                          CODA_REG_BIT_STREAM_CTRL);
+       }
+       if (dev->devtype->product == CODA_960)
+               coda_write(dev, 1 << 12, CODA_REG_BIT_FRAME_MEM_CTRL);
+       else
+               coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL);
+
+       if (dev->devtype->product != CODA_DX6)
+               coda_write(dev, 0, CODA7_REG_BIT_AXI_SRAM_USE);
+
+       coda_write(dev, CODA_INT_INTERRUPT_ENABLE,
+                     CODA_REG_BIT_INT_ENABLE);
+
+       /* Reset VPU and start processor */
+       data = coda_read(dev, CODA_REG_BIT_CODE_RESET);
+       data |= CODA_REG_RESET_ENABLE;
+       coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
+       udelay(10);
+       data &= ~CODA_REG_RESET_ENABLE;
+       coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
+       coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
+
+       clk_disable_unprepare(dev->clk_ahb);
+       clk_disable_unprepare(dev->clk_per);
+
+       return 0;
+
+err_clk_ahb:
+       clk_disable_unprepare(dev->clk_per);
+err_clk_per:
+       return ret;
+}
+
+static int coda_register_device(struct coda_dev *dev, struct video_device *vfd)
+{
+       vfd->release    = video_device_release_empty,
+       vfd->lock       = &dev->dev_mutex;
+       vfd->v4l2_dev   = &dev->v4l2_dev;
+       vfd->vfl_dir    = VFL_DIR_M2M;
+       video_set_drvdata(vfd, dev);
+
+       /* Not applicable, use the selection API instead */
+       v4l2_disable_ioctl(vfd, VIDIOC_CROPCAP);
+       v4l2_disable_ioctl(vfd, VIDIOC_G_CROP);
+       v4l2_disable_ioctl(vfd, VIDIOC_S_CROP);
+
+       return video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+}
+
+static void coda_fw_callback(const struct firmware *fw, void *context)
+{
+       struct coda_dev *dev = context;
+       struct platform_device *pdev = dev->plat_dev;
+       int ret;
+
+       if (!fw) {
+               v4l2_err(&dev->v4l2_dev, "firmware request failed\n");
+               goto put_pm;
+       }
+
+       /* allocate auxiliary per-device code buffer for the BIT processor */
+       ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf",
+                                dev->debugfs_root);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to allocate code buffer\n");
+               goto put_pm;
+       }
+
+       /* Copy the whole firmware image to the code buffer */
+       memcpy(dev->codebuf.vaddr, fw->data, fw->size);
+       release_firmware(fw);
+
+       ret = coda_hw_init(dev);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "HW initialization failed\n");
+               goto put_pm;
+       }
+
+       ret = coda_check_firmware(dev);
+       if (ret < 0)
+               goto put_pm;
+
+       dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(dev->alloc_ctx)) {
+               v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n");
+               goto put_pm;
+       }
+
+       dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops);
+       if (IS_ERR(dev->m2m_dev)) {
+               v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+               goto rel_ctx;
+       }
+
+       dev->vfd[0].fops      = &coda_encoder_fops,
+       dev->vfd[0].ioctl_ops = &coda_ioctl_ops;
+       snprintf(dev->vfd[0].name, sizeof(dev->vfd[0].name), "coda-encoder");
+       ret = coda_register_device(dev, &dev->vfd[0]);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev,
+                        "Failed to register encoder video device\n");
+               goto rel_m2m;
+       }
+
+       dev->vfd[1].fops      = &coda_decoder_fops,
+       dev->vfd[1].ioctl_ops = &coda_ioctl_ops;
+       snprintf(dev->vfd[1].name, sizeof(dev->vfd[1].name), "coda-decoder");
+       ret = coda_register_device(dev, &dev->vfd[1]);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev,
+                        "Failed to register decoder video device\n");
+               goto rel_m2m;
+       }
+
+       v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n",
+                 dev->vfd[0].num, dev->vfd[1].num);
+
+       pm_runtime_put_sync(&pdev->dev);
+       return;
+
+rel_m2m:
+       v4l2_m2m_release(dev->m2m_dev);
+rel_ctx:
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+put_pm:
+       pm_runtime_put_sync(&pdev->dev);
+}
+
+static int coda_firmware_request(struct coda_dev *dev)
+{
+       char *fw = dev->devtype->firmware;
+
+       dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
+               coda_product_name(dev->devtype->product));
+
+       return request_firmware_nowait(THIS_MODULE, true,
+               fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback);
+}
+
+enum coda_platform {
+       CODA_IMX27,
+       CODA_IMX53,
+       CODA_IMX6Q,
+       CODA_IMX6DL,
+};
+
+static const struct coda_devtype coda_devdata[] = {
+       [CODA_IMX27] = {
+               .firmware     = "v4l-codadx6-imx27.bin",
+               .product      = CODA_DX6,
+               .codecs       = codadx6_codecs,
+               .num_codecs   = ARRAY_SIZE(codadx6_codecs),
+               .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024,
+               .iram_size    = 0xb000,
+       },
+       [CODA_IMX53] = {
+               .firmware     = "v4l-coda7541-imx53.bin",
+               .product      = CODA_7541,
+               .codecs       = coda7_codecs,
+               .num_codecs   = ARRAY_SIZE(coda7_codecs),
+               .workbuf_size = 128 * 1024,
+               .tempbuf_size = 304 * 1024,
+               .iram_size    = 0x14000,
+       },
+       [CODA_IMX6Q] = {
+               .firmware     = "v4l-coda960-imx6q.bin",
+               .product      = CODA_960,
+               .codecs       = coda9_codecs,
+               .num_codecs   = ARRAY_SIZE(coda9_codecs),
+               .workbuf_size = 80 * 1024,
+               .tempbuf_size = 204 * 1024,
+               .iram_size    = 0x21000,
+       },
+       [CODA_IMX6DL] = {
+               .firmware     = "v4l-coda960-imx6dl.bin",
+               .product      = CODA_960,
+               .codecs       = coda9_codecs,
+               .num_codecs   = ARRAY_SIZE(coda9_codecs),
+               .workbuf_size = 80 * 1024,
+               .tempbuf_size = 204 * 1024,
+               .iram_size    = 0x20000,
+       },
+};
+
+static struct platform_device_id coda_platform_ids[] = {
+       { .name = "coda-imx27", .driver_data = CODA_IMX27 },
+       { .name = "coda-imx53", .driver_data = CODA_IMX53 },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, coda_platform_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id coda_dt_ids[] = {
+       { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] },
+       { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] },
+       { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] },
+       { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, coda_dt_ids);
+#endif
+
+static int coda_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *of_id =
+                       of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev);
+       const struct platform_device_id *pdev_id;
+       struct coda_platform_data *pdata = pdev->dev.platform_data;
+       struct device_node *np = pdev->dev.of_node;
+       struct gen_pool *pool;
+       struct coda_dev *dev;
+       struct resource *res;
+       int ret, irq;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&pdev->dev, "Not enough memory for %s\n",
+                       CODA_NAME);
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&dev->irqlock);
+       INIT_LIST_HEAD(&dev->instances);
+
+       dev->plat_dev = pdev;
+       dev->clk_per = devm_clk_get(&pdev->dev, "per");
+       if (IS_ERR(dev->clk_per)) {
+               dev_err(&pdev->dev, "Could not get per clock\n");
+               return PTR_ERR(dev->clk_per);
+       }
+
+       dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
+       if (IS_ERR(dev->clk_ahb)) {
+               dev_err(&pdev->dev, "Could not get ahb clock\n");
+               return PTR_ERR(dev->clk_ahb);
+       }
+
+       /* Get  memory for physical registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dev->regs_base))
+               return PTR_ERR(dev->regs_base);
+
+       /* IRQ */
+       irq = platform_get_irq_byname(pdev, "bit");
+       if (irq < 0)
+               irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get irq resource\n");
+               return irq;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
+                       IRQF_ONESHOT, dev_name(&pdev->dev), dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+               return ret;
+       }
+
+       dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL);
+       if (IS_ERR(dev->rstc)) {
+               ret = PTR_ERR(dev->rstc);
+               if (ret == -ENOENT || ret == -ENOSYS) {
+                       dev->rstc = NULL;
+               } else {
+                       dev_err(&pdev->dev, "failed get reset control: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       /* Get IRAM pool from device tree or platform data */
+       pool = of_get_named_gen_pool(np, "iram", 0);
+       if (!pool && pdata)
+               pool = dev_get_gen_pool(pdata->iram_dev);
+       if (!pool) {
+               dev_err(&pdev->dev, "iram pool not available\n");
+               return -ENOMEM;
+       }
+       dev->iram_pool = pool;
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret)
+               return ret;
+
+       mutex_init(&dev->dev_mutex);
+       mutex_init(&dev->coda_mutex);
+
+       pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
+
+       if (of_id) {
+               dev->devtype = of_id->data;
+       } else if (pdev_id) {
+               dev->devtype = &coda_devdata[pdev_id->driver_data];
+       } else {
+               v4l2_device_unregister(&dev->v4l2_dev);
+               return -EINVAL;
+       }
+
+       dev->debugfs_root = debugfs_create_dir("coda", NULL);
+       if (!dev->debugfs_root)
+               dev_warn(&pdev->dev, "failed to create debugfs root\n");
+
+       /* allocate auxiliary per-device buffers for the BIT processor */
+       if (dev->devtype->product == CODA_DX6) {
+               ret = coda_alloc_aux_buf(dev, &dev->workbuf,
+                                        dev->devtype->workbuf_size, "workbuf",
+                                        dev->debugfs_root);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to allocate work buffer\n");
+                       v4l2_device_unregister(&dev->v4l2_dev);
+                       return ret;
+               }
+       }
+
+       if (dev->devtype->tempbuf_size) {
+               ret = coda_alloc_aux_buf(dev, &dev->tempbuf,
+                                        dev->devtype->tempbuf_size, "tempbuf",
+                                        dev->debugfs_root);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to allocate temp buffer\n");
+                       v4l2_device_unregister(&dev->v4l2_dev);
+                       return ret;
+               }
+       }
+
+       dev->iram.size = dev->devtype->iram_size;
+       dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size,
+                                            &dev->iram.paddr);
+       if (!dev->iram.vaddr) {
+               dev_warn(&pdev->dev, "unable to alloc iram\n");
+       } else {
+               dev->iram.blob.data = dev->iram.vaddr;
+               dev->iram.blob.size = dev->iram.size;
+               dev->iram.dentry = debugfs_create_blob("iram", 0644,
+                                                      dev->debugfs_root,
+                                                      &dev->iram.blob);
+       }
+
+       dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+       if (!dev->workqueue) {
+               dev_err(&pdev->dev, "unable to alloc workqueue\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, dev);
+
+       /*
+        * Start activated so we can directly call coda_hw_init in
+        * coda_fw_callback regardless of whether CONFIG_PM_RUNTIME is
+        * enabled or whether the device is associated with a PM domain.
+        */
+       pm_runtime_get_noresume(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
+       return coda_firmware_request(dev);
+}
+
+static int coda_remove(struct platform_device *pdev)
+{
+       struct coda_dev *dev = platform_get_drvdata(pdev);
+
+       video_unregister_device(&dev->vfd[0]);
+       video_unregister_device(&dev->vfd[1]);
+       if (dev->m2m_dev)
+               v4l2_m2m_release(dev->m2m_dev);
+       pm_runtime_disable(&pdev->dev);
+       if (dev->alloc_ctx)
+               vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       destroy_workqueue(dev->workqueue);
+       if (dev->iram.vaddr)
+               gen_pool_free(dev->iram_pool, (unsigned long)dev->iram.vaddr,
+                             dev->iram.size);
+       coda_free_aux_buf(dev, &dev->codebuf);
+       coda_free_aux_buf(dev, &dev->tempbuf);
+       coda_free_aux_buf(dev, &dev->workbuf);
+       debugfs_remove_recursive(dev->debugfs_root);
+       return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int coda_runtime_resume(struct device *dev)
+{
+       struct coda_dev *cdev = dev_get_drvdata(dev);
+       int ret = 0;
+
+       if (dev->pm_domain && cdev->codebuf.vaddr) {
+               ret = coda_hw_init(cdev);
+               if (ret)
+                       v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n");
+       }
+
+       return ret;
+}
+#endif
+
+static const struct dev_pm_ops coda_pm_ops = {
+       SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL)
+};
+
+static struct platform_driver coda_driver = {
+       .probe  = coda_probe,
+       .remove = coda_remove,
+       .driver = {
+               .name   = CODA_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(coda_dt_ids),
+               .pm     = &coda_pm_ops,
+       },
+       .id_table = coda_platform_ids,
+};
+
+module_platform_driver(coda_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
+MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver");
diff --git a/drivers/media/platform/coda/coda-h264.c b/drivers/media/platform/coda/coda-h264.c
new file mode 100644 (file)
index 0000000..456773a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Coda multi-standard codec IP - H.264 helper functions
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ *
+ * 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/kernel.h>
+#include <linux/string.h>
+
+static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff,
+                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 };
+static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 };
+
+int coda_h264_padding(int size, char *p)
+{
+       int nal_size;
+       int diff;
+
+       diff = size - (size & ~0x7);
+       if (diff == 0)
+               return 0;
+
+       nal_size = coda_filler_size[diff];
+       memcpy(p, coda_filler_nal, nal_size);
+
+       /* Add rbsp stop bit and trailing at the end */
+       *(p + nal_size - 1) = 0x80;
+
+       return nal_size;
+}
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
new file mode 100644 (file)
index 0000000..bbc18c0
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Coda multi-standard codec IP
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix
+ *
+ * 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/debugfs.h>
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <linux/kfifo.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-core.h>
+
+#include "coda_regs.h"
+
+#define CODA_MAX_FRAMEBUFFERS  8
+#define CODA_MAX_FRAME_SIZE    0x100000
+#define FMO_SLICE_SAVE_BUF_SIZE        (32)
+
+enum {
+       V4L2_M2M_SRC = 0,
+       V4L2_M2M_DST = 1,
+};
+
+enum coda_inst_type {
+       CODA_INST_ENCODER,
+       CODA_INST_DECODER,
+};
+
+enum coda_product {
+       CODA_DX6 = 0xf001,
+       CODA_7541 = 0xf012,
+       CODA_960 = 0xf020,
+};
+
+struct coda_devtype {
+       char                    *firmware;
+       enum coda_product       product;
+       const struct coda_codec *codecs;
+       unsigned int            num_codecs;
+       size_t                  workbuf_size;
+       size_t                  tempbuf_size;
+       size_t                  iram_size;
+};
+
+struct coda_aux_buf {
+       void                    *vaddr;
+       dma_addr_t              paddr;
+       u32                     size;
+       struct debugfs_blob_wrapper blob;
+       struct dentry           *dentry;
+};
+
+struct coda_dev {
+       struct v4l2_device      v4l2_dev;
+       struct video_device     vfd[2];
+       struct platform_device  *plat_dev;
+       const struct coda_devtype *devtype;
+
+       void __iomem            *regs_base;
+       struct clk              *clk_per;
+       struct clk              *clk_ahb;
+       struct reset_control    *rstc;
+
+       struct coda_aux_buf     codebuf;
+       struct coda_aux_buf     tempbuf;
+       struct coda_aux_buf     workbuf;
+       struct gen_pool         *iram_pool;
+       struct coda_aux_buf     iram;
+
+       spinlock_t              irqlock;
+       struct mutex            dev_mutex;
+       struct mutex            coda_mutex;
+       struct workqueue_struct *workqueue;
+       struct v4l2_m2m_dev     *m2m_dev;
+       struct vb2_alloc_ctx    *alloc_ctx;
+       struct list_head        instances;
+       unsigned long           instance_mask;
+       struct dentry           *debugfs_root;
+};
+
+struct coda_codec {
+       u32 mode;
+       u32 src_fourcc;
+       u32 dst_fourcc;
+       u32 max_w;
+       u32 max_h;
+};
+
+struct coda_huff_tab;
+
+struct coda_params {
+       u8                      rot_mode;
+       u8                      h264_intra_qp;
+       u8                      h264_inter_qp;
+       u8                      h264_min_qp;
+       u8                      h264_max_qp;
+       u8                      h264_deblk_enabled;
+       u8                      h264_deblk_alpha;
+       u8                      h264_deblk_beta;
+       u8                      mpeg4_intra_qp;
+       u8                      mpeg4_inter_qp;
+       u8                      gop_size;
+       int                     intra_refresh;
+       int                     codec_mode;
+       int                     codec_mode_aux;
+       enum v4l2_mpeg_video_multi_slice_mode slice_mode;
+       u32                     framerate;
+       u16                     bitrate;
+       u32                     slice_max_bits;
+       u32                     slice_max_mb;
+};
+
+struct coda_timestamp {
+       struct list_head        list;
+       u32                     sequence;
+       struct v4l2_timecode    timecode;
+       struct timeval          timestamp;
+};
+
+/* Per-queue, driver-specific private data */
+struct coda_q_data {
+       unsigned int            width;
+       unsigned int            height;
+       unsigned int            bytesperline;
+       unsigned int            sizeimage;
+       unsigned int            fourcc;
+       struct v4l2_rect        rect;
+};
+
+struct coda_iram_info {
+       u32             axi_sram_use;
+       phys_addr_t     buf_bit_use;
+       phys_addr_t     buf_ip_ac_dc_use;
+       phys_addr_t     buf_dbk_y_use;
+       phys_addr_t     buf_dbk_c_use;
+       phys_addr_t     buf_ovl_use;
+       phys_addr_t     buf_btp_use;
+       phys_addr_t     search_ram_paddr;
+       int             search_ram_size;
+       int             remaining;
+       phys_addr_t     next_paddr;
+};
+
+struct gdi_tiled_map {
+       int xy2ca_map[16];
+       int xy2ba_map[16];
+       int xy2ra_map[16];
+       int rbc2axi_map[32];
+       int xy2rbc_config;
+       int map_type;
+#define GDI_LINEAR_FRAME_MAP 0
+};
+
+struct coda_ctx;
+
+struct coda_context_ops {
+       int (*queue_init)(void *priv, struct vb2_queue *src_vq,
+                         struct vb2_queue *dst_vq);
+       int (*start_streaming)(struct coda_ctx *ctx);
+       int (*prepare_run)(struct coda_ctx *ctx);
+       void (*finish_run)(struct coda_ctx *ctx);
+       void (*seq_end_work)(struct work_struct *work);
+       void (*release)(struct coda_ctx *ctx);
+};
+
+struct coda_ctx {
+       struct coda_dev                 *dev;
+       struct mutex                    buffer_mutex;
+       struct list_head                list;
+       struct work_struct              pic_run_work;
+       struct work_struct              seq_end_work;
+       struct completion               completion;
+       const struct coda_context_ops   *ops;
+       int                             aborting;
+       int                             initialized;
+       int                             streamon_out;
+       int                             streamon_cap;
+       u32                             isequence;
+       u32                             qsequence;
+       u32                             osequence;
+       u32                             sequence_offset;
+       struct coda_q_data              q_data[2];
+       enum coda_inst_type             inst_type;
+       const struct coda_codec         *codec;
+       enum v4l2_colorspace            colorspace;
+       struct coda_params              params;
+       struct v4l2_ctrl_handler        ctrls;
+       struct v4l2_fh                  fh;
+       int                             gopcounter;
+       int                             runcounter;
+       char                            vpu_header[3][64];
+       int                             vpu_header_size[3];
+       struct kfifo                    bitstream_fifo;
+       struct mutex                    bitstream_mutex;
+       struct coda_aux_buf             bitstream;
+       bool                            hold;
+       struct coda_aux_buf             parabuf;
+       struct coda_aux_buf             psbuf;
+       struct coda_aux_buf             slicebuf;
+       struct coda_aux_buf             internal_frames[CODA_MAX_FRAMEBUFFERS];
+       u32                             frame_types[CODA_MAX_FRAMEBUFFERS];
+       struct coda_timestamp           frame_timestamps[CODA_MAX_FRAMEBUFFERS];
+       u32                             frame_errors[CODA_MAX_FRAMEBUFFERS];
+       struct list_head                timestamp_list;
+       struct coda_aux_buf             workbuf;
+       int                             num_internal_frames;
+       int                             idx;
+       int                             reg_idx;
+       struct coda_iram_info           iram_info;
+       struct gdi_tiled_map            tiled_map;
+       u32                             bit_stream_param;
+       u32                             frm_dis_flg;
+       u32                             frame_mem_ctrl;
+       int                             display_idx;
+       struct dentry                   *debugfs_entry;
+};
+
+extern int coda_debug;
+
+void coda_write(struct coda_dev *dev, u32 data, u32 reg);
+unsigned int coda_read(struct coda_dev *dev, u32 reg);
+
+int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
+                      size_t size, const char *name, struct dentry *parent);
+void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf);
+
+static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
+                                        struct coda_aux_buf *buf, size_t size,
+                                        const char *name)
+{
+       return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry);
+}
+
+int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq,
+                           struct vb2_queue *dst_vq);
+int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
+                           struct vb2_queue *dst_vq);
+
+int coda_hw_reset(struct coda_ctx *ctx);
+
+void coda_fill_bitstream(struct coda_ctx *ctx);
+
+void coda_set_gdi_regs(struct coda_ctx *ctx);
+
+static inline struct coda_q_data *get_q_data(struct coda_ctx *ctx,
+                                            enum v4l2_buf_type type)
+{
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               return &(ctx->q_data[V4L2_M2M_SRC]);
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return &(ctx->q_data[V4L2_M2M_DST]);
+       default:
+               return NULL;
+       }
+}
+
+const char *coda_product_name(int product);
+
+int coda_check_firmware(struct coda_dev *dev);
+
+static inline int coda_get_bitstream_payload(struct coda_ctx *ctx)
+{
+       return kfifo_len(&ctx->bitstream_fifo);
+}
+
+void coda_bit_stream_end_flag(struct coda_ctx *ctx);
+
+int coda_h264_padding(int size, char *p);
+
+extern const struct coda_context_ops coda_bit_encode_ops;
+extern const struct coda_context_ops coda_bit_decode_ops;
+
+irqreturn_t coda_irq_handler(int irq, void *data);
diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h
new file mode 100644 (file)
index 0000000..c791275
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * linux/drivers/media/platform/coda/coda_regs.h
+ *
+ * Copyright (C) 2012 Vista Silicon SL
+ *    Javier Martin <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ *
+ * 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.
+ */
+
+#ifndef _REGS_CODA_H_
+#define _REGS_CODA_H_
+
+/* HW registers */
+#define CODA_REG_BIT_CODE_RUN                  0x000
+#define                CODA_REG_RUN_ENABLE             (1 << 0)
+#define CODA_REG_BIT_CODE_DOWN                 0x004
+#define                CODA_DOWN_ADDRESS_SET(x)        (((x) & 0xffff) << 16)
+#define                CODA_DOWN_DATA_SET(x)           ((x) & 0xffff)
+#define CODA_REG_BIT_HOST_IN_REQ               0x008
+#define CODA_REG_BIT_INT_CLEAR                 0x00c
+#define                CODA_REG_BIT_INT_CLEAR_SET      0x1
+#define CODA_REG_BIT_INT_STATUS                0x010
+#define CODA_REG_BIT_CODE_RESET                0x014
+#define                CODA_REG_RESET_ENABLE           (1 << 0)
+#define CODA_REG_BIT_CUR_PC                    0x018
+#define CODA9_REG_BIT_SW_RESET                 0x024
+#define                CODA9_SW_RESET_BPU_CORE   0x008
+#define                CODA9_SW_RESET_BPU_BUS    0x010
+#define                CODA9_SW_RESET_VCE_CORE   0x020
+#define                CODA9_SW_RESET_VCE_BUS    0x040
+#define                CODA9_SW_RESET_GDI_CORE   0x080
+#define                CODA9_SW_RESET_GDI_BUS    0x100
+#define CODA9_REG_BIT_SW_RESET_STATUS          0x034
+
+/* Static SW registers */
+#define CODA_REG_BIT_CODE_BUF_ADDR             0x100
+#define CODA_REG_BIT_WORK_BUF_ADDR             0x104
+#define CODA_REG_BIT_PARA_BUF_ADDR             0x108
+#define CODA_REG_BIT_STREAM_CTRL               0x10c
+#define                CODA7_STREAM_BUF_PIC_RESET      (1 << 4)
+#define                CODADX6_STREAM_BUF_PIC_RESET    (1 << 3)
+#define                CODA7_STREAM_BUF_PIC_FLUSH      (1 << 3)
+#define                CODADX6_STREAM_BUF_PIC_FLUSH    (1 << 2)
+#define                CODA7_STREAM_BUF_DYNALLOC_EN    (1 << 5)
+#define                CODADX6_STREAM_BUF_DYNALLOC_EN  (1 << 4)
+#define                CODADX6_STREAM_CHKDIS_OFFSET    (1 << 1)
+#define                CODA7_STREAM_SEL_64BITS_ENDIAN  (1 << 1)
+#define                CODA_STREAM_ENDIAN_SELECT       (1 << 0)
+#define CODA_REG_BIT_FRAME_MEM_CTRL            0x110
+#define                CODA_FRAME_CHROMA_INTERLEAVE    (1 << 2)
+#define                CODA_IMAGE_ENDIAN_SELECT        (1 << 0)
+#define CODA_REG_BIT_BIT_STREAM_PARAM          0x114
+#define                CODA_BIT_STREAM_END_FLAG        (1 << 2)
+#define                CODA_BIT_DEC_SEQ_INIT_ESCAPE    (1 << 0)
+#define CODA_REG_BIT_TEMP_BUF_ADDR             0x118
+#define CODA_REG_BIT_RD_PTR(x)                 (0x120 + 8 * (x))
+#define CODA_REG_BIT_WR_PTR(x)                 (0x124 + 8 * (x))
+#define CODA_REG_BIT_FRM_DIS_FLG(x)            (0x150 + 4 * (x))
+#define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR   0x140
+#define CODA7_REG_BIT_AXI_SRAM_USE             0x140
+#define                CODA9_USE_HOST_BTP_ENABLE       (1 << 13)
+#define                CODA9_USE_HOST_OVL_ENABLE       (1 << 12)
+#define                CODA7_USE_HOST_ME_ENABLE        (1 << 11)
+#define                CODA9_USE_HOST_DBK_ENABLE       (3 << 10)
+#define                CODA7_USE_HOST_OVL_ENABLE       (1 << 10)
+#define                CODA7_USE_HOST_DBK_ENABLE       (1 << 9)
+#define                CODA9_USE_HOST_IP_ENABLE        (1 << 9)
+#define                CODA7_USE_HOST_IP_ENABLE        (1 << 8)
+#define                CODA9_USE_HOST_BIT_ENABLE       (1 << 8)
+#define                CODA7_USE_HOST_BIT_ENABLE       (1 << 7)
+#define                CODA9_USE_BTP_ENABLE            (1 << 5)
+#define                CODA7_USE_ME_ENABLE             (1 << 4)
+#define                CODA9_USE_OVL_ENABLE            (1 << 4)
+#define                CODA7_USE_OVL_ENABLE            (1 << 3)
+#define                CODA9_USE_DBK_ENABLE            (3 << 2)
+#define                CODA7_USE_DBK_ENABLE            (1 << 2)
+#define                CODA7_USE_IP_ENABLE             (1 << 1)
+#define                CODA7_USE_BIT_ENABLE            (1 << 0)
+
+#define CODA_REG_BIT_BUSY                      0x160
+#define                CODA_REG_BIT_BUSY_FLAG          1
+#define CODA_REG_BIT_RUN_COMMAND               0x164
+#define                CODA_COMMAND_SEQ_INIT           1
+#define                CODA_COMMAND_SEQ_END            2
+#define                CODA_COMMAND_PIC_RUN            3
+#define                CODA_COMMAND_SET_FRAME_BUF      4
+#define                CODA_COMMAND_ENCODE_HEADER      5
+#define                CODA_COMMAND_ENC_PARA_SET       6
+#define                CODA_COMMAND_DEC_PARA_SET       7
+#define                CODA_COMMAND_DEC_BUF_FLUSH      8
+#define                CODA_COMMAND_RC_CHANGE_PARAMETER 9
+#define                CODA_COMMAND_FIRMWARE_GET       0xf
+#define CODA_REG_BIT_RUN_INDEX                 0x168
+#define                CODA_INDEX_SET(x)               ((x) & 0x3)
+#define CODA_REG_BIT_RUN_COD_STD               0x16c
+#define                CODADX6_MODE_DECODE_MP4         0
+#define                CODADX6_MODE_ENCODE_MP4         1
+#define                CODADX6_MODE_DECODE_H264        2
+#define                CODADX6_MODE_ENCODE_H264        3
+#define                CODA7_MODE_DECODE_H264          0
+#define                CODA7_MODE_DECODE_VC1           1
+#define                CODA7_MODE_DECODE_MP2           2
+#define                CODA7_MODE_DECODE_MP4           3
+#define                CODA7_MODE_DECODE_DV3           3
+#define                CODA7_MODE_DECODE_RV            4
+#define                CODA7_MODE_DECODE_MJPG          5
+#define                CODA7_MODE_ENCODE_H264          8
+#define                CODA7_MODE_ENCODE_MP4           11
+#define                CODA7_MODE_ENCODE_MJPG          13
+#define                CODA9_MODE_DECODE_H264          0
+#define                CODA9_MODE_DECODE_VC1           1
+#define                CODA9_MODE_DECODE_MP2           2
+#define                CODA9_MODE_DECODE_MP4           3
+#define                CODA9_MODE_DECODE_DV3           3
+#define                CODA9_MODE_DECODE_RV            4
+#define                CODA9_MODE_DECODE_AVS           5
+#define                CODA9_MODE_DECODE_MJPG          6
+#define                CODA9_MODE_DECODE_VPX           7
+#define                CODA9_MODE_ENCODE_H264          8
+#define                CODA9_MODE_ENCODE_MP4           11
+#define                CODA9_MODE_ENCODE_MJPG          13
+#define        CODA_MODE_INVALID               0xffff
+#define CODA_REG_BIT_INT_ENABLE                0x170
+#define                CODA_INT_INTERRUPT_ENABLE       (1 << 3)
+#define CODA_REG_BIT_INT_REASON                        0x174
+#define CODA7_REG_BIT_RUN_AUX_STD              0x178
+#define                CODA_MP4_AUX_MPEG4              0
+#define                CODA_MP4_AUX_DIVX3              1
+#define                CODA_VPX_AUX_THO                0
+#define                CODA_VPX_AUX_VP6                1
+#define                CODA_VPX_AUX_VP8                2
+#define                CODA_H264_AUX_AVC               0
+#define                CODA_H264_AUX_MVC               1
+
+/*
+ * Commands' mailbox:
+ * registers with offsets in the range 0x180-0x1d0
+ * have different meaning depending on the command being
+ * issued.
+ */
+
+/* Decoder Sequence Initialization */
+#define CODA_CMD_DEC_SEQ_BB_START              0x180
+#define CODA_CMD_DEC_SEQ_BB_SIZE               0x184
+#define CODA_CMD_DEC_SEQ_OPTION                        0x188
+#define                CODA_REORDER_ENABLE                     (1 << 1)
+#define                CODADX6_QP_REPORT                       (1 << 0)
+#define                CODA7_MP4_DEBLK_ENABLE                  (1 << 0)
+#define CODA_CMD_DEC_SEQ_SRC_SIZE              0x18c
+#define CODA_CMD_DEC_SEQ_START_BYTE            0x190
+#define CODA_CMD_DEC_SEQ_PS_BB_START           0x194
+#define CODA_CMD_DEC_SEQ_PS_BB_SIZE            0x198
+#define CODA_CMD_DEC_SEQ_MP4_ASP_CLASS         0x19c
+#define CODA_CMD_DEC_SEQ_X264_MV_EN            0x19c
+#define CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE                0x1a0
+
+#define CODA7_RET_DEC_SEQ_ASPECT               0x1b0
+#define CODA9_RET_DEC_SEQ_BITRATE              0x1b4
+#define CODA_RET_DEC_SEQ_SUCCESS               0x1c0
+#define CODA_RET_DEC_SEQ_SRC_FMT               0x1c4 /* SRC_SIZE on CODA7 */
+#define CODA_RET_DEC_SEQ_SRC_SIZE              0x1c4
+#define CODA_RET_DEC_SEQ_SRC_F_RATE            0x1c8
+#define CODA9_RET_DEC_SEQ_ASPECT               0x1c8
+#define CODA_RET_DEC_SEQ_FRAME_NEED            0x1cc
+#define CODA_RET_DEC_SEQ_FRAME_DELAY           0x1d0
+#define CODA_RET_DEC_SEQ_INFO                  0x1d4
+#define CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT       0x1d8
+#define CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM       0x1dc
+#define CODA_RET_DEC_SEQ_NEXT_FRAME_NUM                0x1e0
+#define CODA_RET_DEC_SEQ_ERR_REASON            0x1e0
+#define CODA_RET_DEC_SEQ_FRATE_NR              0x1e4
+#define CODA_RET_DEC_SEQ_FRATE_DR              0x1e8
+#define CODA_RET_DEC_SEQ_JPG_PARA              0x1e4
+#define CODA_RET_DEC_SEQ_JPG_THUMB_IND         0x1e8
+#define CODA9_RET_DEC_SEQ_HEADER_REPORT                0x1ec
+
+/* Decoder Picture Run */
+#define CODA_CMD_DEC_PIC_ROT_MODE              0x180
+#define CODA_CMD_DEC_PIC_ROT_ADDR_Y            0x184
+#define CODA9_CMD_DEC_PIC_ROT_INDEX            0x184
+#define CODA_CMD_DEC_PIC_ROT_ADDR_CB           0x188
+#define CODA9_CMD_DEC_PIC_ROT_ADDR_Y           0x188
+#define CODA_CMD_DEC_PIC_ROT_ADDR_CR           0x18c
+#define CODA9_CMD_DEC_PIC_ROT_ADDR_CB          0x18c
+#define CODA_CMD_DEC_PIC_ROT_STRIDE            0x190
+#define CODA9_CMD_DEC_PIC_ROT_ADDR_CR          0x190
+#define CODA9_CMD_DEC_PIC_ROT_STRIDE           0x1b8
+
+#define CODA_CMD_DEC_PIC_OPTION                        0x194
+#define                CODA_PRE_SCAN_EN                        (1 << 0)
+#define                CODA_PRE_SCAN_MODE_DECODE               (0 << 1)
+#define                CODA_PRE_SCAN_MODE_RETURN               (1 << 1)
+#define                CODA_IFRAME_SEARCH_EN                   (1 << 2)
+#define                CODA_SKIP_FRAME_MODE                    (0x3 << 3)
+#define CODA_CMD_DEC_PIC_SKIP_NUM              0x198
+#define CODA_CMD_DEC_PIC_CHUNK_SIZE            0x19c
+#define CODA_CMD_DEC_PIC_BB_START              0x1a0
+#define CODA_CMD_DEC_PIC_START_BYTE            0x1a4
+#define CODA_RET_DEC_PIC_SIZE                  0x1bc
+#define CODA_RET_DEC_PIC_FRAME_NUM             0x1c0
+#define CODA_RET_DEC_PIC_FRAME_IDX             0x1c4
+#define CODA_RET_DEC_PIC_ERR_MB                        0x1c8
+#define CODA_RET_DEC_PIC_TYPE                  0x1cc
+#define                CODA_PIC_TYPE_MASK                      0x7
+#define                CODA_PIC_TYPE_MASK_VC1                  0x3f
+#define                CODA9_PIC_TYPE_FIRST_MASK               (0x7 << 3)
+#define                CODA9_PIC_TYPE_IDR_MASK                 (0x3 << 6)
+#define                CODA7_PIC_TYPE_H264_NPF_MASK            (0x3 << 16)
+#define                CODA7_PIC_TYPE_INTERLACED               (1 << 18)
+#define CODA_RET_DEC_PIC_POST                  0x1d0
+#define CODA_RET_DEC_PIC_MVC_REPORT            0x1d0
+#define CODA_RET_DEC_PIC_OPTION                        0x1d4
+#define CODA_RET_DEC_PIC_SUCCESS               0x1d8
+#define CODA_RET_DEC_PIC_CUR_IDX               0x1dc
+#define CODA_RET_DEC_PIC_CROP_LEFT_RIGHT       0x1e0
+#define CODA_RET_DEC_PIC_CROP_TOP_BOTTOM       0x1e4
+#define CODA_RET_DEC_PIC_FRAME_NEED            0x1ec
+
+#define CODA9_RET_DEC_PIC_VP8_PIC_REPORT       0x1e8
+#define CODA9_RET_DEC_PIC_ASPECT               0x1f0
+#define CODA9_RET_DEC_PIC_VP8_SCALE_INFO       0x1f0
+#define CODA9_RET_DEC_PIC_FRATE_NR             0x1f4
+#define CODA9_RET_DEC_PIC_FRATE_DR             0x1f8
+
+/* Encoder Sequence Initialization */
+#define CODA_CMD_ENC_SEQ_BB_START                              0x180
+#define CODA_CMD_ENC_SEQ_BB_SIZE                               0x184
+#define CODA_CMD_ENC_SEQ_OPTION                                0x188
+#define                CODA7_OPTION_AVCINTRA16X16ONLY_OFFSET           9
+#define                CODA9_OPTION_MVC_PREFIX_NAL_OFFSET              9
+#define                CODA7_OPTION_GAMMA_OFFSET                       8
+#define                CODA9_OPTION_MVC_PARASET_REFRESH_OFFSET         8
+#define                CODA7_OPTION_RCQPMAX_OFFSET                     7
+#define                CODA9_OPTION_GAMMA_OFFSET                       7
+#define                CODADX6_OPTION_GAMMA_OFFSET                     7
+#define                CODA7_OPTION_RCQPMIN_OFFSET                     6
+#define                CODA9_OPTION_RCQPMAX_OFFSET                     6
+#define                CODA_OPTION_LIMITQP_OFFSET                      6
+#define                CODA_OPTION_RCINTRAQP_OFFSET                    5
+#define                CODA_OPTION_FMO_OFFSET                          4
+#define                CODA9_OPTION_MVC_INTERVIEW_OFFSET               4
+#define                CODA_OPTION_AVC_AUD_OFFSET                      2
+#define                CODA_OPTION_SLICEREPORT_OFFSET                  1
+#define CODA_CMD_ENC_SEQ_COD_STD                               0x18c
+#define                CODA_STD_MPEG4                                  0
+#define                CODA9_STD_H264                                  0
+#define                CODA_STD_H263                                   1
+#define                CODA_STD_H264                                   2
+#define                CODA_STD_MJPG                                   3
+#define                CODA9_STD_MPEG4                                 3
+
+#define CODA_CMD_ENC_SEQ_SRC_SIZE                              0x190
+#define                CODA7_PICWIDTH_OFFSET                           16
+#define                CODA7_PICWIDTH_MASK                             0xffff
+#define                CODADX6_PICWIDTH_OFFSET                         10
+#define                CODADX6_PICWIDTH_MASK                           0x3ff
+#define                CODA_PICHEIGHT_OFFSET                           0
+#define                CODADX6_PICHEIGHT_MASK                          0x3ff
+#define                CODA7_PICHEIGHT_MASK                            0xffff
+#define CODA_CMD_ENC_SEQ_SRC_F_RATE                            0x194
+#define CODA_CMD_ENC_SEQ_MP4_PARA                              0x198
+#define                CODA_MP4PARAM_VERID_OFFSET                      6
+#define                CODA_MP4PARAM_VERID_MASK                        0x01
+#define                CODA_MP4PARAM_INTRADCVLCTHR_OFFSET              2
+#define                CODA_MP4PARAM_INTRADCVLCTHR_MASK                0x07
+#define                CODA_MP4PARAM_REVERSIBLEVLCENABLE_OFFSET        1
+#define                CODA_MP4PARAM_REVERSIBLEVLCENABLE_MASK          0x01
+#define                CODA_MP4PARAM_DATAPARTITIONENABLE_OFFSET        0
+#define                CODA_MP4PARAM_DATAPARTITIONENABLE_MASK          0x01
+#define CODA_CMD_ENC_SEQ_263_PARA                              0x19c
+#define                CODA_263PARAM_ANNEXJENABLE_OFFSET               2
+#define                CODA_263PARAM_ANNEXJENABLE_MASK         0x01
+#define                CODA_263PARAM_ANNEXKENABLE_OFFSET               1
+#define                CODA_263PARAM_ANNEXKENABLE_MASK         0x01
+#define                CODA_263PARAM_ANNEXTENABLE_OFFSET               0
+#define                CODA_263PARAM_ANNEXTENABLE_MASK         0x01
+#define CODA_CMD_ENC_SEQ_264_PARA                              0x1a0
+#define                CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET      12
+#define                CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK        0x0f
+#define                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET     8
+#define                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK       0x0f
+#define                CODA_264PARAM_DISABLEDEBLK_OFFSET               6
+#define                CODA_264PARAM_DISABLEDEBLK_MASK         0x01
+#define                CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET   5
+#define                CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK     0x01
+#define                CODA_264PARAM_CHROMAQPOFFSET_OFFSET             0
+#define                CODA_264PARAM_CHROMAQPOFFSET_MASK               0x1f
+#define CODA_CMD_ENC_SEQ_SLICE_MODE                            0x1a4
+#define                CODA_SLICING_SIZE_OFFSET                        2
+#define                CODA_SLICING_SIZE_MASK                          0x3fffffff
+#define                CODA_SLICING_UNIT_OFFSET                        1
+#define                CODA_SLICING_UNIT_MASK                          0x01
+#define                CODA_SLICING_MODE_OFFSET                        0
+#define                CODA_SLICING_MODE_MASK                          0x01
+#define CODA_CMD_ENC_SEQ_GOP_SIZE                              0x1a8
+#define                CODA_GOP_SIZE_OFFSET                            0
+#define                CODA_GOP_SIZE_MASK                              0x3f
+#define CODA_CMD_ENC_SEQ_RC_PARA                               0x1ac
+#define                CODA_RATECONTROL_AUTOSKIP_OFFSET                31
+#define                CODA_RATECONTROL_AUTOSKIP_MASK                  0x01
+#define                CODA_RATECONTROL_INITIALDELAY_OFFSET            16
+#define                CODA_RATECONTROL_INITIALDELAY_MASK              0x7f
+#define                CODA_RATECONTROL_BITRATE_OFFSET         1
+#define                CODA_RATECONTROL_BITRATE_MASK                   0x7f
+#define                CODA_RATECONTROL_ENABLE_OFFSET                  0
+#define                CODA_RATECONTROL_ENABLE_MASK                    0x01
+#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE                           0x1b0
+#define CODA_CMD_ENC_SEQ_INTRA_REFRESH                         0x1b4
+#define CODADX6_CMD_ENC_SEQ_FMO                                        0x1b8
+#define                CODA_FMOPARAM_TYPE_OFFSET                       4
+#define                CODA_FMOPARAM_TYPE_MASK                         1
+#define                CODA_FMOPARAM_SLICENUM_OFFSET                   0
+#define                CODA_FMOPARAM_SLICENUM_MASK                     0x0f
+#define CODADX6_CMD_ENC_SEQ_INTRA_QP                           0x1bc
+#define CODA7_CMD_ENC_SEQ_SEARCH_BASE                          0x1b8
+#define CODA7_CMD_ENC_SEQ_SEARCH_SIZE                          0x1bc
+#define CODA7_CMD_ENC_SEQ_INTRA_QP                             0x1c4
+#define CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX                         0x1c8
+#define                CODA_QPMIN_OFFSET                               8
+#define                CODA_QPMIN_MASK                                 0x3f
+#define                CODA_QPMAX_OFFSET                               0
+#define                CODA_QPMAX_MASK                                 0x3f
+#define CODA_CMD_ENC_SEQ_RC_GAMMA                              0x1cc
+#define                CODA_GAMMA_OFFSET                               0
+#define                CODA_GAMMA_MASK                                 0xffff
+#define CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE                      0x1d0
+#define CODA9_CMD_ENC_SEQ_INTRA_WEIGHT                         0x1d4
+#define CODA9_CMD_ENC_SEQ_ME_OPTION                            0x1d8
+#define CODA_RET_ENC_SEQ_SUCCESS                               0x1c0
+
+/* Encoder Picture Run */
+#define CODA9_CMD_ENC_PIC_SRC_INDEX            0x180
+#define CODA9_CMD_ENC_PIC_SRC_STRIDE           0x184
+#define CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC       0x1a4
+#define CODA9_CMD_ENC_PIC_SRC_ADDR_Y           0x1a8
+#define CODA9_CMD_ENC_PIC_SRC_ADDR_CB          0x1ac
+#define CODA9_CMD_ENC_PIC_SRC_ADDR_CR          0x1b0
+#define CODA_CMD_ENC_PIC_SRC_ADDR_Y    0x180
+#define CODA_CMD_ENC_PIC_SRC_ADDR_CB   0x184
+#define CODA_CMD_ENC_PIC_SRC_ADDR_CR   0x188
+#define CODA_CMD_ENC_PIC_QS            0x18c
+#define CODA_CMD_ENC_PIC_ROT_MODE      0x190
+#define                CODA_ROT_MIR_ENABLE                             (1 << 4)
+#define                CODA_ROT_0                                      (0x0 << 0)
+#define                CODA_ROT_90                                     (0x1 << 0)
+#define                CODA_ROT_180                                    (0x2 << 0)
+#define                CODA_ROT_270                                    (0x3 << 0)
+#define                CODA_MIR_NONE                                   (0x0 << 2)
+#define                CODA_MIR_VER                                    (0x1 << 2)
+#define                CODA_MIR_HOR                                    (0x2 << 2)
+#define                CODA_MIR_VER_HOR                                (0x3 << 2)
+#define CODA_CMD_ENC_PIC_OPTION                0x194
+#define                CODA_FORCE_IPICTURE                             BIT(1)
+#define                CODA_REPORT_MB_INFO                             BIT(3)
+#define                CODA_REPORT_MV_INFO                             BIT(4)
+#define                CODA_REPORT_SLICE_INFO                          BIT(5)
+#define CODA_CMD_ENC_PIC_BB_START      0x198
+#define CODA_CMD_ENC_PIC_BB_SIZE       0x19c
+#define CODA_RET_ENC_FRAME_NUM         0x1c0
+#define CODA_RET_ENC_PIC_TYPE          0x1c4
+#define CODA_RET_ENC_PIC_FRAME_IDX     0x1c8
+#define CODA_RET_ENC_PIC_SLICE_NUM     0x1cc
+#define CODA_RET_ENC_PIC_FLAG          0x1d0
+#define CODA_RET_ENC_PIC_SUCCESS       0x1d8
+
+/* Set Frame Buffer */
+#define CODA_CMD_SET_FRAME_BUF_NUM             0x180
+#define CODA_CMD_SET_FRAME_BUF_STRIDE          0x184
+#define CODA_CMD_SET_FRAME_SLICE_BB_START      0x188
+#define CODA_CMD_SET_FRAME_SLICE_BB_SIZE       0x18c
+#define CODA9_CMD_SET_FRAME_SUBSAMP_A          0x188
+#define CODA9_CMD_SET_FRAME_SUBSAMP_B          0x18c
+#define CODA7_CMD_SET_FRAME_AXI_BIT_ADDR       0x190
+#define CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR    0x194
+#define CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR      0x198
+#define CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR      0x19c
+#define CODA7_CMD_SET_FRAME_AXI_OVL_ADDR       0x1a0
+#define CODA7_CMD_SET_FRAME_MAX_DEC_SIZE       0x1a4
+#define CODA9_CMD_SET_FRAME_AXI_BTP_ADDR       0x1a4
+#define CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE  0x1a8
+#define CODA9_CMD_SET_FRAME_CACHE_SIZE         0x1a8
+#define CODA9_CMD_SET_FRAME_CACHE_CONFIG       0x1ac
+#define                CODA9_CACHE_BYPASS_OFFSET               28
+#define                CODA9_CACHE_DUALCONF_OFFSET             26
+#define                CODA9_CACHE_PAGEMERGE_OFFSET            24
+#define                CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET     16
+#define                CODA9_CACHE_CB_BUFFER_SIZE_OFFSET       8
+#define                CODA9_CACHE_CR_BUFFER_SIZE_OFFSET       0
+#define CODA9_CMD_SET_FRAME_SUBSAMP_A_MVC      0x1b0
+#define CODA9_CMD_SET_FRAME_SUBSAMP_B_MVC      0x1b4
+#define CODA9_CMD_SET_FRAME_DP_BUF_BASE                0x1b0
+#define CODA9_CMD_SET_FRAME_DP_BUF_SIZE                0x1b4
+#define CODA9_CMD_SET_FRAME_MAX_DEC_SIZE       0x1b8
+#define CODA9_CMD_SET_FRAME_DELAY              0x1bc
+
+/* Encoder Header */
+#define CODA_CMD_ENC_HEADER_CODE       0x180
+#define                CODA_GAMMA_OFFSET       0
+#define                CODA_HEADER_H264_SPS    0
+#define                CODA_HEADER_H264_PPS    1
+#define                CODA_HEADER_MP4V_VOL    0
+#define                CODA_HEADER_MP4V_VOS    1
+#define                CODA_HEADER_MP4V_VIS    2
+#define                CODA9_HEADER_FRAME_CROP (1 << 3)
+#define CODA_CMD_ENC_HEADER_BB_START   0x184
+#define CODA_CMD_ENC_HEADER_BB_SIZE    0x188
+#define CODA9_CMD_ENC_HEADER_FRAME_CROP_H      0x18c
+#define CODA9_CMD_ENC_HEADER_FRAME_CROP_V      0x190
+
+/* Get Version */
+#define CODA_CMD_FIRMWARE_VERNUM               0x1c0
+#define                CODA_FIRMWARE_PRODUCT(x)        (((x) >> 16) & 0xffff)
+#define                CODA_FIRMWARE_MAJOR(x)          (((x) >> 12) & 0x0f)
+#define                CODA_FIRMWARE_MINOR(x)          (((x) >> 8) & 0x0f)
+#define                CODA_FIRMWARE_RELEASE(x)        ((x) & 0xff)
+#define                CODA_FIRMWARE_VERNUM(product, major, minor, release)    \
+                       ((product) << 16 | ((major) << 12) |            \
+                       ((minor) << 8) | (release))
+#define CODA9_CMD_FIRMWARE_CODE_REV            0x1c4
+
+#define CODA9_GDMA_BASE                                0x1000
+#define CODA9_GDI_WPROT_ERR_CLR                        (CODA9_GDMA_BASE + 0x0a0)
+#define CODA9_GDI_WPROT_RGN_EN                 (CODA9_GDMA_BASE + 0x0ac)
+
+#define CODA9_GDI_BUS_CTRL                     (CODA9_GDMA_BASE + 0x0f0)
+#define CODA9_GDI_BUS_STATUS                   (CODA9_GDMA_BASE + 0x0f4)
+
+#define CODA9_GDI_XY2_CAS_0                    (CODA9_GDMA_BASE + 0x800)
+#define CODA9_GDI_XY2_CAS_F                    (CODA9_GDMA_BASE + 0x83c)
+
+#define CODA9_GDI_XY2_BA_0                     (CODA9_GDMA_BASE + 0x840)
+#define CODA9_GDI_XY2_BA_1                     (CODA9_GDMA_BASE + 0x844)
+#define CODA9_GDI_XY2_BA_2                     (CODA9_GDMA_BASE + 0x848)
+#define CODA9_GDI_XY2_BA_3                     (CODA9_GDMA_BASE + 0x84c)
+
+#define CODA9_GDI_XY2_RAS_0                    (CODA9_GDMA_BASE + 0x850)
+#define CODA9_GDI_XY2_RAS_F                    (CODA9_GDMA_BASE + 0x88c)
+
+#define CODA9_GDI_XY2_RBC_CONFIG               (CODA9_GDMA_BASE + 0x890)
+#define CODA9_GDI_RBC2_AXI_0                   (CODA9_GDMA_BASE + 0x8a0)
+#define CODA9_GDI_RBC2_AXI_1F                  (CODA9_GDMA_BASE + 0x91c)
+
+#endif
index afb3aec1320e8262351a31cf1efe6f7fcbe695be..d9e1ddb586b190e99da9cd0b97f60163549e655c 100644 (file)
@@ -1,6 +1,8 @@
 config VIDEO_DAVINCI_VPIF_DISPLAY
        tristate "TI DaVinci VPIF V4L2-Display driver"
-       depends on VIDEO_DEV && ARCH_DAVINCI
+       depends on VIDEO_DEV
+       depends on ARCH_DAVINCI || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT
        select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT
@@ -14,7 +16,9 @@ config VIDEO_DAVINCI_VPIF_DISPLAY
 
 config VIDEO_DAVINCI_VPIF_CAPTURE
        tristate "TI DaVinci VPIF video capture driver"
-       depends on VIDEO_DEV && ARCH_DAVINCI
+       depends on VIDEO_DEV
+       depends on ARCH_DAVINCI || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        help
          Enables Davinci VPIF module used for capture devices.
@@ -26,7 +30,9 @@ config VIDEO_DAVINCI_VPIF_CAPTURE
 
 config VIDEO_DM6446_CCDC
        tristate "TI DM6446 CCDC video capture driver"
-       depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
+       depends on VIDEO_V4L2
+       depends on ARCH_DAVINCI || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF_DMA_CONTIG
        help
           Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
@@ -40,7 +46,9 @@ config VIDEO_DM6446_CCDC
 
 config VIDEO_DM355_CCDC
        tristate "TI DM355 CCDC video capture driver"
-       depends on VIDEO_V4L2 && ARCH_DAVINCI
+       depends on VIDEO_V4L2
+       depends on ARCH_DAVINCI || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF_DMA_CONTIG
        help
           Enables DM355 CCD hw module. DM355 CCDC hw interfaces
@@ -55,6 +63,7 @@ config VIDEO_DM355_CCDC
 config VIDEO_DM365_ISIF
        tristate "TI DM365 ISIF video capture driver"
        depends on VIDEO_V4L2 && ARCH_DAVINCI
+       depends on HAS_DMA
        select VIDEOBUF_DMA_CONTIG
        help
           Enables ISIF hw module. This is the hardware module for
@@ -67,6 +76,7 @@ config VIDEO_DM365_ISIF
 config VIDEO_DAVINCI_VPBE_DISPLAY
        tristate "TI DaVinci VPBE V4L2-Display driver"
        depends on ARCH_DAVINCI
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        help
            Enables Davinci VPBE module used for display devices.
index 05f8fb7f7b70a335c89eade3925fca309a79ab5d..3f44deb5b7a76182ad7d637340f989e618ee5a30 100644 (file)
@@ -460,7 +460,7 @@ static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
  * ccdc_write_dfc_entry()
  * write an entry in the dfc table.
  */
-int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
+static int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
 {
 /* TODO This is to be re-visited and adjusted */
 #define DFC_WRITE_WAIT_COUNT   1000
index 07e98df3d86797710dda4b1555dedf84e461f9e2..62a0ebb01056cf867d1400132379dfe0c275ec4f 100644 (file)
@@ -130,9 +130,9 @@ static void ccdc_enable_vport(int flag)
  * This function will configure the window size
  * to be capture in CCDC reg
  */
-void ccdc_setwin(struct v4l2_rect *image_win,
-               enum ccdc_frmfmt frm_fmt,
-               int ppc)
+static void ccdc_setwin(struct v4l2_rect *image_win,
+                       enum ccdc_frmfmt frm_fmt,
+                       int ppc)
 {
        int horz_start, horz_nr_pixels;
        int vert_start, vert_nr_lines;
@@ -291,7 +291,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
                dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed");
                return -EFAULT;
        }
-       config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr;
+       config_params->fault_pxl.fpc_table_addr = (unsigned long)fpc_physaddr;
        return 0;
 }
 
@@ -370,7 +370,7 @@ static int ccdc_set_params(void __user *params)
  * ccdc_config_ycbcr()
  * This function will configure CCDC for YCbCr video capture
  */
-void ccdc_config_ycbcr(void)
+static void ccdc_config_ycbcr(void)
 {
        struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
        u32 syn_mode;
@@ -506,7 +506,7 @@ static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
 
        /* Configure Fault pixel if needed */
        regw(fpc->fpc_table_addr, CCDC_FPC_ADDR);
-       dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n",
+       dev_dbg(ccdc_cfg.dev, "\nWriting 0x%lx to FPC_ADDR...\n",
                       (fpc->fpc_table_addr));
        /* Write the FPC params with FPC disable */
        val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK;
@@ -523,7 +523,7 @@ static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
  * ccdc_config_raw()
  * This function will configure CCDC for Raw capture mode
  */
-void ccdc_config_raw(void)
+static void ccdc_config_raw(void)
 {
        struct ccdc_params_raw *params = &ccdc_cfg.bayer;
        struct ccdc_config_params_raw *config_params =
index ea7661a27479f4ef7cc7580b4e9fd11db7aceb9e..de55f47a77dba1b3bcd90196ed86392fc3fcdf11 100644 (file)
@@ -125,7 +125,7 @@ static DEFINE_MUTEX(ccdc_lock);
 /* ccdc configuration */
 static struct ccdc_config *ccdc_cfg;
 
-const struct vpfe_standard vpfe_standards[] = {
+static const struct vpfe_standard vpfe_standards[] = {
        {V4L2_STD_525_60, 720, 480, {11, 10}, 1},
        {V4L2_STD_625_50, 720, 576, {54, 59}, 1},
 };
@@ -442,11 +442,10 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
                return ret;
 
        /* Update the values of sizeimage and bytesperline */
-       if (!ret) {
-               pix->bytesperline = ccdc_dev->hw_ops.get_line_length();
-               pix->sizeimage = pix->bytesperline * pix->height;
-       }
-       return ret;
+       pix->bytesperline = ccdc_dev->hw_ops.get_line_length();
+       pix->sizeimage = pix->bytesperline * pix->height;
+
+       return 0;
 }
 
 static int vpfe_initialize_device(struct vpfe_device *vpfe_dev)
@@ -943,12 +942,11 @@ static int vpfe_g_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *fmt)
 {
        struct vpfe_device *vpfe_dev = video_drvdata(file);
-       int ret = 0;
 
        v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n");
        /* Fill in the information about format */
        *fmt = vpfe_dev->fmt;
-       return ret;
+       return 0;
 }
 
 static int vpfe_enum_fmt_vid_cap(struct file *file, void  *priv,
@@ -1914,7 +1912,7 @@ static int vpfe_probe(struct platform_device *pdev)
        v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
                "trying to register vpfe device.\n");
        v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
-               "video_dev=%x\n", (int)&vpfe_dev->video_dev);
+               "video_dev=%p\n", &vpfe_dev->video_dev);
        vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        ret = video_register_device(vpfe_dev->video_dev,
                                    VFL_TYPE_GRABBER, -1);
index cd08e5248387038f333eee4726775b139988973b..3dad5bd7fe0a8aaad40bdf17b2ac9f6c776d9b44 100644 (file)
@@ -38,6 +38,7 @@ MODULE_LICENSE("GPL");
 #define VPIF_CH3_MAX_MODES     2
 
 spinlock_t vpif_lock;
+EXPORT_SYMBOL_GPL(vpif_lock);
 
 void __iomem *vpif_base;
 EXPORT_SYMBOL_GPL(vpif_base);
index b054b7eec53dc5a98dd43ba02dd8e343bbc19005..3ccb26ff43c8dfa31935c3f8f1eed6dee126c3c5 100644 (file)
@@ -213,8 +213,6 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
        /* Remove buffer from the buffer queue */
        list_del(&common->cur_frm->list);
        spin_unlock_irqrestore(&common->irqlock, flags);
-       /* Mark state of the current frame to active */
-       common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
 
        addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
 
@@ -350,7 +348,6 @@ static void vpif_schedule_next_buffer(struct common_obj *common)
        /* Remove that buffer from the buffer queue */
        list_del(&common->next_frm->list);
        spin_unlock(&common->irqlock);
-       common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
        addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
 
        /* Set top and bottom field addresses in VPIF registers */
@@ -373,7 +370,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
        struct vpif_device *dev = &vpif_obj;
        struct common_obj *common;
        struct channel_obj *ch;
-       enum v4l2_field field;
        int channel_id = 0;
        int fid = -1, i;
 
@@ -383,8 +379,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
 
        ch = dev->dev[channel_id];
 
-       field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
-
        for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) {
                common = &ch->common[i];
                /* skip If streaming is not started in this channel */
@@ -533,7 +527,7 @@ static int vpif_update_std_info(struct channel_obj *ch)
  */
 static void vpif_calculate_offsets(struct channel_obj *ch)
 {
-       unsigned int hpitch, vpitch, sizeimage;
+       unsigned int hpitch, sizeimage;
        struct video_obj *vid_ch = &(ch->video);
        struct vpif_params *vpifparams = &ch->vpifparams;
        struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
@@ -552,7 +546,6 @@ static void vpif_calculate_offsets(struct channel_obj *ch)
        sizeimage = common->fmt.fmt.pix.sizeimage;
 
        hpitch = common->fmt.fmt.pix.bytesperline;
-       vpitch = sizeimage / (hpitch * 2);
 
        if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
            (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
@@ -1603,7 +1596,7 @@ static int vpif_suspend(struct device *dev)
                ch = vpif_obj.dev[i];
                common = &ch->common[VPIF_VIDEO_INDEX];
 
-               if (!vb2_is_streaming(&common->buffer_queue))
+               if (!vb2_start_streaming_called(&common->buffer_queue))
                        continue;
 
                mutex_lock(&common->lock);
@@ -1637,7 +1630,7 @@ static int vpif_resume(struct device *dev)
                ch = vpif_obj.dev[i];
                common = &ch->common[VPIF_VIDEO_INDEX];
 
-               if (!vb2_is_streaming(&common->buffer_queue))
+               if (!vb2_start_streaming_called(&common->buffer_queue))
                        continue;
 
                mutex_lock(&common->lock);
index a03ec7381cfef734da18537f822e34ed959af55f..8d6ced56253c1f9fba99230fdd871f63d5cb0832 100644 (file)
@@ -196,8 +196,6 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
 
        list_del(&common->cur_frm->list);
        spin_unlock_irqrestore(&common->irqlock, flags);
-       /* Mark state of the current frame to active */
-       common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
 
        addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
        common->set_addr((addr + common->ytop_off),
@@ -306,8 +304,6 @@ static void process_progressive_mode(struct common_obj *common)
        /* Remove that buffer from the buffer queue */
        list_del(&common->next_frm->list);
        spin_unlock(&common->irqlock);
-       /* Mark status of the buffer as active */
-       common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
 
        /* Set top and bottom field addrs in VPIF registers */
        addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
@@ -360,7 +356,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
        struct vpif_device *dev = &vpif_obj;
        struct channel_obj *ch;
        struct common_obj *common;
-       enum v4l2_field field;
        int fid = -1, i;
        int channel_id = 0;
 
@@ -369,7 +364,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
                return IRQ_NONE;
 
        ch = dev->dev[channel_id];
-       field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
        for (i = 0; i < VPIF_NUMOBJECTS; i++) {
                common = &ch->common[i];
                /* If streaming is started in this channel */
@@ -502,7 +496,7 @@ static void vpif_calculate_offsets(struct channel_obj *ch)
        struct vpif_params *vpifparams = &ch->vpifparams;
        enum v4l2_field field = common->fmt.fmt.pix.field;
        struct video_obj *vid_ch = &ch->video;
-       unsigned int hpitch, vpitch, sizeimage;
+       unsigned int hpitch, sizeimage;
 
        if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) {
                if (ch->vpifparams.std_info.frm_fmt)
@@ -516,7 +510,6 @@ static void vpif_calculate_offsets(struct channel_obj *ch)
        sizeimage = common->fmt.fmt.pix.sizeimage;
 
        hpitch = common->fmt.fmt.pix.bytesperline;
-       vpitch = sizeimage / (hpitch * 2);
        if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
            (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
                common->ytop_off = 0;
@@ -813,17 +806,14 @@ static int vpif_set_output(struct vpif_display_config *vpif_cfg,
 {
        struct vpif_display_chan_config *chan_cfg =
                &vpif_cfg->chan_config[ch->channel_id];
-       struct vpif_subdev_info *subdev_info = NULL;
        struct v4l2_subdev *sd = NULL;
        u32 input = 0, output = 0;
        int sd_index;
        int ret;
 
        sd_index = vpif_output_to_subdev(vpif_cfg, chan_cfg, index);
-       if (sd_index >= 0) {
+       if (sd_index >= 0)
                sd = vpif_obj.sd[sd_index];
-               subdev_info = &vpif_cfg->subdevinfo[sd_index];
-       }
 
        if (sd) {
                input = chan_cfg->outputs[index].input_route;
@@ -1210,8 +1200,8 @@ static int vpif_probe_complete(void)
                INIT_LIST_HEAD(&common->dma_queue);
 
                /* register video device */
-               vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
-                        (int)ch, (int)&ch->video_dev);
+               vpif_dbg(1, debug, "channel=%p,channel->video_dev=%p\n",
+                        ch, &ch->video_dev);
 
                /* Initialize the video_device structure */
                vdev = ch->video_dev;
@@ -1410,7 +1400,7 @@ static int vpif_suspend(struct device *dev)
                ch = vpif_obj.dev[i];
                common = &ch->common[VPIF_VIDEO_INDEX];
 
-               if (!vb2_is_streaming(&common->buffer_queue))
+               if (!vb2_start_streaming_called(&common->buffer_queue))
                        continue;
 
                mutex_lock(&common->lock);
@@ -1442,7 +1432,7 @@ static int vpif_resume(struct device *dev)
                ch = vpif_obj.dev[i];
                common = &ch->common[VPIF_VIDEO_INDEX];
 
-               if (!vb2_is_streaming(&common->buffer_queue))
+               if (!vb2_start_streaming_called(&common->buffer_queue))
                        continue;
 
                mutex_lock(&common->lock);
index 9d0cc04d7ab7ee1ffc2e41db4bb14436f9c15e80..b4c9f1d089684f316215803018541a47d0f4270b 100644 (file)
@@ -852,8 +852,8 @@ int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
                (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
                swap(addr->cb, addr->cr);
 
-       pr_debug("ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
-               addr->y, addr->cb, addr->cr, ret);
+       pr_debug("ADDR: y= %pad  cb= %pad cr= %pad ret= %d",
+               &addr->y, &addr->cb, &addr->cr, ret);
 
        return ret;
 }
@@ -1086,7 +1086,7 @@ static int gsc_probe(struct platform_device *pdev)
        else
                gsc->id = pdev->id;
 
-       if (gsc->id < 0 || gsc->id >= drv_data->num_entities) {
+       if (gsc->id >= drv_data->num_entities) {
                dev_err(dev, "Invalid platform device id: %d\n", gsc->id);
                return -EINVAL;
        }
index e434f1f03d7b3a4458e0543923d9189b2992b8a3..74e1de637e8f65fdb0f8b784e8e24e63374fd43a 100644 (file)
@@ -362,7 +362,6 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh,
 {
        struct gsc_ctx *ctx = fh_to_ctx(fh);
        struct gsc_dev *gsc = ctx->gsc_dev;
-       struct gsc_frame *frame;
        u32 max_cnt;
 
        max_cnt = (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
@@ -376,8 +375,6 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh,
                        gsc_ctx_state_lock_clear(GSC_DST_FMT, ctx);
        }
 
-       frame = ctx_get_frame(ctx, reqbufs->type);
-
        return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
 }
 
index e22d147a6940fee9969fe3ebcabf3ed6b701900c..ce12a11005115e1196244de742b41740d9040200 100644 (file)
@@ -90,8 +90,8 @@ void gsc_hw_set_output_buf_masking(struct gsc_dev *dev, u32 shift,
 void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,
                                int index)
 {
-       pr_debug("src_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", index,
-                       addr->y, addr->cb, addr->cr);
+       pr_debug("src_buf[%d]: %pad, cb: %pad, cr: %pad", index,
+                       &addr->y, &addr->cb, &addr->cr);
        writel(addr->y, dev->regs + GSC_IN_BASE_ADDR_Y(index));
        writel(addr->cb, dev->regs + GSC_IN_BASE_ADDR_CB(index));
        writel(addr->cr, dev->regs + GSC_IN_BASE_ADDR_CR(index));
@@ -101,8 +101,8 @@ void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,
 void gsc_hw_set_output_addr(struct gsc_dev *dev,
                             struct gsc_addr *addr, int index)
 {
-       pr_debug("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
-                       index, addr->y, addr->cb, addr->cr);
+       pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad",
+                       index, &addr->y, &addr->cb, &addr->cr);
        writel(addr->y, dev->regs + GSC_OUT_BASE_ADDR_Y(index));
        writel(addr->cb, dev->regs + GSC_OUT_BASE_ADDR_CB(index));
        writel(addr->cr, dev->regs + GSC_OUT_BASE_ADDR_CR(index));
index 5dcaa0a805403c5e23372ee12bf3af06e49d35b7..77c95123774409ac491d45d8db465fdb9c72360b 100644 (file)
@@ -2,7 +2,7 @@
 config VIDEO_SAMSUNG_EXYNOS4_IS
        bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver"
        depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
-       depends on (PLAT_S5P || ARCH_EXYNOS)
+       depends on (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST)
        depends on OF && COMMON_CLK
        help
          Say Y here to enable camera host interface devices for
@@ -16,6 +16,7 @@ config VIDEO_EXYNOS4_IS_COMMON
 config VIDEO_S5P_FIMC
        tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver"
        depends on I2C
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        select MFD_SYSCON
@@ -43,6 +44,7 @@ if SOC_EXYNOS4212 || SOC_EXYNOS4412 || SOC_EXYNOS5250
 config VIDEO_EXYNOS_FIMC_LITE
        tristate "EXYNOS FIMC-LITE camera interface driver"
        depends on I2C
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select VIDEO_EXYNOS4_IS_COMMON
        help
@@ -55,6 +57,7 @@ endif
 
 config VIDEO_EXYNOS4_FIMC_IS
        tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver"
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        depends on OF
        select FW_LOADER
index e8519e151c1ac0bca0391c51dafde78bbcebcd87..e050e63fe358683c61e1c0c0e00e21e5e25f41d5 100644 (file)
@@ -15,7 +15,7 @@
 
 #include "fimc-is-errno.h"
 
-const char * const fimc_is_param_strerr(unsigned int error)
+const char *fimc_is_param_strerr(unsigned int error)
 {
        switch (error) {
        case ERROR_COMMON_CMD:
@@ -146,7 +146,7 @@ const char * const fimc_is_param_strerr(unsigned int error)
        }
 }
 
-const char * const fimc_is_strerr(unsigned int error)
+const char *fimc_is_strerr(unsigned int error)
 {
        error &= ~IS_ERROR_TIME_OUT_FLAG;
 
index 3de6f6da6f87058e9c0bc8e12a6658b8764d96b7..ef981e74513a9f5f60df574e1045627915b3f0be 100644 (file)
@@ -242,7 +242,7 @@ enum fimc_is_error {
        ERROR_SCALER_FLIP                               = 521,
 };
 
-const char * const fimc_is_strerr(unsigned int error);
-const char * const fimc_is_param_strerr(unsigned int error);
+const char *fimc_is_strerr(unsigned int error);
+const char *fimc_is_param_strerr(unsigned int error);
 
 #endif /* FIMC_IS_ERR_H_ */
index bf1465d1bf6d709b266862bef57b61b257f22bfc..72b9b436c5c0a149601f9caa9d53d95e53084a74 100644 (file)
@@ -667,7 +667,6 @@ void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val)
 void fimc_is_set_initial_params(struct fimc_is *is)
 {
        struct global_param *global;
-       struct sensor_param *sensor;
        struct isp_param *isp;
        struct drc_param *drc;
        struct fd_param *fd;
@@ -676,7 +675,6 @@ void fimc_is_set_initial_params(struct fimc_is *is)
 
        index = is->config_index;
        global = &is->config[index].global;
-       sensor = &is->config[index].sensor;
        isp = &is->config[index].isp;
        drc = &is->config[index].drc;
        fd = &is->config[index].fd;
index 5476dce3ad293716fc940b130d1cf9f4aaa219c5..22162b2567dae446947dce4e7193cff9cfbb0940 100644 (file)
@@ -388,7 +388,7 @@ static void fimc_is_load_firmware(const struct firmware *fw, void *context)
        mutex_lock(&is->lock);
 
        if (fw->size < FIMC_IS_FW_SIZE_MIN || fw->size > FIMC_IS_FW_SIZE_MAX) {
-               dev_err(dev, "wrong firmware size: %d\n", fw->size);
+               dev_err(dev, "wrong firmware size: %zu\n", fw->size);
                goto done;
        }
 
@@ -416,7 +416,7 @@ static void fimc_is_load_firmware(const struct firmware *fw, void *context)
 
        dev_info(dev, "loaded firmware: %s, rev. %s\n",
                 is->fw.info, is->fw.version);
-       dev_dbg(dev, "FW size: %d, paddr: %#x\n", fw->size, is->memory.paddr);
+       dev_dbg(dev, "FW size: %zu, paddr: %pad\n", fw->size, &is->memory.paddr);
 
        is->is_shared_region->chip_id = 0xe4412;
        is->is_shared_region->chip_rev_no = 1;
@@ -693,9 +693,9 @@ int fimc_is_hw_initialize(struct fimc_is *is)
                return -EIO;
        }
 
-       pr_debug("shared region: %#x, parameter region: %#x\n",
-                is->memory.paddr + FIMC_IS_SHARED_REGION_OFFSET,
-                is->is_dma_p_region);
+       pr_debug("shared region: %pad, parameter region: %pad\n",
+                &is->memory.paddr + FIMC_IS_SHARED_REGION_OFFSET,
+                &is->is_dma_p_region);
 
        is->setfile.sub_index = 0;
 
index 93f9cf2ebcd67293d5565c9900b37f949e86c4be..76b6b4d146169824593170c08f79a89a2b18c06f 100644 (file)
@@ -219,9 +219,9 @@ static void isp_video_capture_buffer_queue(struct vb2_buffer *vb)
                                                        ivb->dma_addr[i];
 
                        isp_dbg(2, &video->ve.vdev,
-                               "dma_buf %d (%d/%d/%d) addr: %#x\n",
-                               buf_index, ivb->index, i, vb->v4l2_buf.index,
-                               ivb->dma_addr[i]);
+                               "dma_buf %pad (%d/%d/%d) addr: %pad\n",
+                               &buf_index, ivb->index, i, vb->v4l2_buf.index,
+                               &ivb->dma_addr[i]);
                }
 
                if (++video->buf_count < video->reqbufs_count)
@@ -313,7 +313,6 @@ static int isp_video_release(struct file *file)
        struct fimc_is_video *ivc = &isp->video_capture;
        struct media_entity *entity = &ivc->ve.vdev.entity;
        struct media_device *mdev = entity->parent;
-       int ret = 0;
 
        mutex_lock(&isp->video_lock);
 
@@ -335,7 +334,7 @@ static int isp_video_release(struct file *file)
        pm_runtime_put(&isp->pdev->dev);
        mutex_unlock(&isp->video_lock);
 
-       return ret;
+       return 0;
 }
 
 static const struct v4l2_file_operations isp_video_fops = {
index 344718df5c62885866d8c6ec0953163c7d99c60a..54c49d5e769021fa4036b2efe5dd02b9805ada5c 100644 (file)
@@ -1098,8 +1098,10 @@ static int fimc_md_link_notify(struct media_link *link, unsigned int flags,
        if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) {
                if (!(flags & MEDIA_LNK_FL_ENABLED))
                        ret = __fimc_md_modify_pipelines(sink, false);
+#if 0
                else
-                       ; /* TODO: Link state change validation */
+                       /* TODO: Link state change validation */
+#endif
        /* After link activation */
        } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
                   (link->flags & MEDIA_LNK_FL_ENABLED)) {
index ae54ef5f535d9c105f643d76e3f78c72ee341095..db6fd14d19366b6a43f89bc363a7586783dd55f7 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/videodev2.h>
@@ -752,7 +753,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
        v4l2_of_parse_endpoint(node, &endpoint);
 
        state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0;
-       if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES)
+       if (state->index >= CSIS_MAX_ENTITIES)
                return -ENXIO;
 
        /* Get MIPI CSI-2 bus configration from the endpoint node. */
index bf739e3b33984c0ef36d262fa5b70426c74f41ce..6265d36adcebcb893ca9345765fac5337d8835e3 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_CAFE_CCIC
        tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support"
        depends on PCI && I2C && VIDEO_V4L2
+       depends on HAS_DMA
        select VIDEO_OV7670
        select VIDEOBUF2_VMALLOC
        select VIDEOBUF2_DMA_CONTIG
@@ -12,6 +13,7 @@ config VIDEO_CAFE_CCIC
 config VIDEO_MMP_CAMERA
        tristate "Marvell Armada 610 integrated camera controller support"
        depends on ARCH_MMP && I2C && VIDEO_V4L2
+       depends on HAS_DMA
        select VIDEO_OV7670
        select I2C_GPIO
        select VIDEOBUF2_DMA_SG
index be4b51212106e41d1420b6c27b1fb68c041782cc..7a86c77bffa08257d35713361deaadb2e91bc1d8 100644 (file)
@@ -67,7 +67,7 @@ MODULE_PARM_DESC(dma_buf_size,
                "parameters require larger buffers, an attempt to reallocate "
                "will be made.");
 #else /* MCAM_MODE_VMALLOC */
-static const bool alloc_bufs_at_read = 0;
+static const bool alloc_bufs_at_read;
 static const int n_dma_bufs = 3;  /* Used by S/G_PARM */
 #endif /* MCAM_MODE_VMALLOC */
 
index fa8f7cabe364d4d36b20009d462eab02ff95f78f..4971ff21f82b6b46a5a2c43e25a40adfd6611ab8 100644 (file)
@@ -27,7 +27,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf2-dma-contig.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #define EMMAPRP_MODULE_NAME "mem2mem-emmaprp"
 
index 37ad446b35b309acc1f40099f9e71503785e5640..05de442d24e42ca6a2273b55271ea8425efb6a73 100644 (file)
@@ -3,7 +3,7 @@ config VIDEO_OMAP2_VOUT_VRFB
 
 config VIDEO_OMAP2_VOUT
        tristate "OMAP2/OMAP3 V4L2-Display driver"
-       depends on ARCH_OMAP2 || ARCH_OMAP3
+       depends on ARCH_OMAP2 || ARCH_OMAP3 || (COMPILE_TEST && HAS_MMU)
        select VIDEOBUF_GEN
        select VIDEOBUF_DMA_CONTIG
        select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS
index 2d177fa5847168f65d58b33b664c4e40ee3dd638..64ab6fb06b9c6ed478661a93f7fdf8424422237a 100644 (file)
@@ -369,7 +369,7 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout,
 {
        int ret = 0;
        struct omap_overlay_info info;
-       int cropheight, cropwidth, pixheight, pixwidth;
+       int cropheight, cropwidth, pixwidth;
 
        if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 &&
                        (outw != vout->pix.width || outh != vout->pix.height)) {
@@ -389,12 +389,10 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout,
        if (is_rotation_90_or_270(vout)) {
                cropheight = vout->crop.width;
                cropwidth = vout->crop.height;
-               pixheight = vout->pix.width;
                pixwidth = vout->pix.height;
        } else {
                cropheight = vout->crop.height;
                cropwidth = vout->crop.width;
-               pixheight = vout->pix.height;
                pixwidth = vout->pix.width;
        }
 
@@ -991,7 +989,7 @@ static int omap_vout_release(struct file *file)
                mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
                        DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2;
                omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
-               vout->streaming = 0;
+               vout->streaming = false;
 
                videobuf_streamoff(q);
                videobuf_queue_cancel(q);
@@ -1451,12 +1449,10 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
        }
        case V4L2_CID_VFLIP:
        {
-               struct omap_overlay *ovl;
                struct omapvideo_info *ovid;
                unsigned int  mirror = a->value;
 
                ovid = &vout->vid_info;
-               ovl = ovid->overlays[0];
 
                mutex_lock(&vout->lock);
                if (mirror && ovid->rotation_type == VOUT_ROT_NONE) {
@@ -1489,7 +1485,7 @@ static int vidioc_reqbufs(struct file *file, void *fh,
        struct omap_vout_device *vout = fh;
        struct videobuf_queue *q = &vout->vbq;
 
-       if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0))
+       if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
                return -EINVAL;
        /* if memory is not mmp or userptr
           return error */
@@ -1648,7 +1644,7 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
        vout->field_id = 0;
 
        /* set flag here. Next QBUF will start DMA */
-       vout->streaming = 1;
+       vout->streaming = true;
 
        vout->first_int = 1;
 
@@ -1708,7 +1704,7 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
        if (!vout->streaming)
                return -EINVAL;
 
-       vout->streaming = 0;
+       vout->streaming = false;
        mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
                | DISPC_IRQ_VSYNC2;
 
@@ -1916,7 +1912,7 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
        control[0].id = V4L2_CID_ROTATE;
        control[0].value = 0;
        vout->rotation = 0;
-       vout->mirror = 0;
+       vout->mirror = false;
        vout->control[2].id = V4L2_CID_HFLIP;
        vout->control[2].value = 0;
        if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
index 62e7e5783ce809c52f8905d482bb7aa232a3c287..aa39306afc73ac84439655314460acfa3202b43d 100644 (file)
@@ -148,7 +148,7 @@ int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
                        ret =  -ENOMEM;
                        goto release_vrfb_ctx;
                }
-               vout->vrfb_static_allocation = 1;
+               vout->vrfb_static_allocation = true;
        }
        return 0;
 
@@ -336,7 +336,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
                offset = vout->vrfb_context[0].yoffset *
                        vout->vrfb_context[0].bytespp;
                temp_ps = ps / vr_ps;
-               if (mirroring == 0) {
+               if (!mirroring) {
                        *cropped_offset = offset + line_length *
                                temp_ps * cleft + crop->top * temp_ps;
                } else {
@@ -350,7 +350,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
                        vout->vrfb_context[0].bytespp) +
                        (vout->vrfb_context[0].xoffset *
                        vout->vrfb_context[0].bytespp));
-               if (mirroring == 0) {
+               if (!mirroring) {
                        *cropped_offset = offset + (line_length * ps * ctop) +
                                (cleft / vr_ps) * ps;
 
@@ -364,7 +364,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
                offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset *
                        vout->vrfb_context[0].bytespp;
                temp_ps = ps / vr_ps;
-               if (mirroring == 0) {
+               if (!mirroring) {
                        *cropped_offset = offset + line_length *
                            temp_ps * crop->left + ctop * ps;
                } else {
@@ -375,7 +375,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
                }
                break;
        case dss_rotation_0_degree:
-               if (mirroring == 0) {
+               if (!mirroring) {
                        *cropped_offset = (line_length * ps) *
                                crop->top + (crop->left / vr_ps) * ps;
                } else {
index ffde741e0590813c754dda94dc4ee0c9277484bc..4c2314839b487768a9257d61ac3e9a30a46da2c6 100644 (file)
@@ -23,18 +23,18 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
                        struct videobuf_buffer *vb);
 void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout);
 #else
-void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }
-int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
+static inline void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { };
+static inline int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
                        u32 static_vrfb_allocation)
-               { return 0; }
-void omap_vout_release_vrfb(struct omap_vout_device *vout) { }
-int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+               { return 0; };
+static inline void omap_vout_release_vrfb(struct omap_vout_device *vout) { };
+static inline int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
                        unsigned int *count, unsigned int startindex)
-               { return 0; }
-int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
+               { return 0; };
+static inline int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
                        struct videobuf_buffer *vb)
-               { return 0; }
-void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { }
+               { return 0; };
+static inline void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { };
 #endif
 
 #endif
index c84df0706f3e098542d822e8fefc0755b010d836..e75b0eb2519b77f260e49acb84451ca99edd124c 100644 (file)
  * 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
  */
 
 { 244, 0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
index 78deebf7d9650df80a2011c8a175db7124ce4fa5..3b507078016d1e8b9f74f7ee6cd8633a1514ac3e 100644 (file)
  * 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
  */
 
   0,   0,   1,   2,   3,   3,   4,   5,   6,   8,  10,  12,  14,  16,  18,  20,
index 2c7aa67205693f36287756296aaa6e8debf0bc1c..72265e58ca6090add9643759a8ad92a79e4f03bc 100644 (file)
  * 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
  */
 
 #include <asm/cacheflush.h>
@@ -999,16 +989,14 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
                                         video, s_stream, 0);
                }
 
-               v4l2_subdev_call(subdev, video, s_stream, 0);
+               ret = v4l2_subdev_call(subdev, video, s_stream, 0);
 
                if (subdev == &isp->isp_res.subdev)
-                       ret = isp_pipeline_wait(isp, isp_pipeline_wait_resizer);
+                       ret |= isp_pipeline_wait(isp, isp_pipeline_wait_resizer);
                else if (subdev == &isp->isp_prev.subdev)
-                       ret = isp_pipeline_wait(isp, isp_pipeline_wait_preview);
+                       ret |= isp_pipeline_wait(isp, isp_pipeline_wait_preview);
                else if (subdev == &isp->isp_ccdc.subdev)
-                       ret = isp_pipeline_wait(isp, isp_pipeline_wait_ccdc);
-               else
-                       ret = 0;
+                       ret |= isp_pipeline_wait(isp, isp_pipeline_wait_ccdc);
 
                /* Handle stop failures. An entity that fails to stop can
                 * usually just be restarted. Flag the stop failure nonetheless
index 2c314eea125275942db5076c34ac4613d4d02537..cfdfc8714b6b8f7fb7d633a75b48b82971b0e482 100644 (file)
  * 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 OMAP3_ISP_CORE_H
index 9f727d20f06d98298dcf36a4e0a9e8390ad2d9da..81a9dc053d5883e13844b78d99339cedc5cd7482 100644 (file)
  * 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
  */
 
 #include <linux/module.h>
@@ -491,14 +481,13 @@ done:
 static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc)
 {
        unsigned long flags;
+       int ret;
 
        spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
-       if (ccdc->lsc.active) {
-               spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
-               return 1;
-       }
+       ret = ccdc->lsc.active != NULL;
        spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
-       return 0;
+
+       return ret;
 }
 
 static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc)
@@ -818,29 +807,48 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
        struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
        struct isp_device *isp = to_isp_device(ccdc);
        const struct isp_format_info *info;
+       struct v4l2_mbus_framefmt *format;
        unsigned long l3_ick = pipe->l3_ick;
        unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8;
        unsigned int div = 0;
-       u32 fmtcfg_vp;
+       u32 fmtcfg = ISPCCDC_FMTCFG_VPEN;
+
+       format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
+
+       if (!format->code) {
+               /* Disable the video port when the input format isn't supported.
+                * This is indicated by a pixel code set to 0.
+                */
+               isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
+               return;
+       }
+
+       isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
+                      (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);
+       isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
+                      ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);
 
-       fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG)
-                 & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK);
+       isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
+                      (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
 
        info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code);
 
        switch (info->width) {
        case 8:
        case 10:
-               fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
+               fmtcfg |= ISPCCDC_FMTCFG_VPIN_9_0;
                break;
        case 11:
-               fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
+               fmtcfg |= ISPCCDC_FMTCFG_VPIN_10_1;
                break;
        case 12:
-               fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
+               fmtcfg |= ISPCCDC_FMTCFG_VPIN_11_2;
                break;
        case 13:
-               fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
+               fmtcfg |= ISPCCDC_FMTCFG_VPIN_12_3;
                break;
        }
 
@@ -850,75 +858,59 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
                div = l3_ick / pipe->external_rate;
 
        div = clamp(div, 2U, max_div);
-       fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
+       fmtcfg |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
 
-       isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
-}
-
-/*
- * ccdc_enable_vp - Enable Video Port.
- * @ccdc: Pointer to ISP CCDC device.
- * @enable: 0 Disables VP, 1 Enables VP
- *
- * This is needed for outputting image to Preview, H3A and HIST ISP submodules.
- */
-static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable)
-{
-       struct isp_device *isp = to_isp_device(ccdc);
-
-       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
-                       ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0);
+       isp_reg_writel(isp, fmtcfg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
 }
 
 /*
  * ccdc_config_outlineoffset - Configure memory saving output line offset
  * @ccdc: Pointer to ISP CCDC device.
- * @offset: Address offset to start a new line. Must be twice the
- *          Output width and aligned on 32 byte boundary
- * @oddeven: Specifies the odd/even line pattern to be chosen to store the
- *           output.
- * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
+ * @bpl: Number of bytes per line when stored in memory.
+ * @field: Field order when storing interlaced formats in memory.
+ *
+ * Configure the offsets for the line output control:
+ *
+ * - The horizontal line offset is defined as the number of bytes between the
+ *   start of two consecutive lines in memory. Set it to the given bytes per
+ *   line value.
+ *
+ * - The field offset value is defined as the number of lines to offset the
+ *   start of the field identified by FID = 1. Set it to one.
  *
- * - Configures the output line offset when stored in memory
- * - Sets the odd/even line pattern to store the output
- *    (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
- * - Configures the number of even and odd line fields in case of rearranging
- * the lines.
+ * - The line offset values are defined as the number of lines (as defined by
+ *   the horizontal line offset) between the start of two consecutive lines for
+ *   all combinations of odd/even lines in odd/even fields. When interleaving
+ *   fields set them all to two lines, and to one line otherwise.
  */
 static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc,
-                                       u32 offset, u8 oddeven, u8 numlines)
+                                     unsigned int bpl,
+                                     enum v4l2_field field)
 {
        struct isp_device *isp = to_isp_device(ccdc);
+       u32 sdofst = 0;
 
-       isp_reg_writel(isp, offset & 0xffff,
-                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF);
+       isp_reg_writel(isp, bpl & 0xffff, OMAP3_ISP_IOMEM_CCDC,
+                      ISPCCDC_HSIZE_OFF);
 
-       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-                   ISPCCDC_SDOFST_FINV);
-
-       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-                   ISPCCDC_SDOFST_FOFST_4L);
-
-       switch (oddeven) {
-       case EVENEVEN:
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-                           (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
-               break;
-       case ODDEVEN:
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-                           (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
-               break;
-       case EVENODD:
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-                           (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
-               break;
-       case ODDODD:
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-                           (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
+       switch (field) {
+       case V4L2_FIELD_INTERLACED_TB:
+       case V4L2_FIELD_INTERLACED_BT:
+               /* When interleaving fields in memory offset field one by one
+                * line and set the line offset to two lines.
+                */
+               sdofst |= (1 << ISPCCDC_SDOFST_LOFST0_SHIFT)
+                      |  (1 << ISPCCDC_SDOFST_LOFST1_SHIFT)
+                      |  (1 << ISPCCDC_SDOFST_LOFST2_SHIFT)
+                      |  (1 << ISPCCDC_SDOFST_LOFST3_SHIFT);
                break;
+
        default:
+               /* In all other cases set the line offsets to one line. */
                break;
        }
+
+       isp_reg_writel(isp, sdofst, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST);
 }
 
 /*
@@ -981,10 +973,16 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
 
        if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
            format->code == V4L2_MBUS_FMT_UYVY8_2X8) {
-               /* The bridge is enabled for YUV8 formats. Configure the input
-                * mode accordingly.
+               /* According to the OMAP3 TRM the input mode only affects SYNC
+                * mode, enabling BT.656 mode should take precedence. However,
+                * in practice setting the input mode to YCbCr data on 8 bits
+                * seems to be required in BT.656 mode. In SYNC mode set it to
+                * YCbCr on 16 bits as the bridge is enabled in that case.
                 */
-               syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16;
+               if (ccdc->bt656)
+                       syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR8;
+               else
+                       syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16;
        }
 
        switch (data_size) {
@@ -1008,9 +1006,15 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
        if (pdata && pdata->hs_pol)
                syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
 
-       if (pdata && pdata->vs_pol)
+       /* The polarity of the vertical sync signal output by the BT.656
+        * decoder is not documented and seems to be active low.
+        */
+       if ((pdata && pdata->vs_pol) || ccdc->bt656)
                syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
 
+       if (pdata && pdata->fld_pol)
+               syn_mode |= ISPCCDC_SYN_MODE_FLDPOL;
+
        isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
 
        /* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The
@@ -1023,8 +1027,16 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
                isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
                            ISPCCDC_CFG_Y8POS);
 
-       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
-                   ISPCCDC_REC656IF_R656ON);
+       /* Enable or disable BT.656 mode, including error correction for the
+        * synchronization codes.
+        */
+       if (ccdc->bt656)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
+                           ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
+                           ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH);
+
 }
 
 /* CCDC formats descriptions */
@@ -1115,17 +1127,33 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        unsigned long flags;
        unsigned int bridge;
        unsigned int shift;
+       unsigned int nph;
+       unsigned int sph;
        u32 syn_mode;
        u32 ccdc_pattern;
 
+       ccdc->bt656 = false;
+       ccdc->fields = 0;
+
        pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]);
        sensor = media_entity_to_v4l2_subdev(pad->entity);
-       if (ccdc->input == CCDC_INPUT_PARALLEL)
+       if (ccdc->input == CCDC_INPUT_PARALLEL) {
+               struct v4l2_mbus_config cfg;
+               int ret;
+
+               ret = v4l2_subdev_call(sensor, video, g_mbus_config, &cfg);
+               if (!ret)
+                       ccdc->bt656 = cfg.type == V4L2_MBUS_BT656;
+
                pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
                        ->bus.parallel;
+       }
+
+       /* CCDC_PAD_SINK */
+       format = &ccdc->formats[CCDC_PAD_SINK];
 
        /* Compute the lane shifter shift value and enable the bridge when the
-        * input format is YUV.
+        * input format is a non-BT.656 YUV variant.
         */
        fmt_src.pad = pad->index;
        fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
@@ -1134,12 +1162,13 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
                depth_in = fmt_info->width;
        }
 
-       fmt_info = omap3isp_video_format_info
-               (isp->isp_ccdc.formats[CCDC_PAD_SINK].code);
+       fmt_info = omap3isp_video_format_info(format->code);
        depth_out = fmt_info->width;
        shift = depth_in - depth_out;
 
-       if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8)
+       if (ccdc->bt656)
+               bridge = ISPCTRL_PAR_BRIDGE_DISABLE;
+       else if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8)
                bridge = ISPCTRL_PAR_BRIDGE_LENDIAN;
        else if (fmt_info->code == V4L2_MBUS_FMT_UYVY8_2X8)
                bridge = ISPCTRL_PAR_BRIDGE_BENDIAN;
@@ -1148,6 +1177,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
 
        omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge);
 
+       /* Configure the sync interface. */
        ccdc_config_sync_if(ccdc, pdata, depth_out);
 
        syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
@@ -1167,9 +1197,6 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        else
                syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
 
-       /* CCDC_PAD_SINK */
-       format = &ccdc->formats[CCDC_PAD_SINK];
-
        /* Mosaic filter */
        switch (format->code) {
        case V4L2_MBUS_FMT_SRGGB10_1X10:
@@ -1202,16 +1229,40 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
        crop = &ccdc->crop;
 
-       isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
-                      ((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
+       /* The horizontal coordinates are expressed in pixel clock cycles. We
+        * need two cycles per pixel in BT.656 mode, and one cycle per pixel in
+        * SYNC mode regardless of the format as the bridge is enabled for YUV
+        * formats in that case.
+        */
+       if (ccdc->bt656) {
+               sph = crop->left * 2;
+               nph = crop->width * 2 - 1;
+       } else {
+               sph = crop->left;
+               nph = crop->width - 1;
+       }
+
+       isp_reg_writel(isp, (sph << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
+                      (nph << ISPCCDC_HORZ_INFO_NPH_SHIFT),
                       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
-       isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT,
+       isp_reg_writel(isp, (crop->top << ISPCCDC_VERT_START_SLV0_SHIFT) |
+                      (crop->top << ISPCCDC_VERT_START_SLV1_SHIFT),
                       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
        isp_reg_writel(isp, (crop->height - 1)
                        << ISPCCDC_VERT_LINES_NLV_SHIFT,
                       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);
 
-       ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0);
+       ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value,
+                                 format->field);
+
+       /* When interleaving fields enable processing of the field input signal.
+        * This will cause the line output control module to apply the field
+        * offset to field 1.
+        */
+       if (ccdc->formats[CCDC_PAD_SINK].field == V4L2_FIELD_ALTERNATE &&
+           (format->field == V4L2_FIELD_INTERLACED_TB ||
+            format->field == V4L2_FIELD_INTERLACED_BT))
+               syn_mode |= ISPCCDC_SYN_MODE_FLDMODE;
 
        /* The CCDC outputs data in UYVY order by default. Swap bytes to get
         * YUYV.
@@ -1223,8 +1274,11 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
                isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
                            ISPCCDC_CFG_BSWD);
 
-       /* Use PACK8 mode for 1byte per pixel formats. */
-       if (omap3isp_video_format_info(format->code)->width <= 8)
+       /* Use PACK8 mode for 1byte per pixel formats. Check for BT.656 mode
+        * explicitly as the driver reports 1X16 instead of 2X8 at the OF pad
+        * for simplicity.
+        */
+       if (omap3isp_video_format_info(format->code)->width <= 8 || ccdc->bt656)
                syn_mode |= ISPCCDC_SYN_MODE_PACK8;
        else
                syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;
@@ -1232,18 +1286,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
 
        /* CCDC_PAD_SOURCE_VP */
-       format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
-
-       isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
-                      (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
-                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);
-       isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
-                      ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
-                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);
-
-       isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
-                      (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
-                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
+       ccdc_config_vp(ccdc);
 
        /* Lens shading correction. */
        spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
@@ -1277,6 +1320,8 @@ static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable)
 
        isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
                        ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
+
+       ccdc->running = enable;
 }
 
 static int ccdc_disable(struct isp_ccdc_device *ccdc)
@@ -1287,6 +1332,8 @@ static int ccdc_disable(struct isp_ccdc_device *ccdc)
        spin_lock_irqsave(&ccdc->lock, flags);
        if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS)
                ccdc->stopping = CCDC_STOP_REQUEST;
+       if (!ccdc->running)
+               ccdc->stopping = CCDC_STOP_FINISHED;
        spin_unlock_irqrestore(&ccdc->lock, flags);
 
        ret = wait_event_timeout(ccdc->wait,
@@ -1369,14 +1416,14 @@ static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc,
        return -EBUSY;
 }
 
-/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence
+/* ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence
  * @ccdc: Pointer to ISP CCDC device.
  * @event: Pointing which event trigger handler
  *
  * Return 1 when the event and stopping request combination is satisfied,
  * zero otherwise.
  */
-static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
+static int ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
 {
        int rval = 0;
 
@@ -1458,7 +1505,7 @@ static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events)
        if (ccdc->lsc.state == LSC_STATE_STOPPING)
                ccdc->lsc.state = LSC_STATE_STOPPED;
 
-       if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))
+       if (ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))
                goto done;
 
        if (ccdc->lsc.state != LSC_STATE_RECONFIG)
@@ -1486,12 +1533,59 @@ done:
        spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
 }
 
+/*
+ * Check whether the CCDC has captured all fields necessary to complete the
+ * buffer.
+ */
+static bool ccdc_has_all_fields(struct isp_ccdc_device *ccdc)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+       struct isp_device *isp = to_isp_device(ccdc);
+       enum v4l2_field of_field = ccdc->formats[CCDC_PAD_SOURCE_OF].field;
+       enum v4l2_field field;
+
+       /* When the input is progressive fields don't matter. */
+       if (of_field == V4L2_FIELD_NONE)
+               return true;
+
+       /* Read the current field identifier. */
+       field = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE)
+             & ISPCCDC_SYN_MODE_FLDSTAT
+             ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;
+
+       /* When capturing fields in alternate order just store the current field
+        * identifier in the pipeline.
+        */
+       if (of_field == V4L2_FIELD_ALTERNATE) {
+               pipe->field = field;
+               return true;
+       }
+
+       /* The format is interlaced. Make sure we've captured both fields. */
+       ccdc->fields |= field == V4L2_FIELD_BOTTOM
+                     ? CCDC_FIELD_BOTTOM : CCDC_FIELD_TOP;
+
+       if (ccdc->fields != CCDC_FIELD_BOTH)
+               return false;
+
+       /* Verify that the field just captured corresponds to the last field
+        * needed based on the desired field order.
+        */
+       if ((of_field == V4L2_FIELD_INTERLACED_TB && field == V4L2_FIELD_TOP) ||
+           (of_field == V4L2_FIELD_INTERLACED_BT && field == V4L2_FIELD_BOTTOM))
+               return false;
+
+       /* The buffer can be completed, reset the fields for the next buffer. */
+       ccdc->fields = 0;
+
+       return true;
+}
+
 static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
 {
        struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
        struct isp_device *isp = to_isp_device(ccdc);
        struct isp_buffer *buffer;
-       int restart = 0;
 
        /* The CCDC generates VD0 interrupts even when disabled (the datasheet
         * doesn't explicitly state if that's supposed to happen or not, so it
@@ -1500,30 +1594,31 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
         * would thus not be enough, we need to handle the situation explicitly.
         */
        if (list_empty(&ccdc->video_out.dmaqueue))
-               goto done;
+               return 0;
 
        /* We're in continuous mode, and memory writes were disabled due to a
         * buffer underrun. Reenable them now that we have a buffer. The buffer
         * address has been set in ccdc_video_queue.
         */
        if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) {
-               restart = 1;
                ccdc->underrun = 0;
-               goto done;
+               return 1;
        }
 
+       /* Wait for the CCDC to become idle. */
        if (ccdc_sbl_wait_idle(ccdc, 1000)) {
                dev_info(isp->dev, "CCDC won't become idle!\n");
                isp->crashed |= 1U << ccdc->subdev.entity.id;
                omap3isp_pipeline_cancel_stream(pipe);
-               goto done;
+               return 0;
        }
 
+       if (!ccdc_has_all_fields(ccdc))
+               return 1;
+
        buffer = omap3isp_video_buffer_next(&ccdc->video_out);
-       if (buffer != NULL) {
+       if (buffer != NULL)
                ccdc_set_outaddr(ccdc, buffer->dma);
-               restart = 1;
-       }
 
        pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
 
@@ -1532,8 +1627,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
                omap3isp_pipeline_set_stream(pipe,
                                        ISP_PIPELINE_STREAM_SINGLESHOT);
 
-done:
-       return restart;
+       return buffer != NULL;
 }
 
 /*
@@ -1547,11 +1641,38 @@ static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc)
        unsigned long flags;
        int restart = 0;
 
+       /* In BT.656 mode the CCDC doesn't generate an HS/VS interrupt. We thus
+        * need to increment the frame counter here.
+        */
+       if (ccdc->bt656) {
+               struct isp_pipeline *pipe =
+                       to_isp_pipeline(&ccdc->subdev.entity);
+
+               atomic_inc(&pipe->frame_number);
+       }
+
+       /* Emulate a VD1 interrupt for BT.656 mode, as we can't stop the CCDC in
+        * the VD1 interrupt handler in that mode without risking a CCDC stall
+        * if a short frame is received.
+        */
+       if (ccdc->bt656) {
+               spin_lock_irqsave(&ccdc->lock, flags);
+               if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
+                   ccdc->output & CCDC_OUTPUT_MEMORY) {
+                       if (ccdc->lsc.state != LSC_STATE_STOPPED)
+                               __ccdc_lsc_enable(ccdc, 0);
+                       __ccdc_enable(ccdc, 0);
+               }
+               ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1);
+               spin_unlock_irqrestore(&ccdc->lock, flags);
+       }
+
        if (ccdc->output & CCDC_OUTPUT_MEMORY)
                restart = ccdc_isr_buffer(ccdc);
 
        spin_lock_irqsave(&ccdc->lock, flags);
-       if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
+
+       if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
                spin_unlock_irqrestore(&ccdc->lock, flags);
                return;
        }
@@ -1572,6 +1693,18 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)
 {
        unsigned long flags;
 
+       /* In BT.656 mode the synchronization signals are generated by the CCDC
+        * from the embedded sync codes. The VD0 and VD1 interrupts are thus
+        * only triggered when the CCDC is enabled, unlike external sync mode
+        * where the line counter runs even when the CCDC is stopped. We can't
+        * disable the CCDC at VD1 time, as no VD0 interrupt would be generated
+        * for a short frame, which would result in the CCDC being stopped and
+        * no VD interrupt generated anymore. The CCDC is stopped from the VD0
+        * interrupt handler instead for BT.656.
+        */
+       if (ccdc->bt656)
+               return;
+
        spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
 
        /*
@@ -1601,7 +1734,7 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)
                break;
        }
 
-       if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))
+       if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))
                goto done;
 
        if (ccdc->lsc.request == NULL)
@@ -1656,6 +1789,8 @@ int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events)
 static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
 {
        struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc;
+       unsigned long flags;
+       bool restart = false;
 
        if (!(ccdc->output & CCDC_OUTPUT_MEMORY))
                return -ENODEV;
@@ -1664,9 +1799,20 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
 
        /* We now have a buffer queued on the output, restart the pipeline
         * on the next CCDC interrupt if running in continuous mode (or when
-        * starting the stream).
+        * starting the stream) in external sync mode, or immediately in BT.656
+        * sync mode as no CCDC interrupt is generated when the CCDC is stopped
+        * in that case.
         */
-       ccdc->underrun = 1;
+       spin_lock_irqsave(&ccdc->lock, flags);
+       if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && !ccdc->running &&
+           ccdc->bt656)
+               restart = true;
+       else
+               ccdc->underrun = 1;
+       spin_unlock_irqrestore(&ccdc->lock, flags);
+
+       if (restart)
+               ccdc_enable(ccdc);
 
        return 0;
 }
@@ -1753,11 +1899,6 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
 
                ccdc_configure(ccdc);
 
-               /* TODO: Don't configure the video port if all of its output
-                * links are inactive.
-                */
-               ccdc_config_vp(ccdc);
-               ccdc_enable_vp(ccdc, 1);
                ccdc_print_status(ccdc);
        }
 
@@ -1830,6 +1971,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
        unsigned int width = fmt->width;
        unsigned int height = fmt->height;
        struct v4l2_rect *crop;
+       enum v4l2_field field;
        unsigned int i;
 
        switch (pad) {
@@ -1846,14 +1988,24 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
                /* Clamp the input size. */
                fmt->width = clamp_t(u32, width, 32, 4096);
                fmt->height = clamp_t(u32, height, 32, 4096);
+
+               /* Default to progressive field order. */
+               if (fmt->field == V4L2_FIELD_ANY)
+                       fmt->field = V4L2_FIELD_NONE;
+
                break;
 
        case CCDC_PAD_SOURCE_OF:
                pixelcode = fmt->code;
+               field = fmt->field;
                *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
 
-               /* YUV formats are converted from 2X8 to 1X16 by the bridge and
-                * can be byte-swapped.
+               /* In SYNC mode the bridge converts YUV formats from 2X8 to
+                * 1X16. In BT.656 no such conversion occurs. As we don't know
+                * at this point whether the source will use SYNC or BT.656 mode
+                * let's pretend the conversion always occurs. The CCDC will be
+                * configured to pack bytes in BT.656, hiding the inaccuracy.
+                * In all cases bytes can be swapped.
                 */
                if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
                    fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) {
@@ -1874,6 +2026,17 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
                crop = __ccdc_get_crop(ccdc, fh, which);
                fmt->width = crop->width;
                fmt->height = crop->height;
+
+               /* When input format is interlaced with alternating fields the
+                * CCDC can interleave the fields.
+                */
+               if (fmt->field == V4L2_FIELD_ALTERNATE &&
+                   (field == V4L2_FIELD_INTERLACED_TB ||
+                    field == V4L2_FIELD_INTERLACED_BT)) {
+                       fmt->field = field;
+                       fmt->height *= 2;
+               }
+
                break;
 
        case CCDC_PAD_SOURCE_VP:
@@ -1901,7 +2064,6 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
         * stored on 2 bytes.
         */
        fmt->colorspace = V4L2_COLORSPACE_SRGB;
-       fmt->field = V4L2_FIELD_NONE;
 }
 
 /*
index f65061602c71e585695503d30c4d9f340af1a27a..3440a709794001a68513ba9300e677808b43e401 100644 (file)
  * 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 OMAP3_ISP_CCDC_H
@@ -103,6 +93,10 @@ struct ispccdc_lsc {
 #define CCDC_PAD_SOURCE_VP             2
 #define CCDC_PADS_NUM                  3
 
+#define CCDC_FIELD_TOP                 1
+#define CCDC_FIELD_BOTTOM              2
+#define CCDC_FIELD_BOTH                        3
+
 /*
  * struct isp_ccdc_device - Structure for the CCDC module to store its own
  *                         information
@@ -123,11 +117,14 @@ struct ispccdc_lsc {
  * @lsc: Lens shading compensation configuration
  * @update: Bitmask of controls to update during the next interrupt
  * @shadow_update: Controls update in progress by userspace
+ * @bt656: Whether the input interface uses BT.656 synchronization
+ * @fields: The fields (CCDC_FIELD_*) stored in the current buffer
  * @underrun: A buffer underrun occurred and a new buffer has been queued
  * @state: Streaming state
  * @lock: Serializes shadow_update with interrupt handler
  * @wait: Wait queue used to stop the module
  * @stopping: Stopping state
+ * @running: Is the CCDC hardware running
  * @ioctl_lock: Serializes ioctl calls and LSC requests freeing
  */
 struct isp_ccdc_device {
@@ -151,11 +148,15 @@ struct isp_ccdc_device {
        unsigned int update;
        unsigned int shadow_update;
 
+       bool bt656;
+       unsigned int fields;
+
        unsigned int underrun:1;
        enum isp_pipeline_stream_state state;
        spinlock_t lock;
        wait_queue_head_t wait;
        unsigned int stopping;
+       bool running;
        struct mutex ioctl_lock;
 };
 
index f3801db9095ca301bf53e564e9d9f4eb33a13327..9cb49b3c04bd2d596093bf6486f2b46c9cd99b3e 100644 (file)
  * 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
  */
 
 #include <linux/delay.h>
index 76d65f4576ef017d6ca2dad854a0697e4799e35c..4662bffa79e31a0044e09efe8f09c9042f97869d 100644 (file)
  * 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 OMAP3_ISP_CCP2_H
index 5a2e47e58b846543f651d38acf5fba05012e2c3e..6530b255f1038cdb7f7cf46aa87a81d2ecbde586 100644 (file)
  * 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
  */
 #include <linux/delay.h>
 #include <media/v4l2-common.h>
index c57729b7e86e44c0ad74fe3bdb73a2645cff4fd4..453ed62fe3946c7a3dc7fb7cdc2399804fcfc7e1 100644 (file)
  * 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 OMAP3_ISP_CSI2_H
index c09de32f986a5d797b01ab4ac5f679078e39eb85..e033f2237a72f4383236556d984b6bd773b3832d 100644 (file)
  * 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
  */
 
 #include <linux/delay.h>
index 14551fd7769780d3f319c6d5d146ed4742b291ac..e17c88beab92630722fdd6cc48d9a084d0bcfd8e 100644 (file)
  * 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 OMAP3_ISP_CSI_PHY_H
index fb09fd4ca7559f744ed49a4554a00e38f2d88933..e5b28d0f3b0f49a9069a9c50855e7064bfbb564d 100644 (file)
  * 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 OMAP3_ISP_H3A_H
index d6811ce263eb113102cceb7611a42e4c5f21f11d..b208c5417146e081facc8675f345f221e346f567 100644 (file)
  * 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
  */
 
 #include <linux/slab.h>
index 6fc960cd30f57accab300b749aa7049dcf5efd28..8a83e195f3e30443dc914a4d10dc12edc90f02a9 100644 (file)
  * 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
  */
 
 /* Linux specific include files */
index 06a5f8164eaa0a4e5aa9b3e8b64674d83a5f3042..ce822c34c843a7d9c92c020ccd9d19526ac32af1 100644 (file)
  * 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
  */
 
 #include <linux/delay.h>
index 0b2a38ec94c4af59bb9c30750d7574d24c4b1dc5..3b5415517dcda6992914b90d3532e80586d87bb9 100644 (file)
  * 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 OMAP3_ISP_HIST_H
index 720809b07e75f4779f20da64aa1b0af498bad012..605f57ef0a493a82439d3055c233c68015dfaba3 100644 (file)
  * 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
  */
 
 #include <linux/device.h>
index f66923407f8c5a90f2a4280201cb21460ad2fab6..16fdc03a3d43bfb114d3ee64e6a5e04521cb5357 100644 (file)
  * 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 OMAP3_ISP_PREVIEW_H
index b7d90e6fb01dc043c240a20bd27ae444dd96fc79..b5ea8da0b904cbb0498ab7001e1e1e98acb4707a 100644 (file)
  * 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 OMAP3_ISP_REG_H
 
 #define ISPCCDC_HSIZE_OFF_SHIFT                        0
 
-#define ISPCCDC_SDOFST_FINV                    (1 << 14)
-#define ISPCCDC_SDOFST_FOFST_1L                        0
-#define ISPCCDC_SDOFST_FOFST_4L                        (3 << 12)
+#define ISPCCDC_SDOFST_FIINV                   (1 << 14)
+#define ISPCCDC_SDOFST_FOFST_SHIFT             12
+#define ISPCCDC_SDOFST_FOFST_MASK              (3 << 12)
 #define ISPCCDC_SDOFST_LOFST3_SHIFT            0
 #define ISPCCDC_SDOFST_LOFST2_SHIFT            3
 #define ISPCCDC_SDOFST_LOFST1_SHIFT            6
 #define ISPCCDC_SDOFST_LOFST0_SHIFT            9
-#define EVENEVEN                               1
-#define ODDEVEN                                        2
-#define EVENODD                                        3
-#define ODDODD                                 4
 
 #define ISPCCDC_CLAMP_OBGAIN_SHIFT             0
 #define ISPCCDC_CLAMP_OBST_SHIFT               10
index 6f077c2377db6a7b785f1f8a4b688c2996c0d2b1..05d1ace57451a67536e0d7b7821f953ef5515e7f 100644 (file)
  * 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
  */
 
 #include <linux/device.h>
@@ -239,7 +229,7 @@ static void resizer_set_phase(struct isp_res_device *res, u32 h_phase,
                              u32 v_phase)
 {
        struct isp_device *isp = to_isp_device(res);
-       u32 rgval = 0;
+       u32 rgval;
 
        rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
              ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
@@ -275,7 +265,7 @@ static void resizer_set_luma(struct isp_res_device *res,
                             struct resizer_luma_yenh *luma)
 {
        struct isp_device *isp = to_isp_device(res);
-       u32 rgval = 0;
+       u32 rgval;
 
        rgval  = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT)
                  & ISPRSZ_YENH_ALGO_MASK;
@@ -322,7 +312,7 @@ static void resizer_set_ratio(struct isp_res_device *res,
 {
        struct isp_device *isp = to_isp_device(res);
        const u16 *h_filter, *v_filter;
-       u32 rgval = 0;
+       u32 rgval;
 
        rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
                              ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
@@ -365,9 +355,8 @@ static void resizer_set_output_size(struct isp_res_device *res,
                                    u32 width, u32 height)
 {
        struct isp_device *isp = to_isp_device(res);
-       u32 rgval = 0;
+       u32 rgval;
 
-       dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height);
        rgval  = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
                 & ISPRSZ_OUT_SIZE_HORZ_MASK;
        rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
@@ -409,7 +398,7 @@ static void resizer_set_output_offset(struct isp_res_device *res, u32 offset)
 static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
 {
        struct isp_device *isp = to_isp_device(res);
-       u32 rgval = 0;
+       u32 rgval;
 
        rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT)
                & ISPRSZ_IN_START_HORZ_ST_MASK;
@@ -429,9 +418,7 @@ static void resizer_set_input_size(struct isp_res_device *res,
                                   u32 width, u32 height)
 {
        struct isp_device *isp = to_isp_device(res);
-       u32 rgval = 0;
-
-       dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height);
+       u32 rgval;
 
        rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT)
                & ISPRSZ_IN_SIZE_HORZ_MASK;
@@ -1075,10 +1062,13 @@ static void resizer_isr_buffer(struct isp_res_device *res)
 void omap3isp_resizer_isr(struct isp_res_device *res)
 {
        struct v4l2_mbus_framefmt *informat, *outformat;
+       unsigned long flags;
 
        if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
                return;
 
+       spin_lock_irqsave(&res->lock, flags);
+
        if (res->applycrop) {
                outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
                                              V4L2_SUBDEV_FORMAT_ACTIVE);
@@ -1088,6 +1078,8 @@ void omap3isp_resizer_isr(struct isp_res_device *res)
                res->applycrop = 0;
        }
 
+       spin_unlock_irqrestore(&res->lock, flags);
+
        resizer_isr_buffer(res);
 }
 
@@ -1290,8 +1282,10 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
 {
        struct isp_res_device *res = v4l2_get_subdevdata(sd);
        struct isp_device *isp = to_isp_device(res);
-       struct v4l2_mbus_framefmt *format_sink, *format_source;
+       const struct v4l2_mbus_framefmt *format_sink;
+       struct v4l2_mbus_framefmt format_source;
        struct resizer_ratio ratio;
+       unsigned long flags;
 
        if (sel->target != V4L2_SEL_TGT_CROP ||
            sel->pad != RESZ_PAD_SINK)
@@ -1299,16 +1293,14 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
 
        format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
                                           sel->which);
-       format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
-                                            sel->which);
-
-       dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
-               sel->r.left, sel->r.top, sel->r.width, sel->r.height,
-               sel->which);
+       format_source = *__resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+                                             sel->which);
 
-       dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
+       dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
+               __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act",
                format_sink->width, format_sink->height,
-               format_source->width, format_source->height);
+               sel->r.left, sel->r.top, sel->r.width, sel->r.height,
+               format_source.width, format_source.height);
 
        /* Clamp the crop rectangle to the bounds, and then mangle it further to
         * fulfill the TRM equations. Store the clamped but otherwise unmangled
@@ -1318,23 +1310,39 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
         * smaller input crop rectangle every time the output size is set if we
         * stored the mangled rectangle.
         */
-       resizer_try_crop(format_sink, format_source, &sel->r);
+       resizer_try_crop(format_sink, &format_source, &sel->r);
        *__resizer_get_crop(res, fh, sel->which) = sel->r;
-       resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+       resizer_calc_ratios(res, &sel->r, &format_source, &ratio);
 
-       if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
+       dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
+               __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act",
+               format_sink->width, format_sink->height,
+               sel->r.left, sel->r.top, sel->r.width, sel->r.height,
+               format_source.width, format_source.height);
+
+       if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+               *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) =
+                       format_source;
                return 0;
+       }
+
+       /* Update the source format, resizing ratios and crop rectangle. If
+        * streaming is on the IRQ handler will reprogram the resizer after the
+        * current frame. We thus we need to protect against race conditions.
+        */
+       spin_lock_irqsave(&res->lock, flags);
+
+       *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) =
+               format_source;
 
        res->ratio = ratio;
        res->crop.active = sel->r;
 
-       /*
-        * set_selection can be called while streaming is on. In this case the
-        * crop values will be set in the next IRQ.
-        */
        if (res->state != ISP_PIPELINE_STREAM_STOPPED)
                res->applycrop = 1;
 
+       spin_unlock_irqrestore(&res->lock, flags);
+
        return 0;
 }
 
@@ -1781,6 +1789,8 @@ int omap3isp_resizer_init(struct isp_device *isp)
 
        init_waitqueue_head(&res->wait);
        atomic_set(&res->stopping, 0);
+       spin_lock_init(&res->lock);
+
        return resizer_init_entities(res);
 }
 
index 9b01e9047c15d8ce98d177760ff82a3f588c3071..5414542912e2723b39f0ec034293af10ab7c279c 100644 (file)
  * 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 OMAP3_ISP_RESIZER_H
 #define OMAP3_ISP_RESIZER_H
 
+#include <linux/spinlock.h>
 #include <linux/types.h>
 
 /*
@@ -96,6 +87,7 @@ enum resizer_input_entity {
 
 /*
  * struct isp_res_device - OMAP3 ISP resizer module
+ * @lock: Protects formats and crop rectangles between set_selection and IRQ
  * @crop.request: Crop rectangle requested by the user
  * @crop.active: Active crop rectangle (based on hardware requirements)
  */
@@ -116,6 +108,7 @@ struct isp_res_device {
        enum isp_pipeline_stream_state state;
        wait_queue_head_t wait;
        atomic_t stopping;
+       spinlock_t lock;
 
        struct {
                struct v4l2_rect request;
index e6cbc1eaf4cab03fa5c29ab1ffba1de8d7bb6cec..a94e8340508f703efea86f51232578e30912f496 100644 (file)
  * 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
  */
 
 #include <linux/dma-mapping.h>
index 58d6ac7cb6648ce18f2e8284cc85fe9d96199242..b32b29677e2c48f3fc3bd4dbe9d9208452ee1cf5 100644 (file)
  * 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 OMAP3_ISP_STAT_H
index e36bac26476c0fd7ac382f5e85effc07a7a0b202..bc38c88c7bd9cc179de2afd0b120aa00dc139833 100644 (file)
  * 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
  */
 
 #include <asm/cacheflush.h>
@@ -319,10 +309,11 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
            vfh->format.fmt.pix.height != format.fmt.pix.height ||
            vfh->format.fmt.pix.width != format.fmt.pix.width ||
            vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline ||
-           vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage)
+           vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage ||
+           vfh->format.fmt.pix.field != format.fmt.pix.field)
                return -EINVAL;
 
-       return ret;
+       return 0;
 }
 
 /* -----------------------------------------------------------------------------
@@ -491,6 +482,11 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
        else
                buf->vb.v4l2_buf.sequence = atomic_read(&pipe->frame_number);
 
+       if (pipe->field != V4L2_FIELD_NONE)
+               buf->vb.v4l2_buf.sequence /= 2;
+
+       buf->vb.v4l2_buf.field = pipe->field;
+
        /* Report pipeline errors to userspace on the capture device side. */
        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
                state = VB2_BUF_STATE_ERROR;
@@ -641,7 +637,40 @@ isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
        if (format->type != video->type)
                return -EINVAL;
 
-       mutex_lock(&video->mutex);
+       /* Replace unsupported field orders with sane defaults. */
+       switch (format->fmt.pix.field) {
+       case V4L2_FIELD_NONE:
+               /* Progressive is supported everywhere. */
+               break;
+       case V4L2_FIELD_ALTERNATE:
+               /* ALTERNATE is not supported on output nodes. */
+               if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+                       format->fmt.pix.field = V4L2_FIELD_NONE;
+               break;
+       case V4L2_FIELD_INTERLACED:
+               /* The ISP has no concept of video standard, select the
+                * top-bottom order when the unqualified interlaced order is
+                * requested.
+                */
+               format->fmt.pix.field = V4L2_FIELD_INTERLACED_TB;
+               /* Fall-through */
+       case V4L2_FIELD_INTERLACED_TB:
+       case V4L2_FIELD_INTERLACED_BT:
+               /* Interlaced orders are only supported at the CCDC output. */
+               if (video != &video->isp->isp_ccdc.video_out)
+                       format->fmt.pix.field = V4L2_FIELD_NONE;
+               break;
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+       case V4L2_FIELD_SEQ_TB:
+       case V4L2_FIELD_SEQ_BT:
+       default:
+               /* All other field orders are currently unsupported, default to
+                * progressive.
+                */
+               format->fmt.pix.field = V4L2_FIELD_NONE;
+               break;
+       }
 
        /* Fill the bytesperline and sizeimage fields by converting to media bus
         * format and back to pixel format.
@@ -649,9 +678,10 @@ isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
        isp_video_pix_to_mbus(&format->fmt.pix, &fmt);
        isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
 
+       mutex_lock(&video->mutex);
        vfh->format = *format;
-
        mutex_unlock(&video->mutex);
+
        return 0;
 }
 
@@ -1039,6 +1069,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        video->queue = &vfh->queue;
        INIT_LIST_HEAD(&video->dmaqueue);
        atomic_set(&pipe->frame_number, -1);
+       pipe->field = vfh->format.fmt.pix.field;
 
        mutex_lock(&video->queue_lock);
        ret = vb2_streamon(&vfh->queue, type);
index 7d2e82122ecda431d417ae10ba8193b9fb9154ec..0b7efedc3da990945bddc7e32389b55693df1ab3 100644 (file)
  * 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 OMAP3_ISP_VIDEO_H
@@ -88,6 +78,7 @@ enum isp_pipeline_state {
 
 /*
  * struct isp_pipeline - An ISP hardware pipeline
+ * @field: The field being processed by the pipeline
  * @error: A hardware error occurred during capture
  * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
  */
@@ -101,6 +92,7 @@ struct isp_pipeline {
        u32 entities;
        unsigned long l3_ick;
        unsigned int max_rate;
+       enum v4l2_field field;
        atomic_t frame_number;
        bool do_propagation; /* of frame number */
        bool error;
index 098b45e2280f064fc3a304555e3925c1b61ee841..81c5b1566469f16587c319907bf30d6d860243f7 100644 (file)
  * 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
  */
 
 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
index d50451a4a2424616915e6c40b18ecb0b8f2454f2..5073f98479379cf3dde0c8ddb47fac14c49ac6fb 100644 (file)
  * 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
  */
 
 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
index f33641384e15adf817542a689bb5df57082fe812..4f81b4c9d113f1a61aa8d10751d2f898dd70228d 100644 (file)
@@ -280,8 +280,8 @@ static int camif_prepare_addr(struct camif_vp *vp, struct vb2_buffer *vb,
                return -EINVAL;
        }
 
-       pr_debug("DMA address: y: %#x  cb: %#x cr: %#x\n",
-                paddr->y, paddr->cb, paddr->cr);
+       pr_debug("DMA address: y: %pad  cb: %pad cr: %pad\n",
+                &paddr->y, &paddr->cb, &paddr->cr);
 
        return 0;
 }
index ebf5b184cce427a1b4274328f7683bd5408af03a..6e0c9988a1919df0ea9b89fb0349f77d7db66e55 100644 (file)
@@ -214,8 +214,8 @@ void camif_hw_set_output_addr(struct camif_vp *vp,
                                                                paddr->cr);
        }
 
-       pr_debug("dst_buf[%d]: %#X, cb: %#X, cr: %#X\n",
-                i, paddr->y, paddr->cb, paddr->cr);
+       pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad\n",
+                i, &paddr->y, &paddr->cb, &paddr->cr);
 }
 
 static void camif_hw_set_out_dma_size(struct camif_vp *vp)
index 357af1ebaeda2791667e8f5c32b12fe7f45bf18a..d79e214ce8ce3e7526027aea3141c16f9a609a39 100644 (file)
@@ -490,14 +490,13 @@ static void job_abort(void *prv)
 {
        struct g2d_ctx *ctx = prv;
        struct g2d_dev *dev = ctx->dev;
-       int ret;
 
        if (dev->curr == NULL) /* No job currently running */
                return;
 
-       ret = wait_event_timeout(dev->irq_queue,
-               dev->curr == NULL,
-               msecs_to_jiffies(G2D_TIMEOUT));
+       wait_event_timeout(dev->irq_queue,
+                          dev->curr == NULL,
+                          msecs_to_jiffies(G2D_TIMEOUT));
 }
 
 static void device_run(void *prv)
index e66acbc2a82d7dcca7dbe106de82b19a68633a51..e525a7c8d885770c7f0e85e3219a387f432a13c2 100644 (file)
@@ -729,7 +729,7 @@ static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
                             ARRAY_SIZE(qtbl_chrominance[quality]));
 }
 
-void exynos4_jpeg_set_huff_tbl(void __iomem *base)
+static void exynos4_jpeg_set_huff_tbl(void __iomem *base)
 {
        exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
                                                        ARRAY_SIZE(hdctbl0));
index d26e1f8465536614201a2a3a66035f3061f95d93..e8c2cad9396272ed9fa6f43c0fbab2699ba0073e 100644 (file)
@@ -233,6 +233,7 @@ void exynos3250_jpeg_set_x(void __iomem *regs, unsigned int x)
        writel(reg, regs + EXYNOS3250_JPGX);
 }
 
+#if 0  /* Currently unused */
 unsigned int exynos3250_jpeg_get_y(void __iomem *regs)
 {
        return readl(regs + EXYNOS3250_JPGY);
@@ -242,6 +243,7 @@ unsigned int exynos3250_jpeg_get_x(void __iomem *regs)
 {
        return readl(regs + EXYNOS3250_JPGX);
 }
+#endif
 
 void exynos3250_jpeg_interrupts_enable(void __iomem *regs)
 {
index da8d6a1a984f84be834c49e0fe21c0a5710ebd89..ab6d6f43c96f1a81361a98b7acc6faa160e368d1 100644 (file)
@@ -23,7 +23,7 @@ void exynos4_jpeg_sw_reset(void __iomem *base)
        reg = readl(base + EXYNOS4_JPEG_CNTL_REG);
        writel(reg & ~EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG);
 
-       ndelay(100000);
+       udelay(100);
 
        writel(reg | EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG);
 }
@@ -151,9 +151,6 @@ void exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt)
 
 void exynos4_jpeg_set_interrupt(void __iomem *base)
 {
-       unsigned int reg;
-
-       reg = readl(base + EXYNOS4_INT_EN_REG) & ~EXYNOS4_INT_EN_MASK;
        writel(EXYNOS4_INT_EN_ALL, base + EXYNOS4_INT_EN_REG);
 }
 
@@ -185,7 +182,7 @@ void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value)
                writel(reg | EXYNOS4_HUF_TBL_EN,
                                        base + EXYNOS4_JPEG_CNTL_REG);
        else
-               writel(reg | ~EXYNOS4_HUF_TBL_EN,
+               writel(reg & ~EXYNOS4_HUF_TBL_EN,
                                        base + EXYNOS4_JPEG_CNTL_REG);
 }
 
@@ -196,9 +193,9 @@ void exynos4_jpeg_set_sys_int_enable(void __iomem *base, int value)
        reg = readl(base + EXYNOS4_JPEG_CNTL_REG) & ~(EXYNOS4_SYS_INT_EN);
 
        if (value == 1)
-               writel(EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
+               writel(reg | EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
        else
-               writel(~EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
+               writel(reg & ~EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
 }
 
 void exynos4_jpeg_set_stream_buf_address(void __iomem *base,
index 52407d7907267e520b81bcc540420f1f2ff34544..e3b8e67e005f12fa21a37045844fce373aef134d 100644 (file)
@@ -324,11 +324,9 @@ int s5p_jpeg_stream_stat_ok(void __iomem *regs)
 
 void s5p_jpeg_clear_int(void __iomem *regs)
 {
-       unsigned long reg;
-
-       reg = readl(regs + S5P_JPGINTST);
+       readl(regs + S5P_JPGINTST);
        writel(S5P_INT_RELEASE, regs + S5P_JPGCOM);
-       reg = readl(regs + S5P_JPGOPR);
+       readl(regs + S5P_JPGOPR);
 }
 
 unsigned int s5p_jpeg_compressed_size(void __iomem *regs)
index d35b0418ab371ec132760182a3f35fe71662e279..165bc86c596267f701cf6997422f953ec412227a 100644 (file)
@@ -37,8 +37,8 @@
 #define S5P_MFC_DEC_NAME       "s5p-mfc-dec"
 #define S5P_MFC_ENC_NAME       "s5p-mfc-enc"
 
-int debug;
-module_param(debug, int, S_IRUGO | S_IWUSR);
+int mfc_debug_level;
+module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages");
 
 /* Helper functions for interrupt processing */
@@ -150,10 +150,10 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work)
                if (!ctx)
                        continue;
                ctx->state = MFCINST_ERROR;
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
-                               &ctx->vq_dst);
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
-                               &ctx->vq_src);
+               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+                                               &ctx->dst_queue, &ctx->vq_dst);
+               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+                                               &ctx->src_queue, &ctx->vq_src);
                clear_work_bit(ctx);
                wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0);
        }
@@ -264,7 +264,12 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
        unsigned int frame_type;
 
        dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev);
-       frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_disp_frame_type, ctx);
+       if (IS_MFCV6_PLUS(dev))
+               frame_type = s5p_mfc_hw_call(dev->mfc_ops,
+                       get_disp_frame_type, ctx);
+       else
+               frame_type = s5p_mfc_hw_call(dev->mfc_ops,
+                       get_dec_frame_type, dev);
 
        /* If frame is same as previous then skip and do not dequeue */
        if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) {
@@ -327,12 +332,12 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
        if (res_change == S5P_FIMV_RES_INCREASE ||
                res_change == S5P_FIMV_RES_DECREASE) {
                ctx->state = MFCINST_RES_CHANGE_INIT;
-               s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
                wake_up_ctx(ctx, reason, err);
                if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                        BUG();
                s5p_mfc_clock_off();
-               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
                return;
        }
        if (ctx->dpb_flush_flag)
@@ -400,7 +405,7 @@ leave_handle_frame:
        if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
                                    || ctx->dst_queue_cnt < ctx->pb_count)
                clear_work_bit(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
        wake_up_ctx(ctx, reason, err);
        if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                BUG();
@@ -409,7 +414,7 @@ leave_handle_frame:
        if (test_bit(0, &dev->enter_suspend))
                wake_up_dev(dev, reason, err);
        else
-               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 }
 
 /* Error handling for interrupt */
@@ -435,10 +440,10 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
                        ctx->state = MFCINST_ERROR;
                        /* Mark all dst buffers as having an error */
                        spin_lock_irqsave(&dev->irqlock, flags);
-                       s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue,
+                       s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
                                                &ctx->dst_queue, &ctx->vq_dst);
                        /* Mark all src buffers as having an error */
-                       s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue,
+                       s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
                                                &ctx->src_queue, &ctx->vq_src);
                        spin_unlock_irqrestore(&dev->irqlock, flags);
                        wake_up_ctx(ctx, reason, err);
@@ -452,7 +457,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
        }
        if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                BUG();
-       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
        s5p_mfc_clock_off();
        wake_up_dev(dev, reason, err);
        return;
@@ -476,7 +481,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
                ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height,
                                dev);
 
-               s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx);
+               s5p_mfc_hw_call_void(dev->mfc_ops, dec_calc_dpb_size, ctx);
 
                ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count,
                                dev);
@@ -503,12 +508,12 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
                        ctx->head_processed = 1;
                }
        }
-       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
        clear_work_bit(ctx);
        if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                BUG();
        s5p_mfc_clock_off();
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        wake_up_ctx(ctx, reason, err);
 }
 
@@ -523,7 +528,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
        if (ctx == NULL)
                return;
        dev = ctx->dev;
-       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
        ctx->int_type = reason;
        ctx->int_err = err;
        ctx->int_cond = 1;
@@ -550,7 +555,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
                s5p_mfc_clock_off();
 
                wake_up(&ctx->queue);
-               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        } else {
                if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                        BUG();
@@ -591,7 +596,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx,
 
        s5p_mfc_clock_off();
        wake_up(&ctx->queue);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 }
 
 /* Interrupt processing */
@@ -628,12 +633,12 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
                if (ctx->c_ops->post_frame_start) {
                        if (ctx->c_ops->post_frame_start(ctx))
                                mfc_err("post_frame_start() failed\n");
-                       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+                       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
                        wake_up_ctx(ctx, reason, err);
                        if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                                BUG();
                        s5p_mfc_clock_off();
-                       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+                       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
                } else {
                        s5p_mfc_handle_frame(ctx, reason, err);
                }
@@ -663,7 +668,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
        case S5P_MFC_R2H_CMD_WAKEUP_RET:
                if (ctx)
                        clear_work_bit(ctx);
-               s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
                wake_up_dev(dev, reason, err);
                clear_bit(0, &dev->hw_lock);
                clear_bit(0, &dev->enter_suspend);
@@ -685,12 +690,12 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
 
        default:
                mfc_debug(2, "Unknown int reason\n");
-               s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
        }
        mfc_debug_leave();
        return IRQ_HANDLED;
 irq_cleanup_hw:
-       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
        ctx->int_type = reason;
        ctx->int_err = err;
        ctx->int_cond = 1;
@@ -699,7 +704,7 @@ irq_cleanup_hw:
 
        s5p_mfc_clock_off();
 
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        mfc_debug(2, "Exit via irq_cleanup_hw\n");
        return IRQ_HANDLED;
 }
@@ -1311,11 +1316,9 @@ static int s5p_mfc_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
-       int pre_power;
 
        if (!m_dev->alloc_ctx)
                return 0;
-       pre_power = atomic_read(&m_dev->pm.power);
        atomic_set(&m_dev->pm.power, 1);
        return 0;
 }
@@ -1328,20 +1331,20 @@ static const struct dev_pm_ops s5p_mfc_pm_ops = {
                           NULL)
 };
 
-struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = {
+static struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = {
        .h264_ctx       = MFC_H264_CTX_BUF_SIZE,
        .non_h264_ctx   = MFC_CTX_BUF_SIZE,
        .dsc            = DESC_BUF_SIZE,
        .shm            = SHARED_BUF_SIZE,
 };
 
-struct s5p_mfc_buf_size buf_size_v5 = {
+static struct s5p_mfc_buf_size buf_size_v5 = {
        .fw     = MAX_FW_SIZE,
        .cpb    = MAX_CPB_SIZE,
        .priv   = &mfc_buf_size_v5,
 };
 
-struct s5p_mfc_buf_align mfc_buf_align_v5 = {
+static struct s5p_mfc_buf_align mfc_buf_align_v5 = {
        .base = MFC_BASE_ALIGN_ORDER,
 };
 
@@ -1354,7 +1357,7 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = {
        .fw_name[0]     = "s5p-mfc.fw",
 };
 
-struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = {
+static struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = {
        .dev_ctx        = MFC_CTX_BUF_SIZE_V6,
        .h264_dec_ctx   = MFC_H264_DEC_CTX_BUF_SIZE_V6,
        .other_dec_ctx  = MFC_OTHER_DEC_CTX_BUF_SIZE_V6,
@@ -1362,13 +1365,13 @@ struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = {
        .other_enc_ctx  = MFC_OTHER_ENC_CTX_BUF_SIZE_V6,
 };
 
-struct s5p_mfc_buf_size buf_size_v6 = {
+static struct s5p_mfc_buf_size buf_size_v6 = {
        .fw     = MAX_FW_SIZE_V6,
        .cpb    = MAX_CPB_SIZE_V6,
        .priv   = &mfc_buf_size_v6,
 };
 
-struct s5p_mfc_buf_align mfc_buf_align_v6 = {
+static struct s5p_mfc_buf_align mfc_buf_align_v6 = {
        .base = 0,
 };
 
@@ -1386,7 +1389,7 @@ static struct s5p_mfc_variant mfc_drvdata_v6 = {
        .fw_name[1]     = "s5p-mfc-v6-v2.fw",
 };
 
-struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = {
+static struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = {
        .dev_ctx        = MFC_CTX_BUF_SIZE_V7,
        .h264_dec_ctx   = MFC_H264_DEC_CTX_BUF_SIZE_V7,
        .other_dec_ctx  = MFC_OTHER_DEC_CTX_BUF_SIZE_V7,
@@ -1394,13 +1397,13 @@ struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = {
        .other_enc_ctx  = MFC_OTHER_ENC_CTX_BUF_SIZE_V7,
 };
 
-struct s5p_mfc_buf_size buf_size_v7 = {
+static struct s5p_mfc_buf_size buf_size_v7 = {
        .fw     = MAX_FW_SIZE_V7,
        .cpb    = MAX_CPB_SIZE_V7,
        .priv   = &mfc_buf_size_v7,
 };
 
-struct s5p_mfc_buf_align mfc_buf_align_v7 = {
+static struct s5p_mfc_buf_align mfc_buf_align_v7 = {
        .base = 0,
 };
 
@@ -1413,7 +1416,7 @@ static struct s5p_mfc_variant mfc_drvdata_v7 = {
        .fw_name[0]     = "s5p-mfc-v7.fw",
 };
 
-struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = {
+static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = {
        .dev_ctx        = MFC_CTX_BUF_SIZE_V8,
        .h264_dec_ctx   = MFC_H264_DEC_CTX_BUF_SIZE_V8,
        .other_dec_ctx  = MFC_OTHER_DEC_CTX_BUF_SIZE_V8,
@@ -1421,13 +1424,13 @@ struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = {
        .other_enc_ctx  = MFC_OTHER_ENC_CTX_BUF_SIZE_V8,
 };
 
-struct s5p_mfc_buf_size buf_size_v8 = {
+static struct s5p_mfc_buf_size buf_size_v8 = {
        .fw     = MAX_FW_SIZE_V8,
        .cpb    = MAX_CPB_SIZE_V8,
        .priv   = &mfc_buf_size_v8,
 };
 
-struct s5p_mfc_buf_align mfc_buf_align_v8 = {
+static struct s5p_mfc_buf_align mfc_buf_align_v8 = {
        .base = 0,
 };
 
index 9a6efd6c13292dec6ab9ba3ba3c052ea9772f24c..8c4739ca16d67d55b0556c1f8880092759232b56 100644 (file)
@@ -14,6 +14,7 @@
 #include "s5p_mfc_cmd.h"
 #include "s5p_mfc_common.h"
 #include "s5p_mfc_debug.h"
+#include "s5p_mfc_cmd_v5.h"
 
 /* This function is used to send a command to the MFC */
 static int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd,
index ec1a5947ed7d00649dcdaf3a7e8b151695fd6902..f17609669b96a275d06001a3053f43f97fa74406 100644 (file)
@@ -16,6 +16,7 @@
 #include "s5p_mfc_debug.h"
 #include "s5p_mfc_intr.h"
 #include "s5p_mfc_opr.h"
+#include "s5p_mfc_cmd_v6.h"
 
 static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd,
                                struct s5p_mfc_cmd_args *args)
index 01816ffb384b8834fe816e899f9d38d3ea61d472..3e41ca1293ed364088f75c830f0a4ee5d7c502d0 100644 (file)
@@ -698,6 +698,12 @@ struct mfc_control {
 #define s5p_mfc_hw_call(f, op, args...) \
        ((f && f->op) ? f->op(args) : -ENODEV)
 
+#define s5p_mfc_hw_call_void(f, op, args...) \
+do { \
+       if (f && f->op) \
+               f->op(args); \
+} while (0)
+
 #define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh)
 #define ctrl_to_ctx(__ctrl) \
        container_of((__ctrl)->handler, struct s5p_mfc_ctx, ctrl_handler)
index ca9f789228329c9d2f0de9b6fadc34d957f2cadb..0c885a8a0e9fcd4341103991f5da3e788defbc89 100644 (file)
@@ -21,6 +21,7 @@
 #include "s5p_mfc_intr.h"
 #include "s5p_mfc_opr.h"
 #include "s5p_mfc_pm.h"
+#include "s5p_mfc_ctrl.h"
 
 /* Allocate memory for firmware */
 int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
@@ -188,12 +189,12 @@ static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
 {
        if (IS_MFCV6_PLUS(dev)) {
                mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6);
-               mfc_debug(2, "Base Address : %08x\n", dev->bank1);
+               mfc_debug(2, "Base Address : %pad\n", &dev->bank1);
        } else {
                mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A);
                mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B);
-               mfc_debug(2, "Bank1: %08x, Bank2: %08x\n",
-                               dev->bank1, dev->bank2);
+               mfc_debug(2, "Bank1: %pad, Bank2: %pad\n",
+                               &dev->bank1, &dev->bank2);
        }
 }
 
@@ -257,9 +258,9 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
                s5p_mfc_clock_off();
                return ret;
        }
-       mfc_debug(2, "Ok, now will write a command to init the system\n");
+       mfc_debug(2, "Ok, now will wait for completion of hardware init\n");
        if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) {
-               mfc_err("Failed to load firmware\n");
+               mfc_err("Failed to init hardware\n");
                s5p_mfc_reset(dev);
                s5p_mfc_clock_off();
                return -EIO;
@@ -293,7 +294,7 @@ void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
        s5p_mfc_clock_on();
 
        s5p_mfc_reset(dev);
-       s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, release_dev_context_buffer, dev);
 
        s5p_mfc_clock_off();
 }
@@ -396,7 +397,7 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
 
        set_work_bit_irqsave(ctx);
        s5p_mfc_clean_ctx_int_flags(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        if (s5p_mfc_wait_for_done_ctx(ctx,
                S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
                /* Error or timeout */
@@ -410,9 +411,9 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
 
 err_free_desc_buf:
        if (ctx->type == MFCINST_DECODER)
-               s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
+               s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx);
 err_free_inst_buf:
-       s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
+       s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx);
 err:
        return ret;
 }
@@ -422,17 +423,17 @@ void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
        ctx->state = MFCINST_RETURN_INST;
        set_work_bit_irqsave(ctx);
        s5p_mfc_clean_ctx_int_flags(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        /* Wait until instance is returned or timeout occurred */
        if (s5p_mfc_wait_for_done_ctx(ctx,
                                S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0))
                mfc_err("Err returning instance\n");
 
        /* Free resources */
-       s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
+       s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx);
+       s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx);
        if (ctx->type == MFCINST_DECODER)
-               s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
+               s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx);
 
        ctx->inst_no = MFC_NO_INSTANCE_SET;
        ctx->state = MFCINST_FREE;
index 8e608f5aa0d7c866009a06f7b203c51d136040f1..5936923c631c9f9e1c2d6173cd13ce88adf2a9a6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * drivers/media/platform/samsung/mfc5/s5p_mfc_debug.h
+ * drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
  *
  * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
  * This file contains debug macros
 #define DEBUG
 
 #ifdef DEBUG
-extern int debug;
+extern int mfc_debug_level;
 
 #define mfc_debug(level, fmt, args...)                         \
        do {                                                    \
-               if (debug >= level)                             \
+               if (mfc_debug_level >= level)                   \
                        printk(KERN_DEBUG "%s:%d: " fmt,        \
                                __func__, __LINE__, ##args);    \
        } while (0)
index 9103258b7df386b8434d7b89e2e92240be1feb5f..a98fe023deaf79e5879d3d9ae5e2317bd44204e8 100644 (file)
@@ -283,17 +283,13 @@ static int vidioc_querycap(struct file *file, void *priv,
 
 /* Enumerate format */
 static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
-                                                       bool mplane, bool out)
+                                                       bool out)
 {
        struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_fmt *fmt;
        int i, j = 0;
 
        for (i = 0; i < ARRAY_SIZE(formats); ++i) {
-               if (mplane && formats[i].num_planes == 1)
-                       continue;
-               else if (!mplane && formats[i].num_planes > 1)
-                       continue;
                if (out && formats[i].type != MFC_FMT_DEC)
                        continue;
                else if (!out && formats[i].type != MFC_FMT_RAW)
@@ -313,28 +309,16 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
        return 0;
 }
 
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
-                                                       struct v4l2_fmtdesc *f)
-{
-       return vidioc_enum_fmt(file, f, false, false);
-}
-
 static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
                                                        struct v4l2_fmtdesc *f)
 {
-       return vidioc_enum_fmt(file, f, true, false);
-}
-
-static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
-                                                       struct v4l2_fmtdesc *f)
-{
-       return vidioc_enum_fmt(file, f, false, true);
+       return vidioc_enum_fmt(file, f, false);
 }
 
 static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv,
                                                        struct v4l2_fmtdesc *f)
 {
-       return vidioc_enum_fmt(file, f, true, true);
+       return vidioc_enum_fmt(file, f, true);
 }
 
 /* Get format */
@@ -543,7 +527,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
                ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
                if (ret)
                        goto out;
-               s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
+               s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx);
                ctx->dst_bufs_cnt = 0;
        } else if (ctx->capture_state == QUEUE_FREE) {
                WARN_ON(ctx->dst_bufs_cnt != 0);
@@ -571,7 +555,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
 
                if (s5p_mfc_ctx_ready(ctx))
                        set_work_bit_irqsave(ctx);
-               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
                s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET,
                                          0);
        } else {
@@ -823,8 +807,8 @@ static int vidioc_g_crop(struct file *file, void *priv,
        return 0;
 }
 
-int vidioc_decoder_cmd(struct file *file, void *priv,
-                                               struct v4l2_decoder_cmd *cmd)
+static int vidioc_decoder_cmd(struct file *file, void *priv,
+                             struct v4l2_decoder_cmd *cmd)
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
        struct s5p_mfc_dev *dev = ctx->dev;
@@ -846,7 +830,7 @@ int vidioc_decoder_cmd(struct file *file, void *priv,
                        if (s5p_mfc_ctx_ready(ctx))
                                set_work_bit_irqsave(ctx);
                        spin_unlock_irqrestore(&dev->irqlock, flags);
-                       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+                       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
                } else {
                        mfc_err("EOS: marking last buffer of stream");
                        buf = list_entry(ctx->src_queue.prev,
@@ -881,9 +865,7 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh,
 /* v4l2_ioctl_ops */
 static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
        .vidioc_querycap = vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
        .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
-       .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
        .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
        .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
        .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
@@ -990,7 +972,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
        if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
                if (ctx->capture_state == QUEUE_BUFS_MMAPED)
                        return 0;
-               for (i = 0; i <= ctx->src_fmt->num_planes ; i++) {
+               for (i = 0; i < ctx->dst_fmt->num_planes; i++) {
                        if (IS_ERR_OR_NULL(ERR_PTR(
                                        vb2_dma_contig_plane_dma_addr(vb, i)))) {
                                mfc_err("Plane mem not allocated\n");
@@ -1044,7 +1026,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
        /* If context is ready then dev = work->data;schedule it to run */
        if (s5p_mfc_ctx_ready(ctx))
                set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        return 0;
 }
 
@@ -1065,8 +1047,8 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
        }
        if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
                spin_lock_irqsave(&dev->irqlock, flags);
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
-                               &ctx->vq_dst);
+               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+                                               &ctx->dst_queue, &ctx->vq_dst);
                INIT_LIST_HEAD(&ctx->dst_queue);
                ctx->dst_queue_cnt = 0;
                ctx->dpb_flush_flag = 1;
@@ -1076,7 +1058,7 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
                        ctx->state = MFCINST_FLUSH;
                        set_work_bit_irqsave(ctx);
                        s5p_mfc_clean_ctx_int_flags(ctx);
-                       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+                       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
                        if (s5p_mfc_wait_for_done_ctx(ctx,
                                S5P_MFC_R2H_CMD_DPB_FLUSH_RET, 0))
                                mfc_err("Err flushing buffers\n");
@@ -1084,8 +1066,8 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
        }
        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
                spin_lock_irqsave(&dev->irqlock, flags);
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
-                               &ctx->vq_src);
+               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+                                               &ctx->src_queue, &ctx->vq_src);
                INIT_LIST_HEAD(&ctx->src_queue);
                ctx->src_queue_cnt = 0;
                spin_unlock_irqrestore(&dev->irqlock, flags);
@@ -1124,7 +1106,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
        }
        if (s5p_mfc_ctx_ready(ctx))
                set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 }
 
 static struct vb2_ops s5p_mfc_dec_qops = {
@@ -1220,7 +1202,7 @@ void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx)
        else
                f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT;
        ctx->dst_fmt = find_format(&f, MFC_FMT_RAW);
-       mfc_debug(2, "Default src_fmt is %x, dest_fmt is %x\n",
-                       (unsigned int)ctx->src_fmt, (unsigned int)ctx->dst_fmt);
+       mfc_debug(2, "Default src_fmt is %p, dest_fmt is %p\n",
+                       ctx->src_fmt, ctx->dst_fmt);
 }
 
index d26b2484ca10b04576e56437c47e4b38473b4cd8..a904a1c7bb21e70bf8b29719a0c537b87bc0e465 100644 (file)
@@ -739,14 +739,11 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
 static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_buf *mb_entry;
-       unsigned long mb_y_addr, mb_c_addr;
 
        /* move buffers in ref queue to src queue */
        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_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);
@@ -770,7 +767,7 @@ static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx)
        dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
        dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
        dst_size = vb2_plane_size(dst_mb->b, 0);
-       s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
+       s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
                        dst_size);
        spin_unlock_irqrestore(&dev->irqlock, flags);
        return 0;
@@ -803,7 +800,7 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
                ctx->state = MFCINST_RUNNING;
                if (s5p_mfc_ctx_ready(ctx))
                        set_work_bit_irqsave(ctx);
-               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        } else {
                enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops,
                                get_enc_dpb_count, dev);
@@ -828,15 +825,15 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
        src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
        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_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx, src_y_addr,
-                       src_c_addr);
+       s5p_mfc_hw_call_void(dev->mfc_ops, 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_dma_addr(dst_mb->b, 0);
        dst_size = vb2_plane_size(dst_mb->b, 0);
-       s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
+       s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
                        dst_size);
        spin_unlock_irqrestore(&dev->irqlock, flags);
 
@@ -861,7 +858,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
                  mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
        spin_lock_irqsave(&dev->irqlock, flags);
        if (slice_type >= 0) {
-               s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx,
+               s5p_mfc_hw_call_void(dev->mfc_ops, 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_dma_addr(mb_entry->b, 0);
@@ -954,17 +951,13 @@ static int vidioc_querycap(struct file *file, void *priv,
 }
 
 static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
-                                                       bool mplane, bool out)
+                                                       bool out)
 {
        struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_fmt *fmt;
        int i, j = 0;
 
        for (i = 0; i < ARRAY_SIZE(formats); ++i) {
-               if (mplane && formats[i].num_planes == 1)
-                       continue;
-               else if (!mplane && formats[i].num_planes > 1)
-                       continue;
                if (out && formats[i].type != MFC_FMT_RAW)
                        continue;
                else if (!out && formats[i].type != MFC_FMT_ENC)
@@ -984,28 +977,16 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
        return -EINVAL;
 }
 
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
-                                  struct v4l2_fmtdesc *f)
-{
-       return vidioc_enum_fmt(file, f, false, false);
-}
-
 static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
                                          struct v4l2_fmtdesc *f)
 {
-       return vidioc_enum_fmt(file, f, true, false);
-}
-
-static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
-                                  struct v4l2_fmtdesc *f)
-{
-       return vidioc_enum_fmt(file, f, false, true);
+       return vidioc_enum_fmt(file, f, false);
 }
 
 static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
                                          struct v4l2_fmtdesc *f)
 {
-       return vidioc_enum_fmt(file, f, true, true);
+       return vidioc_enum_fmt(file, f, true);
 }
 
 static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
@@ -1127,7 +1108,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
                        pix_fmt_mp->width, pix_fmt_mp->height,
                        ctx->img_width, ctx->img_height);
 
-               s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx);
+               s5p_mfc_hw_call_void(dev->mfc_ops, enc_calc_src_size, ctx);
                pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
                pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
                pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
@@ -1681,8 +1662,8 @@ static int vidioc_g_parm(struct file *file, void *priv,
        return 0;
 }
 
-int vidioc_encoder_cmd(struct file *file, void *priv,
-                                               struct v4l2_encoder_cmd *cmd)
+static int vidioc_encoder_cmd(struct file *file, void *priv,
+                             struct v4l2_encoder_cmd *cmd)
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
        struct s5p_mfc_dev *dev = ctx->dev;
@@ -1704,7 +1685,7 @@ int vidioc_encoder_cmd(struct file *file, void *priv,
                        if (s5p_mfc_ctx_ready(ctx))
                                set_work_bit_irqsave(ctx);
                        spin_unlock_irqrestore(&dev->irqlock, flags);
-                       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+                       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
                } else {
                        mfc_debug(2, "EOS: marking last buffer of stream\n");
                        buf = list_entry(ctx->src_queue.prev,
@@ -1736,9 +1717,7 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh,
 
 static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
        .vidioc_querycap = vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
        .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
-       .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
        .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
        .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
        .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
@@ -1771,13 +1750,13 @@ 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_dma_addr(vb, i)) {
+               dma_addr_t dma = vb2_dma_contig_plane_dma_addr(vb, i);
+               if (!dma) {
                        mfc_err("failed to get plane cookie\n");
                        return -EINVAL;
                }
-               mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx\n",
-                         vb->v4l2_buf.index, i,
-                         vb2_dma_contig_plane_dma_addr(vb, i));
+               mfc_debug(2, "index: %d, plane[%d] cookie: %pad\n",
+                         vb->v4l2_buf.index, i, &dma);
        }
        return 0;
 }
@@ -1897,7 +1876,7 @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
                ret = check_vb_with_fmt(ctx->dst_fmt, vb);
                if (ret < 0)
                        return ret;
-               mfc_debug(2, "plane size: %ld, dst size: %d\n",
+               mfc_debug(2, "plane size: %ld, dst size: %zu\n",
                        vb2_plane_size(vb, 0), ctx->enc_dst_buf_size);
                if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) {
                        mfc_err("plane size is too small for capture\n");
@@ -1948,7 +1927,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
        /* If context is ready then dev = work->data;schedule it to run */
        if (s5p_mfc_ctx_ready(ctx))
                set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 
        return 0;
 }
@@ -1969,14 +1948,14 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
        ctx->state = MFCINST_FINISHED;
        spin_lock_irqsave(&dev->irqlock, flags);
        if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
-                               &ctx->vq_dst);
+               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+                                               &ctx->dst_queue, &ctx->vq_dst);
                INIT_LIST_HEAD(&ctx->dst_queue);
                ctx->dst_queue_cnt = 0;
        }
        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
                cleanup_ref_queue(ctx);
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
+               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
                                &ctx->vq_src);
                INIT_LIST_HEAD(&ctx->src_queue);
                ctx->src_queue_cnt = 0;
@@ -2017,7 +1996,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
        }
        if (s5p_mfc_ctx_ready(ctx))
                set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 }
 
 static struct vb2_ops s5p_mfc_enc_qops = {
index c9a227428e6ad38c99d7fa2e88c533cf8a39dadc..00a1d8b2a8c236195259885bc0aaaca7a549fd37 100644 (file)
@@ -41,7 +41,7 @@ int s5p_mfc_alloc_priv_buf(struct device *dev,
                                        struct s5p_mfc_priv_buf *b)
 {
 
-       mfc_debug(3, "Allocating priv: %d\n", b->size);
+       mfc_debug(3, "Allocating priv: %zu\n", b->size);
 
        b->virt = dma_alloc_coherent(dev, b->size, &b->dma, GFP_KERNEL);
 
@@ -50,7 +50,7 @@ int s5p_mfc_alloc_priv_buf(struct device *dev,
                return -ENOMEM;
        }
 
-       mfc_debug(3, "Allocated addr %p %08x\n", b->virt, b->dma);
+       mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma);
        return 0;
 }
 
index 7a7ad32ee60883e81544cf5a036df33c08a5039d..de2b8c69daa535dd6ea906dcd476638e3185c72f 100644 (file)
 struct s5p_mfc_regs {
 
        /* codec common registers */
-       void *risc_on;
-       void *risc2host_int;
-       void *host2risc_int;
-       void *risc_base_address;
-       void *mfc_reset;
-       void *host2risc_command;
-       void *risc2host_command;
-       void *mfc_bus_reset_ctrl;
-       void *firmware_version;
-       void *instance_id;
-       void *codec_type;
-       void *context_mem_addr;
-       void *context_mem_size;
-       void *pixel_format;
-       void *metadata_enable;
-       void *mfc_version;
-       void *dbg_info_enable;
-       void *dbg_buffer_addr;
-       void *dbg_buffer_size;
-       void *hed_control;
-       void *mfc_timeout_value;
-       void *hed_shared_mem_addr;
-       void *dis_shared_mem_addr;/* only v7 */
-       void *ret_instance_id;
-       void *error_code;
-       void *dbg_buffer_output_size;
-       void *metadata_status;
-       void *metadata_addr_mb_info;
-       void *metadata_size_mb_info;
-       void *dbg_info_stage_counter;
+       volatile void __iomem *risc_on;
+       volatile void __iomem *risc2host_int;
+       volatile void __iomem *host2risc_int;
+       volatile void __iomem *risc_base_address;
+       volatile void __iomem *mfc_reset;
+       volatile void __iomem *host2risc_command;
+       volatile void __iomem *risc2host_command;
+       volatile void __iomem *mfc_bus_reset_ctrl;
+       volatile void __iomem *firmware_version;
+       volatile void __iomem *instance_id;
+       volatile void __iomem *codec_type;
+       volatile void __iomem *context_mem_addr;
+       volatile void __iomem *context_mem_size;
+       volatile void __iomem *pixel_format;
+       volatile void __iomem *metadata_enable;
+       volatile void __iomem *mfc_version;
+       volatile void __iomem *dbg_info_enable;
+       volatile void __iomem *dbg_buffer_addr;
+       volatile void __iomem *dbg_buffer_size;
+       volatile void __iomem *hed_control;
+       volatile void __iomem *mfc_timeout_value;
+       volatile void __iomem *hed_shared_mem_addr;
+       volatile void __iomem *dis_shared_mem_addr;/* only v7 */
+       volatile void __iomem *ret_instance_id;
+       volatile void __iomem *error_code;
+       volatile void __iomem *dbg_buffer_output_size;
+       volatile void __iomem *metadata_status;
+       volatile void __iomem *metadata_addr_mb_info;
+       volatile void __iomem *metadata_size_mb_info;
+       volatile void __iomem *dbg_info_stage_counter;
 
        /* decoder registers */
-       void *d_crc_ctrl;
-       void *d_dec_options;
-       void *d_display_delay;
-       void *d_set_frame_width;
-       void *d_set_frame_height;
-       void *d_sei_enable;
-       void *d_min_num_dpb;
-       void *d_min_first_plane_dpb_size;
-       void *d_min_second_plane_dpb_size;
-       void *d_min_third_plane_dpb_size;/* only v8 */
-       void *d_min_num_mv;
-       void *d_mvc_num_views;
-       void *d_min_num_dis;/* only v7 */
-       void *d_min_first_dis_size;/* only v7 */
-       void *d_min_second_dis_size;/* only v7 */
-       void *d_min_third_dis_size;/* only v7 */
-       void *d_post_filter_luma_dpb0;/*  v7 and v8 */
-       void *d_post_filter_luma_dpb1;/* v7 and v8 */
-       void *d_post_filter_luma_dpb2;/* only v7 */
-       void *d_post_filter_chroma_dpb0;/* v7 and v8 */
-       void *d_post_filter_chroma_dpb1;/* v7 and v8 */
-       void *d_post_filter_chroma_dpb2;/* only v7 */
-       void *d_num_dpb;
-       void *d_num_mv;
-       void *d_init_buffer_options;
-       void *d_first_plane_dpb_stride_size;/* only v8 */
-       void *d_second_plane_dpb_stride_size;/* only v8 */
-       void *d_third_plane_dpb_stride_size;/* only v8 */
-       void *d_first_plane_dpb_size;
-       void *d_second_plane_dpb_size;
-       void *d_third_plane_dpb_size;/* only v8 */
-       void *d_mv_buffer_size;
-       void *d_first_plane_dpb;
-       void *d_second_plane_dpb;
-       void *d_third_plane_dpb;
-       void *d_mv_buffer;
-       void *d_scratch_buffer_addr;
-       void *d_scratch_buffer_size;
-       void *d_metadata_buffer_addr;
-       void *d_metadata_buffer_size;
-       void *d_nal_start_options;/* v7 and v8 */
-       void *d_cpb_buffer_addr;
-       void *d_cpb_buffer_size;
-       void *d_available_dpb_flag_upper;
-       void *d_available_dpb_flag_lower;
-       void *d_cpb_buffer_offset;
-       void *d_slice_if_enable;
-       void *d_picture_tag;
-       void *d_stream_data_size;
-       void *d_dynamic_dpb_flag_upper;/* v7 and v8 */
-       void *d_dynamic_dpb_flag_lower;/* v7 and v8 */
-       void *d_display_frame_width;
-       void *d_display_frame_height;
-       void *d_display_status;
-       void *d_display_first_plane_addr;
-       void *d_display_second_plane_addr;
-       void *d_display_third_plane_addr;/* only v8 */
-       void *d_display_frame_type;
-       void *d_display_crop_info1;
-       void *d_display_crop_info2;
-       void *d_display_picture_profile;
-       void *d_display_luma_crc;/* v7 and v8 */
-       void *d_display_chroma0_crc;/* v7 and v8 */
-       void *d_display_chroma1_crc;/* only v8 */
-       void *d_display_luma_crc_top;/* only v6 */
-       void *d_display_chroma_crc_top;/* only v6 */
-       void *d_display_luma_crc_bot;/* only v6 */
-       void *d_display_chroma_crc_bot;/* only v6 */
-       void *d_display_aspect_ratio;
-       void *d_display_extended_ar;
-       void *d_decoded_frame_width;
-       void *d_decoded_frame_height;
-       void *d_decoded_status;
-       void *d_decoded_first_plane_addr;
-       void *d_decoded_second_plane_addr;
-       void *d_decoded_third_plane_addr;/* only v8 */
-       void *d_decoded_frame_type;
-       void *d_decoded_crop_info1;
-       void *d_decoded_crop_info2;
-       void *d_decoded_picture_profile;
-       void *d_decoded_nal_size;
-       void *d_decoded_luma_crc;
-       void *d_decoded_chroma0_crc;
-       void *d_decoded_chroma1_crc;/* only v8 */
-       void *d_ret_picture_tag_top;
-       void *d_ret_picture_tag_bot;
-       void *d_ret_picture_time_top;
-       void *d_ret_picture_time_bot;
-       void *d_chroma_format;
-       void *d_vc1_info;/* v7 and v8 */
-       void *d_mpeg4_info;
-       void *d_h264_info;
-       void *d_metadata_addr_concealed_mb;
-       void *d_metadata_size_concealed_mb;
-       void *d_metadata_addr_vc1_param;
-       void *d_metadata_size_vc1_param;
-       void *d_metadata_addr_sei_nal;
-       void *d_metadata_size_sei_nal;
-       void *d_metadata_addr_vui;
-       void *d_metadata_size_vui;
-       void *d_metadata_addr_mvcvui;/* v7 and v8 */
-       void *d_metadata_size_mvcvui;/* v7 and v8 */
-       void *d_mvc_view_id;
-       void *d_frame_pack_sei_avail;
-       void *d_frame_pack_arrgment_id;
-       void *d_frame_pack_sei_info;
-       void *d_frame_pack_grid_pos;
-       void *d_display_recovery_sei_info;/* v7 and v8 */
-       void *d_decoded_recovery_sei_info;/* v7 and v8 */
-       void *d_display_first_addr;/* only v7 */
-       void *d_display_second_addr;/* only v7 */
-       void *d_display_third_addr;/* only v7 */
-       void *d_decoded_first_addr;/* only v7 */
-       void *d_decoded_second_addr;/* only v7 */
-       void *d_decoded_third_addr;/* only v7 */
-       void *d_used_dpb_flag_upper;/* v7 and v8 */
-       void *d_used_dpb_flag_lower;/* v7 and v8 */
+       volatile void __iomem *d_crc_ctrl;
+       volatile void __iomem *d_dec_options;
+       volatile void __iomem *d_display_delay;
+       volatile void __iomem *d_set_frame_width;
+       volatile void __iomem *d_set_frame_height;
+       volatile void __iomem *d_sei_enable;
+       volatile void __iomem *d_min_num_dpb;
+       volatile void __iomem *d_min_first_plane_dpb_size;
+       volatile void __iomem *d_min_second_plane_dpb_size;
+       volatile void __iomem *d_min_third_plane_dpb_size;/* only v8 */
+       volatile void __iomem *d_min_num_mv;
+       volatile void __iomem *d_mvc_num_views;
+       volatile void __iomem *d_min_num_dis;/* only v7 */
+       volatile void __iomem *d_min_first_dis_size;/* only v7 */
+       volatile void __iomem *d_min_second_dis_size;/* only v7 */
+       volatile void __iomem *d_min_third_dis_size;/* only v7 */
+       volatile void __iomem *d_post_filter_luma_dpb0;/*  v7 and v8 */
+       volatile void __iomem *d_post_filter_luma_dpb1;/* v7 and v8 */
+       volatile void __iomem *d_post_filter_luma_dpb2;/* only v7 */
+       volatile void __iomem *d_post_filter_chroma_dpb0;/* v7 and v8 */
+       volatile void __iomem *d_post_filter_chroma_dpb1;/* v7 and v8 */
+       volatile void __iomem *d_post_filter_chroma_dpb2;/* only v7 */
+       volatile void __iomem *d_num_dpb;
+       volatile void __iomem *d_num_mv;
+       volatile void __iomem *d_init_buffer_options;
+       volatile void __iomem *d_first_plane_dpb_stride_size;/* only v8 */
+       volatile void __iomem *d_second_plane_dpb_stride_size;/* only v8 */
+       volatile void __iomem *d_third_plane_dpb_stride_size;/* only v8 */
+       volatile void __iomem *d_first_plane_dpb_size;
+       volatile void __iomem *d_second_plane_dpb_size;
+       volatile void __iomem *d_third_plane_dpb_size;/* only v8 */
+       volatile void __iomem *d_mv_buffer_size;
+       volatile void __iomem *d_first_plane_dpb;
+       volatile void __iomem *d_second_plane_dpb;
+       volatile void __iomem *d_third_plane_dpb;
+       volatile void __iomem *d_mv_buffer;
+       volatile void __iomem *d_scratch_buffer_addr;
+       volatile void __iomem *d_scratch_buffer_size;
+       volatile void __iomem *d_metadata_buffer_addr;
+       volatile void __iomem *d_metadata_buffer_size;
+       volatile void __iomem *d_nal_start_options;/* v7 and v8 */
+       volatile void __iomem *d_cpb_buffer_addr;
+       volatile void __iomem *d_cpb_buffer_size;
+       volatile void __iomem *d_available_dpb_flag_upper;
+       volatile void __iomem *d_available_dpb_flag_lower;
+       volatile void __iomem *d_cpb_buffer_offset;
+       volatile void __iomem *d_slice_if_enable;
+       volatile void __iomem *d_picture_tag;
+       volatile void __iomem *d_stream_data_size;
+       volatile void __iomem *d_dynamic_dpb_flag_upper;/* v7 and v8 */
+       volatile void __iomem *d_dynamic_dpb_flag_lower;/* v7 and v8 */
+       volatile void __iomem *d_display_frame_width;
+       volatile void __iomem *d_display_frame_height;
+       volatile void __iomem *d_display_status;
+       volatile void __iomem *d_display_first_plane_addr;
+       volatile void __iomem *d_display_second_plane_addr;
+       volatile void __iomem *d_display_third_plane_addr;/* only v8 */
+       volatile void __iomem *d_display_frame_type;
+       volatile void __iomem *d_display_crop_info1;
+       volatile void __iomem *d_display_crop_info2;
+       volatile void __iomem *d_display_picture_profile;
+       volatile void __iomem *d_display_luma_crc;/* v7 and v8 */
+       volatile void __iomem *d_display_chroma0_crc;/* v7 and v8 */
+       volatile void __iomem *d_display_chroma1_crc;/* only v8 */
+       volatile void __iomem *d_display_luma_crc_top;/* only v6 */
+       volatile void __iomem *d_display_chroma_crc_top;/* only v6 */
+       volatile void __iomem *d_display_luma_crc_bot;/* only v6 */
+       volatile void __iomem *d_display_chroma_crc_bot;/* only v6 */
+       volatile void __iomem *d_display_aspect_ratio;
+       volatile void __iomem *d_display_extended_ar;
+       volatile void __iomem *d_decoded_frame_width;
+       volatile void __iomem *d_decoded_frame_height;
+       volatile void __iomem *d_decoded_status;
+       volatile void __iomem *d_decoded_first_plane_addr;
+       volatile void __iomem *d_decoded_second_plane_addr;
+       volatile void __iomem *d_decoded_third_plane_addr;/* only v8 */
+       volatile void __iomem *d_decoded_frame_type;
+       volatile void __iomem *d_decoded_crop_info1;
+       volatile void __iomem *d_decoded_crop_info2;
+       volatile void __iomem *d_decoded_picture_profile;
+       volatile void __iomem *d_decoded_nal_size;
+       volatile void __iomem *d_decoded_luma_crc;
+       volatile void __iomem *d_decoded_chroma0_crc;
+       volatile void __iomem *d_decoded_chroma1_crc;/* only v8 */
+       volatile void __iomem *d_ret_picture_tag_top;
+       volatile void __iomem *d_ret_picture_tag_bot;
+       volatile void __iomem *d_ret_picture_time_top;
+       volatile void __iomem *d_ret_picture_time_bot;
+       volatile void __iomem *d_chroma_format;
+       volatile void __iomem *d_vc1_info;/* v7 and v8 */
+       volatile void __iomem *d_mpeg4_info;
+       volatile void __iomem *d_h264_info;
+       volatile void __iomem *d_metadata_addr_concealed_mb;
+       volatile void __iomem *d_metadata_size_concealed_mb;
+       volatile void __iomem *d_metadata_addr_vc1_param;
+       volatile void __iomem *d_metadata_size_vc1_param;
+       volatile void __iomem *d_metadata_addr_sei_nal;
+       volatile void __iomem *d_metadata_size_sei_nal;
+       volatile void __iomem *d_metadata_addr_vui;
+       volatile void __iomem *d_metadata_size_vui;
+       volatile void __iomem *d_metadata_addr_mvcvui;/* v7 and v8 */
+       volatile void __iomem *d_metadata_size_mvcvui;/* v7 and v8 */
+       volatile void __iomem *d_mvc_view_id;
+       volatile void __iomem *d_frame_pack_sei_avail;
+       volatile void __iomem *d_frame_pack_arrgment_id;
+       volatile void __iomem *d_frame_pack_sei_info;
+       volatile void __iomem *d_frame_pack_grid_pos;
+       volatile void __iomem *d_display_recovery_sei_info;/* v7 and v8 */
+       volatile void __iomem *d_decoded_recovery_sei_info;/* v7 and v8 */
+       volatile void __iomem *d_display_first_addr;/* only v7 */
+       volatile void __iomem *d_display_second_addr;/* only v7 */
+       volatile void __iomem *d_display_third_addr;/* only v7 */
+       volatile void __iomem *d_decoded_first_addr;/* only v7 */
+       volatile void __iomem *d_decoded_second_addr;/* only v7 */
+       volatile void __iomem *d_decoded_third_addr;/* only v7 */
+       volatile void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */
+       volatile void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */
 
        /* encoder registers */
-       void *e_frame_width;
-       void *e_frame_height;
-       void *e_cropped_frame_width;
-       void *e_cropped_frame_height;
-       void *e_frame_crop_offset;
-       void *e_enc_options;
-       void *e_picture_profile;
-       void *e_vbv_buffer_size;
-       void *e_vbv_init_delay;
-       void *e_fixed_picture_qp;
-       void *e_rc_config;
-       void *e_rc_qp_bound;
-       void *e_rc_qp_bound_pb;/* v7 and v8 */
-       void *e_rc_mode;
-       void *e_mb_rc_config;
-       void *e_padding_ctrl;
-       void *e_air_threshold;
-       void *e_mv_hor_range;
-       void *e_mv_ver_range;
-       void *e_num_dpb;
-       void *e_luma_dpb;
-       void *e_chroma_dpb;
-       void *e_me_buffer;
-       void *e_scratch_buffer_addr;
-       void *e_scratch_buffer_size;
-       void *e_tmv_buffer0;
-       void *e_tmv_buffer1;
-       void *e_ir_buffer_addr;/* v7 and v8 */
-       void *e_source_first_plane_addr;
-       void *e_source_second_plane_addr;
-       void *e_source_third_plane_addr;/* v7 and v8 */
-       void *e_source_first_plane_stride;/* v7 and v8 */
-       void *e_source_second_plane_stride;/* v7 and v8 */
-       void *e_source_third_plane_stride;/* v7 and v8 */
-       void *e_stream_buffer_addr;
-       void *e_stream_buffer_size;
-       void *e_roi_buffer_addr;
-       void *e_param_change;
-       void *e_ir_size;
-       void *e_gop_config;
-       void *e_mslice_mode;
-       void *e_mslice_size_mb;
-       void *e_mslice_size_bits;
-       void *e_frame_insertion;
-       void *e_rc_frame_rate;
-       void *e_rc_bit_rate;
-       void *e_rc_roi_ctrl;
-       void *e_picture_tag;
-       void *e_bit_count_enable;
-       void *e_max_bit_count;
-       void *e_min_bit_count;
-       void *e_metadata_buffer_addr;
-       void *e_metadata_buffer_size;
-       void *e_encoded_source_first_plane_addr;
-       void *e_encoded_source_second_plane_addr;
-       void *e_encoded_source_third_plane_addr;/* v7 and v8 */
-       void *e_stream_size;
-       void *e_slice_type;
-       void *e_picture_count;
-       void *e_ret_picture_tag;
-       void *e_stream_buffer_write_pointer; /*  only v6 */
-       void *e_recon_luma_dpb_addr;
-       void *e_recon_chroma_dpb_addr;
-       void *e_metadata_addr_enc_slice;
-       void *e_metadata_size_enc_slice;
-       void *e_mpeg4_options;
-       void *e_mpeg4_hec_period;
-       void *e_aspect_ratio;
-       void *e_extended_sar;
-       void *e_h264_options;
-       void *e_h264_options_2;/* v7 and v8 */
-       void *e_h264_lf_alpha_offset;
-       void *e_h264_lf_beta_offset;
-       void *e_h264_i_period;
-       void *e_h264_fmo_slice_grp_map_type;
-       void *e_h264_fmo_num_slice_grp_minus1;
-       void *e_h264_fmo_slice_grp_change_dir;
-       void *e_h264_fmo_slice_grp_change_rate_minus1;
-       void *e_h264_fmo_run_length_minus1_0;
-       void *e_h264_aso_slice_order_0;
-       void *e_h264_chroma_qp_offset;
-       void *e_h264_num_t_layer;
-       void *e_h264_hierarchical_qp_layer0;
-       void *e_h264_frame_packing_sei_info;
-       void *e_h264_nal_control;/* v7 and v8 */
-       void *e_mvc_frame_qp_view1;
-       void *e_mvc_rc_bit_rate_view1;
-       void *e_mvc_rc_qbound_view1;
-       void *e_mvc_rc_mode_view1;
-       void *e_mvc_inter_view_prediction_on;
-       void *e_vp8_options;/* v7 and v8 */
-       void *e_vp8_filter_options;/* v7 and v8 */
-       void *e_vp8_golden_frame_option;/* v7 and v8 */
-       void *e_vp8_num_t_layer;/* v7 and v8 */
-       void *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
-       void *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
-       void *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
+       volatile void __iomem *e_frame_width;
+       volatile void __iomem *e_frame_height;
+       volatile void __iomem *e_cropped_frame_width;
+       volatile void __iomem *e_cropped_frame_height;
+       volatile void __iomem *e_frame_crop_offset;
+       volatile void __iomem *e_enc_options;
+       volatile void __iomem *e_picture_profile;
+       volatile void __iomem *e_vbv_buffer_size;
+       volatile void __iomem *e_vbv_init_delay;
+       volatile void __iomem *e_fixed_picture_qp;
+       volatile void __iomem *e_rc_config;
+       volatile void __iomem *e_rc_qp_bound;
+       volatile void __iomem *e_rc_qp_bound_pb;/* v7 and v8 */
+       volatile void __iomem *e_rc_mode;
+       volatile void __iomem *e_mb_rc_config;
+       volatile void __iomem *e_padding_ctrl;
+       volatile void __iomem *e_air_threshold;
+       volatile void __iomem *e_mv_hor_range;
+       volatile void __iomem *e_mv_ver_range;
+       volatile void __iomem *e_num_dpb;
+       volatile void __iomem *e_luma_dpb;
+       volatile void __iomem *e_chroma_dpb;
+       volatile void __iomem *e_me_buffer;
+       volatile void __iomem *e_scratch_buffer_addr;
+       volatile void __iomem *e_scratch_buffer_size;
+       volatile void __iomem *e_tmv_buffer0;
+       volatile void __iomem *e_tmv_buffer1;
+       volatile void __iomem *e_ir_buffer_addr;/* v7 and v8 */
+       volatile void __iomem *e_source_first_plane_addr;
+       volatile void __iomem *e_source_second_plane_addr;
+       volatile void __iomem *e_source_third_plane_addr;/* v7 and v8 */
+       volatile void __iomem *e_source_first_plane_stride;/* v7 and v8 */
+       volatile void __iomem *e_source_second_plane_stride;/* v7 and v8 */
+       volatile void __iomem *e_source_third_plane_stride;/* v7 and v8 */
+       volatile void __iomem *e_stream_buffer_addr;
+       volatile void __iomem *e_stream_buffer_size;
+       volatile void __iomem *e_roi_buffer_addr;
+       volatile void __iomem *e_param_change;
+       volatile void __iomem *e_ir_size;
+       volatile void __iomem *e_gop_config;
+       volatile void __iomem *e_mslice_mode;
+       volatile void __iomem *e_mslice_size_mb;
+       volatile void __iomem *e_mslice_size_bits;
+       volatile void __iomem *e_frame_insertion;
+       volatile void __iomem *e_rc_frame_rate;
+       volatile void __iomem *e_rc_bit_rate;
+       volatile void __iomem *e_rc_roi_ctrl;
+       volatile void __iomem *e_picture_tag;
+       volatile void __iomem *e_bit_count_enable;
+       volatile void __iomem *e_max_bit_count;
+       volatile void __iomem *e_min_bit_count;
+       volatile void __iomem *e_metadata_buffer_addr;
+       volatile void __iomem *e_metadata_buffer_size;
+       volatile void __iomem *e_encoded_source_first_plane_addr;
+       volatile void __iomem *e_encoded_source_second_plane_addr;
+       volatile void __iomem *e_encoded_source_third_plane_addr;/* v7 and v8 */
+       volatile void __iomem *e_stream_size;
+       volatile void __iomem *e_slice_type;
+       volatile void __iomem *e_picture_count;
+       volatile void __iomem *e_ret_picture_tag;
+       volatile void __iomem *e_stream_buffer_write_pointer; /*  only v6 */
+       volatile void __iomem *e_recon_luma_dpb_addr;
+       volatile void __iomem *e_recon_chroma_dpb_addr;
+       volatile void __iomem *e_metadata_addr_enc_slice;
+       volatile void __iomem *e_metadata_size_enc_slice;
+       volatile void __iomem *e_mpeg4_options;
+       volatile void __iomem *e_mpeg4_hec_period;
+       volatile void __iomem *e_aspect_ratio;
+       volatile void __iomem *e_extended_sar;
+       volatile void __iomem *e_h264_options;
+       volatile void __iomem *e_h264_options_2;/* v7 and v8 */
+       volatile void __iomem *e_h264_lf_alpha_offset;
+       volatile void __iomem *e_h264_lf_beta_offset;
+       volatile void __iomem *e_h264_i_period;
+       volatile void __iomem *e_h264_fmo_slice_grp_map_type;
+       volatile void __iomem *e_h264_fmo_num_slice_grp_minus1;
+       volatile void __iomem *e_h264_fmo_slice_grp_change_dir;
+       volatile void __iomem *e_h264_fmo_slice_grp_change_rate_minus1;
+       volatile void __iomem *e_h264_fmo_run_length_minus1_0;
+       volatile void __iomem *e_h264_aso_slice_order_0;
+       volatile void __iomem *e_h264_chroma_qp_offset;
+       volatile void __iomem *e_h264_num_t_layer;
+       volatile void __iomem *e_h264_hierarchical_qp_layer0;
+       volatile void __iomem *e_h264_frame_packing_sei_info;
+       volatile void __iomem *e_h264_nal_control;/* v7 and v8 */
+       volatile void __iomem *e_mvc_frame_qp_view1;
+       volatile void __iomem *e_mvc_rc_bit_rate_view1;
+       volatile void __iomem *e_mvc_rc_qbound_view1;
+       volatile void __iomem *e_mvc_rc_mode_view1;
+       volatile void __iomem *e_mvc_inter_view_prediction_on;
+       volatile void __iomem *e_vp8_options;/* v7 and v8 */
+       volatile void __iomem *e_vp8_filter_options;/* v7 and v8 */
+       volatile void __iomem *e_vp8_golden_frame_option;/* v7 and v8 */
+       volatile void __iomem *e_vp8_num_t_layer;/* v7 and v8 */
+       volatile void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
+       volatile void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
+       volatile void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
 };
 
 struct s5p_mfc_hw_ops {
index 58ec7bb26ebc715f11b145f72149b9a4535a9297..7cf07963187dd33e254cc3d89db849f2ae877faf 100644 (file)
@@ -228,6 +228,7 @@ static int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx)
        ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, &ctx->shm);
        if (ret) {
                mfc_err("Failed to allocate shared memory buffer\n");
+               s5p_mfc_release_priv_buf(dev->mem_dev_l, &ctx->ctx);
                return ret;
        }
 
@@ -262,7 +263,7 @@ static void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev)
 static void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data,
                        unsigned int ofs)
 {
-       writel(data, (ctx->shm.virt + ofs));
+       writel(data, (volatile void __iomem *)(ctx->shm.virt + ofs));
        wmb();
 }
 
@@ -270,7 +271,7 @@ static unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx,
                                unsigned int ofs)
 {
        rmb();
-       return readl(ctx->shm.virt + ofs);
+       return readl((volatile void __iomem *)(ctx->shm.virt + ofs));
 }
 
 static void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx)
@@ -377,7 +378,7 @@ static int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx,
 /* Set decoding frame buffer */
 static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx)
 {
-       unsigned int frame_size, i;
+       unsigned int frame_size_lu, i;
        unsigned int frame_size_ch, frame_size_mv;
        struct s5p_mfc_dev *dev = ctx->dev;
        unsigned int dpb;
@@ -465,23 +466,23 @@ static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx)
                        ctx->codec_mode);
                return -EINVAL;
        }
-       frame_size = ctx->luma_size;
+       frame_size_lu = ctx->luma_size;
        frame_size_ch = ctx->chroma_size;
        frame_size_mv = ctx->mv_size;
-       mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch,
+       mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size_lu, frame_size_ch,
                                                                frame_size_mv);
        for (i = 0; i < ctx->total_dpb_count; i++) {
                /* Bank2 */
-               mfc_debug(2, "Luma %d: %x\n", i,
+               mfc_debug(2, "Luma %d: %zx\n", i,
                                        ctx->dst_bufs[i].cookie.raw.luma);
                mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma),
                                                S5P_FIMV_DEC_LUMA_ADR + i * 4);
-               mfc_debug(2, "\tChroma %d: %x\n", i,
+               mfc_debug(2, "\tChroma %d: %zx\n", i,
                                        ctx->dst_bufs[i].cookie.raw.chroma);
                mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma),
                                               S5P_FIMV_DEC_CHROMA_ADR + i * 4);
                if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) {
-                       mfc_debug(2, "\tBuf2: %x, size: %d\n",
+                       mfc_debug(2, "\tBuf2: %zx, size: %d\n",
                                                        buf_addr2, buf_size2);
                        mfc_write(dev, OFFSETB(buf_addr2),
                                                S5P_FIMV_H264_MV_ADR + i * 4);
@@ -489,14 +490,14 @@ static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx)
                        buf_size2 -= frame_size_mv;
                }
        }
-       mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1);
+       mfc_debug(2, "Buf1: %zu, buf_size1: %d\n", buf_addr1, buf_size1);
        mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n",
                        buf_size1,  buf_size2, ctx->total_dpb_count);
        if (buf_size1 < 0 || buf_size2 < 0) {
                mfc_debug(2, "Not enough memory has been allocated\n");
                return -ENOMEM;
        }
-       s5p_mfc_write_info_v5(ctx, frame_size, ALLOC_LUMA_DPB_SIZE);
+       s5p_mfc_write_info_v5(ctx, frame_size_lu, ALLOC_LUMA_DPB_SIZE);
        s5p_mfc_write_info_v5(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE);
        if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC)
                s5p_mfc_write_info_v5(ctx, frame_size_mv, ALLOC_MV_SIZE);
@@ -566,7 +567,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx)
                enc_ref_c_size = ALIGN(guard_width * guard_height,
                                       S5P_FIMV_NV12MT_SALIGN);
        }
-       mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2);
+       mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", buf_size1, buf_size2);
        switch (ctx->codec_mode) {
        case S5P_MFC_CODEC_H264_ENC:
                for (i = 0; i < 2; i++) {
@@ -605,7 +606,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx)
                                        S5P_FIMV_H264_NBOR_INFO_ADR);
                buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE;
                buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE;
-               mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+               mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n",
                        buf_size1, buf_size2);
                break;
        case S5P_MFC_CODEC_MPEG4_ENC:
@@ -636,7 +637,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx)
                                                S5P_FIMV_MPEG4_ACDC_COEF_ADR);
                buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
                buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
-               mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+               mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n",
                        buf_size1, buf_size2);
                break;
        case S5P_MFC_CODEC_H263_ENC:
@@ -662,7 +663,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx)
                mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR);
                buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
                buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
-               mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+               mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n",
                        buf_size1, buf_size2);
                break;
        default:
@@ -1186,7 +1187,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
        struct s5p_mfc_dev *dev = ctx->dev;
        struct s5p_mfc_buf *temp_vb;
        unsigned long flags;
-       unsigned int index;
 
        if (ctx->state == MFCINST_FINISHING) {
                last_frame = MFC_DEC_LAST_FRAME;
@@ -1211,7 +1211,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
                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;
        dev->curr_ctx = ctx->num;
        s5p_mfc_clean_ctx_int_flags(ctx);
        if (temp_vb->b->v4l2_planes[0].bytesused == 0) {
index c1c12f8d8f68055352ccc3ef271524ec4d171beb..8798b14bacce8f1e85a658b578728a9976a549f0 100644 (file)
        } while (0)
 #endif /* S5P_MFC_DEBUG_REGWRITE */
 
-#define READL(reg) \
-       (WARN_ON_ONCE(!(reg)) ? 0 : readl(reg))
-#define WRITEL(data, reg) \
-       (WARN_ON_ONCE(!(reg)) ? 0 : writel((data), (reg)))
-
 #define IS_MFCV6_V2(dev) (!IS_MFCV7_PLUS(dev) && dev->fw_ver == MFC_FW_V2)
 
 /* Allocate temporary buffers for decoding */
@@ -105,7 +100,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
                                                mb_width, mb_height),
                                                S5P_FIMV_ME_BUFFER_ALIGN_V6);
 
-               mfc_debug(2, "recon luma size: %d chroma size: %d\n",
+               mfc_debug(2, "recon luma size: %zu chroma size: %zu\n",
                          ctx->luma_dpb_size, ctx->chroma_dpb_size);
        } else {
                return -EINVAL;
@@ -416,10 +411,10 @@ static int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
        mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x,\n"
                "buf_size: 0x%08x (%d)\n",
                ctx->inst_no, buf_addr, strm_size, strm_size);
-       WRITEL(strm_size, mfc_regs->d_stream_data_size);
-       WRITEL(buf_addr, mfc_regs->d_cpb_buffer_addr);
-       WRITEL(buf_size->cpb, mfc_regs->d_cpb_buffer_size);
-       WRITEL(start_num_byte, mfc_regs->d_cpb_buffer_offset);
+       writel(strm_size, mfc_regs->d_stream_data_size);
+       writel(buf_addr, mfc_regs->d_cpb_buffer_addr);
+       writel(buf_size->cpb, mfc_regs->d_cpb_buffer_size);
+       writel(start_num_byte, mfc_regs->d_cpb_buffer_offset);
 
        mfc_debug_leave();
        return 0;
@@ -443,17 +438,17 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
        mfc_debug(2, "Total DPB COUNT: %d\n", ctx->total_dpb_count);
        mfc_debug(2, "Setting display delay to %d\n", ctx->display_delay);
 
-       WRITEL(ctx->total_dpb_count, mfc_regs->d_num_dpb);
-       WRITEL(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
-       WRITEL(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
+       writel(ctx->total_dpb_count, mfc_regs->d_num_dpb);
+       writel(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
+       writel(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
 
-       WRITEL(buf_addr1, mfc_regs->d_scratch_buffer_addr);
-       WRITEL(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
+       writel(buf_addr1, mfc_regs->d_scratch_buffer_addr);
+       writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
 
        if (IS_MFCV8(dev)) {
-               WRITEL(ctx->img_width,
+               writel(ctx->img_width,
                        mfc_regs->d_first_plane_dpb_stride_size);
-               WRITEL(ctx->img_width,
+               writel(ctx->img_width,
                        mfc_regs->d_second_plane_dpb_stride_size);
        }
 
@@ -462,8 +457,8 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
 
        if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
                        ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){
-               WRITEL(ctx->mv_size, mfc_regs->d_mv_buffer_size);
-               WRITEL(ctx->mv_count, mfc_regs->d_num_mv);
+               writel(ctx->mv_size, mfc_regs->d_mv_buffer_size);
+               writel(ctx->mv_count, mfc_regs->d_num_mv);
        }
 
        frame_size = ctx->luma_size;
@@ -474,13 +469,13 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
 
        for (i = 0; i < ctx->total_dpb_count; i++) {
                /* Bank2 */
-               mfc_debug(2, "Luma %d: %x\n", i,
+               mfc_debug(2, "Luma %d: %zx\n", i,
                                        ctx->dst_bufs[i].cookie.raw.luma);
-               WRITEL(ctx->dst_bufs[i].cookie.raw.luma,
+               writel(ctx->dst_bufs[i].cookie.raw.luma,
                                mfc_regs->d_first_plane_dpb + i * 4);
-               mfc_debug(2, "\tChroma %d: %x\n", i,
+               mfc_debug(2, "\tChroma %d: %zx\n", i,
                                        ctx->dst_bufs[i].cookie.raw.chroma);
-               WRITEL(ctx->dst_bufs[i].cookie.raw.chroma,
+               writel(ctx->dst_bufs[i].cookie.raw.chroma,
                                mfc_regs->d_second_plane_dpb + i * 4);
        }
        if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
@@ -492,23 +487,23 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
                        align_gap = buf_addr1 - align_gap;
                        buf_size1 -= align_gap;
 
-                       mfc_debug(2, "\tBuf1: %x, size: %d\n",
+                       mfc_debug(2, "\tBuf1: %zx, size: %d\n",
                                        buf_addr1, buf_size1);
-                       WRITEL(buf_addr1, mfc_regs->d_mv_buffer + i * 4);
+                       writel(buf_addr1, mfc_regs->d_mv_buffer + i * 4);
                        buf_addr1 += frame_size_mv;
                        buf_size1 -= frame_size_mv;
                }
        }
 
-       mfc_debug(2, "Buf1: %u, buf_size1: %d (frames %d)\n",
+       mfc_debug(2, "Buf1: %zu, buf_size1: %d (frames %d)\n",
                        buf_addr1, buf_size1, ctx->total_dpb_count);
        if (buf_size1 < 0) {
                mfc_debug(2, "Not enough memory has been allocated.\n");
                return -ENOMEM;
        }
 
-       WRITEL(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+       writel(ctx->inst_no, mfc_regs->instance_id);
+       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_INIT_BUFS_V6, NULL);
 
        mfc_debug(2, "After setting buffers.\n");
@@ -522,8 +517,8 @@ static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
        struct s5p_mfc_dev *dev = ctx->dev;
        const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
 
-       WRITEL(addr, mfc_regs->e_stream_buffer_addr); /* 16B align */
-       WRITEL(size, mfc_regs->e_stream_buffer_size);
+       writel(addr, mfc_regs->e_stream_buffer_addr); /* 16B align */
+       writel(size, mfc_regs->e_stream_buffer_size);
 
        mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%d\n",
                  addr, size);
@@ -537,8 +532,8 @@ static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
        struct s5p_mfc_dev *dev = ctx->dev;
        const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
 
-       WRITEL(y_addr, mfc_regs->e_source_first_plane_addr);
-       WRITEL(c_addr, mfc_regs->e_source_second_plane_addr);
+       writel(y_addr, mfc_regs->e_source_first_plane_addr);
+       writel(c_addr, mfc_regs->e_source_second_plane_addr);
 
        mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr);
        mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr);
@@ -551,11 +546,11 @@ static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
        const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
        unsigned long enc_recon_y_addr, enc_recon_c_addr;
 
-       *y_addr = READL(mfc_regs->e_encoded_source_first_plane_addr);
-       *c_addr = READL(mfc_regs->e_encoded_source_second_plane_addr);
+       *y_addr = readl(mfc_regs->e_encoded_source_first_plane_addr);
+       *c_addr = readl(mfc_regs->e_encoded_source_second_plane_addr);
 
-       enc_recon_y_addr = READL(mfc_regs->e_recon_luma_dpb_addr);
-       enc_recon_c_addr = READL(mfc_regs->e_recon_chroma_dpb_addr);
+       enc_recon_y_addr = readl(mfc_regs->e_recon_luma_dpb_addr);
+       enc_recon_c_addr = readl(mfc_regs->e_recon_chroma_dpb_addr);
 
        mfc_debug(2, "recon y addr: 0x%08lx\n", enc_recon_y_addr);
        mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr);
@@ -577,36 +572,36 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
        mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1);
 
        for (i = 0; i < ctx->pb_count; i++) {
-               WRITEL(buf_addr1, mfc_regs->e_luma_dpb + (4 * i));
+               writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i));
                buf_addr1 += ctx->luma_dpb_size;
-               WRITEL(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i));
+               writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i));
                buf_addr1 += ctx->chroma_dpb_size;
-               WRITEL(buf_addr1, mfc_regs->e_me_buffer + (4 * i));
+               writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i));
                buf_addr1 += ctx->me_buffer_size;
                buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size +
                        ctx->me_buffer_size);
        }
 
-       WRITEL(buf_addr1, mfc_regs->e_scratch_buffer_addr);
-       WRITEL(ctx->scratch_buf_size, mfc_regs->e_scratch_buffer_size);
+       writel(buf_addr1, mfc_regs->e_scratch_buffer_addr);
+       writel(ctx->scratch_buf_size, mfc_regs->e_scratch_buffer_size);
        buf_addr1 += ctx->scratch_buf_size;
        buf_size1 -= ctx->scratch_buf_size;
 
-       WRITEL(buf_addr1, mfc_regs->e_tmv_buffer0);
+       writel(buf_addr1, mfc_regs->e_tmv_buffer0);
        buf_addr1 += ctx->tmv_buffer_size >> 1;
-       WRITEL(buf_addr1, mfc_regs->e_tmv_buffer1);
+       writel(buf_addr1, mfc_regs->e_tmv_buffer1);
        buf_addr1 += ctx->tmv_buffer_size >> 1;
        buf_size1 -= ctx->tmv_buffer_size;
 
-       mfc_debug(2, "Buf1: %u, buf_size1: %d (ref frames %d)\n",
+       mfc_debug(2, "Buf1: %zu, buf_size1: %d (ref frames %d)\n",
                        buf_addr1, buf_size1, ctx->pb_count);
        if (buf_size1 < 0) {
                mfc_debug(2, "Not enough memory has been allocated.\n");
                return -ENOMEM;
        }
 
-       WRITEL(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+       writel(ctx->inst_no, mfc_regs->instance_id);
+       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_INIT_BUFS_V6, NULL);
 
        mfc_debug_leave();
@@ -621,15 +616,15 @@ static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx)
 
        /* multi-slice control */
        /* multi-slice MB number or bit size */
-       WRITEL(ctx->slice_mode, mfc_regs->e_mslice_mode);
+       writel(ctx->slice_mode, mfc_regs->e_mslice_mode);
        if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
-               WRITEL(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb);
+               writel(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb);
        } else if (ctx->slice_mode ==
                        V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
-               WRITEL(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits);
+               writel(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits);
        } else {
-               WRITEL(0x0, mfc_regs->e_mslice_size_mb);
-               WRITEL(0x0, mfc_regs->e_mslice_size_bits);
+               writel(0x0, mfc_regs->e_mslice_size_mb);
+               writel(0x0, mfc_regs->e_mslice_size_bits);
        }
 
        return 0;
@@ -645,21 +640,21 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
        mfc_debug_enter();
 
        /* width */
-       WRITEL(ctx->img_width, mfc_regs->e_frame_width); /* 16 align */
+       writel(ctx->img_width, mfc_regs->e_frame_width); /* 16 align */
        /* height */
-       WRITEL(ctx->img_height, mfc_regs->e_frame_height); /* 16 align */
+       writel(ctx->img_height, mfc_regs->e_frame_height); /* 16 align */
 
        /* cropped width */
-       WRITEL(ctx->img_width, mfc_regs->e_cropped_frame_width);
+       writel(ctx->img_width, mfc_regs->e_cropped_frame_width);
        /* cropped height */
-       WRITEL(ctx->img_height, mfc_regs->e_cropped_frame_height);
+       writel(ctx->img_height, mfc_regs->e_cropped_frame_height);
        /* cropped offset */
-       WRITEL(0x0, mfc_regs->e_frame_crop_offset);
+       writel(0x0, mfc_regs->e_frame_crop_offset);
 
        /* pictype : IDR period */
        reg = 0;
        reg |= p->gop_size & 0xFFFF;
-       WRITEL(reg, mfc_regs->e_gop_config);
+       writel(reg, mfc_regs->e_gop_config);
 
        /* multi-slice control */
        /* multi-slice MB number or bit size */
@@ -667,65 +662,65 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
        reg = 0;
        if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
                reg |= (0x1 << 3);
-               WRITEL(reg, mfc_regs->e_enc_options);
+               writel(reg, mfc_regs->e_enc_options);
                ctx->slice_size.mb = p->slice_mb;
        } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
                reg |= (0x1 << 3);
-               WRITEL(reg, mfc_regs->e_enc_options);
+               writel(reg, mfc_regs->e_enc_options);
                ctx->slice_size.bits = p->slice_bit;
        } else {
                reg &= ~(0x1 << 3);
-               WRITEL(reg, mfc_regs->e_enc_options);
+               writel(reg, mfc_regs->e_enc_options);
        }
 
        s5p_mfc_set_slice_mode(ctx);
 
        /* cyclic intra refresh */
-       WRITEL(p->intra_refresh_mb, mfc_regs->e_ir_size);
-       reg = READL(mfc_regs->e_enc_options);
+       writel(p->intra_refresh_mb, mfc_regs->e_ir_size);
+       reg = readl(mfc_regs->e_enc_options);
        if (p->intra_refresh_mb == 0)
                reg &= ~(0x1 << 4);
        else
                reg |= (0x1 << 4);
-       WRITEL(reg, mfc_regs->e_enc_options);
+       writel(reg, mfc_regs->e_enc_options);
 
        /* 'NON_REFERENCE_STORE_ENABLE' for debugging */
-       reg = READL(mfc_regs->e_enc_options);
+       reg = readl(mfc_regs->e_enc_options);
        reg &= ~(0x1 << 9);
-       WRITEL(reg, mfc_regs->e_enc_options);
+       writel(reg, mfc_regs->e_enc_options);
 
        /* memory structure cur. frame */
        if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) {
                /* 0: Linear, 1: 2D tiled*/
-               reg = READL(mfc_regs->e_enc_options);
+               reg = readl(mfc_regs->e_enc_options);
                reg &= ~(0x1 << 7);
-               WRITEL(reg, mfc_regs->e_enc_options);
+               writel(reg, mfc_regs->e_enc_options);
                /* 0: NV12(CbCr), 1: NV21(CrCb) */
-               WRITEL(0x0, mfc_regs->pixel_format);
+               writel(0x0, mfc_regs->pixel_format);
        } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M) {
                /* 0: Linear, 1: 2D tiled*/
-               reg = READL(mfc_regs->e_enc_options);
+               reg = readl(mfc_regs->e_enc_options);
                reg &= ~(0x1 << 7);
-               WRITEL(reg, mfc_regs->e_enc_options);
+               writel(reg, mfc_regs->e_enc_options);
                /* 0: NV12(CbCr), 1: NV21(CrCb) */
-               WRITEL(0x1, mfc_regs->pixel_format);
+               writel(0x1, mfc_regs->pixel_format);
        } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) {
                /* 0: Linear, 1: 2D tiled*/
-               reg = READL(mfc_regs->e_enc_options);
+               reg = readl(mfc_regs->e_enc_options);
                reg |= (0x1 << 7);
-               WRITEL(reg, mfc_regs->e_enc_options);
+               writel(reg, mfc_regs->e_enc_options);
                /* 0: NV12(CbCr), 1: NV21(CrCb) */
-               WRITEL(0x0, mfc_regs->pixel_format);
+               writel(0x0, mfc_regs->pixel_format);
        }
 
        /* memory structure recon. frame */
        /* 0: Linear, 1: 2D tiled */
-       reg = READL(mfc_regs->e_enc_options);
+       reg = readl(mfc_regs->e_enc_options);
        reg |= (0x1 << 8);
-       WRITEL(reg, mfc_regs->e_enc_options);
+       writel(reg, mfc_regs->e_enc_options);
 
        /* padding control & value */
-       WRITEL(0x0, mfc_regs->e_padding_ctrl);
+       writel(0x0, mfc_regs->e_padding_ctrl);
        if (p->pad) {
                reg = 0;
                /** enable */
@@ -736,64 +731,64 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
                reg |= ((p->pad_cb & 0xFF) << 8);
                /** y value */
                reg |= p->pad_luma & 0xFF;
-               WRITEL(reg, mfc_regs->e_padding_ctrl);
+               writel(reg, mfc_regs->e_padding_ctrl);
        }
 
        /* rate control config. */
        reg = 0;
        /* frame-level rate control */
        reg |= ((p->rc_frame & 0x1) << 9);
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* bit rate */
        if (p->rc_frame)
-               WRITEL(p->rc_bitrate,
+               writel(p->rc_bitrate,
                        mfc_regs->e_rc_bit_rate);
        else
-               WRITEL(1, mfc_regs->e_rc_bit_rate);
+               writel(1, mfc_regs->e_rc_bit_rate);
 
        /* reaction coefficient */
        if (p->rc_frame) {
                if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */
-                       WRITEL(1, mfc_regs->e_rc_mode);
+                       writel(1, mfc_regs->e_rc_mode);
                else                                      /* loose CBR */
-                       WRITEL(2, mfc_regs->e_rc_mode);
+                       writel(2, mfc_regs->e_rc_mode);
        }
 
        /* seq header ctrl */
-       reg = READL(mfc_regs->e_enc_options);
+       reg = readl(mfc_regs->e_enc_options);
        reg &= ~(0x1 << 2);
        reg |= ((p->seq_hdr_mode & 0x1) << 2);
 
        /* frame skip mode */
        reg &= ~(0x3);
        reg |= (p->frame_skip_mode & 0x3);
-       WRITEL(reg, mfc_regs->e_enc_options);
+       writel(reg, mfc_regs->e_enc_options);
 
        /* 'DROP_CONTROL_ENABLE', disable */
-       reg = READL(mfc_regs->e_rc_config);
+       reg = readl(mfc_regs->e_rc_config);
        reg &= ~(0x1 << 10);
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* setting for MV range [16, 256] */
        reg = (p->mv_h_range & S5P_FIMV_E_MV_RANGE_V6_MASK);
-       WRITEL(reg, mfc_regs->e_mv_hor_range);
+       writel(reg, mfc_regs->e_mv_hor_range);
 
        reg = (p->mv_v_range & S5P_FIMV_E_MV_RANGE_V6_MASK);
-       WRITEL(reg, mfc_regs->e_mv_ver_range);
+       writel(reg, mfc_regs->e_mv_ver_range);
 
-       WRITEL(0x0, mfc_regs->e_frame_insertion);
-       WRITEL(0x0, mfc_regs->e_roi_buffer_addr);
-       WRITEL(0x0, mfc_regs->e_param_change);
-       WRITEL(0x0, mfc_regs->e_rc_roi_ctrl);
-       WRITEL(0x0, mfc_regs->e_picture_tag);
+       writel(0x0, mfc_regs->e_frame_insertion);
+       writel(0x0, mfc_regs->e_roi_buffer_addr);
+       writel(0x0, mfc_regs->e_param_change);
+       writel(0x0, mfc_regs->e_rc_roi_ctrl);
+       writel(0x0, mfc_regs->e_picture_tag);
 
-       WRITEL(0x0, mfc_regs->e_bit_count_enable);
-       WRITEL(0x0, mfc_regs->e_max_bit_count);
-       WRITEL(0x0, mfc_regs->e_min_bit_count);
+       writel(0x0, mfc_regs->e_bit_count_enable);
+       writel(0x0, mfc_regs->e_max_bit_count);
+       writel(0x0, mfc_regs->e_min_bit_count);
 
-       WRITEL(0x0, mfc_regs->e_metadata_buffer_addr);
-       WRITEL(0x0, mfc_regs->e_metadata_buffer_size);
+       writel(0x0, mfc_regs->e_metadata_buffer_addr);
+       writel(0x0, mfc_regs->e_metadata_buffer_size);
 
        mfc_debug_leave();
 
@@ -814,10 +809,10 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
        s5p_mfc_set_enc_params(ctx);
 
        /* pictype : number of B */
-       reg = READL(mfc_regs->e_gop_config);
+       reg = readl(mfc_regs->e_gop_config);
        reg &= ~(0x3 << 16);
        reg |= ((p->num_b_frame & 0x3) << 16);
-       WRITEL(reg, mfc_regs->e_gop_config);
+       writel(reg, mfc_regs->e_gop_config);
 
        /* profile & level */
        reg = 0;
@@ -825,19 +820,19 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
        reg |= ((p_h264->level & 0xFF) << 8);
        /** profile - 0 ~ 3 */
        reg |= p_h264->profile & 0x3F;
-       WRITEL(reg, mfc_regs->e_picture_profile);
+       writel(reg, mfc_regs->e_picture_profile);
 
        /* rate control config. */
-       reg = READL(mfc_regs->e_rc_config);
+       reg = readl(mfc_regs->e_rc_config);
        /** macroblock level rate control */
        reg &= ~(0x1 << 8);
        reg |= ((p->rc_mb & 0x1) << 8);
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /** frame QP */
        reg &= ~(0x3F);
        reg |= p_h264->rc_frame_qp & 0x3F;
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* max & min value of QP */
        reg = 0;
@@ -845,16 +840,16 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
        reg |= ((p_h264->rc_max_qp & 0x3F) << 8);
        /** min QP */
        reg |= p_h264->rc_min_qp & 0x3F;
-       WRITEL(reg, mfc_regs->e_rc_qp_bound);
+       writel(reg, mfc_regs->e_rc_qp_bound);
 
        /* other QPs */
-       WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
+       writel(0x0, mfc_regs->e_fixed_picture_qp);
        if (!p->rc_frame && !p->rc_mb) {
                reg = 0;
                reg |= ((p_h264->rc_b_frame_qp & 0x3F) << 16);
                reg |= ((p_h264->rc_p_frame_qp & 0x3F) << 8);
                reg |= p_h264->rc_frame_qp & 0x3F;
-               WRITEL(reg, mfc_regs->e_fixed_picture_qp);
+               writel(reg, mfc_regs->e_fixed_picture_qp);
        }
 
        /* frame rate */
@@ -862,38 +857,38 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                reg = 0;
                reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
                reg |= p->rc_framerate_denom & 0xFFFF;
-               WRITEL(reg, mfc_regs->e_rc_frame_rate);
+               writel(reg, mfc_regs->e_rc_frame_rate);
        }
 
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
-               WRITEL(p_h264->cpb_size & 0xFFFF,
+               writel(p_h264->cpb_size & 0xFFFF,
                                mfc_regs->e_vbv_buffer_size);
 
                if (p->rc_frame)
-                       WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
+                       writel(p->vbv_delay, mfc_regs->e_vbv_init_delay);
        }
 
        /* interlace */
        reg = 0;
        reg |= ((p_h264->interlace & 0x1) << 3);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* height */
        if (p_h264->interlace) {
-               WRITEL(ctx->img_height >> 1,
+               writel(ctx->img_height >> 1,
                                mfc_regs->e_frame_height); /* 32 align */
                /* cropped height */
-               WRITEL(ctx->img_height >> 1,
+               writel(ctx->img_height >> 1,
                                mfc_regs->e_cropped_frame_height);
        }
 
        /* loop filter ctrl */
-       reg = READL(mfc_regs->e_h264_options);
+       reg = readl(mfc_regs->e_h264_options);
        reg &= ~(0x3 << 1);
        reg |= ((p_h264->loop_filter_mode & 0x3) << 1);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* loopfilter alpha offset */
        if (p_h264->loop_filter_alpha < 0) {
@@ -903,7 +898,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                reg = 0x00;
                reg |= (p_h264->loop_filter_alpha & 0xF);
        }
-       WRITEL(reg, mfc_regs->e_h264_lf_alpha_offset);
+       writel(reg, mfc_regs->e_h264_lf_alpha_offset);
 
        /* loopfilter beta offset */
        if (p_h264->loop_filter_beta < 0) {
@@ -913,28 +908,28 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                reg = 0x00;
                reg |= (p_h264->loop_filter_beta & 0xF);
        }
-       WRITEL(reg, mfc_regs->e_h264_lf_beta_offset);
+       writel(reg, mfc_regs->e_h264_lf_beta_offset);
 
        /* entropy coding mode */
-       reg = READL(mfc_regs->e_h264_options);
+       reg = readl(mfc_regs->e_h264_options);
        reg &= ~(0x1);
        reg |= p_h264->entropy_mode & 0x1;
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* number of ref. picture */
-       reg = READL(mfc_regs->e_h264_options);
+       reg = readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 7);
        reg |= (((p_h264->num_ref_pic_4p - 1) & 0x1) << 7);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* 8x8 transform enable */
-       reg = READL(mfc_regs->e_h264_options);
+       reg = readl(mfc_regs->e_h264_options);
        reg &= ~(0x3 << 12);
        reg |= ((p_h264->_8x8_transform & 0x3) << 12);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* macroblock adaptive scaling features */
-       WRITEL(0x0, mfc_regs->e_mb_rc_config);
+       writel(0x0, mfc_regs->e_mb_rc_config);
        if (p->rc_mb) {
                reg = 0;
                /** dark region */
@@ -945,95 +940,95 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                reg |= ((p_h264->rc_mb_static & 0x1) << 1);
                /** high activity region */
                reg |= p_h264->rc_mb_activity & 0x1;
-               WRITEL(reg, mfc_regs->e_mb_rc_config);
+               writel(reg, mfc_regs->e_mb_rc_config);
        }
 
        /* aspect ratio VUI */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 5);
        reg |= ((p_h264->vui_sar & 0x1) << 5);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
-       WRITEL(0x0, mfc_regs->e_aspect_ratio);
-       WRITEL(0x0, mfc_regs->e_extended_sar);
+       writel(0x0, mfc_regs->e_aspect_ratio);
+       writel(0x0, mfc_regs->e_extended_sar);
        if (p_h264->vui_sar) {
                /* aspect ration IDC */
                reg = 0;
                reg |= p_h264->vui_sar_idc & 0xFF;
-               WRITEL(reg, mfc_regs->e_aspect_ratio);
+               writel(reg, mfc_regs->e_aspect_ratio);
                if (p_h264->vui_sar_idc == 0xFF) {
                        /* extended SAR */
                        reg = 0;
                        reg |= (p_h264->vui_ext_sar_width & 0xFFFF) << 16;
                        reg |= p_h264->vui_ext_sar_height & 0xFFFF;
-                       WRITEL(reg, mfc_regs->e_extended_sar);
+                       writel(reg, mfc_regs->e_extended_sar);
                }
        }
 
        /* intra picture period for H.264 open GOP */
        /* control */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 4);
        reg |= ((p_h264->open_gop & 0x1) << 4);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* value */
-       WRITEL(0x0, mfc_regs->e_h264_i_period);
+       writel(0x0, mfc_regs->e_h264_i_period);
        if (p_h264->open_gop) {
                reg = 0;
                reg |= p_h264->open_gop_size & 0xFFFF;
-               WRITEL(reg, mfc_regs->e_h264_i_period);
+               writel(reg, mfc_regs->e_h264_i_period);
        }
 
        /* 'WEIGHTED_BI_PREDICTION' for B is disable */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x3 << 9);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 14);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* ASO */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 6);
        reg |= ((p_h264->aso & 0x1) << 6);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* hier qp enable */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 8);
        reg |= ((p_h264->open_gop & 0x1) << 8);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
        reg = 0;
        if (p_h264->hier_qp && p_h264->hier_qp_layer) {
                reg |= (p_h264->hier_qp_type & 0x1) << 0x3;
                reg |= p_h264->hier_qp_layer & 0x7;
-               WRITEL(reg, mfc_regs->e_h264_num_t_layer);
+               writel(reg, mfc_regs->e_h264_num_t_layer);
                /* QP value for each layer */
                for (i = 0; i < p_h264->hier_qp_layer &&
                                i < ARRAY_SIZE(p_h264->hier_qp_layer_qp); i++) {
-                       WRITEL(p_h264->hier_qp_layer_qp[i],
+                       writel(p_h264->hier_qp_layer_qp[i],
                                mfc_regs->e_h264_hierarchical_qp_layer0
                                + i * 4);
                }
        }
        /* number of coding layer should be zero when hierarchical is disable */
-       WRITEL(reg, mfc_regs->e_h264_num_t_layer);
+       writel(reg, mfc_regs->e_h264_num_t_layer);
 
        /* frame packing SEI generation */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 25);
        reg |= ((p_h264->sei_frame_packing & 0x1) << 25);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
        if (p_h264->sei_frame_packing) {
                reg = 0;
                /** current frame0 flag */
                reg |= ((p_h264->sei_fp_curr_frame_0 & 0x1) << 2);
                /** arrangement type */
                reg |= p_h264->sei_fp_arrangement_type & 0x3;
-               WRITEL(reg, mfc_regs->e_h264_frame_packing_sei_info);
+               writel(reg, mfc_regs->e_h264_frame_packing_sei_info);
        }
 
        if (p_h264->fmo) {
@@ -1042,7 +1037,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                        if (p_h264->fmo_slice_grp > 4)
                                p_h264->fmo_slice_grp = 4;
                        for (i = 0; i < (p_h264->fmo_slice_grp & 0xF); i++)
-                               WRITEL(p_h264->fmo_run_len[i] - 1,
+                               writel(p_h264->fmo_run_len[i] - 1,
                                        mfc_regs->e_h264_fmo_run_length_minus1_0
                                        + i * 4);
                        break;
@@ -1054,10 +1049,10 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN:
                        if (p_h264->fmo_slice_grp > 2)
                                p_h264->fmo_slice_grp = 2;
-                       WRITEL(p_h264->fmo_chg_dir & 0x1,
+                       writel(p_h264->fmo_chg_dir & 0x1,
                                mfc_regs->e_h264_fmo_slice_grp_change_dir);
                        /* the valid range is 0 ~ number of macroblocks -1 */
-                       WRITEL(p_h264->fmo_chg_rate,
+                       writel(p_h264->fmo_chg_rate,
                        mfc_regs->e_h264_fmo_slice_grp_change_rate_minus1);
                        break;
                default:
@@ -1068,12 +1063,12 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                        break;
                }
 
-               WRITEL(p_h264->fmo_map_type,
+               writel(p_h264->fmo_map_type,
                                mfc_regs->e_h264_fmo_slice_grp_map_type);
-               WRITEL(p_h264->fmo_slice_grp - 1,
+               writel(p_h264->fmo_slice_grp - 1,
                                mfc_regs->e_h264_fmo_num_slice_grp_minus1);
        } else {
-               WRITEL(0, mfc_regs->e_h264_fmo_num_slice_grp_minus1);
+               writel(0, mfc_regs->e_h264_fmo_num_slice_grp_minus1);
        }
 
        mfc_debug_leave();
@@ -1094,10 +1089,10 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
        s5p_mfc_set_enc_params(ctx);
 
        /* pictype : number of B */
-       reg = READL(mfc_regs->e_gop_config);
+       reg = readl(mfc_regs->e_gop_config);
        reg &= ~(0x3 << 16);
        reg |= ((p->num_b_frame & 0x3) << 16);
-       WRITEL(reg, mfc_regs->e_gop_config);
+       writel(reg, mfc_regs->e_gop_config);
 
        /* profile & level */
        reg = 0;
@@ -1105,19 +1100,19 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
        reg |= ((p_mpeg4->level & 0xFF) << 8);
        /** profile - 0 ~ 1 */
        reg |= p_mpeg4->profile & 0x3F;
-       WRITEL(reg, mfc_regs->e_picture_profile);
+       writel(reg, mfc_regs->e_picture_profile);
 
        /* rate control config. */
-       reg = READL(mfc_regs->e_rc_config);
+       reg = readl(mfc_regs->e_rc_config);
        /** macroblock level rate control */
        reg &= ~(0x1 << 8);
        reg |= ((p->rc_mb & 0x1) << 8);
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /** frame QP */
        reg &= ~(0x3F);
        reg |= p_mpeg4->rc_frame_qp & 0x3F;
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* max & min value of QP */
        reg = 0;
@@ -1125,16 +1120,16 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
        reg |= ((p_mpeg4->rc_max_qp & 0x3F) << 8);
        /** min QP */
        reg |= p_mpeg4->rc_min_qp & 0x3F;
-       WRITEL(reg, mfc_regs->e_rc_qp_bound);
+       writel(reg, mfc_regs->e_rc_qp_bound);
 
        /* other QPs */
-       WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
+       writel(0x0, mfc_regs->e_fixed_picture_qp);
        if (!p->rc_frame && !p->rc_mb) {
                reg = 0;
                reg |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 16);
                reg |= ((p_mpeg4->rc_p_frame_qp & 0x3F) << 8);
                reg |= p_mpeg4->rc_frame_qp & 0x3F;
-               WRITEL(reg, mfc_regs->e_fixed_picture_qp);
+               writel(reg, mfc_regs->e_fixed_picture_qp);
        }
 
        /* frame rate */
@@ -1142,21 +1137,21 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
                reg = 0;
                reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
                reg |= p->rc_framerate_denom & 0xFFFF;
-               WRITEL(reg, mfc_regs->e_rc_frame_rate);
+               writel(reg, mfc_regs->e_rc_frame_rate);
        }
 
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
-               WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
+               writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
 
                if (p->rc_frame)
-                       WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
+                       writel(p->vbv_delay, mfc_regs->e_vbv_init_delay);
        }
 
        /* Disable HEC */
-       WRITEL(0x0, mfc_regs->e_mpeg4_options);
-       WRITEL(0x0, mfc_regs->e_mpeg4_hec_period);
+       writel(0x0, mfc_regs->e_mpeg4_options);
+       writel(0x0, mfc_regs->e_mpeg4_hec_period);
 
        mfc_debug_leave();
 
@@ -1179,19 +1174,19 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
        reg = 0;
        /** profile */
        reg |= (0x1 << 4);
-       WRITEL(reg, mfc_regs->e_picture_profile);
+       writel(reg, mfc_regs->e_picture_profile);
 
        /* rate control config. */
-       reg = READL(mfc_regs->e_rc_config);
+       reg = readl(mfc_regs->e_rc_config);
        /** macroblock level rate control */
        reg &= ~(0x1 << 8);
        reg |= ((p->rc_mb & 0x1) << 8);
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /** frame QP */
        reg &= ~(0x3F);
        reg |= p_h263->rc_frame_qp & 0x3F;
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* max & min value of QP */
        reg = 0;
@@ -1199,16 +1194,16 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
        reg |= ((p_h263->rc_max_qp & 0x3F) << 8);
        /** min QP */
        reg |= p_h263->rc_min_qp & 0x3F;
-       WRITEL(reg, mfc_regs->e_rc_qp_bound);
+       writel(reg, mfc_regs->e_rc_qp_bound);
 
        /* other QPs */
-       WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
+       writel(0x0, mfc_regs->e_fixed_picture_qp);
        if (!p->rc_frame && !p->rc_mb) {
                reg = 0;
                reg |= ((p_h263->rc_b_frame_qp & 0x3F) << 16);
                reg |= ((p_h263->rc_p_frame_qp & 0x3F) << 8);
                reg |= p_h263->rc_frame_qp & 0x3F;
-               WRITEL(reg, mfc_regs->e_fixed_picture_qp);
+               writel(reg, mfc_regs->e_fixed_picture_qp);
        }
 
        /* frame rate */
@@ -1216,16 +1211,16 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
                reg = 0;
                reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
                reg |= p->rc_framerate_denom & 0xFFFF;
-               WRITEL(reg, mfc_regs->e_rc_frame_rate);
+               writel(reg, mfc_regs->e_rc_frame_rate);
        }
 
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
-               WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
+               writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
 
                if (p->rc_frame)
-                       WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
+                       writel(p->vbv_delay, mfc_regs->e_vbv_init_delay);
        }
 
        mfc_debug_leave();
@@ -1247,57 +1242,57 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
        s5p_mfc_set_enc_params(ctx);
 
        /* pictype : number of B */
-       reg = READL(mfc_regs->e_gop_config);
+       reg = readl(mfc_regs->e_gop_config);
        reg &= ~(0x3 << 16);
        reg |= ((p->num_b_frame & 0x3) << 16);
-       WRITEL(reg, mfc_regs->e_gop_config);
+       writel(reg, mfc_regs->e_gop_config);
 
        /* profile - 0 ~ 3 */
        reg = p_vp8->profile & 0x3;
-       WRITEL(reg, mfc_regs->e_picture_profile);
+       writel(reg, mfc_regs->e_picture_profile);
 
        /* rate control config. */
-       reg = READL(mfc_regs->e_rc_config);
+       reg = readl(mfc_regs->e_rc_config);
        /** macroblock level rate control */
        reg &= ~(0x1 << 8);
        reg |= ((p->rc_mb & 0x1) << 8);
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* frame rate */
        if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
                reg = 0;
                reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
                reg |= p->rc_framerate_denom & 0xFFFF;
-               WRITEL(reg, mfc_regs->e_rc_frame_rate);
+               writel(reg, mfc_regs->e_rc_frame_rate);
        }
 
        /* frame QP */
        reg &= ~(0x7F);
        reg |= p_vp8->rc_frame_qp & 0x7F;
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* other QPs */
-       WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
+       writel(0x0, mfc_regs->e_fixed_picture_qp);
        if (!p->rc_frame && !p->rc_mb) {
                reg = 0;
                reg |= ((p_vp8->rc_p_frame_qp & 0x7F) << 8);
                reg |= p_vp8->rc_frame_qp & 0x7F;
-               WRITEL(reg, mfc_regs->e_fixed_picture_qp);
+               writel(reg, mfc_regs->e_fixed_picture_qp);
        }
 
        /* max QP */
        reg = ((p_vp8->rc_max_qp & 0x7F) << 8);
        /* min QP */
        reg |= p_vp8->rc_min_qp & 0x7F;
-       WRITEL(reg, mfc_regs->e_rc_qp_bound);
+       writel(reg, mfc_regs->e_rc_qp_bound);
 
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
-               WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
+               writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
 
                if (p->rc_frame)
-                       WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
+                       writel(p->vbv_delay, mfc_regs->e_vbv_init_delay);
        }
 
        /* VP8 specific params */
@@ -1319,7 +1314,7 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
        }
        reg |= (val & 0xF) << 3;
        reg |= (p_vp8->num_ref & 0x2);
-       WRITEL(reg, mfc_regs->e_vp8_options);
+       writel(reg, mfc_regs->e_vp8_options);
 
        mfc_debug_leave();
 
@@ -1338,9 +1333,9 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
        mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no,
                        S5P_FIMV_CH_SEQ_HEADER_V6);
        mfc_debug(2, "BUFs: %08x %08x %08x\n",
-                 READL(mfc_regs->d_cpb_buffer_addr),
-                 READL(mfc_regs->d_cpb_buffer_addr),
-                 READL(mfc_regs->d_cpb_buffer_addr));
+                 readl(mfc_regs->d_cpb_buffer_addr),
+                 readl(mfc_regs->d_cpb_buffer_addr),
+                 readl(mfc_regs->d_cpb_buffer_addr));
 
        /* FMO_ASO_CTRL - 0: Enable, 1: Disable */
        reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6);
@@ -1351,11 +1346,11 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
         * set to negative value. */
        if (ctx->display_delay >= 0) {
                reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6);
-               WRITEL(ctx->display_delay, mfc_regs->d_display_delay);
+               writel(ctx->display_delay, mfc_regs->d_display_delay);
        }
 
        if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev)) {
-               WRITEL(reg, mfc_regs->d_dec_options);
+               writel(reg, mfc_regs->d_dec_options);
                reg = 0;
        }
 
@@ -1370,22 +1365,22 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
                reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6);
 
        if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev))
-               WRITEL(reg, mfc_regs->d_init_buffer_options);
+               writel(reg, mfc_regs->d_init_buffer_options);
        else
-               WRITEL(reg, mfc_regs->d_dec_options);
+               writel(reg, mfc_regs->d_dec_options);
 
        /* 0: NV12(CbCr), 1: NV21(CrCb) */
        if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
-               WRITEL(0x1, mfc_regs->pixel_format);
+               writel(0x1, mfc_regs->pixel_format);
        else
-               WRITEL(0x0, mfc_regs->pixel_format);
+               writel(0x0, mfc_regs->pixel_format);
 
 
        /* sei parse */
-       WRITEL(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable);
+       writel(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable);
 
-       WRITEL(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+       writel(ctx->inst_no, mfc_regs->instance_id);
+       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
 
        mfc_debug_leave();
@@ -1400,8 +1395,8 @@ static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
        if (flush) {
                dev->curr_ctx = ctx->num;
                s5p_mfc_clean_ctx_int_flags(ctx);
-               WRITEL(ctx->inst_no, mfc_regs->instance_id);
-               s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+               writel(ctx->inst_no, mfc_regs->instance_id);
+               s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                                S5P_FIMV_H2R_CMD_FLUSH_V6, NULL);
        }
 }
@@ -1413,19 +1408,19 @@ static int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx,
        struct s5p_mfc_dev *dev = ctx->dev;
        const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
 
-       WRITEL(ctx->dec_dst_flag, mfc_regs->d_available_dpb_flag_lower);
-       WRITEL(ctx->slice_interface & 0x1, mfc_regs->d_slice_if_enable);
+       writel(ctx->dec_dst_flag, mfc_regs->d_available_dpb_flag_lower);
+       writel(ctx->slice_interface & 0x1, mfc_regs->d_slice_if_enable);
 
-       WRITEL(ctx->inst_no, mfc_regs->instance_id);
+       writel(ctx->inst_no, mfc_regs->instance_id);
        /* Issue different commands to instance basing on whether it
         * is the last frame or not. */
        switch (last_frame) {
        case 0:
-               s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+               s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                                S5P_FIMV_CH_FRAME_START_V6, NULL);
                break;
        case 1:
-               s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+               s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                                S5P_FIMV_CH_LAST_FRAME_V6, NULL);
                break;
        default:
@@ -1458,12 +1453,12 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
 
        /* Set stride lengths for v7 & above */
        if (IS_MFCV7_PLUS(dev)) {
-               WRITEL(ctx->img_width, mfc_regs->e_source_first_plane_stride);
-               WRITEL(ctx->img_width, mfc_regs->e_source_second_plane_stride);
+               writel(ctx->img_width, mfc_regs->e_source_first_plane_stride);
+               writel(ctx->img_width, mfc_regs->e_source_second_plane_stride);
        }
 
-       WRITEL(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+       writel(ctx->inst_no, mfc_regs->instance_id);
+       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
 
        return 0;
@@ -1479,7 +1474,7 @@ static int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx)
 
        if (p_h264->aso) {
                for (i = 0; i < ARRAY_SIZE(p_h264->aso_slice_order); i++) {
-                       WRITEL(p_h264->aso_slice_order[i],
+                       writel(p_h264->aso_slice_order[i],
                                mfc_regs->e_h264_aso_slice_order_0 + i * 4);
                }
        }
@@ -1501,8 +1496,8 @@ static int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx)
 
        s5p_mfc_set_slice_mode(ctx);
 
-       WRITEL(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+       writel(ctx->inst_no, mfc_regs->instance_id);
+       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_FRAME_START_V6, NULL);
 
        mfc_debug(2, "--\n");
@@ -1877,15 +1872,15 @@ static void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq)
 static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev)
 {
        const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
-       WRITEL(0, mfc_regs->risc2host_command);
-       WRITEL(0, mfc_regs->risc2host_int);
+       writel(0, mfc_regs->risc2host_command);
+       writel(0, mfc_regs->risc2host_int);
 }
 
 static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data,
                unsigned int ofs)
 {
        s5p_mfc_clock_on();
-       WRITEL(data, (void *)ofs);
+       writel(data, (volatile void __iomem *)((unsigned long)ofs));
        s5p_mfc_clock_off();
 }
 
@@ -1895,7 +1890,7 @@ s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs)
        int ret;
 
        s5p_mfc_clock_on();
-       ret = READL((void *)ofs);
+       ret = readl((volatile void __iomem *)((unsigned long)ofs));
        s5p_mfc_clock_off();
 
        return ret;
@@ -1903,51 +1898,51 @@ s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs)
 
 static int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_display_first_plane_addr);
+       return readl(dev->mfc_regs->d_display_first_plane_addr);
 }
 
 static int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_decoded_first_plane_addr);
+       return readl(dev->mfc_regs->d_decoded_first_plane_addr);
 }
 
 static int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_display_status);
+       return readl(dev->mfc_regs->d_display_status);
 }
 
 static int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_decoded_status);
+       return readl(dev->mfc_regs->d_decoded_status);
 }
 
 static int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_decoded_frame_type) &
+       return readl(dev->mfc_regs->d_decoded_frame_type) &
                S5P_FIMV_DECODE_FRAME_MASK_V6;
 }
 
 static int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
-       return READL(dev->mfc_regs->d_display_frame_type) &
+       return readl(dev->mfc_regs->d_display_frame_type) &
                S5P_FIMV_DECODE_FRAME_MASK_V6;
 }
 
 static int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_decoded_nal_size);
+       return readl(dev->mfc_regs->d_decoded_nal_size);
 }
 
 static int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->risc2host_command) &
+       return readl(dev->mfc_regs->risc2host_command) &
                S5P_FIMV_RISC2HOST_CMD_MASK;
 }
 
 static int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->error_code);
+       return readl(dev->mfc_regs->error_code);
 }
 
 static int s5p_mfc_err_dec_v6(unsigned int err)
@@ -1962,87 +1957,87 @@ static int s5p_mfc_err_dspl_v6(unsigned int err)
 
 static int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_display_frame_width);
+       return readl(dev->mfc_regs->d_display_frame_width);
 }
 
 static int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_display_frame_height);
+       return readl(dev->mfc_regs->d_display_frame_height);
 }
 
 static int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_min_num_dpb);
+       return readl(dev->mfc_regs->d_min_num_dpb);
 }
 
 static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_min_num_mv);
+       return readl(dev->mfc_regs->d_min_num_mv);
 }
 
 static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->ret_instance_id);
+       return readl(dev->mfc_regs->ret_instance_id);
 }
 
 static int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->e_num_dpb);
+       return readl(dev->mfc_regs->e_num_dpb);
 }
 
 static int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->e_stream_size);
+       return readl(dev->mfc_regs->e_stream_size);
 }
 
 static int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->e_slice_type);
+       return readl(dev->mfc_regs->e_slice_type);
 }
 
 static int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->e_picture_count);
+       return readl(dev->mfc_regs->e_picture_count);
 }
 
 static int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
-       return READL(dev->mfc_regs->d_frame_pack_sei_avail);
+       return readl(dev->mfc_regs->d_frame_pack_sei_avail);
 }
 
 static int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_mvc_num_views);
+       return readl(dev->mfc_regs->d_mvc_num_views);
 }
 
 static int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_mvc_view_id);
+       return readl(dev->mfc_regs->d_mvc_view_id);
 }
 
 static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx)
 {
        return s5p_mfc_read_info_v6(ctx,
-               (unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_top);
+               (__force unsigned long) ctx->dev->mfc_regs->d_ret_picture_tag_top);
 }
 
 static unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx)
 {
        return s5p_mfc_read_info_v6(ctx,
-               (unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_bot);
+               (__force unsigned long) ctx->dev->mfc_regs->d_ret_picture_tag_bot);
 }
 
 static unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx)
 {
        return s5p_mfc_read_info_v6(ctx,
-               (unsigned int) ctx->dev->mfc_regs->d_display_crop_info1);
+               (__force unsigned long) ctx->dev->mfc_regs->d_display_crop_info1);
 }
 
 static unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx)
 {
        return s5p_mfc_read_info_v6(ctx,
-               (unsigned int) ctx->dev->mfc_regs->d_display_crop_info2);
+               (__force unsigned long) ctx->dev->mfc_regs->d_display_crop_info2);
 }
 
 static struct s5p_mfc_regs mfc_regs;
index b6a8be97a96c57715d2454518052351d43864340..826c48945bf50b188357c31d8108c627697bbac6 100644 (file)
@@ -21,7 +21,7 @@
 #include "s5p_mfc_pm.h"
 
 #define MFC_GATE_CLK_NAME      "mfc"
-#define MFC_SCLK_NAME          "sclk-mfc"
+#define MFC_SCLK_NAME          "sclk_mfc"
 #define MFC_SCLK_RATE          (200 * 1000000)
 
 #define CLK_DEBUG
index 369a4c191e18a8e80e63edcb57cb790df28394a3..a9d56f8936b4e576d2e4552b1d86323d15801da5 100644 (file)
@@ -8,7 +8,8 @@
 
 config VIDEO_SAMSUNG_S5P_TV
        bool "Samsung TV driver for S5P platform"
-       depends on (PLAT_S5P || ARCH_EXYNOS) && PM_RUNTIME
+       depends on PM_RUNTIME
+       depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
        default n
        ---help---
          Say Y here to enable selecting the TV output devices for
@@ -70,6 +71,7 @@ config VIDEO_SAMSUNG_S5P_MIXER
        tristate "Samsung Mixer and Video Processor Driver"
        depends on VIDEO_DEV && VIDEO_V4L2
        depends on VIDEO_SAMSUNG_S5P_TV
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        help
          Say Y here if you want support for the Mixer in Samsung S5P SoCs.
index 754740f4b671db0a0749d3b21ee7afdf5c1fc8b1..37c8bd694c5f250c0e7d64f8a601cb14d5c93bcd 100644 (file)
@@ -615,7 +615,7 @@ static int hdmi_s_power(struct v4l2_subdev *sd, int on)
        else
                ret = pm_runtime_put_sync(hdev->dev);
        /* only values < 0 indicate errors */
-       return IS_ERR_VALUE(ret) ? ret : 0;
+       return ret < 0 ? ret : 0;
 }
 
 static int hdmi_s_dv_timings(struct v4l2_subdev *sd,
index 5a7c3796f22e349de4edf608bd5eb8ffee62d0dd..72cf892dd0089af58d9d2eac6bf533b881b1d6bd 100644 (file)
@@ -190,7 +190,7 @@ static int sdo_s_power(struct v4l2_subdev *sd, int on)
                ret = pm_runtime_put_sync(dev);
 
        /* only values < 0 indicate errors */
-       return IS_ERR_VALUE(ret) ? ret : 0;
+       return ret < 0 ? ret : 0;
 }
 
 static int sdo_streamon(struct sdo_device *sdev)
index 3dd762e5b67e8e53ff05d2fd57351c71e9471797..db8c17bb4aaaf357b6aa1c613e5aee570b953d5d 100644 (file)
@@ -289,7 +289,7 @@ static int sii9234_s_power(struct v4l2_subdev *sd, int on)
        else
                ret = pm_runtime_put(&ctx->client->dev);
        /* only values < 0 indicate errors */
-       return IS_ERR_VALUE(ret) ? ret : 0;
+       return ret < 0 ? ret : 0;
 }
 
 static int sii9234_s_stream(struct v4l2_subdev *sd, int enable)
index 8dc279d4d5610fac3219cb253aa9d383108ab3d4..be3b3bc71a0fcdd2f9e931a06127a71aa33555a9 100644 (file)
@@ -26,6 +26,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-mem2mem.h>
+#include <media/v4l2-image-sizes.h>
 #include <media/videobuf2-dma-contig.h>
 
 #define VEU_STR 0x00 /* start register */
@@ -135,9 +136,6 @@ enum sh_veu_fmt_idx {
        SH_VEU_FMT_RGB24,
 };
 
-#define VGA_WIDTH      640
-#define VGA_HEIGHT     480
-
 #define DEFAULT_IN_WIDTH       VGA_WIDTH
 #define DEFAULT_IN_HEIGHT      VGA_HEIGHT
 #define DEFAULT_IN_FMTIDX      SH_VEU_FMT_NV12
index 6540847f4e1d3345cb90a73ef6ad8531c03f2150..f2776cd415ca81625df0972330adbb636db9d6d8 100644 (file)
@@ -20,6 +20,8 @@ config SOC_CAMERA_PLATFORM
 config VIDEO_MX3
        tristate "i.MX3x Camera Sensor Interface driver"
        depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
+       depends on MX3_IPU || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          This is a v4l2 driver for the i.MX3x Camera Sensor Interface
@@ -35,6 +37,7 @@ config VIDEO_RCAR_VIN
        tristate "R-Car Video Input (VIN) support"
        depends on VIDEO_DEV && SOC_CAMERA
        depends on ARCH_SHMOBILE || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select SOC_CAMERA_SCALE_CROP
        ---help---
@@ -51,6 +54,7 @@ config VIDEO_SH_MOBILE_CEU
        tristate "SuperH Mobile CEU Interface driver"
        depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
        depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select SOC_CAMERA_SCALE_CROP
        ---help---
@@ -58,7 +62,9 @@ config VIDEO_SH_MOBILE_CEU
 
 config VIDEO_OMAP1
        tristate "OMAP1 Camera Interface driver"
-       depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA
+       depends on VIDEO_DEV && SOC_CAMERA
+       depends on ARCH_OMAP1
+       depends on HAS_DMA
        select VIDEOBUF_DMA_CONTIG
        select VIDEOBUF_DMA_SG
        ---help---
@@ -66,14 +72,18 @@ config VIDEO_OMAP1
 
 config VIDEO_MX2
        tristate "i.MX27 Camera Sensor Interface driver"
-       depends on VIDEO_DEV && SOC_CAMERA && SOC_IMX27
+       depends on VIDEO_DEV && SOC_CAMERA
+       depends on SOC_IMX27 || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          This is a v4l2 driver for the i.MX27 Camera Sensor Interface
 
 config VIDEO_ATMEL_ISI
        tristate "ATMEL Image Sensor Interface (ISI) support"
-       depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91
+       depends on VIDEO_DEV && SOC_CAMERA
+       depends on ARCH_AT91 || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          This module makes the ATMEL Image Sensor Interface available
index 3408b045b3f1cf2697715c4e552c0289284f3443..c5291b00105758b8452b0f9ef383780c794fbac7 100644 (file)
@@ -54,7 +54,7 @@ static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl)
 struct isi_dma_desc {
        struct list_head list;
        struct fbd *p_fbd;
-       u32 fbd_phys;
+       dma_addr_t fbd_phys;
 };
 
 /* Frame buffer data */
@@ -75,7 +75,7 @@ struct atmel_isi {
 
        /* Allocate descriptors for dma buffer use */
        struct fbd                      *p_fb_descriptors;
-       u32                             fb_descriptors_phys;
+       dma_addr_t                      fb_descriptors_phys;
        struct                          list_head dma_desc_head;
        struct isi_dma_desc             dma_desc[MAX_BUFFER_NUM];
 
@@ -169,7 +169,7 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
                isi->active = list_entry(isi->video_buffer_list.next,
                                        struct frame_buffer, list);
                isi_writel(isi, ISI_DMA_C_DSCR,
-                       isi->active->p_dma_desc->fbd_phys);
+                       (u32)isi->active->p_dma_desc->fbd_phys);
                isi_writel(isi, ISI_DMA_C_CTRL,
                        ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
                isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
@@ -346,7 +346,7 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
                return;
        }
 
-       isi_writel(isi, ISI_DMA_C_DSCR, buffer->p_dma_desc->fbd_phys);
+       isi_writel(isi, ISI_DMA_C_DSCR, (u32)buffer->p_dma_desc->fbd_phys);
        isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
        isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
 
@@ -384,7 +384,6 @@ 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);
        struct atmel_isi *isi = ici->priv;
-       u32 sr = 0;
        int ret;
 
        /* Reset ISI */
@@ -394,11 +393,11 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
                return ret;
        }
        /* Disable all interrupts */
-       isi_writel(isi, ISI_INTDIS, ~0UL);
+       isi_writel(isi, ISI_INTDIS, (u32)~0UL);
 
        spin_lock_irq(&isi->lock);
        /* Clear any pending interrupt */
-       sr = isi_readl(isi, ISI_STATUS);
+       isi_readl(isi, ISI_STATUS);
 
        if (count)
                start_dma(isi, isi->active);
index b40bc2e5ba47d6cbcf8ec942adc53a0797970ac7..2347612a4cc167a08af0bf831020d7b7dc932ebd 100644 (file)
@@ -809,10 +809,9 @@ static int mx2_camera_init_videobuf(struct vb2_queue *q,
 
 static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
 {
-       u32 cntl;
        int count = 0;
 
-       cntl = readl(pcdev->base_emma + PRP_CNTL);
+       readl(pcdev->base_emma + PRP_CNTL);
        writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
        while (count++ < 100) {
                if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST))
@@ -1003,7 +1002,7 @@ static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev,
                              struct v4l2_mbus_framefmt *mf_in,
                              struct v4l2_pix_format *pix_out, bool apply)
 {
-       int num, den;
+       unsigned int num, den;
        unsigned long m;
        int i, dir;
 
index 64dc80ccd6f932ded137ab36dd562bda860d2366..66178fc9f9ebf90b720430016321668ab5dbcfd8 100644 (file)
@@ -1694,7 +1694,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev,
                break;
        default:
                break;
-       };
+       }
 
        if (ep.bus.parallel.flags & V4L2_MBUS_MASTER)
                pcdev->platform_flags |= PXA_CAMERA_MASTER;
index 85d579f65f5206d0558ed38e4ed6ccba5aa7f0e5..20defcb8b31b005fca81c2f4c0f4ad3b51ffd817 100644 (file)
@@ -981,7 +981,7 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx,
 
                if (shift == 3) {
                        dev_err(dev,
-                               "Failed to configure the client below %ux%x\n",
+                               "Failed to configure the client below %ux%u\n",
                                mf.width, mf.height);
                        return -EIO;
                }
@@ -1502,7 +1502,7 @@ static int rcar_vin_probe(struct platform_device *pdev)
        } else {
                priv->ici.nr = of_alias_get_id(pdev->dev.of_node, "vin");
                priv->chip = (enum chip_id)match->data;
-       };
+       }
 
        spin_lock_init(&priv->lock);
        INIT_LIST_HEAD(&priv->capture);
index f4308fed54318625d6e802aac288b96bd8cecd68..8e61b976da19ed17fe09866eb3efd7d6544a02bd 100644 (file)
@@ -437,6 +437,22 @@ static int soc_camera_prepare_buf(struct file *file, void *priv,
                return vb2_prepare_buf(&icd->vb2_vidq, b);
 }
 
+static int soc_camera_expbuf(struct file *file, void *priv,
+                            struct v4l2_exportbuffer *p)
+{
+       struct soc_camera_device *icd = file->private_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+       if (icd->streamer != file)
+               return -EBUSY;
+
+       /* videobuf2 only */
+       if (ici->ops->init_videobuf)
+               return -EINVAL;
+       else
+               return vb2_expbuf(&icd->vb2_vidq, p);
+}
+
 /* Always entered with .host_lock held */
 static int soc_camera_init_user_formats(struct soc_camera_device *icd)
 {
@@ -1347,13 +1363,11 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
                return -ENODEV;
        }
 
-       ssdd = kzalloc(sizeof(*ssdd), GFP_KERNEL);
+       ssdd = kmemdup(&sdesc->subdev_desc, sizeof(*ssdd), GFP_KERNEL);
        if (!ssdd) {
                ret = -ENOMEM;
                goto ealloc;
        }
-
-       memcpy(ssdd, &sdesc->subdev_desc, sizeof(*ssdd));
        /*
         * In synchronous case we request regulators ourselves in
         * soc_camera_pdrv_probe(), make sure the subdevice driver doesn't try
@@ -2085,6 +2099,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
        .vidioc_dqbuf            = soc_camera_dqbuf,
        .vidioc_create_bufs      = soc_camera_create_bufs,
        .vidioc_prepare_buf      = soc_camera_prepare_buf,
+       .vidioc_expbuf           = soc_camera_expbuf,
        .vidioc_streamon         = soc_camera_streamon,
        .vidioc_streamoff        = soc_camera_streamoff,
        .vidioc_cropcap          = soc_camera_cropcap,
index a51a0135980534e6952db9f492b091128938eb1e..3e2e3a33e6ed850e4ceccd223f90f1c4eb956875 100644 (file)
@@ -329,7 +329,7 @@ int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size)
        if (!buf->addr)
                return -ENOMEM;
 
-       WARN_ON((u32) buf->addr & VPDMA_DESC_ALIGN);
+       WARN_ON(((unsigned long)buf->addr & VPDMA_DESC_ALIGN) != 0);
 
        return 0;
 }
@@ -584,7 +584,7 @@ static void dump_dtd(struct vpdma_dtd *dtd)
                pr_debug("word1: line_length = %d, xfer_height = %d\n",
                        dtd_get_line_length(dtd), dtd_get_xfer_height(dtd));
 
-       pr_debug("word2: start_addr = 0x%08x\n", dtd->start_addr);
+       pr_debug("word2: start_addr = %pad\n", &dtd->start_addr);
 
        pr_debug("word3: pkt_type = %d, mode = %d, dir = %d, chan = %d, "
                "pri = %d, next_chan = %d\n", dtd_get_pkt_type(dtd),
index 972f43f69206b8156dc492d6915f1ca97e8ba536..9a081c2911598502fb33e0d500d876a0361fcbc0 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/log2.h>
+#include <linux/sizes.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
@@ -138,12 +139,12 @@ struct vpe_dei_regs {
  * default expert DEI register values, unlikely to be modified.
  */
 static const struct vpe_dei_regs dei_regs = {
-       0x020C0804u,
-       0x0118100Fu,
-       0x08040200u,
-       0x1010100Cu,
-       0x10101010u,
-       0x10101010u,
+       .mdt_spacial_freq_thr_reg = 0x020C0804u,
+       .edi_config_reg = 0x0118100Fu,
+       .edi_lut_reg0 = 0x08040200u,
+       .edi_lut_reg1 = 0x1010100Cu,
+       .edi_lut_reg2 = 0x10101010u,
+       .edi_lut_reg3 = 0x10101010u,
 };
 
 /*
@@ -834,10 +835,10 @@ static int set_srcdst_params(struct vpe_ctx *ctx)
                                        VPDMA_STRIDE_ALIGN);
                mv_buf_size = bytes_per_line * s_q_data->height;
 
-               ctx->deinterlacing = 1;
+               ctx->deinterlacing = true;
                src_h <<= 1;
        } else {
-               ctx->deinterlacing = 0;
+               ctx->deinterlacing = false;
                mv_buf_size = 0;
        }
 
@@ -2343,8 +2344,7 @@ v4l2_dev_unreg:
 
 static int vpe_remove(struct platform_device *pdev)
 {
-       struct vpe_dev *dev =
-               (struct vpe_dev *) platform_get_drvdata(pdev);
+       struct vpe_dev *dev = platform_get_drvdata(pdev);
 
        v4l2_info(&dev->v4l2_dev, "Removing " VPE_MODULE_NAME);
 
index b4f9d03636e3e8067e7adefc50070318915e37d1..ae6870cb8339dbff2959c956e8a8229d96b598a3 100644 (file)
@@ -18,6 +18,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-image-sizes.h>
 #include <media/ov7670.h>
 #include <media/videobuf-dma-sg.h>
 #include <linux/delay.h>
@@ -48,14 +49,6 @@ MODULE_PARM_DESC(override_serial,
                "the XO 1.5 serial port is enabled.  Set this option "
                "to force-enable the camera.");
 
-/*
- * Basic window sizes.
- */
-#define VGA_WIDTH      640
-#define VGA_HEIGHT     480
-#define QCIF_WIDTH     176
-#define        QCIF_HEIGHT     144
-
 /*
  * The structure describing our camera.
  */
@@ -89,7 +82,7 @@ struct via_camera {
         * live in frame buffer memory, so we don't call them "DMA".
         */
        unsigned int cb_offsets[3];     /* offsets into fb mem */
-       u8 *cb_addrs[3];                /* Kernel-space addresses */
+       u8 __iomem *cb_addrs[3];                /* Kernel-space addresses */
        int n_cap_bufs;                 /* How many are we using? */
        int next_buf;
        struct videobuf_queue vb_queue;
@@ -1283,7 +1276,7 @@ static bool viacam_serial_is_enabled(void)
                        VIACAM_SERIAL_CREG, &cbyte);
        if ((cbyte & VIACAM_SERIAL_BIT) == 0)
                return false; /* Not enabled */
-       if (override_serial == 0) {
+       if (!override_serial) {
                printk(KERN_NOTICE "Via camera: serial port is enabled, " \
                                "refusing to load.\n");
                printk(KERN_NOTICE "Specify override_serial=1 to force " \
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
deleted file mode 100644 (file)
index 8033371..0000000
+++ /dev/null
@@ -1,1542 +0,0 @@
-/*
- * Virtual Video driver - This code emulates a real video device with v4l2 api
- *
- * Copyright (c) 2006 by:
- *      Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
- *      Ted Walther <ted--a.t--enumera.com>
- *      John Sokol <sokol--a.t--videotechnology.com>
- *      http://v4l.videotechnology.com/
- *
- *      Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski
- *      Copyright (c) 2010 Samsung Electronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the BSD Licence, 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/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/font.h>
-#include <linux/mutex.h>
-#include <linux/videodev2.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <media/videobuf2-vmalloc.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-common.h>
-
-#define VIVI_MODULE_NAME "vivi"
-
-/* Maximum allowed frame rate
- *
- * Vivi will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range.
- *
- * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that
- * might hit application errors when they manipulate these values.
- *
- * Besides, for tpf < 1ms image-generation logic should be changed, to avoid
- * producing frames with equal content.
- */
-#define FPS_MAX 1000
-
-#define MAX_WIDTH 1920
-#define MAX_HEIGHT 1200
-
-#define VIVI_VERSION "0.8.1"
-
-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION(VIVI_VERSION);
-
-static unsigned video_nr = -1;
-module_param(video_nr, uint, 0644);
-MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
-
-static unsigned n_devs = 1;
-module_param(n_devs, uint, 0644);
-MODULE_PARM_DESC(n_devs, "number of video devices to create");
-
-static unsigned debug;
-module_param(debug, uint, 0644);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-/* Global font descriptor */
-static const u8 *font8x16;
-
-/* timeperframe: min/max and default */
-static const struct v4l2_fract
-       tpf_min     = {.numerator = 1,          .denominator = FPS_MAX},
-       tpf_max     = {.numerator = FPS_MAX,    .denominator = 1},
-       tpf_default = {.numerator = 1001,       .denominator = 30000};  /* NTSC */
-
-#define dprintk(dev, level, fmt, arg...) \
-       v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
-
-/* ------------------------------------------------------------------
-       Basic structures
-   ------------------------------------------------------------------*/
-
-struct vivi_fmt {
-       const char *name;
-       u32   fourcc;          /* v4l2 format id */
-       u8    depth;
-       bool  is_yuv;
-};
-
-static const struct vivi_fmt formats[] = {
-       {
-               .name     = "4:2:2, packed, YUYV",
-               .fourcc   = V4L2_PIX_FMT_YUYV,
-               .depth    = 16,
-               .is_yuv   = true,
-       },
-       {
-               .name     = "4:2:2, packed, UYVY",
-               .fourcc   = V4L2_PIX_FMT_UYVY,
-               .depth    = 16,
-               .is_yuv   = true,
-       },
-       {
-               .name     = "4:2:2, packed, YVYU",
-               .fourcc   = V4L2_PIX_FMT_YVYU,
-               .depth    = 16,
-               .is_yuv   = true,
-       },
-       {
-               .name     = "4:2:2, packed, VYUY",
-               .fourcc   = V4L2_PIX_FMT_VYUY,
-               .depth    = 16,
-               .is_yuv   = true,
-       },
-       {
-               .name     = "RGB565 (LE)",
-               .fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
-               .depth    = 16,
-       },
-       {
-               .name     = "RGB565 (BE)",
-               .fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
-               .depth    = 16,
-       },
-       {
-               .name     = "RGB555 (LE)",
-               .fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
-               .depth    = 16,
-       },
-       {
-               .name     = "RGB555 (BE)",
-               .fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
-               .depth    = 16,
-       },
-       {
-               .name     = "RGB24 (LE)",
-               .fourcc   = V4L2_PIX_FMT_RGB24, /* rgb */
-               .depth    = 24,
-       },
-       {
-               .name     = "RGB24 (BE)",
-               .fourcc   = V4L2_PIX_FMT_BGR24, /* bgr */
-               .depth    = 24,
-       },
-       {
-               .name     = "RGB32 (LE)",
-               .fourcc   = V4L2_PIX_FMT_RGB32, /* argb */
-               .depth    = 32,
-       },
-       {
-               .name     = "RGB32 (BE)",
-               .fourcc   = V4L2_PIX_FMT_BGR32, /* bgra */
-               .depth    = 32,
-       },
-};
-
-static const struct vivi_fmt *__get_format(u32 pixelformat)
-{
-       const struct vivi_fmt *fmt;
-       unsigned int k;
-
-       for (k = 0; k < ARRAY_SIZE(formats); k++) {
-               fmt = &formats[k];
-               if (fmt->fourcc == pixelformat)
-                       break;
-       }
-
-       if (k == ARRAY_SIZE(formats))
-               return NULL;
-
-       return &formats[k];
-}
-
-static const struct vivi_fmt *get_format(struct v4l2_format *f)
-{
-       return __get_format(f->fmt.pix.pixelformat);
-}
-
-/* buffer for one video frame */
-struct vivi_buffer {
-       /* common v4l buffer stuff -- must be first */
-       struct vb2_buffer       vb;
-       struct list_head        list;
-};
-
-struct vivi_dmaqueue {
-       struct list_head       active;
-
-       /* thread for generating video stream*/
-       struct task_struct         *kthread;
-       wait_queue_head_t          wq;
-       /* Counters to control fps rate */
-       int                        frame;
-       int                        ini_jiffies;
-};
-
-static LIST_HEAD(vivi_devlist);
-
-struct vivi_dev {
-       struct list_head           vivi_devlist;
-       struct v4l2_device         v4l2_dev;
-       struct v4l2_ctrl_handler   ctrl_handler;
-       struct video_device        vdev;
-
-       /* controls */
-       struct v4l2_ctrl           *brightness;
-       struct v4l2_ctrl           *contrast;
-       struct v4l2_ctrl           *saturation;
-       struct v4l2_ctrl           *hue;
-       struct {
-               /* autogain/gain cluster */
-               struct v4l2_ctrl           *autogain;
-               struct v4l2_ctrl           *gain;
-       };
-       struct v4l2_ctrl           *volume;
-       struct v4l2_ctrl           *alpha;
-       struct v4l2_ctrl           *button;
-       struct v4l2_ctrl           *boolean;
-       struct v4l2_ctrl           *int32;
-       struct v4l2_ctrl           *int64;
-       struct v4l2_ctrl           *menu;
-       struct v4l2_ctrl           *string;
-       struct v4l2_ctrl           *bitmask;
-       struct v4l2_ctrl           *int_menu;
-
-       spinlock_t                 slock;
-       struct mutex               mutex;
-
-       struct vivi_dmaqueue       vidq;
-
-       /* Several counters */
-       unsigned                   ms;
-       unsigned long              jiffies;
-       unsigned                   button_pressed;
-
-       int                        mv_count;    /* Controls bars movement */
-
-       /* Input Number */
-       int                        input;
-
-       /* video capture */
-       const struct vivi_fmt      *fmt;
-       struct v4l2_fract          timeperframe;
-       unsigned int               width, height;
-       struct vb2_queue           vb_vidq;
-       unsigned int               seq_count;
-
-       u8                         bars[9][3];
-       u8                         line[MAX_WIDTH * 8] __attribute__((__aligned__(4)));
-       unsigned int               pixelsize;
-       u8                         alpha_component;
-       u32                        textfg, textbg;
-};
-
-/* ------------------------------------------------------------------
-       DMA and thread functions
-   ------------------------------------------------------------------*/
-
-/* Bars and Colors should match positions */
-
-enum colors {
-       WHITE,
-       AMBER,
-       CYAN,
-       GREEN,
-       MAGENTA,
-       RED,
-       BLUE,
-       BLACK,
-       TEXT_BLACK,
-};
-
-/* R   G   B */
-#define COLOR_WHITE    {204, 204, 204}
-#define COLOR_AMBER    {208, 208,   0}
-#define COLOR_CYAN     {  0, 206, 206}
-#define        COLOR_GREEN     {  0, 239,   0}
-#define COLOR_MAGENTA  {239,   0, 239}
-#define COLOR_RED      {205,   0,   0}
-#define COLOR_BLUE     {  0,   0, 255}
-#define COLOR_BLACK    {  0,   0,   0}
-
-struct bar_std {
-       u8 bar[9][3];
-};
-
-/* Maximum number of bars are 10 - otherwise, the input print code
-   should be modified */
-static const struct bar_std bars[] = {
-       {       /* Standard ITU-R color bar sequence */
-               { COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN,
-                 COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK }
-       }, {
-               { COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE,
-                 COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK }
-       }, {
-               { COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE,
-                 COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK }
-       }, {
-               { COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE,
-                 COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK }
-       },
-};
-
-#define NUM_INPUTS ARRAY_SIZE(bars)
-
-#define TO_Y(r, g, b) \
-       (((16829 * r + 33039 * g + 6416 * b  + 32768) >> 16) + 16)
-/* RGB to  V(Cr) Color transform */
-#define TO_V(r, g, b) \
-       (((28784 * r - 24103 * g - 4681 * b  + 32768) >> 16) + 128)
-/* RGB to  U(Cb) Color transform */
-#define TO_U(r, g, b) \
-       (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
-
-/* precalculate color bar values to speed up rendering */
-static void precalculate_bars(struct vivi_dev *dev)
-{
-       u8 r, g, b;
-       int k, is_yuv;
-
-       for (k = 0; k < 9; k++) {
-               r = bars[dev->input].bar[k][0];
-               g = bars[dev->input].bar[k][1];
-               b = bars[dev->input].bar[k][2];
-               is_yuv = dev->fmt->is_yuv;
-
-               switch (dev->fmt->fourcc) {
-               case V4L2_PIX_FMT_RGB565:
-               case V4L2_PIX_FMT_RGB565X:
-                       r >>= 3;
-                       g >>= 2;
-                       b >>= 3;
-                       break;
-               case V4L2_PIX_FMT_RGB555:
-               case V4L2_PIX_FMT_RGB555X:
-                       r >>= 3;
-                       g >>= 3;
-                       b >>= 3;
-                       break;
-               case V4L2_PIX_FMT_YUYV:
-               case V4L2_PIX_FMT_UYVY:
-               case V4L2_PIX_FMT_YVYU:
-               case V4L2_PIX_FMT_VYUY:
-               case V4L2_PIX_FMT_RGB24:
-               case V4L2_PIX_FMT_BGR24:
-               case V4L2_PIX_FMT_RGB32:
-               case V4L2_PIX_FMT_BGR32:
-                       break;
-               }
-
-               if (is_yuv) {
-                       dev->bars[k][0] = TO_Y(r, g, b);        /* Luma */
-                       dev->bars[k][1] = TO_U(r, g, b);        /* Cb */
-                       dev->bars[k][2] = TO_V(r, g, b);        /* Cr */
-               } else {
-                       dev->bars[k][0] = r;
-                       dev->bars[k][1] = g;
-                       dev->bars[k][2] = b;
-               }
-       }
-}
-
-/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
-static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd)
-{
-       u8 r_y, g_u, b_v;
-       u8 alpha = dev->alpha_component;
-       int color;
-       u8 *p;
-
-       r_y = dev->bars[colorpos][0]; /* R or precalculated Y */
-       g_u = dev->bars[colorpos][1]; /* G or precalculated U */
-       b_v = dev->bars[colorpos][2]; /* B or precalculated V */
-
-       for (color = 0; color < dev->pixelsize; color++) {
-               p = buf + color;
-
-               switch (dev->fmt->fourcc) {
-               case V4L2_PIX_FMT_YUYV:
-                       switch (color) {
-                       case 0:
-                               *p = r_y;
-                               break;
-                       case 1:
-                               *p = odd ? b_v : g_u;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_UYVY:
-                       switch (color) {
-                       case 0:
-                               *p = odd ? b_v : g_u;
-                               break;
-                       case 1:
-                               *p = r_y;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_YVYU:
-                       switch (color) {
-                       case 0:
-                               *p = r_y;
-                               break;
-                       case 1:
-                               *p = odd ? g_u : b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_VYUY:
-                       switch (color) {
-                       case 0:
-                               *p = odd ? g_u : b_v;
-                               break;
-                       case 1:
-                               *p = r_y;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB565:
-                       switch (color) {
-                       case 0:
-                               *p = (g_u << 5) | b_v;
-                               break;
-                       case 1:
-                               *p = (r_y << 3) | (g_u >> 3);
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB565X:
-                       switch (color) {
-                       case 0:
-                               *p = (r_y << 3) | (g_u >> 3);
-                               break;
-                       case 1:
-                               *p = (g_u << 5) | b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB555:
-                       switch (color) {
-                       case 0:
-                               *p = (g_u << 5) | b_v;
-                               break;
-                       case 1:
-                               *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB555X:
-                       switch (color) {
-                       case 0:
-                               *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
-                               break;
-                       case 1:
-                               *p = (g_u << 5) | b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB24:
-                       switch (color) {
-                       case 0:
-                               *p = r_y;
-                               break;
-                       case 1:
-                               *p = g_u;
-                               break;
-                       case 2:
-                               *p = b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_BGR24:
-                       switch (color) {
-                       case 0:
-                               *p = b_v;
-                               break;
-                       case 1:
-                               *p = g_u;
-                               break;
-                       case 2:
-                               *p = r_y;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB32:
-                       switch (color) {
-                       case 0:
-                               *p = alpha;
-                               break;
-                       case 1:
-                               *p = r_y;
-                               break;
-                       case 2:
-                               *p = g_u;
-                               break;
-                       case 3:
-                               *p = b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_BGR32:
-                       switch (color) {
-                       case 0:
-                               *p = b_v;
-                               break;
-                       case 1:
-                               *p = g_u;
-                               break;
-                       case 2:
-                               *p = r_y;
-                               break;
-                       case 3:
-                               *p = alpha;
-                               break;
-                       }
-                       break;
-               }
-       }
-}
-
-static void precalculate_line(struct vivi_dev *dev)
-{
-       unsigned pixsize  = dev->pixelsize;
-       unsigned pixsize2 = 2*pixsize;
-       int colorpos;
-       u8 *pos;
-
-       for (colorpos = 0; colorpos < 16; ++colorpos) {
-               u8 pix[8];
-               int wstart =  colorpos    * dev->width / 8;
-               int wend   = (colorpos+1) * dev->width / 8;
-               int w;
-
-               gen_twopix(dev, &pix[0],        colorpos % 8, 0);
-               gen_twopix(dev, &pix[pixsize],  colorpos % 8, 1);
-
-               for (w = wstart/2*2, pos = dev->line + w*pixsize; w < wend; w += 2, pos += pixsize2)
-                       memcpy(pos, pix, pixsize2);
-       }
-}
-
-/* need this to do rgb24 rendering */
-typedef struct { u16 __; u8 _; } __attribute__((packed)) x24;
-
-static void gen_text(struct vivi_dev *dev, char *basep,
-                                       int y, int x, char *text)
-{
-       int line;
-       unsigned int width = dev->width;
-
-       /* Checks if it is possible to show string */
-       if (y + 16 >= dev->height || x + strlen(text) * 8 >= width)
-               return;
-
-       /* Print stream time */
-#define PRINTSTR(PIXTYPE) do { \
-       PIXTYPE fg;     \
-       PIXTYPE bg;     \
-       memcpy(&fg, &dev->textfg, sizeof(PIXTYPE));     \
-       memcpy(&bg, &dev->textbg, sizeof(PIXTYPE));     \
-       \
-       for (line = 0; line < 16; line++) {     \
-               PIXTYPE *pos = (PIXTYPE *)( basep + ((y + line) * width + x) * sizeof(PIXTYPE) );       \
-               u8 *s;  \
-       \
-               for (s = text; *s; s++) {       \
-                       u8 chr = font8x16[*s * 16 + line];      \
-       \
-                       pos[0] = (chr & (0x01 << 7) ? fg : bg); \
-                       pos[1] = (chr & (0x01 << 6) ? fg : bg); \
-                       pos[2] = (chr & (0x01 << 5) ? fg : bg); \
-                       pos[3] = (chr & (0x01 << 4) ? fg : bg); \
-                       pos[4] = (chr & (0x01 << 3) ? fg : bg); \
-                       pos[5] = (chr & (0x01 << 2) ? fg : bg); \
-                       pos[6] = (chr & (0x01 << 1) ? fg : bg); \
-                       pos[7] = (chr & (0x01 << 0) ? fg : bg); \
-       \
-                       pos += 8;       \
-               }       \
-       }       \
-} while (0)
-
-       switch (dev->pixelsize) {
-       case 2:
-               PRINTSTR(u16); break;
-       case 4:
-               PRINTSTR(u32); break;
-       case 3:
-               PRINTSTR(x24); break;
-       }
-}
-
-static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
-{
-       int stride = dev->width * dev->pixelsize;
-       int hmax = dev->height;
-       void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
-       unsigned ms;
-       char str[100];
-       int h, line = 1;
-       u8 *linestart;
-       s32 gain;
-
-       if (!vbuf)
-               return;
-
-       linestart = dev->line + (dev->mv_count % dev->width) * dev->pixelsize;
-
-       for (h = 0; h < hmax; h++)
-               memcpy(vbuf + h * stride, linestart, stride);
-
-       /* Updates stream time */
-
-       gen_twopix(dev, (u8 *)&dev->textbg, TEXT_BLACK, /*odd=*/ 0);
-       gen_twopix(dev, (u8 *)&dev->textfg, WHITE, /*odd=*/ 0);
-
-       dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);
-       dev->jiffies = jiffies;
-       ms = dev->ms;
-       snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ",
-                       (ms / (60 * 60 * 1000)) % 24,
-                       (ms / (60 * 1000)) % 60,
-                       (ms / 1000) % 60,
-                       ms % 1000);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " %dx%d, input %d ",
-                       dev->width, dev->height, dev->input);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-
-       gain = v4l2_ctrl_g_ctrl(dev->gain);
-       mutex_lock(dev->ctrl_handler.lock);
-       snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
-                       dev->brightness->cur.val,
-                       dev->contrast->cur.val,
-                       dev->saturation->cur.val,
-                       dev->hue->cur.val);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ",
-                       dev->autogain->cur.val, gain, dev->volume->cur.val,
-                       dev->alpha->cur.val);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
-                       dev->int32->cur.val,
-                       *dev->int64->p_cur.p_s64,
-                       dev->bitmask->cur.val);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
-                       dev->boolean->cur.val,
-                       dev->menu->qmenu[dev->menu->cur.val],
-                       dev->string->p_cur.p_char);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
-                       dev->int_menu->qmenu_int[dev->int_menu->cur.val],
-                       dev->int_menu->cur.val);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-       mutex_unlock(dev->ctrl_handler.lock);
-       if (dev->button_pressed) {
-               dev->button_pressed--;
-               snprintf(str, sizeof(str), " button pressed!");
-               gen_text(dev, vbuf, line++ * 16, 16, str);
-       }
-
-       dev->mv_count += 2;
-
-       buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
-       buf->vb.v4l2_buf.sequence = dev->seq_count++;
-       v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
-}
-
-static void vivi_thread_tick(struct vivi_dev *dev)
-{
-       struct vivi_dmaqueue *dma_q = &dev->vidq;
-       struct vivi_buffer *buf;
-       unsigned long flags = 0;
-
-       dprintk(dev, 1, "Thread tick\n");
-
-       spin_lock_irqsave(&dev->slock, flags);
-       if (list_empty(&dma_q->active)) {
-               dprintk(dev, 1, "No active queue to serve\n");
-               spin_unlock_irqrestore(&dev->slock, flags);
-               return;
-       }
-
-       buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
-       list_del(&buf->list);
-       spin_unlock_irqrestore(&dev->slock, flags);
-
-       v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
-
-       /* Fill buffer */
-       vivi_fillbuff(dev, buf);
-       dprintk(dev, 1, "filled buffer %p\n", buf);
-
-       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
-       dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
-}
-
-#define frames_to_ms(dev, frames)                              \
-       ((frames * dev->timeperframe.numerator * 1000) / dev->timeperframe.denominator)
-
-static void vivi_sleep(struct vivi_dev *dev)
-{
-       struct vivi_dmaqueue *dma_q = &dev->vidq;
-       int timeout;
-       DECLARE_WAITQUEUE(wait, current);
-
-       dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
-               (unsigned long)dma_q);
-
-       add_wait_queue(&dma_q->wq, &wait);
-       if (kthread_should_stop())
-               goto stop_task;
-
-       /* Calculate time to wake up */
-       timeout = msecs_to_jiffies(frames_to_ms(dev, 1));
-
-       vivi_thread_tick(dev);
-
-       schedule_timeout_interruptible(timeout);
-
-stop_task:
-       remove_wait_queue(&dma_q->wq, &wait);
-       try_to_freeze();
-}
-
-static int vivi_thread(void *data)
-{
-       struct vivi_dev *dev = data;
-
-       dprintk(dev, 1, "thread started\n");
-
-       set_freezable();
-
-       for (;;) {
-               vivi_sleep(dev);
-
-               if (kthread_should_stop())
-                       break;
-       }
-       dprintk(dev, 1, "thread: exit\n");
-       return 0;
-}
-
-static int vivi_start_generating(struct vivi_dev *dev)
-{
-       struct vivi_dmaqueue *dma_q = &dev->vidq;
-
-       dprintk(dev, 1, "%s\n", __func__);
-
-       /* Resets frame counters */
-       dev->ms = 0;
-       dev->mv_count = 0;
-       dev->jiffies = jiffies;
-
-       dma_q->frame = 0;
-       dma_q->ini_jiffies = jiffies;
-       dma_q->kthread = kthread_run(vivi_thread, dev, "%s",
-                                    dev->v4l2_dev.name);
-
-       if (IS_ERR(dma_q->kthread)) {
-               v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-               return PTR_ERR(dma_q->kthread);
-       }
-       /* Wakes thread */
-       wake_up_interruptible(&dma_q->wq);
-
-       dprintk(dev, 1, "returning from %s\n", __func__);
-       return 0;
-}
-
-static void vivi_stop_generating(struct vivi_dev *dev)
-{
-       struct vivi_dmaqueue *dma_q = &dev->vidq;
-
-       dprintk(dev, 1, "%s\n", __func__);
-
-       /* shutdown control thread */
-       if (dma_q->kthread) {
-               kthread_stop(dma_q->kthread);
-               dma_q->kthread = NULL;
-       }
-
-       /*
-        * Typical driver might need to wait here until dma engine stops.
-        * In this case we can abort imiedetly, so it's just a noop.
-        */
-
-       /* Release all active buffers */
-       while (!list_empty(&dma_q->active)) {
-               struct vivi_buffer *buf;
-               buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
-               list_del(&buf->list);
-               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
-               dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
-       }
-}
-/* ------------------------------------------------------------------
-       Videobuf operations
-   ------------------------------------------------------------------*/
-static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
-                               unsigned int *nbuffers, unsigned int *nplanes,
-                               unsigned int sizes[], void *alloc_ctxs[])
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vq);
-       unsigned long size;
-
-       size = dev->width * dev->height * dev->pixelsize;
-       if (fmt) {
-               if (fmt->fmt.pix.sizeimage < size)
-                       return -EINVAL;
-               size = fmt->fmt.pix.sizeimage;
-               /* check against insane over 8K resolution buffers */
-               if (size > 7680 * 4320 * dev->pixelsize)
-                       return -EINVAL;
-       }
-
-       *nplanes = 1;
-
-       sizes[0] = size;
-
-       /*
-        * videobuf2-vmalloc allocator is context-less so no need to set
-        * alloc_ctxs array.
-        */
-
-       dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__,
-               *nbuffers, size);
-
-       return 0;
-}
-
-static int buffer_prepare(struct vb2_buffer *vb)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
-       struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
-       unsigned long size;
-
-       dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
-
-       BUG_ON(NULL == dev->fmt);
-
-       /*
-        * Theses properties only change when queue is idle, see s_fmt.
-        * The below checks should not be performed here, on each
-        * buffer_prepare (i.e. on each qbuf). Most of the code in this function
-        * should thus be moved to buffer_init and s_fmt.
-        */
-       if (dev->width  < 48 || dev->width  > MAX_WIDTH ||
-           dev->height < 32 || dev->height > MAX_HEIGHT)
-               return -EINVAL;
-
-       size = dev->width * dev->height * dev->pixelsize;
-       if (vb2_plane_size(vb, 0) < size) {
-               dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
-                               __func__, vb2_plane_size(vb, 0), size);
-               return -EINVAL;
-       }
-
-       vb2_set_plane_payload(&buf->vb, 0, size);
-
-       precalculate_bars(dev);
-       precalculate_line(dev);
-
-       return 0;
-}
-
-static void buffer_queue(struct vb2_buffer *vb)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
-       struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
-       struct vivi_dmaqueue *vidq = &dev->vidq;
-       unsigned long flags = 0;
-
-       dprintk(dev, 1, "%s\n", __func__);
-
-       spin_lock_irqsave(&dev->slock, flags);
-       list_add_tail(&buf->list, &vidq->active);
-       spin_unlock_irqrestore(&dev->slock, flags);
-}
-
-static int start_streaming(struct vb2_queue *vq, unsigned int count)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vq);
-       int err;
-
-       dprintk(dev, 1, "%s\n", __func__);
-       dev->seq_count = 0;
-       err = vivi_start_generating(dev);
-       if (err) {
-               struct vivi_buffer *buf, *tmp;
-
-               list_for_each_entry_safe(buf, tmp, &dev->vidq.active, list) {
-                       list_del(&buf->list);
-                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
-               }
-       }
-       return err;
-}
-
-/* abort streaming and wait for last buffer */
-static void stop_streaming(struct vb2_queue *vq)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vq);
-       dprintk(dev, 1, "%s\n", __func__);
-       vivi_stop_generating(dev);
-}
-
-static void vivi_lock(struct vb2_queue *vq)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vq);
-       mutex_lock(&dev->mutex);
-}
-
-static void vivi_unlock(struct vb2_queue *vq)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vq);
-       mutex_unlock(&dev->mutex);
-}
-
-
-static const struct vb2_ops vivi_video_qops = {
-       .queue_setup            = queue_setup,
-       .buf_prepare            = buffer_prepare,
-       .buf_queue              = buffer_queue,
-       .start_streaming        = start_streaming,
-       .stop_streaming         = stop_streaming,
-       .wait_prepare           = vivi_unlock,
-       .wait_finish            = vivi_lock,
-};
-
-/* ------------------------------------------------------------------
-       IOCTL vidioc handling
-   ------------------------------------------------------------------*/
-static int vidioc_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *cap)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-
-       strcpy(cap->driver, "vivi");
-       strcpy(cap->card, "vivi");
-       snprintf(cap->bus_info, sizeof(cap->bus_info),
-                       "platform:%s", dev->v4l2_dev.name);
-       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
-                           V4L2_CAP_READWRITE;
-       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-       return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
-                                       struct v4l2_fmtdesc *f)
-{
-       const struct vivi_fmt *fmt;
-
-       if (f->index >= ARRAY_SIZE(formats))
-               return -EINVAL;
-
-       fmt = &formats[f->index];
-
-       strlcpy(f->description, fmt->name, sizeof(f->description));
-       f->pixelformat = fmt->fourcc;
-       return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
-                                       struct v4l2_format *f)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-
-       f->fmt.pix.width        = dev->width;
-       f->fmt.pix.height       = dev->height;
-       f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
-       f->fmt.pix.pixelformat  = dev->fmt->fourcc;
-       f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * dev->fmt->depth) >> 3;
-       f->fmt.pix.sizeimage =
-               f->fmt.pix.height * f->fmt.pix.bytesperline;
-       if (dev->fmt->is_yuv)
-               f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-       else
-               f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
-       return 0;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
-                       struct v4l2_format *f)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       const struct vivi_fmt *fmt;
-
-       fmt = get_format(f);
-       if (!fmt) {
-               dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
-                       f->fmt.pix.pixelformat);
-               f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-               fmt = get_format(f);
-       }
-
-       f->fmt.pix.field = V4L2_FIELD_INTERLACED;
-       v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
-                             &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
-       f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * fmt->depth) >> 3;
-       f->fmt.pix.sizeimage =
-               f->fmt.pix.height * f->fmt.pix.bytesperline;
-       if (fmt->is_yuv)
-               f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-       else
-               f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                                       struct v4l2_format *f)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       struct vb2_queue *q = &dev->vb_vidq;
-
-       int ret = vidioc_try_fmt_vid_cap(file, priv, f);
-       if (ret < 0)
-               return ret;
-
-       if (vb2_is_busy(q)) {
-               dprintk(dev, 1, "%s device busy\n", __func__);
-               return -EBUSY;
-       }
-
-       dev->fmt = get_format(f);
-       dev->pixelsize = dev->fmt->depth / 8;
-       dev->width = f->fmt.pix.width;
-       dev->height = f->fmt.pix.height;
-
-       return 0;
-}
-
-static int vidioc_enum_framesizes(struct file *file, void *fh,
-                                        struct v4l2_frmsizeenum *fsize)
-{
-       static const struct v4l2_frmsize_stepwise sizes = {
-               48, MAX_WIDTH, 4,
-               32, MAX_HEIGHT, 1
-       };
-       int i;
-
-       if (fsize->index)
-               return -EINVAL;
-       for (i = 0; i < ARRAY_SIZE(formats); i++)
-               if (formats[i].fourcc == fsize->pixel_format)
-                       break;
-       if (i == ARRAY_SIZE(formats))
-               return -EINVAL;
-       fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-       fsize->stepwise = sizes;
-       return 0;
-}
-
-/* only one input in this sample driver */
-static int vidioc_enum_input(struct file *file, void *priv,
-                               struct v4l2_input *inp)
-{
-       if (inp->index >= NUM_INPUTS)
-               return -EINVAL;
-
-       inp->type = V4L2_INPUT_TYPE_CAMERA;
-       sprintf(inp->name, "Camera %u", inp->index);
-       return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-
-       *i = dev->input;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-
-       if (i >= NUM_INPUTS)
-               return -EINVAL;
-
-       if (i == dev->input)
-               return 0;
-
-       dev->input = i;
-       /*
-        * Modify the brightness range depending on the input.
-        * This makes it easy to use vivi to test if applications can
-        * handle control range modifications and is also how this is
-        * typically used in practice as different inputs may be hooked
-        * up to different receivers with different control ranges.
-        */
-       v4l2_ctrl_modify_range(dev->brightness,
-                       128 * i, 255 + 128 * i, 1, 127 + 128 * i);
-       precalculate_bars(dev);
-       precalculate_line(dev);
-       return 0;
-}
-
-/* timeperframe is arbitrary and continuous */
-static int vidioc_enum_frameintervals(struct file *file, void *priv,
-                                            struct v4l2_frmivalenum *fival)
-{
-       const struct vivi_fmt *fmt;
-
-       if (fival->index)
-               return -EINVAL;
-
-       fmt = __get_format(fival->pixel_format);
-       if (!fmt)
-               return -EINVAL;
-
-       /* check for valid width/height */
-       if (fival->width < 48 || fival->width > MAX_WIDTH || (fival->width & 3))
-               return -EINVAL;
-       if (fival->height < 32 || fival->height > MAX_HEIGHT)
-               return -EINVAL;
-
-       fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
-
-       /* fill in stepwise (step=1.0 is required by V4L2 spec) */
-       fival->stepwise.min  = tpf_min;
-       fival->stepwise.max  = tpf_max;
-       fival->stepwise.step = (struct v4l2_fract) {1, 1};
-
-       return 0;
-}
-
-static int vidioc_g_parm(struct file *file, void *priv,
-                         struct v4l2_streamparm *parm)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-
-       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       parm->parm.capture.capability   = V4L2_CAP_TIMEPERFRAME;
-       parm->parm.capture.timeperframe = dev->timeperframe;
-       parm->parm.capture.readbuffers  = 1;
-       return 0;
-}
-
-#define FRACT_CMP(a, OP, b)    \
-       ((u64)(a).numerator * (b).denominator  OP  (u64)(b).numerator * (a).denominator)
-
-static int vidioc_s_parm(struct file *file, void *priv,
-                         struct v4l2_streamparm *parm)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       struct v4l2_fract tpf;
-
-       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       tpf = parm->parm.capture.timeperframe;
-
-       /* tpf: {*, 0} resets timing; clip to [min, max]*/
-       tpf = tpf.denominator ? tpf : tpf_default;
-       tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf;
-       tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf;
-
-       dev->timeperframe = tpf;
-       parm->parm.capture.timeperframe = tpf;
-       parm->parm.capture.readbuffers  = 1;
-       return 0;
-}
-
-/* --- controls ---------------------------------------------- */
-
-static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
-
-       if (ctrl == dev->autogain)
-               dev->gain->val = jiffies & 0xff;
-       return 0;
-}
-
-static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
-
-       switch (ctrl->id) {
-       case V4L2_CID_ALPHA_COMPONENT:
-               dev->alpha_component = ctrl->val;
-               break;
-       default:
-               if (ctrl == dev->button)
-                       dev->button_pressed = 30;
-               break;
-       }
-       return 0;
-}
-
-/* ------------------------------------------------------------------
-       File operations for the device
-   ------------------------------------------------------------------*/
-
-static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
-       .g_volatile_ctrl = vivi_g_volatile_ctrl,
-       .s_ctrl = vivi_s_ctrl,
-};
-
-#define VIVI_CID_CUSTOM_BASE   (V4L2_CID_USER_BASE | 0xf000)
-
-static const struct v4l2_ctrl_config vivi_ctrl_button = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 0,
-       .name = "Button",
-       .type = V4L2_CTRL_TYPE_BUTTON,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_boolean = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 1,
-       .name = "Boolean",
-       .type = V4L2_CTRL_TYPE_BOOLEAN,
-       .min = 0,
-       .max = 1,
-       .step = 1,
-       .def = 1,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 2,
-       .name = "Integer 32 Bits",
-       .type = V4L2_CTRL_TYPE_INTEGER,
-       .min = -0x80000000LL,
-       .max = 0x7fffffff,
-       .step = 1,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 3,
-       .name = "Integer 64 Bits",
-       .type = V4L2_CTRL_TYPE_INTEGER64,
-       .min = LLONG_MIN,
-       .max = LLONG_MAX,
-       .step = 1,
-};
-
-static const char * const vivi_ctrl_menu_strings[] = {
-       "Menu Item 0 (Skipped)",
-       "Menu Item 1",
-       "Menu Item 2 (Skipped)",
-       "Menu Item 3",
-       "Menu Item 4",
-       "Menu Item 5 (Skipped)",
-       NULL,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_menu = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 4,
-       .name = "Menu",
-       .type = V4L2_CTRL_TYPE_MENU,
-       .min = 1,
-       .max = 4,
-       .def = 3,
-       .menu_skip_mask = 0x04,
-       .qmenu = vivi_ctrl_menu_strings,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_string = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 5,
-       .name = "String",
-       .type = V4L2_CTRL_TYPE_STRING,
-       .min = 2,
-       .max = 4,
-       .step = 1,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_bitmask = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 6,
-       .name = "Bitmask",
-       .type = V4L2_CTRL_TYPE_BITMASK,
-       .def = 0x80002000,
-       .min = 0,
-       .max = 0x80402010,
-       .step = 0,
-};
-
-static const s64 vivi_ctrl_int_menu_values[] = {
-       1, 1, 2, 3, 5, 8, 13, 21, 42,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_int_menu = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 7,
-       .name = "Integer menu",
-       .type = V4L2_CTRL_TYPE_INTEGER_MENU,
-       .min = 1,
-       .max = 8,
-       .def = 4,
-       .menu_skip_mask = 0x02,
-       .qmenu_int = vivi_ctrl_int_menu_values,
-};
-
-static const struct v4l2_file_operations vivi_fops = {
-       .owner          = THIS_MODULE,
-       .open           = v4l2_fh_open,
-       .release        = vb2_fop_release,
-       .read           = vb2_fop_read,
-       .poll           = vb2_fop_poll,
-       .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
-       .mmap           = vb2_fop_mmap,
-};
-
-static const struct v4l2_ioctl_ops vivi_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_enum_framesizes   = vidioc_enum_framesizes,
-       .vidioc_reqbufs       = vb2_ioctl_reqbufs,
-       .vidioc_create_bufs   = vb2_ioctl_create_bufs,
-       .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
-       .vidioc_querybuf      = vb2_ioctl_querybuf,
-       .vidioc_qbuf          = vb2_ioctl_qbuf,
-       .vidioc_dqbuf         = vb2_ioctl_dqbuf,
-       .vidioc_enum_input    = vidioc_enum_input,
-       .vidioc_g_input       = vidioc_g_input,
-       .vidioc_s_input       = vidioc_s_input,
-       .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
-       .vidioc_g_parm        = vidioc_g_parm,
-       .vidioc_s_parm        = vidioc_s_parm,
-       .vidioc_streamon      = vb2_ioctl_streamon,
-       .vidioc_streamoff     = vb2_ioctl_streamoff,
-       .vidioc_log_status    = v4l2_ctrl_log_status,
-       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
-       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static const struct video_device vivi_template = {
-       .name           = "vivi",
-       .fops           = &vivi_fops,
-       .ioctl_ops      = &vivi_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
-/* -----------------------------------------------------------------
-       Initialization and module stuff
-   ------------------------------------------------------------------*/
-
-static int vivi_release(void)
-{
-       struct vivi_dev *dev;
-       struct list_head *list;
-
-       while (!list_empty(&vivi_devlist)) {
-               list = vivi_devlist.next;
-               list_del(list);
-               dev = list_entry(list, struct vivi_dev, vivi_devlist);
-
-               v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
-                       video_device_node_name(&dev->vdev));
-               video_unregister_device(&dev->vdev);
-               v4l2_device_unregister(&dev->v4l2_dev);
-               v4l2_ctrl_handler_free(&dev->ctrl_handler);
-               kfree(dev);
-       }
-
-       return 0;
-}
-
-static int __init vivi_create_instance(int inst)
-{
-       struct vivi_dev *dev;
-       struct video_device *vfd;
-       struct v4l2_ctrl_handler *hdl;
-       struct vb2_queue *q;
-       int ret;
-
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
-
-       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
-                       "%s-%03d", VIVI_MODULE_NAME, inst);
-       ret = v4l2_device_register(NULL, &dev->v4l2_dev);
-       if (ret)
-               goto free_dev;
-
-       dev->fmt = &formats[0];
-       dev->timeperframe = tpf_default;
-       dev->width = 640;
-       dev->height = 480;
-       dev->pixelsize = dev->fmt->depth / 8;
-       hdl = &dev->ctrl_handler;
-       v4l2_ctrl_handler_init(hdl, 11);
-       dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
-       dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
-       dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_CONTRAST, 0, 255, 1, 16);
-       dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_SATURATION, 0, 255, 1, 127);
-       dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_HUE, -128, 127, 1, 0);
-       dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
-       dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_GAIN, 0, 255, 1, 100);
-       dev->alpha = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
-       dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
-       dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
-       dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
-       dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
-       dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
-       dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
-       dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
-       dev->int_menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int_menu, NULL);
-       if (hdl->error) {
-               ret = hdl->error;
-               goto unreg_dev;
-       }
-       v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
-       dev->v4l2_dev.ctrl_handler = hdl;
-
-       /* initialize locks */
-       spin_lock_init(&dev->slock);
-
-       /* initialize queue */
-       q = &dev->vb_vidq;
-       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
-       q->drv_priv = dev;
-       q->buf_struct_size = sizeof(struct vivi_buffer);
-       q->ops = &vivi_video_qops;
-       q->mem_ops = &vb2_vmalloc_memops;
-       q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-
-       ret = vb2_queue_init(q);
-       if (ret)
-               goto unreg_dev;
-
-       mutex_init(&dev->mutex);
-
-       /* init video dma queues */
-       INIT_LIST_HEAD(&dev->vidq.active);
-       init_waitqueue_head(&dev->vidq.wq);
-
-       vfd = &dev->vdev;
-       *vfd = vivi_template;
-       vfd->debug = debug;
-       vfd->v4l2_dev = &dev->v4l2_dev;
-       vfd->queue = q;
-
-       /*
-        * Provide a mutex to v4l2 core. It will be used to protect
-        * all fops and v4l2 ioctls.
-        */
-       vfd->lock = &dev->mutex;
-       video_set_drvdata(vfd, dev);
-
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
-       if (ret < 0)
-               goto unreg_dev;
-
-       /* Now that everything is fine, let's add it to device list */
-       list_add_tail(&dev->vivi_devlist, &vivi_devlist);
-
-       v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
-                 video_device_node_name(vfd));
-       return 0;
-
-unreg_dev:
-       v4l2_ctrl_handler_free(hdl);
-       v4l2_device_unregister(&dev->v4l2_dev);
-free_dev:
-       kfree(dev);
-       return ret;
-}
-
-/* This routine allocates from 1 to n_devs virtual drivers.
-
-   The real maximum number of virtual drivers will depend on how many drivers
-   will succeed. This is limited to the maximum number of devices that
-   videodev supports, which is equal to VIDEO_NUM_DEVICES.
- */
-static int __init vivi_init(void)
-{
-       const struct font_desc *font = find_font("VGA8x16");
-       int ret = 0, i;
-
-       if (font == NULL) {
-               printk(KERN_ERR "vivi: could not find font\n");
-               return -ENODEV;
-       }
-       font8x16 = font->data;
-
-       if (n_devs <= 0)
-               n_devs = 1;
-
-       for (i = 0; i < n_devs; i++) {
-               ret = vivi_create_instance(i);
-               if (ret) {
-                       /* If some instantiations succeeded, keep driver */
-                       if (i)
-                               ret = 0;
-                       break;
-               }
-       }
-
-       if (ret < 0) {
-               printk(KERN_ERR "vivi: error %d while loading driver\n", ret);
-               return ret;
-       }
-
-       printk(KERN_INFO "Video Technology Magazine Virtual Video "
-                       "Capture Board ver %s successfully loaded.\n",
-                       VIVI_VERSION);
-
-       /* n_devs will reflect the actual number of allocated devices */
-       n_devs = i;
-
-       return ret;
-}
-
-static void __exit vivi_exit(void)
-{
-       vivi_release();
-}
-
-module_init(vivi_init);
-module_exit(vivi_exit);
diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig
new file mode 100644 (file)
index 0000000..d71139a
--- /dev/null
@@ -0,0 +1,19 @@
+config VIDEO_VIVID
+       tristate "Virtual Video Test Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
+       select FONT_SUPPORT
+       select FONT_8x16
+       select VIDEOBUF2_VMALLOC
+       default n
+       ---help---
+         Enables a virtual video driver. This driver emulates a webcam,
+         TV, S-Video and HDMI capture hardware, including VBI support for
+         the SDTV inputs. Also video output, VBI output, radio receivers,
+         transmitters and software defined radio capture is emulated.
+
+         It is highly configurable and is ideal for testing applications.
+         Error injection is supported to test rare errors that are hard
+         to reproduce in real hardware.
+
+         Say Y here if you want to test video apps or debug V4L devices.
+         When in doubt, say N.
diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile
new file mode 100644 (file)
index 0000000..756fc12
--- /dev/null
@@ -0,0 +1,6 @@
+vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \
+               vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \
+               vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \
+               vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \
+               vivid-osd.o vivid-tpg.o vivid-tpg-colors.o
+obj-$(CONFIG_VIDEO_VIVID) += vivid.o
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
new file mode 100644 (file)
index 0000000..2c61a62
--- /dev/null
@@ -0,0 +1,1390 @@
+/*
+ * vivid-core.c - A Virtual Video Test Driver, core initialization
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-vid-cap.h"
+#include "vivid-vid-out.h"
+#include "vivid-radio-common.h"
+#include "vivid-radio-rx.h"
+#include "vivid-radio-tx.h"
+#include "vivid-sdr-cap.h"
+#include "vivid-vbi-cap.h"
+#include "vivid-vbi-out.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.h"
+
+#define VIVID_MODULE_NAME "vivid"
+
+/* The maximum number of vivid devices */
+#define VIVID_MAX_DEVS 64
+
+MODULE_DESCRIPTION("Virtual Video Test Driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static unsigned n_devs = 1;
+module_param(n_devs, uint, 0444);
+MODULE_PARM_DESC(n_devs, " number of driver instances to create");
+
+static int vid_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(vid_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vid_cap_nr, " videoX start number, -1 is autodetect");
+
+static int vid_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(vid_out_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vid_out_nr, " videoX start number, -1 is autodetect");
+
+static int vbi_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(vbi_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vbi_cap_nr, " vbiX start number, -1 is autodetect");
+
+static int vbi_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(vbi_out_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vbi_out_nr, " vbiX start number, -1 is autodetect");
+
+static int sdr_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(sdr_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(sdr_cap_nr, " swradioX start number, -1 is autodetect");
+
+static int radio_rx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(radio_rx_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_rx_nr, " radioX start number, -1 is autodetect");
+
+static int radio_tx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(radio_tx_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_tx_nr, " radioX start number, -1 is autodetect");
+
+static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(ccs_cap_mode, int, NULL, 0444);
+MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n"
+                          "\t\t    bit 0=crop, 1=compose, 2=scale,\n"
+                          "\t\t    -1=user-controlled (default)");
+
+static int ccs_out_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(ccs_out_mode, int, NULL, 0444);
+MODULE_PARM_DESC(ccs_out_mode, " output crop/compose/scale mode:\n"
+                          "\t\t    bit 0=crop, 1=compose, 2=scale,\n"
+                          "\t\t    -1=user-controlled (default)");
+
+static unsigned multiplanar[VIVID_MAX_DEVS];
+module_param_array(multiplanar, uint, NULL, 0444);
+MODULE_PARM_DESC(multiplanar, " 0 (default) is alternating single and multiplanar devices,\n"
+                             "\t\t    1 is single planar devices,\n"
+                             "\t\t    2 is multiplanar devices");
+
+/* Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + vbi-out + vid-out */
+static unsigned node_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0x1d3d };
+module_param_array(node_types, uint, NULL, 0444);
+MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the following meaning:\n"
+                            "\t\t    bit 0: Video Capture node\n"
+                            "\t\t    bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
+                            "\t\t    bit 4: Radio Receiver node\n"
+                            "\t\t    bit 5: Software Defined Radio Receiver node\n"
+                            "\t\t    bit 8: Video Output node\n"
+                            "\t\t    bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
+                            "\t\t    bit 12: Radio Transmitter node\n"
+                            "\t\t    bit 16: Framebuffer for testing overlays");
+
+/* Default: 4 inputs */
+static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 };
+module_param_array(num_inputs, uint, NULL, 0444);
+MODULE_PARM_DESC(num_inputs, " number of inputs, default is 4");
+
+/* Default: input 0 = WEBCAM, 1 = TV, 2 = SVID, 3 = HDMI */
+static unsigned input_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0xe4 };
+module_param_array(input_types, uint, NULL, 0444);
+MODULE_PARM_DESC(input_types, " input types, default is 0xe4. Two bits per input,\n"
+                             "\t\t    bits 0-1 == input 0, bits 31-30 == input 15.\n"
+                             "\t\t    Type 0 == webcam, 1 == TV, 2 == S-Video, 3 == HDMI");
+
+/* Default: 2 outputs */
+static unsigned num_outputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 2 };
+module_param_array(num_outputs, uint, NULL, 0444);
+MODULE_PARM_DESC(num_outputs, " number of outputs, default is 2");
+
+/* Default: output 0 = SVID, 1 = HDMI */
+static unsigned output_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 2 };
+module_param_array(output_types, uint, NULL, 0444);
+MODULE_PARM_DESC(output_types, " output types, default is 0x02. One bit per output,\n"
+                             "\t\t    bit 0 == output 0, bit 15 == output 15.\n"
+                             "\t\t    Type 0 == S-Video, 1 == HDMI");
+
+unsigned vivid_debug;
+module_param(vivid_debug, uint, 0644);
+MODULE_PARM_DESC(vivid_debug, " activates debug info");
+
+static bool no_error_inj;
+module_param(no_error_inj, bool, 0444);
+MODULE_PARM_DESC(no_error_inj, " if set disable the error injecting controls");
+
+static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS];
+
+const struct v4l2_rect vivid_min_rect = {
+       0, 0, MIN_WIDTH, MIN_HEIGHT
+};
+
+const struct v4l2_rect vivid_max_rect = {
+       0, 0, MAX_WIDTH * MAX_ZOOM, MAX_HEIGHT * MAX_ZOOM
+};
+
+static const u8 vivid_hdmi_edid[256] = {
+       0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+       0x63, 0x3a, 0xaa, 0x55, 0x00, 0x00, 0x00, 0x00,
+       0x0a, 0x18, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
+       0x0e, 0x00, 0xb2, 0xa0, 0x57, 0x49, 0x9b, 0x26,
+       0x10, 0x48, 0x4f, 0x2f, 0xcf, 0x00, 0x31, 0x59,
+       0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40,
+       0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x02, 0x3a,
+       0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+       0x46, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00, 0x1e,
+       0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18,
+       0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20,
+       0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00,  'v',
+       '4',   'l',  '2',  '-',  'h',  'd',  'm',  'i',
+       0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x10,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0,
+
+       0x02, 0x03, 0x1a, 0xc0, 0x48, 0xa2, 0x10, 0x04,
+       0x02, 0x01, 0x21, 0x14, 0x13, 0x23, 0x09, 0x07,
+       0x07, 0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, 0xe2,
+       0x00, 0x2a, 0x01, 0x1d, 0x00, 0x80, 0x51, 0xd0,
+       0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x1e, 0x8c, 0x0a, 0xd0, 0x8a,
+       0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 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,
+       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, 0xd7
+};
+
+void vivid_lock(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       mutex_lock(&dev->mutex);
+}
+
+void vivid_unlock(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       mutex_unlock(&dev->mutex);
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       strcpy(cap->driver, "vivid");
+       strcpy(cap->card, "vivid");
+       snprintf(cap->bus_info, sizeof(cap->bus_info),
+                       "platform:%s", dev->v4l2_dev.name);
+
+       if (vdev->vfl_type == VFL_TYPE_GRABBER && vdev->vfl_dir == VFL_DIR_RX)
+               cap->device_caps = dev->vid_cap_caps;
+       if (vdev->vfl_type == VFL_TYPE_GRABBER && vdev->vfl_dir == VFL_DIR_TX)
+               cap->device_caps = dev->vid_out_caps;
+       else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_RX)
+               cap->device_caps = dev->vbi_cap_caps;
+       else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_TX)
+               cap->device_caps = dev->vbi_out_caps;
+       else if (vdev->vfl_type == VFL_TYPE_SDR)
+               cap->device_caps = dev->sdr_cap_caps;
+       else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_RX)
+               cap->device_caps = dev->radio_rx_caps;
+       else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_TX)
+               cap->device_caps = dev->radio_tx_caps;
+       cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps |
+               dev->vbi_cap_caps | dev->vbi_out_caps |
+               dev->radio_rx_caps | dev->radio_tx_caps |
+               dev->sdr_cap_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int vidioc_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
+               return vivid_radio_rx_s_hw_freq_seek(file, fh, a);
+       return -ENOTTY;
+}
+
+static int vidioc_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
+               return vivid_radio_rx_enum_freq_bands(file, fh, band);
+       if (vdev->vfl_type == VFL_TYPE_SDR)
+               return vivid_sdr_enum_freq_bands(file, fh, band);
+       return -ENOTTY;
+}
+
+static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
+               return vivid_radio_rx_g_tuner(file, fh, vt);
+       if (vdev->vfl_type == VFL_TYPE_SDR)
+               return vivid_sdr_g_tuner(file, fh, vt);
+       return vivid_video_g_tuner(file, fh, vt);
+}
+
+static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
+               return vivid_radio_rx_s_tuner(file, fh, vt);
+       if (vdev->vfl_type == VFL_TYPE_SDR)
+               return vivid_sdr_s_tuner(file, fh, vt);
+       return vivid_video_s_tuner(file, fh, vt);
+}
+
+static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
+               return vivid_radio_g_frequency(file,
+                       vdev->vfl_dir == VFL_DIR_RX ?
+                       &dev->radio_rx_freq : &dev->radio_tx_freq, vf);
+       if (vdev->vfl_type == VFL_TYPE_SDR)
+               return vivid_sdr_g_frequency(file, fh, vf);
+       return vivid_video_g_frequency(file, fh, vf);
+}
+
+static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
+               return vivid_radio_s_frequency(file,
+                       vdev->vfl_dir == VFL_DIR_RX ?
+                       &dev->radio_rx_freq : &dev->radio_tx_freq, vf);
+       if (vdev->vfl_type == VFL_TYPE_SDR)
+               return vivid_sdr_s_frequency(file, fh, vf);
+       return vivid_video_s_frequency(file, fh, vf);
+}
+
+static int vidioc_overlay(struct file *file, void *fh, unsigned i)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_overlay(file, fh, i);
+       return vivid_vid_out_overlay(file, fh, i);
+}
+
+static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_g_fbuf(file, fh, a);
+       return vivid_vid_out_g_fbuf(file, fh, a);
+}
+
+static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_s_fbuf(file, fh, a);
+       return vivid_vid_out_s_fbuf(file, fh, a);
+}
+
+static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_s_std(file, fh, id);
+       return vivid_vid_out_s_std(file, fh, id);
+}
+
+static int vidioc_s_dv_timings(struct file *file, void *fh, struct v4l2_dv_timings *timings)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_s_dv_timings(file, fh, timings);
+       return vivid_vid_out_s_dv_timings(file, fh, timings);
+}
+
+static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cc)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_cropcap(file, fh, cc);
+       return vivid_vid_out_cropcap(file, fh, cc);
+}
+
+static int vidioc_g_selection(struct file *file, void *fh,
+                             struct v4l2_selection *sel)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_g_selection(file, fh, sel);
+       return vivid_vid_out_g_selection(file, fh, sel);
+}
+
+static int vidioc_s_selection(struct file *file, void *fh,
+                             struct v4l2_selection *sel)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_s_selection(file, fh, sel);
+       return vivid_vid_out_s_selection(file, fh, sel);
+}
+
+static int vidioc_g_parm(struct file *file, void *fh,
+                         struct v4l2_streamparm *parm)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_g_parm(file, fh, parm);
+       return vivid_vid_out_g_parm(file, fh, parm);
+}
+
+static int vidioc_s_parm(struct file *file, void *fh,
+                         struct v4l2_streamparm *parm)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_s_parm(file, fh, parm);
+       return vivid_vid_out_g_parm(file, fh, parm);
+}
+
+static ssize_t vivid_radio_read(struct file *file, char __user *buf,
+                        size_t size, loff_t *offset)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_TX)
+               return -EINVAL;
+       return vivid_radio_rx_read(file, buf, size, offset);
+}
+
+static ssize_t vivid_radio_write(struct file *file, const char __user *buf,
+                         size_t size, loff_t *offset)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return -EINVAL;
+       return vivid_radio_tx_write(file, buf, size, offset);
+}
+
+static unsigned int vivid_radio_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_radio_rx_poll(file, wait);
+       return vivid_radio_tx_poll(file, wait);
+}
+
+static bool vivid_is_in_use(struct video_device *vdev)
+{
+       unsigned long flags;
+       bool res;
+
+       spin_lock_irqsave(&vdev->fh_lock, flags);
+       res = !list_empty(&vdev->fh_list);
+       spin_unlock_irqrestore(&vdev->fh_lock, flags);
+       return res;
+}
+
+static bool vivid_is_last_user(struct vivid_dev *dev)
+{
+       unsigned uses = vivid_is_in_use(&dev->vid_cap_dev) +
+                       vivid_is_in_use(&dev->vid_out_dev) +
+                       vivid_is_in_use(&dev->vbi_cap_dev) +
+                       vivid_is_in_use(&dev->vbi_out_dev) +
+                       vivid_is_in_use(&dev->sdr_cap_dev) +
+                       vivid_is_in_use(&dev->radio_rx_dev) +
+                       vivid_is_in_use(&dev->radio_tx_dev);
+
+       return uses == 1;
+}
+
+static int vivid_fop_release(struct file *file)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       mutex_lock(&dev->mutex);
+       if (!no_error_inj && v4l2_fh_is_singular_file(file) &&
+           !video_is_registered(vdev) && vivid_is_last_user(dev)) {
+               /*
+                * I am the last user of this driver, and a disconnect
+                * was forced (since this video_device is unregistered),
+                * so re-register all video_device's again.
+                */
+               v4l2_info(&dev->v4l2_dev, "reconnect\n");
+               set_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags);
+               set_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags);
+               set_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags);
+               set_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags);
+               set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags);
+               set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags);
+               set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
+       }
+       mutex_unlock(&dev->mutex);
+       if (file->private_data == dev->overlay_cap_owner)
+               dev->overlay_cap_owner = NULL;
+       if (file->private_data == dev->radio_rx_rds_owner) {
+               dev->radio_rx_rds_last_block = 0;
+               dev->radio_rx_rds_owner = NULL;
+       }
+       if (file->private_data == dev->radio_tx_rds_owner) {
+               dev->radio_tx_rds_last_block = 0;
+               dev->radio_tx_rds_owner = NULL;
+       }
+       if (vdev->queue)
+               return vb2_fop_release(file);
+       return v4l2_fh_release(file);
+}
+
+static const struct v4l2_file_operations vivid_fops = {
+       .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .release        = vivid_fop_release,
+       .read           = vb2_fop_read,
+       .write          = vb2_fop_write,
+       .poll           = vb2_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = vb2_fop_mmap,
+};
+
+static const struct v4l2_file_operations vivid_radio_fops = {
+       .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .release        = vivid_fop_release,
+       .read           = vivid_radio_read,
+       .write          = vivid_radio_write,
+       .poll           = vivid_radio_poll,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
+       .vidioc_querycap                = vidioc_querycap,
+
+       .vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt_vid,
+       .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_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_mplane,
+       .vidioc_g_fmt_vid_cap_mplane    = vidioc_g_fmt_vid_cap_mplane,
+       .vidioc_try_fmt_vid_cap_mplane  = vidioc_try_fmt_vid_cap_mplane,
+       .vidioc_s_fmt_vid_cap_mplane    = vidioc_s_fmt_vid_cap_mplane,
+
+       .vidioc_enum_fmt_vid_out        = vidioc_enum_fmt_vid,
+       .vidioc_g_fmt_vid_out           = vidioc_g_fmt_vid_out,
+       .vidioc_try_fmt_vid_out         = vidioc_try_fmt_vid_out,
+       .vidioc_s_fmt_vid_out           = vidioc_s_fmt_vid_out,
+       .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_mplane,
+       .vidioc_g_fmt_vid_out_mplane    = vidioc_g_fmt_vid_out_mplane,
+       .vidioc_try_fmt_vid_out_mplane  = vidioc_try_fmt_vid_out_mplane,
+       .vidioc_s_fmt_vid_out_mplane    = vidioc_s_fmt_vid_out_mplane,
+
+       .vidioc_g_selection             = vidioc_g_selection,
+       .vidioc_s_selection             = vidioc_s_selection,
+       .vidioc_cropcap                 = vidioc_cropcap,
+
+       .vidioc_g_fmt_vbi_cap           = vidioc_g_fmt_vbi_cap,
+       .vidioc_try_fmt_vbi_cap         = vidioc_g_fmt_vbi_cap,
+       .vidioc_s_fmt_vbi_cap           = vidioc_s_fmt_vbi_cap,
+
+       .vidioc_g_fmt_sliced_vbi_cap    = vidioc_g_fmt_sliced_vbi_cap,
+       .vidioc_try_fmt_sliced_vbi_cap  = vidioc_try_fmt_sliced_vbi_cap,
+       .vidioc_s_fmt_sliced_vbi_cap    = vidioc_s_fmt_sliced_vbi_cap,
+       .vidioc_g_sliced_vbi_cap        = vidioc_g_sliced_vbi_cap,
+
+       .vidioc_g_fmt_vbi_out           = vidioc_g_fmt_vbi_out,
+       .vidioc_try_fmt_vbi_out         = vidioc_g_fmt_vbi_out,
+       .vidioc_s_fmt_vbi_out           = vidioc_s_fmt_vbi_out,
+
+       .vidioc_g_fmt_sliced_vbi_out    = vidioc_g_fmt_sliced_vbi_out,
+       .vidioc_try_fmt_sliced_vbi_out  = vidioc_try_fmt_sliced_vbi_out,
+       .vidioc_s_fmt_sliced_vbi_out    = vidioc_s_fmt_sliced_vbi_out,
+
+       .vidioc_enum_fmt_sdr_cap        = vidioc_enum_fmt_sdr_cap,
+       .vidioc_g_fmt_sdr_cap           = vidioc_g_fmt_sdr_cap,
+       .vidioc_try_fmt_sdr_cap         = vidioc_g_fmt_sdr_cap,
+       .vidioc_s_fmt_sdr_cap           = vidioc_g_fmt_sdr_cap,
+
+       .vidioc_overlay                 = vidioc_overlay,
+       .vidioc_enum_framesizes         = vidioc_enum_framesizes,
+       .vidioc_enum_frameintervals     = vidioc_enum_frameintervals,
+       .vidioc_g_parm                  = vidioc_g_parm,
+       .vidioc_s_parm                  = vidioc_s_parm,
+
+       .vidioc_enum_fmt_vid_overlay    = vidioc_enum_fmt_vid_overlay,
+       .vidioc_g_fmt_vid_overlay       = vidioc_g_fmt_vid_overlay,
+       .vidioc_try_fmt_vid_overlay     = vidioc_try_fmt_vid_overlay,
+       .vidioc_s_fmt_vid_overlay       = vidioc_s_fmt_vid_overlay,
+       .vidioc_g_fmt_vid_out_overlay   = vidioc_g_fmt_vid_out_overlay,
+       .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_out_overlay,
+       .vidioc_s_fmt_vid_out_overlay   = vidioc_s_fmt_vid_out_overlay,
+       .vidioc_g_fbuf                  = vidioc_g_fbuf,
+       .vidioc_s_fbuf                  = vidioc_s_fbuf,
+
+       .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
+       .vidioc_create_bufs             = vb2_ioctl_create_bufs,
+       .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf                = vb2_ioctl_querybuf,
+       .vidioc_qbuf                    = vb2_ioctl_qbuf,
+       .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
+/* Not yet     .vidioc_expbuf          = vb2_ioctl_expbuf,*/
+       .vidioc_streamon                = vb2_ioctl_streamon,
+       .vidioc_streamoff               = vb2_ioctl_streamoff,
+
+       .vidioc_enum_input              = vidioc_enum_input,
+       .vidioc_g_input                 = vidioc_g_input,
+       .vidioc_s_input                 = vidioc_s_input,
+       .vidioc_s_audio                 = vidioc_s_audio,
+       .vidioc_g_audio                 = vidioc_g_audio,
+       .vidioc_enumaudio               = vidioc_enumaudio,
+       .vidioc_s_frequency             = vidioc_s_frequency,
+       .vidioc_g_frequency             = vidioc_g_frequency,
+       .vidioc_s_tuner                 = vidioc_s_tuner,
+       .vidioc_g_tuner                 = vidioc_g_tuner,
+       .vidioc_s_modulator             = vidioc_s_modulator,
+       .vidioc_g_modulator             = vidioc_g_modulator,
+       .vidioc_s_hw_freq_seek          = vidioc_s_hw_freq_seek,
+       .vidioc_enum_freq_bands         = vidioc_enum_freq_bands,
+
+       .vidioc_enum_output             = vidioc_enum_output,
+       .vidioc_g_output                = vidioc_g_output,
+       .vidioc_s_output                = vidioc_s_output,
+       .vidioc_s_audout                = vidioc_s_audout,
+       .vidioc_g_audout                = vidioc_g_audout,
+       .vidioc_enumaudout              = vidioc_enumaudout,
+
+       .vidioc_querystd                = vidioc_querystd,
+       .vidioc_g_std                   = vidioc_g_std,
+       .vidioc_s_std                   = vidioc_s_std,
+       .vidioc_s_dv_timings            = vidioc_s_dv_timings,
+       .vidioc_g_dv_timings            = vidioc_g_dv_timings,
+       .vidioc_query_dv_timings        = vidioc_query_dv_timings,
+       .vidioc_enum_dv_timings         = vidioc_enum_dv_timings,
+       .vidioc_dv_timings_cap          = vidioc_dv_timings_cap,
+       .vidioc_g_edid                  = vidioc_g_edid,
+       .vidioc_s_edid                  = vidioc_s_edid,
+
+       .vidioc_log_status              = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event         = vidioc_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+};
+
+/* -----------------------------------------------------------------
+       Initialization and module stuff
+   ------------------------------------------------------------------*/
+
+static int __init vivid_create_instance(int inst)
+{
+       static const struct v4l2_dv_timings def_dv_timings =
+                                       V4L2_DV_BT_CEA_1280X720P60;
+       unsigned in_type_counter[4] = { 0, 0, 0, 0 };
+       unsigned out_type_counter[4] = { 0, 0, 0, 0 };
+       int ccs_cap = ccs_cap_mode[inst];
+       int ccs_out = ccs_out_mode[inst];
+       bool has_tuner;
+       bool has_modulator;
+       struct vivid_dev *dev;
+       struct video_device *vfd;
+       struct vb2_queue *q;
+       unsigned node_type = node_types[inst];
+       v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0;
+       int ret;
+       int i;
+
+       /* allocate main vivid state structure */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       dev->inst = inst;
+
+       /* register v4l2_device */
+       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+                       "%s-%03d", VIVID_MODULE_NAME, inst);
+       ret = v4l2_device_register(NULL, &dev->v4l2_dev);
+       if (ret)
+               goto free_dev;
+
+       /* start detecting feature set */
+
+       /* do we use single- or multi-planar? */
+       if (multiplanar[inst] == 0)
+               dev->multiplanar = inst & 1;
+       else
+               dev->multiplanar = multiplanar[inst] > 1;
+       v4l2_info(&dev->v4l2_dev, "using %splanar format API\n",
+                       dev->multiplanar ? "multi" : "single ");
+
+       /* how many inputs do we have and of what type? */
+       dev->num_inputs = num_inputs[inst];
+       if (dev->num_inputs < 1)
+               dev->num_inputs = 1;
+       if (dev->num_inputs >= MAX_INPUTS)
+               dev->num_inputs = MAX_INPUTS;
+       for (i = 0; i < dev->num_inputs; i++) {
+               dev->input_type[i] = (input_types[inst] >> (i * 2)) & 0x3;
+               dev->input_name_counter[i] = in_type_counter[dev->input_type[i]]++;
+       }
+       dev->has_audio_inputs = in_type_counter[TV] && in_type_counter[SVID];
+
+       /* how many outputs do we have and of what type? */
+       dev->num_outputs = num_outputs[inst];
+       if (dev->num_outputs < 1)
+               dev->num_outputs = 1;
+       if (dev->num_outputs >= MAX_OUTPUTS)
+               dev->num_outputs = MAX_OUTPUTS;
+       for (i = 0; i < dev->num_outputs; i++) {
+               dev->output_type[i] = ((output_types[inst] >> i) & 1) ? HDMI : SVID;
+               dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++;
+       }
+       dev->has_audio_outputs = out_type_counter[SVID];
+
+       /* do we create a video capture device? */
+       dev->has_vid_cap = node_type & 0x0001;
+
+       /* do we create a vbi capture device? */
+       if (in_type_counter[TV] || in_type_counter[SVID]) {
+               dev->has_raw_vbi_cap = node_type & 0x0004;
+               dev->has_sliced_vbi_cap = node_type & 0x0008;
+               dev->has_vbi_cap = dev->has_raw_vbi_cap | dev->has_sliced_vbi_cap;
+       }
+
+       /* do we create a video output device? */
+       dev->has_vid_out = node_type & 0x0100;
+
+       /* do we create a vbi output device? */
+       if (out_type_counter[SVID]) {
+               dev->has_raw_vbi_out = node_type & 0x0400;
+               dev->has_sliced_vbi_out = node_type & 0x0800;
+               dev->has_vbi_out = dev->has_raw_vbi_out | dev->has_sliced_vbi_out;
+       }
+
+       /* do we create a radio receiver device? */
+       dev->has_radio_rx = node_type & 0x0010;
+
+       /* do we create a radio transmitter device? */
+       dev->has_radio_tx = node_type & 0x1000;
+
+       /* do we create a software defined radio capture device? */
+       dev->has_sdr_cap = node_type & 0x0020;
+
+       /* do we have a tuner? */
+       has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) ||
+                   dev->has_radio_rx || dev->has_sdr_cap;
+
+       /* do we have a modulator? */
+       has_modulator = dev->has_radio_tx;
+
+       if (dev->has_vid_cap)
+               /* do we have a framebuffer for overlay testing? */
+               dev->has_fb = node_type & 0x10000;
+
+       /* can we do crop/compose/scaling while capturing? */
+       if (no_error_inj && ccs_cap == -1)
+               ccs_cap = 7;
+
+       /* if ccs_cap == -1, then the use can select it using controls */
+       if (ccs_cap != -1) {
+               dev->has_crop_cap = ccs_cap & 1;
+               dev->has_compose_cap = ccs_cap & 2;
+               dev->has_scaler_cap = ccs_cap & 4;
+               v4l2_info(&dev->v4l2_dev, "Capture Crop: %c Compose: %c Scaler: %c\n",
+                       dev->has_crop_cap ? 'Y' : 'N',
+                       dev->has_compose_cap ? 'Y' : 'N',
+                       dev->has_scaler_cap ? 'Y' : 'N');
+       }
+
+       /* can we do crop/compose/scaling with video output? */
+       if (no_error_inj && ccs_out == -1)
+               ccs_out = 7;
+
+       /* if ccs_out == -1, then the use can select it using controls */
+       if (ccs_out != -1) {
+               dev->has_crop_out = ccs_out & 1;
+               dev->has_compose_out = ccs_out & 2;
+               dev->has_scaler_out = ccs_out & 4;
+               v4l2_info(&dev->v4l2_dev, "Output Crop: %c Compose: %c Scaler: %c\n",
+                       dev->has_crop_out ? 'Y' : 'N',
+                       dev->has_compose_out ? 'Y' : 'N',
+                       dev->has_scaler_out ? 'Y' : 'N');
+       }
+
+       /* end detecting feature set */
+
+       if (dev->has_vid_cap) {
+               /* set up the capabilities of the video capture device */
+               dev->vid_cap_caps = dev->multiplanar ?
+                       V4L2_CAP_VIDEO_CAPTURE_MPLANE :
+                       V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY;
+               dev->vid_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+               if (dev->has_audio_inputs)
+                       dev->vid_cap_caps |= V4L2_CAP_AUDIO;
+               if (in_type_counter[TV])
+                       dev->vid_cap_caps |= V4L2_CAP_TUNER;
+       }
+       if (dev->has_vid_out) {
+               /* set up the capabilities of the video output device */
+               dev->vid_out_caps = dev->multiplanar ?
+                       V4L2_CAP_VIDEO_OUTPUT_MPLANE :
+                       V4L2_CAP_VIDEO_OUTPUT;
+               if (dev->has_fb)
+                       dev->vid_out_caps |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+               dev->vid_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+               if (dev->has_audio_outputs)
+                       dev->vid_out_caps |= V4L2_CAP_AUDIO;
+       }
+       if (dev->has_vbi_cap) {
+               /* set up the capabilities of the vbi capture device */
+               dev->vbi_cap_caps = (dev->has_raw_vbi_cap ? V4L2_CAP_VBI_CAPTURE : 0) |
+                                   (dev->has_sliced_vbi_cap ? V4L2_CAP_SLICED_VBI_CAPTURE : 0);
+               dev->vbi_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+               if (dev->has_audio_inputs)
+                       dev->vbi_cap_caps |= V4L2_CAP_AUDIO;
+               if (in_type_counter[TV])
+                       dev->vbi_cap_caps |= V4L2_CAP_TUNER;
+       }
+       if (dev->has_vbi_out) {
+               /* set up the capabilities of the vbi output device */
+               dev->vbi_out_caps = (dev->has_raw_vbi_out ? V4L2_CAP_VBI_OUTPUT : 0) |
+                                   (dev->has_sliced_vbi_out ? V4L2_CAP_SLICED_VBI_OUTPUT : 0);
+               dev->vbi_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+               if (dev->has_audio_outputs)
+                       dev->vbi_out_caps |= V4L2_CAP_AUDIO;
+       }
+       if (dev->has_sdr_cap) {
+               /* set up the capabilities of the sdr capture device */
+               dev->sdr_cap_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER;
+               dev->sdr_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+       }
+       /* set up the capabilities of the radio receiver device */
+       if (dev->has_radio_rx)
+               dev->radio_rx_caps = V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE |
+                                    V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
+                                    V4L2_CAP_READWRITE;
+       /* set up the capabilities of the radio transmitter device */
+       if (dev->has_radio_tx)
+               dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR |
+                                    V4L2_CAP_READWRITE;
+
+       /* initialize the test pattern generator */
+       tpg_init(&dev->tpg, 640, 360);
+       if (tpg_alloc(&dev->tpg, MAX_ZOOM * MAX_WIDTH))
+               goto free_dev;
+       dev->scaled_line = vzalloc(MAX_ZOOM * MAX_WIDTH);
+       if (!dev->scaled_line)
+               goto free_dev;
+       dev->blended_line = vzalloc(MAX_ZOOM * MAX_WIDTH);
+       if (!dev->blended_line)
+               goto free_dev;
+
+       /* load the edid */
+       dev->edid = vmalloc(256 * 128);
+       if (!dev->edid)
+               goto free_dev;
+
+       /* create a string array containing the names of all the preset timings */
+       while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width)
+               dev->query_dv_timings_size++;
+       dev->query_dv_timings_qmenu = kmalloc(dev->query_dv_timings_size *
+                                          (sizeof(void *) + 32), GFP_KERNEL);
+       if (dev->query_dv_timings_qmenu == NULL)
+               goto free_dev;
+       for (i = 0; i < dev->query_dv_timings_size; i++) {
+               const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt;
+               char *p = (char *)&dev->query_dv_timings_qmenu[dev->query_dv_timings_size];
+               u32 htot, vtot;
+
+               p += i * 32;
+               dev->query_dv_timings_qmenu[i] = p;
+
+               htot = V4L2_DV_BT_FRAME_WIDTH(bt);
+               vtot = V4L2_DV_BT_FRAME_HEIGHT(bt);
+               snprintf(p, 32, "%ux%u%s%u",
+                       bt->width, bt->height, bt->interlaced ? "i" : "p",
+                       (u32)bt->pixelclock / (htot * vtot));
+       }
+
+       /* disable invalid ioctls based on the feature set */
+       if (!dev->has_audio_inputs) {
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_AUDIO);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_AUDIO);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMAUDIO);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_AUDIO);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_AUDIO);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_ENUMAUDIO);
+       }
+       if (!dev->has_audio_outputs) {
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_AUDOUT);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMAUDOUT);
+               v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_AUDOUT);
+               v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_AUDOUT);
+               v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_ENUMAUDOUT);
+       }
+       if (!in_type_counter[TV] && !in_type_counter[SVID]) {
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_STD);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_STD);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMSTD);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERYSTD);
+       }
+       if (!out_type_counter[SVID]) {
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_STD);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_STD);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMSTD);
+       }
+       if (!has_tuner && !has_modulator) {
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_FREQUENCY);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_FREQUENCY);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_FREQUENCY);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY);
+       }
+       if (!has_tuner) {
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_TUNER);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_TUNER);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER);
+       }
+       if (in_type_counter[HDMI] == 0) {
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_EDID);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_DV_TIMINGS_CAP);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_DV_TIMINGS);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_DV_TIMINGS);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUM_DV_TIMINGS);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERY_DV_TIMINGS);
+       }
+       if (out_type_counter[HDMI] == 0) {
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_EDID);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_DV_TIMINGS_CAP);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_DV_TIMINGS);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_DV_TIMINGS);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_DV_TIMINGS);
+       }
+       if (!dev->has_fb) {
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FBUF);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FBUF);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_OVERLAY);
+       }
+       v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+       v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+       v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+       v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY);
+       v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY);
+       v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES);
+       v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMEINTERVALS);
+       v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_FREQUENCY);
+       v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_FREQUENCY);
+
+       /* configure internal data */
+       dev->fmt_cap = &vivid_formats[0];
+       dev->fmt_out = &vivid_formats[0];
+       if (!dev->multiplanar)
+               vivid_formats[0].data_offset[0] = 0;
+       dev->webcam_size_idx = 1;
+       dev->webcam_ival_idx = 3;
+       tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
+       dev->std_cap = V4L2_STD_PAL;
+       dev->std_out = V4L2_STD_PAL;
+       if (dev->input_type[0] == TV || dev->input_type[0] == SVID)
+               tvnorms_cap = V4L2_STD_ALL;
+       if (dev->output_type[0] == SVID)
+               tvnorms_out = V4L2_STD_ALL;
+       dev->dv_timings_cap = def_dv_timings;
+       dev->dv_timings_out = def_dv_timings;
+       dev->tv_freq = 2804 /* 175.25 * 16 */;
+       dev->tv_audmode = V4L2_TUNER_MODE_STEREO;
+       dev->tv_field_cap = V4L2_FIELD_INTERLACED;
+       dev->tv_field_out = V4L2_FIELD_INTERLACED;
+       dev->radio_rx_freq = 95000 * 16;
+       dev->radio_rx_audmode = V4L2_TUNER_MODE_STEREO;
+       if (dev->has_radio_tx) {
+               dev->radio_tx_freq = 95500 * 16;
+               dev->radio_rds_loop = false;
+       }
+       dev->radio_tx_subchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS;
+       dev->sdr_adc_freq = 300000;
+       dev->sdr_fm_freq = 50000000;
+       dev->edid_max_blocks = dev->edid_blocks = 2;
+       memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid));
+       ktime_get_ts(&dev->radio_rds_init_ts);
+
+       /* create all controls */
+       ret = vivid_create_controls(dev, ccs_cap == -1, ccs_out == -1, no_error_inj,
+                       in_type_counter[TV] || in_type_counter[SVID] ||
+                       out_type_counter[SVID],
+                       in_type_counter[HDMI] || out_type_counter[HDMI]);
+       if (ret)
+               goto unreg_dev;
+
+       /*
+        * update the capture and output formats to do a proper initial
+        * configuration.
+        */
+       vivid_update_format_cap(dev, false);
+       vivid_update_format_out(dev);
+
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out);
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap);
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out);
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx);
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx);
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
+
+       /* initialize overlay */
+       dev->fb_cap.fmt.width = dev->src_rect.width;
+       dev->fb_cap.fmt.height = dev->src_rect.height;
+       dev->fb_cap.fmt.pixelformat = dev->fmt_cap->fourcc;
+       dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
+       dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
+
+       /* initialize locks */
+       spin_lock_init(&dev->slock);
+       mutex_init(&dev->mutex);
+
+       /* init dma queues */
+       INIT_LIST_HEAD(&dev->vid_cap_active);
+       INIT_LIST_HEAD(&dev->vid_out_active);
+       INIT_LIST_HEAD(&dev->vbi_cap_active);
+       INIT_LIST_HEAD(&dev->vbi_out_active);
+       INIT_LIST_HEAD(&dev->sdr_cap_active);
+
+       /* start creating the vb2 queues */
+       if (dev->has_vid_cap) {
+               /* initialize vid_cap queue */
+               q = &dev->vb_vid_cap_q;
+               q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+                       V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+               q->drv_priv = dev;
+               q->buf_struct_size = sizeof(struct vivid_buffer);
+               q->ops = &vivid_vid_cap_qops;
+               q->mem_ops = &vb2_vmalloc_memops;
+               q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               q->min_buffers_needed = 2;
+
+               ret = vb2_queue_init(q);
+               if (ret)
+                       goto unreg_dev;
+       }
+
+       if (dev->has_vid_out) {
+               /* initialize vid_out queue */
+               q = &dev->vb_vid_out_q;
+               q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+                       V4L2_BUF_TYPE_VIDEO_OUTPUT;
+               q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE;
+               q->drv_priv = dev;
+               q->buf_struct_size = sizeof(struct vivid_buffer);
+               q->ops = &vivid_vid_out_qops;
+               q->mem_ops = &vb2_vmalloc_memops;
+               q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               q->min_buffers_needed = 2;
+
+               ret = vb2_queue_init(q);
+               if (ret)
+                       goto unreg_dev;
+       }
+
+       if (dev->has_vbi_cap) {
+               /* initialize vbi_cap queue */
+               q = &dev->vb_vbi_cap_q;
+               q->type = dev->has_raw_vbi_cap ? V4L2_BUF_TYPE_VBI_CAPTURE :
+                                             V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+               q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+               q->drv_priv = dev;
+               q->buf_struct_size = sizeof(struct vivid_buffer);
+               q->ops = &vivid_vbi_cap_qops;
+               q->mem_ops = &vb2_vmalloc_memops;
+               q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               q->min_buffers_needed = 2;
+
+               ret = vb2_queue_init(q);
+               if (ret)
+                       goto unreg_dev;
+       }
+
+       if (dev->has_vbi_out) {
+               /* initialize vbi_out queue */
+               q = &dev->vb_vbi_out_q;
+               q->type = dev->has_raw_vbi_out ? V4L2_BUF_TYPE_VBI_OUTPUT :
+                                             V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
+               q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE;
+               q->drv_priv = dev;
+               q->buf_struct_size = sizeof(struct vivid_buffer);
+               q->ops = &vivid_vbi_out_qops;
+               q->mem_ops = &vb2_vmalloc_memops;
+               q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               q->min_buffers_needed = 2;
+
+               ret = vb2_queue_init(q);
+               if (ret)
+                       goto unreg_dev;
+       }
+
+       if (dev->has_sdr_cap) {
+               /* initialize sdr_cap queue */
+               q = &dev->vb_sdr_cap_q;
+               q->type = V4L2_BUF_TYPE_SDR_CAPTURE;
+               q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+               q->drv_priv = dev;
+               q->buf_struct_size = sizeof(struct vivid_buffer);
+               q->ops = &vivid_sdr_cap_qops;
+               q->mem_ops = &vb2_vmalloc_memops;
+               q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               q->min_buffers_needed = 8;
+
+               ret = vb2_queue_init(q);
+               if (ret)
+                       goto unreg_dev;
+       }
+
+       if (dev->has_fb) {
+               /* Create framebuffer for testing capture/output overlay */
+               ret = vivid_fb_init(dev);
+               if (ret)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "Framebuffer device registered as fb%d\n",
+                               dev->fb_info.node);
+       }
+
+       /* finally start creating the device nodes */
+       if (dev->has_vid_cap) {
+               vfd = &dev->vid_cap_dev;
+               strlcpy(vfd->name, "vivid-vid-cap", sizeof(vfd->name));
+               vfd->fops = &vivid_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->queue = &dev->vb_vid_cap_q;
+               vfd->tvnorms = tvnorms_cap;
+
+               /*
+                * Provide a mutex to v4l2 core. It will be used to protect
+                * all fops and v4l2 ioctls.
+                */
+               vfd->lock = &dev->mutex;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_cap_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n",
+                                         video_device_node_name(vfd));
+       }
+
+       if (dev->has_vid_out) {
+               vfd = &dev->vid_out_dev;
+               strlcpy(vfd->name, "vivid-vid-out", sizeof(vfd->name));
+               vfd->vfl_dir = VFL_DIR_TX;
+               vfd->fops = &vivid_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->queue = &dev->vb_vid_out_q;
+               vfd->tvnorms = tvnorms_out;
+
+               /*
+                * Provide a mutex to v4l2 core. It will be used to protect
+                * all fops and v4l2 ioctls.
+                */
+               vfd->lock = &dev->mutex;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_out_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s\n",
+                                         video_device_node_name(vfd));
+       }
+
+       if (dev->has_vbi_cap) {
+               vfd = &dev->vbi_cap_dev;
+               strlcpy(vfd->name, "vivid-vbi-cap", sizeof(vfd->name));
+               vfd->fops = &vivid_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->queue = &dev->vb_vbi_cap_q;
+               vfd->lock = &dev->mutex;
+               vfd->tvnorms = tvnorms_cap;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_cap_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s, supports %s VBI\n",
+                                         video_device_node_name(vfd),
+                                         (dev->has_raw_vbi_cap && dev->has_sliced_vbi_cap) ?
+                                         "raw and sliced" :
+                                         (dev->has_raw_vbi_cap ? "raw" : "sliced"));
+       }
+
+       if (dev->has_vbi_out) {
+               vfd = &dev->vbi_out_dev;
+               strlcpy(vfd->name, "vivid-vbi-out", sizeof(vfd->name));
+               vfd->vfl_dir = VFL_DIR_TX;
+               vfd->fops = &vivid_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->queue = &dev->vb_vbi_out_q;
+               vfd->lock = &dev->mutex;
+               vfd->tvnorms = tvnorms_out;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_out_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s, supports %s VBI\n",
+                                         video_device_node_name(vfd),
+                                         (dev->has_raw_vbi_out && dev->has_sliced_vbi_out) ?
+                                         "raw and sliced" :
+                                         (dev->has_raw_vbi_out ? "raw" : "sliced"));
+       }
+
+       if (dev->has_sdr_cap) {
+               vfd = &dev->sdr_cap_dev;
+               strlcpy(vfd->name, "vivid-sdr-cap", sizeof(vfd->name));
+               vfd->fops = &vivid_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->queue = &dev->vb_sdr_cap_q;
+               vfd->lock = &dev->mutex;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_SDR, sdr_cap_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n",
+                                         video_device_node_name(vfd));
+       }
+
+       if (dev->has_radio_rx) {
+               vfd = &dev->radio_rx_dev;
+               strlcpy(vfd->name, "vivid-rad-rx", sizeof(vfd->name));
+               vfd->fops = &vivid_radio_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->lock = &dev->mutex;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_rx_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 receiver device registered as %s\n",
+                                         video_device_node_name(vfd));
+       }
+
+       if (dev->has_radio_tx) {
+               vfd = &dev->radio_tx_dev;
+               strlcpy(vfd->name, "vivid-rad-tx", sizeof(vfd->name));
+               vfd->vfl_dir = VFL_DIR_TX;
+               vfd->fops = &vivid_radio_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->lock = &dev->mutex;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_tx_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 transmitter device registered as %s\n",
+                                         video_device_node_name(vfd));
+       }
+
+       /* Now that everything is fine, let's add it to device list */
+       vivid_devs[inst] = dev;
+
+       return 0;
+
+unreg_dev:
+       video_unregister_device(&dev->radio_tx_dev);
+       video_unregister_device(&dev->radio_rx_dev);
+       video_unregister_device(&dev->sdr_cap_dev);
+       video_unregister_device(&dev->vbi_out_dev);
+       video_unregister_device(&dev->vbi_cap_dev);
+       video_unregister_device(&dev->vid_out_dev);
+       video_unregister_device(&dev->vid_cap_dev);
+       vivid_free_controls(dev);
+       v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+       vfree(dev->scaled_line);
+       vfree(dev->blended_line);
+       vfree(dev->edid);
+       tpg_free(&dev->tpg);
+       kfree(dev->query_dv_timings_qmenu);
+       kfree(dev);
+       return ret;
+}
+
+/* This routine allocates from 1 to n_devs virtual drivers.
+
+   The real maximum number of virtual drivers will depend on how many drivers
+   will succeed. This is limited to the maximum number of devices that
+   videodev supports, which is equal to VIDEO_NUM_DEVICES.
+ */
+static int __init vivid_init(void)
+{
+       const struct font_desc *font = find_font("VGA8x16");
+       int ret = 0, i;
+
+       if (font == NULL) {
+               pr_err("vivid: could not find font\n");
+               return -ENODEV;
+       }
+
+       tpg_set_font(font->data);
+
+       n_devs = clamp_t(unsigned, n_devs, 1, VIVID_MAX_DEVS);
+
+       for (i = 0; i < n_devs; i++) {
+               ret = vivid_create_instance(i);
+               if (ret) {
+                       /* If some instantiations succeeded, keep driver */
+                       if (i)
+                               ret = 0;
+                       break;
+               }
+       }
+
+       if (ret < 0) {
+               pr_err("vivid: error %d while loading driver\n", ret);
+               return ret;
+       }
+
+       /* n_devs will reflect the actual number of allocated devices */
+       n_devs = i;
+
+       return ret;
+}
+
+static void __exit vivid_exit(void)
+{
+       struct vivid_dev *dev;
+       unsigned i;
+
+       for (i = 0; vivid_devs[i]; i++) {
+               dev = vivid_devs[i];
+
+               if (dev->has_vid_cap) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->vid_cap_dev));
+                       video_unregister_device(&dev->vid_cap_dev);
+               }
+               if (dev->has_vid_out) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->vid_out_dev));
+                       video_unregister_device(&dev->vid_out_dev);
+               }
+               if (dev->has_vbi_cap) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->vbi_cap_dev));
+                       video_unregister_device(&dev->vbi_cap_dev);
+               }
+               if (dev->has_vbi_out) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->vbi_out_dev));
+                       video_unregister_device(&dev->vbi_out_dev);
+               }
+               if (dev->has_sdr_cap) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->sdr_cap_dev));
+                       video_unregister_device(&dev->sdr_cap_dev);
+               }
+               if (dev->has_radio_rx) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->radio_rx_dev));
+                       video_unregister_device(&dev->radio_rx_dev);
+               }
+               if (dev->has_radio_tx) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->radio_tx_dev));
+                       video_unregister_device(&dev->radio_tx_dev);
+               }
+               if (dev->has_fb) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering fb%d\n",
+                               dev->fb_info.node);
+                       unregister_framebuffer(&dev->fb_info);
+                       vivid_fb_release_buffers(dev);
+               }
+               v4l2_device_unregister(&dev->v4l2_dev);
+               vivid_free_controls(dev);
+               vfree(dev->scaled_line);
+               vfree(dev->blended_line);
+               vfree(dev->edid);
+               vfree(dev->bitmap_cap);
+               vfree(dev->bitmap_out);
+               tpg_free(&dev->tpg);
+               kfree(dev->query_dv_timings_qmenu);
+               kfree(dev);
+               vivid_devs[i] = NULL;
+       }
+}
+
+module_init(vivid_init);
+module_exit(vivid_exit);
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
new file mode 100644 (file)
index 0000000..811c286
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * vivid-core.h - core datastructures
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_CORE_H_
+#define _VIVID_CORE_H_
+
+#include <linux/fb.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ctrls.h>
+#include "vivid-tpg.h"
+#include "vivid-rds-gen.h"
+#include "vivid-vbi-gen.h"
+
+#define dprintk(dev, level, fmt, arg...) \
+       v4l2_dbg(level, vivid_debug, &dev->v4l2_dev, fmt, ## arg)
+
+/* Maximum allowed frame rate
+ *
+ * vivid will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range.
+ *
+ * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that
+ * might hit application errors when they manipulate these values.
+ *
+ * Besides, for tpf < 10ms image-generation logic should be changed, to avoid
+ * producing frames with equal content.
+ */
+#define FPS_MAX 100
+
+/* The maximum number of clip rectangles */
+#define MAX_CLIPS  16
+/* The maximum number of inputs */
+#define MAX_INPUTS 16
+/* The maximum number of outputs */
+#define MAX_OUTPUTS 16
+/* The maximum up or down scaling factor is 4 */
+#define MAX_ZOOM  4
+/* The maximum image width/height are set to 4K DMT */
+#define MAX_WIDTH  4096
+#define MAX_HEIGHT 2160
+/* The minimum image width/height */
+#define MIN_WIDTH  16
+#define MIN_HEIGHT 16
+/* The data_offset of plane 0 for the multiplanar formats */
+#define PLANE0_DATA_OFFSET 128
+
+/* The supported TV frequency range in MHz */
+#define MIN_TV_FREQ (44U * 16U)
+#define MAX_TV_FREQ (958U * 16U)
+
+/* The number of samples returned in every SDR buffer */
+#define SDR_CAP_SAMPLES_PER_BUF 0x4000
+
+/* used by the threads to know when to resync internal counters */
+#define JIFFIES_PER_DAY (3600U * 24U * HZ)
+#define JIFFIES_RESYNC (JIFFIES_PER_DAY * (0xf0000000U / JIFFIES_PER_DAY))
+
+extern const struct v4l2_rect vivid_min_rect;
+extern const struct v4l2_rect vivid_max_rect;
+extern unsigned vivid_debug;
+
+struct vivid_fmt {
+       const char *name;
+       u32     fourcc;          /* v4l2 format id */
+       u8      depth;
+       bool    is_yuv;
+       bool    can_do_overlay;
+       u32     alpha_mask;
+       u8      planes;
+       u32     data_offset[2];
+};
+
+extern struct vivid_fmt vivid_formats[];
+
+/* buffer for one video frame */
+struct vivid_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct vb2_buffer       vb;
+       struct list_head        list;
+};
+
+enum vivid_input {
+       WEBCAM,
+       TV,
+       SVID,
+       HDMI,
+};
+
+enum vivid_signal_mode {
+       CURRENT_DV_TIMINGS,
+       CURRENT_STD = CURRENT_DV_TIMINGS,
+       NO_SIGNAL,
+       NO_LOCK,
+       OUT_OF_RANGE,
+       SELECTED_DV_TIMINGS,
+       SELECTED_STD = SELECTED_DV_TIMINGS,
+       CYCLE_DV_TIMINGS,
+       CYCLE_STD = CYCLE_DV_TIMINGS,
+       CUSTOM_DV_TIMINGS,
+};
+
+#define VIVID_INVALID_SIGNAL(mode) \
+       ((mode) == NO_SIGNAL || (mode) == NO_LOCK || (mode) == OUT_OF_RANGE)
+
+struct vivid_dev {
+       unsigned                        inst;
+       struct v4l2_device              v4l2_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_user_gen;
+       struct v4l2_ctrl_handler        ctrl_hdl_user_vid;
+       struct v4l2_ctrl_handler        ctrl_hdl_user_aud;
+       struct v4l2_ctrl_handler        ctrl_hdl_streaming;
+       struct v4l2_ctrl_handler        ctrl_hdl_sdtv_cap;
+       struct v4l2_ctrl_handler        ctrl_hdl_loop_out;
+       struct video_device             vid_cap_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_vid_cap;
+       struct video_device             vid_out_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_vid_out;
+       struct video_device             vbi_cap_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_vbi_cap;
+       struct video_device             vbi_out_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_vbi_out;
+       struct video_device             radio_rx_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_radio_rx;
+       struct video_device             radio_tx_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_radio_tx;
+       struct video_device             sdr_cap_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_sdr_cap;
+       spinlock_t                      slock;
+       struct mutex                    mutex;
+
+       /* capabilities */
+       u32                             vid_cap_caps;
+       u32                             vid_out_caps;
+       u32                             vbi_cap_caps;
+       u32                             vbi_out_caps;
+       u32                             sdr_cap_caps;
+       u32                             radio_rx_caps;
+       u32                             radio_tx_caps;
+
+       /* supported features */
+       bool                            multiplanar;
+       unsigned                        num_inputs;
+       u8                              input_type[MAX_INPUTS];
+       u8                              input_name_counter[MAX_INPUTS];
+       unsigned                        num_outputs;
+       u8                              output_type[MAX_OUTPUTS];
+       u8                              output_name_counter[MAX_OUTPUTS];
+       bool                            has_audio_inputs;
+       bool                            has_audio_outputs;
+       bool                            has_vid_cap;
+       bool                            has_vid_out;
+       bool                            has_vbi_cap;
+       bool                            has_raw_vbi_cap;
+       bool                            has_sliced_vbi_cap;
+       bool                            has_vbi_out;
+       bool                            has_raw_vbi_out;
+       bool                            has_sliced_vbi_out;
+       bool                            has_radio_rx;
+       bool                            has_radio_tx;
+       bool                            has_sdr_cap;
+       bool                            has_fb;
+
+       bool                            can_loop_video;
+
+       /* controls */
+       struct v4l2_ctrl                *brightness;
+       struct v4l2_ctrl                *contrast;
+       struct v4l2_ctrl                *saturation;
+       struct v4l2_ctrl                *hue;
+       struct {
+               /* autogain/gain cluster */
+               struct v4l2_ctrl        *autogain;
+               struct v4l2_ctrl        *gain;
+       };
+       struct v4l2_ctrl                *volume;
+       struct v4l2_ctrl                *mute;
+       struct v4l2_ctrl                *alpha;
+       struct v4l2_ctrl                *button;
+       struct v4l2_ctrl                *boolean;
+       struct v4l2_ctrl                *int32;
+       struct v4l2_ctrl                *int64;
+       struct v4l2_ctrl                *menu;
+       struct v4l2_ctrl                *string;
+       struct v4l2_ctrl                *bitmask;
+       struct v4l2_ctrl                *int_menu;
+       struct v4l2_ctrl                *test_pattern;
+       struct v4l2_ctrl                *colorspace;
+       struct v4l2_ctrl                *rgb_range_cap;
+       struct v4l2_ctrl                *real_rgb_range_cap;
+       struct {
+               /* std_signal_mode/standard cluster */
+               struct v4l2_ctrl        *ctrl_std_signal_mode;
+               struct v4l2_ctrl        *ctrl_standard;
+       };
+       struct {
+               /* dv_timings_signal_mode/timings cluster */
+               struct v4l2_ctrl        *ctrl_dv_timings_signal_mode;
+               struct v4l2_ctrl        *ctrl_dv_timings;
+       };
+       struct v4l2_ctrl                *ctrl_has_crop_cap;
+       struct v4l2_ctrl                *ctrl_has_compose_cap;
+       struct v4l2_ctrl                *ctrl_has_scaler_cap;
+       struct v4l2_ctrl                *ctrl_has_crop_out;
+       struct v4l2_ctrl                *ctrl_has_compose_out;
+       struct v4l2_ctrl                *ctrl_has_scaler_out;
+       struct v4l2_ctrl                *ctrl_tx_mode;
+       struct v4l2_ctrl                *ctrl_tx_rgb_range;
+
+       struct v4l2_ctrl                *radio_tx_rds_pi;
+       struct v4l2_ctrl                *radio_tx_rds_pty;
+       struct v4l2_ctrl                *radio_tx_rds_mono_stereo;
+       struct v4l2_ctrl                *radio_tx_rds_art_head;
+       struct v4l2_ctrl                *radio_tx_rds_compressed;
+       struct v4l2_ctrl                *radio_tx_rds_dyn_pty;
+       struct v4l2_ctrl                *radio_tx_rds_ta;
+       struct v4l2_ctrl                *radio_tx_rds_tp;
+       struct v4l2_ctrl                *radio_tx_rds_ms;
+       struct v4l2_ctrl                *radio_tx_rds_psname;
+       struct v4l2_ctrl                *radio_tx_rds_radiotext;
+
+       struct v4l2_ctrl                *radio_rx_rds_pty;
+       struct v4l2_ctrl                *radio_rx_rds_ta;
+       struct v4l2_ctrl                *radio_rx_rds_tp;
+       struct v4l2_ctrl                *radio_rx_rds_ms;
+       struct v4l2_ctrl                *radio_rx_rds_psname;
+       struct v4l2_ctrl                *radio_rx_rds_radiotext;
+
+       unsigned                        input_brightness[MAX_INPUTS];
+       unsigned                        osd_mode;
+       unsigned                        button_pressed;
+       bool                            sensor_hflip;
+       bool                            sensor_vflip;
+       bool                            hflip;
+       bool                            vflip;
+       bool                            vbi_cap_interlaced;
+       bool                            loop_video;
+
+       /* Framebuffer */
+       unsigned long                   video_pbase;
+       void                            *video_vbase;
+       u32                             video_buffer_size;
+       int                             display_width;
+       int                             display_height;
+       int                             display_byte_stride;
+       int                             bits_per_pixel;
+       int                             bytes_per_pixel;
+       struct fb_info                  fb_info;
+       struct fb_var_screeninfo        fb_defined;
+       struct fb_fix_screeninfo        fb_fix;
+
+       /* Error injection */
+       bool                            queue_setup_error;
+       bool                            buf_prepare_error;
+       bool                            start_streaming_error;
+       bool                            dqbuf_error;
+       bool                            seq_wrap;
+       bool                            time_wrap;
+       __kernel_time_t                 time_wrap_offset;
+       unsigned                        perc_dropped_buffers;
+       enum vivid_signal_mode          std_signal_mode;
+       unsigned                        query_std_last;
+       v4l2_std_id                     query_std;
+       enum tpg_video_aspect           std_aspect_ratio;
+
+       enum vivid_signal_mode          dv_timings_signal_mode;
+       char                            **query_dv_timings_qmenu;
+       unsigned                        query_dv_timings_size;
+       unsigned                        query_dv_timings_last;
+       unsigned                        query_dv_timings;
+       enum tpg_video_aspect           dv_timings_aspect_ratio;
+
+       /* Input */
+       unsigned                        input;
+       v4l2_std_id                     std_cap;
+       struct v4l2_dv_timings          dv_timings_cap;
+       u32                             service_set_cap;
+       struct vivid_vbi_gen_data       vbi_gen;
+       u8                              *edid;
+       unsigned                        edid_blocks;
+       unsigned                        edid_max_blocks;
+       unsigned                        webcam_size_idx;
+       unsigned                        webcam_ival_idx;
+       unsigned                        tv_freq;
+       unsigned                        tv_audmode;
+       unsigned                        tv_field_cap;
+       unsigned                        tv_audio_input;
+
+       /* Capture Overlay */
+       struct v4l2_framebuffer         fb_cap;
+       struct v4l2_fh                  *overlay_cap_owner;
+       void                            *fb_vbase_cap;
+       int                             overlay_cap_top, overlay_cap_left;
+       enum v4l2_field                 overlay_cap_field;
+       void                            *bitmap_cap;
+       struct v4l2_clip                clips_cap[MAX_CLIPS];
+       struct v4l2_clip                try_clips_cap[MAX_CLIPS];
+       unsigned                        clipcount_cap;
+
+       /* Output */
+       unsigned                        output;
+       v4l2_std_id                     std_out;
+       struct v4l2_dv_timings          dv_timings_out;
+       u32                             colorspace_out;
+       u32                             service_set_out;
+       u32                             bytesperline_out[2];
+       unsigned                        tv_field_out;
+       unsigned                        tv_audio_output;
+       bool                            vbi_out_have_wss;
+       u8                              vbi_out_wss[2];
+       bool                            vbi_out_have_cc[2];
+       u8                              vbi_out_cc[2][2];
+       bool                            dvi_d_out;
+       u8                              *scaled_line;
+       u8                              *blended_line;
+       unsigned                        cur_scaled_line;
+
+       /* Output Overlay */
+       void                            *fb_vbase_out;
+       bool                            overlay_out_enabled;
+       int                             overlay_out_top, overlay_out_left;
+       void                            *bitmap_out;
+       struct v4l2_clip                clips_out[MAX_CLIPS];
+       struct v4l2_clip                try_clips_out[MAX_CLIPS];
+       unsigned                        clipcount_out;
+       unsigned                        fbuf_out_flags;
+       u32                             chromakey_out;
+       u8                              global_alpha_out;
+
+       /* video capture */
+       struct tpg_data                 tpg;
+       unsigned                        ms_vid_cap;
+       bool                            must_blank[VIDEO_MAX_FRAME];
+
+       const struct vivid_fmt          *fmt_cap;
+       struct v4l2_fract               timeperframe_vid_cap;
+       enum v4l2_field                 field_cap;
+       struct v4l2_rect                src_rect;
+       struct v4l2_rect                fmt_cap_rect;
+       struct v4l2_rect                crop_cap;
+       struct v4l2_rect                compose_cap;
+       struct v4l2_rect                crop_bounds_cap;
+       struct vb2_queue                vb_vid_cap_q;
+       struct list_head                vid_cap_active;
+       struct vb2_queue                vb_vbi_cap_q;
+       struct list_head                vbi_cap_active;
+
+       /* thread for generating video capture stream */
+       struct task_struct              *kthread_vid_cap;
+       unsigned long                   jiffies_vid_cap;
+       u32                             cap_seq_offset;
+       u32                             cap_seq_count;
+       bool                            cap_seq_resync;
+       u32                             vid_cap_seq_start;
+       u32                             vid_cap_seq_count;
+       bool                            vid_cap_streaming;
+       u32                             vbi_cap_seq_start;
+       u32                             vbi_cap_seq_count;
+       bool                            vbi_cap_streaming;
+       bool                            stream_sliced_vbi_cap;
+
+       /* video output */
+       const struct vivid_fmt          *fmt_out;
+       struct v4l2_fract               timeperframe_vid_out;
+       enum v4l2_field                 field_out;
+       struct v4l2_rect                sink_rect;
+       struct v4l2_rect                fmt_out_rect;
+       struct v4l2_rect                crop_out;
+       struct v4l2_rect                compose_out;
+       struct v4l2_rect                compose_bounds_out;
+       struct vb2_queue                vb_vid_out_q;
+       struct list_head                vid_out_active;
+       struct vb2_queue                vb_vbi_out_q;
+       struct list_head                vbi_out_active;
+
+       /* video loop precalculated rectangles */
+
+       /*
+        * Intersection between what the output side composes and the capture side
+        * crops. I.e., what actually needs to be copied from the output buffer to
+        * the capture buffer.
+        */
+       struct v4l2_rect                loop_vid_copy;
+       /* The part of the output buffer that (after scaling) corresponds to loop_vid_copy. */
+       struct v4l2_rect                loop_vid_out;
+       /* The part of the capture buffer that (after scaling) corresponds to loop_vid_copy. */
+       struct v4l2_rect                loop_vid_cap;
+       /*
+        * The intersection of the framebuffer, the overlay output window and
+        * loop_vid_copy. I.e., the part of the framebuffer that actually should be
+        * blended with the compose_out rectangle. This uses the framebuffer origin.
+        */
+       struct v4l2_rect                loop_fb_copy;
+       /* The same as loop_fb_copy but with compose_out origin. */
+       struct v4l2_rect                loop_vid_overlay;
+       /*
+        * The part of the capture buffer that (after scaling) corresponds
+        * to loop_vid_overlay.
+        */
+       struct v4l2_rect                loop_vid_overlay_cap;
+
+       /* thread for generating video output stream */
+       struct task_struct              *kthread_vid_out;
+       unsigned long                   jiffies_vid_out;
+       u32                             out_seq_offset;
+       u32                             out_seq_count;
+       bool                            out_seq_resync;
+       u32                             vid_out_seq_start;
+       u32                             vid_out_seq_count;
+       bool                            vid_out_streaming;
+       u32                             vbi_out_seq_start;
+       u32                             vbi_out_seq_count;
+       bool                            vbi_out_streaming;
+       bool                            stream_sliced_vbi_out;
+
+       /* SDR capture */
+       struct vb2_queue                vb_sdr_cap_q;
+       struct list_head                sdr_cap_active;
+       unsigned                        sdr_adc_freq;
+       unsigned                        sdr_fm_freq;
+       int                             sdr_fixp_src_phase;
+       int                             sdr_fixp_mod_phase;
+
+       bool                            tstamp_src_is_soe;
+       bool                            has_crop_cap;
+       bool                            has_compose_cap;
+       bool                            has_scaler_cap;
+       bool                            has_crop_out;
+       bool                            has_compose_out;
+       bool                            has_scaler_out;
+
+       /* thread for generating SDR stream */
+       struct task_struct              *kthread_sdr_cap;
+       unsigned long                   jiffies_sdr_cap;
+       u32                             sdr_cap_seq_offset;
+       u32                             sdr_cap_seq_count;
+       bool                            sdr_cap_seq_resync;
+
+       /* RDS generator */
+       struct vivid_rds_gen            rds_gen;
+
+       /* Radio receiver */
+       unsigned                        radio_rx_freq;
+       unsigned                        radio_rx_audmode;
+       int                             radio_rx_sig_qual;
+       unsigned                        radio_rx_hw_seek_mode;
+       bool                            radio_rx_hw_seek_prog_lim;
+       bool                            radio_rx_rds_controls;
+       bool                            radio_rx_rds_enabled;
+       unsigned                        radio_rx_rds_use_alternates;
+       unsigned                        radio_rx_rds_last_block;
+       struct v4l2_fh                  *radio_rx_rds_owner;
+
+       /* Radio transmitter */
+       unsigned                        radio_tx_freq;
+       unsigned                        radio_tx_subchans;
+       bool                            radio_tx_rds_controls;
+       unsigned                        radio_tx_rds_last_block;
+       struct v4l2_fh                  *radio_tx_rds_owner;
+
+       /* Shared between radio receiver and transmitter */
+       bool                            radio_rds_loop;
+       struct timespec                 radio_rds_init_ts;
+};
+
+static inline bool vivid_is_webcam(const struct vivid_dev *dev)
+{
+       return dev->input_type[dev->input] == WEBCAM;
+}
+
+static inline bool vivid_is_tv_cap(const struct vivid_dev *dev)
+{
+       return dev->input_type[dev->input] == TV;
+}
+
+static inline bool vivid_is_svid_cap(const struct vivid_dev *dev)
+{
+       return dev->input_type[dev->input] == SVID;
+}
+
+static inline bool vivid_is_hdmi_cap(const struct vivid_dev *dev)
+{
+       return dev->input_type[dev->input] == HDMI;
+}
+
+static inline bool vivid_is_sdtv_cap(const struct vivid_dev *dev)
+{
+       return vivid_is_tv_cap(dev) || vivid_is_svid_cap(dev);
+}
+
+static inline bool vivid_is_svid_out(const struct vivid_dev *dev)
+{
+       return dev->output_type[dev->output] == SVID;
+}
+
+static inline bool vivid_is_hdmi_out(const struct vivid_dev *dev)
+{
+       return dev->output_type[dev->output] == HDMI;
+}
+
+void vivid_lock(struct vb2_queue *vq);
+void vivid_unlock(struct vb2_queue *vq);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
new file mode 100644 (file)
index 0000000..d5cbf00
--- /dev/null
@@ -0,0 +1,1502 @@
+/*
+ * vivid-ctrls.c - control support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-cap.h"
+#include "vivid-vid-out.h"
+#include "vivid-vid-common.h"
+#include "vivid-radio-common.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.h"
+
+#define VIVID_CID_CUSTOM_BASE          (V4L2_CID_USER_BASE | 0xf000)
+#define VIVID_CID_BUTTON               (VIVID_CID_CUSTOM_BASE + 0)
+#define VIVID_CID_BOOLEAN              (VIVID_CID_CUSTOM_BASE + 1)
+#define VIVID_CID_INTEGER              (VIVID_CID_CUSTOM_BASE + 2)
+#define VIVID_CID_INTEGER64            (VIVID_CID_CUSTOM_BASE + 3)
+#define VIVID_CID_MENU                 (VIVID_CID_CUSTOM_BASE + 4)
+#define VIVID_CID_STRING               (VIVID_CID_CUSTOM_BASE + 5)
+#define VIVID_CID_BITMASK              (VIVID_CID_CUSTOM_BASE + 6)
+#define VIVID_CID_INTMENU              (VIVID_CID_CUSTOM_BASE + 7)
+
+#define VIVID_CID_VIVID_BASE           (0x00f00000 | 0xf000)
+#define VIVID_CID_VIVID_CLASS          (0x00f00000 | 1)
+#define VIVID_CID_TEST_PATTERN         (VIVID_CID_VIVID_BASE + 0)
+#define VIVID_CID_OSD_TEXT_MODE                (VIVID_CID_VIVID_BASE + 1)
+#define VIVID_CID_HOR_MOVEMENT         (VIVID_CID_VIVID_BASE + 2)
+#define VIVID_CID_VERT_MOVEMENT                (VIVID_CID_VIVID_BASE + 3)
+#define VIVID_CID_SHOW_BORDER          (VIVID_CID_VIVID_BASE + 4)
+#define VIVID_CID_SHOW_SQUARE          (VIVID_CID_VIVID_BASE + 5)
+#define VIVID_CID_INSERT_SAV           (VIVID_CID_VIVID_BASE + 6)
+#define VIVID_CID_INSERT_EAV           (VIVID_CID_VIVID_BASE + 7)
+#define VIVID_CID_VBI_CAP_INTERLACED   (VIVID_CID_VIVID_BASE + 8)
+
+#define VIVID_CID_HFLIP                        (VIVID_CID_VIVID_BASE + 20)
+#define VIVID_CID_VFLIP                        (VIVID_CID_VIVID_BASE + 21)
+#define VIVID_CID_STD_ASPECT_RATIO     (VIVID_CID_VIVID_BASE + 22)
+#define VIVID_CID_DV_TIMINGS_ASPECT_RATIO      (VIVID_CID_VIVID_BASE + 23)
+#define VIVID_CID_TSTAMP_SRC           (VIVID_CID_VIVID_BASE + 24)
+#define VIVID_CID_COLORSPACE           (VIVID_CID_VIVID_BASE + 25)
+#define VIVID_CID_LIMITED_RGB_RANGE    (VIVID_CID_VIVID_BASE + 26)
+#define VIVID_CID_ALPHA_MODE           (VIVID_CID_VIVID_BASE + 27)
+#define VIVID_CID_HAS_CROP_CAP         (VIVID_CID_VIVID_BASE + 28)
+#define VIVID_CID_HAS_COMPOSE_CAP      (VIVID_CID_VIVID_BASE + 29)
+#define VIVID_CID_HAS_SCALER_CAP       (VIVID_CID_VIVID_BASE + 30)
+#define VIVID_CID_HAS_CROP_OUT         (VIVID_CID_VIVID_BASE + 31)
+#define VIVID_CID_HAS_COMPOSE_OUT      (VIVID_CID_VIVID_BASE + 32)
+#define VIVID_CID_HAS_SCALER_OUT       (VIVID_CID_VIVID_BASE + 33)
+#define VIVID_CID_LOOP_VIDEO           (VIVID_CID_VIVID_BASE + 34)
+#define VIVID_CID_SEQ_WRAP             (VIVID_CID_VIVID_BASE + 35)
+#define VIVID_CID_TIME_WRAP            (VIVID_CID_VIVID_BASE + 36)
+#define VIVID_CID_MAX_EDID_BLOCKS      (VIVID_CID_VIVID_BASE + 37)
+#define VIVID_CID_PERCENTAGE_FILL      (VIVID_CID_VIVID_BASE + 38)
+
+#define VIVID_CID_STD_SIGNAL_MODE      (VIVID_CID_VIVID_BASE + 60)
+#define VIVID_CID_STANDARD             (VIVID_CID_VIVID_BASE + 61)
+#define VIVID_CID_DV_TIMINGS_SIGNAL_MODE       (VIVID_CID_VIVID_BASE + 62)
+#define VIVID_CID_DV_TIMINGS           (VIVID_CID_VIVID_BASE + 63)
+#define VIVID_CID_PERC_DROPPED         (VIVID_CID_VIVID_BASE + 64)
+#define VIVID_CID_DISCONNECT           (VIVID_CID_VIVID_BASE + 65)
+#define VIVID_CID_DQBUF_ERROR          (VIVID_CID_VIVID_BASE + 66)
+#define VIVID_CID_QUEUE_SETUP_ERROR    (VIVID_CID_VIVID_BASE + 67)
+#define VIVID_CID_BUF_PREPARE_ERROR    (VIVID_CID_VIVID_BASE + 68)
+#define VIVID_CID_START_STR_ERROR      (VIVID_CID_VIVID_BASE + 69)
+#define VIVID_CID_QUEUE_ERROR          (VIVID_CID_VIVID_BASE + 70)
+#define VIVID_CID_CLEAR_FB             (VIVID_CID_VIVID_BASE + 71)
+
+#define VIVID_CID_RADIO_SEEK_MODE      (VIVID_CID_VIVID_BASE + 90)
+#define VIVID_CID_RADIO_SEEK_PROG_LIM  (VIVID_CID_VIVID_BASE + 91)
+#define VIVID_CID_RADIO_RX_RDS_RBDS    (VIVID_CID_VIVID_BASE + 92)
+#define VIVID_CID_RADIO_RX_RDS_BLOCKIO (VIVID_CID_VIVID_BASE + 93)
+
+#define VIVID_CID_RADIO_TX_RDS_BLOCKIO (VIVID_CID_VIVID_BASE + 94)
+
+
+/* General User Controls */
+
+static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_gen);
+
+       switch (ctrl->id) {
+       case VIVID_CID_DISCONNECT:
+               v4l2_info(&dev->v4l2_dev, "disconnect\n");
+               clear_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags);
+               clear_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags);
+               clear_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags);
+               clear_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags);
+               clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags);
+               clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags);
+               clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
+               break;
+       case VIVID_CID_CLEAR_FB:
+               vivid_clear_fb(dev);
+               break;
+       case VIVID_CID_BUTTON:
+               dev->button_pressed = 30;
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_user_gen_ctrl_ops = {
+       .s_ctrl = vivid_user_gen_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_button = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_BUTTON,
+       .name = "Button",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_boolean = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_BOOLEAN,
+       .name = "Boolean",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .min = 0,
+       .max = 1,
+       .step = 1,
+       .def = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_int32 = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_INTEGER,
+       .name = "Integer 32 Bits",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = 0xffffffff80000000ULL,
+       .max = 0x7fffffff,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_int64 = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_INTEGER64,
+       .name = "Integer 64 Bits",
+       .type = V4L2_CTRL_TYPE_INTEGER64,
+       .min = 0x8000000000000000ULL,
+       .max = 0x7fffffffffffffffLL,
+       .step = 1,
+};
+
+static const char * const vivid_ctrl_menu_strings[] = {
+       "Menu Item 0 (Skipped)",
+       "Menu Item 1",
+       "Menu Item 2 (Skipped)",
+       "Menu Item 3",
+       "Menu Item 4",
+       "Menu Item 5 (Skipped)",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_menu = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_MENU,
+       .name = "Menu",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .min = 1,
+       .max = 4,
+       .def = 3,
+       .menu_skip_mask = 0x04,
+       .qmenu = vivid_ctrl_menu_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_string = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_STRING,
+       .name = "String",
+       .type = V4L2_CTRL_TYPE_STRING,
+       .min = 2,
+       .max = 4,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_bitmask = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_BITMASK,
+       .name = "Bitmask",
+       .type = V4L2_CTRL_TYPE_BITMASK,
+       .def = 0x80002000,
+       .min = 0,
+       .max = 0x80402010,
+       .step = 0,
+};
+
+static const s64 vivid_ctrl_int_menu_values[] = {
+       1, 1, 2, 3, 5, 8, 13, 21, 42,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_int_menu = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_INTMENU,
+       .name = "Integer Menu",
+       .type = V4L2_CTRL_TYPE_INTEGER_MENU,
+       .min = 1,
+       .max = 8,
+       .def = 4,
+       .menu_skip_mask = 0x02,
+       .qmenu_int = vivid_ctrl_int_menu_values,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_disconnect = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_DISCONNECT,
+       .name = "Disconnect",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_clear_fb = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_CLEAR_FB,
+       .name = "Clear Framebuffer",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+
+/* Video User Controls */
+
+static int vivid_user_vid_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTOGAIN:
+               dev->gain->val = dev->jiffies_vid_cap & 0xff;
+               break;
+       }
+       return 0;
+}
+
+static int vivid_user_vid_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid);
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               dev->input_brightness[dev->input] = ctrl->val - dev->input * 128;
+               tpg_s_brightness(&dev->tpg, dev->input_brightness[dev->input]);
+               break;
+       case V4L2_CID_CONTRAST:
+               tpg_s_contrast(&dev->tpg, ctrl->val);
+               break;
+       case V4L2_CID_SATURATION:
+               tpg_s_saturation(&dev->tpg, ctrl->val);
+               break;
+       case V4L2_CID_HUE:
+               tpg_s_hue(&dev->tpg, ctrl->val);
+               break;
+       case V4L2_CID_HFLIP:
+               dev->hflip = ctrl->val;
+               tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip);
+               break;
+       case V4L2_CID_VFLIP:
+               dev->vflip = ctrl->val;
+               tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip);
+               break;
+       case V4L2_CID_ALPHA_COMPONENT:
+               tpg_s_alpha_component(&dev->tpg, ctrl->val);
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_user_vid_ctrl_ops = {
+       .g_volatile_ctrl = vivid_user_vid_g_volatile_ctrl,
+       .s_ctrl = vivid_user_vid_s_ctrl,
+};
+
+
+/* Video Capture Controls */
+
+static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap);
+       unsigned i;
+
+       switch (ctrl->id) {
+       case VIVID_CID_TEST_PATTERN:
+               vivid_update_quality(dev);
+               tpg_s_pattern(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_COLORSPACE:
+               tpg_s_colorspace(&dev->tpg, ctrl->val);
+               vivid_send_source_change(dev, TV);
+               vivid_send_source_change(dev, SVID);
+               vivid_send_source_change(dev, HDMI);
+               vivid_send_source_change(dev, WEBCAM);
+               break;
+       case V4L2_CID_DV_RX_RGB_RANGE:
+               if (!vivid_is_hdmi_cap(dev))
+                       break;
+               tpg_s_rgb_range(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_LIMITED_RGB_RANGE:
+               tpg_s_real_rgb_range(&dev->tpg, ctrl->val ?
+                               V4L2_DV_RGB_RANGE_LIMITED : V4L2_DV_RGB_RANGE_FULL);
+               break;
+       case VIVID_CID_ALPHA_MODE:
+               tpg_s_alpha_mode(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_HOR_MOVEMENT:
+               tpg_s_mv_hor_mode(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_VERT_MOVEMENT:
+               tpg_s_mv_vert_mode(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_OSD_TEXT_MODE:
+               dev->osd_mode = ctrl->val;
+               break;
+       case VIVID_CID_PERCENTAGE_FILL:
+               tpg_s_perc_fill(&dev->tpg, ctrl->val);
+               for (i = 0; i < VIDEO_MAX_FRAME; i++)
+                       dev->must_blank[i] = ctrl->val < 100;
+               break;
+       case VIVID_CID_INSERT_SAV:
+               tpg_s_insert_sav(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_INSERT_EAV:
+               tpg_s_insert_eav(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_HFLIP:
+               dev->sensor_hflip = ctrl->val;
+               tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip);
+               break;
+       case VIVID_CID_VFLIP:
+               dev->sensor_vflip = ctrl->val;
+               tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip);
+               break;
+       case VIVID_CID_HAS_CROP_CAP:
+               dev->has_crop_cap = ctrl->val;
+               vivid_update_format_cap(dev, true);
+               break;
+       case VIVID_CID_HAS_COMPOSE_CAP:
+               dev->has_compose_cap = ctrl->val;
+               vivid_update_format_cap(dev, true);
+               break;
+       case VIVID_CID_HAS_SCALER_CAP:
+               dev->has_scaler_cap = ctrl->val;
+               vivid_update_format_cap(dev, true);
+               break;
+       case VIVID_CID_SHOW_BORDER:
+               tpg_s_show_border(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_SHOW_SQUARE:
+               tpg_s_show_square(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_STD_ASPECT_RATIO:
+               dev->std_aspect_ratio = ctrl->val;
+               tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
+               break;
+       case VIVID_CID_DV_TIMINGS_SIGNAL_MODE:
+               dev->dv_timings_signal_mode = dev->ctrl_dv_timings_signal_mode->val;
+               if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS)
+                       dev->query_dv_timings = dev->ctrl_dv_timings->val;
+               v4l2_ctrl_activate(dev->ctrl_dv_timings,
+                               dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS);
+               vivid_update_quality(dev);
+               vivid_send_source_change(dev, HDMI);
+               break;
+       case VIVID_CID_DV_TIMINGS_ASPECT_RATIO:
+               dev->dv_timings_aspect_ratio = ctrl->val;
+               tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
+               break;
+       case VIVID_CID_TSTAMP_SRC:
+               dev->tstamp_src_is_soe = ctrl->val;
+               dev->vb_vid_cap_q.timestamp_flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+               if (dev->tstamp_src_is_soe)
+                       dev->vb_vid_cap_q.timestamp_flags |= V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
+               break;
+       case VIVID_CID_MAX_EDID_BLOCKS:
+               dev->edid_max_blocks = ctrl->val;
+               if (dev->edid_blocks > dev->edid_max_blocks)
+                       dev->edid_blocks = dev->edid_max_blocks;
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_vid_cap_ctrl_ops = {
+       .s_ctrl = vivid_vid_cap_s_ctrl,
+};
+
+static const char * const vivid_ctrl_hor_movement_strings[] = {
+       "Move Left Fast",
+       "Move Left",
+       "Move Left Slow",
+       "No Movement",
+       "Move Right Slow",
+       "Move Right",
+       "Move Right Fast",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_hor_movement = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_HOR_MOVEMENT,
+       .name = "Horizontal Movement",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = TPG_MOVE_POS_FAST,
+       .def = TPG_MOVE_NONE,
+       .qmenu = vivid_ctrl_hor_movement_strings,
+};
+
+static const char * const vivid_ctrl_vert_movement_strings[] = {
+       "Move Up Fast",
+       "Move Up",
+       "Move Up Slow",
+       "No Movement",
+       "Move Down Slow",
+       "Move Down",
+       "Move Down Fast",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_vert_movement = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_VERT_MOVEMENT,
+       .name = "Vertical Movement",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = TPG_MOVE_POS_FAST,
+       .def = TPG_MOVE_NONE,
+       .qmenu = vivid_ctrl_vert_movement_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_show_border = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_SHOW_BORDER,
+       .name = "Show Border",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_show_square = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_SHOW_SQUARE,
+       .name = "Show Square",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const char * const vivid_ctrl_osd_mode_strings[] = {
+       "All",
+       "Counters Only",
+       "None",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_osd_mode = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_OSD_TEXT_MODE,
+       .name = "OSD Text Mode",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 2,
+       .qmenu = vivid_ctrl_osd_mode_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_perc_fill = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_PERCENTAGE_FILL,
+       .name = "Fill Percentage of Frame",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = 0,
+       .max = 100,
+       .def = 100,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_insert_sav = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_INSERT_SAV,
+       .name = "Insert SAV Code in Image",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_insert_eav = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_INSERT_EAV,
+       .name = "Insert EAV Code in Image",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_hflip = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_HFLIP,
+       .name = "Sensor Flipped Horizontally",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_vflip = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_VFLIP,
+       .name = "Sensor Flipped Vertically",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_crop_cap = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_HAS_CROP_CAP,
+       .name = "Enable Capture Cropping",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .def = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_compose_cap = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_HAS_COMPOSE_CAP,
+       .name = "Enable Capture Composing",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .def = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_cap = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_HAS_SCALER_CAP,
+       .name = "Enable Capture Scaler",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .def = 1,
+       .step = 1,
+};
+
+static const char * const vivid_ctrl_tstamp_src_strings[] = {
+       "End of Frame",
+       "Start of Exposure",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_tstamp_src = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_TSTAMP_SRC,
+       .name = "Timestamp Source",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 1,
+       .qmenu = vivid_ctrl_tstamp_src_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_std_aspect_ratio = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_STD_ASPECT_RATIO,
+       .name = "Standard Aspect Ratio",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .min = 1,
+       .max = 4,
+       .def = 1,
+       .qmenu = tpg_aspect_strings,
+};
+
+static const char * const vivid_ctrl_dv_timings_signal_mode_strings[] = {
+       "Current DV Timings",
+       "No Signal",
+       "No Lock",
+       "Out of Range",
+       "Selected DV Timings",
+       "Cycle Through All DV Timings",
+       "Custom DV Timings",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_signal_mode = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_DV_TIMINGS_SIGNAL_MODE,
+       .name = "DV Timings Signal Mode",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 5,
+       .qmenu = vivid_ctrl_dv_timings_signal_mode_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_aspect_ratio = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_DV_TIMINGS_ASPECT_RATIO,
+       .name = "DV Timings Aspect Ratio",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 3,
+       .qmenu = tpg_aspect_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_max_edid_blocks = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_MAX_EDID_BLOCKS,
+       .name = "Maximum EDID Blocks",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = 1,
+       .max = 256,
+       .def = 2,
+       .step = 1,
+};
+
+static const char * const vivid_ctrl_colorspace_strings[] = {
+       "",
+       "SMPTE 170M",
+       "SMPTE 240M",
+       "REC 709",
+       "", /* Skip Bt878 entry */
+       "470 System M",
+       "470 System BG",
+       "", /* Skip JPEG entry */
+       "sRGB",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_colorspace = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_COLORSPACE,
+       .name = "Colorspace",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .min = 1,
+       .max = 8,
+       .menu_skip_mask = (1 << 4) | (1 << 7),
+       .def = 8,
+       .qmenu = vivid_ctrl_colorspace_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_alpha_mode = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_ALPHA_MODE,
+       .name = "Apply Alpha To Red Only",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_limited_rgb_range = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_LIMITED_RGB_RANGE,
+       .name = "Limited RGB Range (16-235)",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+
+/* VBI Capture Control */
+
+static int vivid_vbi_cap_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vbi_cap);
+
+       switch (ctrl->id) {
+       case VIVID_CID_VBI_CAP_INTERLACED:
+               dev->vbi_cap_interlaced = ctrl->val;
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_vbi_cap_ctrl_ops = {
+       .s_ctrl = vivid_vbi_cap_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_vbi_cap_interlaced = {
+       .ops = &vivid_vbi_cap_ctrl_ops,
+       .id = VIVID_CID_VBI_CAP_INTERLACED,
+       .name = "Interlaced VBI Format",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+
+/* Video Output Controls */
+
+static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_out);
+       struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
+
+       switch (ctrl->id) {
+       case VIVID_CID_HAS_CROP_OUT:
+               dev->has_crop_out = ctrl->val;
+               vivid_update_format_out(dev);
+               break;
+       case VIVID_CID_HAS_COMPOSE_OUT:
+               dev->has_compose_out = ctrl->val;
+               vivid_update_format_out(dev);
+               break;
+       case VIVID_CID_HAS_SCALER_OUT:
+               dev->has_scaler_out = ctrl->val;
+               vivid_update_format_out(dev);
+               break;
+       case V4L2_CID_DV_TX_MODE:
+               dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D;
+               if (!vivid_is_hdmi_out(dev))
+                       break;
+               if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) {
+                       if (bt->width == 720 && bt->height <= 576)
+                               dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
+                       else
+                               dev->colorspace_out = V4L2_COLORSPACE_REC709;
+               } else {
+                       dev->colorspace_out = V4L2_COLORSPACE_SRGB;
+               }
+               if (dev->loop_video)
+                       vivid_send_source_change(dev, HDMI);
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_vid_out_ctrl_ops = {
+       .s_ctrl = vivid_vid_out_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_crop_out = {
+       .ops = &vivid_vid_out_ctrl_ops,
+       .id = VIVID_CID_HAS_CROP_OUT,
+       .name = "Enable Output Cropping",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .def = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_compose_out = {
+       .ops = &vivid_vid_out_ctrl_ops,
+       .id = VIVID_CID_HAS_COMPOSE_OUT,
+       .name = "Enable Output Composing",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .def = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = {
+       .ops = &vivid_vid_out_ctrl_ops,
+       .id = VIVID_CID_HAS_SCALER_OUT,
+       .name = "Enable Output Scaler",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .def = 1,
+       .step = 1,
+};
+
+
+/* Streaming Controls */
+
+static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_streaming);
+       struct timeval tv;
+
+       switch (ctrl->id) {
+       case VIVID_CID_DQBUF_ERROR:
+               dev->dqbuf_error = true;
+               break;
+       case VIVID_CID_PERC_DROPPED:
+               dev->perc_dropped_buffers = ctrl->val;
+               break;
+       case VIVID_CID_QUEUE_SETUP_ERROR:
+               dev->queue_setup_error = true;
+               break;
+       case VIVID_CID_BUF_PREPARE_ERROR:
+               dev->buf_prepare_error = true;
+               break;
+       case VIVID_CID_START_STR_ERROR:
+               dev->start_streaming_error = true;
+               break;
+       case VIVID_CID_QUEUE_ERROR:
+               if (dev->vb_vid_cap_q.start_streaming_called)
+                       vb2_queue_error(&dev->vb_vid_cap_q);
+               if (dev->vb_vbi_cap_q.start_streaming_called)
+                       vb2_queue_error(&dev->vb_vbi_cap_q);
+               if (dev->vb_vid_out_q.start_streaming_called)
+                       vb2_queue_error(&dev->vb_vid_out_q);
+               if (dev->vb_vbi_out_q.start_streaming_called)
+                       vb2_queue_error(&dev->vb_vbi_out_q);
+               if (dev->vb_sdr_cap_q.start_streaming_called)
+                       vb2_queue_error(&dev->vb_sdr_cap_q);
+               break;
+       case VIVID_CID_SEQ_WRAP:
+               dev->seq_wrap = ctrl->val;
+               break;
+       case VIVID_CID_TIME_WRAP:
+               dev->time_wrap = ctrl->val;
+               if (ctrl->val == 0) {
+                       dev->time_wrap_offset = 0;
+                       break;
+               }
+               v4l2_get_timestamp(&tv);
+               dev->time_wrap_offset = -tv.tv_sec - 16;
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_streaming_ctrl_ops = {
+       .s_ctrl = vivid_streaming_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_dqbuf_error = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_DQBUF_ERROR,
+       .name = "Inject V4L2_BUF_FLAG_ERROR",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_perc_dropped = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_PERC_DROPPED,
+       .name = "Percentage of Dropped Buffers",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = 0,
+       .max = 100,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_queue_setup_error = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_QUEUE_SETUP_ERROR,
+       .name = "Inject VIDIOC_REQBUFS Error",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_buf_prepare_error = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_BUF_PREPARE_ERROR,
+       .name = "Inject VIDIOC_QBUF Error",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_start_streaming_error = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_START_STR_ERROR,
+       .name = "Inject VIDIOC_STREAMON Error",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_queue_error = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_QUEUE_ERROR,
+       .name = "Inject Fatal Streaming Error",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_seq_wrap = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_SEQ_WRAP,
+       .name = "Wrap Sequence Number",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_time_wrap = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_TIME_WRAP,
+       .name = "Wrap Timestamp",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+
+/* SDTV Capture Controls */
+
+static int vivid_sdtv_cap_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_sdtv_cap);
+
+       switch (ctrl->id) {
+       case VIVID_CID_STD_SIGNAL_MODE:
+               dev->std_signal_mode = dev->ctrl_std_signal_mode->val;
+               if (dev->std_signal_mode == SELECTED_STD)
+                       dev->query_std = vivid_standard[dev->ctrl_standard->val];
+               v4l2_ctrl_activate(dev->ctrl_standard, dev->std_signal_mode == SELECTED_STD);
+               vivid_update_quality(dev);
+               vivid_send_source_change(dev, TV);
+               vivid_send_source_change(dev, SVID);
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_sdtv_cap_ctrl_ops = {
+       .s_ctrl = vivid_sdtv_cap_s_ctrl,
+};
+
+static const char * const vivid_ctrl_std_signal_mode_strings[] = {
+       "Current Standard",
+       "No Signal",
+       "No Lock",
+       "",
+       "Selected Standard",
+       "Cycle Through All Standards",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_std_signal_mode = {
+       .ops = &vivid_sdtv_cap_ctrl_ops,
+       .id = VIVID_CID_STD_SIGNAL_MODE,
+       .name = "Standard Signal Mode",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 5,
+       .menu_skip_mask = 1 << 3,
+       .qmenu = vivid_ctrl_std_signal_mode_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_standard = {
+       .ops = &vivid_sdtv_cap_ctrl_ops,
+       .id = VIVID_CID_STANDARD,
+       .name = "Standard",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 14,
+       .qmenu = vivid_ctrl_standard_strings,
+};
+
+
+
+/* Radio Receiver Controls */
+
+static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_rx);
+
+       switch (ctrl->id) {
+       case VIVID_CID_RADIO_SEEK_MODE:
+               dev->radio_rx_hw_seek_mode = ctrl->val;
+               break;
+       case VIVID_CID_RADIO_SEEK_PROG_LIM:
+               dev->radio_rx_hw_seek_prog_lim = ctrl->val;
+               break;
+       case VIVID_CID_RADIO_RX_RDS_RBDS:
+               dev->rds_gen.use_rbds = ctrl->val;
+               break;
+       case VIVID_CID_RADIO_RX_RDS_BLOCKIO:
+               dev->radio_rx_rds_controls = ctrl->val;
+               dev->radio_rx_caps &= ~V4L2_CAP_READWRITE;
+               dev->radio_rx_rds_use_alternates = false;
+               if (!dev->radio_rx_rds_controls) {
+                       dev->radio_rx_caps |= V4L2_CAP_READWRITE;
+                       __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, 0);
+                       __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, 0);
+                       __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, 0);
+                       __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, 0);
+                       __v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, "");
+                       __v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, "");
+               }
+               v4l2_ctrl_activate(dev->radio_rx_rds_pty, dev->radio_rx_rds_controls);
+               v4l2_ctrl_activate(dev->radio_rx_rds_psname, dev->radio_rx_rds_controls);
+               v4l2_ctrl_activate(dev->radio_rx_rds_radiotext, dev->radio_rx_rds_controls);
+               v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls);
+               v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls);
+               v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls);
+               break;
+       case V4L2_CID_RDS_RECEPTION:
+               dev->radio_rx_rds_enabled = ctrl->val;
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_radio_rx_ctrl_ops = {
+       .s_ctrl = vivid_radio_rx_s_ctrl,
+};
+
+static const char * const vivid_ctrl_radio_rds_mode_strings[] = {
+       "Block I/O",
+       "Controls",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_blockio = {
+       .ops = &vivid_radio_rx_ctrl_ops,
+       .id = VIVID_CID_RADIO_RX_RDS_BLOCKIO,
+       .name = "RDS Rx I/O Mode",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .qmenu = vivid_ctrl_radio_rds_mode_strings,
+       .max = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_rbds = {
+       .ops = &vivid_radio_rx_ctrl_ops,
+       .id = VIVID_CID_RADIO_RX_RDS_RBDS,
+       .name = "Generate RBDS Instead of RDS",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const char * const vivid_ctrl_radio_hw_seek_mode_strings[] = {
+       "Bounded",
+       "Wrap Around",
+       "Both",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_mode = {
+       .ops = &vivid_radio_rx_ctrl_ops,
+       .id = VIVID_CID_RADIO_SEEK_MODE,
+       .name = "Radio HW Seek Mode",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 2,
+       .qmenu = vivid_ctrl_radio_hw_seek_mode_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_prog_lim = {
+       .ops = &vivid_radio_rx_ctrl_ops,
+       .id = VIVID_CID_RADIO_SEEK_PROG_LIM,
+       .name = "Radio Programmable HW Seek",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+
+/* Radio Transmitter Controls */
+
+static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_tx);
+
+       switch (ctrl->id) {
+       case VIVID_CID_RADIO_TX_RDS_BLOCKIO:
+               dev->radio_tx_rds_controls = ctrl->val;
+               dev->radio_tx_caps &= ~V4L2_CAP_READWRITE;
+               if (!dev->radio_tx_rds_controls)
+                       dev->radio_tx_caps |= V4L2_CAP_READWRITE;
+               break;
+       case V4L2_CID_RDS_TX_PTY:
+               if (dev->radio_rx_rds_controls)
+                       v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, ctrl->val);
+               break;
+       case V4L2_CID_RDS_TX_PS_NAME:
+               if (dev->radio_rx_rds_controls)
+                       v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, ctrl->p_new.p_char);
+               break;
+       case V4L2_CID_RDS_TX_RADIO_TEXT:
+               if (dev->radio_rx_rds_controls)
+                       v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, ctrl->p_new.p_char);
+               break;
+       case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
+               if (dev->radio_rx_rds_controls)
+                       v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, ctrl->val);
+               break;
+       case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
+               if (dev->radio_rx_rds_controls)
+                       v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, ctrl->val);
+               break;
+       case V4L2_CID_RDS_TX_MUSIC_SPEECH:
+               if (dev->radio_rx_rds_controls)
+                       v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, ctrl->val);
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_radio_tx_ctrl_ops = {
+       .s_ctrl = vivid_radio_tx_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_tx_rds_blockio = {
+       .ops = &vivid_radio_tx_ctrl_ops,
+       .id = VIVID_CID_RADIO_TX_RDS_BLOCKIO,
+       .name = "RDS Tx I/O Mode",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .qmenu = vivid_ctrl_radio_rds_mode_strings,
+       .max = 1,
+       .def = 1,
+};
+
+
+
+/* Video Loop Control */
+
+static int vivid_loop_out_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_loop_out);
+
+       switch (ctrl->id) {
+       case VIVID_CID_LOOP_VIDEO:
+               dev->loop_video = ctrl->val;
+               vivid_update_quality(dev);
+               vivid_send_source_change(dev, SVID);
+               vivid_send_source_change(dev, HDMI);
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_loop_out_ctrl_ops = {
+       .s_ctrl = vivid_loop_out_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_loop_video = {
+       .ops = &vivid_loop_out_ctrl_ops,
+       .id = VIVID_CID_LOOP_VIDEO,
+       .name = "Loop Video",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+
+static const struct v4l2_ctrl_config vivid_ctrl_class = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY,
+       .id = VIVID_CID_VIVID_CLASS,
+       .name = "Vivid Controls",
+       .type = V4L2_CTRL_TYPE_CTRL_CLASS,
+};
+
+int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
+               bool show_ccs_out, bool no_error_inj,
+               bool has_sdtv, bool has_hdmi)
+{
+       struct v4l2_ctrl_handler *hdl_user_gen = &dev->ctrl_hdl_user_gen;
+       struct v4l2_ctrl_handler *hdl_user_vid = &dev->ctrl_hdl_user_vid;
+       struct v4l2_ctrl_handler *hdl_user_aud = &dev->ctrl_hdl_user_aud;
+       struct v4l2_ctrl_handler *hdl_streaming = &dev->ctrl_hdl_streaming;
+       struct v4l2_ctrl_handler *hdl_sdtv_cap = &dev->ctrl_hdl_sdtv_cap;
+       struct v4l2_ctrl_handler *hdl_loop_out = &dev->ctrl_hdl_loop_out;
+       struct v4l2_ctrl_handler *hdl_vid_cap = &dev->ctrl_hdl_vid_cap;
+       struct v4l2_ctrl_handler *hdl_vid_out = &dev->ctrl_hdl_vid_out;
+       struct v4l2_ctrl_handler *hdl_vbi_cap = &dev->ctrl_hdl_vbi_cap;
+       struct v4l2_ctrl_handler *hdl_vbi_out = &dev->ctrl_hdl_vbi_out;
+       struct v4l2_ctrl_handler *hdl_radio_rx = &dev->ctrl_hdl_radio_rx;
+       struct v4l2_ctrl_handler *hdl_radio_tx = &dev->ctrl_hdl_radio_tx;
+       struct v4l2_ctrl_handler *hdl_sdr_cap = &dev->ctrl_hdl_sdr_cap;
+       struct v4l2_ctrl_config vivid_ctrl_dv_timings = {
+               .ops = &vivid_vid_cap_ctrl_ops,
+               .id = VIVID_CID_DV_TIMINGS,
+               .name = "DV Timings",
+               .type = V4L2_CTRL_TYPE_MENU,
+       };
+       int i;
+
+       v4l2_ctrl_handler_init(hdl_user_gen, 10);
+       v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_user_vid, 9);
+       v4l2_ctrl_new_custom(hdl_user_vid, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_user_aud, 2);
+       v4l2_ctrl_new_custom(hdl_user_aud, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_streaming, 8);
+       v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_sdtv_cap, 2);
+       v4l2_ctrl_new_custom(hdl_sdtv_cap, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_loop_out, 1);
+       v4l2_ctrl_new_custom(hdl_loop_out, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_vid_cap, 55);
+       v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_vid_out, 26);
+       v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_vbi_cap, 21);
+       v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_vbi_out, 19);
+       v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_radio_rx, 17);
+       v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_radio_tx, 17);
+       v4l2_ctrl_new_custom(hdl_radio_tx, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_sdr_cap, 18);
+       v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_class, NULL);
+
+       /* User Controls */
+       dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL,
+               V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
+       dev->mute = v4l2_ctrl_new_std(hdl_user_aud, NULL,
+               V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+       if (dev->has_vid_cap) {
+               dev->brightness = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+               for (i = 0; i < MAX_INPUTS; i++)
+                       dev->input_brightness[i] = 128;
+               dev->contrast = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_CONTRAST, 0, 255, 1, 128);
+               dev->saturation = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_SATURATION, 0, 255, 1, 128);
+               dev->hue = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_HUE, -128, 128, 1, 0);
+               v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_HFLIP, 0, 1, 1, 0);
+               v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+               dev->autogain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+               dev->gain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_GAIN, 0, 255, 1, 100);
+               dev->alpha = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
+       }
+       dev->button = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_button, NULL);
+       dev->int32 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int32, NULL);
+       dev->int64 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int64, NULL);
+       dev->boolean = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_boolean, NULL);
+       dev->menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_menu, NULL);
+       dev->string = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_string, NULL);
+       dev->bitmask = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_bitmask, NULL);
+       dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL);
+
+       if (dev->has_vid_cap) {
+               /* Image Processing Controls */
+               struct v4l2_ctrl_config vivid_ctrl_test_pattern = {
+                       .ops = &vivid_vid_cap_ctrl_ops,
+                       .id = VIVID_CID_TEST_PATTERN,
+                       .name = "Test Pattern",
+                       .type = V4L2_CTRL_TYPE_MENU,
+                       .max = TPG_PAT_NOISE,
+                       .qmenu = tpg_pattern_strings,
+               };
+
+               dev->test_pattern = v4l2_ctrl_new_custom(hdl_vid_cap,
+                               &vivid_ctrl_test_pattern, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_perc_fill, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hor_movement, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vert_movement, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_osd_mode, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_border, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_square, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hflip, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vflip, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_sav, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_eav, NULL);
+               if (show_ccs_cap) {
+                       dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
+                               &vivid_ctrl_has_crop_cap, NULL);
+                       dev->ctrl_has_compose_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
+                               &vivid_ctrl_has_compose_cap, NULL);
+                       dev->ctrl_has_scaler_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
+                               &vivid_ctrl_has_scaler_cap, NULL);
+               }
+
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_tstamp_src, NULL);
+               dev->colorspace = v4l2_ctrl_new_custom(hdl_vid_cap,
+                       &vivid_ctrl_colorspace, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL);
+       }
+
+       if (dev->has_vid_out && show_ccs_out) {
+               dev->ctrl_has_crop_out = v4l2_ctrl_new_custom(hdl_vid_out,
+                       &vivid_ctrl_has_crop_out, NULL);
+               dev->ctrl_has_compose_out = v4l2_ctrl_new_custom(hdl_vid_out,
+                       &vivid_ctrl_has_compose_out, NULL);
+               dev->ctrl_has_scaler_out = v4l2_ctrl_new_custom(hdl_vid_out,
+                       &vivid_ctrl_has_scaler_out, NULL);
+       }
+
+       /*
+        * Testing this driver with v4l2-compliance will trigger the error
+        * injection controls, and after that nothing will work as expected.
+        * So we have a module option to drop these error injecting controls
+        * allowing us to run v4l2_compliance again.
+        */
+       if (!no_error_inj) {
+               v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_disconnect, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_dqbuf_error, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_perc_dropped, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_setup_error, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_buf_prepare_error, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_start_streaming_error, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_error, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_seq_wrap, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_time_wrap, NULL);
+       }
+
+       if (has_sdtv && (dev->has_vid_cap || dev->has_vbi_cap)) {
+               if (dev->has_vid_cap)
+                       v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_std_aspect_ratio, NULL);
+               dev->ctrl_std_signal_mode = v4l2_ctrl_new_custom(hdl_sdtv_cap,
+                       &vivid_ctrl_std_signal_mode, NULL);
+               dev->ctrl_standard = v4l2_ctrl_new_custom(hdl_sdtv_cap,
+                       &vivid_ctrl_standard, NULL);
+               if (dev->ctrl_std_signal_mode)
+                       v4l2_ctrl_cluster(2, &dev->ctrl_std_signal_mode);
+               if (dev->has_raw_vbi_cap)
+                       v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_vbi_cap_interlaced, NULL);
+       }
+
+       if (has_hdmi && dev->has_vid_cap) {
+               dev->ctrl_dv_timings_signal_mode = v4l2_ctrl_new_custom(hdl_vid_cap,
+                                       &vivid_ctrl_dv_timings_signal_mode, NULL);
+
+               vivid_ctrl_dv_timings.max = dev->query_dv_timings_size - 1;
+               vivid_ctrl_dv_timings.qmenu =
+                       (const char * const *)dev->query_dv_timings_qmenu;
+               dev->ctrl_dv_timings = v4l2_ctrl_new_custom(hdl_vid_cap,
+                       &vivid_ctrl_dv_timings, NULL);
+               if (dev->ctrl_dv_timings_signal_mode)
+                       v4l2_ctrl_cluster(2, &dev->ctrl_dv_timings_signal_mode);
+
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_dv_timings_aspect_ratio, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_max_edid_blocks, NULL);
+               dev->real_rgb_range_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
+                       &vivid_ctrl_limited_rgb_range, NULL);
+               dev->rgb_range_cap = v4l2_ctrl_new_std_menu(hdl_vid_cap,
+                       &vivid_vid_cap_ctrl_ops,
+                       V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
+                       0, V4L2_DV_RGB_RANGE_AUTO);
+       }
+       if (has_hdmi && dev->has_vid_out) {
+               /*
+                * We aren't doing anything with this at the moment, but
+                * HDMI outputs typically have this controls.
+                */
+               dev->ctrl_tx_rgb_range = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL,
+                       V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
+                       0, V4L2_DV_RGB_RANGE_AUTO);
+               dev->ctrl_tx_mode = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL,
+                       V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI,
+                       0, V4L2_DV_TX_MODE_HDMI);
+       }
+       if ((dev->has_vid_cap && dev->has_vid_out) ||
+           (dev->has_vbi_cap && dev->has_vbi_out))
+               v4l2_ctrl_new_custom(hdl_loop_out, &vivid_ctrl_loop_video, NULL);
+
+       if (dev->has_fb)
+               v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_clear_fb, NULL);
+
+       if (dev->has_radio_rx) {
+               v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_mode, NULL);
+               v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_prog_lim, NULL);
+               v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_blockio, NULL);
+               v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_rbds, NULL);
+               v4l2_ctrl_new_std(hdl_radio_rx, &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RECEPTION, 0, 1, 1, 1);
+               dev->radio_rx_rds_pty = v4l2_ctrl_new_std(hdl_radio_rx,
+                       &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RX_PTY, 0, 31, 1, 0);
+               dev->radio_rx_rds_psname = v4l2_ctrl_new_std(hdl_radio_rx,
+                       &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RX_PS_NAME, 0, 8, 8, 0);
+               dev->radio_rx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_rx,
+                       &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RX_RADIO_TEXT, 0, 64, 64, 0);
+               dev->radio_rx_rds_ta = v4l2_ctrl_new_std(hdl_radio_rx,
+                       &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
+               dev->radio_rx_rds_tp = v4l2_ctrl_new_std(hdl_radio_rx,
+                       &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, 0, 1, 1, 0);
+               dev->radio_rx_rds_ms = v4l2_ctrl_new_std(hdl_radio_rx,
+                       &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RX_MUSIC_SPEECH, 0, 1, 1, 1);
+       }
+       if (dev->has_radio_tx) {
+               v4l2_ctrl_new_custom(hdl_radio_tx,
+                       &vivid_ctrl_radio_tx_rds_blockio, NULL);
+               dev->radio_tx_rds_pi = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_PI, 0, 0xffff, 1, 0x8088);
+               dev->radio_tx_rds_pty = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_PTY, 0, 31, 1, 3);
+               dev->radio_tx_rds_psname = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_PS_NAME, 0, 8, 8, 0);
+               if (dev->radio_tx_rds_psname)
+                       v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_psname, "VIVID-TX");
+               dev->radio_tx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_RADIO_TEXT, 0, 64 * 2, 64, 0);
+               if (dev->radio_tx_rds_radiotext)
+                       v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_radiotext,
+                              "This is a VIVID default Radio Text template text, change at will");
+               dev->radio_tx_rds_mono_stereo = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_MONO_STEREO, 0, 1, 1, 1);
+               dev->radio_tx_rds_art_head = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_ARTIFICIAL_HEAD, 0, 1, 1, 0);
+               dev->radio_tx_rds_compressed = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_COMPRESSED, 0, 1, 1, 0);
+               dev->radio_tx_rds_dyn_pty = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_DYNAMIC_PTY, 0, 1, 1, 0);
+               dev->radio_tx_rds_ta = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
+               dev->radio_tx_rds_tp = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_TRAFFIC_PROGRAM, 0, 1, 1, 1);
+               dev->radio_tx_rds_ms = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_MUSIC_SPEECH, 0, 1, 1, 1);
+       }
+       if (hdl_user_gen->error)
+               return hdl_user_gen->error;
+       if (hdl_user_vid->error)
+               return hdl_user_vid->error;
+       if (hdl_user_aud->error)
+               return hdl_user_aud->error;
+       if (hdl_streaming->error)
+               return hdl_streaming->error;
+       if (hdl_sdr_cap->error)
+               return hdl_sdr_cap->error;
+       if (hdl_loop_out->error)
+               return hdl_loop_out->error;
+
+       if (dev->autogain)
+               v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
+
+       if (dev->has_vid_cap) {
+               v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_vid, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_aud, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_cap, hdl_streaming, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_cap, hdl_sdtv_cap, NULL);
+               if (hdl_vid_cap->error)
+                       return hdl_vid_cap->error;
+               dev->vid_cap_dev.ctrl_handler = hdl_vid_cap;
+       }
+       if (dev->has_vid_out) {
+               v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_aud, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_out, hdl_streaming, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_out, hdl_loop_out, NULL);
+               if (hdl_vid_out->error)
+                       return hdl_vid_out->error;
+               dev->vid_out_dev.ctrl_handler = hdl_vid_out;
+       }
+       if (dev->has_vbi_cap) {
+               v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_streaming, NULL);
+               v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_sdtv_cap, NULL);
+               if (hdl_vbi_cap->error)
+                       return hdl_vbi_cap->error;
+               dev->vbi_cap_dev.ctrl_handler = hdl_vbi_cap;
+       }
+       if (dev->has_vbi_out) {
+               v4l2_ctrl_add_handler(hdl_vbi_out, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_vbi_out, hdl_streaming, NULL);
+               v4l2_ctrl_add_handler(hdl_vbi_out, hdl_loop_out, NULL);
+               if (hdl_vbi_out->error)
+                       return hdl_vbi_out->error;
+               dev->vbi_out_dev.ctrl_handler = hdl_vbi_out;
+       }
+       if (dev->has_radio_rx) {
+               v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_aud, NULL);
+               if (hdl_radio_rx->error)
+                       return hdl_radio_rx->error;
+               dev->radio_rx_dev.ctrl_handler = hdl_radio_rx;
+       }
+       if (dev->has_radio_tx) {
+               v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_aud, NULL);
+               if (hdl_radio_tx->error)
+                       return hdl_radio_tx->error;
+               dev->radio_tx_dev.ctrl_handler = hdl_radio_tx;
+       }
+       if (dev->has_sdr_cap) {
+               v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_streaming, NULL);
+               if (hdl_sdr_cap->error)
+                       return hdl_sdr_cap->error;
+               dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap;
+       }
+       return 0;
+}
+
+void vivid_free_controls(struct vivid_dev *dev)
+{
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_cap);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_out);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_cap);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_out);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_rx);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_tx);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdr_cap);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_gen);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_vid);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_aud);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_streaming);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_out);
+}
diff --git a/drivers/media/platform/vivid/vivid-ctrls.h b/drivers/media/platform/vivid/vivid-ctrls.h
new file mode 100644 (file)
index 0000000..9bcca9d
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * vivid-ctrls.h - control support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_CTRLS_H_
+#define _VIVID_CTRLS_H_
+
+enum vivid_hw_seek_modes {
+       VIVID_HW_SEEK_BOUNDED,
+       VIVID_HW_SEEK_WRAP,
+       VIVID_HW_SEEK_BOTH,
+};
+
+int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
+               bool show_ccs_out, bool no_error_inj,
+               bool has_sdtv, bool has_hdmi);
+void vivid_free_controls(struct vivid_dev *dev);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
new file mode 100644 (file)
index 0000000..39a67cf
--- /dev/null
@@ -0,0 +1,886 @@
+/*
+ * vivid-kthread-cap.h - video/vbi capture thread support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/random.h>
+#include <linux/v4l2-dv-timings.h>
+#include <asm/div64.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-vid-cap.h"
+#include "vivid-vid-out.h"
+#include "vivid-radio-common.h"
+#include "vivid-radio-rx.h"
+#include "vivid-radio-tx.h"
+#include "vivid-sdr-cap.h"
+#include "vivid-vbi-cap.h"
+#include "vivid-vbi-out.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.h"
+#include "vivid-kthread-cap.h"
+
+static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev)
+{
+       if (vivid_is_sdtv_cap(dev))
+               return dev->std_cap;
+       return 0;
+}
+
+static void copy_pix(struct vivid_dev *dev, int win_y, int win_x,
+                       u16 *cap, const u16 *osd)
+{
+       u16 out;
+       int left = dev->overlay_out_left;
+       int top = dev->overlay_out_top;
+       int fb_x = win_x + left;
+       int fb_y = win_y + top;
+       int i;
+
+       out = *cap;
+       *cap = *osd;
+       if (dev->bitmap_out) {
+               const u8 *p = dev->bitmap_out;
+               unsigned stride = (dev->compose_out.width + 7) / 8;
+
+               win_x -= dev->compose_out.left;
+               win_y -= dev->compose_out.top;
+               if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7))))
+                       return;
+       }
+
+       for (i = 0; i < dev->clipcount_out; i++) {
+               struct v4l2_rect *r = &dev->clips_out[i].c;
+
+               if (fb_y >= r->top && fb_y < r->top + r->height &&
+                   fb_x >= r->left && fb_x < r->left + r->width)
+                       return;
+       }
+       if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
+           *osd != dev->chromakey_out)
+               return;
+       if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) &&
+           out == dev->chromakey_out)
+               return;
+       if (dev->fmt_cap->alpha_mask) {
+               if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) &&
+                   dev->global_alpha_out)
+                       return;
+               if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) &&
+                   *cap & dev->fmt_cap->alpha_mask)
+                       return;
+               if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA) &&
+                   !(*cap & dev->fmt_cap->alpha_mask))
+                       return;
+       }
+       *cap = out;
+}
+
+static void blend_line(struct vivid_dev *dev, unsigned y_offset, unsigned x_offset,
+               u8 *vcapbuf, const u8 *vosdbuf,
+               unsigned width, unsigned pixsize)
+{
+       unsigned x;
+
+       for (x = 0; x < width; x++, vcapbuf += pixsize, vosdbuf += pixsize) {
+               copy_pix(dev, y_offset, x_offset + x,
+                        (u16 *)vcapbuf, (const u16 *)vosdbuf);
+       }
+}
+
+static void scale_line(const u8 *src, u8 *dst, unsigned srcw, unsigned dstw, unsigned twopixsize)
+{
+       /* Coarse scaling with Bresenham */
+       unsigned int_part;
+       unsigned fract_part;
+       unsigned src_x = 0;
+       unsigned error = 0;
+       unsigned x;
+
+       /*
+        * We always combine two pixels to prevent color bleed in the packed
+        * yuv case.
+        */
+       srcw /= 2;
+       dstw /= 2;
+       int_part = srcw / dstw;
+       fract_part = srcw % dstw;
+       for (x = 0; x < dstw; x++, dst += twopixsize) {
+               memcpy(dst, src + src_x * twopixsize, twopixsize);
+               src_x += int_part;
+               error += fract_part;
+               if (error >= dstw) {
+                       error -= dstw;
+                       src_x++;
+               }
+       }
+}
+
+/*
+ * Precalculate the rectangles needed to perform video looping:
+ *
+ * The nominal pipeline is that the video output buffer is cropped by
+ * crop_out, scaled to compose_out, overlaid with the output overlay,
+ * cropped on the capture side by crop_cap and scaled again to the video
+ * capture buffer using compose_cap.
+ *
+ * To keep things efficient we calculate the intersection of compose_out
+ * and crop_cap (since that's the only part of the video that will
+ * actually end up in the capture buffer), determine which part of the
+ * video output buffer that is and which part of the video capture buffer
+ * so we can scale the video straight from the output buffer to the capture
+ * buffer without any intermediate steps.
+ *
+ * If we need to deal with an output overlay, then there is no choice and
+ * that intermediate step still has to be taken. For the output overlay
+ * support we calculate the intersection of the framebuffer and the overlay
+ * window (which may be partially or wholly outside of the framebuffer
+ * itself) and the intersection of that with loop_vid_copy (i.e. the part of
+ * the actual looped video that will be overlaid). The result is calculated
+ * both in framebuffer coordinates (loop_fb_copy) and compose_out coordinates
+ * (loop_vid_overlay). Finally calculate the part of the capture buffer that
+ * will receive that overlaid video.
+ */
+static void vivid_precalc_copy_rects(struct vivid_dev *dev)
+{
+       /* Framebuffer rectangle */
+       struct v4l2_rect r_fb = {
+               0, 0, dev->display_width, dev->display_height
+       };
+       /* Overlay window rectangle in framebuffer coordinates */
+       struct v4l2_rect r_overlay = {
+               dev->overlay_out_left, dev->overlay_out_top,
+               dev->compose_out.width, dev->compose_out.height
+       };
+
+       dev->loop_vid_copy = rect_intersect(&dev->crop_cap, &dev->compose_out);
+
+       dev->loop_vid_out = dev->loop_vid_copy;
+       rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out);
+       dev->loop_vid_out.left += dev->crop_out.left;
+       dev->loop_vid_out.top += dev->crop_out.top;
+
+       dev->loop_vid_cap = dev->loop_vid_copy;
+       rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap);
+
+       dprintk(dev, 1,
+               "loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n",
+               dev->loop_vid_copy.width, dev->loop_vid_copy.height,
+               dev->loop_vid_copy.left, dev->loop_vid_copy.top,
+               dev->loop_vid_out.width, dev->loop_vid_out.height,
+               dev->loop_vid_out.left, dev->loop_vid_out.top,
+               dev->loop_vid_cap.width, dev->loop_vid_cap.height,
+               dev->loop_vid_cap.left, dev->loop_vid_cap.top);
+
+       r_overlay = rect_intersect(&r_fb, &r_overlay);
+
+       /* shift r_overlay to the same origin as compose_out */
+       r_overlay.left += dev->compose_out.left - dev->overlay_out_left;
+       r_overlay.top += dev->compose_out.top - dev->overlay_out_top;
+
+       dev->loop_vid_overlay = rect_intersect(&r_overlay, &dev->loop_vid_copy);
+       dev->loop_fb_copy = dev->loop_vid_overlay;
+
+       /* shift dev->loop_fb_copy back again to the fb origin */
+       dev->loop_fb_copy.left -= dev->compose_out.left - dev->overlay_out_left;
+       dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top;
+
+       dev->loop_vid_overlay_cap = dev->loop_vid_overlay;
+       rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap);
+
+       dprintk(dev, 1,
+               "loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n",
+               dev->loop_fb_copy.width, dev->loop_fb_copy.height,
+               dev->loop_fb_copy.left, dev->loop_fb_copy.top,
+               dev->loop_vid_overlay.width, dev->loop_vid_overlay.height,
+               dev->loop_vid_overlay.left, dev->loop_vid_overlay.top,
+               dev->loop_vid_overlay_cap.width, dev->loop_vid_overlay_cap.height,
+               dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top);
+}
+
+static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
+               struct vivid_buffer *vid_cap_buf)
+{
+       bool blank = dev->must_blank[vid_cap_buf->vb.v4l2_buf.index];
+       struct tpg_data *tpg = &dev->tpg;
+       struct vivid_buffer *vid_out_buf = NULL;
+       unsigned pixsize = tpg_g_twopixelsize(tpg, p) / 2;
+       unsigned img_width = dev->compose_cap.width;
+       unsigned img_height = dev->compose_cap.height;
+       unsigned stride_cap = tpg->bytesperline[p];
+       unsigned stride_out = dev->bytesperline_out[p];
+       unsigned stride_osd = dev->display_byte_stride;
+       unsigned hmax = (img_height * tpg->perc_fill) / 100;
+       u8 *voutbuf;
+       u8 *vosdbuf = NULL;
+       unsigned y;
+       bool blend = dev->bitmap_out || dev->clipcount_out || dev->fbuf_out_flags;
+       /* Coarse scaling with Bresenham */
+       unsigned vid_out_int_part;
+       unsigned vid_out_fract_part;
+       unsigned vid_out_y = 0;
+       unsigned vid_out_error = 0;
+       unsigned vid_overlay_int_part = 0;
+       unsigned vid_overlay_fract_part = 0;
+       unsigned vid_overlay_y = 0;
+       unsigned vid_overlay_error = 0;
+       unsigned vid_cap_right;
+       bool quick;
+
+       vid_out_int_part = dev->loop_vid_out.height / dev->loop_vid_cap.height;
+       vid_out_fract_part = dev->loop_vid_out.height % dev->loop_vid_cap.height;
+
+       if (!list_empty(&dev->vid_out_active))
+               vid_out_buf = list_entry(dev->vid_out_active.next,
+                                        struct vivid_buffer, list);
+       if (vid_out_buf == NULL)
+               return -ENODATA;
+
+       vid_cap_buf->vb.v4l2_buf.field = vid_out_buf->vb.v4l2_buf.field;
+
+       voutbuf = vb2_plane_vaddr(&vid_out_buf->vb, p) +
+                                 vid_out_buf->vb.v4l2_planes[p].data_offset;
+       voutbuf += dev->loop_vid_out.left * pixsize + dev->loop_vid_out.top * stride_out;
+       vcapbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride_cap;
+
+       if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) {
+               /*
+                * If there is nothing to copy, then just fill the capture window
+                * with black.
+                */
+               for (y = 0; y < hmax; y++, vcapbuf += stride_cap)
+                       memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize);
+               return 0;
+       }
+
+       if (dev->overlay_out_enabled &&
+           dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) {
+               vosdbuf = dev->video_vbase;
+               vosdbuf += dev->loop_fb_copy.left * pixsize +
+                          dev->loop_fb_copy.top * stride_osd;
+               vid_overlay_int_part = dev->loop_vid_overlay.height /
+                                      dev->loop_vid_overlay_cap.height;
+               vid_overlay_fract_part = dev->loop_vid_overlay.height %
+                                        dev->loop_vid_overlay_cap.height;
+       }
+
+       vid_cap_right = dev->loop_vid_cap.left + dev->loop_vid_cap.width;
+       /* quick is true if no video scaling is needed */
+       quick = dev->loop_vid_out.width == dev->loop_vid_cap.width;
+
+       dev->cur_scaled_line = dev->loop_vid_out.height;
+       for (y = 0; y < hmax; y++, vcapbuf += stride_cap) {
+               /* osdline is true if this line requires overlay blending */
+               bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top &&
+                         y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height;
+
+               /*
+                * If this line of the capture buffer doesn't get any video, then
+                * just fill with black.
+                */
+               if (y < dev->loop_vid_cap.top ||
+                   y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) {
+                       memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize);
+                       continue;
+               }
+
+               /* fill the left border with black */
+               if (dev->loop_vid_cap.left)
+                       memcpy(vcapbuf, tpg->black_line[p], dev->loop_vid_cap.left * pixsize);
+
+               /* fill the right border with black */
+               if (vid_cap_right < img_width)
+                       memcpy(vcapbuf + vid_cap_right * pixsize,
+                               tpg->black_line[p], (img_width - vid_cap_right) * pixsize);
+
+               if (quick && !osdline) {
+                       memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
+                              voutbuf + vid_out_y * stride_out,
+                              dev->loop_vid_cap.width * pixsize);
+                       goto update_vid_out_y;
+               }
+               if (dev->cur_scaled_line == vid_out_y) {
+                       memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
+                              dev->scaled_line,
+                              dev->loop_vid_cap.width * pixsize);
+                       goto update_vid_out_y;
+               }
+               if (!osdline) {
+                       scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line,
+                               dev->loop_vid_out.width, dev->loop_vid_cap.width,
+                               tpg_g_twopixelsize(tpg, p));
+               } else {
+                       /*
+                        * Offset in bytes within loop_vid_copy to the start of the
+                        * loop_vid_overlay rectangle.
+                        */
+                       unsigned offset =
+                               (dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * pixsize;
+                       u8 *osd = vosdbuf + vid_overlay_y * stride_osd;
+
+                       scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line,
+                               dev->loop_vid_out.width, dev->loop_vid_copy.width,
+                               tpg_g_twopixelsize(tpg, p));
+                       if (blend)
+                               blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top,
+                                          dev->loop_vid_overlay.left,
+                                          dev->blended_line + offset, osd,
+                                          dev->loop_vid_overlay.width, pixsize);
+                       else
+                               memcpy(dev->blended_line + offset,
+                                      osd, dev->loop_vid_overlay.width * pixsize);
+                       scale_line(dev->blended_line, dev->scaled_line,
+                                       dev->loop_vid_copy.width, dev->loop_vid_cap.width,
+                                       tpg_g_twopixelsize(tpg, p));
+               }
+               dev->cur_scaled_line = vid_out_y;
+               memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
+                      dev->scaled_line,
+                      dev->loop_vid_cap.width * pixsize);
+
+update_vid_out_y:
+               if (osdline) {
+                       vid_overlay_y += vid_overlay_int_part;
+                       vid_overlay_error += vid_overlay_fract_part;
+                       if (vid_overlay_error >= dev->loop_vid_overlay_cap.height) {
+                               vid_overlay_error -= dev->loop_vid_overlay_cap.height;
+                               vid_overlay_y++;
+                       }
+               }
+               vid_out_y += vid_out_int_part;
+               vid_out_error += vid_out_fract_part;
+               if (vid_out_error >= dev->loop_vid_cap.height) {
+                       vid_out_error -= dev->loop_vid_cap.height;
+                       vid_out_y++;
+               }
+       }
+
+       if (!blank)
+               return 0;
+       for (; y < img_height; y++, vcapbuf += stride_cap)
+               memcpy(vcapbuf, tpg->contrast_line[p], img_width * pixsize);
+       return 0;
+}
+
+static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+       unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
+       unsigned line_height = 16 / factor;
+       bool is_tv = vivid_is_sdtv_cap(dev);
+       bool is_60hz = is_tv && (dev->std_cap & V4L2_STD_525_60);
+       unsigned p;
+       int line = 1;
+       u8 *basep[TPG_MAX_PLANES][2];
+       unsigned ms;
+       char str[100];
+       s32 gain;
+       bool is_loop = false;
+
+       if (dev->loop_video && dev->can_loop_video &&
+           ((vivid_is_svid_cap(dev) && !VIVID_INVALID_SIGNAL(dev->std_signal_mode)) ||
+            (vivid_is_hdmi_cap(dev) && !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode))))
+               is_loop = true;
+
+       buf->vb.v4l2_buf.sequence = dev->vid_cap_seq_count;
+       /*
+        * Take the timestamp now if the timestamp source is set to
+        * "Start of Exposure".
+        */
+       if (dev->tstamp_src_is_soe)
+               v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+       if (dev->field_cap == V4L2_FIELD_ALTERNATE) {
+               /*
+                * 60 Hz standards start with the bottom field, 50 Hz standards
+                * with the top field. So if the 0-based seq_count is even,
+                * then the field is TOP for 50 Hz and BOTTOM for 60 Hz
+                * standards.
+                */
+               buf->vb.v4l2_buf.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ?
+                       V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
+               /*
+                * The sequence counter counts frames, not fields. So divide
+                * by two.
+                */
+               buf->vb.v4l2_buf.sequence /= 2;
+       } else {
+               buf->vb.v4l2_buf.field = dev->field_cap;
+       }
+       tpg_s_field(&dev->tpg, buf->vb.v4l2_buf.field);
+       tpg_s_perc_fill_blank(&dev->tpg, dev->must_blank[buf->vb.v4l2_buf.index]);
+
+       vivid_precalc_copy_rects(dev);
+
+       for (p = 0; p < tpg_g_planes(&dev->tpg); p++) {
+               void *vbuf = vb2_plane_vaddr(&buf->vb, p);
+
+               /*
+                * The first plane of a multiplanar format has a non-zero
+                * data_offset. This helps testing whether the application
+                * correctly supports non-zero data offsets.
+                */
+               if (dev->fmt_cap->data_offset[p]) {
+                       memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff,
+                              dev->fmt_cap->data_offset[p]);
+                       vbuf += dev->fmt_cap->data_offset[p];
+               }
+               tpg_calc_text_basep(&dev->tpg, basep, p, vbuf);
+               if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf))
+                       tpg_fillbuffer(&dev->tpg, vivid_get_std_cap(dev), p, vbuf);
+       }
+       dev->must_blank[buf->vb.v4l2_buf.index] = false;
+
+       /* Updates stream time, only update at the start of a new frame. */
+       if (dev->field_cap != V4L2_FIELD_ALTERNATE || (buf->vb.v4l2_buf.sequence & 1) == 0)
+               dev->ms_vid_cap = jiffies_to_msecs(jiffies - dev->jiffies_vid_cap);
+
+       ms = dev->ms_vid_cap;
+       if (dev->osd_mode <= 1) {
+               snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d %u%s",
+                               (ms / (60 * 60 * 1000)) % 24,
+                               (ms / (60 * 1000)) % 60,
+                               (ms / 1000) % 60,
+                               ms % 1000,
+                               buf->vb.v4l2_buf.sequence,
+                               (dev->field_cap == V4L2_FIELD_ALTERNATE) ?
+                                       (buf->vb.v4l2_buf.field == V4L2_FIELD_TOP ?
+                                        " top" : " bottom") : "");
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+       }
+       if (dev->osd_mode == 0) {
+               snprintf(str, sizeof(str), " %dx%d, input %d ",
+                               dev->src_rect.width, dev->src_rect.height, dev->input);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+
+               gain = v4l2_ctrl_g_ctrl(dev->gain);
+               mutex_lock(dev->ctrl_hdl_user_vid.lock);
+               snprintf(str, sizeof(str),
+                       " brightness %3d, contrast %3d, saturation %3d, hue %d ",
+                       dev->brightness->cur.val,
+                       dev->contrast->cur.val,
+                       dev->saturation->cur.val,
+                       dev->hue->cur.val);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               snprintf(str, sizeof(str),
+                       " autogain %d, gain %3d, alpha 0x%02x ",
+                       dev->autogain->cur.val, gain, dev->alpha->cur.val);
+               mutex_unlock(dev->ctrl_hdl_user_vid.lock);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               mutex_lock(dev->ctrl_hdl_user_aud.lock);
+               snprintf(str, sizeof(str),
+                       " volume %3d, mute %d ",
+                       dev->volume->cur.val, dev->mute->cur.val);
+               mutex_unlock(dev->ctrl_hdl_user_aud.lock);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               mutex_lock(dev->ctrl_hdl_user_gen.lock);
+               snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
+                       dev->int32->cur.val,
+                       *dev->int64->p_cur.p_s64,
+                       dev->bitmask->cur.val);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
+                       dev->boolean->cur.val,
+                       dev->menu->qmenu[dev->menu->cur.val],
+                       dev->string->p_cur.p_char);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
+                       dev->int_menu->qmenu_int[dev->int_menu->cur.val],
+                       dev->int_menu->cur.val);
+               mutex_unlock(dev->ctrl_hdl_user_gen.lock);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               if (dev->button_pressed) {
+                       dev->button_pressed--;
+                       snprintf(str, sizeof(str), " button pressed!");
+                       tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               }
+       }
+
+       /*
+        * If "End of Frame" is specified at the timestamp source, then take
+        * the timestamp now.
+        */
+       if (!dev->tstamp_src_is_soe)
+               v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+       buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+}
+
+/*
+ * Return true if this pixel coordinate is a valid video pixel.
+ */
+static bool valid_pix(struct vivid_dev *dev, int win_y, int win_x, int fb_y, int fb_x)
+{
+       int i;
+
+       if (dev->bitmap_cap) {
+               /*
+                * Only if the corresponding bit in the bitmap is set can
+                * the video pixel be shown. Coordinates are relative to
+                * the overlay window set by VIDIOC_S_FMT.
+                */
+               const u8 *p = dev->bitmap_cap;
+               unsigned stride = (dev->compose_cap.width + 7) / 8;
+
+               if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7))))
+                       return false;
+       }
+
+       for (i = 0; i < dev->clipcount_cap; i++) {
+               /*
+                * Only if the framebuffer coordinate is not in any of the
+                * clip rectangles will be video pixel be shown.
+                */
+               struct v4l2_rect *r = &dev->clips_cap[i].c;
+
+               if (fb_y >= r->top && fb_y < r->top + r->height &&
+                   fb_x >= r->left && fb_x < r->left + r->width)
+                       return false;
+       }
+       return true;
+}
+
+/*
+ * Draw the image into the overlay buffer.
+ * Note that the combination of overlay and multiplanar is not supported.
+ */
+static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+       struct tpg_data *tpg = &dev->tpg;
+       unsigned pixsize = tpg_g_twopixelsize(tpg, 0) / 2;
+       void *vbase = dev->fb_vbase_cap;
+       void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+       unsigned img_width = dev->compose_cap.width;
+       unsigned img_height = dev->compose_cap.height;
+       unsigned stride = tpg->bytesperline[0];
+       /* if quick is true, then valid_pix() doesn't have to be called */
+       bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0;
+       int x, y, w, out_x = 0;
+
+       if ((dev->overlay_cap_field == V4L2_FIELD_TOP ||
+            dev->overlay_cap_field == V4L2_FIELD_BOTTOM) &&
+           dev->overlay_cap_field != buf->vb.v4l2_buf.field)
+               return;
+
+       vbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride;
+       x = dev->overlay_cap_left;
+       w = img_width;
+       if (x < 0) {
+               out_x = -x;
+               w = w - out_x;
+               x = 0;
+       } else {
+               w = dev->fb_cap.fmt.width - x;
+               if (w > img_width)
+                       w = img_width;
+       }
+       if (w <= 0)
+               return;
+       if (dev->overlay_cap_top >= 0)
+               vbase += dev->overlay_cap_top * dev->fb_cap.fmt.bytesperline;
+       for (y = dev->overlay_cap_top;
+            y < dev->overlay_cap_top + (int)img_height;
+            y++, vbuf += stride) {
+               int px;
+
+               if (y < 0 || y > dev->fb_cap.fmt.height)
+                       continue;
+               if (quick) {
+                       memcpy(vbase + x * pixsize,
+                              vbuf + out_x * pixsize, w * pixsize);
+                       vbase += dev->fb_cap.fmt.bytesperline;
+                       continue;
+               }
+               for (px = 0; px < w; px++) {
+                       if (!valid_pix(dev, y - dev->overlay_cap_top,
+                                      px + out_x, y, px + x))
+                               continue;
+                       memcpy(vbase + (px + x) * pixsize,
+                              vbuf + (px + out_x) * pixsize,
+                              pixsize);
+               }
+               vbase += dev->fb_cap.fmt.bytesperline;
+       }
+}
+
+static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
+{
+       struct vivid_buffer *vid_cap_buf = NULL;
+       struct vivid_buffer *vbi_cap_buf = NULL;
+
+       dprintk(dev, 1, "Video Capture Thread Tick\n");
+
+       while (dropped_bufs-- > 1)
+               tpg_update_mv_count(&dev->tpg,
+                               dev->field_cap == V4L2_FIELD_NONE ||
+                               dev->field_cap == V4L2_FIELD_ALTERNATE);
+
+       /* Drop a certain percentage of buffers. */
+       if (dev->perc_dropped_buffers &&
+           prandom_u32_max(100) < dev->perc_dropped_buffers)
+               goto update_mv;
+
+       spin_lock(&dev->slock);
+       if (!list_empty(&dev->vid_cap_active)) {
+               vid_cap_buf = list_entry(dev->vid_cap_active.next, struct vivid_buffer, list);
+               list_del(&vid_cap_buf->list);
+       }
+       if (!list_empty(&dev->vbi_cap_active)) {
+               if (dev->field_cap != V4L2_FIELD_ALTERNATE ||
+                   (dev->vbi_cap_seq_count & 1)) {
+                       vbi_cap_buf = list_entry(dev->vbi_cap_active.next,
+                                                struct vivid_buffer, list);
+                       list_del(&vbi_cap_buf->list);
+               }
+       }
+       spin_unlock(&dev->slock);
+
+       if (!vid_cap_buf && !vbi_cap_buf)
+               goto update_mv;
+
+       if (vid_cap_buf) {
+               /* Fill buffer */
+               vivid_fillbuff(dev, vid_cap_buf);
+               dprintk(dev, 1, "filled buffer %d\n",
+                       vid_cap_buf->vb.v4l2_buf.index);
+
+               /* Handle overlay */
+               if (dev->overlay_cap_owner && dev->fb_cap.base &&
+                               dev->fb_cap.fmt.pixelformat == dev->fmt_cap->fourcc)
+                       vivid_overlay(dev, vid_cap_buf);
+
+               vb2_buffer_done(&vid_cap_buf->vb, dev->dqbuf_error ?
+                               VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+               dprintk(dev, 2, "vid_cap buffer %d done\n",
+                               vid_cap_buf->vb.v4l2_buf.index);
+       }
+
+       if (vbi_cap_buf) {
+               if (dev->stream_sliced_vbi_cap)
+                       vivid_sliced_vbi_cap_process(dev, vbi_cap_buf);
+               else
+                       vivid_raw_vbi_cap_process(dev, vbi_cap_buf);
+               vb2_buffer_done(&vbi_cap_buf->vb, dev->dqbuf_error ?
+                               VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+               dprintk(dev, 2, "vbi_cap %d done\n",
+                               vbi_cap_buf->vb.v4l2_buf.index);
+       }
+       dev->dqbuf_error = false;
+
+update_mv:
+       /* Update the test pattern movement counters */
+       tpg_update_mv_count(&dev->tpg, dev->field_cap == V4L2_FIELD_NONE ||
+                                      dev->field_cap == V4L2_FIELD_ALTERNATE);
+}
+
+static int vivid_thread_vid_cap(void *data)
+{
+       struct vivid_dev *dev = data;
+       u64 numerators_since_start;
+       u64 buffers_since_start;
+       u64 next_jiffies_since_start;
+       unsigned long jiffies_since_start;
+       unsigned long cur_jiffies;
+       unsigned wait_jiffies;
+       unsigned numerator;
+       unsigned denominator;
+       int dropped_bufs;
+
+       dprintk(dev, 1, "Video Capture Thread Start\n");
+
+       set_freezable();
+
+       /* Resets frame counters */
+       dev->cap_seq_offset = 0;
+       dev->cap_seq_count = 0;
+       dev->cap_seq_resync = false;
+       dev->jiffies_vid_cap = jiffies;
+
+       for (;;) {
+               try_to_freeze();
+               if (kthread_should_stop())
+                       break;
+
+               mutex_lock(&dev->mutex);
+               cur_jiffies = jiffies;
+               if (dev->cap_seq_resync) {
+                       dev->jiffies_vid_cap = cur_jiffies;
+                       dev->cap_seq_offset = dev->cap_seq_count + 1;
+                       dev->cap_seq_count = 0;
+                       dev->cap_seq_resync = false;
+               }
+               numerator = dev->timeperframe_vid_cap.numerator;
+               denominator = dev->timeperframe_vid_cap.denominator;
+
+               if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+                       denominator *= 2;
+
+               /* Calculate the number of jiffies since we started streaming */
+               jiffies_since_start = cur_jiffies - dev->jiffies_vid_cap;
+               /* Get the number of buffers streamed since the start */
+               buffers_since_start = (u64)jiffies_since_start * denominator +
+                                     (HZ * numerator) / 2;
+               do_div(buffers_since_start, HZ * numerator);
+
+               /*
+                * After more than 0xf0000000 (rounded down to a multiple of
+                * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
+                * jiffies have passed since we started streaming reset the
+                * counters and keep track of the sequence offset.
+                */
+               if (jiffies_since_start > JIFFIES_RESYNC) {
+                       dev->jiffies_vid_cap = cur_jiffies;
+                       dev->cap_seq_offset = buffers_since_start;
+                       buffers_since_start = 0;
+               }
+               dropped_bufs = buffers_since_start + dev->cap_seq_offset - dev->cap_seq_count;
+               dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset;
+               dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start;
+               dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start;
+
+               vivid_thread_vid_cap_tick(dev, dropped_bufs);
+
+               /*
+                * Calculate the number of 'numerators' streamed since we started,
+                * including the current buffer.
+                */
+               numerators_since_start = ++buffers_since_start * numerator;
+
+               /* And the number of jiffies since we started */
+               jiffies_since_start = jiffies - dev->jiffies_vid_cap;
+
+               mutex_unlock(&dev->mutex);
+
+               /*
+                * Calculate when that next buffer is supposed to start
+                * in jiffies since we started streaming.
+                */
+               next_jiffies_since_start = numerators_since_start * HZ +
+                                          denominator / 2;
+               do_div(next_jiffies_since_start, denominator);
+               /* If it is in the past, then just schedule asap */
+               if (next_jiffies_since_start < jiffies_since_start)
+                       next_jiffies_since_start = jiffies_since_start;
+
+               wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+               schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
+       }
+       dprintk(dev, 1, "Video Capture Thread End\n");
+       return 0;
+}
+
+static void vivid_grab_controls(struct vivid_dev *dev, bool grab)
+{
+       v4l2_ctrl_grab(dev->ctrl_has_crop_cap, grab);
+       v4l2_ctrl_grab(dev->ctrl_has_compose_cap, grab);
+       v4l2_ctrl_grab(dev->ctrl_has_scaler_cap, grab);
+}
+
+int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
+{
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->kthread_vid_cap) {
+               u32 seq_count = dev->cap_seq_count + dev->seq_wrap * 128;
+
+               if (pstreaming == &dev->vid_cap_streaming)
+                       dev->vid_cap_seq_start = seq_count;
+               else
+                       dev->vbi_cap_seq_start = seq_count;
+               *pstreaming = true;
+               return 0;
+       }
+
+       /* Resets frame counters */
+       tpg_init_mv_count(&dev->tpg);
+
+       dev->vid_cap_seq_start = dev->seq_wrap * 128;
+       dev->vbi_cap_seq_start = dev->seq_wrap * 128;
+
+       dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev,
+                       "%s-vid-cap", dev->v4l2_dev.name);
+
+       if (IS_ERR(dev->kthread_vid_cap)) {
+               v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+               return PTR_ERR(dev->kthread_vid_cap);
+       }
+       *pstreaming = true;
+       vivid_grab_controls(dev, true);
+
+       dprintk(dev, 1, "returning from %s\n", __func__);
+       return 0;
+}
+
+void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
+{
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->kthread_vid_cap == NULL)
+               return;
+
+       *pstreaming = false;
+       if (pstreaming == &dev->vid_cap_streaming) {
+               /* Release all active buffers */
+               while (!list_empty(&dev->vid_cap_active)) {
+                       struct vivid_buffer *buf;
+
+                       buf = list_entry(dev->vid_cap_active.next,
+                                        struct vivid_buffer, list);
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+                       dprintk(dev, 2, "vid_cap buffer %d done\n",
+                               buf->vb.v4l2_buf.index);
+               }
+       }
+
+       if (pstreaming == &dev->vbi_cap_streaming) {
+               while (!list_empty(&dev->vbi_cap_active)) {
+                       struct vivid_buffer *buf;
+
+                       buf = list_entry(dev->vbi_cap_active.next,
+                                        struct vivid_buffer, list);
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+                       dprintk(dev, 2, "vbi_cap buffer %d done\n",
+                               buf->vb.v4l2_buf.index);
+               }
+       }
+
+       if (dev->vid_cap_streaming || dev->vbi_cap_streaming)
+               return;
+
+       /* shutdown control thread */
+       vivid_grab_controls(dev, false);
+       mutex_unlock(&dev->mutex);
+       kthread_stop(dev->kthread_vid_cap);
+       dev->kthread_vid_cap = NULL;
+       mutex_lock(&dev->mutex);
+}
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.h b/drivers/media/platform/vivid/vivid-kthread-cap.h
new file mode 100644 (file)
index 0000000..5b92fc9
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * vivid-kthread-cap.h - video/vbi capture thread support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_KTHREAD_CAP_H_
+#define _VIVID_KTHREAD_CAP_H_
+
+int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming);
+void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c
new file mode 100644 (file)
index 0000000..d9f36cc
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * vivid-kthread-out.h - video/vbi output thread support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/random.h>
+#include <linux/v4l2-dv-timings.h>
+#include <asm/div64.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-vid-cap.h"
+#include "vivid-vid-out.h"
+#include "vivid-radio-common.h"
+#include "vivid-radio-rx.h"
+#include "vivid-radio-tx.h"
+#include "vivid-sdr-cap.h"
+#include "vivid-vbi-cap.h"
+#include "vivid-vbi-out.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.h"
+#include "vivid-kthread-out.h"
+
+static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
+{
+       struct vivid_buffer *vid_out_buf = NULL;
+       struct vivid_buffer *vbi_out_buf = NULL;
+
+       dprintk(dev, 1, "Video Output Thread Tick\n");
+
+       /* Drop a certain percentage of buffers. */
+       if (dev->perc_dropped_buffers &&
+           prandom_u32_max(100) < dev->perc_dropped_buffers)
+               return;
+
+       spin_lock(&dev->slock);
+       /*
+        * Only dequeue buffer if there is at least one more pending.
+        * This makes video loopback possible.
+        */
+       if (!list_empty(&dev->vid_out_active) &&
+           !list_is_singular(&dev->vid_out_active)) {
+               vid_out_buf = list_entry(dev->vid_out_active.next,
+                                        struct vivid_buffer, list);
+               list_del(&vid_out_buf->list);
+       }
+       if (!list_empty(&dev->vbi_out_active) &&
+           (dev->field_out != V4L2_FIELD_ALTERNATE ||
+            (dev->vbi_out_seq_count & 1))) {
+               vbi_out_buf = list_entry(dev->vbi_out_active.next,
+                                        struct vivid_buffer, list);
+               list_del(&vbi_out_buf->list);
+       }
+       spin_unlock(&dev->slock);
+
+       if (!vid_out_buf && !vbi_out_buf)
+               return;
+
+       if (vid_out_buf) {
+               vid_out_buf->vb.v4l2_buf.sequence = dev->vid_out_seq_count;
+               if (dev->field_out == V4L2_FIELD_ALTERNATE) {
+                       /*
+                        * The sequence counter counts frames, not fields. So divide
+                        * by two.
+                        */
+                       vid_out_buf->vb.v4l2_buf.sequence /= 2;
+               }
+               v4l2_get_timestamp(&vid_out_buf->vb.v4l2_buf.timestamp);
+               vid_out_buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+               vb2_buffer_done(&vid_out_buf->vb, dev->dqbuf_error ?
+                               VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+               dprintk(dev, 2, "vid_out buffer %d done\n",
+                       vid_out_buf->vb.v4l2_buf.index);
+       }
+
+       if (vbi_out_buf) {
+               if (dev->stream_sliced_vbi_out)
+                       vivid_sliced_vbi_out_process(dev, vbi_out_buf);
+
+               vbi_out_buf->vb.v4l2_buf.sequence = dev->vbi_out_seq_count;
+               v4l2_get_timestamp(&vbi_out_buf->vb.v4l2_buf.timestamp);
+               vbi_out_buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+               vb2_buffer_done(&vbi_out_buf->vb, dev->dqbuf_error ?
+                               VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+               dprintk(dev, 2, "vbi_out buffer %d done\n",
+                       vbi_out_buf->vb.v4l2_buf.index);
+       }
+       dev->dqbuf_error = false;
+}
+
+static int vivid_thread_vid_out(void *data)
+{
+       struct vivid_dev *dev = data;
+       u64 numerators_since_start;
+       u64 buffers_since_start;
+       u64 next_jiffies_since_start;
+       unsigned long jiffies_since_start;
+       unsigned long cur_jiffies;
+       unsigned wait_jiffies;
+       unsigned numerator;
+       unsigned denominator;
+
+       dprintk(dev, 1, "Video Output Thread Start\n");
+
+       set_freezable();
+
+       /* Resets frame counters */
+       dev->out_seq_offset = 0;
+       if (dev->seq_wrap)
+               dev->out_seq_count = 0xffffff80U;
+       dev->jiffies_vid_out = jiffies;
+       dev->vid_out_seq_start = dev->vbi_out_seq_start = 0;
+       dev->out_seq_resync = false;
+
+       for (;;) {
+               try_to_freeze();
+               if (kthread_should_stop())
+                       break;
+
+               mutex_lock(&dev->mutex);
+               cur_jiffies = jiffies;
+               if (dev->out_seq_resync) {
+                       dev->jiffies_vid_out = cur_jiffies;
+                       dev->out_seq_offset = dev->out_seq_count + 1;
+                       dev->out_seq_count = 0;
+                       dev->out_seq_resync = false;
+               }
+               numerator = dev->timeperframe_vid_out.numerator;
+               denominator = dev->timeperframe_vid_out.denominator;
+
+               if (dev->field_out == V4L2_FIELD_ALTERNATE)
+                       denominator *= 2;
+
+               /* Calculate the number of jiffies since we started streaming */
+               jiffies_since_start = cur_jiffies - dev->jiffies_vid_out;
+               /* Get the number of buffers streamed since the start */
+               buffers_since_start = (u64)jiffies_since_start * denominator +
+                                     (HZ * numerator) / 2;
+               do_div(buffers_since_start, HZ * numerator);
+
+               /*
+                * After more than 0xf0000000 (rounded down to a multiple of
+                * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
+                * jiffies have passed since we started streaming reset the
+                * counters and keep track of the sequence offset.
+                */
+               if (jiffies_since_start > JIFFIES_RESYNC) {
+                       dev->jiffies_vid_out = cur_jiffies;
+                       dev->out_seq_offset = buffers_since_start;
+                       buffers_since_start = 0;
+               }
+               dev->out_seq_count = buffers_since_start + dev->out_seq_offset;
+               dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start;
+               dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start;
+
+               vivid_thread_vid_out_tick(dev);
+               mutex_unlock(&dev->mutex);
+
+               /*
+                * Calculate the number of 'numerators' streamed since we started,
+                * not including the current buffer.
+                */
+               numerators_since_start = buffers_since_start * numerator;
+
+               /* And the number of jiffies since we started */
+               jiffies_since_start = jiffies - dev->jiffies_vid_out;
+
+               /* Increase by the 'numerator' of one buffer */
+               numerators_since_start += numerator;
+               /*
+                * Calculate when that next buffer is supposed to start
+                * in jiffies since we started streaming.
+                */
+               next_jiffies_since_start = numerators_since_start * HZ +
+                                          denominator / 2;
+               do_div(next_jiffies_since_start, denominator);
+               /* If it is in the past, then just schedule asap */
+               if (next_jiffies_since_start < jiffies_since_start)
+                       next_jiffies_since_start = jiffies_since_start;
+
+               wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+               schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
+       }
+       dprintk(dev, 1, "Video Output Thread End\n");
+       return 0;
+}
+
+static void vivid_grab_controls(struct vivid_dev *dev, bool grab)
+{
+       v4l2_ctrl_grab(dev->ctrl_has_crop_out, grab);
+       v4l2_ctrl_grab(dev->ctrl_has_compose_out, grab);
+       v4l2_ctrl_grab(dev->ctrl_has_scaler_out, grab);
+       v4l2_ctrl_grab(dev->ctrl_tx_mode, grab);
+       v4l2_ctrl_grab(dev->ctrl_tx_rgb_range, grab);
+}
+
+int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
+{
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->kthread_vid_out) {
+               u32 seq_count = dev->out_seq_count + dev->seq_wrap * 128;
+
+               if (pstreaming == &dev->vid_out_streaming)
+                       dev->vid_out_seq_start = seq_count;
+               else
+                       dev->vbi_out_seq_start = seq_count;
+               *pstreaming = true;
+               return 0;
+       }
+
+       /* Resets frame counters */
+       dev->jiffies_vid_out = jiffies;
+       dev->vid_out_seq_start = dev->seq_wrap * 128;
+       dev->vbi_out_seq_start = dev->seq_wrap * 128;
+
+       dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev,
+                       "%s-vid-out", dev->v4l2_dev.name);
+
+       if (IS_ERR(dev->kthread_vid_out)) {
+               v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+               return PTR_ERR(dev->kthread_vid_out);
+       }
+       *pstreaming = true;
+       vivid_grab_controls(dev, true);
+
+       dprintk(dev, 1, "returning from %s\n", __func__);
+       return 0;
+}
+
+void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
+{
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->kthread_vid_out == NULL)
+               return;
+
+       *pstreaming = false;
+       if (pstreaming == &dev->vid_out_streaming) {
+               /* Release all active buffers */
+               while (!list_empty(&dev->vid_out_active)) {
+                       struct vivid_buffer *buf;
+
+                       buf = list_entry(dev->vid_out_active.next,
+                                        struct vivid_buffer, list);
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+                       dprintk(dev, 2, "vid_out buffer %d done\n",
+                               buf->vb.v4l2_buf.index);
+               }
+       }
+
+       if (pstreaming == &dev->vbi_out_streaming) {
+               while (!list_empty(&dev->vbi_out_active)) {
+                       struct vivid_buffer *buf;
+
+                       buf = list_entry(dev->vbi_out_active.next,
+                                        struct vivid_buffer, list);
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+                       dprintk(dev, 2, "vbi_out buffer %d done\n",
+                               buf->vb.v4l2_buf.index);
+               }
+       }
+
+       if (dev->vid_out_streaming || dev->vbi_out_streaming)
+               return;
+
+       /* shutdown control thread */
+       vivid_grab_controls(dev, false);
+       mutex_unlock(&dev->mutex);
+       kthread_stop(dev->kthread_vid_out);
+       dev->kthread_vid_out = NULL;
+       mutex_lock(&dev->mutex);
+}
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.h b/drivers/media/platform/vivid/vivid-kthread-out.h
new file mode 100644 (file)
index 0000000..2bf04a1
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * vivid-kthread-out.h - video/vbi output thread support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_KTHREAD_OUT_H_
+#define _VIVID_KTHREAD_OUT_H_
+
+int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming);
+void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c
new file mode 100644 (file)
index 0000000..084d346
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * vivid-osd.c - osd support for testing overlays.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/fb.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
+
+#include "vivid-core.h"
+#include "vivid-osd.h"
+
+#define MAX_OSD_WIDTH  720
+#define MAX_OSD_HEIGHT 576
+
+/*
+ * Order: white, yellow, cyan, green, magenta, red, blue, black,
+ * and same again with the alpha bit set (if any)
+ */
+static const u16 rgb555[16] = {
+       0x7fff, 0x7fe0, 0x03ff, 0x03e0, 0x7c1f, 0x7c00, 0x001f, 0x0000,
+       0xffff, 0xffe0, 0x83ff, 0x83e0, 0xfc1f, 0xfc00, 0x801f, 0x8000
+};
+
+static const u16 rgb565[16] = {
+       0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000,
+       0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000
+};
+
+void vivid_clear_fb(struct vivid_dev *dev)
+{
+       void *p = dev->video_vbase;
+       const u16 *rgb = rgb555;
+       unsigned x, y;
+
+       if (dev->fb_defined.green.length == 6)
+               rgb = rgb565;
+
+       for (y = 0; y < dev->display_height; y++) {
+               u16 *d = p;
+
+               for (x = 0; x < dev->display_width; x++)
+                       d[x] = rgb[(y / 16 + x / 16) % 16];
+               p += dev->display_byte_stride;
+       }
+}
+
+/* --------------------------------------------------------------------- */
+
+static int vivid_fb_ioctl(struct fb_info *info, unsigned cmd, unsigned long arg)
+{
+       struct vivid_dev *dev = (struct vivid_dev *)info->par;
+
+       switch (cmd) {
+       case FBIOGET_VBLANK: {
+               struct fb_vblank vblank;
+
+               vblank.flags = FB_VBLANK_HAVE_COUNT | FB_VBLANK_HAVE_VCOUNT |
+                       FB_VBLANK_HAVE_VSYNC;
+               vblank.count = 0;
+               vblank.vcount = 0;
+               vblank.hcount = 0;
+               if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       default:
+               dprintk(dev, 1, "Unknown ioctl %08x\n", cmd);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* Framebuffer device handling */
+
+static int vivid_fb_set_var(struct vivid_dev *dev, struct fb_var_screeninfo *var)
+{
+       dprintk(dev, 1, "vivid_fb_set_var\n");
+
+       if (var->bits_per_pixel != 16) {
+               dprintk(dev, 1, "vivid_fb_set_var - Invalid bpp\n");
+               return -EINVAL;
+       }
+       dev->display_byte_stride = var->xres * dev->bytes_per_pixel;
+
+       return 0;
+}
+
+static int vivid_fb_get_fix(struct vivid_dev *dev, struct fb_fix_screeninfo *fix)
+{
+       dprintk(dev, 1, "vivid_fb_get_fix\n");
+       memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+       strlcpy(fix->id, "vioverlay fb", sizeof(fix->id));
+       fix->smem_start = dev->video_pbase;
+       fix->smem_len = dev->video_buffer_size;
+       fix->type = FB_TYPE_PACKED_PIXELS;
+       fix->visual = FB_VISUAL_TRUECOLOR;
+       fix->xpanstep = 1;
+       fix->ypanstep = 1;
+       fix->ywrapstep = 0;
+       fix->line_length = dev->display_byte_stride;
+       fix->accel = FB_ACCEL_NONE;
+       return 0;
+}
+
+/* Check the requested display mode, returning -EINVAL if we can't
+   handle it. */
+
+static int _vivid_fb_check_var(struct fb_var_screeninfo *var, struct vivid_dev *dev)
+{
+       dprintk(dev, 1, "vivid_fb_check_var\n");
+
+       var->bits_per_pixel = 16;
+       if (var->green.length == 5) {
+               var->red.offset = 10;
+               var->red.length = 5;
+               var->green.offset = 5;
+               var->green.length = 5;
+               var->blue.offset = 0;
+               var->blue.length = 5;
+               var->transp.offset = 15;
+               var->transp.length = 1;
+       } else {
+               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;
+       }
+       var->xoffset = var->yoffset = 0;
+       var->left_margin = var->upper_margin = 0;
+       var->nonstd = 0;
+
+       var->vmode &= ~FB_VMODE_MASK;
+       var->vmode = FB_VMODE_NONINTERLACED;
+
+       /* Dummy values */
+       var->hsync_len = 24;
+       var->vsync_len = 2;
+       var->pixclock = 84316;
+       var->right_margin = 776;
+       var->lower_margin = 591;
+       return 0;
+}
+
+static int vivid_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct vivid_dev *dev = (struct vivid_dev *) info->par;
+
+       dprintk(dev, 1, "vivid_fb_check_var\n");
+       return _vivid_fb_check_var(var, dev);
+}
+
+static int vivid_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       return 0;
+}
+
+static int vivid_fb_set_par(struct fb_info *info)
+{
+       int rc = 0;
+       struct vivid_dev *dev = (struct vivid_dev *) info->par;
+
+       dprintk(dev, 1, "vivid_fb_set_par\n");
+
+       rc = vivid_fb_set_var(dev, &info->var);
+       vivid_fb_get_fix(dev, &info->fix);
+       return rc;
+}
+
+static int vivid_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                               unsigned blue, unsigned transp,
+                               struct fb_info *info)
+{
+       u32 color, *palette;
+
+       if (regno >= info->cmap.len)
+               return -EINVAL;
+
+       color = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) |
+                (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+       if (regno >= 16)
+               return -EINVAL;
+
+       palette = info->pseudo_palette;
+       if (info->var.bits_per_pixel == 16) {
+               switch (info->var.green.length) {
+               case 6:
+                       color = (red & 0xf800) |
+                               ((green & 0xfc00) >> 5) |
+                               ((blue & 0xf800) >> 11);
+                       break;
+               case 5:
+                       color = ((red & 0xf800) >> 1) |
+                               ((green & 0xf800) >> 6) |
+                               ((blue & 0xf800) >> 11) |
+                               (transp ? 0x8000 : 0);
+                       break;
+               }
+       }
+       palette[regno] = color;
+       return 0;
+}
+
+/* We don't really support blanking. All this does is enable or
+   disable the OSD. */
+static int vivid_fb_blank(int blank_mode, struct fb_info *info)
+{
+       struct vivid_dev *dev = (struct vivid_dev *)info->par;
+
+       dprintk(dev, 1, "Set blanking mode : %d\n", blank_mode);
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:
+               break;
+       case FB_BLANK_NORMAL:
+       case FB_BLANK_HSYNC_SUSPEND:
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_POWERDOWN:
+               break;
+       }
+       return 0;
+}
+
+static struct fb_ops vivid_fb_ops = {
+       .owner = THIS_MODULE,
+       .fb_check_var   = vivid_fb_check_var,
+       .fb_set_par     = vivid_fb_set_par,
+       .fb_setcolreg   = vivid_fb_setcolreg,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+       .fb_cursor      = NULL,
+       .fb_ioctl       = vivid_fb_ioctl,
+       .fb_pan_display = vivid_fb_pan_display,
+       .fb_blank       = vivid_fb_blank,
+};
+
+/* Initialization */
+
+
+/* Setup our initial video mode */
+static int vivid_fb_init_vidmode(struct vivid_dev *dev)
+{
+       struct v4l2_rect start_window;
+
+       /* Color mode */
+
+       dev->bits_per_pixel = 16;
+       dev->bytes_per_pixel = dev->bits_per_pixel / 8;
+
+       start_window.width = MAX_OSD_WIDTH;
+       start_window.left = 0;
+
+       dev->display_byte_stride = start_window.width * dev->bytes_per_pixel;
+
+       /* Vertical size & position */
+
+       start_window.height = MAX_OSD_HEIGHT;
+       start_window.top = 0;
+
+       dev->display_width = start_window.width;
+       dev->display_height = start_window.height;
+
+       /* Generate a valid fb_var_screeninfo */
+
+       dev->fb_defined.xres = dev->display_width;
+       dev->fb_defined.yres = dev->display_height;
+       dev->fb_defined.xres_virtual = dev->display_width;
+       dev->fb_defined.yres_virtual = dev->display_height;
+       dev->fb_defined.bits_per_pixel = dev->bits_per_pixel;
+       dev->fb_defined.vmode = FB_VMODE_NONINTERLACED;
+       dev->fb_defined.left_margin = start_window.left + 1;
+       dev->fb_defined.upper_margin = start_window.top + 1;
+       dev->fb_defined.accel_flags = FB_ACCEL_NONE;
+       dev->fb_defined.nonstd = 0;
+       /* set default to 1:5:5:5 */
+       dev->fb_defined.green.length = 5;
+
+       /* We've filled in the most data, let the usual mode check
+          routine fill in the rest. */
+       _vivid_fb_check_var(&dev->fb_defined, dev);
+
+       /* Generate valid fb_fix_screeninfo */
+
+       vivid_fb_get_fix(dev, &dev->fb_fix);
+
+       /* Generate valid fb_info */
+
+       dev->fb_info.node = -1;
+       dev->fb_info.flags = FBINFO_FLAG_DEFAULT;
+       dev->fb_info.fbops = &vivid_fb_ops;
+       dev->fb_info.par = dev;
+       dev->fb_info.var = dev->fb_defined;
+       dev->fb_info.fix = dev->fb_fix;
+       dev->fb_info.screen_base = (u8 __iomem *)dev->video_vbase;
+       dev->fb_info.fbops = &vivid_fb_ops;
+
+       /* Supply some monitor specs. Bogus values will do for now */
+       dev->fb_info.monspecs.hfmin = 8000;
+       dev->fb_info.monspecs.hfmax = 70000;
+       dev->fb_info.monspecs.vfmin = 10;
+       dev->fb_info.monspecs.vfmax = 100;
+
+       /* Allocate color map */
+       if (fb_alloc_cmap(&dev->fb_info.cmap, 256, 1)) {
+               pr_err("abort, unable to alloc cmap\n");
+               return -ENOMEM;
+       }
+
+       /* Allocate the pseudo palette */
+       dev->fb_info.pseudo_palette = kmalloc_array(16, sizeof(u32), GFP_KERNEL);
+
+       return dev->fb_info.pseudo_palette ? 0 : -ENOMEM;
+}
+
+/* Release any memory we've grabbed */
+void vivid_fb_release_buffers(struct vivid_dev *dev)
+{
+       if (dev->video_vbase == NULL)
+               return;
+
+       /* Release cmap */
+       if (dev->fb_info.cmap.len)
+               fb_dealloc_cmap(&dev->fb_info.cmap);
+
+       /* Release pseudo palette */
+       kfree(dev->fb_info.pseudo_palette);
+       kfree((void *)dev->video_vbase);
+}
+
+/* Initialize the specified card */
+
+int vivid_fb_init(struct vivid_dev *dev)
+{
+       int ret;
+
+       dev->video_buffer_size = MAX_OSD_HEIGHT * MAX_OSD_WIDTH * 2;
+       dev->video_vbase = kzalloc(dev->video_buffer_size, GFP_KERNEL | GFP_DMA32);
+       if (dev->video_vbase == NULL)
+               return -ENOMEM;
+       dev->video_pbase = virt_to_phys(dev->video_vbase);
+
+       pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+                       dev->video_pbase, dev->video_vbase,
+                       dev->video_buffer_size / 1024);
+
+       /* Set the startup video mode information */
+       ret = vivid_fb_init_vidmode(dev);
+       if (ret) {
+               vivid_fb_release_buffers(dev);
+               return ret;
+       }
+
+       vivid_clear_fb(dev);
+
+       /* Register the framebuffer */
+       if (register_framebuffer(&dev->fb_info) < 0) {
+               vivid_fb_release_buffers(dev);
+               return -EINVAL;
+       }
+
+       /* Set the card to the requested mode */
+       vivid_fb_set_par(&dev->fb_info);
+       return 0;
+
+}
diff --git a/drivers/media/platform/vivid/vivid-osd.h b/drivers/media/platform/vivid/vivid-osd.h
new file mode 100644 (file)
index 0000000..57c9daa
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * vivid-osd.h - output overlay support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_OSD_H_
+#define _VIVID_OSD_H_
+
+int vivid_fb_init(struct vivid_dev *dev);
+void vivid_fb_release_buffers(struct vivid_dev *dev);
+void vivid_clear_fb(struct vivid_dev *dev);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-radio-common.c b/drivers/media/platform/vivid/vivid-radio-common.c
new file mode 100644 (file)
index 0000000..78c1e92
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * vivid-radio-common.c - common radio rx/tx support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-radio-common.h"
+#include "vivid-rds-gen.h"
+
+/*
+ * These functions are shared between the vivid receiver and transmitter
+ * since both use the same frequency bands.
+ */
+
+const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS] = {
+       /* Band FM */
+       {
+               .type = V4L2_TUNER_RADIO,
+               .index = 0,
+               .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+                             V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   = FM_FREQ_RANGE_LOW,
+               .rangehigh  = FM_FREQ_RANGE_HIGH,
+               .modulation = V4L2_BAND_MODULATION_FM,
+       },
+       /* Band AM */
+       {
+               .type = V4L2_TUNER_RADIO,
+               .index = 1,
+               .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   = AM_FREQ_RANGE_LOW,
+               .rangehigh  = AM_FREQ_RANGE_HIGH,
+               .modulation = V4L2_BAND_MODULATION_AM,
+       },
+       /* Band SW */
+       {
+               .type = V4L2_TUNER_RADIO,
+               .index = 2,
+               .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   = SW_FREQ_RANGE_LOW,
+               .rangehigh  = SW_FREQ_RANGE_HIGH,
+               .modulation = V4L2_BAND_MODULATION_AM,
+       },
+};
+
+/*
+ * Initialize the RDS generator. If we can loop, then the RDS generator
+ * is set up with the values from the RDS TX controls, otherwise it
+ * will fill in standard values using one of two alternates.
+ */
+void vivid_radio_rds_init(struct vivid_dev *dev)
+{
+       struct vivid_rds_gen *rds = &dev->rds_gen;
+       bool alt = dev->radio_rx_rds_use_alternates;
+
+       /* Do nothing, blocks will be filled by the transmitter */
+       if (dev->radio_rds_loop && !dev->radio_tx_rds_controls)
+               return;
+
+       if (dev->radio_rds_loop) {
+               v4l2_ctrl_lock(dev->radio_tx_rds_pi);
+               rds->picode = dev->radio_tx_rds_pi->cur.val;
+               rds->pty = dev->radio_tx_rds_pty->cur.val;
+               rds->mono_stereo = dev->radio_tx_rds_mono_stereo->cur.val;
+               rds->art_head = dev->radio_tx_rds_art_head->cur.val;
+               rds->compressed = dev->radio_tx_rds_compressed->cur.val;
+               rds->dyn_pty = dev->radio_tx_rds_dyn_pty->cur.val;
+               rds->ta = dev->radio_tx_rds_ta->cur.val;
+               rds->tp = dev->radio_tx_rds_tp->cur.val;
+               rds->ms = dev->radio_tx_rds_ms->cur.val;
+               strlcpy(rds->psname,
+                       dev->radio_tx_rds_psname->p_cur.p_char,
+                       sizeof(rds->psname));
+               strlcpy(rds->radiotext,
+                       dev->radio_tx_rds_radiotext->p_cur.p_char + alt * 64,
+                       sizeof(rds->radiotext));
+               v4l2_ctrl_unlock(dev->radio_tx_rds_pi);
+       } else {
+               vivid_rds_gen_fill(rds, dev->radio_rx_freq, alt);
+       }
+       if (dev->radio_rx_rds_controls) {
+               v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, rds->pty);
+               v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, rds->ta);
+               v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, rds->tp);
+               v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, rds->ms);
+               v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, rds->psname);
+               v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, rds->radiotext);
+               if (!dev->radio_rds_loop)
+                       dev->radio_rx_rds_use_alternates = !dev->radio_rx_rds_use_alternates;
+       }
+       vivid_rds_generate(rds);
+}
+
+/*
+ * Calculate the emulated signal quality taking into account the frequency
+ * the transmitter is using.
+ */
+static void vivid_radio_calc_sig_qual(struct vivid_dev *dev)
+{
+       int mod = 16000;
+       int delta = 800;
+       int sig_qual, sig_qual_tx = mod;
+
+       /*
+        * For SW and FM there is a channel every 1000 kHz, for AM there is one
+        * every 100 kHz.
+        */
+       if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH) {
+               mod /= 10;
+               delta /= 10;
+       }
+       sig_qual = (dev->radio_rx_freq + delta) % mod - delta;
+       if (dev->has_radio_tx)
+               sig_qual_tx = dev->radio_rx_freq - dev->radio_tx_freq;
+       if (abs(sig_qual_tx) <= abs(sig_qual)) {
+               sig_qual = sig_qual_tx;
+               /*
+                * Zero the internal rds buffer if we are going to loop
+                * rds blocks.
+                */
+               if (!dev->radio_rds_loop && !dev->radio_tx_rds_controls)
+                       memset(dev->rds_gen.data, 0,
+                              sizeof(dev->rds_gen.data));
+               dev->radio_rds_loop = dev->radio_rx_freq >= FM_FREQ_RANGE_LOW;
+       } else {
+               dev->radio_rds_loop = false;
+       }
+       if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH)
+               sig_qual *= 10;
+       dev->radio_rx_sig_qual = sig_qual;
+}
+
+int vivid_radio_g_frequency(struct file *file, const unsigned *pfreq, struct v4l2_frequency *vf)
+{
+       if (vf->tuner != 0)
+               return -EINVAL;
+       vf->frequency = *pfreq;
+       return 0;
+}
+
+int vivid_radio_s_frequency(struct file *file, unsigned *pfreq, const struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       unsigned freq;
+       unsigned band;
+
+       if (vf->tuner != 0)
+               return -EINVAL;
+
+       if (vf->frequency >= (FM_FREQ_RANGE_LOW + SW_FREQ_RANGE_HIGH) / 2)
+               band = BAND_FM;
+       else if (vf->frequency <= (AM_FREQ_RANGE_HIGH + SW_FREQ_RANGE_LOW) / 2)
+               band = BAND_AM;
+       else
+               band = BAND_SW;
+
+       freq = clamp_t(u32, vf->frequency, vivid_radio_bands[band].rangelow,
+                                          vivid_radio_bands[band].rangehigh);
+       *pfreq = freq;
+
+       /*
+        * For both receiver and transmitter recalculate the signal quality
+        * (since that depends on both frequencies) and re-init the rds
+        * generator.
+        */
+       vivid_radio_calc_sig_qual(dev);
+       vivid_radio_rds_init(dev);
+       return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-radio-common.h b/drivers/media/platform/vivid/vivid-radio-common.h
new file mode 100644 (file)
index 0000000..92fe589
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * vivid-radio-common.h - common radio rx/tx support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_RADIO_COMMON_H_
+#define _VIVID_RADIO_COMMON_H_
+
+/* The supported radio frequency ranges in kHz */
+#define FM_FREQ_RANGE_LOW       (64000U * 16U)
+#define FM_FREQ_RANGE_HIGH      (108000U * 16U)
+#define AM_FREQ_RANGE_LOW       (520U * 16U)
+#define AM_FREQ_RANGE_HIGH      (1710U * 16U)
+#define SW_FREQ_RANGE_LOW       (2300U * 16U)
+#define SW_FREQ_RANGE_HIGH      (26100U * 16U)
+
+enum { BAND_FM, BAND_AM, BAND_SW, TOT_BANDS };
+
+extern const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS];
+
+int vivid_radio_g_frequency(struct file *file, const unsigned *freq, struct v4l2_frequency *vf);
+int vivid_radio_s_frequency(struct file *file, unsigned *freq, const struct v4l2_frequency *vf);
+
+void vivid_radio_rds_init(struct vivid_dev *dev);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c
new file mode 100644 (file)
index 0000000..c7651a5
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * vivid-radio-rx.c - radio receiver support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-radio-common.h"
+#include "vivid-rds-gen.h"
+#include "vivid-radio-rx.h"
+
+ssize_t vivid_radio_rx_read(struct file *file, char __user *buf,
+                        size_t size, loff_t *offset)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct timespec ts;
+       struct v4l2_rds_data *data = dev->rds_gen.data;
+       bool use_alternates;
+       unsigned blk;
+       int perc;
+       int i;
+
+       if (dev->radio_rx_rds_controls)
+               return -EINVAL;
+       if (size < sizeof(*data))
+               return 0;
+       size = sizeof(*data) * (size / sizeof(*data));
+
+       if (mutex_lock_interruptible(&dev->mutex))
+               return -ERESTARTSYS;
+       if (dev->radio_rx_rds_owner &&
+           file->private_data != dev->radio_rx_rds_owner) {
+               mutex_unlock(&dev->mutex);
+               return -EBUSY;
+       }
+       if (dev->radio_rx_rds_owner == NULL) {
+               vivid_radio_rds_init(dev);
+               dev->radio_rx_rds_owner = file->private_data;
+       }
+
+retry:
+       ktime_get_ts(&ts);
+       use_alternates = ts.tv_sec % 10 >= 5;
+       if (dev->radio_rx_rds_last_block == 0 ||
+           dev->radio_rx_rds_use_alternates != use_alternates) {
+               dev->radio_rx_rds_use_alternates = use_alternates;
+               /* Re-init the RDS generator */
+               vivid_radio_rds_init(dev);
+       }
+       ts = timespec_sub(ts, dev->radio_rds_init_ts);
+       blk = ts.tv_sec * 100 + ts.tv_nsec / 10000000;
+       blk = (blk * VIVID_RDS_GEN_BLOCKS) / 500;
+       if (blk >= dev->radio_rx_rds_last_block + VIVID_RDS_GEN_BLOCKS)
+               dev->radio_rx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1;
+
+       /*
+        * No data is available if there hasn't been time to get new data,
+        * or if the RDS receiver has been disabled, or if we use the data
+        * from the RDS transmitter and that RDS transmitter has been disabled,
+        * or if the signal quality is too weak.
+        */
+       if (blk == dev->radio_rx_rds_last_block || !dev->radio_rx_rds_enabled ||
+           (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) ||
+           abs(dev->radio_rx_sig_qual) > 200) {
+               mutex_unlock(&dev->mutex);
+               if (file->f_flags & O_NONBLOCK)
+                       return -EWOULDBLOCK;
+               if (msleep_interruptible(20) && signal_pending(current))
+                       return -EINTR;
+               if (mutex_lock_interruptible(&dev->mutex))
+                       return -ERESTARTSYS;
+               goto retry;
+       }
+
+       /* abs(dev->radio_rx_sig_qual) <= 200, map that to a 0-50% range */
+       perc = abs(dev->radio_rx_sig_qual) / 4;
+
+       for (i = 0; i < size && blk > dev->radio_rx_rds_last_block;
+                       dev->radio_rx_rds_last_block++) {
+               unsigned data_blk = dev->radio_rx_rds_last_block % VIVID_RDS_GEN_BLOCKS;
+               struct v4l2_rds_data rds = data[data_blk];
+
+               if (data_blk == 0 && dev->radio_rds_loop)
+                       vivid_radio_rds_init(dev);
+               if (perc && prandom_u32_max(100) < perc) {
+                       switch (prandom_u32_max(4)) {
+                       case 0:
+                               rds.block |= V4L2_RDS_BLOCK_CORRECTED;
+                               break;
+                       case 1:
+                               rds.block |= V4L2_RDS_BLOCK_INVALID;
+                               break;
+                       case 2:
+                               rds.block |= V4L2_RDS_BLOCK_ERROR;
+                               rds.lsb = prandom_u32_max(256);
+                               rds.msb = prandom_u32_max(256);
+                               break;
+                       case 3: /* Skip block altogether */
+                               if (i)
+                                       continue;
+                               /*
+                                * Must make sure at least one block is
+                                * returned, otherwise the application
+                                * might think that end-of-file occurred.
+                                */
+                               break;
+                       }
+               }
+               if (copy_to_user(buf + i, &rds, sizeof(rds))) {
+                       i = -EFAULT;
+                       break;
+               }
+               i += sizeof(rds);
+       }
+       mutex_unlock(&dev->mutex);
+       return i;
+}
+
+unsigned int vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait)
+{
+       return POLLIN | POLLRDNORM | v4l2_ctrl_poll(file, wait);
+}
+
+int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band)
+{
+       if (band->tuner != 0)
+               return -EINVAL;
+
+       if (band->index >= TOT_BANDS)
+               return -EINVAL;
+
+       *band = vivid_radio_bands[band->index];
+       return 0;
+}
+
+int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       unsigned low, high;
+       unsigned freq;
+       unsigned spacing;
+       unsigned band;
+
+       if (a->tuner)
+               return -EINVAL;
+       if (a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_BOUNDED)
+               return -EINVAL;
+
+       if (!a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_WRAP)
+               return -EINVAL;
+       if (!a->rangelow ^ !a->rangehigh)
+               return -EINVAL;
+
+       if (file->f_flags & O_NONBLOCK)
+               return -EWOULDBLOCK;
+
+       if (a->rangelow) {
+               for (band = 0; band < TOT_BANDS; band++)
+                       if (a->rangelow >= vivid_radio_bands[band].rangelow &&
+                           a->rangehigh <= vivid_radio_bands[band].rangehigh)
+                               break;
+               if (band == TOT_BANDS)
+                       return -EINVAL;
+               if (!dev->radio_rx_hw_seek_prog_lim &&
+                   (a->rangelow != vivid_radio_bands[band].rangelow ||
+                    a->rangehigh != vivid_radio_bands[band].rangehigh))
+                       return -EINVAL;
+               low = a->rangelow;
+               high = a->rangehigh;
+       } else {
+               for (band = 0; band < TOT_BANDS; band++)
+                       if (dev->radio_rx_freq >= vivid_radio_bands[band].rangelow &&
+                           dev->radio_rx_freq <= vivid_radio_bands[band].rangehigh)
+                               break;
+               low = vivid_radio_bands[band].rangelow;
+               high = vivid_radio_bands[band].rangehigh;
+       }
+       spacing = band == BAND_AM ? 1600 : 16000;
+       freq = clamp(dev->radio_rx_freq, low, high);
+
+       if (a->seek_upward) {
+               freq = spacing * (freq / spacing) + spacing;
+               if (freq > high) {
+                       if (!a->wrap_around)
+                               return -ENODATA;
+                       freq = spacing * (low / spacing) + spacing;
+                       if (freq >= dev->radio_rx_freq)
+                               return -ENODATA;
+               }
+       } else {
+               freq = spacing * ((freq + spacing - 1) / spacing) - spacing;
+               if (freq < low) {
+                       if (!a->wrap_around)
+                               return -ENODATA;
+                       freq = spacing * ((high + spacing - 1) / spacing) - spacing;
+                       if (freq <= dev->radio_rx_freq)
+                               return -ENODATA;
+               }
+       }
+       return 0;
+}
+
+int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       int delta = 800;
+       int sig_qual;
+
+       if (vt->index > 0)
+               return -EINVAL;
+
+       strlcpy(vt->name, "AM/FM/SW Receiver", sizeof(vt->name));
+       vt->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+                        V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS |
+                        (dev->radio_rx_rds_controls ?
+                               V4L2_TUNER_CAP_RDS_CONTROLS :
+                               V4L2_TUNER_CAP_RDS_BLOCK_IO) |
+                        (dev->radio_rx_hw_seek_prog_lim ?
+                               V4L2_TUNER_CAP_HWSEEK_PROG_LIM : 0);
+       switch (dev->radio_rx_hw_seek_mode) {
+       case VIVID_HW_SEEK_BOUNDED:
+               vt->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED;
+               break;
+       case VIVID_HW_SEEK_WRAP:
+               vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP;
+               break;
+       case VIVID_HW_SEEK_BOTH:
+               vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP |
+                                 V4L2_TUNER_CAP_HWSEEK_BOUNDED;
+               break;
+       }
+       vt->rangelow = AM_FREQ_RANGE_LOW;
+       vt->rangehigh = FM_FREQ_RANGE_HIGH;
+       sig_qual = dev->radio_rx_sig_qual;
+       vt->signal = abs(sig_qual) > delta ? 0 :
+                    0xffff - (abs(sig_qual) * 0xffff) / delta;
+       vt->afc = sig_qual > delta ? 0 : sig_qual;
+       if (abs(sig_qual) > delta)
+               vt->rxsubchans = 0;
+       else if (dev->radio_rx_freq < FM_FREQ_RANGE_LOW || vt->signal < 0x8000)
+               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+       else if (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_STEREO))
+               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+       else
+               vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+       if (dev->radio_rx_rds_enabled &&
+           (!dev->radio_rds_loop || (dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) &&
+           dev->radio_rx_freq >= FM_FREQ_RANGE_LOW && vt->signal >= 0xc000)
+               vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
+       if (dev->radio_rx_rds_controls)
+               vivid_radio_rds_init(dev);
+       vt->audmode = dev->radio_rx_audmode;
+       return 0;
+}
+
+int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (vt->index)
+               return -EINVAL;
+       dev->radio_rx_audmode = vt->audmode >= V4L2_TUNER_MODE_STEREO;
+       return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-radio-rx.h b/drivers/media/platform/vivid/vivid-radio-rx.h
new file mode 100644 (file)
index 0000000..1077d8f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * vivid-radio-rx.h - radio receiver support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_RADIO_RX_H_
+#define _VIVID_RADIO_RX_H_
+
+ssize_t vivid_radio_rx_read(struct file *, char __user *, size_t, loff_t *);
+unsigned int vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait);
+
+int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band);
+int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a);
+int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt);
+int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.c b/drivers/media/platform/vivid/vivid-radio-tx.c
new file mode 100644 (file)
index 0000000..8c59d4f
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * vivid-radio-tx.c - radio transmitter support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-radio-common.h"
+#include "vivid-radio-tx.h"
+
+ssize_t vivid_radio_tx_write(struct file *file, const char __user *buf,
+                         size_t size, loff_t *offset)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_rds_data *data = dev->rds_gen.data;
+       struct timespec ts;
+       unsigned blk;
+       int i;
+
+       if (dev->radio_tx_rds_controls)
+               return -EINVAL;
+
+       if (size < sizeof(*data))
+               return -EINVAL;
+       size = sizeof(*data) * (size / sizeof(*data));
+
+       if (mutex_lock_interruptible(&dev->mutex))
+               return -ERESTARTSYS;
+       if (dev->radio_tx_rds_owner &&
+           file->private_data != dev->radio_tx_rds_owner) {
+               mutex_unlock(&dev->mutex);
+               return -EBUSY;
+       }
+       dev->radio_tx_rds_owner = file->private_data;
+
+retry:
+       ktime_get_ts(&ts);
+       ts = timespec_sub(ts, dev->radio_rds_init_ts);
+       blk = ts.tv_sec * 100 + ts.tv_nsec / 10000000;
+       blk = (blk * VIVID_RDS_GEN_BLOCKS) / 500;
+       if (blk - VIVID_RDS_GEN_BLOCKS >= dev->radio_tx_rds_last_block)
+               dev->radio_tx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1;
+
+       /*
+        * No data is available if there hasn't been time to get new data,
+        * or if the RDS receiver has been disabled, or if we use the data
+        * from the RDS transmitter and that RDS transmitter has been disabled,
+        * or if the signal quality is too weak.
+        */
+       if (blk == dev->radio_tx_rds_last_block ||
+           !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) {
+               mutex_unlock(&dev->mutex);
+               if (file->f_flags & O_NONBLOCK)
+                       return -EWOULDBLOCK;
+               if (msleep_interruptible(20) && signal_pending(current))
+                       return -EINTR;
+               if (mutex_lock_interruptible(&dev->mutex))
+                       return -ERESTARTSYS;
+               goto retry;
+       }
+
+       for (i = 0; i < size && blk > dev->radio_tx_rds_last_block;
+                       dev->radio_tx_rds_last_block++) {
+               unsigned data_blk = dev->radio_tx_rds_last_block % VIVID_RDS_GEN_BLOCKS;
+               struct v4l2_rds_data rds;
+
+               if (copy_from_user(&rds, buf + i, sizeof(rds))) {
+                       i = -EFAULT;
+                       break;
+               }
+               i += sizeof(rds);
+               if (!dev->radio_rds_loop)
+                       continue;
+               if ((rds.block & V4L2_RDS_BLOCK_MSK) == V4L2_RDS_BLOCK_INVALID ||
+                   (rds.block & V4L2_RDS_BLOCK_ERROR))
+                       continue;
+               rds.block &= V4L2_RDS_BLOCK_MSK;
+               data[data_blk] = rds;
+       }
+       mutex_unlock(&dev->mutex);
+       return i;
+}
+
+unsigned int vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait)
+{
+       return POLLOUT | POLLWRNORM | v4l2_ctrl_poll(file, wait);
+}
+
+int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (a->index > 0)
+               return -EINVAL;
+
+       strlcpy(a->name, "AM/FM/SW Transmitter", sizeof(a->name));
+       a->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+                       V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS |
+                       (dev->radio_tx_rds_controls ?
+                               V4L2_TUNER_CAP_RDS_CONTROLS :
+                               V4L2_TUNER_CAP_RDS_BLOCK_IO);
+       a->rangelow = AM_FREQ_RANGE_LOW;
+       a->rangehigh = FM_FREQ_RANGE_HIGH;
+       a->txsubchans = dev->radio_tx_subchans;
+       return 0;
+}
+
+int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (a->index)
+               return -EINVAL;
+       if (a->txsubchans & ~0x13)
+               return -EINVAL;
+       dev->radio_tx_subchans = a->txsubchans;
+       return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.h b/drivers/media/platform/vivid/vivid-radio-tx.h
new file mode 100644 (file)
index 0000000..7f8ff75
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * vivid-radio-tx.h - radio transmitter support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_RADIO_TX_H_
+#define _VIVID_RADIO_TX_H_
+
+ssize_t vivid_radio_tx_write(struct file *, const char __user *, size_t, loff_t *);
+unsigned int vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait);
+
+int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a);
+int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c
new file mode 100644 (file)
index 0000000..c382343
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * vivid-rds-gen.c - rds (radio data system) generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+
+#include "vivid-rds-gen.h"
+
+static u8 vivid_get_di(const struct vivid_rds_gen *rds, unsigned grp)
+{
+       switch (grp) {
+       case 0:
+               return (rds->dyn_pty << 2) | (grp & 3);
+       case 1:
+               return (rds->compressed << 2) | (grp & 3);
+       case 2:
+               return (rds->art_head << 2) | (grp & 3);
+       case 3:
+               return (rds->mono_stereo << 2) | (grp & 3);
+       }
+       return 0;
+}
+
+/*
+ * This RDS generator creates 57 RDS groups (one group == four RDS blocks).
+ * Groups 0-3, 22-25 and 44-47 (spaced 22 groups apart) are filled with a
+ * standard 0B group containing the PI code and PS name.
+ *
+ * Groups 4-19 and 26-41 use group 2A for the radio text.
+ *
+ * Group 56 contains the time (group 4A).
+ *
+ * All remaining groups use a filler group 15B block that just repeats
+ * the PI and PTY codes.
+ */
+void vivid_rds_generate(struct vivid_rds_gen *rds)
+{
+       struct v4l2_rds_data *data = rds->data;
+       unsigned grp;
+       struct tm tm;
+       unsigned date;
+       unsigned time;
+       int l;
+
+       for (grp = 0; grp < VIVID_RDS_GEN_GROUPS; grp++, data += VIVID_RDS_GEN_BLKS_PER_GRP) {
+               data[0].lsb = rds->picode & 0xff;
+               data[0].msb = rds->picode >> 8;
+               data[0].block = V4L2_RDS_BLOCK_A | (V4L2_RDS_BLOCK_A << 3);
+               data[1].lsb = rds->pty << 5;
+               data[1].msb = (rds->pty >> 3) | (rds->tp << 2);
+               data[1].block = V4L2_RDS_BLOCK_B | (V4L2_RDS_BLOCK_B << 3);
+               data[3].block = V4L2_RDS_BLOCK_D | (V4L2_RDS_BLOCK_D << 3);
+
+               switch (grp) {
+               case 0 ... 3:
+               case 22 ... 25:
+               case 44 ... 47: /* Group 0B */
+                       data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
+                       data[1].lsb |= vivid_get_di(rds, grp % 22);
+                       data[1].msb |= 1 << 3;
+                       data[2].lsb = rds->picode & 0xff;
+                       data[2].msb = rds->picode >> 8;
+                       data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
+                       data[3].lsb = rds->psname[2 * (grp % 22) + 1];
+                       data[3].msb = rds->psname[2 * (grp % 22)];
+                       break;
+               case 4 ... 19:
+               case 26 ... 41: /* Group 2A */
+                       data[1].lsb |= (grp - 4) % 22;
+                       data[1].msb |= 4 << 3;
+                       data[2].msb = rds->radiotext[4 * ((grp - 4) % 22)];
+                       data[2].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 1];
+                       data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
+                       data[3].msb = rds->radiotext[4 * ((grp - 4) % 22) + 2];
+                       data[3].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 3];
+                       break;
+               case 56:
+                       /*
+                        * Group 4A
+                        *
+                        * Uses the algorithm from Annex G of the RDS standard
+                        * EN 50067:1998 to convert a UTC date to an RDS Modified
+                        * Julian Day.
+                        */
+                       time_to_tm(get_seconds(), 0, &tm);
+                       l = tm.tm_mon <= 1;
+                       date = 14956 + tm.tm_mday + ((tm.tm_year - l) * 1461) / 4 +
+                               ((tm.tm_mon + 2 + l * 12) * 306001) / 10000;
+                       time = (tm.tm_hour << 12) |
+                              (tm.tm_min << 6) |
+                              (sys_tz.tz_minuteswest >= 0 ? 0x20 : 0) |
+                              (abs(sys_tz.tz_minuteswest) / 30);
+                       data[1].lsb &= ~3;
+                       data[1].lsb |= date >> 15;
+                       data[1].msb |= 8 << 3;
+                       data[2].lsb = (date << 1) & 0xfe;
+                       data[2].lsb |= (time >> 16) & 1;
+                       data[2].msb = (date >> 7) & 0xff;
+                       data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
+                       data[3].lsb = time & 0xff;
+                       data[3].msb = (time >> 8) & 0xff;
+                       break;
+               default: /* Group 15B */
+                       data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
+                       data[1].lsb |= vivid_get_di(rds, grp % 22);
+                       data[1].msb |= 0x1f << 3;
+                       data[2].lsb = rds->picode & 0xff;
+                       data[2].msb = rds->picode >> 8;
+                       data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
+                       data[3].lsb = rds->pty << 5;
+                       data[3].lsb |= (rds->ta << 4) | (rds->ms << 3);
+                       data[3].lsb |= vivid_get_di(rds, grp % 22);
+                       data[3].msb |= rds->pty >> 3;
+                       data[3].msb |= 0x1f << 3;
+                       break;
+               }
+       }
+}
+
+void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq,
+                         bool alt)
+{
+       /* Alternate PTY between Info and Weather */
+       if (rds->use_rbds) {
+               rds->picode = 0x2e75; /* 'KLNX' call sign */
+               rds->pty = alt ? 29 : 2;
+       } else {
+               rds->picode = 0x8088;
+               rds->pty = alt ? 16 : 3;
+       }
+       rds->mono_stereo = true;
+       rds->art_head = false;
+       rds->compressed = false;
+       rds->dyn_pty = false;
+       rds->tp = true;
+       rds->ta = alt;
+       rds->ms = true;
+       snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d",
+                freq / 16, ((freq & 0xf) * 10) / 16);
+       if (alt)
+               strlcpy(rds->radiotext,
+                       " The Radio Data System can switch between different Radio Texts ",
+                       sizeof(rds->radiotext));
+       else
+               strlcpy(rds->radiotext,
+                       "An example of Radio Text as transmitted by the Radio Data System",
+                       sizeof(rds->radiotext));
+}
diff --git a/drivers/media/platform/vivid/vivid-rds-gen.h b/drivers/media/platform/vivid/vivid-rds-gen.h
new file mode 100644 (file)
index 0000000..eff4bf5
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * vivid-rds-gen.h - rds (radio data system) generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_RDS_GEN_H_
+#define _VIVID_RDS_GEN_H_
+
+/*
+ * It takes almost exactly 5 seconds to transmit 57 RDS groups.
+ * Each group has 4 blocks and each block has a payload of 16 bits + a
+ * block identification. The driver will generate the contents of these
+ * 57 groups only when necessary and it will just be played continuously.
+ */
+#define VIVID_RDS_GEN_GROUPS 57
+#define VIVID_RDS_GEN_BLKS_PER_GRP 4
+#define VIVID_RDS_GEN_BLOCKS (VIVID_RDS_GEN_BLKS_PER_GRP * VIVID_RDS_GEN_GROUPS)
+
+struct vivid_rds_gen {
+       struct v4l2_rds_data    data[VIVID_RDS_GEN_BLOCKS];
+       bool                    use_rbds;
+       u16                     picode;
+       u8                      pty;
+       bool                    mono_stereo;
+       bool                    art_head;
+       bool                    compressed;
+       bool                    dyn_pty;
+       bool                    ta;
+       bool                    tp;
+       bool                    ms;
+       char                    psname[8 + 1];
+       char                    radiotext[64 + 1];
+};
+
+void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq,
+                   bool use_alternate);
+void vivid_rds_generate(struct vivid_rds_gen *rds);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c
new file mode 100644 (file)
index 0000000..8c5d661
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+ * vivid-sdr-cap.c - software defined radio support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-sdr-cap.h"
+
+static const struct v4l2_frequency_band bands_adc[] = {
+       {
+               .tuner = 0,
+               .type = V4L2_TUNER_ADC,
+               .index = 0,
+               .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   =  300000,
+               .rangehigh  =  300000,
+       },
+       {
+               .tuner = 0,
+               .type = V4L2_TUNER_ADC,
+               .index = 1,
+               .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   =  900001,
+               .rangehigh  = 2800000,
+       },
+       {
+               .tuner = 0,
+               .type = V4L2_TUNER_ADC,
+               .index = 2,
+               .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   = 3200000,
+               .rangehigh  = 3200000,
+       },
+};
+
+/* ADC band midpoints */
+#define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2)
+#define BAND_ADC_1 ((bands_adc[1].rangehigh + bands_adc[2].rangelow) / 2)
+
+static const struct v4l2_frequency_band bands_fm[] = {
+       {
+               .tuner = 1,
+               .type = V4L2_TUNER_RF,
+               .index = 0,
+               .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   =    50000000,
+               .rangehigh  =  2000000000,
+       },
+};
+
+static void vivid_thread_sdr_cap_tick(struct vivid_dev *dev)
+{
+       struct vivid_buffer *sdr_cap_buf = NULL;
+
+       dprintk(dev, 1, "SDR Capture Thread Tick\n");
+
+       /* Drop a certain percentage of buffers. */
+       if (dev->perc_dropped_buffers &&
+           prandom_u32_max(100) < dev->perc_dropped_buffers)
+               return;
+
+       spin_lock(&dev->slock);
+       if (!list_empty(&dev->sdr_cap_active)) {
+               sdr_cap_buf = list_entry(dev->sdr_cap_active.next,
+                                        struct vivid_buffer, list);
+               list_del(&sdr_cap_buf->list);
+       }
+       spin_unlock(&dev->slock);
+
+       if (sdr_cap_buf) {
+               sdr_cap_buf->vb.v4l2_buf.sequence = dev->sdr_cap_seq_count;
+               vivid_sdr_cap_process(dev, sdr_cap_buf);
+               v4l2_get_timestamp(&sdr_cap_buf->vb.v4l2_buf.timestamp);
+               sdr_cap_buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+               vb2_buffer_done(&sdr_cap_buf->vb, dev->dqbuf_error ?
+                               VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+               dev->dqbuf_error = false;
+       }
+}
+
+static int vivid_thread_sdr_cap(void *data)
+{
+       struct vivid_dev *dev = data;
+       u64 samples_since_start;
+       u64 buffers_since_start;
+       u64 next_jiffies_since_start;
+       unsigned long jiffies_since_start;
+       unsigned long cur_jiffies;
+       unsigned wait_jiffies;
+
+       dprintk(dev, 1, "SDR Capture Thread Start\n");
+
+       set_freezable();
+
+       /* Resets frame counters */
+       dev->sdr_cap_seq_offset = 0;
+       if (dev->seq_wrap)
+               dev->sdr_cap_seq_offset = 0xffffff80U;
+       dev->jiffies_sdr_cap = jiffies;
+       dev->sdr_cap_seq_resync = false;
+
+       for (;;) {
+               try_to_freeze();
+               if (kthread_should_stop())
+                       break;
+
+               mutex_lock(&dev->mutex);
+               cur_jiffies = jiffies;
+               if (dev->sdr_cap_seq_resync) {
+                       dev->jiffies_sdr_cap = cur_jiffies;
+                       dev->sdr_cap_seq_offset = dev->sdr_cap_seq_count + 1;
+                       dev->sdr_cap_seq_count = 0;
+                       dev->sdr_cap_seq_resync = false;
+               }
+               /* Calculate the number of jiffies since we started streaming */
+               jiffies_since_start = cur_jiffies - dev->jiffies_sdr_cap;
+               /* Get the number of buffers streamed since the start */
+               buffers_since_start = (u64)jiffies_since_start * dev->sdr_adc_freq +
+                                     (HZ * SDR_CAP_SAMPLES_PER_BUF) / 2;
+               do_div(buffers_since_start, HZ * SDR_CAP_SAMPLES_PER_BUF);
+
+               /*
+                * After more than 0xf0000000 (rounded down to a multiple of
+                * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
+                * jiffies have passed since we started streaming reset the
+                * counters and keep track of the sequence offset.
+                */
+               if (jiffies_since_start > JIFFIES_RESYNC) {
+                       dev->jiffies_sdr_cap = cur_jiffies;
+                       dev->sdr_cap_seq_offset = buffers_since_start;
+                       buffers_since_start = 0;
+               }
+               dev->sdr_cap_seq_count = buffers_since_start + dev->sdr_cap_seq_offset;
+
+               vivid_thread_sdr_cap_tick(dev);
+               mutex_unlock(&dev->mutex);
+
+               /*
+                * Calculate the number of samples streamed since we started,
+                * not including the current buffer.
+                */
+               samples_since_start = buffers_since_start * SDR_CAP_SAMPLES_PER_BUF;
+
+               /* And the number of jiffies since we started */
+               jiffies_since_start = jiffies - dev->jiffies_sdr_cap;
+
+               /* Increase by the number of samples in one buffer */
+               samples_since_start += SDR_CAP_SAMPLES_PER_BUF;
+               /*
+                * Calculate when that next buffer is supposed to start
+                * in jiffies since we started streaming.
+                */
+               next_jiffies_since_start = samples_since_start * HZ +
+                                          dev->sdr_adc_freq / 2;
+               do_div(next_jiffies_since_start, dev->sdr_adc_freq);
+               /* If it is in the past, then just schedule asap */
+               if (next_jiffies_since_start < jiffies_since_start)
+                       next_jiffies_since_start = jiffies_since_start;
+
+               wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+               schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
+       }
+       dprintk(dev, 1, "SDR Capture Thread End\n");
+       return 0;
+}
+
+static int sdr_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                      unsigned *nbuffers, unsigned *nplanes,
+                      unsigned sizes[], void *alloc_ctxs[])
+{
+       /* 2 = max 16-bit sample returned */
+       sizes[0] = SDR_CAP_SAMPLES_PER_BUF * 2;
+       *nplanes = 1;
+       return 0;
+}
+
+static int sdr_cap_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       unsigned size = SDR_CAP_SAMPLES_PER_BUF * 2;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->buf_prepare_error) {
+               /*
+                * Error injection: test what happens if buf_prepare() returns
+                * an error.
+                */
+               dev->buf_prepare_error = false;
+               return -EINVAL;
+       }
+       if (vb2_plane_size(vb, 0) < size) {
+               dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+                               __func__, vb2_plane_size(vb, 0), size);
+               return -EINVAL;
+       }
+       vb2_set_plane_payload(vb, 0, size);
+
+       return 0;
+}
+
+static void sdr_cap_buf_queue(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       spin_lock(&dev->slock);
+       list_add_tail(&buf->list, &dev->sdr_cap_active);
+       spin_unlock(&dev->slock);
+}
+
+static int sdr_cap_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       int err = 0;
+
+       dprintk(dev, 1, "%s\n", __func__);
+       dev->sdr_cap_seq_count = 0;
+       if (dev->start_streaming_error) {
+               dev->start_streaming_error = false;
+               err = -EINVAL;
+       } else if (dev->kthread_sdr_cap == NULL) {
+               dev->kthread_sdr_cap = kthread_run(vivid_thread_sdr_cap, dev,
+                               "%s-sdr-cap", dev->v4l2_dev.name);
+
+               if (IS_ERR(dev->kthread_sdr_cap)) {
+                       v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+                       err = PTR_ERR(dev->kthread_sdr_cap);
+                       dev->kthread_sdr_cap = NULL;
+               }
+       }
+       if (err) {
+               struct vivid_buffer *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &dev->sdr_cap_active, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+       return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void sdr_cap_stop_streaming(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       if (dev->kthread_sdr_cap == NULL)
+               return;
+
+       while (!list_empty(&dev->sdr_cap_active)) {
+               struct vivid_buffer *buf;
+
+               buf = list_entry(dev->sdr_cap_active.next, struct vivid_buffer, list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+
+       /* shutdown control thread */
+       mutex_unlock(&dev->mutex);
+       kthread_stop(dev->kthread_sdr_cap);
+       dev->kthread_sdr_cap = NULL;
+       mutex_lock(&dev->mutex);
+}
+
+const struct vb2_ops vivid_sdr_cap_qops = {
+       .queue_setup            = sdr_cap_queue_setup,
+       .buf_prepare            = sdr_cap_buf_prepare,
+       .buf_queue              = sdr_cap_buf_queue,
+       .start_streaming        = sdr_cap_start_streaming,
+       .stop_streaming         = sdr_cap_stop_streaming,
+       .wait_prepare           = vivid_unlock,
+       .wait_finish            = vivid_lock,
+};
+
+int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band)
+{
+       switch (band->tuner) {
+       case 0:
+               if (band->index >= ARRAY_SIZE(bands_adc))
+                       return -EINVAL;
+               *band = bands_adc[band->index];
+               return 0;
+       case 1:
+               if (band->index >= ARRAY_SIZE(bands_fm))
+                       return -EINVAL;
+               *band = bands_fm[band->index];
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       switch (vf->tuner) {
+       case 0:
+               vf->frequency = dev->sdr_adc_freq;
+               vf->type = V4L2_TUNER_ADC;
+               return 0;
+       case 1:
+               vf->frequency = dev->sdr_fm_freq;
+               vf->type = V4L2_TUNER_RF;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       unsigned freq = vf->frequency;
+       unsigned band;
+
+       switch (vf->tuner) {
+       case 0:
+               if (vf->type != V4L2_TUNER_ADC)
+                       return -EINVAL;
+               if (freq < BAND_ADC_0)
+                       band = 0;
+               else if (freq < BAND_ADC_1)
+                       band = 1;
+               else
+                       band = 2;
+
+               freq = clamp_t(unsigned, freq,
+                               bands_adc[band].rangelow,
+                               bands_adc[band].rangehigh);
+
+               if (vb2_is_streaming(&dev->vb_sdr_cap_q) &&
+                   freq != dev->sdr_adc_freq) {
+                       /* resync the thread's timings */
+                       dev->sdr_cap_seq_resync = true;
+               }
+               dev->sdr_adc_freq = freq;
+               return 0;
+       case 1:
+               if (vf->type != V4L2_TUNER_RF)
+                       return -EINVAL;
+               dev->sdr_fm_freq = clamp_t(unsigned, freq,
+                               bands_fm[0].rangelow,
+                               bands_fm[0].rangehigh);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+       switch (vt->index) {
+       case 0:
+               strlcpy(vt->name, "ADC", sizeof(vt->name));
+               vt->type = V4L2_TUNER_ADC;
+               vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+               vt->rangelow = bands_adc[0].rangelow;
+               vt->rangehigh = bands_adc[2].rangehigh;
+               return 0;
+       case 1:
+               strlcpy(vt->name, "RF", sizeof(vt->name));
+               vt->type = V4L2_TUNER_RF;
+               vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+               vt->rangelow = bands_fm[0].rangelow;
+               vt->rangehigh = bands_fm[0].rangehigh;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
+{
+       if (vt->index > 1)
+               return -EINVAL;
+       return 0;
+}
+
+int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+       if (f->index)
+               return -EINVAL;
+       f->pixelformat = V4L2_SDR_FMT_CU8;
+       strlcpy(f->description, "IQ U8", sizeof(f->description));
+       return 0;
+}
+
+int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+       f->fmt.sdr.pixelformat = V4L2_SDR_FMT_CU8;
+       f->fmt.sdr.buffersize = SDR_CAP_SAMPLES_PER_BUF * 2;
+       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+       return 0;
+}
+
+#define FIXP_FRAC    (1 << 15)
+#define FIXP_PI      ((int)(FIXP_FRAC * 3.141592653589))
+
+/* cos() from cx88 driver: cx88-dsp.c */
+static s32 fixp_cos(unsigned int x)
+{
+       u32 t2, t4, t6, t8;
+       u16 period = x / FIXP_PI;
+
+       if (period % 2)
+               return -fixp_cos(x - FIXP_PI);
+       x = x % FIXP_PI;
+       if (x > FIXP_PI/2)
+               return -fixp_cos(FIXP_PI/2 - (x % (FIXP_PI/2)));
+       /* Now x is between 0 and FIXP_PI/2.
+        * To calculate cos(x) we use it's Taylor polinom. */
+       t2 = x*x/FIXP_FRAC/2;
+       t4 = t2*x/FIXP_FRAC*x/FIXP_FRAC/3/4;
+       t6 = t4*x/FIXP_FRAC*x/FIXP_FRAC/5/6;
+       t8 = t6*x/FIXP_FRAC*x/FIXP_FRAC/7/8;
+       return FIXP_FRAC-t2+t4-t6+t8;
+}
+
+static inline s32 fixp_sin(unsigned int x)
+{
+       return -fixp_cos(x + (FIXP_PI / 2));
+}
+
+void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+       u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+       unsigned long i;
+       unsigned long plane_size = vb2_plane_size(&buf->vb, 0);
+       int fixp_src_phase_step, fixp_i, fixp_q;
+
+       /*
+        * TODO: Generated beep tone goes very crackly when sample rate is
+        * increased to ~1Msps or more. That is because of huge rounding error
+        * of phase angle caused by used cosine implementation.
+        */
+
+       /* calculate phase step */
+       #define BEEP_FREQ 1000 /* 1kHz beep */
+       fixp_src_phase_step = DIV_ROUND_CLOSEST(2 * FIXP_PI * BEEP_FREQ,
+                       dev->sdr_adc_freq);
+
+       for (i = 0; i < plane_size; i += 2) {
+               dev->sdr_fixp_mod_phase += fixp_cos(dev->sdr_fixp_src_phase);
+               dev->sdr_fixp_src_phase += fixp_src_phase_step;
+
+               /*
+                * Transfer phases to [0 / 2xPI] in order to avoid variable
+                * overflow and make it suitable for cosine implementation
+                * used, which does not support negative angles.
+                */
+               while (dev->sdr_fixp_mod_phase < (0 * FIXP_PI))
+                       dev->sdr_fixp_mod_phase += (2 * FIXP_PI);
+               while (dev->sdr_fixp_mod_phase > (2 * FIXP_PI))
+                       dev->sdr_fixp_mod_phase -= (2 * FIXP_PI);
+
+               while (dev->sdr_fixp_src_phase > (2 * FIXP_PI))
+                       dev->sdr_fixp_src_phase -= (2 * FIXP_PI);
+
+               fixp_i = fixp_cos(dev->sdr_fixp_mod_phase);
+               fixp_q = fixp_sin(dev->sdr_fixp_mod_phase);
+
+               /* convert 'fixp float' to u8 */
+               /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */
+               fixp_i = fixp_i * 1275 + FIXP_FRAC * 1275;
+               fixp_q = fixp_q * 1275 + FIXP_FRAC * 1275;
+               *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10);
+               *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10);
+       }
+}
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.h b/drivers/media/platform/vivid/vivid-sdr-cap.h
new file mode 100644 (file)
index 0000000..79c1890
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * vivid-sdr-cap.h - software defined radio support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_SDR_CAP_H_
+#define _VIVID_SDR_CAP_H_
+
+int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band);
+int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf);
+int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt);
+int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt);
+int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f);
+int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f);
+void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+
+extern const struct vb2_ops vivid_sdr_cap_qops;
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.c b/drivers/media/platform/vivid/vivid-tpg-colors.c
new file mode 100644 (file)
index 0000000..2adddc0
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * vivid-color.c - A table that converts colors to various colorspaces
+ *
+ * The test pattern generator uses the tpg_colors for its test patterns.
+ * For testing colorspaces the first 8 colors of that table need to be
+ * converted to their equivalent in the target colorspace.
+ *
+ * The tpg_csc_colors[] table is the result of that conversion and since
+ * it is precalculated the colorspace conversion is just a simple table
+ * lookup.
+ *
+ * This source also contains the code used to generate the tpg_csc_colors
+ * table. Run the following command to compile it:
+ *
+ *     gcc vivid-colors.c -DCOMPILE_APP -o gen-colors -lm
+ *
+ * and run the utility.
+ *
+ * Note that the converted colors are in the range 0x000-0xff0 (so times 16)
+ * in order to preserve precision.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/videodev2.h>
+
+#include "vivid-tpg-colors.h"
+
+/* sRGB colors with range [0-255] */
+const struct color tpg_colors[TPG_COLOR_MAX] = {
+       /*
+        * Colors to test colorspace conversion: converting these colors
+        * to other colorspaces will never lead to out-of-gamut colors.
+        */
+       { 191, 191, 191 }, /* TPG_COLOR_CSC_WHITE */
+       { 191, 191,  50 }, /* TPG_COLOR_CSC_YELLOW */
+       {  50, 191, 191 }, /* TPG_COLOR_CSC_CYAN */
+       {  50, 191,  50 }, /* TPG_COLOR_CSC_GREEN */
+       { 191,  50, 191 }, /* TPG_COLOR_CSC_MAGENTA */
+       { 191,  50,  50 }, /* TPG_COLOR_CSC_RED */
+       {  50,  50, 191 }, /* TPG_COLOR_CSC_BLUE */
+       {  50,  50,  50 }, /* TPG_COLOR_CSC_BLACK */
+
+       /* 75% colors */
+       { 191, 191,   0 }, /* TPG_COLOR_75_YELLOW */
+       {   0, 191, 191 }, /* TPG_COLOR_75_CYAN */
+       {   0, 191,   0 }, /* TPG_COLOR_75_GREEN */
+       { 191,   0, 191 }, /* TPG_COLOR_75_MAGENTA */
+       { 191,   0,   0 }, /* TPG_COLOR_75_RED */
+       {   0,   0, 191 }, /* TPG_COLOR_75_BLUE */
+
+       /* 100% colors */
+       { 255, 255, 255 }, /* TPG_COLOR_100_WHITE */
+       { 255, 255,   0 }, /* TPG_COLOR_100_YELLOW */
+       {   0, 255, 255 }, /* TPG_COLOR_100_CYAN */
+       {   0, 255,   0 }, /* TPG_COLOR_100_GREEN */
+       { 255,   0, 255 }, /* TPG_COLOR_100_MAGENTA */
+       { 255,   0,   0 }, /* TPG_COLOR_100_RED */
+       {   0,   0, 255 }, /* TPG_COLOR_100_BLUE */
+       {   0,   0,   0 }, /* TPG_COLOR_100_BLACK */
+
+       {   0,   0,   0 }, /* TPG_COLOR_RANDOM placeholder */
+};
+
+#ifndef COMPILE_APP
+
+/* Generated table */
+const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1] = {
+       [V4L2_COLORSPACE_SMPTE170M][0] = { 2953, 2939, 2939 },
+       [V4L2_COLORSPACE_SMPTE170M][1] = { 2954, 2963, 585 },
+       [V4L2_COLORSPACE_SMPTE170M][2] = { 84, 2967, 2937 },
+       [V4L2_COLORSPACE_SMPTE170M][3] = { 93, 2990, 575 },
+       [V4L2_COLORSPACE_SMPTE170M][4] = { 3030, 259, 2933 },
+       [V4L2_COLORSPACE_SMPTE170M][5] = { 3031, 406, 557 },
+       [V4L2_COLORSPACE_SMPTE170M][6] = { 544, 428, 2931 },
+       [V4L2_COLORSPACE_SMPTE170M][7] = { 551, 547, 547 },
+       [V4L2_COLORSPACE_SMPTE240M][0] = { 2926, 2926, 2926 },
+       [V4L2_COLORSPACE_SMPTE240M][1] = { 2926, 2926, 857 },
+       [V4L2_COLORSPACE_SMPTE240M][2] = { 1594, 2901, 2901 },
+       [V4L2_COLORSPACE_SMPTE240M][3] = { 1594, 2901, 774 },
+       [V4L2_COLORSPACE_SMPTE240M][4] = { 2484, 618, 2858 },
+       [V4L2_COLORSPACE_SMPTE240M][5] = { 2484, 618, 617 },
+       [V4L2_COLORSPACE_SMPTE240M][6] = { 507, 507, 2832 },
+       [V4L2_COLORSPACE_SMPTE240M][7] = { 507, 507, 507 },
+       [V4L2_COLORSPACE_REC709][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_REC709][1] = { 2939, 2939, 547 },
+       [V4L2_COLORSPACE_REC709][2] = { 547, 2939, 2939 },
+       [V4L2_COLORSPACE_REC709][3] = { 547, 2939, 547 },
+       [V4L2_COLORSPACE_REC709][4] = { 2939, 547, 2939 },
+       [V4L2_COLORSPACE_REC709][5] = { 2939, 547, 547 },
+       [V4L2_COLORSPACE_REC709][6] = { 547, 547, 2939 },
+       [V4L2_COLORSPACE_REC709][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][0] = { 2894, 2988, 2808 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][1] = { 2847, 3070, 843 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][2] = { 1656, 2962, 2783 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][3] = { 1572, 3045, 763 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][4] = { 2477, 229, 2743 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][5] = { 2422, 672, 614 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][6] = { 725, 63, 2718 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][7] = { 534, 561, 509 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][1] = { 2939, 2939, 621 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][2] = { 786, 2939, 2939 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][3] = { 786, 2939, 621 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][4] = { 2879, 547, 2923 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][5] = { 2879, 547, 547 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][6] = { 547, 547, 2923 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_SRGB][0] = { 3056, 3056, 3056 },
+       [V4L2_COLORSPACE_SRGB][1] = { 3056, 3056, 800 },
+       [V4L2_COLORSPACE_SRGB][2] = { 800, 3056, 3056 },
+       [V4L2_COLORSPACE_SRGB][3] = { 800, 3056, 800 },
+       [V4L2_COLORSPACE_SRGB][4] = { 3056, 800, 3056 },
+       [V4L2_COLORSPACE_SRGB][5] = { 3056, 800, 800 },
+       [V4L2_COLORSPACE_SRGB][6] = { 800, 800, 3056 },
+       [V4L2_COLORSPACE_SRGB][7] = { 800, 800, 800 },
+};
+
+#else
+
+/* This code generates the table above */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static const double rec709_to_ntsc1953[3][3] = {
+       { 0.6698, 0.2678,  0.0323 },
+       { 0.0185, 1.0742, -0.0603 },
+       { 0.0162, 0.0432,  0.8551 }
+};
+
+static const double rec709_to_ebu[3][3] = {
+       { 0.9578, 0.0422, 0      },
+       { 0     , 1     , 0      },
+       { 0     , 0.0118, 0.9882 }
+};
+
+static const double rec709_to_170m[3][3] = {
+       {  1.0654, -0.0554, -0.0010 },
+       { -0.0196,  1.0364, -0.0167 },
+       {  0.0016,  0.0044,  0.9940 }
+};
+
+static const double rec709_to_240m[3][3] = {
+       { 0.7151, 0.2849, 0      },
+       { 0.0179, 0.9821, 0      },
+       { 0.0177, 0.0472, 0.9350 }
+};
+
+
+static void mult_matrix(double *r, double *g, double *b, const double m[3][3])
+{
+       double ir, ig, ib;
+
+       ir = m[0][0] * (*r) + m[0][1] * (*g) + m[0][2] * (*b);
+       ig = m[1][0] * (*r) + m[1][1] * (*g) + m[1][2] * (*b);
+       ib = m[2][0] * (*r) + m[2][1] * (*g) + m[2][2] * (*b);
+       *r = ir;
+       *g = ig;
+       *b = ib;
+}
+
+static double transfer_srgb_to_rgb(double v)
+{
+       return (v <= 0.03928) ? v / 12.92 : pow((v + 0.055) / 1.055, 2.4);
+}
+
+static double transfer_rgb_to_smpte240m(double v)
+{
+       return (v <= 0.0228) ? v * 4.0 : 1.1115 * pow(v, 0.45) - 0.1115;
+}
+
+static double transfer_rgb_to_rec709(double v)
+{
+       return (v < 0.018) ? v * 4.5 : 1.099 * pow(v, 0.45) - 0.099;
+}
+
+static double transfer_srgb_to_rec709(double v)
+{
+       return transfer_rgb_to_rec709(transfer_srgb_to_rgb(v));
+}
+
+static void csc(enum v4l2_colorspace colorspace, double *r, double *g, double *b)
+{
+       /* Convert the primaries of Rec. 709 Linear RGB */
+       switch (colorspace) {
+       case V4L2_COLORSPACE_SMPTE240M:
+               *r = transfer_srgb_to_rgb(*r);
+               *g = transfer_srgb_to_rgb(*g);
+               *b = transfer_srgb_to_rgb(*b);
+               mult_matrix(r, g, b, rec709_to_240m);
+               break;
+       case V4L2_COLORSPACE_SMPTE170M:
+               *r = transfer_srgb_to_rgb(*r);
+               *g = transfer_srgb_to_rgb(*g);
+               *b = transfer_srgb_to_rgb(*b);
+               mult_matrix(r, g, b, rec709_to_170m);
+               break;
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               *r = transfer_srgb_to_rgb(*r);
+               *g = transfer_srgb_to_rgb(*g);
+               *b = transfer_srgb_to_rgb(*b);
+               mult_matrix(r, g, b, rec709_to_ebu);
+               break;
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+               *r = transfer_srgb_to_rgb(*r);
+               *g = transfer_srgb_to_rgb(*g);
+               *b = transfer_srgb_to_rgb(*b);
+               mult_matrix(r, g, b, rec709_to_ntsc1953);
+               break;
+       case V4L2_COLORSPACE_SRGB:
+       case V4L2_COLORSPACE_REC709:
+       default:
+               break;
+       }
+
+       *r = ((*r) < 0) ? 0 : (((*r) > 1) ? 1 : (*r));
+       *g = ((*g) < 0) ? 0 : (((*g) > 1) ? 1 : (*g));
+       *b = ((*b) < 0) ? 0 : (((*b) > 1) ? 1 : (*b));
+
+       /* Encode to gamma corrected colorspace */
+       switch (colorspace) {
+       case V4L2_COLORSPACE_SMPTE240M:
+               *r = transfer_rgb_to_smpte240m(*r);
+               *g = transfer_rgb_to_smpte240m(*g);
+               *b = transfer_rgb_to_smpte240m(*b);
+               break;
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               *r = transfer_rgb_to_rec709(*r);
+               *g = transfer_rgb_to_rec709(*g);
+               *b = transfer_rgb_to_rec709(*b);
+               break;
+       case V4L2_COLORSPACE_SRGB:
+               break;
+       case V4L2_COLORSPACE_REC709:
+       default:
+               *r = transfer_srgb_to_rec709(*r);
+               *g = transfer_srgb_to_rec709(*g);
+               *b = transfer_srgb_to_rec709(*b);
+               break;
+       }
+}
+
+int main(int argc, char **argv)
+{
+       static const unsigned colorspaces[] = {
+               0,
+               V4L2_COLORSPACE_SMPTE170M,
+               V4L2_COLORSPACE_SMPTE240M,
+               V4L2_COLORSPACE_REC709,
+               0,
+               V4L2_COLORSPACE_470_SYSTEM_M,
+               V4L2_COLORSPACE_470_SYSTEM_BG,
+               0,
+               V4L2_COLORSPACE_SRGB,
+       };
+       static const char * const colorspace_names[] = {
+               "",
+               "V4L2_COLORSPACE_SMPTE170M",
+               "V4L2_COLORSPACE_SMPTE240M",
+               "V4L2_COLORSPACE_REC709",
+               "",
+               "V4L2_COLORSPACE_470_SYSTEM_M",
+               "V4L2_COLORSPACE_470_SYSTEM_BG",
+               "",
+               "V4L2_COLORSPACE_SRGB",
+       };
+       int i;
+       int c;
+
+       printf("/* Generated table */\n");
+       printf("const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1] = {\n");
+       for (c = 0; c <= V4L2_COLORSPACE_SRGB; c++) {
+               for (i = 0; i <= TPG_COLOR_CSC_BLACK; i++) {
+                       double r, g, b;
+
+                       if (colorspaces[c] == 0)
+                               continue;
+
+                       r = tpg_colors[i].r / 255.0;
+                       g = tpg_colors[i].g / 255.0;
+                       b = tpg_colors[i].b / 255.0;
+
+                       csc(c, &r, &g, &b);
+
+                       printf("\t[%s][%d] = { %d, %d, %d },\n", colorspace_names[c], i,
+                               (int)(r * 4080), (int)(g * 4080), (int)(b * 4080));
+               }
+       }
+       printf("};\n\n");
+       return 0;
+}
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.h b/drivers/media/platform/vivid/vivid-tpg-colors.h
new file mode 100644 (file)
index 0000000..a2678fb
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * vivid-color.h - Color definitions for the test pattern generator
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_COLORS_H_
+#define _VIVID_COLORS_H_
+
+struct color {
+       unsigned char r, g, b;
+};
+
+struct color16 {
+       int r, g, b;
+};
+
+enum tpg_color {
+       TPG_COLOR_CSC_WHITE,
+       TPG_COLOR_CSC_YELLOW,
+       TPG_COLOR_CSC_CYAN,
+       TPG_COLOR_CSC_GREEN,
+       TPG_COLOR_CSC_MAGENTA,
+       TPG_COLOR_CSC_RED,
+       TPG_COLOR_CSC_BLUE,
+       TPG_COLOR_CSC_BLACK,
+       TPG_COLOR_75_YELLOW,
+       TPG_COLOR_75_CYAN,
+       TPG_COLOR_75_GREEN,
+       TPG_COLOR_75_MAGENTA,
+       TPG_COLOR_75_RED,
+       TPG_COLOR_75_BLUE,
+       TPG_COLOR_100_WHITE,
+       TPG_COLOR_100_YELLOW,
+       TPG_COLOR_100_CYAN,
+       TPG_COLOR_100_GREEN,
+       TPG_COLOR_100_MAGENTA,
+       TPG_COLOR_100_RED,
+       TPG_COLOR_100_BLUE,
+       TPG_COLOR_100_BLACK,
+       TPG_COLOR_TEXTFG,
+       TPG_COLOR_TEXTBG,
+       TPG_COLOR_RANDOM,
+       TPG_COLOR_RAMP,
+       TPG_COLOR_MAX = TPG_COLOR_RAMP + 256
+};
+
+extern const struct color tpg_colors[TPG_COLOR_MAX];
+extern const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1];
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c
new file mode 100644 (file)
index 0000000..0c6fa53
--- /dev/null
@@ -0,0 +1,1439 @@
+/*
+ * vivid-tpg.c - Test Pattern Generator
+ *
+ * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the
+ * vivi.c source for the copyright information of those functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "vivid-tpg.h"
+
+/* Must remain in sync with enum tpg_pattern */
+const char * const tpg_pattern_strings[] = {
+       "75% Colorbar",
+       "100% Colorbar",
+       "CSC Colorbar",
+       "Horizontal 100% Colorbar",
+       "100% Color Squares",
+       "100% Black",
+       "100% White",
+       "100% Red",
+       "100% Green",
+       "100% Blue",
+       "16x16 Checkers",
+       "1x1 Checkers",
+       "Alternating Hor Lines",
+       "Alternating Vert Lines",
+       "One Pixel Wide Cross",
+       "Two Pixels Wide Cross",
+       "Ten Pixels Wide Cross",
+       "Gray Ramp",
+       "Noise",
+       NULL
+};
+
+/* Must remain in sync with enum tpg_aspect */
+const char * const tpg_aspect_strings[] = {
+       "Source Width x Height",
+       "4x3",
+       "14x9",
+       "16x9",
+       "16x9 Anamorphic",
+       NULL
+};
+
+/*
+ * Sine table: sin[0] = 127 * sin(-180 degrees)
+ *             sin[128] = 127 * sin(0 degrees)
+ *             sin[256] = 127 * sin(180 degrees)
+ */
+static const s8 sin[257] = {
+          0,   -4,   -7,  -11,  -13,  -18,  -20,  -22,  -26,  -29,  -33,  -35,  -37,  -41,  -43,  -48,
+        -50,  -52,  -56,  -58,  -62,  -63,  -65,  -69,  -71,  -75,  -76,  -78,  -82,  -83,  -87,  -88,
+        -90,  -93,  -94,  -97,  -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
+       -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
+       -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
+       -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100,  -97,  -96,  -93,  -91,
+        -90,  -87,  -85,  -82,  -80,  -76,  -75,  -73,  -69,  -67,  -63,  -62,  -60,  -56,  -54,  -50,
+        -48,  -46,  -41,  -39,  -35,  -33,  -31,  -26,  -24,  -20,  -18,  -15,  -11,   -9,   -4,   -2,
+          0,    2,    4,    9,   11,   15,   18,   20,   24,   26,   31,   33,   35,   39,   41,   46,
+         48,   50,   54,   56,   60,   62,   64,   67,   69,   73,   75,   76,   80,   82,   85,   87,
+         90,   91,   93,   96,   97,  100,  101,  103,  105,  107,  109,  110,  111,  113,  114,  116,
+        117,  118,  119,  120,  121,  122,  123,  124,  124,  125,  125,  126,  126,  127,  127,  127,
+        127,  127,  127,  127,  127,  126,  126,  125,  125,  124,  123,  123,  122,  121,  120,  119,
+        118,  117,  115,  114,  112,  111,  110,  108,  107,  104,  103,  101,   99,   97,   94,   93,
+         90,   88,   87,   83,   82,   78,   76,   75,   71,   69,   65,   64,   62,   58,   56,   52,
+         50,   48,   43,   41,   37,   35,   33,   29,   26,   22,   20,   18,   13,   11,    7,    4,
+          0,
+};
+
+#define cos(idx) sin[((idx) + 64) % sizeof(sin)]
+
+/* Global font descriptor */
+static const u8 *font8x16;
+
+void tpg_set_font(const u8 *f)
+{
+       font8x16 = f;
+}
+
+void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
+{
+       memset(tpg, 0, sizeof(*tpg));
+       tpg->scaled_width = tpg->src_width = w;
+       tpg->src_height = tpg->buf_height = h;
+       tpg->crop.width = tpg->compose.width = w;
+       tpg->crop.height = tpg->compose.height = h;
+       tpg->recalc_colors = true;
+       tpg->recalc_square_border = true;
+       tpg->brightness = 128;
+       tpg->contrast = 128;
+       tpg->saturation = 128;
+       tpg->hue = 0;
+       tpg->mv_hor_mode = TPG_MOVE_NONE;
+       tpg->mv_vert_mode = TPG_MOVE_NONE;
+       tpg->field = V4L2_FIELD_NONE;
+       tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);
+       tpg->colorspace = V4L2_COLORSPACE_SRGB;
+       tpg->perc_fill = 100;
+}
+
+int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
+{
+       unsigned pat;
+       unsigned plane;
+
+       tpg->max_line_width = max_w;
+       for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
+               for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+                       unsigned pixelsz = plane ? 1 : 4;
+
+                       tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
+                       if (!tpg->lines[pat][plane])
+                               return -ENOMEM;
+               }
+       }
+       for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+               unsigned pixelsz = plane ? 1 : 4;
+
+               tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
+               if (!tpg->contrast_line[plane])
+                       return -ENOMEM;
+               tpg->black_line[plane] = vzalloc(max_w * pixelsz);
+               if (!tpg->black_line[plane])
+                       return -ENOMEM;
+               tpg->random_line[plane] = vzalloc(max_w * pixelsz);
+               if (!tpg->random_line[plane])
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
+void tpg_free(struct tpg_data *tpg)
+{
+       unsigned pat;
+       unsigned plane;
+
+       for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
+               for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+                       vfree(tpg->lines[pat][plane]);
+                       tpg->lines[pat][plane] = NULL;
+               }
+       for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+               vfree(tpg->contrast_line[plane]);
+               vfree(tpg->black_line[plane]);
+               vfree(tpg->random_line[plane]);
+               tpg->contrast_line[plane] = NULL;
+               tpg->black_line[plane] = NULL;
+               tpg->random_line[plane] = NULL;
+       }
+}
+
+bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
+{
+       tpg->fourcc = fourcc;
+       tpg->planes = 1;
+       tpg->recalc_colors = true;
+       switch (fourcc) {
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_RGB565X:
+       case V4L2_PIX_FMT_RGB555:
+       case V4L2_PIX_FMT_XRGB555:
+       case V4L2_PIX_FMT_ARGB555:
+       case V4L2_PIX_FMT_RGB555X:
+       case V4L2_PIX_FMT_RGB24:
+       case V4L2_PIX_FMT_BGR24:
+       case V4L2_PIX_FMT_RGB32:
+       case V4L2_PIX_FMT_BGR32:
+       case V4L2_PIX_FMT_XRGB32:
+       case V4L2_PIX_FMT_XBGR32:
+       case V4L2_PIX_FMT_ARGB32:
+       case V4L2_PIX_FMT_ABGR32:
+               tpg->is_yuv = false;
+               break;
+       case V4L2_PIX_FMT_NV16M:
+       case V4L2_PIX_FMT_NV61M:
+               tpg->planes = 2;
+               /* fall-through */
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_VYUY:
+               tpg->is_yuv = true;
+               break;
+       default:
+               return false;
+       }
+
+       switch (fourcc) {
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_RGB565X:
+       case V4L2_PIX_FMT_RGB555:
+       case V4L2_PIX_FMT_XRGB555:
+       case V4L2_PIX_FMT_ARGB555:
+       case V4L2_PIX_FMT_RGB555X:
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_VYUY:
+               tpg->twopixelsize[0] = 2 * 2;
+               break;
+       case V4L2_PIX_FMT_RGB24:
+       case V4L2_PIX_FMT_BGR24:
+               tpg->twopixelsize[0] = 2 * 3;
+               break;
+       case V4L2_PIX_FMT_RGB32:
+       case V4L2_PIX_FMT_BGR32:
+       case V4L2_PIX_FMT_XRGB32:
+       case V4L2_PIX_FMT_XBGR32:
+       case V4L2_PIX_FMT_ARGB32:
+       case V4L2_PIX_FMT_ABGR32:
+               tpg->twopixelsize[0] = 2 * 4;
+               break;
+       case V4L2_PIX_FMT_NV16M:
+       case V4L2_PIX_FMT_NV61M:
+               tpg->twopixelsize[0] = 2;
+               tpg->twopixelsize[1] = 2;
+               break;
+       }
+       return true;
+}
+
+void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
+               const struct v4l2_rect *compose)
+{
+       tpg->crop = *crop;
+       tpg->compose = *compose;
+       tpg->scaled_width = (tpg->src_width * tpg->compose.width +
+                                tpg->crop.width - 1) / tpg->crop.width;
+       tpg->scaled_width &= ~1;
+       if (tpg->scaled_width > tpg->max_line_width)
+               tpg->scaled_width = tpg->max_line_width;
+       if (tpg->scaled_width < 2)
+               tpg->scaled_width = 2;
+       tpg->recalc_lines = true;
+}
+
+void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
+                      u32 field)
+{
+       unsigned p;
+
+       tpg->src_width = width;
+       tpg->src_height = height;
+       tpg->field = field;
+       tpg->buf_height = height;
+       if (V4L2_FIELD_HAS_T_OR_B(field))
+               tpg->buf_height /= 2;
+       tpg->scaled_width = width;
+       tpg->crop.top = tpg->crop.left = 0;
+       tpg->crop.width = width;
+       tpg->crop.height = height;
+       tpg->compose.top = tpg->compose.left = 0;
+       tpg->compose.width = width;
+       tpg->compose.height = tpg->buf_height;
+       for (p = 0; p < tpg->planes; p++)
+               tpg->bytesperline[p] = width * tpg->twopixelsize[p] / 2;
+       tpg->recalc_square_border = true;
+}
+
+static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
+{
+       switch (tpg->pattern) {
+       case TPG_PAT_BLACK:
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_CSC_COLORBAR:
+               return TPG_COLOR_CSC_BLACK;
+       default:
+               return TPG_COLOR_100_BLACK;
+       }
+}
+
+static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
+{
+       switch (tpg->pattern) {
+       case TPG_PAT_75_COLORBAR:
+       case TPG_PAT_CSC_COLORBAR:
+               return TPG_COLOR_CSC_WHITE;
+       case TPG_PAT_BLACK:
+               return TPG_COLOR_100_BLACK;
+       default:
+               return TPG_COLOR_100_WHITE;
+       }
+}
+
+static u16 color_to_y(struct tpg_data *tpg, int r, int g, int b)
+{
+       switch (tpg->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               return ((16829 * r + 33039 * g + 6416 * b + 16 * 32768) >> 16) + (16 << 4);
+       case V4L2_COLORSPACE_SMPTE240M:
+               return ((11932 * r + 39455 * g + 4897 * b + 16 * 32768) >> 16) + (16 << 4);
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_SRGB:
+       default:
+               return ((11966 * r + 40254 * g + 4064 * b + 16 * 32768) >> 16) + (16 << 4);
+       }
+}
+
+static u16 color_to_cb(struct tpg_data *tpg, int r, int g, int b)
+{
+       switch (tpg->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               return ((-9714 * r - 19070 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
+       case V4L2_COLORSPACE_SMPTE240M:
+               return ((-6684 * r - 22100 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_SRGB:
+       default:
+               return ((-6596 * r - 22189 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
+       }
+}
+
+static u16 color_to_cr(struct tpg_data *tpg, int r, int g, int b)
+{
+       switch (tpg->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               return ((28784 * r - 24103 * g - 4681 * b + 16 * 32768) >> 16) + (128 << 4);
+       case V4L2_COLORSPACE_SMPTE240M:
+               return ((28784 * r - 25606 * g - 3178 * b + 16 * 32768) >> 16) + (128 << 4);
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_SRGB:
+       default:
+               return ((28784 * r - 26145 * g - 2639 * b + 16 * 32768) >> 16) + (128 << 4);
+       }
+}
+
+static u16 ycbcr_to_r(struct tpg_data *tpg, int y, int cb, int cr)
+{
+       int r;
+
+       y -= 16 << 4;
+       cb -= 128 << 4;
+       cr -= 128 << 4;
+       switch (tpg->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               r = 4769 * y + 6537 * cr;
+               break;
+       case V4L2_COLORSPACE_SMPTE240M:
+               r = 4769 * y + 7376 * cr;
+               break;
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_SRGB:
+       default:
+               r = 4769 * y + 7343 * cr;
+               break;
+       }
+       return clamp(r >> 12, 0, 0xff0);
+}
+
+static u16 ycbcr_to_g(struct tpg_data *tpg, int y, int cb, int cr)
+{
+       int g;
+
+       y -= 16 << 4;
+       cb -= 128 << 4;
+       cr -= 128 << 4;
+       switch (tpg->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               g = 4769 * y - 1605 * cb - 3330 * cr;
+               break;
+       case V4L2_COLORSPACE_SMPTE240M:
+               g = 4769 * y - 1055 * cb - 2341 * cr;
+               break;
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_SRGB:
+       default:
+               g = 4769 * y - 873 * cb - 2183 * cr;
+               break;
+       }
+       return clamp(g >> 12, 0, 0xff0);
+}
+
+static u16 ycbcr_to_b(struct tpg_data *tpg, int y, int cb, int cr)
+{
+       int b;
+
+       y -= 16 << 4;
+       cb -= 128 << 4;
+       cr -= 128 << 4;
+       switch (tpg->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               b = 4769 * y + 7343 * cb;
+               break;
+       case V4L2_COLORSPACE_SMPTE240M:
+               b = 4769 * y + 8552 * cb;
+               break;
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_SRGB:
+       default:
+               b = 4769 * y + 8652 * cb;
+               break;
+       }
+       return clamp(b >> 12, 0, 0xff0);
+}
+
+/* precalculate color bar values to speed up rendering */
+static void precalculate_color(struct tpg_data *tpg, int k)
+{
+       int col = k;
+       int r = tpg_colors[col].r;
+       int g = tpg_colors[col].g;
+       int b = tpg_colors[col].b;
+
+       if (k == TPG_COLOR_TEXTBG) {
+               col = tpg_get_textbg_color(tpg);
+
+               r = tpg_colors[col].r;
+               g = tpg_colors[col].g;
+               b = tpg_colors[col].b;
+       } else if (k == TPG_COLOR_TEXTFG) {
+               col = tpg_get_textfg_color(tpg);
+
+               r = tpg_colors[col].r;
+               g = tpg_colors[col].g;
+               b = tpg_colors[col].b;
+       } else if (tpg->pattern == TPG_PAT_NOISE) {
+               r = g = b = prandom_u32_max(256);
+       } else if (k == TPG_COLOR_RANDOM) {
+               r = g = b = tpg->qual_offset + prandom_u32_max(196);
+       } else if (k >= TPG_COLOR_RAMP) {
+               r = g = b = k - TPG_COLOR_RAMP;
+       }
+
+       if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
+               r = tpg_csc_colors[tpg->colorspace][col].r;
+               g = tpg_csc_colors[tpg->colorspace][col].g;
+               b = tpg_csc_colors[tpg->colorspace][col].b;
+       } else {
+               r <<= 4;
+               g <<= 4;
+               b <<= 4;
+       }
+       if (tpg->qual == TPG_QUAL_GRAY)
+               r = g = b = color_to_y(tpg, r, g, b);
+
+       /*
+        * The assumption is that the RGB output is always full range,
+        * so only if the rgb_range overrides the 'real' rgb range do
+        * we need to convert the RGB values.
+        *
+        * Currently there is no way of signalling to userspace if you
+        * are actually giving it limited range RGB (or full range
+        * YUV for that matter).
+        *
+        * Remember that r, g and b are still in the 0 - 0xff0 range.
+        */
+       if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
+           tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
+               /*
+                * Convert from full range (which is what r, g and b are)
+                * to limited range (which is the 'real' RGB range), which
+                * is then interpreted as full range.
+                */
+               r = (r * 219) / 255 + (16 << 4);
+               g = (g * 219) / 255 + (16 << 4);
+               b = (b * 219) / 255 + (16 << 4);
+       } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
+                  tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
+               /*
+                * Clamp r, g and b to the limited range and convert to full
+                * range since that's what we deliver.
+                */
+               r = clamp(r, 16 << 4, 235 << 4);
+               g = clamp(g, 16 << 4, 235 << 4);
+               b = clamp(b, 16 << 4, 235 << 4);
+               r = (r - (16 << 4)) * 255 / 219;
+               g = (g - (16 << 4)) * 255 / 219;
+               b = (b - (16 << 4)) * 255 / 219;
+       }
+
+       if (tpg->brightness != 128 || tpg->contrast != 128 ||
+           tpg->saturation != 128 || tpg->hue) {
+               /* Implement these operations */
+
+               /* First convert to YCbCr */
+               int y = color_to_y(tpg, r, g, b);       /* Luma */
+               int cb = color_to_cb(tpg, r, g, b);     /* Cb */
+               int cr = color_to_cr(tpg, r, g, b);     /* Cr */
+               int tmp_cb, tmp_cr;
+
+               y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
+               y += (tpg->brightness << 4) - (128 << 4);
+
+               cb -= 128 << 4;
+               cr -= 128 << 4;
+               tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
+               tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
+
+               cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
+               cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
+               if (tpg->is_yuv) {
+                       tpg->colors[k][0] = clamp(y >> 4, 1, 254);
+                       tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
+                       tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
+                       return;
+               }
+               r = ycbcr_to_r(tpg, y, cb, cr);
+               g = ycbcr_to_g(tpg, y, cb, cr);
+               b = ycbcr_to_b(tpg, y, cb, cr);
+       }
+
+       if (tpg->is_yuv) {
+               /* Convert to YCbCr */
+               u16 y = color_to_y(tpg, r, g, b);       /* Luma */
+               u16 cb = color_to_cb(tpg, r, g, b);     /* Cb */
+               u16 cr = color_to_cr(tpg, r, g, b);     /* Cr */
+
+               tpg->colors[k][0] = clamp(y >> 4, 1, 254);
+               tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
+               tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
+       } else {
+               switch (tpg->fourcc) {
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_RGB565X:
+                       r >>= 7;
+                       g >>= 6;
+                       b >>= 7;
+                       break;
+               case V4L2_PIX_FMT_RGB555:
+               case V4L2_PIX_FMT_XRGB555:
+               case V4L2_PIX_FMT_ARGB555:
+               case V4L2_PIX_FMT_RGB555X:
+                       r >>= 7;
+                       g >>= 7;
+                       b >>= 7;
+                       break;
+               default:
+                       r >>= 4;
+                       g >>= 4;
+                       b >>= 4;
+                       break;
+               }
+
+               tpg->colors[k][0] = r;
+               tpg->colors[k][1] = g;
+               tpg->colors[k][2] = b;
+       }
+}
+
+static void tpg_precalculate_colors(struct tpg_data *tpg)
+{
+       int k;
+
+       for (k = 0; k < TPG_COLOR_MAX; k++)
+               precalculate_color(tpg, k);
+}
+
+/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
+static void gen_twopix(struct tpg_data *tpg,
+               u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
+{
+       unsigned offset = odd * tpg->twopixelsize[0] / 2;
+       u8 alpha = tpg->alpha_component;
+       u8 r_y, g_u, b_v;
+
+       if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
+                                  color != TPG_COLOR_100_RED &&
+                                  color != TPG_COLOR_75_RED)
+               alpha = 0;
+       if (color == TPG_COLOR_RANDOM)
+               precalculate_color(tpg, color);
+       r_y = tpg->colors[color][0]; /* R or precalculated Y */
+       g_u = tpg->colors[color][1]; /* G or precalculated U */
+       b_v = tpg->colors[color][2]; /* B or precalculated V */
+
+       switch (tpg->fourcc) {
+       case V4L2_PIX_FMT_NV16M:
+               buf[0][offset] = r_y;
+               buf[1][offset] = odd ? b_v : g_u;
+               break;
+       case V4L2_PIX_FMT_NV61M:
+               buf[0][offset] = r_y;
+               buf[1][offset] = odd ? g_u : b_v;
+               break;
+
+       case V4L2_PIX_FMT_YUYV:
+               buf[0][offset] = r_y;
+               buf[0][offset + 1] = odd ? b_v : g_u;
+               break;
+       case V4L2_PIX_FMT_UYVY:
+               buf[0][offset] = odd ? b_v : g_u;
+               buf[0][offset + 1] = r_y;
+               break;
+       case V4L2_PIX_FMT_YVYU:
+               buf[0][offset] = r_y;
+               buf[0][offset + 1] = odd ? g_u : b_v;
+               break;
+       case V4L2_PIX_FMT_VYUY:
+               buf[0][offset] = odd ? g_u : b_v;
+               buf[0][offset + 1] = r_y;
+               break;
+       case V4L2_PIX_FMT_RGB565:
+               buf[0][offset] = (g_u << 5) | b_v;
+               buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
+               break;
+       case V4L2_PIX_FMT_RGB565X:
+               buf[0][offset] = (r_y << 3) | (g_u >> 3);
+               buf[0][offset + 1] = (g_u << 5) | b_v;
+               break;
+       case V4L2_PIX_FMT_RGB555:
+       case V4L2_PIX_FMT_XRGB555:
+               alpha = 0;
+               /* fall through */
+       case V4L2_PIX_FMT_ARGB555:
+               buf[0][offset] = (g_u << 5) | b_v;
+               buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+               break;
+       case V4L2_PIX_FMT_RGB555X:
+               buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+               buf[0][offset + 1] = (g_u << 5) | b_v;
+               break;
+       case V4L2_PIX_FMT_RGB24:
+               buf[0][offset] = r_y;
+               buf[0][offset + 1] = g_u;
+               buf[0][offset + 2] = b_v;
+               break;
+       case V4L2_PIX_FMT_BGR24:
+               buf[0][offset] = b_v;
+               buf[0][offset + 1] = g_u;
+               buf[0][offset + 2] = r_y;
+               break;
+       case V4L2_PIX_FMT_RGB32:
+       case V4L2_PIX_FMT_XRGB32:
+               alpha = 0;
+               /* fall through */
+       case V4L2_PIX_FMT_ARGB32:
+               buf[0][offset] = alpha;
+               buf[0][offset + 1] = r_y;
+               buf[0][offset + 2] = g_u;
+               buf[0][offset + 3] = b_v;
+               break;
+       case V4L2_PIX_FMT_BGR32:
+       case V4L2_PIX_FMT_XBGR32:
+               alpha = 0;
+               /* fall through */
+       case V4L2_PIX_FMT_ABGR32:
+               buf[0][offset] = b_v;
+               buf[0][offset + 1] = g_u;
+               buf[0][offset + 2] = r_y;
+               buf[0][offset + 3] = alpha;
+               break;
+       }
+}
+
+/* Return how many pattern lines are used by the current pattern. */
+static unsigned tpg_get_pat_lines(struct tpg_data *tpg)
+{
+       switch (tpg->pattern) {
+       case TPG_PAT_CHECKERS_16X16:
+       case TPG_PAT_CHECKERS_1X1:
+       case TPG_PAT_ALTERNATING_HLINES:
+       case TPG_PAT_CROSS_1_PIXEL:
+       case TPG_PAT_CROSS_2_PIXELS:
+       case TPG_PAT_CROSS_10_PIXELS:
+               return 2;
+       case TPG_PAT_100_COLORSQUARES:
+       case TPG_PAT_100_HCOLORBAR:
+               return 8;
+       default:
+               return 1;
+       }
+}
+
+/* Which pattern line should be used for the given frame line. */
+static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line)
+{
+       switch (tpg->pattern) {
+       case TPG_PAT_CHECKERS_16X16:
+               return (line >> 4) & 1;
+       case TPG_PAT_CHECKERS_1X1:
+       case TPG_PAT_ALTERNATING_HLINES:
+               return line & 1;
+       case TPG_PAT_100_COLORSQUARES:
+       case TPG_PAT_100_HCOLORBAR:
+               return (line * 8) / tpg->src_height;
+       case TPG_PAT_CROSS_1_PIXEL:
+               return line == tpg->src_height / 2;
+       case TPG_PAT_CROSS_2_PIXELS:
+               return (line + 1) / 2 == tpg->src_height / 4;
+       case TPG_PAT_CROSS_10_PIXELS:
+               return (line + 10) / 20 == tpg->src_height / 40;
+       default:
+               return 0;
+       }
+}
+
+/*
+ * Which color should be used for the given pattern line and X coordinate.
+ * Note: x is in the range 0 to 2 * tpg->src_width.
+ */
+static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, unsigned x)
+{
+       /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
+          should be modified */
+       static const enum tpg_color bars[3][8] = {
+               /* Standard ITU-R 75% color bar sequence */
+               { TPG_COLOR_CSC_WHITE,   TPG_COLOR_75_YELLOW,
+                 TPG_COLOR_75_CYAN,     TPG_COLOR_75_GREEN,
+                 TPG_COLOR_75_MAGENTA,  TPG_COLOR_75_RED,
+                 TPG_COLOR_75_BLUE,     TPG_COLOR_100_BLACK, },
+               /* Standard ITU-R 100% color bar sequence */
+               { TPG_COLOR_100_WHITE,   TPG_COLOR_100_YELLOW,
+                 TPG_COLOR_100_CYAN,    TPG_COLOR_100_GREEN,
+                 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
+                 TPG_COLOR_100_BLUE,    TPG_COLOR_100_BLACK, },
+               /* Color bar sequence suitable to test CSC */
+               { TPG_COLOR_CSC_WHITE,   TPG_COLOR_CSC_YELLOW,
+                 TPG_COLOR_CSC_CYAN,    TPG_COLOR_CSC_GREEN,
+                 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
+                 TPG_COLOR_CSC_BLUE,    TPG_COLOR_CSC_BLACK, },
+       };
+
+       switch (tpg->pattern) {
+       case TPG_PAT_75_COLORBAR:
+       case TPG_PAT_100_COLORBAR:
+       case TPG_PAT_CSC_COLORBAR:
+               return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
+       case TPG_PAT_100_COLORSQUARES:
+               return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
+       case TPG_PAT_100_HCOLORBAR:
+               return bars[1][pat_line];
+       case TPG_PAT_BLACK:
+               return TPG_COLOR_100_BLACK;
+       case TPG_PAT_WHITE:
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_RED:
+               return TPG_COLOR_100_RED;
+       case TPG_PAT_GREEN:
+               return TPG_COLOR_100_GREEN;
+       case TPG_PAT_BLUE:
+               return TPG_COLOR_100_BLUE;
+       case TPG_PAT_CHECKERS_16X16:
+               return (((x >> 4) & 1) ^ (pat_line & 1)) ?
+                       TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
+       case TPG_PAT_CHECKERS_1X1:
+               return ((x & 1) ^ (pat_line & 1)) ?
+                       TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+       case TPG_PAT_ALTERNATING_HLINES:
+               return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+       case TPG_PAT_ALTERNATING_VLINES:
+               return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+       case TPG_PAT_CROSS_1_PIXEL:
+               if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
+                       return TPG_COLOR_100_BLACK;
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_CROSS_2_PIXELS:
+               if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
+                       return TPG_COLOR_100_BLACK;
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_CROSS_10_PIXELS:
+               if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
+                       return TPG_COLOR_100_BLACK;
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_GRAY_RAMP:
+               return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
+       default:
+               return TPG_COLOR_100_RED;
+       }
+}
+
+/*
+ * Given the pixel aspect ratio and video aspect ratio calculate the
+ * coordinates of a centered square and the coordinates of the border of
+ * the active video area. The coordinates are relative to the source
+ * frame rectangle.
+ */
+static void tpg_calculate_square_border(struct tpg_data *tpg)
+{
+       unsigned w = tpg->src_width;
+       unsigned h = tpg->src_height;
+       unsigned sq_w, sq_h;
+
+       sq_w = (w * 2 / 5) & ~1;
+       if (((w - sq_w) / 2) & 1)
+               sq_w += 2;
+       sq_h = sq_w;
+       tpg->square.width = sq_w;
+       if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
+               unsigned ana_sq_w = (sq_w / 4) * 3;
+
+               if (((w - ana_sq_w) / 2) & 1)
+                       ana_sq_w += 2;
+               tpg->square.width = ana_sq_w;
+       }
+       tpg->square.left = (w - tpg->square.width) / 2;
+       if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
+               sq_h = sq_w * 10 / 11;
+       else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
+               sq_h = sq_w * 59 / 54;
+       tpg->square.height = sq_h;
+       tpg->square.top = (h - sq_h) / 2;
+       tpg->border.left = 0;
+       tpg->border.width = w;
+       tpg->border.top = 0;
+       tpg->border.height = h;
+       switch (tpg->vid_aspect) {
+       case TPG_VIDEO_ASPECT_4X3:
+               if (tpg->pix_aspect)
+                       return;
+               if (3 * w >= 4 * h) {
+                       tpg->border.width = ((4 * h) / 3) & ~1;
+                       if (((w - tpg->border.width) / 2) & ~1)
+                               tpg->border.width -= 2;
+                       tpg->border.left = (w - tpg->border.width) / 2;
+                       break;
+               }
+               tpg->border.height = ((3 * w) / 4) & ~1;
+               tpg->border.top = (h - tpg->border.height) / 2;
+               break;
+       case TPG_VIDEO_ASPECT_14X9_CENTRE:
+               if (tpg->pix_aspect) {
+                       tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
+                       tpg->border.top = (h - tpg->border.height) / 2;
+                       break;
+               }
+               if (9 * w >= 14 * h) {
+                       tpg->border.width = ((14 * h) / 9) & ~1;
+                       if (((w - tpg->border.width) / 2) & ~1)
+                               tpg->border.width -= 2;
+                       tpg->border.left = (w - tpg->border.width) / 2;
+                       break;
+               }
+               tpg->border.height = ((9 * w) / 14) & ~1;
+               tpg->border.top = (h - tpg->border.height) / 2;
+               break;
+       case TPG_VIDEO_ASPECT_16X9_CENTRE:
+               if (tpg->pix_aspect) {
+                       tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
+                       tpg->border.top = (h - tpg->border.height) / 2;
+                       break;
+               }
+               if (9 * w >= 16 * h) {
+                       tpg->border.width = ((16 * h) / 9) & ~1;
+                       if (((w - tpg->border.width) / 2) & ~1)
+                               tpg->border.width -= 2;
+                       tpg->border.left = (w - tpg->border.width) / 2;
+                       break;
+               }
+               tpg->border.height = ((9 * w) / 16) & ~1;
+               tpg->border.top = (h - tpg->border.height) / 2;
+               break;
+       default:
+               break;
+       }
+}
+
+static void tpg_precalculate_line(struct tpg_data *tpg)
+{
+       enum tpg_color contrast;
+       unsigned pat;
+       unsigned p;
+       unsigned x;
+
+       switch (tpg->pattern) {
+       case TPG_PAT_GREEN:
+               contrast = TPG_COLOR_100_RED;
+               break;
+       case TPG_PAT_CSC_COLORBAR:
+               contrast = TPG_COLOR_CSC_GREEN;
+               break;
+       default:
+               contrast = TPG_COLOR_100_GREEN;
+               break;
+       }
+
+       for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
+               /* Coarse scaling with Bresenham */
+               unsigned int_part = tpg->src_width / tpg->scaled_width;
+               unsigned fract_part = tpg->src_width % tpg->scaled_width;
+               unsigned src_x = 0;
+               unsigned error = 0;
+
+               for (x = 0; x < tpg->scaled_width * 2; x += 2) {
+                       unsigned real_x = src_x;
+                       enum tpg_color color1, color2;
+                       u8 pix[TPG_MAX_PLANES][8];
+
+                       real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
+                       color1 = tpg_get_color(tpg, pat, real_x);
+
+                       src_x += int_part;
+                       error += fract_part;
+                       if (error >= tpg->scaled_width) {
+                               error -= tpg->scaled_width;
+                               src_x++;
+                       }
+
+                       real_x = src_x;
+                       real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
+                       color2 = tpg_get_color(tpg, pat, real_x);
+
+                       src_x += int_part;
+                       error += fract_part;
+                       if (error >= tpg->scaled_width) {
+                               error -= tpg->scaled_width;
+                               src_x++;
+                       }
+
+                       gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
+                       gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
+                       for (p = 0; p < tpg->planes; p++) {
+                               unsigned twopixsize = tpg->twopixelsize[p];
+                               u8 *pos = tpg->lines[pat][p] + x * twopixsize / 2;
+
+                               memcpy(pos, pix[p], twopixsize);
+                       }
+               }
+       }
+       for (x = 0; x < tpg->scaled_width; x += 2) {
+               u8 pix[TPG_MAX_PLANES][8];
+
+               gen_twopix(tpg, pix, contrast, 0);
+               gen_twopix(tpg, pix, contrast, 1);
+               for (p = 0; p < tpg->planes; p++) {
+                       unsigned twopixsize = tpg->twopixelsize[p];
+                       u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2;
+
+                       memcpy(pos, pix[p], twopixsize);
+               }
+       }
+       for (x = 0; x < tpg->scaled_width; x += 2) {
+               u8 pix[TPG_MAX_PLANES][8];
+
+               gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
+               gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
+               for (p = 0; p < tpg->planes; p++) {
+                       unsigned twopixsize = tpg->twopixelsize[p];
+                       u8 *pos = tpg->black_line[p] + x * twopixsize / 2;
+
+                       memcpy(pos, pix[p], twopixsize);
+               }
+       }
+       for (x = 0; x < tpg->scaled_width * 2; x += 2) {
+               u8 pix[TPG_MAX_PLANES][8];
+
+               gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
+               gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
+               for (p = 0; p < tpg->planes; p++) {
+                       unsigned twopixsize = tpg->twopixelsize[p];
+                       u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
+
+                       memcpy(pos, pix[p], twopixsize);
+               }
+       }
+       gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
+       gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
+       gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
+       gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
+}
+
+/* need this to do rgb24 rendering */
+typedef struct { u16 __; u8 _; } __packed x24;
+
+void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
+               int y, int x, char *text)
+{
+       int line;
+       unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
+       unsigned div = step;
+       unsigned first = 0;
+       unsigned len = strlen(text);
+       unsigned p;
+
+       if (font8x16 == NULL || basep == NULL)
+               return;
+
+       /* Checks if it is possible to show string */
+       if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
+               return;
+
+       if (len > (tpg->compose.width - x) / 8)
+               len = (tpg->compose.width - x) / 8;
+       if (tpg->vflip)
+               y = tpg->compose.height - y - 16;
+       if (tpg->hflip)
+               x = tpg->compose.width - x - 8;
+       y += tpg->compose.top;
+       x += tpg->compose.left;
+       if (tpg->field == V4L2_FIELD_BOTTOM)
+               first = 1;
+       else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
+               div = 2;
+
+       for (p = 0; p < tpg->planes; p++) {
+               /* Print stream time */
+#define PRINTSTR(PIXTYPE) do { \
+       PIXTYPE fg;     \
+       PIXTYPE bg;     \
+       memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE));   \
+       memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE));   \
+       \
+       for (line = first; line < 16; line += step) {   \
+               int l = tpg->vflip ? 15 - line : line; \
+               PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \
+                              ((y * step + l) / div) * tpg->bytesperline[p] + \
+                              x * sizeof(PIXTYPE));    \
+               unsigned s;     \
+       \
+               for (s = 0; s < len; s++) {     \
+                       u8 chr = font8x16[text[s] * 16 + line]; \
+       \
+                       if (tpg->hflip) { \
+                               pos[7] = (chr & (0x01 << 7) ? fg : bg); \
+                               pos[6] = (chr & (0x01 << 6) ? fg : bg); \
+                               pos[5] = (chr & (0x01 << 5) ? fg : bg); \
+                               pos[4] = (chr & (0x01 << 4) ? fg : bg); \
+                               pos[3] = (chr & (0x01 << 3) ? fg : bg); \
+                               pos[2] = (chr & (0x01 << 2) ? fg : bg); \
+                               pos[1] = (chr & (0x01 << 1) ? fg : bg); \
+                               pos[0] = (chr & (0x01 << 0) ? fg : bg); \
+                       } else { \
+                               pos[0] = (chr & (0x01 << 7) ? fg : bg); \
+                               pos[1] = (chr & (0x01 << 6) ? fg : bg); \
+                               pos[2] = (chr & (0x01 << 5) ? fg : bg); \
+                               pos[3] = (chr & (0x01 << 4) ? fg : bg); \
+                               pos[4] = (chr & (0x01 << 3) ? fg : bg); \
+                               pos[5] = (chr & (0x01 << 2) ? fg : bg); \
+                               pos[6] = (chr & (0x01 << 1) ? fg : bg); \
+                               pos[7] = (chr & (0x01 << 0) ? fg : bg); \
+                       } \
+       \
+                       pos += tpg->hflip ? -8 : 8;     \
+               }       \
+       }       \
+} while (0)
+
+               switch (tpg->twopixelsize[p]) {
+               case 2:
+                       PRINTSTR(u8); break;
+               case 4:
+                       PRINTSTR(u16); break;
+               case 6:
+                       PRINTSTR(x24); break;
+               case 8:
+                       PRINTSTR(u32); break;
+               }
+       }
+}
+
+void tpg_update_mv_step(struct tpg_data *tpg)
+{
+       int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
+
+       if (tpg->hflip)
+               factor = -factor;
+       switch (tpg->mv_hor_mode) {
+       case TPG_MOVE_NEG_FAST:
+       case TPG_MOVE_POS_FAST:
+               tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
+               break;
+       case TPG_MOVE_NEG:
+       case TPG_MOVE_POS:
+               tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
+               break;
+       case TPG_MOVE_NEG_SLOW:
+       case TPG_MOVE_POS_SLOW:
+               tpg->mv_hor_step = 2;
+               break;
+       case TPG_MOVE_NONE:
+               tpg->mv_hor_step = 0;
+               break;
+       }
+       if (factor < 0)
+               tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
+
+       factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
+       switch (tpg->mv_vert_mode) {
+       case TPG_MOVE_NEG_FAST:
+       case TPG_MOVE_POS_FAST:
+               tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
+               break;
+       case TPG_MOVE_NEG:
+       case TPG_MOVE_POS:
+               tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
+               break;
+       case TPG_MOVE_NEG_SLOW:
+       case TPG_MOVE_POS_SLOW:
+               tpg->mv_vert_step = 1;
+               break;
+       case TPG_MOVE_NONE:
+               tpg->mv_vert_step = 0;
+               break;
+       }
+       if (factor < 0)
+               tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
+}
+
+/* Map the line number relative to the crop rectangle to a frame line number */
+static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
+                                   unsigned field)
+{
+       switch (field) {
+       case V4L2_FIELD_TOP:
+               return tpg->crop.top + src_y * 2;
+       case V4L2_FIELD_BOTTOM:
+               return tpg->crop.top + src_y * 2 + 1;
+       default:
+               return src_y + tpg->crop.top;
+       }
+}
+
+/*
+ * Map the line number relative to the compose rectangle to a destination
+ * buffer line number.
+ */
+static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y,
+                                   unsigned field)
+{
+       y += tpg->compose.top;
+       switch (field) {
+       case V4L2_FIELD_SEQ_TB:
+               if (y & 1)
+                       return tpg->buf_height / 2 + y / 2;
+               return y / 2;
+       case V4L2_FIELD_SEQ_BT:
+               if (y & 1)
+                       return y / 2;
+               return tpg->buf_height / 2 + y / 2;
+       default:
+               return y;
+       }
+}
+
+static void tpg_recalc(struct tpg_data *tpg)
+{
+       if (tpg->recalc_colors) {
+               tpg->recalc_colors = false;
+               tpg->recalc_lines = true;
+               tpg_precalculate_colors(tpg);
+       }
+       if (tpg->recalc_square_border) {
+               tpg->recalc_square_border = false;
+               tpg_calculate_square_border(tpg);
+       }
+       if (tpg->recalc_lines) {
+               tpg->recalc_lines = false;
+               tpg_precalculate_line(tpg);
+       }
+}
+
+void tpg_calc_text_basep(struct tpg_data *tpg,
+               u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
+{
+       unsigned stride = tpg->bytesperline[p];
+
+       tpg_recalc(tpg);
+
+       basep[p][0] = vbuf;
+       basep[p][1] = vbuf;
+       if (tpg->field == V4L2_FIELD_SEQ_TB)
+               basep[p][1] += tpg->buf_height * stride / 2;
+       else if (tpg->field == V4L2_FIELD_SEQ_BT)
+               basep[p][0] += tpg->buf_height * stride / 2;
+}
+
+void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
+{
+       bool is_tv = std;
+       bool is_60hz = is_tv && (std & V4L2_STD_525_60);
+       unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width;
+       unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width;
+       unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height;
+       unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
+       unsigned wss_width;
+       unsigned f;
+       int hmax = (tpg->compose.height * tpg->perc_fill) / 100;
+       int h;
+       unsigned twopixsize = tpg->twopixelsize[p];
+       unsigned img_width = tpg->compose.width * twopixsize / 2;
+       unsigned line_offset;
+       unsigned left_pillar_width = 0;
+       unsigned right_pillar_start = img_width;
+       unsigned stride = tpg->bytesperline[p];
+       unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
+       u8 *orig_vbuf = vbuf;
+
+       /* Coarse scaling with Bresenham */
+       unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
+       unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
+       unsigned src_y = 0;
+       unsigned error = 0;
+
+       tpg_recalc(tpg);
+
+       mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1;
+       mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1;
+       wss_width = tpg->crop.left < tpg->src_width / 2 ?
+                       tpg->src_width / 2 - tpg->crop.left : 0;
+       if (wss_width > tpg->crop.width)
+               wss_width = tpg->crop.width;
+       wss_width = wss_width * tpg->scaled_width / tpg->src_width;
+
+       vbuf += tpg->compose.left * twopixsize / 2;
+       line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width;
+       line_offset = (line_offset & ~1) * twopixsize / 2;
+       if (tpg->crop.left < tpg->border.left) {
+               left_pillar_width = tpg->border.left - tpg->crop.left;
+               if (left_pillar_width > tpg->crop.width)
+                       left_pillar_width = tpg->crop.width;
+               left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width;
+               left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2;
+       }
+       if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
+               right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
+               right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width;
+               right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2;
+               if (right_pillar_start > img_width)
+                       right_pillar_start = img_width;
+       }
+
+       f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+
+       for (h = 0; h < tpg->compose.height; h++) {
+               bool even;
+               bool fill_blank = false;
+               unsigned frame_line;
+               unsigned buf_line;
+               unsigned pat_line_old;
+               unsigned pat_line_new;
+               u8 *linestart_older;
+               u8 *linestart_newer;
+               u8 *linestart_top;
+               u8 *linestart_bottom;
+
+               frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
+               even = !(frame_line & 1);
+               buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
+               src_y += int_part;
+               error += fract_part;
+               if (error >= tpg->compose.height) {
+                       error -= tpg->compose.height;
+                       src_y++;
+               }
+
+               if (h >= hmax) {
+                       if (hmax == tpg->compose.height)
+                               continue;
+                       if (!tpg->perc_fill_blank)
+                               continue;
+                       fill_blank = true;
+               }
+
+               if (tpg->vflip)
+                       frame_line = tpg->src_height - frame_line - 1;
+
+               if (fill_blank) {
+                       linestart_older = tpg->contrast_line[p];
+                       linestart_newer = tpg->contrast_line[p];
+               } else if (tpg->qual != TPG_QUAL_NOISE &&
+                          (frame_line < tpg->border.top ||
+                           frame_line >= tpg->border.top + tpg->border.height)) {
+                       linestart_older = tpg->black_line[p];
+                       linestart_newer = tpg->black_line[p];
+               } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
+                       linestart_older = tpg->random_line[p] +
+                                         twopixsize * prandom_u32_max(tpg->src_width / 2);
+                       linestart_newer = tpg->random_line[p] +
+                                         twopixsize * prandom_u32_max(tpg->src_width / 2);
+               } else {
+                       pat_line_old = tpg_get_pat_line(tpg,
+                                               (frame_line + mv_vert_old) % tpg->src_height);
+                       pat_line_new = tpg_get_pat_line(tpg,
+                                               (frame_line + mv_vert_new) % tpg->src_height);
+                       linestart_older = tpg->lines[pat_line_old][p] +
+                                         mv_hor_old * twopixsize / 2;
+                       linestart_newer = tpg->lines[pat_line_new][p] +
+                                         mv_hor_new * twopixsize / 2;
+                       linestart_older += line_offset;
+                       linestart_newer += line_offset;
+               }
+               if (is_60hz) {
+                       linestart_top = linestart_newer;
+                       linestart_bottom = linestart_older;
+               } else {
+                       linestart_top = linestart_older;
+                       linestart_bottom = linestart_newer;
+               }
+
+               switch (tpg->field) {
+               case V4L2_FIELD_INTERLACED:
+               case V4L2_FIELD_INTERLACED_TB:
+               case V4L2_FIELD_SEQ_TB:
+               case V4L2_FIELD_SEQ_BT:
+                       if (even)
+                               memcpy(vbuf + buf_line * stride, linestart_top, img_width);
+                       else
+                               memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
+                       break;
+               case V4L2_FIELD_INTERLACED_BT:
+                       if (even)
+                               memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
+                       else
+                               memcpy(vbuf + buf_line * stride, linestart_top, img_width);
+                       break;
+               case V4L2_FIELD_TOP:
+                       memcpy(vbuf + buf_line * stride, linestart_top, img_width);
+                       break;
+               case V4L2_FIELD_BOTTOM:
+                       memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
+                       break;
+               case V4L2_FIELD_NONE:
+               default:
+                       memcpy(vbuf + buf_line * stride, linestart_older, img_width);
+                       break;
+               }
+
+               if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
+                       /*
+                        * Replace the first half of the top line of a 50 Hz frame
+                        * with random data to simulate a WSS signal.
+                        */
+                       u8 *wss = tpg->random_line[p] +
+                                 twopixsize * prandom_u32_max(tpg->src_width / 2);
+
+                       memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2);
+               }
+       }
+
+       vbuf = orig_vbuf;
+       vbuf += tpg->compose.left * twopixsize / 2;
+       src_y = 0;
+       error = 0;
+       for (h = 0; h < tpg->compose.height; h++) {
+               unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
+               unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
+               const struct v4l2_rect *sq = &tpg->square;
+               const struct v4l2_rect *b = &tpg->border;
+               const struct v4l2_rect *c = &tpg->crop;
+
+               src_y += int_part;
+               error += fract_part;
+               if (error >= tpg->compose.height) {
+                       error -= tpg->compose.height;
+                       src_y++;
+               }
+
+               if (tpg->show_border && frame_line >= b->top &&
+                   frame_line < b->top + b->height) {
+                       unsigned bottom = b->top + b->height - 1;
+                       unsigned left = left_pillar_width;
+                       unsigned right = right_pillar_start;
+
+                       if (frame_line == b->top || frame_line == b->top + 1 ||
+                           frame_line == bottom || frame_line == bottom - 1) {
+                               memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
+                                               right - left);
+                       } else {
+                               if (b->left >= c->left &&
+                                   b->left < c->left + c->width)
+                                       memcpy(vbuf + buf_line * stride + left,
+                                               tpg->contrast_line[p], twopixsize);
+                               if (b->left + b->width > c->left &&
+                                   b->left + b->width <= c->left + c->width)
+                                       memcpy(vbuf + buf_line * stride + right - twopixsize,
+                                               tpg->contrast_line[p], twopixsize);
+                       }
+               }
+               if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
+                   frame_line < b->top + b->height) {
+                       memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width);
+                       memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p],
+                              img_width - right_pillar_start);
+               }
+               if (tpg->show_square && frame_line >= sq->top &&
+                   frame_line < sq->top + sq->height &&
+                   sq->left < c->left + c->width &&
+                   sq->left + sq->width >= c->left) {
+                       unsigned left = sq->left;
+                       unsigned width = sq->width;
+
+                       if (c->left > left) {
+                               width -= c->left - left;
+                               left = c->left;
+                       }
+                       if (c->left + c->width < left + width)
+                               width -= left + width - c->left - c->width;
+                       left -= c->left;
+                       left = (left * tpg->scaled_width) / tpg->src_width;
+                       left = (left & ~1) * twopixsize / 2;
+                       width = (width * tpg->scaled_width) / tpg->src_width;
+                       width = (width & ~1) * twopixsize / 2;
+                       memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
+               }
+               if (tpg->insert_sav) {
+                       unsigned offset = (tpg->compose.width / 6) * twopixsize;
+                       u8 *p = vbuf + buf_line * stride + offset;
+                       unsigned vact = 0, hact = 0;
+
+                       p[0] = 0xff;
+                       p[1] = 0;
+                       p[2] = 0;
+                       p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
+                               ((hact ^ vact) << 3) |
+                               ((hact ^ f) << 2) |
+                               ((f ^ vact) << 1) |
+                               (hact ^ vact ^ f);
+               }
+               if (tpg->insert_eav) {
+                       unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize;
+                       u8 *p = vbuf + buf_line * stride + offset;
+                       unsigned vact = 0, hact = 1;
+
+                       p[0] = 0xff;
+                       p[1] = 0;
+                       p[2] = 0;
+                       p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
+                               ((hact ^ vact) << 3) |
+                               ((hact ^ f) << 2) |
+                               ((f ^ vact) << 1) |
+                               (hact ^ vact ^ f);
+               }
+       }
+}
diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h
new file mode 100644 (file)
index 0000000..8ef3e52
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * vivid-tpg.h - Test Pattern Generator
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_TPG_H_
+#define _VIVID_TPG_H_
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+
+#include "vivid-tpg-colors.h"
+
+enum tpg_pattern {
+       TPG_PAT_75_COLORBAR,
+       TPG_PAT_100_COLORBAR,
+       TPG_PAT_CSC_COLORBAR,
+       TPG_PAT_100_HCOLORBAR,
+       TPG_PAT_100_COLORSQUARES,
+       TPG_PAT_BLACK,
+       TPG_PAT_WHITE,
+       TPG_PAT_RED,
+       TPG_PAT_GREEN,
+       TPG_PAT_BLUE,
+       TPG_PAT_CHECKERS_16X16,
+       TPG_PAT_CHECKERS_1X1,
+       TPG_PAT_ALTERNATING_HLINES,
+       TPG_PAT_ALTERNATING_VLINES,
+       TPG_PAT_CROSS_1_PIXEL,
+       TPG_PAT_CROSS_2_PIXELS,
+       TPG_PAT_CROSS_10_PIXELS,
+       TPG_PAT_GRAY_RAMP,
+
+       /* Must be the last pattern */
+       TPG_PAT_NOISE,
+};
+
+extern const char * const tpg_pattern_strings[];
+
+enum tpg_quality {
+       TPG_QUAL_COLOR,
+       TPG_QUAL_GRAY,
+       TPG_QUAL_NOISE
+};
+
+enum tpg_video_aspect {
+       TPG_VIDEO_ASPECT_IMAGE,
+       TPG_VIDEO_ASPECT_4X3,
+       TPG_VIDEO_ASPECT_14X9_CENTRE,
+       TPG_VIDEO_ASPECT_16X9_CENTRE,
+       TPG_VIDEO_ASPECT_16X9_ANAMORPHIC,
+};
+
+enum tpg_pixel_aspect {
+       TPG_PIXEL_ASPECT_SQUARE,
+       TPG_PIXEL_ASPECT_NTSC,
+       TPG_PIXEL_ASPECT_PAL,
+};
+
+enum tpg_move_mode {
+       TPG_MOVE_NEG_FAST,
+       TPG_MOVE_NEG,
+       TPG_MOVE_NEG_SLOW,
+       TPG_MOVE_NONE,
+       TPG_MOVE_POS_SLOW,
+       TPG_MOVE_POS,
+       TPG_MOVE_POS_FAST,
+};
+
+extern const char * const tpg_aspect_strings[];
+
+#define TPG_MAX_PLANES 2
+#define TPG_MAX_PAT_LINES 8
+
+struct tpg_data {
+       /* Source frame size */
+       unsigned                        src_width, src_height;
+       /* Buffer height */
+       unsigned                        buf_height;
+       /* Scaled output frame size */
+       unsigned                        scaled_width;
+       u32                             field;
+       /* crop coordinates are frame-based */
+       struct v4l2_rect                crop;
+       /* compose coordinates are format-based */
+       struct v4l2_rect                compose;
+       /* border and square coordinates are frame-based */
+       struct v4l2_rect                border;
+       struct v4l2_rect                square;
+
+       /* Color-related fields */
+       enum tpg_quality                qual;
+       unsigned                        qual_offset;
+       u8                              alpha_component;
+       bool                            alpha_red_only;
+       u8                              brightness;
+       u8                              contrast;
+       u8                              saturation;
+       s16                             hue;
+       u32                             fourcc;
+       bool                            is_yuv;
+       u32                             colorspace;
+       enum tpg_video_aspect           vid_aspect;
+       enum tpg_pixel_aspect           pix_aspect;
+       unsigned                        rgb_range;
+       unsigned                        real_rgb_range;
+       unsigned                        planes;
+       /* Used to store the colors in native format, either RGB or YUV */
+       u8                              colors[TPG_COLOR_MAX][3];
+       u8                              textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8];
+       /* size in bytes for two pixels in each plane */
+       unsigned                        twopixelsize[TPG_MAX_PLANES];
+       unsigned                        bytesperline[TPG_MAX_PLANES];
+
+       /* Configuration */
+       enum tpg_pattern                pattern;
+       bool                            hflip;
+       bool                            vflip;
+       unsigned                        perc_fill;
+       bool                            perc_fill_blank;
+       bool                            show_border;
+       bool                            show_square;
+       bool                            insert_sav;
+       bool                            insert_eav;
+
+       /* Test pattern movement */
+       enum tpg_move_mode              mv_hor_mode;
+       int                             mv_hor_count;
+       int                             mv_hor_step;
+       enum tpg_move_mode              mv_vert_mode;
+       int                             mv_vert_count;
+       int                             mv_vert_step;
+
+       bool                            recalc_colors;
+       bool                            recalc_lines;
+       bool                            recalc_square_border;
+
+       /* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */
+       unsigned                        max_line_width;
+       u8                              *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES];
+       u8                              *random_line[TPG_MAX_PLANES];
+       u8                              *contrast_line[TPG_MAX_PLANES];
+       u8                              *black_line[TPG_MAX_PLANES];
+};
+
+void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h);
+int tpg_alloc(struct tpg_data *tpg, unsigned max_w);
+void tpg_free(struct tpg_data *tpg);
+void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
+                      u32 field);
+
+void tpg_set_font(const u8 *f);
+void tpg_gen_text(struct tpg_data *tpg,
+               u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text);
+void tpg_calc_text_basep(struct tpg_data *tpg,
+               u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf);
+void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf);
+bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc);
+void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
+               const struct v4l2_rect *compose);
+
+static inline void tpg_s_pattern(struct tpg_data *tpg, enum tpg_pattern pattern)
+{
+       if (tpg->pattern == pattern)
+               return;
+       tpg->pattern = pattern;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_quality(struct tpg_data *tpg,
+                                   enum tpg_quality qual, unsigned qual_offset)
+{
+       if (tpg->qual == qual && tpg->qual_offset == qual_offset)
+               return;
+       tpg->qual = qual;
+       tpg->qual_offset = qual_offset;
+       tpg->recalc_colors = true;
+}
+
+static inline enum tpg_quality tpg_g_quality(const struct tpg_data *tpg)
+{
+       return tpg->qual;
+}
+
+static inline void tpg_s_alpha_component(struct tpg_data *tpg,
+                                           u8 alpha_component)
+{
+       if (tpg->alpha_component == alpha_component)
+               return;
+       tpg->alpha_component = alpha_component;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_alpha_mode(struct tpg_data *tpg,
+                                           bool red_only)
+{
+       if (tpg->alpha_red_only == red_only)
+               return;
+       tpg->alpha_red_only = red_only;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_brightness(struct tpg_data *tpg,
+                                       u8 brightness)
+{
+       if (tpg->brightness == brightness)
+               return;
+       tpg->brightness = brightness;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_contrast(struct tpg_data *tpg,
+                                       u8 contrast)
+{
+       if (tpg->contrast == contrast)
+               return;
+       tpg->contrast = contrast;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_saturation(struct tpg_data *tpg,
+                                       u8 saturation)
+{
+       if (tpg->saturation == saturation)
+               return;
+       tpg->saturation = saturation;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_hue(struct tpg_data *tpg,
+                                       s16 hue)
+{
+       if (tpg->hue == hue)
+               return;
+       tpg->hue = hue;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_rgb_range(struct tpg_data *tpg,
+                                       unsigned rgb_range)
+{
+       if (tpg->rgb_range == rgb_range)
+               return;
+       tpg->rgb_range = rgb_range;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_real_rgb_range(struct tpg_data *tpg,
+                                       unsigned rgb_range)
+{
+       if (tpg->real_rgb_range == rgb_range)
+               return;
+       tpg->real_rgb_range = rgb_range;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_colorspace(struct tpg_data *tpg, u32 colorspace)
+{
+       if (tpg->colorspace == colorspace)
+               return;
+       tpg->colorspace = colorspace;
+       tpg->recalc_colors = true;
+}
+
+static inline u32 tpg_g_colorspace(const struct tpg_data *tpg)
+{
+       return tpg->colorspace;
+}
+
+static inline unsigned tpg_g_planes(const struct tpg_data *tpg)
+{
+       return tpg->planes;
+}
+
+static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane)
+{
+       return tpg->twopixelsize[plane];
+}
+
+static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane)
+{
+       return tpg->bytesperline[plane];
+}
+
+static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl)
+{
+       tpg->bytesperline[plane] = bpl;
+}
+
+static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h)
+{
+       tpg->buf_height = h;
+}
+
+static inline void tpg_s_field(struct tpg_data *tpg, unsigned field)
+{
+       tpg->field = field;
+}
+
+static inline void tpg_s_perc_fill(struct tpg_data *tpg,
+                                     unsigned perc_fill)
+{
+       tpg->perc_fill = perc_fill;
+}
+
+static inline unsigned tpg_g_perc_fill(const struct tpg_data *tpg)
+{
+       return tpg->perc_fill;
+}
+
+static inline void tpg_s_perc_fill_blank(struct tpg_data *tpg,
+                                        bool perc_fill_blank)
+{
+       tpg->perc_fill_blank = perc_fill_blank;
+}
+
+static inline void tpg_s_video_aspect(struct tpg_data *tpg,
+                                       enum tpg_video_aspect vid_aspect)
+{
+       if (tpg->vid_aspect == vid_aspect)
+               return;
+       tpg->vid_aspect = vid_aspect;
+       tpg->recalc_square_border = true;
+}
+
+static inline enum tpg_video_aspect tpg_g_video_aspect(const struct tpg_data *tpg)
+{
+       return tpg->vid_aspect;
+}
+
+static inline void tpg_s_pixel_aspect(struct tpg_data *tpg,
+                                       enum tpg_pixel_aspect pix_aspect)
+{
+       if (tpg->pix_aspect == pix_aspect)
+               return;
+       tpg->pix_aspect = pix_aspect;
+       tpg->recalc_square_border = true;
+}
+
+static inline void tpg_s_show_border(struct tpg_data *tpg,
+                                       bool show_border)
+{
+       tpg->show_border = show_border;
+}
+
+static inline void tpg_s_show_square(struct tpg_data *tpg,
+                                       bool show_square)
+{
+       tpg->show_square = show_square;
+}
+
+static inline void tpg_s_insert_sav(struct tpg_data *tpg, bool insert_sav)
+{
+       tpg->insert_sav = insert_sav;
+}
+
+static inline void tpg_s_insert_eav(struct tpg_data *tpg, bool insert_eav)
+{
+       tpg->insert_eav = insert_eav;
+}
+
+void tpg_update_mv_step(struct tpg_data *tpg);
+
+static inline void tpg_s_mv_hor_mode(struct tpg_data *tpg,
+                               enum tpg_move_mode mv_hor_mode)
+{
+       tpg->mv_hor_mode = mv_hor_mode;
+       tpg_update_mv_step(tpg);
+}
+
+static inline void tpg_s_mv_vert_mode(struct tpg_data *tpg,
+                               enum tpg_move_mode mv_vert_mode)
+{
+       tpg->mv_vert_mode = mv_vert_mode;
+       tpg_update_mv_step(tpg);
+}
+
+static inline void tpg_init_mv_count(struct tpg_data *tpg)
+{
+       tpg->mv_hor_count = tpg->mv_vert_count = 0;
+}
+
+static inline void tpg_update_mv_count(struct tpg_data *tpg, bool frame_is_field)
+{
+       tpg->mv_hor_count += tpg->mv_hor_step * (frame_is_field ? 1 : 2);
+       tpg->mv_vert_count += tpg->mv_vert_step * (frame_is_field ? 1 : 2);
+}
+
+static inline void tpg_s_hflip(struct tpg_data *tpg, bool hflip)
+{
+       if (tpg->hflip == hflip)
+               return;
+       tpg->hflip = hflip;
+       tpg_update_mv_step(tpg);
+       tpg->recalc_lines = true;
+}
+
+static inline bool tpg_g_hflip(const struct tpg_data *tpg)
+{
+       return tpg->hflip;
+}
+
+static inline void tpg_s_vflip(struct tpg_data *tpg, bool vflip)
+{
+       tpg->vflip = vflip;
+}
+
+static inline bool tpg_g_vflip(const struct tpg_data *tpg)
+{
+       return tpg->vflip;
+}
+
+static inline bool tpg_pattern_is_static(const struct tpg_data *tpg)
+{
+       return tpg->pattern != TPG_PAT_NOISE &&
+              tpg->mv_hor_mode == TPG_MOVE_NONE &&
+              tpg->mv_vert_mode == TPG_MOVE_NONE;
+}
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c
new file mode 100644 (file)
index 0000000..2166d0b
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * vivid-vbi-cap.c - vbi capture support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+#include "vivid-core.h"
+#include "vivid-kthread-cap.h"
+#include "vivid-vbi-cap.h"
+#include "vivid-vbi-gen.h"
+
+static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr)
+{
+       struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen;
+       bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+
+       vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr);
+
+       if (!is_60hz) {
+               if (dev->loop_video) {
+                       if (dev->vbi_out_have_wss) {
+                               vbi_gen->data[12].data[0] = dev->vbi_out_wss[0];
+                               vbi_gen->data[12].data[1] = dev->vbi_out_wss[1];
+                       } else {
+                               vbi_gen->data[12].id = 0;
+                       }
+               } else {
+                       switch (tpg_g_video_aspect(&dev->tpg)) {
+                       case TPG_VIDEO_ASPECT_14X9_CENTRE:
+                               vbi_gen->data[12].data[0] = 0x01;
+                               break;
+                       case TPG_VIDEO_ASPECT_16X9_CENTRE:
+                               vbi_gen->data[12].data[0] = 0x0b;
+                               break;
+                       case TPG_VIDEO_ASPECT_16X9_ANAMORPHIC:
+                               vbi_gen->data[12].data[0] = 0x07;
+                               break;
+                       case TPG_VIDEO_ASPECT_4X3:
+                       default:
+                               vbi_gen->data[12].data[0] = 0x08;
+                               break;
+                       }
+               }
+       } else if (dev->loop_video && is_60hz) {
+               if (dev->vbi_out_have_cc[0]) {
+                       vbi_gen->data[0].data[0] = dev->vbi_out_cc[0][0];
+                       vbi_gen->data[0].data[1] = dev->vbi_out_cc[0][1];
+               } else {
+                       vbi_gen->data[0].id = 0;
+               }
+               if (dev->vbi_out_have_cc[1]) {
+                       vbi_gen->data[1].data[0] = dev->vbi_out_cc[1][0];
+                       vbi_gen->data[1].data[1] = dev->vbi_out_cc[1][1];
+               } else {
+                       vbi_gen->data[1].id = 0;
+               }
+       }
+}
+
+static void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi)
+{
+       bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+
+       vbi->sampling_rate = 27000000;
+       vbi->offset = 24;
+       vbi->samples_per_line = 1440;
+       vbi->sample_format = V4L2_PIX_FMT_GREY;
+       vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5;
+       vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5;
+       vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18;
+       vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0;
+       vbi->reserved[0] = 0;
+       vbi->reserved[1] = 0;
+}
+
+void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+       struct v4l2_vbi_format vbi;
+       u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+
+       vivid_g_fmt_vbi_cap(dev, &vbi);
+       buf->vb.v4l2_buf.sequence = dev->vbi_cap_seq_count;
+       if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+               buf->vb.v4l2_buf.sequence /= 2;
+
+       vivid_sliced_vbi_cap_fill(dev, buf->vb.v4l2_buf.sequence);
+
+       memset(vbuf, 0x10, vb2_plane_size(&buf->vb, 0));
+
+       if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode))
+               vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf);
+
+       v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+       buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+}
+
+
+void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+       struct v4l2_sliced_vbi_data *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+
+       buf->vb.v4l2_buf.sequence = dev->vbi_cap_seq_count;
+       if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+               buf->vb.v4l2_buf.sequence /= 2;
+
+       vivid_sliced_vbi_cap_fill(dev, buf->vb.v4l2_buf.sequence);
+
+       memset(vbuf, 0, vb2_plane_size(&buf->vb, 0));
+       if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) {
+               unsigned i;
+
+               for (i = 0; i < 25; i++)
+                       vbuf[i] = dev->vbi_gen.data[i];
+       }
+
+       v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+       buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+}
+
+static int vbi_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                      unsigned *nbuffers, unsigned *nplanes,
+                      unsigned sizes[], void *alloc_ctxs[])
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+       unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ?
+               36 * sizeof(struct v4l2_sliced_vbi_data) :
+               1440 * 2 * (is_60hz ? 12 : 18);
+
+       if (!vivid_is_sdtv_cap(dev))
+               return -EINVAL;
+
+       sizes[0] = size;
+
+       if (vq->num_buffers + *nbuffers < 2)
+               *nbuffers = 2 - vq->num_buffers;
+
+       *nplanes = 1;
+       return 0;
+}
+
+static int vbi_cap_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+       unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ?
+               36 * sizeof(struct v4l2_sliced_vbi_data) :
+               1440 * 2 * (is_60hz ? 12 : 18);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->buf_prepare_error) {
+               /*
+                * Error injection: test what happens if buf_prepare() returns
+                * an error.
+                */
+               dev->buf_prepare_error = false;
+               return -EINVAL;
+       }
+       if (vb2_plane_size(vb, 0) < size) {
+               dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+                               __func__, vb2_plane_size(vb, 0), size);
+               return -EINVAL;
+       }
+       vb2_set_plane_payload(vb, 0, size);
+
+       return 0;
+}
+
+static void vbi_cap_buf_queue(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       spin_lock(&dev->slock);
+       list_add_tail(&buf->list, &dev->vbi_cap_active);
+       spin_unlock(&dev->slock);
+}
+
+static int vbi_cap_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       int err;
+
+       dprintk(dev, 1, "%s\n", __func__);
+       dev->vbi_cap_seq_count = 0;
+       if (dev->start_streaming_error) {
+               dev->start_streaming_error = false;
+               err = -EINVAL;
+       } else {
+               err = vivid_start_generating_vid_cap(dev, &dev->vbi_cap_streaming);
+       }
+       if (err) {
+               struct vivid_buffer *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &dev->vbi_cap_active, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+       return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void vbi_cap_stop_streaming(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       dprintk(dev, 1, "%s\n", __func__);
+       vivid_stop_generating_vid_cap(dev, &dev->vbi_cap_streaming);
+}
+
+const struct vb2_ops vivid_vbi_cap_qops = {
+       .queue_setup            = vbi_cap_queue_setup,
+       .buf_prepare            = vbi_cap_buf_prepare,
+       .buf_queue              = vbi_cap_buf_queue,
+       .start_streaming        = vbi_cap_start_streaming,
+       .stop_streaming         = vbi_cap_stop_streaming,
+       .wait_prepare           = vivid_unlock,
+       .wait_finish            = vivid_lock,
+};
+
+int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_vbi_format *vbi = &f->fmt.vbi;
+
+       if (!vivid_is_sdtv_cap(dev) || !dev->has_raw_vbi_cap)
+               return -EINVAL;
+
+       vivid_g_fmt_vbi_cap(dev, vbi);
+       return 0;
+}
+
+int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       int ret = vidioc_g_fmt_vbi_cap(file, priv, f);
+
+       if (ret)
+               return ret;
+       if (dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q))
+               return -EBUSY;
+       dev->stream_sliced_vbi_cap = false;
+       dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+       return 0;
+}
+
+void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set)
+{
+       vbi->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+       vbi->service_set = service_set;
+       memset(vbi->service_lines, 0, sizeof(vbi->service_lines));
+       memset(vbi->reserved, 0, sizeof(vbi->reserved));
+
+       if (vbi->service_set == 0)
+               return;
+
+       if (vbi->service_set & V4L2_SLICED_CAPTION_525) {
+               vbi->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+               vbi->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+       }
+       if (vbi->service_set & V4L2_SLICED_WSS_625) {
+               unsigned i;
+
+               for (i = 7; i <= 18; i++)
+                       vbi->service_lines[0][i] =
+                       vbi->service_lines[1][i] = V4L2_SLICED_TELETEXT_B;
+               vbi->service_lines[0][23] = V4L2_SLICED_WSS_625;
+       }
+}
+
+int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+
+       if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap)
+               return -EINVAL;
+
+       vivid_fill_service_lines(vbi, dev->service_set_cap);
+       return 0;
+}
+
+int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+       bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+       u32 service_set = vbi->service_set;
+
+       if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap)
+               return -EINVAL;
+
+       service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 :
+                                V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+       vivid_fill_service_lines(vbi, service_set);
+       return 0;
+}
+
+int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+       int ret = vidioc_try_fmt_sliced_vbi_cap(file, fh, fmt);
+
+       if (ret)
+               return ret;
+       if (!dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q))
+               return -EBUSY;
+       dev->service_set_cap = vbi->service_set;
+       dev->stream_sliced_vbi_cap = true;
+       dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+       return 0;
+}
+
+int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+       bool is_60hz;
+
+       if (vdev->vfl_dir == VFL_DIR_RX) {
+               is_60hz = dev->std_cap & V4L2_STD_525_60;
+               if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap ||
+                   cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+                       return -EINVAL;
+       } else {
+               is_60hz = dev->std_out & V4L2_STD_525_60;
+               if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out ||
+                   cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
+                       return -EINVAL;
+       }
+
+       cap->service_set = is_60hz ? V4L2_SLICED_CAPTION_525 :
+                                    V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+       if (is_60hz) {
+               cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+               cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+       } else {
+               unsigned i;
+
+               for (i = 7; i <= 18; i++)
+                       cap->service_lines[0][i] =
+                       cap->service_lines[1][i] = V4L2_SLICED_TELETEXT_B;
+               cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+       }
+       return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.h b/drivers/media/platform/vivid/vivid-vbi-cap.h
new file mode 100644 (file)
index 0000000..2d8ea0b
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * vivid-vbi-cap.h - vbi capture support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_VBI_CAP_H_
+#define _VIVID_VBI_CAP_H_
+
+void vivid_fill_time_of_day_packet(u8 *packet);
+void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f);
+int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f);
+int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap);
+
+void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set);
+
+extern const struct vb2_ops vivid_vbi_cap_qops;
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.c b/drivers/media/platform/vivid/vivid-vbi-gen.c
new file mode 100644 (file)
index 0000000..a2159de
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * vivid-vbi-gen.c - vbi generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+
+#include "vivid-vbi-gen.h"
+
+static void wss_insert(u8 *wss, u32 val, unsigned size)
+{
+       while (size--)
+               *wss++ = (val & (1 << size)) ? 0xc0 : 0x10;
+}
+
+static void vivid_vbi_gen_wss_raw(const struct v4l2_sliced_vbi_data *data,
+               u8 *buf, unsigned sampling_rate)
+{
+       const unsigned rate = 5000000;  /* WSS has a 5 MHz transmission rate */
+       u8 wss[29 + 24 + 24 + 24 + 18 + 18] = { 0 };
+       const unsigned zero = 0x07;
+       const unsigned one = 0x38;
+       unsigned bit = 0;
+       u16 wss_data;
+       int i;
+
+       wss_insert(wss + bit, 0x1f1c71c7, 29); bit += 29;
+       wss_insert(wss + bit, 0x1e3c1f, 24); bit += 24;
+
+       wss_data = (data->data[1] << 8) | data->data[0];
+       for (i = 0; i <= 13; i++, bit += 6)
+               wss_insert(wss + bit, (wss_data & (1 << i)) ? one : zero, 6);
+
+       for (i = 0, bit = 0; bit < sizeof(wss); bit++) {
+               unsigned n = ((bit + 1) * sampling_rate) / rate;
+
+               while (i < n)
+                       buf[i++] = wss[bit];
+       }
+}
+
+static void vivid_vbi_gen_teletext_raw(const struct v4l2_sliced_vbi_data *data,
+               u8 *buf, unsigned sampling_rate)
+{
+       const unsigned rate = 6937500 / 10;     /* Teletext has a 6.9375 MHz transmission rate */
+       u8 teletext[45] = { 0x55, 0x55, 0x27 };
+       unsigned bit = 0;
+       int i;
+
+       memcpy(teletext + 3, data->data, sizeof(teletext) - 3);
+       /* prevents 32 bit overflow */
+       sampling_rate /= 10;
+
+       for (i = 0, bit = 0; bit < sizeof(teletext) * 8; bit++) {
+               unsigned n = ((bit + 1) * sampling_rate) / rate;
+               u8 val = (teletext[bit / 8] & (1 << (bit & 7))) ? 0xc0 : 0x10;
+
+               while (i < n)
+                       buf[i++] = val;
+       }
+}
+
+static void cc_insert(u8 *cc, u8 ch)
+{
+       unsigned tot = 0;
+       unsigned i;
+
+       for (i = 0; i < 7; i++) {
+               cc[2 * i] = cc[2 * i + 1] = (ch & (1 << i)) ? 1 : 0;
+               tot += cc[2 * i];
+       }
+       cc[14] = cc[15] = !(tot & 1);
+}
+
+#define CC_PREAMBLE_BITS (14 + 4 + 2)
+
+static void vivid_vbi_gen_cc_raw(const struct v4l2_sliced_vbi_data *data,
+               u8 *buf, unsigned sampling_rate)
+{
+       const unsigned rate = 1000000;  /* CC has a 1 MHz transmission rate */
+
+       u8 cc[CC_PREAMBLE_BITS + 2 * 16] = {
+               /* Clock run-in: 7 cycles */
+               0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+               /* 2 cycles of 0 */
+               0, 0, 0, 0,
+               /* Start bit of 1 (each bit is two cycles) */
+               1, 1
+       };
+       unsigned bit, i;
+
+       cc_insert(cc + CC_PREAMBLE_BITS, data->data[0]);
+       cc_insert(cc + CC_PREAMBLE_BITS + 16, data->data[1]);
+
+       for (i = 0, bit = 0; bit < sizeof(cc); bit++) {
+               unsigned n = ((bit + 1) * sampling_rate) / rate;
+
+               while (i < n)
+                       buf[i++] = cc[bit] ? 0xc0 : 0x10;
+       }
+}
+
+void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi,
+               const struct v4l2_vbi_format *vbi_fmt, u8 *buf)
+{
+       unsigned idx;
+
+       for (idx = 0; idx < 25; idx++) {
+               const struct v4l2_sliced_vbi_data *data = vbi->data + idx;
+               unsigned start_2nd_field;
+               unsigned line = data->line;
+               u8 *linebuf = buf;
+
+               start_2nd_field = (data->id & V4L2_SLICED_VBI_525) ? 263 : 313;
+               if (data->field)
+                       line += start_2nd_field;
+               line -= vbi_fmt->start[data->field];
+
+               if (vbi_fmt->flags & V4L2_VBI_INTERLACED)
+                       linebuf += (line * 2 + data->field) *
+                               vbi_fmt->samples_per_line;
+               else
+                       linebuf += (line + data->field * vbi_fmt->count[0]) *
+                               vbi_fmt->samples_per_line;
+               if (data->id == V4L2_SLICED_CAPTION_525)
+                       vivid_vbi_gen_cc_raw(data, linebuf, vbi_fmt->sampling_rate);
+               else if (data->id == V4L2_SLICED_WSS_625)
+                       vivid_vbi_gen_wss_raw(data, linebuf, vbi_fmt->sampling_rate);
+               else if (data->id == V4L2_SLICED_TELETEXT_B)
+                       vivid_vbi_gen_teletext_raw(data, linebuf, vbi_fmt->sampling_rate);
+       }
+}
+
+static const u8 vivid_cc_sequence1[30] = {
+       0x14, 0x20,     /* Resume Caption Loading */
+       'H',  'e',
+       'l',  'l',
+       'o',  ' ',
+       'w',  'o',
+       'r',  'l',
+       'd',  '!',
+       0x14, 0x2f,     /* End of Caption */
+};
+
+static const u8 vivid_cc_sequence2[30] = {
+       0x14, 0x20,     /* Resume Caption Loading */
+       'C',  'l',
+       'o',  's',
+       'e',  'd',
+       ' ',  'c',
+       'a',  'p',
+       't',  'i',
+       'o',  'n',
+       's',  ' ',
+       't',  'e',
+       's',  't',
+       0x14, 0x2f,     /* End of Caption */
+};
+
+static u8 calc_parity(u8 val)
+{
+       unsigned i;
+       unsigned tot = 0;
+
+       for (i = 0; i < 7; i++)
+               tot += (val & (1 << i)) ? 1 : 0;
+       return val | ((tot & 1) ? 0 : 0x80);
+}
+
+static void vivid_vbi_gen_set_time_of_day(u8 *packet)
+{
+       struct tm tm;
+       u8 checksum, i;
+
+       time_to_tm(get_seconds(), 0, &tm);
+       packet[0] = calc_parity(0x07);
+       packet[1] = calc_parity(0x01);
+       packet[2] = calc_parity(0x40 | tm.tm_min);
+       packet[3] = calc_parity(0x40 | tm.tm_hour);
+       packet[4] = calc_parity(0x40 | tm.tm_mday);
+       if (tm.tm_mday == 1 && tm.tm_mon == 2 &&
+           sys_tz.tz_minuteswest > tm.tm_min + tm.tm_hour * 60)
+               packet[4] = calc_parity(0x60 | tm.tm_mday);
+       packet[5] = calc_parity(0x40 | (1 + tm.tm_mon));
+       packet[6] = calc_parity(0x40 | (1 + tm.tm_wday));
+       packet[7] = calc_parity(0x40 | ((tm.tm_year - 90) & 0x3f));
+       packet[8] = calc_parity(0x0f);
+       for (checksum = i = 0; i <= 8; i++)
+               checksum += packet[i] & 0x7f;
+       packet[9] = calc_parity(0x100 - checksum);
+       checksum = 0;
+       packet[10] = calc_parity(0x07);
+       packet[11] = calc_parity(0x04);
+       if (sys_tz.tz_minuteswest >= 0)
+               packet[12] = calc_parity(0x40 | ((sys_tz.tz_minuteswest / 60) & 0x1f));
+       else
+               packet[12] = calc_parity(0x40 | ((24 + sys_tz.tz_minuteswest / 60) & 0x1f));
+       packet[13] = calc_parity(0);
+       packet[14] = calc_parity(0x0f);
+       for (checksum = 0, i = 10; i <= 14; i++)
+               checksum += packet[i] & 0x7f;
+       packet[15] = calc_parity(0x100 - checksum);
+}
+
+static const u8 hamming[16] = {
+       0x15, 0x02, 0x49, 0x5e, 0x64, 0x73, 0x38, 0x2f,
+       0xd0, 0xc7, 0x8c, 0x9b, 0xa1, 0xb6, 0xfd, 0xea
+};
+
+static void vivid_vbi_gen_teletext(u8 *packet, unsigned line, unsigned frame)
+{
+       unsigned offset = 2;
+       unsigned i;
+
+       packet[0] = hamming[1 + ((line & 1) << 3)];
+       packet[1] = hamming[line >> 1];
+       memset(packet + 2, 0x20, 40);
+       if (line == 0) {
+               /* subcode */
+               packet[2] = hamming[frame % 10];
+               packet[3] = hamming[frame / 10];
+               packet[4] = hamming[0];
+               packet[5] = hamming[0];
+               packet[6] = hamming[0];
+               packet[7] = hamming[0];
+               packet[8] = hamming[0];
+               packet[9] = hamming[1];
+               offset = 10;
+       }
+       packet += offset;
+       memcpy(packet, "Page: 100 Row: 10", 17);
+       packet[7] = '0' + frame / 10;
+       packet[8] = '0' + frame % 10;
+       packet[15] = '0' + line / 10;
+       packet[16] = '0' + line % 10;
+       for (i = 0; i < 42 - offset; i++)
+               packet[i] = calc_parity(packet[i]);
+}
+
+void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi,
+               bool is_60hz, unsigned seqnr)
+{
+       struct v4l2_sliced_vbi_data *data0 = vbi->data;
+       struct v4l2_sliced_vbi_data *data1 = vbi->data + 1;
+       unsigned frame = seqnr % 60;
+
+       memset(vbi->data, 0, sizeof(vbi->data));
+
+       if (!is_60hz) {
+               unsigned i;
+
+               for (i = 0; i <= 11; i++) {
+                       data0->id = V4L2_SLICED_TELETEXT_B;
+                       data0->line = 7 + i;
+                       vivid_vbi_gen_teletext(data0->data, i, frame);
+                       data0++;
+               }
+               data0->id = V4L2_SLICED_WSS_625;
+               data0->line = 23;
+               /* 4x3 video aspect ratio */
+               data0->data[0] = 0x08;
+               data0++;
+               for (i = 0; i <= 11; i++) {
+                       data0->id = V4L2_SLICED_TELETEXT_B;
+                       data0->field = 1;
+                       data0->line = 7 + i;
+                       vivid_vbi_gen_teletext(data0->data, 12 + i, frame);
+                       data0++;
+               }
+               return;
+       }
+
+       data0->id = V4L2_SLICED_CAPTION_525;
+       data0->line = 21;
+       data1->id = V4L2_SLICED_CAPTION_525;
+       data1->field = 1;
+       data1->line = 21;
+
+       if (frame < 15) {
+               data0->data[0] = calc_parity(vivid_cc_sequence1[2 * frame]);
+               data0->data[1] = calc_parity(vivid_cc_sequence1[2 * frame + 1]);
+       } else if (frame >= 30 && frame < 45) {
+               frame -= 30;
+               data0->data[0] = calc_parity(vivid_cc_sequence2[2 * frame]);
+               data0->data[1] = calc_parity(vivid_cc_sequence2[2 * frame + 1]);
+       } else {
+               data0->data[0] = calc_parity(0);
+               data0->data[1] = calc_parity(0);
+       }
+
+       frame = seqnr % (30 * 60);
+       switch (frame) {
+       case 0:
+               vivid_vbi_gen_set_time_of_day(vbi->time_of_day_packet);
+               /* fall through */
+       case 1 ... 7:
+               data1->data[0] = vbi->time_of_day_packet[frame * 2];
+               data1->data[1] = vbi->time_of_day_packet[frame * 2 + 1];
+               break;
+       default:
+               data1->data[0] = calc_parity(0);
+               data1->data[1] = calc_parity(0);
+               break;
+       }
+}
diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.h b/drivers/media/platform/vivid/vivid-vbi-gen.h
new file mode 100644 (file)
index 0000000..8444abe
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * vivid-vbi-gen.h - vbi generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_VBI_GEN_H_
+#define _VIVID_VBI_GEN_H_
+
+struct vivid_vbi_gen_data {
+       struct v4l2_sliced_vbi_data data[25];
+       u8 time_of_day_packet[16];
+};
+
+void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi,
+               bool is_60hz, unsigned seqnr);
+void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi,
+               const struct v4l2_vbi_format *vbi_fmt, u8 *buf);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c
new file mode 100644 (file)
index 0000000..9d00a07
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * vivid-vbi-out.c - vbi output support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+#include "vivid-core.h"
+#include "vivid-kthread-out.h"
+#include "vivid-vbi-out.h"
+#include "vivid-vbi-cap.h"
+
+static int vbi_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                      unsigned *nbuffers, unsigned *nplanes,
+                      unsigned sizes[], void *alloc_ctxs[])
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       bool is_60hz = dev->std_out & V4L2_STD_525_60;
+       unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ?
+               36 * sizeof(struct v4l2_sliced_vbi_data) :
+               1440 * 2 * (is_60hz ? 12 : 18);
+
+       if (!vivid_is_svid_out(dev))
+               return -EINVAL;
+
+       sizes[0] = size;
+
+       if (vq->num_buffers + *nbuffers < 2)
+               *nbuffers = 2 - vq->num_buffers;
+
+       *nplanes = 1;
+       return 0;
+}
+
+static int vbi_out_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       bool is_60hz = dev->std_out & V4L2_STD_525_60;
+       unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ?
+               36 * sizeof(struct v4l2_sliced_vbi_data) :
+               1440 * 2 * (is_60hz ? 12 : 18);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->buf_prepare_error) {
+               /*
+                * Error injection: test what happens if buf_prepare() returns
+                * an error.
+                */
+               dev->buf_prepare_error = false;
+               return -EINVAL;
+       }
+       if (vb2_plane_size(vb, 0) < size) {
+               dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+                               __func__, vb2_plane_size(vb, 0), size);
+               return -EINVAL;
+       }
+       vb2_set_plane_payload(vb, 0, size);
+
+       return 0;
+}
+
+static void vbi_out_buf_queue(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       spin_lock(&dev->slock);
+       list_add_tail(&buf->list, &dev->vbi_out_active);
+       spin_unlock(&dev->slock);
+}
+
+static int vbi_out_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       int err;
+
+       dprintk(dev, 1, "%s\n", __func__);
+       dev->vbi_out_seq_count = 0;
+       if (dev->start_streaming_error) {
+               dev->start_streaming_error = false;
+               err = -EINVAL;
+       } else {
+               err = vivid_start_generating_vid_out(dev, &dev->vbi_out_streaming);
+       }
+       if (err) {
+               struct vivid_buffer *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &dev->vbi_out_active, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+       return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void vbi_out_stop_streaming(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       dprintk(dev, 1, "%s\n", __func__);
+       vivid_stop_generating_vid_out(dev, &dev->vbi_out_streaming);
+       dev->vbi_out_have_wss = false;
+       dev->vbi_out_have_cc[0] = false;
+       dev->vbi_out_have_cc[1] = false;
+}
+
+const struct vb2_ops vivid_vbi_out_qops = {
+       .queue_setup            = vbi_out_queue_setup,
+       .buf_prepare            = vbi_out_buf_prepare,
+       .buf_queue              = vbi_out_buf_queue,
+       .start_streaming        = vbi_out_start_streaming,
+       .stop_streaming         = vbi_out_stop_streaming,
+       .wait_prepare           = vivid_unlock,
+       .wait_finish            = vivid_lock,
+};
+
+int vidioc_g_fmt_vbi_out(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_vbi_format *vbi = &f->fmt.vbi;
+       bool is_60hz = dev->std_out & V4L2_STD_525_60;
+
+       if (!vivid_is_svid_out(dev) || !dev->has_raw_vbi_out)
+               return -EINVAL;
+
+       vbi->sampling_rate = 25000000;
+       vbi->offset = 24;
+       vbi->samples_per_line = 1440;
+       vbi->sample_format = V4L2_PIX_FMT_GREY;
+       vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5;
+       vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5;
+       vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18;
+       vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0;
+       vbi->reserved[0] = 0;
+       vbi->reserved[1] = 0;
+       return 0;
+}
+
+int vidioc_s_fmt_vbi_out(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       int ret = vidioc_g_fmt_vbi_out(file, priv, f);
+
+       if (ret)
+               return ret;
+       if (vb2_is_busy(&dev->vb_vbi_out_q))
+               return -EBUSY;
+       dev->stream_sliced_vbi_out = false;
+       dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_VBI_OUTPUT;
+       return 0;
+}
+
+int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+
+       if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out)
+               return -EINVAL;
+
+       vivid_fill_service_lines(vbi, dev->service_set_out);
+       return 0;
+}
+
+int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+       bool is_60hz = dev->std_out & V4L2_STD_525_60;
+       u32 service_set = vbi->service_set;
+
+       if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out)
+               return -EINVAL;
+
+       service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 :
+                                V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+       vivid_fill_service_lines(vbi, service_set);
+       return 0;
+}
+
+int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+       int ret = vidioc_try_fmt_sliced_vbi_out(file, fh, fmt);
+
+       if (ret)
+               return ret;
+       if (vb2_is_busy(&dev->vb_vbi_out_q))
+               return -EBUSY;
+       dev->service_set_out = vbi->service_set;
+       dev->stream_sliced_vbi_out = true;
+       dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
+       return 0;
+}
+
+void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+       struct v4l2_sliced_vbi_data *vbi = vb2_plane_vaddr(&buf->vb, 0);
+       unsigned elems = vb2_get_plane_payload(&buf->vb, 0) / sizeof(*vbi);
+
+       dev->vbi_out_have_cc[0] = false;
+       dev->vbi_out_have_cc[1] = false;
+       dev->vbi_out_have_wss = false;
+       while (elems--) {
+               switch (vbi->id) {
+               case V4L2_SLICED_CAPTION_525:
+                       if ((dev->std_out & V4L2_STD_525_60) && vbi->line == 21) {
+                               dev->vbi_out_have_cc[!!vbi->field] = true;
+                               dev->vbi_out_cc[!!vbi->field][0] = vbi->data[0];
+                               dev->vbi_out_cc[!!vbi->field][1] = vbi->data[1];
+                       }
+                       break;
+               case V4L2_SLICED_WSS_625:
+                       if ((dev->std_out & V4L2_STD_625_50) &&
+                           vbi->field == 0 && vbi->line == 23) {
+                               dev->vbi_out_have_wss = true;
+                               dev->vbi_out_wss[0] = vbi->data[0];
+                               dev->vbi_out_wss[1] = vbi->data[1];
+                       }
+                       break;
+               }
+               vbi++;
+       }
+}
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.h b/drivers/media/platform/vivid/vivid-vbi-out.h
new file mode 100644 (file)
index 0000000..6555ba9
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * vivid-vbi-out.h - vbi output support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_VBI_OUT_H_
+#define _VIVID_VBI_OUT_H_
+
+void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+int vidioc_g_fmt_vbi_out(struct file *file, void *priv,
+                                       struct v4l2_format *f);
+int vidioc_s_fmt_vbi_out(struct file *file, void *priv,
+                                       struct v4l2_format *f);
+int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt);
+
+extern const struct vb2_ops vivid_vbi_out_qops;
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
new file mode 100644 (file)
index 0000000..331c544
--- /dev/null
@@ -0,0 +1,1730 @@
+/*
+ * vivid-vid-cap.c - video capture support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-kthread-cap.h"
+#include "vivid-vid-cap.h"
+
+/* timeperframe: min/max and default */
+static const struct v4l2_fract
+       tpf_min     = {.numerator = 1,          .denominator = FPS_MAX},
+       tpf_max     = {.numerator = FPS_MAX,    .denominator = 1},
+       tpf_default = {.numerator = 1,          .denominator = 30};
+
+static const struct vivid_fmt formats_ovl[] = {
+       {
+               .name     = "RGB565 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+               .depth    = 16,
+               .planes   = 1,
+       },
+       {
+               .name     = "XRGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+               .planes   = 1,
+       },
+       {
+               .name     = "ARGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+               .planes   = 1,
+       },
+};
+
+/* The number of discrete webcam framesizes */
+#define VIVID_WEBCAM_SIZES 3
+/* The number of discrete webcam frameintervals */
+#define VIVID_WEBCAM_IVALS (VIVID_WEBCAM_SIZES * 2)
+
+/* Sizes must be in increasing order */
+static const struct v4l2_frmsize_discrete webcam_sizes[VIVID_WEBCAM_SIZES] = {
+       {  320, 180 },
+       {  640, 360 },
+       { 1280, 720 },
+};
+
+/*
+ * Intervals must be in increasing order and there must be twice as many
+ * elements in this array as there are in webcam_sizes.
+ */
+static const struct v4l2_fract webcam_intervals[VIVID_WEBCAM_IVALS] = {
+       {  1, 10 },
+       {  1, 15 },
+       {  1, 25 },
+       {  1, 30 },
+       {  1, 50 },
+       {  1, 60 },
+};
+
+static const struct v4l2_discrete_probe webcam_probe = {
+       webcam_sizes,
+       VIVID_WEBCAM_SIZES
+};
+
+static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                      unsigned *nbuffers, unsigned *nplanes,
+                      unsigned sizes[], void *alloc_ctxs[])
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       unsigned planes = tpg_g_planes(&dev->tpg);
+       unsigned h = dev->fmt_cap_rect.height;
+       unsigned p;
+
+       if (dev->field_cap == V4L2_FIELD_ALTERNATE) {
+               /*
+                * You cannot use read() with FIELD_ALTERNATE since the field
+                * information (TOP/BOTTOM) cannot be passed back to the user.
+                */
+               if (vb2_fileio_is_active(vq))
+                       return -EINVAL;
+       }
+
+       if (dev->queue_setup_error) {
+               /*
+                * Error injection: test what happens if queue_setup() returns
+                * an error.
+                */
+               dev->queue_setup_error = false;
+               return -EINVAL;
+       }
+       if (fmt) {
+               const struct v4l2_pix_format_mplane *mp;
+               struct v4l2_format mp_fmt;
+               const struct vivid_fmt *vfmt;
+
+               if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+                       fmt_sp2mp(fmt, &mp_fmt);
+                       fmt = &mp_fmt;
+               }
+               mp = &fmt->fmt.pix_mp;
+               /*
+                * Check if the number of planes in the specified format match
+                * the number of planes in the current format. You can't mix that.
+                */
+               if (mp->num_planes != planes)
+                       return -EINVAL;
+               vfmt = vivid_get_format(dev, mp->pixelformat);
+               for (p = 0; p < planes; p++) {
+                       sizes[p] = mp->plane_fmt[p].sizeimage;
+                       if (sizes[0] < tpg_g_bytesperline(&dev->tpg, 0) * h +
+                                                       vfmt->data_offset[p])
+                               return -EINVAL;
+               }
+       } else {
+               for (p = 0; p < planes; p++)
+                       sizes[p] = tpg_g_bytesperline(&dev->tpg, p) * h +
+                                       dev->fmt_cap->data_offset[p];
+       }
+
+       if (vq->num_buffers + *nbuffers < 2)
+               *nbuffers = 2 - vq->num_buffers;
+
+       *nplanes = planes;
+
+       /*
+        * videobuf2-vmalloc allocator is context-less so no need to set
+        * alloc_ctxs array.
+        */
+
+       if (planes == 2)
+               dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__,
+                       *nbuffers, sizes[0], sizes[1]);
+       else
+               dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__,
+                       *nbuffers, sizes[0]);
+
+       return 0;
+}
+
+static int vid_cap_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       unsigned long size;
+       unsigned planes = tpg_g_planes(&dev->tpg);
+       unsigned p;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (WARN_ON(NULL == dev->fmt_cap))
+               return -EINVAL;
+
+       if (dev->buf_prepare_error) {
+               /*
+                * Error injection: test what happens if buf_prepare() returns
+                * an error.
+                */
+               dev->buf_prepare_error = false;
+               return -EINVAL;
+       }
+       for (p = 0; p < planes; p++) {
+               size = tpg_g_bytesperline(&dev->tpg, p) * dev->fmt_cap_rect.height +
+                       dev->fmt_cap->data_offset[p];
+
+               if (vb2_plane_size(vb, 0) < size) {
+                       dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n",
+                                       __func__, p, vb2_plane_size(vb, 0), size);
+                       return -EINVAL;
+               }
+
+               vb2_set_plane_payload(vb, p, size);
+               vb->v4l2_planes[p].data_offset = dev->fmt_cap->data_offset[p];
+       }
+
+       return 0;
+}
+
+static void vid_cap_buf_finish(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct v4l2_timecode *tc = &vb->v4l2_buf.timecode;
+       unsigned fps = 25;
+       unsigned seq = vb->v4l2_buf.sequence;
+
+       if (!vivid_is_sdtv_cap(dev))
+               return;
+
+       /*
+        * Set the timecode. Rarely used, so it is interesting to
+        * test this.
+        */
+       vb->v4l2_buf.flags |= V4L2_BUF_FLAG_TIMECODE;
+       if (dev->std_cap & V4L2_STD_525_60)
+               fps = 30;
+       tc->type = (fps == 30) ? V4L2_TC_TYPE_30FPS : V4L2_TC_TYPE_25FPS;
+       tc->flags = 0;
+       tc->frames = seq % fps;
+       tc->seconds = (seq / fps) % 60;
+       tc->minutes = (seq / (60 * fps)) % 60;
+       tc->hours = (seq / (60 * 60 * fps)) % 24;
+}
+
+static void vid_cap_buf_queue(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       spin_lock(&dev->slock);
+       list_add_tail(&buf->list, &dev->vid_cap_active);
+       spin_unlock(&dev->slock);
+}
+
+static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       unsigned i;
+       int err;
+
+       if (vb2_is_streaming(&dev->vb_vid_out_q))
+               dev->can_loop_video = vivid_vid_can_loop(dev);
+
+       if (dev->kthread_vid_cap)
+               return 0;
+
+       dev->vid_cap_seq_count = 0;
+       dprintk(dev, 1, "%s\n", __func__);
+       for (i = 0; i < VIDEO_MAX_FRAME; i++)
+               dev->must_blank[i] = tpg_g_perc_fill(&dev->tpg) < 100;
+       if (dev->start_streaming_error) {
+               dev->start_streaming_error = false;
+               err = -EINVAL;
+       } else {
+               err = vivid_start_generating_vid_cap(dev, &dev->vid_cap_streaming);
+       }
+       if (err) {
+               struct vivid_buffer *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &dev->vid_cap_active, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+       return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void vid_cap_stop_streaming(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       dprintk(dev, 1, "%s\n", __func__);
+       vivid_stop_generating_vid_cap(dev, &dev->vid_cap_streaming);
+       dev->can_loop_video = false;
+}
+
+const struct vb2_ops vivid_vid_cap_qops = {
+       .queue_setup            = vid_cap_queue_setup,
+       .buf_prepare            = vid_cap_buf_prepare,
+       .buf_finish             = vid_cap_buf_finish,
+       .buf_queue              = vid_cap_buf_queue,
+       .start_streaming        = vid_cap_start_streaming,
+       .stop_streaming         = vid_cap_stop_streaming,
+       .wait_prepare           = vivid_unlock,
+       .wait_finish            = vivid_lock,
+};
+
+/*
+ * Determine the 'picture' quality based on the current TV frequency: either
+ * COLOR for a good 'signal', GRAY (grayscale picture) for a slightly off
+ * signal or NOISE for no signal.
+ */
+void vivid_update_quality(struct vivid_dev *dev)
+{
+       unsigned freq_modulus;
+
+       if (dev->loop_video && (vivid_is_svid_cap(dev) || vivid_is_hdmi_cap(dev))) {
+               /*
+                * The 'noise' will only be replaced by the actual video
+                * if the output video matches the input video settings.
+                */
+               tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
+               return;
+       }
+       if (vivid_is_hdmi_cap(dev) && VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode)) {
+               tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
+               return;
+       }
+       if (vivid_is_sdtv_cap(dev) && VIVID_INVALID_SIGNAL(dev->std_signal_mode)) {
+               tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
+               return;
+       }
+       if (!vivid_is_tv_cap(dev)) {
+               tpg_s_quality(&dev->tpg, TPG_QUAL_COLOR, 0);
+               return;
+       }
+
+       /*
+        * There is a fake channel every 6 MHz at 49.25, 55.25, etc.
+        * From +/- 0.25 MHz around the channel there is color, and from
+        * +/- 1 MHz there is grayscale (chroma is lost).
+        * Everywhere else it is just noise.
+        */
+       freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16);
+       if (freq_modulus > 2 * 16) {
+               tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE,
+                       next_pseudo_random32(dev->tv_freq ^ 0x55) & 0x3f);
+               return;
+       }
+       if (freq_modulus < 12 /*0.75 * 16*/ || freq_modulus > 20 /*1.25 * 16*/)
+               tpg_s_quality(&dev->tpg, TPG_QUAL_GRAY, 0);
+       else
+               tpg_s_quality(&dev->tpg, TPG_QUAL_COLOR, 0);
+}
+
+/*
+ * Get the current picture quality and the associated afc value.
+ */
+static enum tpg_quality vivid_get_quality(struct vivid_dev *dev, s32 *afc)
+{
+       unsigned freq_modulus;
+
+       if (afc)
+               *afc = 0;
+       if (tpg_g_quality(&dev->tpg) == TPG_QUAL_COLOR ||
+           tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE)
+               return tpg_g_quality(&dev->tpg);
+
+       /*
+        * There is a fake channel every 6 MHz at 49.25, 55.25, etc.
+        * From +/- 0.25 MHz around the channel there is color, and from
+        * +/- 1 MHz there is grayscale (chroma is lost).
+        * Everywhere else it is just gray.
+        */
+       freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16);
+       if (afc)
+               *afc = freq_modulus - 1 * 16;
+       return TPG_QUAL_GRAY;
+}
+
+enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev)
+{
+       if (vivid_is_sdtv_cap(dev))
+               return dev->std_aspect_ratio;
+
+       if (vivid_is_hdmi_cap(dev))
+               return dev->dv_timings_aspect_ratio;
+
+       return TPG_VIDEO_ASPECT_IMAGE;
+}
+
+static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev)
+{
+       if (vivid_is_sdtv_cap(dev))
+               return (dev->std_cap & V4L2_STD_525_60) ?
+                       TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
+
+       if (vivid_is_hdmi_cap(dev) &&
+           dev->src_rect.width == 720 && dev->src_rect.height <= 576)
+               return dev->src_rect.height == 480 ?
+                       TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
+
+       return TPG_PIXEL_ASPECT_SQUARE;
+}
+
+/*
+ * Called whenever the format has to be reset which can occur when
+ * changing inputs, standard, timings, etc.
+ */
+void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
+{
+       struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
+       unsigned size;
+
+       switch (dev->input_type[dev->input]) {
+       case WEBCAM:
+       default:
+               dev->src_rect.width = webcam_sizes[dev->webcam_size_idx].width;
+               dev->src_rect.height = webcam_sizes[dev->webcam_size_idx].height;
+               dev->timeperframe_vid_cap = webcam_intervals[dev->webcam_ival_idx];
+               dev->field_cap = V4L2_FIELD_NONE;
+               tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO);
+               break;
+       case TV:
+       case SVID:
+               dev->field_cap = dev->tv_field_cap;
+               dev->src_rect.width = 720;
+               if (dev->std_cap & V4L2_STD_525_60) {
+                       dev->src_rect.height = 480;
+                       dev->timeperframe_vid_cap = (struct v4l2_fract) { 1001, 30000 };
+                       dev->service_set_cap = V4L2_SLICED_CAPTION_525;
+               } else {
+                       dev->src_rect.height = 576;
+                       dev->timeperframe_vid_cap = (struct v4l2_fract) { 1000, 25000 };
+                       dev->service_set_cap = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+               }
+               tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO);
+               break;
+       case HDMI:
+               dev->src_rect.width = bt->width;
+               dev->src_rect.height = bt->height;
+               size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
+               dev->timeperframe_vid_cap = (struct v4l2_fract) {
+                       size / 100, (u32)bt->pixelclock / 100
+               };
+               if (bt->interlaced)
+                       dev->field_cap = V4L2_FIELD_ALTERNATE;
+               else
+                       dev->field_cap = V4L2_FIELD_NONE;
+
+               /*
+                * We can be called from within s_ctrl, in that case we can't
+                * set/get controls. Luckily we don't need to in that case.
+                */
+               if (keep_controls || !dev->colorspace)
+                       break;
+               if (bt->standards & V4L2_DV_BT_STD_CEA861) {
+                       if (bt->width == 720 && bt->height <= 576)
+                               v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M);
+                       else
+                               v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_REC709);
+                       v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 1);
+               } else {
+                       v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB);
+                       v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 0);
+               }
+               tpg_s_rgb_range(&dev->tpg, v4l2_ctrl_g_ctrl(dev->rgb_range_cap));
+               break;
+       }
+       vivid_update_quality(dev);
+       tpg_reset_source(&dev->tpg, dev->src_rect.width, dev->src_rect.height, dev->field_cap);
+       dev->crop_cap = dev->src_rect;
+       dev->crop_bounds_cap = dev->src_rect;
+       dev->compose_cap = dev->crop_cap;
+       if (V4L2_FIELD_HAS_T_OR_B(dev->field_cap))
+               dev->compose_cap.height /= 2;
+       dev->fmt_cap_rect = dev->compose_cap;
+       tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
+       tpg_s_pixel_aspect(&dev->tpg, vivid_get_pixel_aspect(dev));
+       tpg_update_mv_step(&dev->tpg);
+}
+
+/* Map the field to something that is valid for the current input */
+static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field field)
+{
+       if (vivid_is_sdtv_cap(dev)) {
+               switch (field) {
+               case V4L2_FIELD_INTERLACED_TB:
+               case V4L2_FIELD_INTERLACED_BT:
+               case V4L2_FIELD_SEQ_TB:
+               case V4L2_FIELD_SEQ_BT:
+               case V4L2_FIELD_TOP:
+               case V4L2_FIELD_BOTTOM:
+               case V4L2_FIELD_ALTERNATE:
+                       return field;
+               case V4L2_FIELD_INTERLACED:
+               default:
+                       return V4L2_FIELD_INTERLACED;
+               }
+       }
+       if (vivid_is_hdmi_cap(dev))
+               return dev->dv_timings_cap.bt.interlaced ? V4L2_FIELD_ALTERNATE :
+                                                      V4L2_FIELD_NONE;
+       return V4L2_FIELD_NONE;
+}
+
+static unsigned vivid_colorspace_cap(struct vivid_dev *dev)
+{
+       if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+               return tpg_g_colorspace(&dev->tpg);
+       return dev->colorspace_out;
+}
+
+int vivid_g_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+       unsigned p;
+
+       mp->width        = dev->fmt_cap_rect.width;
+       mp->height       = dev->fmt_cap_rect.height;
+       mp->field        = dev->field_cap;
+       mp->pixelformat  = dev->fmt_cap->fourcc;
+       mp->colorspace   = vivid_colorspace_cap(dev);
+       mp->num_planes = dev->fmt_cap->planes;
+       for (p = 0; p < mp->num_planes; p++) {
+               mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p);
+               mp->plane_fmt[p].sizeimage =
+                       mp->plane_fmt[p].bytesperline * mp->height +
+                       dev->fmt_cap->data_offset[p];
+       }
+       return 0;
+}
+
+int vivid_try_fmt_vid_cap(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+       struct v4l2_plane_pix_format *pfmt = mp->plane_fmt;
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct vivid_fmt *fmt;
+       unsigned bytesperline, max_bpl;
+       unsigned factor = 1;
+       unsigned w, h;
+       unsigned p;
+
+       fmt = vivid_get_format(dev, mp->pixelformat);
+       if (!fmt) {
+               dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
+                       mp->pixelformat);
+               mp->pixelformat = V4L2_PIX_FMT_YUYV;
+               fmt = vivid_get_format(dev, mp->pixelformat);
+       }
+
+       mp->field = vivid_field_cap(dev, mp->field);
+       if (vivid_is_webcam(dev)) {
+               const struct v4l2_frmsize_discrete *sz =
+                       v4l2_find_nearest_format(&webcam_probe, mp->width, mp->height);
+
+               w = sz->width;
+               h = sz->height;
+       } else if (vivid_is_sdtv_cap(dev)) {
+               w = 720;
+               h = (dev->std_cap & V4L2_STD_525_60) ? 480 : 576;
+       } else {
+               w = dev->src_rect.width;
+               h = dev->src_rect.height;
+       }
+       if (V4L2_FIELD_HAS_T_OR_B(mp->field))
+               factor = 2;
+       if (vivid_is_webcam(dev) ||
+           (!dev->has_scaler_cap && !dev->has_crop_cap && !dev->has_compose_cap)) {
+               mp->width = w;
+               mp->height = h / factor;
+       } else {
+               struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor };
+
+               rect_set_min_size(&r, &vivid_min_rect);
+               rect_set_max_size(&r, &vivid_max_rect);
+               if (dev->has_scaler_cap && !dev->has_compose_cap) {
+                       struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h };
+
+                       rect_set_max_size(&r, &max_r);
+               } else if (!dev->has_scaler_cap && dev->has_crop_cap && !dev->has_compose_cap) {
+                       rect_set_max_size(&r, &dev->src_rect);
+               } else if (!dev->has_scaler_cap && !dev->has_crop_cap) {
+                       rect_set_min_size(&r, &dev->src_rect);
+               }
+               mp->width = r.width;
+               mp->height = r.height / factor;
+       }
+
+       /* This driver supports custom bytesperline values */
+
+       /* Calculate the minimum supported bytesperline value */
+       bytesperline = (mp->width * fmt->depth) >> 3;
+       /* Calculate the maximum supported bytesperline value */
+       max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3;
+       mp->num_planes = fmt->planes;
+       for (p = 0; p < mp->num_planes; p++) {
+               if (pfmt[p].bytesperline > max_bpl)
+                       pfmt[p].bytesperline = max_bpl;
+               if (pfmt[p].bytesperline < bytesperline)
+                       pfmt[p].bytesperline = bytesperline;
+               pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height +
+                       fmt->data_offset[p];
+               memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
+       }
+       mp->colorspace = vivid_colorspace_cap(dev);
+       memset(mp->reserved, 0, sizeof(mp->reserved));
+       return 0;
+}
+
+int vivid_s_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_rect *crop = &dev->crop_cap;
+       struct v4l2_rect *compose = &dev->compose_cap;
+       struct vb2_queue *q = &dev->vb_vid_cap_q;
+       int ret = vivid_try_fmt_vid_cap(file, priv, f);
+       unsigned factor = 1;
+       unsigned i;
+
+       if (ret < 0)
+               return ret;
+
+       if (vb2_is_busy(q)) {
+               dprintk(dev, 1, "%s device busy\n", __func__);
+               return -EBUSY;
+       }
+
+       if (dev->overlay_cap_owner && dev->fb_cap.fmt.pixelformat != mp->pixelformat) {
+               dprintk(dev, 1, "overlay is active, can't change pixelformat\n");
+               return -EBUSY;
+       }
+
+       dev->fmt_cap = vivid_get_format(dev, mp->pixelformat);
+       if (V4L2_FIELD_HAS_T_OR_B(mp->field))
+               factor = 2;
+
+       /* Note: the webcam input doesn't support scaling, cropping or composing */
+
+       if (!vivid_is_webcam(dev) &&
+           (dev->has_scaler_cap || dev->has_crop_cap || dev->has_compose_cap)) {
+               struct v4l2_rect r = { 0, 0, mp->width, mp->height };
+
+               if (dev->has_scaler_cap) {
+                       if (dev->has_compose_cap)
+                               rect_map_inside(compose, &r);
+                       else
+                               *compose = r;
+                       if (dev->has_crop_cap && !dev->has_compose_cap) {
+                               struct v4l2_rect min_r = {
+                                       0, 0,
+                                       r.width / MAX_ZOOM,
+                                       factor * r.height / MAX_ZOOM
+                               };
+                               struct v4l2_rect max_r = {
+                                       0, 0,
+                                       r.width * MAX_ZOOM,
+                                       factor * r.height * MAX_ZOOM
+                               };
+
+                               rect_set_min_size(crop, &min_r);
+                               rect_set_max_size(crop, &max_r);
+                               rect_map_inside(crop, &dev->crop_bounds_cap);
+                       } else if (dev->has_crop_cap) {
+                               struct v4l2_rect min_r = {
+                                       0, 0,
+                                       compose->width / MAX_ZOOM,
+                                       factor * compose->height / MAX_ZOOM
+                               };
+                               struct v4l2_rect max_r = {
+                                       0, 0,
+                                       compose->width * MAX_ZOOM,
+                                       factor * compose->height * MAX_ZOOM
+                               };
+
+                               rect_set_min_size(crop, &min_r);
+                               rect_set_max_size(crop, &max_r);
+                               rect_map_inside(crop, &dev->crop_bounds_cap);
+                       }
+               } else if (dev->has_crop_cap && !dev->has_compose_cap) {
+                       r.height *= factor;
+                       rect_set_size_to(crop, &r);
+                       rect_map_inside(crop, &dev->crop_bounds_cap);
+                       r = *crop;
+                       r.height /= factor;
+                       rect_set_size_to(compose, &r);
+               } else if (!dev->has_crop_cap) {
+                       rect_map_inside(compose, &r);
+               } else {
+                       r.height *= factor;
+                       rect_set_max_size(crop, &r);
+                       rect_map_inside(crop, &dev->crop_bounds_cap);
+                       compose->top *= factor;
+                       compose->height *= factor;
+                       rect_set_size_to(compose, crop);
+                       rect_map_inside(compose, &r);
+                       compose->top /= factor;
+                       compose->height /= factor;
+               }
+       } else if (vivid_is_webcam(dev)) {
+               /* Guaranteed to be a match */
+               for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++)
+                       if (webcam_sizes[i].width == mp->width &&
+                                       webcam_sizes[i].height == mp->height)
+                               break;
+               dev->webcam_size_idx = i;
+               if (dev->webcam_ival_idx >= 2 * (3 - i))
+                       dev->webcam_ival_idx = 2 * (3 - i) - 1;
+               vivid_update_format_cap(dev, false);
+       } else {
+               struct v4l2_rect r = { 0, 0, mp->width, mp->height };
+
+               rect_set_size_to(compose, &r);
+               r.height *= factor;
+               rect_set_size_to(crop, &r);
+       }
+
+       dev->fmt_cap_rect.width = mp->width;
+       dev->fmt_cap_rect.height = mp->height;
+       tpg_s_buf_height(&dev->tpg, mp->height);
+       tpg_s_bytesperline(&dev->tpg, 0, mp->plane_fmt[0].bytesperline);
+       if (tpg_g_planes(&dev->tpg) > 1)
+               tpg_s_bytesperline(&dev->tpg, 1, mp->plane_fmt[1].bytesperline);
+       dev->field_cap = mp->field;
+       tpg_s_field(&dev->tpg, dev->field_cap);
+       tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap);
+       tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
+       if (vivid_is_sdtv_cap(dev))
+               dev->tv_field_cap = mp->field;
+       tpg_update_mv_step(&dev->tpg);
+       return 0;
+}
+
+int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_g_fmt_vid_cap(file, priv, f);
+}
+
+int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_try_fmt_vid_cap(file, priv, f);
+}
+
+int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_s_fmt_vid_cap(file, priv, f);
+}
+
+int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_cap);
+}
+
+int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_cap);
+}
+
+int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_cap);
+}
+
+int vivid_vid_cap_g_selection(struct file *file, void *priv,
+                             struct v4l2_selection *sel)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->has_crop_cap && !dev->has_compose_cap)
+               return -ENOTTY;
+       if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (vivid_is_webcam(dev))
+               return -EINVAL;
+
+       sel->r.left = sel->r.top = 0;
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP:
+               if (!dev->has_crop_cap)
+                       return -EINVAL;
+               sel->r = dev->crop_cap;
+               break;
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               if (!dev->has_crop_cap)
+                       return -EINVAL;
+               sel->r = dev->src_rect;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               if (!dev->has_compose_cap)
+                       return -EINVAL;
+               sel->r = vivid_max_rect;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+               if (!dev->has_compose_cap)
+                       return -EINVAL;
+               sel->r = dev->compose_cap;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+               if (!dev->has_compose_cap)
+                       return -EINVAL;
+               sel->r = dev->fmt_cap_rect;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_rect *crop = &dev->crop_cap;
+       struct v4l2_rect *compose = &dev->compose_cap;
+       unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
+       int ret;
+
+       if (!dev->has_crop_cap && !dev->has_compose_cap)
+               return -ENOTTY;
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (vivid_is_webcam(dev))
+               return -EINVAL;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP:
+               if (!dev->has_crop_cap)
+                       return -EINVAL;
+               ret = vivid_vid_adjust_sel(s->flags, &s->r);
+               if (ret)
+                       return ret;
+               rect_set_min_size(&s->r, &vivid_min_rect);
+               rect_set_max_size(&s->r, &dev->src_rect);
+               rect_map_inside(&s->r, &dev->crop_bounds_cap);
+               s->r.top /= factor;
+               s->r.height /= factor;
+               if (dev->has_scaler_cap) {
+                       struct v4l2_rect fmt = dev->fmt_cap_rect;
+                       struct v4l2_rect max_rect = {
+                               0, 0,
+                               s->r.width * MAX_ZOOM,
+                               s->r.height * MAX_ZOOM
+                       };
+                       struct v4l2_rect min_rect = {
+                               0, 0,
+                               s->r.width / MAX_ZOOM,
+                               s->r.height / MAX_ZOOM
+                       };
+
+                       rect_set_min_size(&fmt, &min_rect);
+                       if (!dev->has_compose_cap)
+                               rect_set_max_size(&fmt, &max_rect);
+                       if (!rect_same_size(&dev->fmt_cap_rect, &fmt) &&
+                           vb2_is_busy(&dev->vb_vid_cap_q))
+                               return -EBUSY;
+                       if (dev->has_compose_cap) {
+                               rect_set_min_size(compose, &min_rect);
+                               rect_set_max_size(compose, &max_rect);
+                       }
+                       dev->fmt_cap_rect = fmt;
+                       tpg_s_buf_height(&dev->tpg, fmt.height);
+               } else if (dev->has_compose_cap) {
+                       struct v4l2_rect fmt = dev->fmt_cap_rect;
+
+                       rect_set_min_size(&fmt, &s->r);
+                       if (!rect_same_size(&dev->fmt_cap_rect, &fmt) &&
+                           vb2_is_busy(&dev->vb_vid_cap_q))
+                               return -EBUSY;
+                       dev->fmt_cap_rect = fmt;
+                       tpg_s_buf_height(&dev->tpg, fmt.height);
+                       rect_set_size_to(compose, &s->r);
+                       rect_map_inside(compose, &dev->fmt_cap_rect);
+               } else {
+                       if (!rect_same_size(&s->r, &dev->fmt_cap_rect) &&
+                           vb2_is_busy(&dev->vb_vid_cap_q))
+                               return -EBUSY;
+                       rect_set_size_to(&dev->fmt_cap_rect, &s->r);
+                       rect_set_size_to(compose, &s->r);
+                       rect_map_inside(compose, &dev->fmt_cap_rect);
+                       tpg_s_buf_height(&dev->tpg, dev->fmt_cap_rect.height);
+               }
+               s->r.top *= factor;
+               s->r.height *= factor;
+               *crop = s->r;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+               if (!dev->has_compose_cap)
+                       return -EINVAL;
+               ret = vivid_vid_adjust_sel(s->flags, &s->r);
+               if (ret)
+                       return ret;
+               rect_set_min_size(&s->r, &vivid_min_rect);
+               rect_set_max_size(&s->r, &dev->fmt_cap_rect);
+               if (dev->has_scaler_cap) {
+                       struct v4l2_rect max_rect = {
+                               0, 0,
+                               dev->src_rect.width * MAX_ZOOM,
+                               (dev->src_rect.height / factor) * MAX_ZOOM
+                       };
+
+                       rect_set_max_size(&s->r, &max_rect);
+                       if (dev->has_crop_cap) {
+                               struct v4l2_rect min_rect = {
+                                       0, 0,
+                                       s->r.width / MAX_ZOOM,
+                                       (s->r.height * factor) / MAX_ZOOM
+                               };
+                               struct v4l2_rect max_rect = {
+                                       0, 0,
+                                       s->r.width * MAX_ZOOM,
+                                       (s->r.height * factor) * MAX_ZOOM
+                               };
+
+                               rect_set_min_size(crop, &min_rect);
+                               rect_set_max_size(crop, &max_rect);
+                               rect_map_inside(crop, &dev->crop_bounds_cap);
+                       }
+               } else if (dev->has_crop_cap) {
+                       s->r.top *= factor;
+                       s->r.height *= factor;
+                       rect_set_max_size(&s->r, &dev->src_rect);
+                       rect_set_size_to(crop, &s->r);
+                       rect_map_inside(crop, &dev->crop_bounds_cap);
+                       s->r.top /= factor;
+                       s->r.height /= factor;
+               } else {
+                       rect_set_size_to(&s->r, &dev->src_rect);
+                       s->r.height /= factor;
+               }
+               rect_map_inside(&s->r, &dev->fmt_cap_rect);
+               if (dev->bitmap_cap && (compose->width != s->r.width ||
+                                       compose->height != s->r.height)) {
+                       kfree(dev->bitmap_cap);
+                       dev->bitmap_cap = NULL;
+               }
+               *compose = s->r;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       tpg_s_crop_compose(&dev->tpg, crop, compose);
+       return 0;
+}
+
+int vivid_vid_cap_cropcap(struct file *file, void *priv,
+                             struct v4l2_cropcap *cap)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       switch (vivid_get_pixel_aspect(dev)) {
+       case TPG_PIXEL_ASPECT_NTSC:
+               cap->pixelaspect.numerator = 11;
+               cap->pixelaspect.denominator = 10;
+               break;
+       case TPG_PIXEL_ASPECT_PAL:
+               cap->pixelaspect.numerator = 54;
+               cap->pixelaspect.denominator = 59;
+               break;
+       case TPG_PIXEL_ASPECT_SQUARE:
+               cap->pixelaspect.numerator = 1;
+               cap->pixelaspect.denominator = 1;
+               break;
+       }
+       return 0;
+}
+
+int vidioc_enum_fmt_vid_overlay(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       const struct vivid_fmt *fmt;
+
+       if (f->index >= ARRAY_SIZE(formats_ovl))
+               return -EINVAL;
+
+       fmt = &formats_ovl[f->index];
+
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+       return 0;
+}
+
+int vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct v4l2_rect *compose = &dev->compose_cap;
+       struct v4l2_window *win = &f->fmt.win;
+       unsigned clipcount = win->clipcount;
+
+       win->w.top = dev->overlay_cap_top;
+       win->w.left = dev->overlay_cap_left;
+       win->w.width = compose->width;
+       win->w.height = compose->height;
+       win->field = dev->overlay_cap_field;
+       win->clipcount = dev->clipcount_cap;
+       if (clipcount > dev->clipcount_cap)
+               clipcount = dev->clipcount_cap;
+       if (dev->bitmap_cap == NULL)
+               win->bitmap = NULL;
+       else if (win->bitmap) {
+               if (copy_to_user(win->bitmap, dev->bitmap_cap,
+                   ((compose->width + 7) / 8) * compose->height))
+                       return -EFAULT;
+       }
+       if (clipcount && win->clips) {
+               if (copy_to_user(win->clips, dev->clips_cap,
+                                clipcount * sizeof(dev->clips_cap[0])))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct v4l2_rect *compose = &dev->compose_cap;
+       struct v4l2_window *win = &f->fmt.win;
+       int i, j;
+
+       win->w.left = clamp_t(int, win->w.left,
+                             -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width);
+       win->w.top = clamp_t(int, win->w.top,
+                            -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height);
+       win->w.width = compose->width;
+       win->w.height = compose->height;
+       if (win->field != V4L2_FIELD_BOTTOM && win->field != V4L2_FIELD_TOP)
+               win->field = V4L2_FIELD_ANY;
+       win->chromakey = 0;
+       win->global_alpha = 0;
+       if (win->clipcount && !win->clips)
+               win->clipcount = 0;
+       if (win->clipcount > MAX_CLIPS)
+               win->clipcount = MAX_CLIPS;
+       if (win->clipcount) {
+               if (copy_from_user(dev->try_clips_cap, win->clips,
+                                  win->clipcount * sizeof(dev->clips_cap[0])))
+                       return -EFAULT;
+               for (i = 0; i < win->clipcount; i++) {
+                       struct v4l2_rect *r = &dev->try_clips_cap[i].c;
+
+                       r->top = clamp_t(s32, r->top, 0, dev->fb_cap.fmt.height - 1);
+                       r->height = clamp_t(s32, r->height, 1, dev->fb_cap.fmt.height - r->top);
+                       r->left = clamp_t(u32, r->left, 0, dev->fb_cap.fmt.width - 1);
+                       r->width = clamp_t(u32, r->width, 1, dev->fb_cap.fmt.width - r->left);
+               }
+               /*
+                * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small
+                * number and it's typically a one-time deal.
+                */
+               for (i = 0; i < win->clipcount - 1; i++) {
+                       struct v4l2_rect *r1 = &dev->try_clips_cap[i].c;
+
+                       for (j = i + 1; j < win->clipcount; j++) {
+                               struct v4l2_rect *r2 = &dev->try_clips_cap[j].c;
+
+                               if (rect_overlap(r1, r2))
+                                       return -EINVAL;
+                       }
+               }
+               if (copy_to_user(win->clips, dev->try_clips_cap,
+                                win->clipcount * sizeof(dev->clips_cap[0])))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct v4l2_rect *compose = &dev->compose_cap;
+       struct v4l2_window *win = &f->fmt.win;
+       int ret = vidioc_try_fmt_vid_overlay(file, priv, f);
+       unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height;
+       unsigned clips_size = win->clipcount * sizeof(dev->clips_cap[0]);
+       void *new_bitmap = NULL;
+
+       if (ret)
+               return ret;
+
+       if (win->bitmap) {
+               new_bitmap = vzalloc(bitmap_size);
+
+               if (new_bitmap == NULL)
+                       return -ENOMEM;
+               if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) {
+                       vfree(new_bitmap);
+                       return -EFAULT;
+               }
+       }
+
+       dev->overlay_cap_top = win->w.top;
+       dev->overlay_cap_left = win->w.left;
+       dev->overlay_cap_field = win->field;
+       vfree(dev->bitmap_cap);
+       dev->bitmap_cap = new_bitmap;
+       dev->clipcount_cap = win->clipcount;
+       if (dev->clipcount_cap)
+               memcpy(dev->clips_cap, dev->try_clips_cap, clips_size);
+       return 0;
+}
+
+int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (i && dev->fb_vbase_cap == NULL)
+               return -EINVAL;
+
+       if (i && dev->fb_cap.fmt.pixelformat != dev->fmt_cap->fourcc) {
+               dprintk(dev, 1, "mismatch between overlay and video capture pixelformats\n");
+               return -EINVAL;
+       }
+
+       if (dev->overlay_cap_owner && dev->overlay_cap_owner != fh)
+               return -EBUSY;
+       dev->overlay_cap_owner = i ? fh : NULL;
+       return 0;
+}
+
+int vivid_vid_cap_g_fbuf(struct file *file, void *fh,
+                               struct v4l2_framebuffer *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       *a = dev->fb_cap;
+       a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING |
+                       V4L2_FBUF_CAP_LIST_CLIPPING;
+       a->flags = V4L2_FBUF_FLAG_PRIMARY;
+       a->fmt.field = V4L2_FIELD_NONE;
+       a->fmt.colorspace = V4L2_COLORSPACE_SRGB;
+       a->fmt.priv = 0;
+       return 0;
+}
+
+int vivid_vid_cap_s_fbuf(struct file *file, void *fh,
+                               const struct v4l2_framebuffer *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct vivid_fmt *fmt;
+
+       if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       if (dev->overlay_cap_owner)
+               return -EBUSY;
+
+       if (a->base == NULL) {
+               dev->fb_cap.base = NULL;
+               dev->fb_vbase_cap = NULL;
+               return 0;
+       }
+
+       if (a->fmt.width < 48 || a->fmt.height < 32)
+               return -EINVAL;
+       fmt = vivid_get_format(dev, a->fmt.pixelformat);
+       if (!fmt || !fmt->can_do_overlay)
+               return -EINVAL;
+       if (a->fmt.bytesperline < (a->fmt.width * fmt->depth) / 8)
+               return -EINVAL;
+       if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage)
+               return -EINVAL;
+
+       dev->fb_vbase_cap = phys_to_virt((unsigned long)a->base);
+       dev->fb_cap = *a;
+       dev->overlay_cap_left = clamp_t(int, dev->overlay_cap_left,
+                                   -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width);
+       dev->overlay_cap_top = clamp_t(int, dev->overlay_cap_top,
+                                  -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height);
+       return 0;
+}
+
+static const struct v4l2_audio vivid_audio_inputs[] = {
+       { 0, "TV", V4L2_AUDCAP_STEREO },
+       { 1, "Line-In", V4L2_AUDCAP_STEREO },
+};
+
+int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *inp)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (inp->index >= dev->num_inputs)
+               return -EINVAL;
+
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+       switch (dev->input_type[inp->index]) {
+       case WEBCAM:
+               snprintf(inp->name, sizeof(inp->name), "Webcam %u",
+                               dev->input_name_counter[inp->index]);
+               inp->capabilities = 0;
+               break;
+       case TV:
+               snprintf(inp->name, sizeof(inp->name), "TV %u",
+                               dev->input_name_counter[inp->index]);
+               inp->type = V4L2_INPUT_TYPE_TUNER;
+               inp->std = V4L2_STD_ALL;
+               if (dev->has_audio_inputs)
+                       inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1;
+               inp->capabilities = V4L2_IN_CAP_STD;
+               break;
+       case SVID:
+               snprintf(inp->name, sizeof(inp->name), "S-Video %u",
+                               dev->input_name_counter[inp->index]);
+               inp->std = V4L2_STD_ALL;
+               if (dev->has_audio_inputs)
+                       inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1;
+               inp->capabilities = V4L2_IN_CAP_STD;
+               break;
+       case HDMI:
+               snprintf(inp->name, sizeof(inp->name), "HDMI %u",
+                               dev->input_name_counter[inp->index]);
+               inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
+               if (dev->edid_blocks == 0 ||
+                   dev->dv_timings_signal_mode == NO_SIGNAL)
+                       inp->status |= V4L2_IN_ST_NO_SIGNAL;
+               else if (dev->dv_timings_signal_mode == NO_LOCK ||
+                        dev->dv_timings_signal_mode == OUT_OF_RANGE)
+                       inp->status |= V4L2_IN_ST_NO_H_LOCK;
+               break;
+       }
+       if (dev->sensor_hflip)
+               inp->status |= V4L2_IN_ST_HFLIP;
+       if (dev->sensor_vflip)
+               inp->status |= V4L2_IN_ST_VFLIP;
+       if (dev->input == inp->index && vivid_is_sdtv_cap(dev)) {
+               if (dev->std_signal_mode == NO_SIGNAL) {
+                       inp->status |= V4L2_IN_ST_NO_SIGNAL;
+               } else if (dev->std_signal_mode == NO_LOCK) {
+                       inp->status |= V4L2_IN_ST_NO_H_LOCK;
+               } else if (vivid_is_tv_cap(dev)) {
+                       switch (tpg_g_quality(&dev->tpg)) {
+                       case TPG_QUAL_GRAY:
+                               inp->status |= V4L2_IN_ST_COLOR_KILL;
+                               break;
+                       case TPG_QUAL_NOISE:
+                               inp->status |= V4L2_IN_ST_NO_H_LOCK;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+int vidioc_g_input(struct file *file, void *priv, unsigned *i)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       *i = dev->input;
+       return 0;
+}
+
+int vidioc_s_input(struct file *file, void *priv, unsigned i)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
+       unsigned brightness;
+
+       if (i >= dev->num_inputs)
+               return -EINVAL;
+
+       if (i == dev->input)
+               return 0;
+
+       if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q))
+               return -EBUSY;
+
+       dev->input = i;
+       dev->vid_cap_dev.tvnorms = 0;
+       if (dev->input_type[i] == TV || dev->input_type[i] == SVID) {
+               dev->tv_audio_input = (dev->input_type[i] == TV) ? 0 : 1;
+               dev->vid_cap_dev.tvnorms = V4L2_STD_ALL;
+       }
+       dev->vbi_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms;
+       vivid_update_format_cap(dev, false);
+
+       if (dev->colorspace) {
+               switch (dev->input_type[i]) {
+               case WEBCAM:
+                       v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB);
+                       break;
+               case TV:
+               case SVID:
+                       v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M);
+                       break;
+               case HDMI:
+                       if (bt->standards & V4L2_DV_BT_STD_CEA861) {
+                               if (dev->src_rect.width == 720 && dev->src_rect.height <= 576)
+                                       v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M);
+                               else
+                                       v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_REC709);
+                       } else {
+                               v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB);
+                       }
+                       break;
+               }
+       }
+
+       /*
+        * Modify the brightness range depending on the input.
+        * This makes it easy to use vivid to test if applications can
+        * handle control range modifications and is also how this is
+        * typically used in practice as different inputs may be hooked
+        * up to different receivers with different control ranges.
+        */
+       brightness = 128 * i + dev->input_brightness[i];
+       v4l2_ctrl_modify_range(dev->brightness,
+                       128 * i, 255 + 128 * i, 1, 128 + 128 * i);
+       v4l2_ctrl_s_ctrl(dev->brightness, brightness);
+       return 0;
+}
+
+int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+       if (vin->index >= ARRAY_SIZE(vivid_audio_inputs))
+               return -EINVAL;
+       *vin = vivid_audio_inputs[vin->index];
+       return 0;
+}
+
+int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_sdtv_cap(dev))
+               return -EINVAL;
+       *vin = vivid_audio_inputs[dev->tv_audio_input];
+       return 0;
+}
+
+int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_sdtv_cap(dev))
+               return -EINVAL;
+       if (vin->index >= ARRAY_SIZE(vivid_audio_inputs))
+               return -EINVAL;
+       dev->tv_audio_input = vin->index;
+       return 0;
+}
+
+int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (vf->tuner != 0)
+               return -EINVAL;
+       vf->frequency = dev->tv_freq;
+       return 0;
+}
+
+int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (vf->tuner != 0)
+               return -EINVAL;
+       dev->tv_freq = clamp_t(unsigned, vf->frequency, MIN_TV_FREQ, MAX_TV_FREQ);
+       if (vivid_is_tv_cap(dev))
+               vivid_update_quality(dev);
+       return 0;
+}
+
+int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (vt->index != 0)
+               return -EINVAL;
+       if (vt->audmode > V4L2_TUNER_MODE_LANG1_LANG2)
+               return -EINVAL;
+       dev->tv_audmode = vt->audmode;
+       return 0;
+}
+
+int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       enum tpg_quality qual;
+
+       if (vt->index != 0)
+               return -EINVAL;
+
+       vt->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
+                        V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+       vt->audmode = dev->tv_audmode;
+       vt->rangelow = MIN_TV_FREQ;
+       vt->rangehigh = MAX_TV_FREQ;
+       qual = vivid_get_quality(dev, &vt->afc);
+       if (qual == TPG_QUAL_COLOR)
+               vt->signal = 0xffff;
+       else if (qual == TPG_QUAL_GRAY)
+               vt->signal = 0x8000;
+       else
+               vt->signal = 0;
+       if (qual == TPG_QUAL_NOISE) {
+               vt->rxsubchans = 0;
+       } else if (qual == TPG_QUAL_GRAY) {
+               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+       } else {
+               unsigned channel_nr = dev->tv_freq / (6 * 16);
+               unsigned options = (dev->std_cap & V4L2_STD_NTSC_M) ? 4 : 3;
+
+               switch (channel_nr % options) {
+               case 0:
+                       vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+                       break;
+               case 1:
+                       vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       break;
+               case 2:
+                       if (dev->std_cap & V4L2_STD_NTSC_M)
+                               vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP;
+                       else
+                               vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+                       break;
+               case 3:
+                       vt->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_SAP;
+                       break;
+               }
+       }
+       strlcpy(vt->name, "TV Tuner", sizeof(vt->name));
+       return 0;
+}
+
+/* Must remain in sync with the vivid_ctrl_standard_strings array */
+const v4l2_std_id vivid_standard[] = {
+       V4L2_STD_NTSC_M,
+       V4L2_STD_NTSC_M_JP,
+       V4L2_STD_NTSC_M_KR,
+       V4L2_STD_NTSC_443,
+       V4L2_STD_PAL_BG | V4L2_STD_PAL_H,
+       V4L2_STD_PAL_I,
+       V4L2_STD_PAL_DK,
+       V4L2_STD_PAL_M,
+       V4L2_STD_PAL_N,
+       V4L2_STD_PAL_Nc,
+       V4L2_STD_PAL_60,
+       V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
+       V4L2_STD_SECAM_DK,
+       V4L2_STD_SECAM_L,
+       V4L2_STD_SECAM_LC,
+       V4L2_STD_UNKNOWN
+};
+
+/* Must remain in sync with the vivid_standard array */
+const char * const vivid_ctrl_standard_strings[] = {
+       "NTSC-M",
+       "NTSC-M-JP",
+       "NTSC-M-KR",
+       "NTSC-443",
+       "PAL-BGH",
+       "PAL-I",
+       "PAL-DK",
+       "PAL-M",
+       "PAL-N",
+       "PAL-Nc",
+       "PAL-60",
+       "SECAM-BGH",
+       "SECAM-DK",
+       "SECAM-L",
+       "SECAM-Lc",
+       NULL,
+};
+
+int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_sdtv_cap(dev))
+               return -ENODATA;
+       if (dev->std_signal_mode == NO_SIGNAL ||
+           dev->std_signal_mode == NO_LOCK) {
+               *id = V4L2_STD_UNKNOWN;
+               return 0;
+       }
+       if (vivid_is_tv_cap(dev) && tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) {
+               *id = V4L2_STD_UNKNOWN;
+       } else if (dev->std_signal_mode == CURRENT_STD) {
+               *id = dev->std_cap;
+       } else if (dev->std_signal_mode == SELECTED_STD) {
+               *id = dev->query_std;
+       } else {
+               *id = vivid_standard[dev->query_std_last];
+               dev->query_std_last = (dev->query_std_last + 1) % ARRAY_SIZE(vivid_standard);
+       }
+
+       return 0;
+}
+
+int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_sdtv_cap(dev))
+               return -ENODATA;
+       if (dev->std_cap == id)
+               return 0;
+       if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q))
+               return -EBUSY;
+       dev->std_cap = id;
+       vivid_update_format_cap(dev, false);
+       return 0;
+}
+
+int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh,
+                                   struct v4l2_dv_timings *timings)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_hdmi_cap(dev))
+               return -ENODATA;
+       if (vb2_is_busy(&dev->vb_vid_cap_q))
+               return -EBUSY;
+       if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap,
+                               0, NULL, NULL))
+               return -EINVAL;
+       if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0))
+               return 0;
+       dev->dv_timings_cap = *timings;
+       vivid_update_format_cap(dev, false);
+       return 0;
+}
+
+int vidioc_query_dv_timings(struct file *file, void *_fh,
+                                   struct v4l2_dv_timings *timings)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_hdmi_cap(dev))
+               return -ENODATA;
+       if (dev->dv_timings_signal_mode == NO_SIGNAL ||
+           dev->edid_blocks == 0)
+               return -ENOLINK;
+       if (dev->dv_timings_signal_mode == NO_LOCK)
+               return -ENOLCK;
+       if (dev->dv_timings_signal_mode == OUT_OF_RANGE) {
+               timings->bt.pixelclock = vivid_dv_timings_cap.bt.max_pixelclock * 2;
+               return -ERANGE;
+       }
+       if (dev->dv_timings_signal_mode == CURRENT_DV_TIMINGS) {
+               *timings = dev->dv_timings_cap;
+       } else if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) {
+               *timings = v4l2_dv_timings_presets[dev->query_dv_timings];
+       } else {
+               *timings = v4l2_dv_timings_presets[dev->query_dv_timings_last];
+               dev->query_dv_timings_last = (dev->query_dv_timings_last + 1) %
+                                               dev->query_dv_timings_size;
+       }
+       return 0;
+}
+
+int vidioc_s_edid(struct file *file, void *_fh,
+                        struct v4l2_edid *edid)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       memset(edid->reserved, 0, sizeof(edid->reserved));
+       if (edid->pad >= dev->num_inputs)
+               return -EINVAL;
+       if (dev->input_type[edid->pad] != HDMI || edid->start_block)
+               return -EINVAL;
+       if (edid->blocks == 0) {
+               dev->edid_blocks = 0;
+               return 0;
+       }
+       if (edid->blocks > dev->edid_max_blocks) {
+               edid->blocks = dev->edid_max_blocks;
+               return -E2BIG;
+       }
+       dev->edid_blocks = edid->blocks;
+       memcpy(dev->edid, edid->edid, edid->blocks * 128);
+       return 0;
+}
+
+int vidioc_enum_framesizes(struct file *file, void *fh,
+                                        struct v4l2_frmsizeenum *fsize)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_webcam(dev) && !dev->has_scaler_cap)
+               return -EINVAL;
+       if (vivid_get_format(dev, fsize->pixel_format) == NULL)
+               return -EINVAL;
+       if (vivid_is_webcam(dev)) {
+               if (fsize->index >= ARRAY_SIZE(webcam_sizes))
+                       return -EINVAL;
+               fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+               fsize->discrete = webcam_sizes[fsize->index];
+               return 0;
+       }
+       if (fsize->index)
+               return -EINVAL;
+       fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+       fsize->stepwise.min_width = MIN_WIDTH;
+       fsize->stepwise.max_width = MAX_WIDTH * MAX_ZOOM;
+       fsize->stepwise.step_width = 2;
+       fsize->stepwise.min_height = MIN_HEIGHT;
+       fsize->stepwise.max_height = MAX_HEIGHT * MAX_ZOOM;
+       fsize->stepwise.step_height = 2;
+       return 0;
+}
+
+/* timeperframe is arbitrary and continuous */
+int vidioc_enum_frameintervals(struct file *file, void *priv,
+                                            struct v4l2_frmivalenum *fival)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct vivid_fmt *fmt;
+       int i;
+
+       fmt = vivid_get_format(dev, fival->pixel_format);
+       if (!fmt)
+               return -EINVAL;
+
+       if (!vivid_is_webcam(dev)) {
+               static const struct v4l2_fract step = { 1, 1 };
+
+               if (fival->index)
+                       return -EINVAL;
+               if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM)
+                       return -EINVAL;
+               if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM)
+                       return -EINVAL;
+               fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
+               fival->stepwise.min = tpf_min;
+               fival->stepwise.max = tpf_max;
+               fival->stepwise.step = step;
+               return 0;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++)
+               if (fival->width == webcam_sizes[i].width &&
+                   fival->height == webcam_sizes[i].height)
+                       break;
+       if (i == ARRAY_SIZE(webcam_sizes))
+               return -EINVAL;
+       if (fival->index >= 2 * (3 - i))
+               return -EINVAL;
+       fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+       fival->discrete = webcam_intervals[fival->index];
+       return 0;
+}
+
+int vivid_vid_cap_g_parm(struct file *file, void *priv,
+                         struct v4l2_streamparm *parm)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (parm->type != (dev->multiplanar ?
+                          V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+                          V4L2_BUF_TYPE_VIDEO_CAPTURE))
+               return -EINVAL;
+
+       parm->parm.capture.capability   = V4L2_CAP_TIMEPERFRAME;
+       parm->parm.capture.timeperframe = dev->timeperframe_vid_cap;
+       parm->parm.capture.readbuffers  = 1;
+       return 0;
+}
+
+#define FRACT_CMP(a, OP, b)    \
+       ((u64)(a).numerator * (b).denominator  OP  (u64)(b).numerator * (a).denominator)
+
+int vivid_vid_cap_s_parm(struct file *file, void *priv,
+                         struct v4l2_streamparm *parm)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       unsigned ival_sz = 2 * (3 - dev->webcam_size_idx);
+       struct v4l2_fract tpf;
+       unsigned i;
+
+       if (parm->type != (dev->multiplanar ?
+                          V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+                          V4L2_BUF_TYPE_VIDEO_CAPTURE))
+               return -EINVAL;
+       if (!vivid_is_webcam(dev))
+               return vivid_vid_cap_g_parm(file, priv, parm);
+
+       tpf = parm->parm.capture.timeperframe;
+
+       if (tpf.denominator == 0)
+               tpf = webcam_intervals[ival_sz - 1];
+       for (i = 0; i < ival_sz; i++)
+               if (FRACT_CMP(tpf, >=, webcam_intervals[i]))
+                       break;
+       if (i == ival_sz)
+               i = ival_sz - 1;
+       dev->webcam_ival_idx = i;
+       tpf = webcam_intervals[dev->webcam_ival_idx];
+       tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf;
+       tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf;
+
+       /* resync the thread's timings */
+       dev->cap_seq_resync = true;
+       dev->timeperframe_vid_cap = tpf;
+       parm->parm.capture.timeperframe = tpf;
+       parm->parm.capture.readbuffers  = 1;
+       return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.h b/drivers/media/platform/vivid/vivid-vid-cap.h
new file mode 100644 (file)
index 0000000..9407981
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * vivid-vid-cap.h - video capture support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_VID_CAP_H_
+#define _VIVID_VID_CAP_H_
+
+void vivid_update_quality(struct vivid_dev *dev);
+void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls);
+enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev);
+
+extern const v4l2_std_id vivid_standard[];
+extern const char * const vivid_ctrl_standard_strings[];
+
+extern const struct vb2_ops vivid_vid_cap_qops;
+
+int vivid_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_vid_cap_g_selection(struct file *file, void *priv, struct v4l2_selection *sel);
+int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s);
+int vivid_vid_cap_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap);
+int vidioc_enum_fmt_vid_overlay(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i);
+int vivid_vid_cap_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a);
+int vivid_vid_cap_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a);
+int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp);
+int vidioc_g_input(struct file *file, void *priv, unsigned *i);
+int vidioc_s_input(struct file *file, void *priv, unsigned i);
+int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin);
+int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin);
+int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin);
+int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf);
+int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt);
+int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt);
+int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id);
+int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id);
+int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
+int vidioc_query_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
+int vidioc_s_edid(struct file *file, void *_fh, struct v4l2_edid *edid);
+int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize);
+int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival);
+int vivid_vid_cap_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm);
+int vivid_vid_cap_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
new file mode 100644 (file)
index 0000000..16cd6d2
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ * vivid-vid-common.c - common video support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+
+const struct v4l2_dv_timings_cap vivid_dv_timings_cap = {
+       .type = V4L2_DV_BT_656_1120,
+       /* keep this initialization for compatibility with GCC < 4.4.6 */
+       .reserved = { 0 },
+       V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 25000000, 600000000,
+               V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT,
+               V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED)
+};
+
+/* ------------------------------------------------------------------
+       Basic structures
+   ------------------------------------------------------------------*/
+
+struct vivid_fmt vivid_formats[] = {
+       {
+               .name     = "4:2:2, packed, YUYV",
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .depth    = 16,
+               .is_yuv   = true,
+               .planes   = 1,
+               .data_offset = { PLANE0_DATA_OFFSET, 0 },
+       },
+       {
+               .name     = "4:2:2, packed, UYVY",
+               .fourcc   = V4L2_PIX_FMT_UYVY,
+               .depth    = 16,
+               .is_yuv   = true,
+               .planes   = 1,
+       },
+       {
+               .name     = "4:2:2, packed, YVYU",
+               .fourcc   = V4L2_PIX_FMT_YVYU,
+               .depth    = 16,
+               .is_yuv   = true,
+               .planes   = 1,
+       },
+       {
+               .name     = "4:2:2, packed, VYUY",
+               .fourcc   = V4L2_PIX_FMT_VYUY,
+               .depth    = 16,
+               .is_yuv   = true,
+               .planes   = 1,
+       },
+       {
+               .name     = "RGB565 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+               .depth    = 16,
+               .planes   = 1,
+               .can_do_overlay = true,
+       },
+       {
+               .name     = "RGB565 (BE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+               .depth    = 16,
+               .planes   = 1,
+               .can_do_overlay = true,
+       },
+       {
+               .name     = "RGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+               .planes   = 1,
+               .can_do_overlay = true,
+       },
+       {
+               .name     = "XRGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+               .planes   = 1,
+               .can_do_overlay = true,
+       },
+       {
+               .name     = "ARGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+               .planes   = 1,
+               .can_do_overlay = true,
+               .alpha_mask = 0x8000,
+       },
+       {
+               .name     = "RGB555 (BE)",
+               .fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
+               .depth    = 16,
+               .planes   = 1,
+               .can_do_overlay = true,
+       },
+       {
+               .name     = "RGB24 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB24, /* rgb */
+               .depth    = 24,
+               .planes   = 1,
+       },
+       {
+               .name     = "RGB24 (BE)",
+               .fourcc   = V4L2_PIX_FMT_BGR24, /* bgr */
+               .depth    = 24,
+               .planes   = 1,
+       },
+       {
+               .name     = "RGB32 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB32, /* argb */
+               .depth    = 32,
+               .planes   = 1,
+       },
+       {
+               .name     = "RGB32 (BE)",
+               .fourcc   = V4L2_PIX_FMT_BGR32, /* bgra */
+               .depth    = 32,
+               .planes   = 1,
+       },
+       {
+               .name     = "XRGB32 (LE)",
+               .fourcc   = V4L2_PIX_FMT_XRGB32, /* argb */
+               .depth    = 32,
+               .planes   = 1,
+       },
+       {
+               .name     = "XRGB32 (BE)",
+               .fourcc   = V4L2_PIX_FMT_XBGR32, /* bgra */
+               .depth    = 32,
+               .planes   = 1,
+       },
+       {
+               .name     = "ARGB32 (LE)",
+               .fourcc   = V4L2_PIX_FMT_ARGB32, /* argb */
+               .depth    = 32,
+               .planes   = 1,
+               .alpha_mask = 0x000000ff,
+       },
+       {
+               .name     = "ARGB32 (BE)",
+               .fourcc   = V4L2_PIX_FMT_ABGR32, /* bgra */
+               .depth    = 32,
+               .planes   = 1,
+               .alpha_mask = 0xff000000,
+       },
+       {
+               .name     = "4:2:2, planar, YUV",
+               .fourcc   = V4L2_PIX_FMT_NV16M,
+               .depth    = 8,
+               .is_yuv   = true,
+               .planes   = 2,
+               .data_offset = { PLANE0_DATA_OFFSET, 0 },
+       },
+       {
+               .name     = "4:2:2, planar, YVU",
+               .fourcc   = V4L2_PIX_FMT_NV61M,
+               .depth    = 8,
+               .is_yuv   = true,
+               .planes   = 2,
+               .data_offset = { 0, PLANE0_DATA_OFFSET },
+       },
+};
+
+/* There are 2 multiplanar formats in the list */
+#define VIVID_MPLANAR_FORMATS 2
+
+const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat)
+{
+       const struct vivid_fmt *fmt;
+       unsigned k;
+
+       for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) {
+               fmt = &vivid_formats[k];
+               if (fmt->fourcc == pixelformat)
+                       if (fmt->planes == 1 || dev->multiplanar)
+                               return fmt;
+       }
+
+       return NULL;
+}
+
+bool vivid_vid_can_loop(struct vivid_dev *dev)
+{
+       if (dev->src_rect.width != dev->sink_rect.width ||
+           dev->src_rect.height != dev->sink_rect.height)
+               return false;
+       if (dev->fmt_cap->fourcc != dev->fmt_out->fourcc)
+               return false;
+       if (dev->field_cap != dev->field_out)
+               return false;
+       if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) {
+               if (!(dev->std_cap & V4L2_STD_525_60) !=
+                   !(dev->std_out & V4L2_STD_525_60))
+                       return false;
+               return true;
+       }
+       if (vivid_is_hdmi_cap(dev) && vivid_is_hdmi_out(dev))
+               return true;
+       return false;
+}
+
+void vivid_send_source_change(struct vivid_dev *dev, unsigned type)
+{
+       struct v4l2_event ev = {
+               .type = V4L2_EVENT_SOURCE_CHANGE,
+               .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+       };
+       unsigned i;
+
+       for (i = 0; i < dev->num_inputs; i++) {
+               ev.id = i;
+               if (dev->input_type[i] == type) {
+                       if (video_is_registered(&dev->vid_cap_dev) && dev->has_vid_cap)
+                               v4l2_event_queue(&dev->vid_cap_dev, &ev);
+                       if (video_is_registered(&dev->vbi_cap_dev) && dev->has_vbi_cap)
+                               v4l2_event_queue(&dev->vbi_cap_dev, &ev);
+               }
+       }
+}
+
+/*
+ * Conversion function that converts a single-planar format to a
+ * single-plane multiplanar format.
+ */
+void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt)
+{
+       struct v4l2_pix_format_mplane *mp = &mp_fmt->fmt.pix_mp;
+       struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0];
+       const struct v4l2_pix_format *pix = &sp_fmt->fmt.pix;
+       bool is_out = sp_fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+       memset(mp->reserved, 0, sizeof(mp->reserved));
+       mp_fmt->type = is_out ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+                          V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+       mp->width = pix->width;
+       mp->height = pix->height;
+       mp->pixelformat = pix->pixelformat;
+       mp->field = pix->field;
+       mp->colorspace = pix->colorspace;
+       mp->num_planes = 1;
+       mp->flags = pix->flags;
+       ppix->sizeimage = pix->sizeimage;
+       ppix->bytesperline = pix->bytesperline;
+       memset(ppix->reserved, 0, sizeof(ppix->reserved));
+}
+
+int fmt_sp2mp_func(struct file *file, void *priv,
+               struct v4l2_format *f, fmtfunc func)
+{
+       struct v4l2_format fmt;
+       struct v4l2_pix_format_mplane *mp = &fmt.fmt.pix_mp;
+       struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0];
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       int ret;
+
+       /* Converts to a mplane format */
+       fmt_sp2mp(f, &fmt);
+       /* Passes it to the generic mplane format function */
+       ret = func(file, priv, &fmt);
+       /* Copies back the mplane data to the single plane format */
+       pix->width = mp->width;
+       pix->height = mp->height;
+       pix->pixelformat = mp->pixelformat;
+       pix->field = mp->field;
+       pix->colorspace = mp->colorspace;
+       pix->sizeimage = ppix->sizeimage;
+       pix->bytesperline = ppix->bytesperline;
+       pix->flags = mp->flags;
+       return ret;
+}
+
+/* v4l2_rect helper function: copy the width/height values */
+void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size)
+{
+       r->width = size->width;
+       r->height = size->height;
+}
+
+/* v4l2_rect helper function: width and height of r should be >= min_size */
+void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size)
+{
+       if (r->width < min_size->width)
+               r->width = min_size->width;
+       if (r->height < min_size->height)
+               r->height = min_size->height;
+}
+
+/* v4l2_rect helper function: width and height of r should be <= max_size */
+void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size)
+{
+       if (r->width > max_size->width)
+               r->width = max_size->width;
+       if (r->height > max_size->height)
+               r->height = max_size->height;
+}
+
+/* v4l2_rect helper function: r should be inside boundary */
+void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary)
+{
+       rect_set_max_size(r, boundary);
+       if (r->left < boundary->left)
+               r->left = boundary->left;
+       if (r->top < boundary->top)
+               r->top = boundary->top;
+       if (r->left + r->width > boundary->width)
+               r->left = boundary->width - r->width;
+       if (r->top + r->height > boundary->height)
+               r->top = boundary->height - r->height;
+}
+
+/* v4l2_rect helper function: return true if r1 has the same size as r2 */
+bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
+{
+       return r1->width == r2->width && r1->height == r2->height;
+}
+
+/* v4l2_rect helper function: calculate the intersection of two rects */
+struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b)
+{
+       struct v4l2_rect r;
+       int right, bottom;
+
+       r.top = max(a->top, b->top);
+       r.left = max(a->left, b->left);
+       bottom = min(a->top + a->height, b->top + b->height);
+       right = min(a->left + a->width, b->left + b->width);
+       r.height = max(0, bottom - r.top);
+       r.width = max(0, right - r.left);
+       return r;
+}
+
+/*
+ * v4l2_rect helper function: scale rect r by to->width / from->width and
+ * to->height / from->height.
+ */
+void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from,
+                                    const struct v4l2_rect *to)
+{
+       if (from->width == 0 || from->height == 0) {
+               r->left = r->top = r->width = r->height = 0;
+               return;
+       }
+       r->left = (((r->left - from->left) * to->width) / from->width) & ~1;
+       r->width = ((r->width * to->width) / from->width) & ~1;
+       r->top = ((r->top - from->top) * to->height) / from->height;
+       r->height = (r->height * to->height) / from->height;
+}
+
+bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
+{
+       /*
+        * IF the left side of r1 is to the right of the right side of r2 OR
+        *    the left side of r2 is to the right of the right side of r1 THEN
+        * they do not overlap.
+        */
+       if (r1->left >= r2->left + r2->width ||
+           r2->left >= r1->left + r1->width)
+               return false;
+       /*
+        * IF the top side of r1 is below the bottom of r2 OR
+        *    the top side of r2 is below the bottom of r1 THEN
+        * they do not overlap.
+        */
+       if (r1->top >= r2->top + r2->height ||
+           r2->top >= r1->top + r1->height)
+               return false;
+       return true;
+}
+int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r)
+{
+       unsigned w = r->width;
+       unsigned h = r->height;
+
+       if (!(flags & V4L2_SEL_FLAG_LE)) {
+               w++;
+               h++;
+               if (w < 2)
+                       w = 2;
+               if (h < 2)
+                       h = 2;
+       }
+       if (!(flags & V4L2_SEL_FLAG_GE)) {
+               if (w > MAX_WIDTH)
+                       w = MAX_WIDTH;
+               if (h > MAX_HEIGHT)
+                       h = MAX_HEIGHT;
+       }
+       w = w & ~1;
+       h = h & ~1;
+       if (w < 2 || h < 2)
+               return -ERANGE;
+       if (w > MAX_WIDTH || h > MAX_HEIGHT)
+               return -ERANGE;
+       if (r->top < 0)
+               r->top = 0;
+       if (r->left < 0)
+               r->left = 0;
+       r->left &= ~1;
+       r->top &= ~1;
+       if (r->left + w > MAX_WIDTH)
+               r->left = MAX_WIDTH - w;
+       if (r->top + h > MAX_HEIGHT)
+               r->top = MAX_HEIGHT - h;
+       if ((flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)) ==
+                       (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE) &&
+           (r->width != w || r->height != h))
+               return -ERANGE;
+       r->width = w;
+       r->height = h;
+       return 0;
+}
+
+int vivid_enum_fmt_vid(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct vivid_fmt *fmt;
+
+       if (f->index >= ARRAY_SIZE(vivid_formats) -
+           (dev->multiplanar ? 0 : VIVID_MPLANAR_FORMATS))
+               return -EINVAL;
+
+       fmt = &vivid_formats[f->index];
+
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+       return 0;
+}
+
+int vidioc_enum_fmt_vid_mplane(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_enum_fmt_vid(file, priv, f);
+}
+
+int vidioc_enum_fmt_vid(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return vivid_enum_fmt_vid(file, priv, f);
+}
+
+int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX) {
+               if (!vivid_is_sdtv_cap(dev))
+                       return -ENODATA;
+               *id = dev->std_cap;
+       } else {
+               if (!vivid_is_svid_out(dev))
+                       return -ENODATA;
+               *id = dev->std_out;
+       }
+       return 0;
+}
+
+int vidioc_g_dv_timings(struct file *file, void *_fh,
+                                   struct v4l2_dv_timings *timings)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX) {
+               if (!vivid_is_hdmi_cap(dev))
+                       return -ENODATA;
+               *timings = dev->dv_timings_cap;
+       } else {
+               if (!vivid_is_hdmi_out(dev))
+                       return -ENODATA;
+               *timings = dev->dv_timings_out;
+       }
+       return 0;
+}
+
+int vidioc_enum_dv_timings(struct file *file, void *_fh,
+                                   struct v4l2_enum_dv_timings *timings)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX) {
+               if (!vivid_is_hdmi_cap(dev))
+                       return -ENODATA;
+       } else {
+               if (!vivid_is_hdmi_out(dev))
+                       return -ENODATA;
+       }
+       return v4l2_enum_dv_timings_cap(timings, &vivid_dv_timings_cap,
+                       NULL, NULL);
+}
+
+int vidioc_dv_timings_cap(struct file *file, void *_fh,
+                                   struct v4l2_dv_timings_cap *cap)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX) {
+               if (!vivid_is_hdmi_cap(dev))
+                       return -ENODATA;
+       } else {
+               if (!vivid_is_hdmi_out(dev))
+                       return -ENODATA;
+       }
+       *cap = vivid_dv_timings_cap;
+       return 0;
+}
+
+int vidioc_g_edid(struct file *file, void *_fh,
+                        struct v4l2_edid *edid)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       memset(edid->reserved, 0, sizeof(edid->reserved));
+       if (vdev->vfl_dir == VFL_DIR_RX) {
+               if (edid->pad >= dev->num_inputs)
+                       return -EINVAL;
+               if (dev->input_type[edid->pad] != HDMI)
+                       return -EINVAL;
+       } else {
+               if (edid->pad >= dev->num_outputs)
+                       return -EINVAL;
+               if (dev->output_type[edid->pad] != HDMI)
+                       return -EINVAL;
+       }
+       if (edid->start_block == 0 && edid->blocks == 0) {
+               edid->blocks = dev->edid_blocks;
+               return 0;
+       }
+       if (dev->edid_blocks == 0)
+               return -ENODATA;
+       if (edid->start_block >= dev->edid_blocks)
+               return -EINVAL;
+       if (edid->start_block + edid->blocks > dev->edid_blocks)
+               edid->blocks = dev->edid_blocks - edid->start_block;
+       memcpy(edid->edid, dev->edid, edid->blocks * 128);
+       return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h
new file mode 100644 (file)
index 0000000..3ec4fa8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * vivid-vid-common.h - common video support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_VID_COMMON_H_
+#define _VIVID_VID_COMMON_H_
+
+typedef int (*fmtfunc)(struct file *file, void *priv, struct v4l2_format *f);
+
+/*
+ * Conversion function that converts a single-planar format to a
+ * single-plane multiplanar format.
+ */
+void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt);
+int fmt_sp2mp_func(struct file *file, void *priv,
+               struct v4l2_format *f, fmtfunc func);
+
+extern const struct v4l2_dv_timings_cap vivid_dv_timings_cap;
+
+const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat);
+
+bool vivid_vid_can_loop(struct vivid_dev *dev);
+void vivid_send_source_change(struct vivid_dev *dev, unsigned type);
+
+bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2);
+void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size);
+void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size);
+void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size);
+void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary);
+bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2);
+struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b);
+void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from,
+                                    const struct v4l2_rect *to);
+int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r);
+
+int vivid_enum_fmt_vid(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_enum_fmt_vid_mplane(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_enum_fmt_vid(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id);
+int vidioc_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
+int vidioc_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings);
+int vidioc_dv_timings_cap(struct file *file, void *_fh, struct v4l2_dv_timings_cap *cap);
+int vidioc_g_edid(struct file *file, void *_fh, struct v4l2_edid *edid);
+int vidioc_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
new file mode 100644 (file)
index 0000000..69c2dbd
--- /dev/null
@@ -0,0 +1,1146 @@
+/*
+ * vivid-vid-out.c - video output support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-kthread-out.h"
+#include "vivid-vid-out.h"
+
+static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                      unsigned *nbuffers, unsigned *nplanes,
+                      unsigned sizes[], void *alloc_ctxs[])
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       unsigned planes = dev->fmt_out->planes;
+       unsigned h = dev->fmt_out_rect.height;
+       unsigned size = dev->bytesperline_out[0] * h;
+
+       if (dev->field_out == V4L2_FIELD_ALTERNATE) {
+               /*
+                * You cannot use write() with FIELD_ALTERNATE since the field
+                * information (TOP/BOTTOM) cannot be passed to the kernel.
+                */
+               if (vb2_fileio_is_active(vq))
+                       return -EINVAL;
+       }
+
+       if (dev->queue_setup_error) {
+               /*
+                * Error injection: test what happens if queue_setup() returns
+                * an error.
+                */
+               dev->queue_setup_error = false;
+               return -EINVAL;
+       }
+
+       if (fmt) {
+               const struct v4l2_pix_format_mplane *mp;
+               struct v4l2_format mp_fmt;
+
+               if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+                       fmt_sp2mp(fmt, &mp_fmt);
+                       fmt = &mp_fmt;
+               }
+               mp = &fmt->fmt.pix_mp;
+               /*
+                * Check if the number of planes in the specified format match
+                * the number of planes in the current format. You can't mix that.
+                */
+               if (mp->num_planes != planes)
+                       return -EINVAL;
+               sizes[0] = mp->plane_fmt[0].sizeimage;
+               if (planes == 2) {
+                       sizes[1] = mp->plane_fmt[1].sizeimage;
+                       if (sizes[0] < dev->bytesperline_out[0] * h ||
+                           sizes[1] < dev->bytesperline_out[1] * h)
+                               return -EINVAL;
+               } else if (sizes[0] < size) {
+                       return -EINVAL;
+               }
+       } else {
+               if (planes == 2) {
+                       sizes[0] = dev->bytesperline_out[0] * h;
+                       sizes[1] = dev->bytesperline_out[1] * h;
+               } else {
+                       sizes[0] = size;
+               }
+       }
+
+       if (vq->num_buffers + *nbuffers < 2)
+               *nbuffers = 2 - vq->num_buffers;
+
+       *nplanes = planes;
+
+       /*
+        * videobuf2-vmalloc allocator is context-less so no need to set
+        * alloc_ctxs array.
+        */
+
+       if (planes == 2)
+               dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__,
+                       *nbuffers, sizes[0], sizes[1]);
+       else
+               dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__,
+                       *nbuffers, sizes[0]);
+       return 0;
+}
+
+static int vid_out_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       unsigned long size;
+       unsigned planes = dev->fmt_out->planes;
+       unsigned p;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (WARN_ON(NULL == dev->fmt_out))
+               return -EINVAL;
+
+       if (dev->buf_prepare_error) {
+               /*
+                * Error injection: test what happens if buf_prepare() returns
+                * an error.
+                */
+               dev->buf_prepare_error = false;
+               return -EINVAL;
+       }
+
+       if (dev->field_out != V4L2_FIELD_ALTERNATE)
+               vb->v4l2_buf.field = dev->field_out;
+       else if (vb->v4l2_buf.field != V4L2_FIELD_TOP &&
+                vb->v4l2_buf.field != V4L2_FIELD_BOTTOM)
+               return -EINVAL;
+
+       for (p = 0; p < planes; p++) {
+               size = dev->bytesperline_out[p] * dev->fmt_out_rect.height +
+                       vb->v4l2_planes[p].data_offset;
+
+               if (vb2_get_plane_payload(vb, p) < size) {
+                       dprintk(dev, 1, "%s the payload is too small for plane %u (%lu < %lu)\n",
+                                       __func__, p, vb2_get_plane_payload(vb, p), size);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static void vid_out_buf_queue(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       spin_lock(&dev->slock);
+       list_add_tail(&buf->list, &dev->vid_out_active);
+       spin_unlock(&dev->slock);
+}
+
+static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       int err;
+
+       if (vb2_is_streaming(&dev->vb_vid_cap_q))
+               dev->can_loop_video = vivid_vid_can_loop(dev);
+
+       if (dev->kthread_vid_out)
+               return 0;
+
+       dev->vid_out_seq_count = 0;
+       dprintk(dev, 1, "%s\n", __func__);
+       if (dev->start_streaming_error) {
+               dev->start_streaming_error = false;
+               err = -EINVAL;
+       } else {
+               err = vivid_start_generating_vid_out(dev, &dev->vid_out_streaming);
+       }
+       if (err) {
+               struct vivid_buffer *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &dev->vid_out_active, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+       return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void vid_out_stop_streaming(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       dprintk(dev, 1, "%s\n", __func__);
+       vivid_stop_generating_vid_out(dev, &dev->vid_out_streaming);
+       dev->can_loop_video = false;
+}
+
+const struct vb2_ops vivid_vid_out_qops = {
+       .queue_setup            = vid_out_queue_setup,
+       .buf_prepare            = vid_out_buf_prepare,
+       .buf_queue              = vid_out_buf_queue,
+       .start_streaming        = vid_out_start_streaming,
+       .stop_streaming         = vid_out_stop_streaming,
+       .wait_prepare           = vivid_unlock,
+       .wait_finish            = vivid_lock,
+};
+
+/*
+ * Called whenever the format has to be reset which can occur when
+ * changing outputs, standard, timings, etc.
+ */
+void vivid_update_format_out(struct vivid_dev *dev)
+{
+       struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
+       unsigned size;
+
+       switch (dev->output_type[dev->output]) {
+       case SVID:
+       default:
+               dev->field_out = dev->tv_field_out;
+               dev->sink_rect.width = 720;
+               if (dev->std_out & V4L2_STD_525_60) {
+                       dev->sink_rect.height = 480;
+                       dev->timeperframe_vid_out = (struct v4l2_fract) { 1001, 30000 };
+                       dev->service_set_out = V4L2_SLICED_CAPTION_525;
+               } else {
+                       dev->sink_rect.height = 576;
+                       dev->timeperframe_vid_out = (struct v4l2_fract) { 1000, 25000 };
+                       dev->service_set_out = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+               }
+               dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
+               break;
+       case HDMI:
+               dev->sink_rect.width = bt->width;
+               dev->sink_rect.height = bt->height;
+               size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
+               dev->timeperframe_vid_out = (struct v4l2_fract) {
+                       size / 100, (u32)bt->pixelclock / 100
+               };
+               if (bt->interlaced)
+                       dev->field_out = V4L2_FIELD_ALTERNATE;
+               else
+                       dev->field_out = V4L2_FIELD_NONE;
+               if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) {
+                       if (bt->width == 720 && bt->height <= 576)
+                               dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
+                       else
+                               dev->colorspace_out = V4L2_COLORSPACE_REC709;
+               } else {
+                       dev->colorspace_out = V4L2_COLORSPACE_SRGB;
+               }
+               break;
+       }
+       dev->compose_out = dev->sink_rect;
+       dev->compose_bounds_out = dev->sink_rect;
+       dev->crop_out = dev->compose_out;
+       if (V4L2_FIELD_HAS_T_OR_B(dev->field_out))
+               dev->crop_out.height /= 2;
+       dev->fmt_out_rect = dev->crop_out;
+       dev->bytesperline_out[0] = (dev->sink_rect.width * dev->fmt_out->depth) / 8;
+       if (dev->fmt_out->planes == 2)
+               dev->bytesperline_out[1] = (dev->sink_rect.width * dev->fmt_out->depth) / 8;
+}
+
+/* Map the field to something that is valid for the current output */
+static enum v4l2_field vivid_field_out(struct vivid_dev *dev, enum v4l2_field field)
+{
+       if (vivid_is_svid_out(dev)) {
+               switch (field) {
+               case V4L2_FIELD_INTERLACED_TB:
+               case V4L2_FIELD_INTERLACED_BT:
+               case V4L2_FIELD_SEQ_TB:
+               case V4L2_FIELD_SEQ_BT:
+               case V4L2_FIELD_ALTERNATE:
+                       return field;
+               case V4L2_FIELD_INTERLACED:
+               default:
+                       return V4L2_FIELD_INTERLACED;
+               }
+       }
+       if (vivid_is_hdmi_out(dev))
+               return dev->dv_timings_out.bt.interlaced ? V4L2_FIELD_ALTERNATE :
+                                                      V4L2_FIELD_NONE;
+       return V4L2_FIELD_NONE;
+}
+
+static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev)
+{
+       if (vivid_is_svid_out(dev))
+               return (dev->std_out & V4L2_STD_525_60) ?
+                       TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
+
+       if (vivid_is_hdmi_out(dev) &&
+           dev->sink_rect.width == 720 && dev->sink_rect.height <= 576)
+               return dev->sink_rect.height == 480 ?
+                       TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
+
+       return TPG_PIXEL_ASPECT_SQUARE;
+}
+
+int vivid_g_fmt_vid_out(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+       unsigned p;
+
+       mp->width        = dev->fmt_out_rect.width;
+       mp->height       = dev->fmt_out_rect.height;
+       mp->field        = dev->field_out;
+       mp->pixelformat  = dev->fmt_out->fourcc;
+       mp->colorspace   = dev->colorspace_out;
+       mp->num_planes = dev->fmt_out->planes;
+       for (p = 0; p < mp->num_planes; p++) {
+               mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p];
+               mp->plane_fmt[p].sizeimage =
+                       mp->plane_fmt[p].bytesperline * mp->height;
+       }
+       return 0;
+}
+
+int vivid_try_fmt_vid_out(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
+       struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+       struct v4l2_plane_pix_format *pfmt = mp->plane_fmt;
+       const struct vivid_fmt *fmt;
+       unsigned bytesperline, max_bpl;
+       unsigned factor = 1;
+       unsigned w, h;
+       unsigned p;
+
+       fmt = vivid_get_format(dev, mp->pixelformat);
+       if (!fmt) {
+               dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
+                       mp->pixelformat);
+               mp->pixelformat = V4L2_PIX_FMT_YUYV;
+               fmt = vivid_get_format(dev, mp->pixelformat);
+       }
+
+       mp->field = vivid_field_out(dev, mp->field);
+       if (vivid_is_svid_out(dev)) {
+               w = 720;
+               h = (dev->std_out & V4L2_STD_525_60) ? 480 : 576;
+       } else {
+               w = dev->sink_rect.width;
+               h = dev->sink_rect.height;
+       }
+       if (V4L2_FIELD_HAS_T_OR_B(mp->field))
+               factor = 2;
+       if (!dev->has_scaler_out && !dev->has_crop_out && !dev->has_compose_out) {
+               mp->width = w;
+               mp->height = h / factor;
+       } else {
+               struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor };
+
+               rect_set_min_size(&r, &vivid_min_rect);
+               rect_set_max_size(&r, &vivid_max_rect);
+               if (dev->has_scaler_out && !dev->has_crop_out) {
+                       struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h };
+
+                       rect_set_max_size(&r, &max_r);
+               } else if (!dev->has_scaler_out && dev->has_compose_out && !dev->has_crop_out) {
+                       rect_set_max_size(&r, &dev->sink_rect);
+               } else if (!dev->has_scaler_out && !dev->has_compose_out) {
+                       rect_set_min_size(&r, &dev->sink_rect);
+               }
+               mp->width = r.width;
+               mp->height = r.height / factor;
+       }
+
+       /* This driver supports custom bytesperline values */
+
+       /* Calculate the minimum supported bytesperline value */
+       bytesperline = (mp->width * fmt->depth) >> 3;
+       /* Calculate the maximum supported bytesperline value */
+       max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3;
+       mp->num_planes = fmt->planes;
+       for (p = 0; p < mp->num_planes; p++) {
+               if (pfmt[p].bytesperline > max_bpl)
+                       pfmt[p].bytesperline = max_bpl;
+               if (pfmt[p].bytesperline < bytesperline)
+                       pfmt[p].bytesperline = bytesperline;
+               pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height;
+               memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
+       }
+       if (vivid_is_svid_out(dev))
+               mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861))
+               mp->colorspace = V4L2_COLORSPACE_SRGB;
+       else if (bt->width == 720 && bt->height <= 576)
+               mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M &&
+                mp->colorspace != V4L2_COLORSPACE_REC709 &&
+                mp->colorspace != V4L2_COLORSPACE_SRGB)
+               mp->colorspace = V4L2_COLORSPACE_REC709;
+       memset(mp->reserved, 0, sizeof(mp->reserved));
+       return 0;
+}
+
+int vivid_s_fmt_vid_out(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_rect *crop = &dev->crop_out;
+       struct v4l2_rect *compose = &dev->compose_out;
+       struct vb2_queue *q = &dev->vb_vid_out_q;
+       int ret = vivid_try_fmt_vid_out(file, priv, f);
+       unsigned factor = 1;
+
+       if (ret < 0)
+               return ret;
+
+       if (vb2_is_busy(q) &&
+           (vivid_is_svid_out(dev) ||
+            mp->width != dev->fmt_out_rect.width ||
+            mp->height != dev->fmt_out_rect.height ||
+            mp->pixelformat != dev->fmt_out->fourcc ||
+            mp->field != dev->field_out)) {
+               dprintk(dev, 1, "%s device busy\n", __func__);
+               return -EBUSY;
+       }
+
+       /*
+        * Allow for changing the colorspace on the fly. Useful for testing
+        * purposes, and it is something that HDMI transmitters are able
+        * to do.
+        */
+       if (vb2_is_busy(q))
+               goto set_colorspace;
+
+       dev->fmt_out = vivid_get_format(dev, mp->pixelformat);
+       if (V4L2_FIELD_HAS_T_OR_B(mp->field))
+               factor = 2;
+
+       if (dev->has_scaler_out || dev->has_crop_out || dev->has_compose_out) {
+               struct v4l2_rect r = { 0, 0, mp->width, mp->height };
+
+               if (dev->has_scaler_out) {
+                       if (dev->has_crop_out)
+                               rect_map_inside(crop, &r);
+                       else
+                               *crop = r;
+                       if (dev->has_compose_out && !dev->has_crop_out) {
+                               struct v4l2_rect min_r = {
+                                       0, 0,
+                                       r.width / MAX_ZOOM,
+                                       factor * r.height / MAX_ZOOM
+                               };
+                               struct v4l2_rect max_r = {
+                                       0, 0,
+                                       r.width * MAX_ZOOM,
+                                       factor * r.height * MAX_ZOOM
+                               };
+
+                               rect_set_min_size(compose, &min_r);
+                               rect_set_max_size(compose, &max_r);
+                               rect_map_inside(compose, &dev->compose_bounds_out);
+                       } else if (dev->has_compose_out) {
+                               struct v4l2_rect min_r = {
+                                       0, 0,
+                                       crop->width / MAX_ZOOM,
+                                       factor * crop->height / MAX_ZOOM
+                               };
+                               struct v4l2_rect max_r = {
+                                       0, 0,
+                                       crop->width * MAX_ZOOM,
+                                       factor * crop->height * MAX_ZOOM
+                               };
+
+                               rect_set_min_size(compose, &min_r);
+                               rect_set_max_size(compose, &max_r);
+                               rect_map_inside(compose, &dev->compose_bounds_out);
+                       }
+               } else if (dev->has_compose_out && !dev->has_crop_out) {
+                       rect_set_size_to(crop, &r);
+                       r.height *= factor;
+                       rect_set_size_to(compose, &r);
+                       rect_map_inside(compose, &dev->compose_bounds_out);
+               } else if (!dev->has_compose_out) {
+                       rect_map_inside(crop, &r);
+                       r.height /= factor;
+                       rect_set_size_to(compose, &r);
+               } else {
+                       r.height *= factor;
+                       rect_set_max_size(compose, &r);
+                       rect_map_inside(compose, &dev->compose_bounds_out);
+                       crop->top *= factor;
+                       crop->height *= factor;
+                       rect_set_size_to(crop, compose);
+                       rect_map_inside(crop, &r);
+                       crop->top /= factor;
+                       crop->height /= factor;
+               }
+       } else {
+               struct v4l2_rect r = { 0, 0, mp->width, mp->height };
+
+               rect_set_size_to(crop, &r);
+               r.height /= factor;
+               rect_set_size_to(compose, &r);
+       }
+
+       dev->fmt_out_rect.width = mp->width;
+       dev->fmt_out_rect.height = mp->height;
+       dev->bytesperline_out[0] = mp->plane_fmt[0].bytesperline;
+       if (mp->num_planes > 1)
+               dev->bytesperline_out[1] = mp->plane_fmt[1].bytesperline;
+       dev->field_out = mp->field;
+       if (vivid_is_svid_out(dev))
+               dev->tv_field_out = mp->field;
+
+set_colorspace:
+       dev->colorspace_out = mp->colorspace;
+       if (dev->loop_video) {
+               vivid_send_source_change(dev, SVID);
+               vivid_send_source_change(dev, HDMI);
+       }
+       return 0;
+}
+
+int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_g_fmt_vid_out(file, priv, f);
+}
+
+int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_try_fmt_vid_out(file, priv, f);
+}
+
+int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_s_fmt_vid_out(file, priv, f);
+}
+
+int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_out);
+}
+
+int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_out);
+}
+
+int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_out);
+}
+
+int vivid_vid_out_g_selection(struct file *file, void *priv,
+                             struct v4l2_selection *sel)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->has_crop_out && !dev->has_compose_out)
+               return -ENOTTY;
+       if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       sel->r.left = sel->r.top = 0;
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP:
+               if (!dev->has_crop_out)
+                       return -EINVAL;
+               sel->r = dev->crop_out;
+               break;
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+               if (!dev->has_crop_out)
+                       return -EINVAL;
+               sel->r = dev->fmt_out_rect;
+               break;
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               if (!dev->has_compose_out)
+                       return -EINVAL;
+               sel->r = vivid_max_rect;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+               if (!dev->has_compose_out)
+                       return -EINVAL;
+               sel->r = dev->compose_out;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               if (!dev->has_compose_out)
+                       return -EINVAL;
+               sel->r = dev->sink_rect;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_rect *crop = &dev->crop_out;
+       struct v4l2_rect *compose = &dev->compose_out;
+       unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_out) ? 2 : 1;
+       int ret;
+
+       if (!dev->has_crop_out && !dev->has_compose_out)
+               return -ENOTTY;
+       if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP:
+               if (!dev->has_crop_out)
+                       return -EINVAL;
+               ret = vivid_vid_adjust_sel(s->flags, &s->r);
+               if (ret)
+                       return ret;
+               rect_set_min_size(&s->r, &vivid_min_rect);
+               rect_set_max_size(&s->r, &dev->fmt_out_rect);
+               if (dev->has_scaler_out) {
+                       struct v4l2_rect max_rect = {
+                               0, 0,
+                               dev->sink_rect.width * MAX_ZOOM,
+                               (dev->sink_rect.height / factor) * MAX_ZOOM
+                       };
+
+                       rect_set_max_size(&s->r, &max_rect);
+                       if (dev->has_compose_out) {
+                               struct v4l2_rect min_rect = {
+                                       0, 0,
+                                       s->r.width / MAX_ZOOM,
+                                       (s->r.height * factor) / MAX_ZOOM
+                               };
+                               struct v4l2_rect max_rect = {
+                                       0, 0,
+                                       s->r.width * MAX_ZOOM,
+                                       (s->r.height * factor) * MAX_ZOOM
+                               };
+
+                               rect_set_min_size(compose, &min_rect);
+                               rect_set_max_size(compose, &max_rect);
+                               rect_map_inside(compose, &dev->compose_bounds_out);
+                       }
+               } else if (dev->has_compose_out) {
+                       s->r.top *= factor;
+                       s->r.height *= factor;
+                       rect_set_max_size(&s->r, &dev->sink_rect);
+                       rect_set_size_to(compose, &s->r);
+                       rect_map_inside(compose, &dev->compose_bounds_out);
+                       s->r.top /= factor;
+                       s->r.height /= factor;
+               } else {
+                       rect_set_size_to(&s->r, &dev->sink_rect);
+                       s->r.height /= factor;
+               }
+               rect_map_inside(&s->r, &dev->fmt_out_rect);
+               *crop = s->r;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+               if (!dev->has_compose_out)
+                       return -EINVAL;
+               ret = vivid_vid_adjust_sel(s->flags, &s->r);
+               if (ret)
+                       return ret;
+               rect_set_min_size(&s->r, &vivid_min_rect);
+               rect_set_max_size(&s->r, &dev->sink_rect);
+               rect_map_inside(&s->r, &dev->compose_bounds_out);
+               s->r.top /= factor;
+               s->r.height /= factor;
+               if (dev->has_scaler_out) {
+                       struct v4l2_rect fmt = dev->fmt_out_rect;
+                       struct v4l2_rect max_rect = {
+                               0, 0,
+                               s->r.width * MAX_ZOOM,
+                               s->r.height * MAX_ZOOM
+                       };
+                       struct v4l2_rect min_rect = {
+                               0, 0,
+                               s->r.width / MAX_ZOOM,
+                               s->r.height / MAX_ZOOM
+                       };
+
+                       rect_set_min_size(&fmt, &min_rect);
+                       if (!dev->has_crop_out)
+                               rect_set_max_size(&fmt, &max_rect);
+                       if (!rect_same_size(&dev->fmt_out_rect, &fmt) &&
+                           vb2_is_busy(&dev->vb_vid_out_q))
+                               return -EBUSY;
+                       if (dev->has_crop_out) {
+                               rect_set_min_size(crop, &min_rect);
+                               rect_set_max_size(crop, &max_rect);
+                       }
+                       dev->fmt_out_rect = fmt;
+               } else if (dev->has_crop_out) {
+                       struct v4l2_rect fmt = dev->fmt_out_rect;
+
+                       rect_set_min_size(&fmt, &s->r);
+                       if (!rect_same_size(&dev->fmt_out_rect, &fmt) &&
+                           vb2_is_busy(&dev->vb_vid_out_q))
+                               return -EBUSY;
+                       dev->fmt_out_rect = fmt;
+                       rect_set_size_to(crop, &s->r);
+                       rect_map_inside(crop, &dev->fmt_out_rect);
+               } else {
+                       if (!rect_same_size(&s->r, &dev->fmt_out_rect) &&
+                           vb2_is_busy(&dev->vb_vid_out_q))
+                               return -EBUSY;
+                       rect_set_size_to(&dev->fmt_out_rect, &s->r);
+                       rect_set_size_to(crop, &s->r);
+                       crop->height /= factor;
+                       rect_map_inside(crop, &dev->fmt_out_rect);
+               }
+               s->r.top *= factor;
+               s->r.height *= factor;
+               if (dev->bitmap_out && (compose->width != s->r.width ||
+                                       compose->height != s->r.height)) {
+                       kfree(dev->bitmap_out);
+                       dev->bitmap_out = NULL;
+               }
+               *compose = s->r;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int vivid_vid_out_cropcap(struct file *file, void *priv,
+                             struct v4l2_cropcap *cap)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (cap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       switch (vivid_get_pixel_aspect(dev)) {
+       case TPG_PIXEL_ASPECT_NTSC:
+               cap->pixelaspect.numerator = 11;
+               cap->pixelaspect.denominator = 10;
+               break;
+       case TPG_PIXEL_ASPECT_PAL:
+               cap->pixelaspect.numerator = 54;
+               cap->pixelaspect.denominator = 59;
+               break;
+       case TPG_PIXEL_ASPECT_SQUARE:
+               cap->pixelaspect.numerator = 1;
+               cap->pixelaspect.denominator = 1;
+               break;
+       }
+       return 0;
+}
+
+int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct v4l2_rect *compose = &dev->compose_out;
+       struct v4l2_window *win = &f->fmt.win;
+       unsigned clipcount = win->clipcount;
+
+       if (!dev->has_fb)
+               return -EINVAL;
+       win->w.top = dev->overlay_out_top;
+       win->w.left = dev->overlay_out_left;
+       win->w.width = compose->width;
+       win->w.height = compose->height;
+       win->clipcount = dev->clipcount_out;
+       win->field = V4L2_FIELD_ANY;
+       win->chromakey = dev->chromakey_out;
+       win->global_alpha = dev->global_alpha_out;
+       if (clipcount > dev->clipcount_out)
+               clipcount = dev->clipcount_out;
+       if (dev->bitmap_out == NULL)
+               win->bitmap = NULL;
+       else if (win->bitmap) {
+               if (copy_to_user(win->bitmap, dev->bitmap_out,
+                   ((dev->compose_out.width + 7) / 8) * dev->compose_out.height))
+                       return -EFAULT;
+       }
+       if (clipcount && win->clips) {
+               if (copy_to_user(win->clips, dev->clips_out,
+                                clipcount * sizeof(dev->clips_out[0])))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct v4l2_rect *compose = &dev->compose_out;
+       struct v4l2_window *win = &f->fmt.win;
+       int i, j;
+
+       if (!dev->has_fb)
+               return -EINVAL;
+       win->w.left = clamp_t(int, win->w.left,
+                             -dev->display_width, dev->display_width);
+       win->w.top = clamp_t(int, win->w.top,
+                            -dev->display_height, dev->display_height);
+       win->w.width = compose->width;
+       win->w.height = compose->height;
+       /*
+        * It makes no sense for an OSD to overlay only top or bottom fields,
+        * so always set this to ANY.
+        */
+       win->field = V4L2_FIELD_ANY;
+       if (win->clipcount && !win->clips)
+               win->clipcount = 0;
+       if (win->clipcount > MAX_CLIPS)
+               win->clipcount = MAX_CLIPS;
+       if (win->clipcount) {
+               if (copy_from_user(dev->try_clips_out, win->clips,
+                                  win->clipcount * sizeof(dev->clips_out[0])))
+                       return -EFAULT;
+               for (i = 0; i < win->clipcount; i++) {
+                       struct v4l2_rect *r = &dev->try_clips_out[i].c;
+
+                       r->top = clamp_t(s32, r->top, 0, dev->display_height - 1);
+                       r->height = clamp_t(s32, r->height, 1, dev->display_height - r->top);
+                       r->left = clamp_t(u32, r->left, 0, dev->display_width - 1);
+                       r->width = clamp_t(u32, r->width, 1, dev->display_width - r->left);
+               }
+               /*
+                * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small
+                * number and it's typically a one-time deal.
+                */
+               for (i = 0; i < win->clipcount - 1; i++) {
+                       struct v4l2_rect *r1 = &dev->try_clips_out[i].c;
+
+                       for (j = i + 1; j < win->clipcount; j++) {
+                               struct v4l2_rect *r2 = &dev->try_clips_out[j].c;
+
+                               if (rect_overlap(r1, r2))
+                                       return -EINVAL;
+                       }
+               }
+               if (copy_to_user(win->clips, dev->try_clips_out,
+                                win->clipcount * sizeof(dev->clips_out[0])))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct v4l2_rect *compose = &dev->compose_out;
+       struct v4l2_window *win = &f->fmt.win;
+       int ret = vidioc_try_fmt_vid_out_overlay(file, priv, f);
+       unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height;
+       unsigned clips_size = win->clipcount * sizeof(dev->clips_out[0]);
+       void *new_bitmap = NULL;
+
+       if (ret)
+               return ret;
+
+       if (win->bitmap) {
+               new_bitmap = memdup_user(win->bitmap, bitmap_size);
+
+               if (IS_ERR(new_bitmap))
+                       return PTR_ERR(new_bitmap);
+       }
+
+       dev->overlay_out_top = win->w.top;
+       dev->overlay_out_left = win->w.left;
+       kfree(dev->bitmap_out);
+       dev->bitmap_out = new_bitmap;
+       dev->clipcount_out = win->clipcount;
+       if (dev->clipcount_out)
+               memcpy(dev->clips_out, dev->try_clips_out, clips_size);
+       dev->chromakey_out = win->chromakey;
+       dev->global_alpha_out = win->global_alpha;
+       return ret;
+}
+
+int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (i && !dev->fmt_out->can_do_overlay) {
+               dprintk(dev, 1, "unsupported output format for output overlay\n");
+               return -EINVAL;
+       }
+
+       dev->overlay_out_enabled = i;
+       return 0;
+}
+
+int vivid_vid_out_g_fbuf(struct file *file, void *fh,
+                               struct v4l2_framebuffer *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
+                       V4L2_FBUF_CAP_BITMAP_CLIPPING |
+                       V4L2_FBUF_CAP_LIST_CLIPPING |
+                       V4L2_FBUF_CAP_CHROMAKEY |
+                       V4L2_FBUF_CAP_SRC_CHROMAKEY |
+                       V4L2_FBUF_CAP_GLOBAL_ALPHA |
+                       V4L2_FBUF_CAP_LOCAL_ALPHA |
+                       V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+       a->flags = V4L2_FBUF_FLAG_OVERLAY | dev->fbuf_out_flags;
+       a->base = (void *)dev->video_pbase;
+       a->fmt.width = dev->display_width;
+       a->fmt.height = dev->display_height;
+       if (dev->fb_defined.green.length == 5)
+               a->fmt.pixelformat = V4L2_PIX_FMT_ARGB555;
+       else
+               a->fmt.pixelformat = V4L2_PIX_FMT_RGB565;
+       a->fmt.bytesperline = dev->display_byte_stride;
+       a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline;
+       a->fmt.field = V4L2_FIELD_NONE;
+       a->fmt.colorspace = V4L2_COLORSPACE_SRGB;
+       a->fmt.priv = 0;
+       return 0;
+}
+
+int vivid_vid_out_s_fbuf(struct file *file, void *fh,
+                               const struct v4l2_framebuffer *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const unsigned chroma_flags = V4L2_FBUF_FLAG_CHROMAKEY |
+                                     V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+       const unsigned alpha_flags = V4L2_FBUF_FLAG_GLOBAL_ALPHA |
+                                    V4L2_FBUF_FLAG_LOCAL_ALPHA |
+                                    V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
+
+
+       if ((a->flags & chroma_flags) == chroma_flags)
+               return -EINVAL;
+       switch (a->flags & alpha_flags) {
+       case 0:
+       case V4L2_FBUF_FLAG_GLOBAL_ALPHA:
+       case V4L2_FBUF_FLAG_LOCAL_ALPHA:
+       case V4L2_FBUF_FLAG_LOCAL_INV_ALPHA:
+               break;
+       default:
+               return -EINVAL;
+       }
+       dev->fbuf_out_flags &= ~(chroma_flags | alpha_flags);
+       dev->fbuf_out_flags = a->flags & (chroma_flags | alpha_flags);
+       return 0;
+}
+
+static const struct v4l2_audioout vivid_audio_outputs[] = {
+       { 0, "Line-Out 1" },
+       { 1, "Line-Out 2" },
+};
+
+int vidioc_enum_output(struct file *file, void *priv,
+                               struct v4l2_output *out)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (out->index >= dev->num_outputs)
+               return -EINVAL;
+
+       out->type = V4L2_OUTPUT_TYPE_ANALOG;
+       switch (dev->output_type[out->index]) {
+       case SVID:
+               snprintf(out->name, sizeof(out->name), "S-Video %u",
+                               dev->output_name_counter[out->index]);
+               out->std = V4L2_STD_ALL;
+               if (dev->has_audio_outputs)
+                       out->audioset = (1 << ARRAY_SIZE(vivid_audio_outputs)) - 1;
+               out->capabilities = V4L2_OUT_CAP_STD;
+               break;
+       case HDMI:
+               snprintf(out->name, sizeof(out->name), "HDMI %u",
+                               dev->output_name_counter[out->index]);
+               out->capabilities = V4L2_OUT_CAP_DV_TIMINGS;
+               break;
+       }
+       return 0;
+}
+
+int vidioc_g_output(struct file *file, void *priv, unsigned *o)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       *o = dev->output;
+       return 0;
+}
+
+int vidioc_s_output(struct file *file, void *priv, unsigned o)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (o >= dev->num_outputs)
+               return -EINVAL;
+
+       if (o == dev->output)
+               return 0;
+
+       if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q))
+               return -EBUSY;
+
+       dev->output = o;
+       dev->tv_audio_output = 0;
+       if (dev->output_type[o] == SVID)
+               dev->vid_out_dev.tvnorms = V4L2_STD_ALL;
+       else
+               dev->vid_out_dev.tvnorms = 0;
+
+       dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms;
+       vivid_update_format_out(dev);
+       return 0;
+}
+
+int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout)
+{
+       if (vout->index >= ARRAY_SIZE(vivid_audio_outputs))
+               return -EINVAL;
+       *vout = vivid_audio_outputs[vout->index];
+       return 0;
+}
+
+int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_svid_out(dev))
+               return -EINVAL;
+       *vout = vivid_audio_outputs[dev->tv_audio_output];
+       return 0;
+}
+
+int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_svid_out(dev))
+               return -EINVAL;
+       if (vout->index >= ARRAY_SIZE(vivid_audio_outputs))
+               return -EINVAL;
+       dev->tv_audio_output = vout->index;
+       return 0;
+}
+
+int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_svid_out(dev))
+               return -ENODATA;
+       if (dev->std_out == id)
+               return 0;
+       if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q))
+               return -EBUSY;
+       dev->std_out = id;
+       vivid_update_format_out(dev);
+       return 0;
+}
+
+int vivid_vid_out_s_dv_timings(struct file *file, void *_fh,
+                                   struct v4l2_dv_timings *timings)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_hdmi_out(dev))
+               return -ENODATA;
+       if (vb2_is_busy(&dev->vb_vid_out_q))
+               return -EBUSY;
+       if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap,
+                               0, NULL, NULL))
+               return -EINVAL;
+       if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0))
+               return 0;
+       dev->dv_timings_out = *timings;
+       vivid_update_format_out(dev);
+       return 0;
+}
+
+int vivid_vid_out_g_parm(struct file *file, void *priv,
+                         struct v4l2_streamparm *parm)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (parm->type != (dev->multiplanar ?
+                          V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+                          V4L2_BUF_TYPE_VIDEO_OUTPUT))
+               return -EINVAL;
+
+       parm->parm.output.capability   = V4L2_CAP_TIMEPERFRAME;
+       parm->parm.output.timeperframe = dev->timeperframe_vid_out;
+       parm->parm.output.writebuffers  = 1;
+return 0;
+}
+
+int vidioc_subscribe_event(struct v4l2_fh *fh,
+                       const struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_CTRL:
+               return v4l2_ctrl_subscribe_event(fh, sub);
+       case V4L2_EVENT_SOURCE_CHANGE:
+               if (fh->vdev->vfl_dir == VFL_DIR_RX)
+                       return v4l2_src_change_event_subscribe(fh, sub);
+               break;
+       default:
+               break;
+       }
+       return -EINVAL;
+}
diff --git a/drivers/media/platform/vivid/vivid-vid-out.h b/drivers/media/platform/vivid/vivid-vid-out.h
new file mode 100644 (file)
index 0000000..dfa84db
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * vivid-vid-out.h - video output support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_VID_OUT_H_
+#define _VIVID_VID_OUT_H_
+
+extern const struct vb2_ops vivid_vid_out_qops;
+
+void vivid_update_format_out(struct vivid_dev *dev);
+
+int vivid_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_vid_out_g_selection(struct file *file, void *priv, struct v4l2_selection *sel);
+int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s);
+int vivid_vid_out_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cap);
+int vidioc_enum_fmt_vid_out_overlay(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i);
+int vivid_vid_out_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a);
+int vivid_vid_out_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a);
+int vidioc_enum_output(struct file *file, void *priv, struct v4l2_output *out);
+int vidioc_g_output(struct file *file, void *priv, unsigned *i);
+int vidioc_s_output(struct file *file, void *priv, unsigned i);
+int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout);
+int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout);
+int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout);
+int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id);
+int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
+int vivid_vid_out_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm);
+
+#endif
index 235c0e349820702cf53387f952262e506eee9e06..cff1eb144a5c71f5db9fa46f10c5c5363cf939d1 100644 (file)
@@ -332,7 +332,7 @@ static int __init gemtek_init(void)
 
 static void __exit gemtek_exit(void)
 {
-       hardmute = 1;   /* Turn off PLL */
+       hardmute = true;        /* Turn off PLL */
 #ifdef CONFIG_PNP
        pnp_unregister_driver(&gemtek_driver.pnp_driver);
 #endif
index d7ce8fe6b5ae1a89c5c578a9f2d88d20aaeecca7..28a89466cddc4a82985a6ab01785c093fa8c91ff 100644 (file)
@@ -56,7 +56,7 @@ struct fmi
 
 static struct fmi fmi_card;
 static struct pnp_dev *dev;
-bool pnp_attached;
+static bool pnp_attached;
 
 #define RSF16_MINFREQ (87U * 16000)
 #define RSF16_MAXFREQ (108U * 16000)
@@ -285,7 +285,7 @@ static int __init fmi_init(void)
                                io = isapnp_fmi_probe();
                                if (io < 0)
                                        continue;
-                               pnp_attached = 1;
+                               pnp_attached = true;
                        }
                        if (!request_region(io, 2, "radio-sf16fmi")) {
                                if (pnp_attached)
@@ -349,7 +349,7 @@ static int __init fmi_init(void)
        mutex_init(&fmi->lock);
 
        /* mute card and set default frequency */
-       fmi->mute = 1;
+       fmi->mute = true;
        fmi->curfreq = RSF16_MINFREQ;
        fmi_set_freq(fmi);
 
index 93d864eb830627898c82d3d33416466819ee5c76..b8d61cbc18cb5d7b9c2dd902c2900c32c399cf1a 100644 (file)
@@ -305,7 +305,7 @@ static void fmr2_pnp_remove(struct pnp_dev *pdev)
        pnp_set_drvdata(pdev, NULL);
 }
 
-struct isa_driver fmr2_isa_driver = {
+static struct isa_driver fmr2_isa_driver = {
        .match          = fmr2_isa_match,
        .remove         = fmr2_isa_remove,
        .driver         = {
@@ -313,7 +313,7 @@ struct isa_driver fmr2_isa_driver = {
        },
 };
 
-struct pnp_driver fmr2_pnp_driver = {
+static struct pnp_driver fmr2_pnp_driver = {
        .name           = "radio-sf16fmr2",
        .id_table       = fmr2_pnp_ids,
        .probe          = fmr2_pnp_probe,
index 925049654c5bc0f33429b45b5cab5fff3795f8e8..cc3990111411bd8b06b4d86ad3d4da9b72a54c94 100644 (file)
@@ -124,11 +124,11 @@ struct tea5764_regs {
 
 struct tea5764_write_regs {
        u8 intreg;                              /* INTMSK */
-       u16 frqset;                             /* FRQSETMSB & FRQSETLSB */
-       u16 tnctrl;                             /* TNCTRL1 & TNCTRL2 */
-       u16 testreg;                            /* TESTBITS & TESTMODE */
-       u16 rdsctrl;                            /* RDSCTRL1 & RDSCTRL2 */
-       u16 rdsbbl;                             /* PAUSEDET & RDSBBL */
+       __be16 frqset;                          /* FRQSETMSB & FRQSETLSB */
+       __be16 tnctrl;                          /* TNCTRL1 & TNCTRL2 */
+       __be16 testreg;                         /* TESTBITS & TESTMODE */
+       __be16 rdsctrl;                         /* RDSCTRL1 & RDSCTRL2 */
+       __be16 rdsbbl;                          /* PAUSEDET & RDSBBL */
 } __attribute__ ((packed));
 
 #ifdef CONFIG_RADIO_TEA5764_XTAL
@@ -165,7 +165,7 @@ static int tea5764_i2c_read(struct tea5764_device *radio)
        if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1)
                return -EIO;
        for (i = 0; i < sizeof(struct tea5764_regs) / sizeof(u16); i++)
-               p[i] = __be16_to_cpu(p[i]);
+               p[i] = __be16_to_cpu((__force __be16)p[i]);
 
        return 0;
 }
index 0e750aef656a6f8a053aafbd965b4e9e1fe64f23..909c3f92d83920de0561d9dc59aa31171826d973 100644 (file)
@@ -208,7 +208,7 @@ static int si470x_set_band(struct si470x_device *radio, int band)
 static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
 {
        int retval;
-       bool timed_out = 0;
+       bool timed_out = false;
 
        /* start tuning */
        radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
@@ -300,7 +300,7 @@ static int si470x_set_seek(struct si470x_device *radio,
 {
        int band, retval;
        unsigned int freq;
-       bool timed_out = 0;
+       bool timed_out = false;
 
        /* set band */
        if (seek->rangelow || seek->rangehigh) {
index 494fac061306ed498a02dff4049cb0223d45f621..57f0bc3b60e7d3a54943ee685c17b295050f79e4 100644 (file)
@@ -607,9 +607,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        /* Set up interrupt endpoint information. */
        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
                endpoint = &iface_desc->endpoint[i].desc;
-               if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
-                USB_DIR_IN) && ((endpoint->bmAttributes &
-                USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT))
+               if (usb_endpoint_is_int_in(endpoint))
                        radio->int_in_endpoint = endpoint;
        }
        if (!radio->int_in_endpoint) {
index 4b2e9e8298e1f6e962a468eeb1fba4b91b5c68bd..6f28f6e02ea57e947a2a8805ccccee4cfaa30cc2 100644 (file)
@@ -440,7 +440,7 @@ static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type,     void *payload,
                 * command with u16 payload - convert to be16
                 */
                if (payload != NULL)
-                       *(u16 *)payload = cpu_to_be16(*(u16 *)payload);
+                       *(__be16 *)payload = cpu_to_be16(*(u16 *)payload);
 
        } else if (payload != NULL) {
                fm_cb(skb)->fm_op = *((u8 *)payload + 2);
@@ -595,7 +595,7 @@ static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev)
        skb_pull(skb, sizeof(struct fm_event_msg_hdr));
        memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen);
 
-       fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag);
+       fmdev->irq_info.flag = be16_to_cpu((__force __be16)fmdev->irq_info.flag);
        fmdbg("irq: flag register(0x%x)\n", fmdev->irq_info.flag);
 
        /* Continue next function in interrupt handler table */
@@ -764,7 +764,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev)
                         * Extract PI code and store in local cache.
                         * We need this during AF switch processing.
                         */
-                       cur_picode = be16_to_cpu(rds_fmt.data.groupgeneral.pidata);
+                       cur_picode = be16_to_cpu((__force __be16)rds_fmt.data.groupgeneral.pidata);
                        if (fmdev->rx.stat_info.picode != cur_picode)
                                fmdev->rx.stat_info.picode = cur_picode;
 
@@ -989,7 +989,7 @@ static void fm_irq_afjump_rd_freq_resp(struct fmdev *fmdev)
        /* Skip header info and copy only response data */
        skb_pull(skb, sizeof(struct fm_event_msg_hdr));
        memcpy(&read_freq, skb->data, sizeof(read_freq));
-       read_freq = be16_to_cpu(read_freq);
+       read_freq = be16_to_cpu((__force __be16)read_freq);
        curr_freq = fmdev->rx.region.bot_freq + ((u32)read_freq * FM_FREQ_MUL);
 
        jumped_freq = fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx];
@@ -1317,7 +1317,8 @@ static int load_default_rx_configuration(struct fmdev *fmdev)
 /* Does FM power on sequence */
 static int fm_power_up(struct fmdev *fmdev, u8 mode)
 {
-       u16 payload, asic_id, asic_ver;
+       u16 payload;
+       __be16 asic_id, asic_ver;
        int resp_len, ret;
        u8 fw_name[50];
 
index ebf09a3927deea0f34070d54aa6e3c65b7bd1742..09632cb26cb6980b06238fc1b09bc2b218343e32 100644 (file)
@@ -116,7 +116,7 @@ int fm_rx_set_freq(struct fmdev *fmdev, u32 freq)
        if (ret < 0)
                goto exit;
 
-       curr_frq = be16_to_cpu(curr_frq);
+       curr_frq = be16_to_cpu((__force __be16)curr_frq);
        curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL));
 
        if (curr_frq_in_khz != freq) {
@@ -189,7 +189,7 @@ int fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
        if (ret < 0)
                return ret;
 
-       curr_frq = be16_to_cpu(curr_frq);
+       curr_frq = be16_to_cpu((__force __be16)curr_frq);
        last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
 
        /* Check the offset in order to be aligned to the channel spacing*/
@@ -285,7 +285,7 @@ again:
                if (ret < 0)
                        return ret;
 
-               curr_frq = be16_to_cpu(curr_frq);
+               curr_frq = be16_to_cpu((__force __be16)curr_frq);
                fmdev->rx.freq = (fmdev->rx.region.bot_freq +
                                ((u32)curr_frq * FM_FREQ_MUL));
 
@@ -517,7 +517,7 @@ int fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
 /* Returns the signal strength level of current channel */
 int fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
 {
-       u16 curr_rssi_lel;
+       __be16 curr_rssi_lel;
        u32 resp_len;
        int ret;
 
@@ -608,7 +608,7 @@ int fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
 /* Gets current RX stereo/mono mode */
 int fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
 {
-       u16 curr_mode;
+       __be16 curr_mode;
        u32 resp_len;
        int ret;
 
index 6ea33e09d63b23b306979142ace913d6806f561f..839970b0f313522a31edfc0430f0d15652f47526 100644 (file)
@@ -374,7 +374,7 @@ int fm_tx_get_tune_cap_val(struct fmdev *fmdev)
        if (ret < 0)
                return ret;
 
-       curr_val = be16_to_cpu(curr_val);
+       curr_val = be16_to_cpu((__force __be16)curr_val);
 
        return curr_val;
 }
index 5e626af8e3130b0a7fbed625c1f7b1101f696270..8ce08107a69d5801d6de12b5ad0f5e9aa7daeacc 100644 (file)
@@ -164,6 +164,16 @@ config IR_ENE
           To compile this driver as a module, choose M here: the
           module will be called ene_ir.
 
+config IR_HIX5HD2
+       tristate "Hisilicon hix5hd2 IR remote control"
+       depends on RC_CORE
+       help
+        Say Y here if you want to use hisilicon hix5hd2 remote control.
+        To compile this driver as a module, choose M here: the module will be
+        called ir-hix5hd2.
+
+        If you're not sure, select N here
+
 config IR_IMON
        tristate "SoundGraph iMON Receiver and Display"
        depends on USB_ARCH_HAS_HCD
@@ -333,7 +343,8 @@ config IR_GPIO_CIR
 
 config RC_ST
        tristate "ST remote control receiver"
-       depends on ARCH_STI && RC_CORE
+       depends on RC_CORE
+       depends on ARCH_STI || COMPILE_TEST
        help
         Say Y here if you want support for ST remote control driver
         which allows both IR and UHF RX.
@@ -344,7 +355,7 @@ config RC_ST
 config IR_SUNXI
     tristate "SUNXI IR remote control"
     depends on RC_CORE
-    depends on ARCH_SUNXI
+    depends on ARCH_SUNXI || COMPILE_TEST
     ---help---
       Say Y if you want to use sunXi internal IR Controller
 
index 9f9843a1af5f2d61ee2ee851d4ef4519135e949c..0989f940e9cfa8d213706ca4989974584561117d 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o
 
 # stand-alone IR receivers/transmitters
 obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o
+obj-$(CONFIG_IR_HIX5HD2) += ir-hix5hd2.o
 obj-$(CONFIG_IR_IMON) += imon.o
 obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
 obj-$(CONFIG_IR_MCEUSB) += mceusb.o
index d16d9b496b92e4f1b1f66fa87b01af7d5757501e..e80f2c6c5f1abf040428f4f6c14666de271ee016 100644 (file)
@@ -979,7 +979,7 @@ static int ene_transmit(struct rc_dev *rdev, unsigned *buf, unsigned n)
        dev->tx_reg = 0;
        dev->tx_done = 0;
        dev->tx_sample = 0;
-       dev->tx_sample_pulse = 0;
+       dev->tx_sample_pulse = false;
 
        dbg("TX: %d samples", dev->tx_len);
 
index f0a1f7d31ee6578925308b9be608f762c5b37fde..b5167573240e3631cd8d3ae74ccc6ec1893eed08 100644 (file)
@@ -148,7 +148,6 @@ static int fintek_hw_detect(struct fintek_dev *fintek)
        u8 vendor_major, vendor_minor;
        u8 portsel, ir_class;
        u16 vendor, chip;
-       int ret = 0;
 
        fintek_config_mode_enable(fintek);
 
@@ -208,7 +207,7 @@ static int fintek_hw_detect(struct fintek_dev *fintek)
 
        spin_unlock_irqrestore(&fintek->fintek_lock, flags);
 
-       return ret;
+       return 0;
 }
 
 static void fintek_cir_ldev_init(struct fintek_dev *fintek)
@@ -644,7 +643,6 @@ static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state)
 
 static int fintek_resume(struct pnp_dev *pdev)
 {
-       int ret = 0;
        struct fintek_dev *fintek = pnp_get_drvdata(pdev);
 
        fit_dbg("%s called", __func__);
@@ -661,7 +659,7 @@ static int fintek_resume(struct pnp_dev *pdev)
 
        fintek_cir_regs_init(fintek);
 
-       return ret;
+       return 0;
 }
 
 static void fintek_shutdown(struct pnp_dev *pdev)
index bfb282a714e8e2ca8bc77777ed375961d6e01a5f..ec49f94425fc757ddc107578adeaa257a1ebd77a 100644 (file)
 /* Decoders lock (only modified to preprocess them) */
 static DEFINE_SPINLOCK(img_ir_decoders_lock);
 
-extern struct img_ir_decoder img_ir_nec;
-extern struct img_ir_decoder img_ir_jvc;
-extern struct img_ir_decoder img_ir_sony;
-extern struct img_ir_decoder img_ir_sharp;
-extern struct img_ir_decoder img_ir_sanyo;
-
 static bool img_ir_decoders_preprocessed;
 static struct img_ir_decoder *img_ir_decoders[] = {
 #ifdef CONFIG_IR_IMG_NEC
index 3e40ce87b898047f511877c547c382898c7db40e..8fcc16c32c5bcd5ce1edc3a1744b30eeb2f1497a 100644 (file)
@@ -168,6 +168,12 @@ struct img_ir_decoder {
                      struct img_ir_filter *out, u64 protocols);
 };
 
+extern struct img_ir_decoder img_ir_nec;
+extern struct img_ir_decoder img_ir_jvc;
+extern struct img_ir_decoder img_ir_sony;
+extern struct img_ir_decoder img_ir_sharp;
+extern struct img_ir_decoder img_ir_sanyo;
+
 /**
  * struct img_ir_reg_timings - Reg values for decoder timings at clock rate.
  * @ctrl:      Processed control register value.
index 7115e68ba6978d36689e96ac0d32628646fc9664..b8837dd39bb2a52740a36765d69d75af464f51fa 100644 (file)
@@ -87,6 +87,18 @@ static ssize_t lcd_write(struct file *file, const char __user *buf,
 
 /*** G L O B A L S ***/
 
+struct imon_panel_key_table {
+       u64 hw_code;
+       u32 keycode;
+};
+
+struct imon_usb_dev_descr {
+       __u16 flags;
+#define IMON_NO_FLAGS 0
+#define IMON_NEED_20MS_PKT_DELAY 1
+       struct imon_panel_key_table key_table[];
+};
+
 struct imon_context {
        struct device *dev;
        /* Newer devices have two interfaces */
@@ -150,6 +162,8 @@ struct imon_context {
        struct timer_list ttimer;       /* touch screen timer */
        int touch_x;                    /* x coordinate on touchscreen */
        int touch_y;                    /* y coordinate on touchscreen */
+       struct imon_usb_dev_descr *dev_descr; /* device description with key
+                                                table for front panels */
 };
 
 #define TOUCH_TIMEOUT  (HZ/30)
@@ -186,8 +200,132 @@ enum {
        IMON_KEY_PANEL  = 2,
 };
 
-enum {
-       IMON_NEED_20MS_PKT_DELAY = 1
+static struct usb_class_driver imon_vfd_class = {
+       .name           = DEVICE_NAME,
+       .fops           = &vfd_fops,
+       .minor_base     = DISPLAY_MINOR_BASE,
+};
+
+static struct usb_class_driver imon_lcd_class = {
+       .name           = DEVICE_NAME,
+       .fops           = &lcd_fops,
+       .minor_base     = DISPLAY_MINOR_BASE,
+};
+
+/* imon receiver front panel/knob key table */
+static const struct imon_usb_dev_descr imon_default_table = {
+       .flags = IMON_NO_FLAGS,
+       .key_table = {
+               { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */
+               { 0x000000001200ffeell, KEY_UP },
+               { 0x000000001300ffeell, KEY_DOWN },
+               { 0x000000001400ffeell, KEY_LEFT },
+               { 0x000000001500ffeell, KEY_RIGHT },
+               { 0x000000001600ffeell, KEY_ENTER },
+               { 0x000000001700ffeell, KEY_ESC },
+               { 0x000000001f00ffeell, KEY_AUDIO },
+               { 0x000000002000ffeell, KEY_VIDEO },
+               { 0x000000002100ffeell, KEY_CAMERA },
+               { 0x000000002700ffeell, KEY_DVD },
+               { 0x000000002300ffeell, KEY_TV },
+               { 0x000000002b00ffeell, KEY_EXIT },
+               { 0x000000002c00ffeell, KEY_SELECT },
+               { 0x000000002d00ffeell, KEY_MENU },
+               { 0x000000000500ffeell, KEY_PREVIOUS },
+               { 0x000000000700ffeell, KEY_REWIND },
+               { 0x000000000400ffeell, KEY_STOP },
+               { 0x000000003c00ffeell, KEY_PLAYPAUSE },
+               { 0x000000000800ffeell, KEY_FASTFORWARD },
+               { 0x000000000600ffeell, KEY_NEXT },
+               { 0x000000010000ffeell, KEY_RIGHT },
+               { 0x000001000000ffeell, KEY_LEFT },
+               { 0x000000003d00ffeell, KEY_SELECT },
+               { 0x000100000000ffeell, KEY_VOLUMEUP },
+               { 0x010000000000ffeell, KEY_VOLUMEDOWN },
+               { 0x000000000100ffeell, KEY_MUTE },
+               /* 0xffdc iMON MCE VFD */
+               { 0x00010000ffffffeell, KEY_VOLUMEUP },
+               { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
+               { 0x00000001ffffffeell, KEY_MUTE },
+               { 0x0000000fffffffeell, KEY_MEDIA },
+               { 0x00000012ffffffeell, KEY_UP },
+               { 0x00000013ffffffeell, KEY_DOWN },
+               { 0x00000014ffffffeell, KEY_LEFT },
+               { 0x00000015ffffffeell, KEY_RIGHT },
+               { 0x00000016ffffffeell, KEY_ENTER },
+               { 0x00000017ffffffeell, KEY_ESC },
+               /* iMON Knob values */
+               { 0x000100ffffffffeell, KEY_VOLUMEUP },
+               { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
+               { 0x000008ffffffffeell, KEY_MUTE },
+               { 0, KEY_RESERVED },
+       }
+};
+
+static const struct imon_usb_dev_descr imon_OEM_VFD = {
+       .flags = IMON_NEED_20MS_PKT_DELAY,
+       .key_table = {
+               { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */
+               { 0x000000001200ffeell, KEY_UP },
+               { 0x000000001300ffeell, KEY_DOWN },
+               { 0x000000001400ffeell, KEY_LEFT },
+               { 0x000000001500ffeell, KEY_RIGHT },
+               { 0x000000001600ffeell, KEY_ENTER },
+               { 0x000000001700ffeell, KEY_ESC },
+               { 0x000000001f00ffeell, KEY_AUDIO },
+               { 0x000000002b00ffeell, KEY_EXIT },
+               { 0x000000002c00ffeell, KEY_SELECT },
+               { 0x000000002d00ffeell, KEY_MENU },
+               { 0x000000000500ffeell, KEY_PREVIOUS },
+               { 0x000000000700ffeell, KEY_REWIND },
+               { 0x000000000400ffeell, KEY_STOP },
+               { 0x000000003c00ffeell, KEY_PLAYPAUSE },
+               { 0x000000000800ffeell, KEY_FASTFORWARD },
+               { 0x000000000600ffeell, KEY_NEXT },
+               { 0x000000010000ffeell, KEY_RIGHT },
+               { 0x000001000000ffeell, KEY_LEFT },
+               { 0x000000003d00ffeell, KEY_SELECT },
+               { 0x000100000000ffeell, KEY_VOLUMEUP },
+               { 0x010000000000ffeell, KEY_VOLUMEDOWN },
+               { 0x000000000100ffeell, KEY_MUTE },
+               /* 0xffdc iMON MCE VFD */
+               { 0x00010000ffffffeell, KEY_VOLUMEUP },
+               { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
+               { 0x00000001ffffffeell, KEY_MUTE },
+               { 0x0000000fffffffeell, KEY_MEDIA },
+               { 0x00000012ffffffeell, KEY_UP },
+               { 0x00000013ffffffeell, KEY_DOWN },
+               { 0x00000014ffffffeell, KEY_LEFT },
+               { 0x00000015ffffffeell, KEY_RIGHT },
+               { 0x00000016ffffffeell, KEY_ENTER },
+               { 0x00000017ffffffeell, KEY_ESC },
+               /* iMON Knob values */
+               { 0x000100ffffffffeell, KEY_VOLUMEUP },
+               { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
+               { 0x000008ffffffffeell, KEY_MUTE },
+               { 0, KEY_RESERVED },
+       }
+};
+
+/* imon receiver front panel/knob key table for DH102*/
+static const struct imon_usb_dev_descr imon_DH102 = {
+       .flags = IMON_NO_FLAGS,
+       .key_table = {
+               { 0x000100000000ffeell, KEY_VOLUMEUP },
+               { 0x010000000000ffeell, KEY_VOLUMEDOWN },
+               { 0x000000010000ffeell, KEY_MUTE },
+               { 0x0000000f0000ffeell, KEY_MEDIA },
+               { 0x000000120000ffeell, KEY_UP },
+               { 0x000000130000ffeell, KEY_DOWN },
+               { 0x000000140000ffeell, KEY_LEFT },
+               { 0x000000150000ffeell, KEY_RIGHT },
+               { 0x000000160000ffeell, KEY_ENTER },
+               { 0x000000170000ffeell, KEY_ESC },
+               { 0x0000002b0000ffeell, KEY_EXIT },
+               { 0x0000002c0000ffeell, KEY_SELECT },
+               { 0x0000002d0000ffeell, KEY_MENU },
+               { 0, KEY_RESERVED }
+       }
 };
 
 /*
@@ -208,7 +346,8 @@ static struct usb_device_id imon_usb_id_table[] = {
         * SoundGraph iMON PAD (IR & LCD)
         * SoundGraph iMON Knob (IR only)
         */
-       { USB_DEVICE(0x15c2, 0xffdc) },
+       { USB_DEVICE(0x15c2, 0xffdc),
+         .driver_info = (unsigned long)&imon_default_table },
 
        /*
         * Newer devices, all driven by the latest iMON Windows driver, full
@@ -216,43 +355,62 @@ static struct usb_device_id imon_usb_id_table[] = {
         * Need user input to fill in details on unknown devices.
         */
        /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */
-       { USB_DEVICE(0x15c2, 0x0034) },
+       { USB_DEVICE(0x15c2, 0x0034),
+         .driver_info = (unsigned long)&imon_DH102 },
        /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */
-       { USB_DEVICE(0x15c2, 0x0035) },
+       { USB_DEVICE(0x15c2, 0x0035),
+         .driver_info = (unsigned long)&imon_default_table},
        /* SoundGraph iMON OEM VFD (IR & VFD) */
-       { USB_DEVICE(0x15c2, 0x0036), .driver_info = IMON_NEED_20MS_PKT_DELAY },
+       { USB_DEVICE(0x15c2, 0x0036),
+         .driver_info = (unsigned long)&imon_OEM_VFD },
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x0037) },
+       { USB_DEVICE(0x15c2, 0x0037),
+         .driver_info = (unsigned long)&imon_default_table},
        /* SoundGraph iMON OEM LCD (IR & LCD) */
-       { USB_DEVICE(0x15c2, 0x0038) },
+       { USB_DEVICE(0x15c2, 0x0038),
+         .driver_info = (unsigned long)&imon_default_table},
        /* SoundGraph iMON UltraBay (IR & LCD) */
-       { USB_DEVICE(0x15c2, 0x0039) },
+       { USB_DEVICE(0x15c2, 0x0039),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x003a) },
+       { USB_DEVICE(0x15c2, 0x003a),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x003b) },
+       { USB_DEVICE(0x15c2, 0x003b),
+         .driver_info = (unsigned long)&imon_default_table},
        /* SoundGraph iMON OEM Inside (IR only) */
-       { USB_DEVICE(0x15c2, 0x003c) },
+       { USB_DEVICE(0x15c2, 0x003c),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x003d) },
+       { USB_DEVICE(0x15c2, 0x003d),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x003e) },
+       { USB_DEVICE(0x15c2, 0x003e),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x003f) },
+       { USB_DEVICE(0x15c2, 0x003f),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x0040) },
+       { USB_DEVICE(0x15c2, 0x0040),
+         .driver_info = (unsigned long)&imon_default_table},
        /* SoundGraph iMON MINI (IR only) */
-       { USB_DEVICE(0x15c2, 0x0041) },
+       { USB_DEVICE(0x15c2, 0x0041),
+         .driver_info = (unsigned long)&imon_default_table},
        /* Antec Veris Multimedia Station EZ External (IR only) */
-       { USB_DEVICE(0x15c2, 0x0042) },
+       { USB_DEVICE(0x15c2, 0x0042),
+         .driver_info = (unsigned long)&imon_default_table},
        /* Antec Veris Multimedia Station Basic Internal (IR only) */
-       { USB_DEVICE(0x15c2, 0x0043) },
+       { USB_DEVICE(0x15c2, 0x0043),
+         .driver_info = (unsigned long)&imon_default_table},
        /* Antec Veris Multimedia Station Elite (IR & VFD) */
-       { USB_DEVICE(0x15c2, 0x0044) },
+       { USB_DEVICE(0x15c2, 0x0044),
+         .driver_info = (unsigned long)&imon_default_table},
        /* Antec Veris Multimedia Station Premiere (IR & LCD) */
-       { USB_DEVICE(0x15c2, 0x0045) },
+       { USB_DEVICE(0x15c2, 0x0045),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x0046) },
+       { USB_DEVICE(0x15c2, 0x0046),
+         .driver_info = (unsigned long)&imon_default_table},
        {}
 };
 
@@ -266,67 +424,6 @@ static struct usb_driver imon_driver = {
        .id_table       = imon_usb_id_table,
 };
 
-static struct usb_class_driver imon_vfd_class = {
-       .name           = DEVICE_NAME,
-       .fops           = &vfd_fops,
-       .minor_base     = DISPLAY_MINOR_BASE,
-};
-
-static struct usb_class_driver imon_lcd_class = {
-       .name           = DEVICE_NAME,
-       .fops           = &lcd_fops,
-       .minor_base     = DISPLAY_MINOR_BASE,
-};
-
-/* imon receiver front panel/knob key table */
-static const struct {
-       u64 hw_code;
-       u32 keycode;
-} imon_panel_key_table[] = {
-       { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */
-       { 0x000000001200ffeell, KEY_UP },
-       { 0x000000001300ffeell, KEY_DOWN },
-       { 0x000000001400ffeell, KEY_LEFT },
-       { 0x000000001500ffeell, KEY_RIGHT },
-       { 0x000000001600ffeell, KEY_ENTER },
-       { 0x000000001700ffeell, KEY_ESC },
-       { 0x000000001f00ffeell, KEY_AUDIO },
-       { 0x000000002000ffeell, KEY_VIDEO },
-       { 0x000000002100ffeell, KEY_CAMERA },
-       { 0x000000002700ffeell, KEY_DVD },
-       { 0x000000002300ffeell, KEY_TV },
-       { 0x000000002b00ffeell, KEY_EXIT },
-       { 0x000000002c00ffeell, KEY_SELECT },
-       { 0x000000002d00ffeell, KEY_MENU },
-       { 0x000000000500ffeell, KEY_PREVIOUS },
-       { 0x000000000700ffeell, KEY_REWIND },
-       { 0x000000000400ffeell, KEY_STOP },
-       { 0x000000003c00ffeell, KEY_PLAYPAUSE },
-       { 0x000000000800ffeell, KEY_FASTFORWARD },
-       { 0x000000000600ffeell, KEY_NEXT },
-       { 0x000000010000ffeell, KEY_RIGHT },
-       { 0x000001000000ffeell, KEY_LEFT },
-       { 0x000000003d00ffeell, KEY_SELECT },
-       { 0x000100000000ffeell, KEY_VOLUMEUP },
-       { 0x010000000000ffeell, KEY_VOLUMEDOWN },
-       { 0x000000000100ffeell, KEY_MUTE },
-       /* 0xffdc iMON MCE VFD */
-       { 0x00010000ffffffeell, KEY_VOLUMEUP },
-       { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
-       { 0x00000001ffffffeell, KEY_MUTE },
-       { 0x0000000fffffffeell, KEY_MEDIA },
-       { 0x00000012ffffffeell, KEY_UP },
-       { 0x00000013ffffffeell, KEY_DOWN },
-       { 0x00000014ffffffeell, KEY_LEFT },
-       { 0x00000015ffffffeell, KEY_RIGHT },
-       { 0x00000016ffffffeell, KEY_ENTER },
-       { 0x00000017ffffffeell, KEY_ESC },
-       /* iMON Knob values */
-       { 0x000100ffffffffeell, KEY_VOLUMEUP },
-       { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
-       { 0x000008ffffffffeell, KEY_MUTE },
-};
-
 /* to prevent races between open() and disconnect(), probing, etc */
 static DEFINE_MUTEX(driver_lock);
 
@@ -1210,18 +1307,19 @@ static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode)
        return keycode;
 }
 
-static u32 imon_panel_key_lookup(u64 code)
+static u32 imon_panel_key_lookup(struct imon_context *ictx, u64 code)
 {
        int i;
        u32 keycode = KEY_RESERVED;
+       struct imon_panel_key_table *key_table = ictx->dev_descr->key_table;
 
-       for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
-               if (imon_panel_key_table[i].hw_code == (code | 0xffee)) {
-                       keycode = imon_panel_key_table[i].keycode;
+       for (i = 0; key_table[i].hw_code != 0; i++) {
+               if (key_table[i].hw_code == (code | 0xffee)) {
+                       keycode = key_table[i].keycode;
                        break;
                }
        }
-
+       ictx->release_code = false;
        return keycode;
 }
 
@@ -1340,7 +1438,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
                                }
                                buf[2] = dir & 0xFF;
                                buf[3] = (dir >> 8) & 0xFF;
-                               scancode = be32_to_cpu(*((u32 *)buf));
+                               scancode = be32_to_cpu(*((__be32 *)buf));
                        }
                } else {
                        /*
@@ -1404,7 +1502,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
                        }
                        buf[2] = dir & 0xFF;
                        buf[3] = (dir >> 8) & 0xFF;
-                       scancode = be32_to_cpu(*((u32 *)buf));
+                       scancode = be32_to_cpu(*((__be32 *)buf));
                } else {
                        /*
                         * Hack alert: instead of using keycodes, we have
@@ -1509,11 +1607,12 @@ static void imon_incoming_packet(struct imon_context *ictx,
 
        /* Figure out what key was pressed */
        if (len == 8 && buf[7] == 0xee) {
-               scancode = be64_to_cpu(*((u64 *)buf));
+               scancode = be64_to_cpu(*((__be64 *)buf));
                ktype = IMON_KEY_PANEL;
-               kc = imon_panel_key_lookup(scancode);
+               kc = imon_panel_key_lookup(ictx, scancode);
+               ictx->release_code = false;
        } else {
-               scancode = be32_to_cpu(*((u32 *)buf));
+               scancode = be32_to_cpu(*((__be32 *)buf));
                if (ictx->rc_type == RC_BIT_RC6_MCE) {
                        ktype = IMON_KEY_IMON;
                        if (buf[0] == 0x80)
@@ -1908,6 +2007,7 @@ out:
 
 static struct input_dev *imon_init_idev(struct imon_context *ictx)
 {
+       struct imon_panel_key_table *key_table = ictx->dev_descr->key_table;
        struct input_dev *idev;
        int ret, i;
 
@@ -1933,8 +2033,8 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx)
                BIT_MASK(REL_WHEEL);
 
        /* panel and/or knob code support */
-       for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
-               u32 kc = imon_panel_key_table[i].keycode;
+       for (i = 0; key_table[i].hw_code != 0; i++) {
+               u32 kc = key_table[i].keycode;
                __set_bit(kc, idev->keybit);
        }
 
@@ -2023,7 +2123,7 @@ static bool imon_find_endpoints(struct imon_context *ictx,
        for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
                ep = &iface_desc->endpoint[i].desc;
                ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
-               ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+               ep_type = usb_endpoint_type(ep);
 
                if (!ir_ep_found && ep_dir == USB_DIR_IN &&
                    ep_type == USB_ENDPOINT_XFER_INT) {
@@ -2135,9 +2235,11 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf,
        ictx->vendor  = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
        ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
 
+       /* save drive info for later accessing the panel/knob key table */
+       ictx->dev_descr = (struct imon_usb_dev_descr *)id->driver_info;
        /* default send_packet delay is 5ms but some devices need more */
-       ictx->send_packet_delay = id->driver_info & IMON_NEED_20MS_PKT_DELAY ?
-                                 20 : 5;
+       ictx->send_packet_delay = ictx->dev_descr->flags &
+                                 IMON_NEED_20MS_PKT_DELAY ? 20 : 5;
 
        ret = -ENODEV;
        iface_desc = intf->cur_altsetting;
@@ -2181,6 +2283,7 @@ idev_setup_failed:
        usb_kill_urb(ictx->rx_urb_intf0);
 urb_submit_failed:
 find_endpoint_failed:
+       usb_put_dev(ictx->usbdev_intf0);
        mutex_unlock(&ictx->lock);
        usb_free_urb(tx_urb);
 tx_urb_alloc_failed:
@@ -2253,6 +2356,7 @@ urb_submit_failed:
                input_unregister_device(ictx->touch);
 touch_setup_failed:
 find_endpoint_failed:
+       usb_put_dev(ictx->usbdev_intf1);
        mutex_unlock(&ictx->lock);
        usb_free_urb(rx_urb);
 rx_urb_alloc_failed:
@@ -2366,11 +2470,13 @@ static int imon_probe(struct usb_interface *interface,
                 usbdev->bus->busnum, usbdev->devnum);
 
        mutex_unlock(&driver_lock);
+       usb_put_dev(usbdev);
 
        return 0;
 
 fail:
        mutex_unlock(&driver_lock);
+       usb_put_dev(usbdev);
        dev_err(dev, "unable to register, err %d\n", ret);
 
        return ret;
@@ -2410,6 +2516,7 @@ static void imon_disconnect(struct usb_interface *interface)
        if (ifnum == 0) {
                ictx->dev_present_intf0 = false;
                usb_kill_urb(ictx->rx_urb_intf0);
+               usb_put_dev(ictx->usbdev_intf0);
                input_unregister_device(ictx->idev);
                rc_unregister_device(ictx->rdev);
                if (ictx->display_supported) {
@@ -2421,6 +2528,7 @@ static void imon_disconnect(struct usb_interface *interface)
        } else {
                ictx->dev_present_intf1 = false;
                usb_kill_urb(ictx->rx_urb_intf1);
+               usb_put_dev(ictx->usbdev_intf1);
                if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
                        input_unregister_device(ictx->touch);
                        del_timer_sync(&ictx->ttimer);
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
new file mode 100644 (file)
index 0000000..08bbd4f
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2014 Linaro Ltd.
+ * Copyright (c) 2014 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <media/rc-core.h>
+
+/* Allow the driver to compile on all architectures */
+#ifndef writel_relaxed
+# define writel_relaxed writel
+#endif
+#ifndef readl_relaxed
+# define readl_relaxed readl
+#endif
+
+#define IR_ENABLE              0x00
+#define IR_CONFIG              0x04
+#define CNT_LEADS              0x08
+#define CNT_LEADE              0x0c
+#define CNT_SLEADE             0x10
+#define CNT0_B                 0x14
+#define CNT1_B                 0x18
+#define IR_BUSY                        0x1c
+#define IR_DATAH               0x20
+#define IR_DATAL               0x24
+#define IR_INTM                        0x28
+#define IR_INTS                        0x2c
+#define IR_INTC                        0x30
+#define IR_START               0x34
+
+/* interrupt mask */
+#define INTMS_SYMBRCV          (BIT(24) | BIT(8))
+#define INTMS_TIMEOUT          (BIT(25) | BIT(9))
+#define INTMS_OVERFLOW         (BIT(26) | BIT(10))
+#define INT_CLR_OVERFLOW       BIT(18)
+#define INT_CLR_TIMEOUT                BIT(17)
+#define INT_CLR_RCV            BIT(16)
+#define INT_CLR_RCVTIMEOUT     (BIT(16) | BIT(17))
+
+#define IR_CLK                 0x48
+#define IR_CLK_ENABLE          BIT(4)
+#define IR_CLK_RESET           BIT(5)
+
+#define IR_CFG_WIDTH_MASK      0xffff
+#define IR_CFG_WIDTH_SHIFT     16
+#define IR_CFG_FORMAT_MASK     0x3
+#define IR_CFG_FORMAT_SHIFT    14
+#define IR_CFG_INT_LEVEL_MASK  0x3f
+#define IR_CFG_INT_LEVEL_SHIFT 8
+/* only support raw mode */
+#define IR_CFG_MODE_RAW                BIT(7)
+#define IR_CFG_FREQ_MASK       0x7f
+#define IR_CFG_FREQ_SHIFT      0
+#define IR_CFG_INT_THRESHOLD   1
+/* symbol start from low to high, symbol stream end at high*/
+#define IR_CFG_SYMBOL_FMT      0
+#define IR_CFG_SYMBOL_MAXWIDTH 0x3e80
+
+#define IR_HIX5HD2_NAME                "hix5hd2-ir"
+
+struct hix5hd2_ir_priv {
+       int                     irq;
+       void volatile __iomem   *base;
+       struct device           *dev;
+       struct rc_dev           *rdev;
+       struct regmap           *regmap;
+       struct clk              *clock;
+       unsigned long           rate;
+};
+
+static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
+{
+       u32 val;
+
+       regmap_read(dev->regmap, IR_CLK, &val);
+       if (on) {
+               val &= ~IR_CLK_RESET;
+               val |= IR_CLK_ENABLE;
+       } else {
+               val &= ~IR_CLK_ENABLE;
+               val |= IR_CLK_RESET;
+       }
+       regmap_write(dev->regmap, IR_CLK, val);
+}
+
+static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv)
+{
+       int timeout = 10000;
+       u32 val, rate;
+
+       writel_relaxed(0x01, priv->base + IR_ENABLE);
+       while (readl_relaxed(priv->base + IR_BUSY)) {
+               if (timeout--) {
+                       udelay(1);
+               } else {
+                       dev_err(priv->dev, "IR_BUSY timeout\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       /* Now only support raw mode, with symbol start from low to high */
+       rate = DIV_ROUND_CLOSEST(priv->rate, 1000000);
+       val = IR_CFG_SYMBOL_MAXWIDTH & IR_CFG_WIDTH_MASK << IR_CFG_WIDTH_SHIFT;
+       val |= IR_CFG_SYMBOL_FMT & IR_CFG_FORMAT_MASK << IR_CFG_FORMAT_SHIFT;
+       val |= (IR_CFG_INT_THRESHOLD - 1) & IR_CFG_INT_LEVEL_MASK
+              << IR_CFG_INT_LEVEL_SHIFT;
+       val |= IR_CFG_MODE_RAW;
+       val |= (rate - 1) & IR_CFG_FREQ_MASK << IR_CFG_FREQ_SHIFT;
+       writel_relaxed(val, priv->base + IR_CONFIG);
+
+       writel_relaxed(0x00, priv->base + IR_INTM);
+       /* write arbitrary value to start  */
+       writel_relaxed(0x01, priv->base + IR_START);
+       return 0;
+}
+
+static int hix5hd2_ir_open(struct rc_dev *rdev)
+{
+       struct hix5hd2_ir_priv *priv = rdev->priv;
+
+       hix5hd2_ir_enable(priv, true);
+       return hix5hd2_ir_config(priv);
+}
+
+static void hix5hd2_ir_close(struct rc_dev *rdev)
+{
+       struct hix5hd2_ir_priv *priv = rdev->priv;
+
+       hix5hd2_ir_enable(priv, false);
+}
+
+static irqreturn_t hix5hd2_ir_rx_interrupt(int irq, void *data)
+{
+       u32 symb_num, symb_val, symb_time;
+       u32 data_l, data_h;
+       u32 irq_sr, i;
+       struct hix5hd2_ir_priv *priv = data;
+
+       irq_sr = readl_relaxed(priv->base + IR_INTS);
+       if (irq_sr & INTMS_OVERFLOW) {
+               /*
+                * we must read IR_DATAL first, then we can clean up
+                * IR_INTS availably since logic would not clear
+                * fifo when overflow, drv do the job
+                */
+               ir_raw_event_reset(priv->rdev);
+               symb_num = readl_relaxed(priv->base + IR_DATAH);
+               for (i = 0; i < symb_num; i++)
+                       readl_relaxed(priv->base + IR_DATAL);
+
+               writel_relaxed(INT_CLR_OVERFLOW, priv->base + IR_INTC);
+               dev_info(priv->dev, "overflow, level=%d\n",
+                        IR_CFG_INT_THRESHOLD);
+       }
+
+       if ((irq_sr & INTMS_SYMBRCV) || (irq_sr & INTMS_TIMEOUT)) {
+               DEFINE_IR_RAW_EVENT(ev);
+
+               symb_num = readl_relaxed(priv->base + IR_DATAH);
+               for (i = 0; i < symb_num; i++) {
+                       symb_val = readl_relaxed(priv->base + IR_DATAL);
+                       data_l = ((symb_val & 0xffff) * 10);
+                       data_h =  ((symb_val >> 16) & 0xffff) * 10;
+                       symb_time = (data_l + data_h) / 10;
+
+                       ev.duration = US_TO_NS(data_l);
+                       ev.pulse = true;
+                       ir_raw_event_store(priv->rdev, &ev);
+
+                       if (symb_time < IR_CFG_SYMBOL_MAXWIDTH) {
+                               ev.duration = US_TO_NS(data_h);
+                               ev.pulse = false;
+                               ir_raw_event_store(priv->rdev, &ev);
+                       } else {
+                               ir_raw_event_set_idle(priv->rdev, true);
+                       }
+               }
+
+               if (irq_sr & INTMS_SYMBRCV)
+                       writel_relaxed(INT_CLR_RCV, priv->base + IR_INTC);
+               if (irq_sr & INTMS_TIMEOUT)
+                       writel_relaxed(INT_CLR_TIMEOUT, priv->base + IR_INTC);
+       }
+
+       /* Empty software fifo */
+       ir_raw_event_handle(priv->rdev);
+       return IRQ_HANDLED;
+}
+
+static int hix5hd2_ir_probe(struct platform_device *pdev)
+{
+       struct rc_dev *rdev;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct hix5hd2_ir_priv *priv;
+       struct device_node *node = pdev->dev.of_node;
+       const char *map_name;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->regmap = syscon_regmap_lookup_by_phandle(node,
+                                                      "hisilicon,power-syscon");
+       if (IS_ERR(priv->regmap)) {
+               dev_err(dev, "no power-reg\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR((__force void *)priv->base))
+               return PTR_ERR((__force void *)priv->base);
+
+       priv->irq = platform_get_irq(pdev, 0);
+       if (priv->irq < 0) {
+               dev_err(dev, "irq can not get\n");
+               return priv->irq;
+       }
+
+       rdev = rc_allocate_device();
+       if (!rdev)
+               return -ENOMEM;
+
+       priv->clock = devm_clk_get(dev, NULL);
+       if (IS_ERR(priv->clock)) {
+               dev_err(dev, "clock not found\n");
+               ret = PTR_ERR(priv->clock);
+               goto err;
+       }
+       clk_prepare_enable(priv->clock);
+       priv->rate = clk_get_rate(priv->clock);
+
+       rdev->driver_type = RC_DRIVER_IR_RAW;
+       rdev->allowed_protocols = RC_BIT_ALL;
+       rdev->priv = priv;
+       rdev->open = hix5hd2_ir_open;
+       rdev->close = hix5hd2_ir_close;
+       rdev->driver_name = IR_HIX5HD2_NAME;
+       map_name = of_get_property(node, "linux,rc-map-name", NULL);
+       rdev->map_name = map_name ?: RC_MAP_EMPTY;
+       rdev->input_name = IR_HIX5HD2_NAME;
+       rdev->input_phys = IR_HIX5HD2_NAME "/input0";
+       rdev->input_id.bustype = BUS_HOST;
+       rdev->input_id.vendor = 0x0001;
+       rdev->input_id.product = 0x0001;
+       rdev->input_id.version = 0x0100;
+       rdev->rx_resolution = US_TO_NS(10);
+       rdev->timeout = US_TO_NS(IR_CFG_SYMBOL_MAXWIDTH * 10);
+
+       ret = rc_register_device(rdev);
+       if (ret < 0)
+               goto clkerr;
+
+       if (devm_request_irq(dev, priv->irq, hix5hd2_ir_rx_interrupt,
+                            IRQF_NO_SUSPEND, pdev->name, priv) < 0) {
+               dev_err(dev, "IRQ %d register failed\n", priv->irq);
+               ret = -EINVAL;
+               goto regerr;
+       }
+
+       priv->rdev = rdev;
+       priv->dev = dev;
+       platform_set_drvdata(pdev, priv);
+
+       return ret;
+
+regerr:
+       rc_unregister_device(rdev);
+       rdev = NULL;
+clkerr:
+       clk_disable_unprepare(priv->clock);
+err:
+       rc_free_device(rdev);
+       dev_err(dev, "Unable to register device (%d)\n", ret);
+       return ret;
+}
+
+static int hix5hd2_ir_remove(struct platform_device *pdev)
+{
+       struct hix5hd2_ir_priv *priv = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(priv->clock);
+       rc_unregister_device(priv->rdev);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int hix5hd2_ir_suspend(struct device *dev)
+{
+       struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(priv->clock);
+       hix5hd2_ir_enable(priv, false);
+
+       return 0;
+}
+
+static int hix5hd2_ir_resume(struct device *dev)
+{
+       struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev);
+
+       hix5hd2_ir_enable(priv, true);
+       clk_prepare_enable(priv->clock);
+
+       writel_relaxed(0x01, priv->base + IR_ENABLE);
+       writel_relaxed(0x00, priv->base + IR_INTM);
+       writel_relaxed(0xff, priv->base + IR_INTC);
+       writel_relaxed(0x01, priv->base + IR_START);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(hix5hd2_ir_pm_ops, hix5hd2_ir_suspend,
+                        hix5hd2_ir_resume);
+
+static struct of_device_id hix5hd2_ir_table[] = {
+       { .compatible = "hisilicon,hix5hd2-ir", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, hix5hd2_ir_table);
+
+static struct platform_driver hix5hd2_ir_driver = {
+       .driver = {
+               .name = IR_HIX5HD2_NAME,
+               .of_match_table = hix5hd2_ir_table,
+               .pm     = &hix5hd2_ir_pm_ops,
+       },
+       .probe = hix5hd2_ir_probe,
+       .remove = hix5hd2_ir_remove,
+};
+
+module_platform_driver(hix5hd2_ir_driver);
+
+MODULE_DESCRIPTION("IR controller driver for hix5hd2 platforms");
+MODULE_AUTHOR("Guoxiong Yan <yanguoxiong@huawei.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:hix5hd2-ir");
index 447fe35862dc2d5ad00cce91eb7fd61edaf9e4b5..56abf9120cc27491d20857958fa10b1111ce573e 100644 (file)
@@ -1666,7 +1666,6 @@ static int ite_suspend(struct pnp_dev *pdev, pm_message_t state)
 
 static int ite_resume(struct pnp_dev *pdev)
 {
-       int ret = 0;
        struct ite_dev *dev = pnp_get_drvdata(pdev);
        unsigned long flags;
 
@@ -1681,7 +1680,7 @@ static int ite_resume(struct pnp_dev *pdev)
 
        spin_unlock_irqrestore(&dev->lock, flags);
 
-       return ret;
+       return 0;
 }
 
 static void ite_shutdown(struct pnp_dev *pdev)
index 0b8c54919010cec79ac916700374f6eca5849f37..abf60794223d3607fce92d6d94aa1e064e23735c 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-dm1105-nec.o \
                        rc-dntv-live-dvb-t.o \
                        rc-dntv-live-dvbt-pro.o \
+                       rc-dvbsky.o \
                        rc-em-terratec.o \
                        rc-encore-enltv2.o \
                        rc-encore-enltv.o \
diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c
new file mode 100644 (file)
index 0000000..c5115a1
--- /dev/null
@@ -0,0 +1,78 @@
+/* rc-dvbsky.c - Keytable for DVBSky Remote Controllers
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ *
+ * Copyright (c) 2010-2012 by Nibble Max <nibble.max@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.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+/*
+ * This table contains the complete RC5 code, instead of just the data part
+ */
+
+static struct rc_map_table rc5_dvbsky[] = {
+       { 0x0000, KEY_0 },
+       { 0x0001, KEY_1 },
+       { 0x0002, KEY_2 },
+       { 0x0003, KEY_3 },
+       { 0x0004, KEY_4 },
+       { 0x0005, KEY_5 },
+       { 0x0006, KEY_6 },
+       { 0x0007, KEY_7 },
+       { 0x0008, KEY_8 },
+       { 0x0009, KEY_9 },
+       { 0x000a, KEY_MUTE },
+       { 0x000d, KEY_OK },
+       { 0x000b, KEY_STOP },
+       { 0x000c, KEY_EXIT },
+       { 0x000e, KEY_CAMERA }, /*Snap shot*/
+       { 0x000f, KEY_SUBTITLE }, /*PIP*/
+       { 0x0010, KEY_VOLUMEUP },
+       { 0x0011, KEY_VOLUMEDOWN },
+       { 0x0012, KEY_FAVORITES },
+       { 0x0013, KEY_LIST }, /*Info*/
+       { 0x0016, KEY_PAUSE },
+       { 0x0017, KEY_PLAY },
+       { 0x001f, KEY_RECORD },
+       { 0x0020, KEY_CHANNELDOWN },
+       { 0x0021, KEY_CHANNELUP },
+       { 0x0025, KEY_POWER2 },
+       { 0x0026, KEY_REWIND },
+       { 0x0027, KEY_FASTFORWARD },
+       { 0x0029, KEY_LAST },
+       { 0x002b, KEY_MENU },
+       { 0x002c, KEY_EPG },
+       { 0x002d, KEY_ZOOM },
+};
+
+static struct rc_map_list rc5_dvbsky_map = {
+       .map = {
+               .scan    = rc5_dvbsky,
+               .size    = ARRAY_SIZE(rc5_dvbsky),
+               .rc_type = RC_TYPE_RC5,
+               .name    = RC_MAP_DVBSKY,
+       }
+};
+
+static int __init init_rc_map_rc5_dvbsky(void)
+{
+       return rc_map_register(&rc5_dvbsky_map);
+}
+
+static void __exit exit_rc_map_rc5_dvbsky(void)
+{
+       rc_map_unregister(&rc5_dvbsky_map);
+}
+
+module_init(init_rc_map_rc5_dvbsky)
+module_exit(exit_rc_map_rc5_dvbsky)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nibble Max <nibble.max@gmail.com>");
index dc5cbffcd5a26a4702b578e97c995e527b644236..249d2fbc8f3748b69fa95ff39e783a458cb18a8f 100644 (file)
@@ -595,7 +595,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
        switch (cmd) {
        case LIRC_GET_FEATURES:
-               result = put_user(ir->d.features, (__u32 *)arg);
+               result = put_user(ir->d.features, (__u32 __user *)arg);
                break;
        case LIRC_GET_REC_MODE:
                if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
@@ -605,7 +605,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                result = put_user(LIRC_REC2MODE
                                  (ir->d.features & LIRC_CAN_REC_MASK),
-                                 (__u32 *)arg);
+                                 (__u32 __user *)arg);
                break;
        case LIRC_SET_REC_MODE:
                if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
@@ -613,7 +613,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        break;
                }
 
-               result = get_user(mode, (__u32 *)arg);
+               result = get_user(mode, (__u32 __user *)arg);
                if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
                        result = -EINVAL;
                /*
@@ -622,7 +622,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                 */
                break;
        case LIRC_GET_LENGTH:
-               result = put_user(ir->d.code_length, (__u32 *)arg);
+               result = put_user(ir->d.code_length, (__u32 __user *)arg);
                break;
        case LIRC_GET_MIN_TIMEOUT:
                if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
@@ -631,7 +631,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        break;
                }
 
-               result = put_user(ir->d.min_timeout, (__u32 *)arg);
+               result = put_user(ir->d.min_timeout, (__u32 __user *)arg);
                break;
        case LIRC_GET_MAX_TIMEOUT:
                if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
@@ -640,7 +640,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        break;
                }
 
-               result = put_user(ir->d.max_timeout, (__u32 *)arg);
+               result = put_user(ir->d.max_timeout, (__u32 __user *)arg);
                break;
        default:
                result = -EINVAL;
@@ -736,7 +736,7 @@ ssize_t lirc_dev_fop_read(struct file *file,
                        }
                } else {
                        lirc_buffer_read(ir->buf, buf);
-                       ret = copy_to_user((void *)buffer+written, buf,
+                       ret = copy_to_user((void __user *)buffer+written, buf,
                                           ir->buf->chunk_size);
                        if (!ret)
                                written += ir->buf->chunk_size;
index 45b0894288e511209a9c63ba314614fc0c382bba..2cdb740cde481e2e8884b7ddb05c90f6f399a954 100644 (file)
@@ -397,6 +397,10 @@ static struct usb_device_id mceusb_dev_table[] = {
          .driver_info = HAUPPAUGE_CX_HYBRID_TV },
        { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb131),
          .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+       { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb138),
+         .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+       { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb139),
+         .driver_info = HAUPPAUGE_CX_HYBRID_TV },
        { USB_DEVICE(VENDOR_PCTV, 0x0259),
          .driver_info = HAUPPAUGE_CX_HYBRID_TV },
        { USB_DEVICE(VENDOR_PCTV, 0x025e),
@@ -1198,10 +1202,9 @@ static void mceusb_flash_led(struct mceusb_dev *ir)
        mce_async_out(ir, FLASH_LED, sizeof(FLASH_LED));
 }
 
-static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir,
-                                        struct usb_interface *intf)
+static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
 {
-       struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf));
+       struct usb_device *udev = ir->usbdev;
        struct device *dev = ir->dev;
        struct rc_dev *rc;
        int ret;
@@ -1341,7 +1344,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
        if (!ir->urb_in)
                goto urb_in_alloc_fail;
 
-       ir->usbdev = dev;
+       ir->usbdev = usb_get_dev(dev);
        ir->dev = &intf->dev;
        ir->len_in = maxp;
        ir->flags.microsoft_gen1 = is_microsoft_gen1;
@@ -1362,7 +1365,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
                snprintf(name + strlen(name), sizeof(name) - strlen(name),
                         " %s", buf);
 
-       ir->rc = mceusb_init_rc_dev(ir, intf);
+       ir->rc = mceusb_init_rc_dev(ir);
        if (!ir->rc)
                goto rc_dev_fail;
 
@@ -1408,6 +1411,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
 
        /* Error-handling path */
 rc_dev_fail:
+       usb_put_dev(ir->usbdev);
        usb_free_urb(ir->urb_in);
 urb_in_alloc_fail:
        usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in);
@@ -1435,6 +1439,7 @@ static void mceusb_dev_disconnect(struct usb_interface *intf)
        usb_kill_urb(ir->urb_in);
        usb_free_urb(ir->urb_in);
        usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
+       usb_put_dev(dev);
 
        kfree(ir);
 }
index 7f4fd859bba5795e209a2c778de94be479e3b1c8..9c2c8635ff3326841178f8f04d65466886424e8b 100644 (file)
@@ -229,7 +229,6 @@ static int nvt_hw_detect(struct nvt_dev *nvt)
 {
        unsigned long flags;
        u8 chip_major, chip_minor;
-       int ret = 0;
        char chip_id[12];
        bool chip_unknown = false;
 
@@ -285,7 +284,7 @@ static int nvt_hw_detect(struct nvt_dev *nvt)
        nvt->chip_minor = chip_minor;
        spin_unlock_irqrestore(&nvt->nvt_lock, flags);
 
-       return ret;
+       return 0;
 }
 
 static void nvt_cir_ldev_init(struct nvt_dev *nvt)
@@ -1177,7 +1176,6 @@ static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state)
 
 static int nvt_resume(struct pnp_dev *pdev)
 {
-       int ret = 0;
        struct nvt_dev *nvt = pnp_get_drvdata(pdev);
 
        nvt_dbg("%s called", __func__);
@@ -1195,7 +1193,7 @@ static int nvt_resume(struct pnp_dev *pdev)
        nvt_cir_regs_init(nvt);
        nvt_cir_wake_regs_init(nvt);
 
-       return ret;
+       return 0;
 }
 
 static void nvt_shutdown(struct pnp_dev *pdev)
index 5c151351afa4c72f48ccf9e48b88abe48cfc8331..0e758ae2e52978b0b76a026d43799a9b75c42fe0 100644 (file)
@@ -22,8 +22,8 @@ struct st_rc_device {
        int                             irq;
        int                             irq_wake;
        struct clk                      *sys_clock;
-       void                            *base;  /* Register base address */
-       void                            *rx_base;/* RX Register base address */
+       volatile void __iomem           *base;  /* Register base address */
+       volatile void __iomem           *rx_base;/* RX Register base address */
        struct rc_dev                   *rdev;
        bool                            overclocking;
        int                             sample_mult;
@@ -267,8 +267,8 @@ static int st_rc_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        rc_dev->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(rc_dev->base)) {
-               ret = PTR_ERR(rc_dev->base);
+       if (IS_ERR((__force void *)rc_dev->base)) {
+               ret = PTR_ERR((__force void *)rc_dev->base);
                goto err;
        }
 
@@ -278,7 +278,7 @@ static int st_rc_probe(struct platform_device *pdev)
                rc_dev->rx_base = rc_dev->base;
 
 
-       rc_dev->rstc = reset_control_get(dev, NULL);
+       rc_dev->rstc = reset_control_get_optional(dev, NULL);
        if (IS_ERR(rc_dev->rstc))
                rc_dev->rstc = NULL;
 
@@ -376,9 +376,10 @@ static int st_rc_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(st_rc_pm_ops, st_rc_suspend, st_rc_resume);
 #endif
 
+static SIMPLE_DEV_PM_OPS(st_rc_pm_ops, st_rc_suspend, st_rc_resume);
+
 #ifdef CONFIG_OF
 static struct of_device_id st_rc_match[] = {
        { .compatible = "st,comms-irb", },
@@ -391,11 +392,8 @@ MODULE_DEVICE_TABLE(of, st_rc_match);
 static struct platform_driver st_rc_driver = {
        .driver = {
                .name = IR_ST_NAME,
-               .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(st_rc_match),
-#ifdef CONFIG_PM
                .pm     = &st_rc_pm_ops,
-#endif
        },
        .probe = st_rc_probe,
        .remove = st_rc_remove,
index 80c4feeb01ea7a47ea52e5b6ccc106b878d045d5..bf4a44272f0e3e00a01c0bc3fb44720e1732ec27 100644 (file)
@@ -362,16 +362,14 @@ static int streamzap_probe(struct usb_interface *intf,
        }
 
        sz->endpoint = &(iface_host->endpoint[0].desc);
-       if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
-           != USB_DIR_IN) {
+       if (!usb_endpoint_dir_in(sz->endpoint)) {
                dev_err(&intf->dev, "%s: endpoint doesn't match input device "
                        "02%02x\n", __func__, sz->endpoint->bEndpointAddress);
                retval = -ENODEV;
                goto free_sz;
        }
 
-       if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-           != USB_ENDPOINT_XFER_INT) {
+       if (!usb_endpoint_xfer_int(sz->endpoint)) {
                dev_err(&intf->dev, "%s: endpoint attributes don't match xfer "
                        "02%02x\n", __func__, sz->endpoint->bmAttributes);
                retval = -ENODEV;
index d79fd1ce5a18b0953d405871cf0c9569adde562a..f039dc2a21cf0fb3538d57fc42905f676b2cbe17 100644 (file)
@@ -204,6 +204,7 @@ config MEDIA_TUNER_FC0013
 config MEDIA_TUNER_TDA18212
        tristate "NXP TDA18212 silicon tuner"
        depends on MEDIA_SUPPORT && I2C
+       select REGMAP_I2C
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
          NXP TDA18212 silicon tuner driver.
@@ -226,6 +227,7 @@ config MEDIA_TUNER_FC2580
 config MEDIA_TUNER_M88TS2022
        tristate "Montage M88TS2022 silicon tuner"
        depends on MEDIA_SUPPORT && I2C
+       select REGMAP_I2C
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
          Montage M88TS2022 silicon tuner driver.
@@ -247,6 +249,7 @@ config MEDIA_TUNER_SI2157
 config MEDIA_TUNER_IT913X
        tristate "ITE Tech IT913x silicon tuner"
        depends on MEDIA_SUPPORT && I2C
+       select REGMAP_I2C
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
          ITE Tech IT913x silicon tuner driver.
@@ -257,4 +260,18 @@ config MEDIA_TUNER_R820T
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
          Rafael Micro R820T silicon tuner driver.
+
+config MEDIA_TUNER_MXL301RF
+       tristate "MaxLinear MxL301RF tuner"
+       depends on MEDIA_SUPPORT && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         MaxLinear MxL301RF OFDM tuner driver.
+
+config MEDIA_TUNER_QM1D1C0042
+       tristate "Sharp QM1D1C0042 tuner"
+       depends on MEDIA_SUPPORT && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         Sharp QM1D1C0042 trellis coded 8PSK tuner driver.
 endmenu
index 5591699755baced61dc7247e476d605a18a1220e..49fcf8033848dcf2e1029349d624268b907c2fc2 100644 (file)
@@ -37,8 +37,10 @@ obj-$(CONFIG_MEDIA_TUNER_M88TS2022) += m88ts2022.o
 obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
 obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
 obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
-obj-$(CONFIG_MEDIA_TUNER_IT913X) += tuner_it913x.o
+obj-$(CONFIG_MEDIA_TUNER_IT913X) += it913x.o
 obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o
+obj-$(CONFIG_MEDIA_TUNER_MXL301RF) += mxl301rf.o
+obj-$(CONFIG_MEDIA_TUNER_QM1D1C0042) += qm1d1c0042.o
 
 ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
index 90d93348f20c5f111aea684ba15b798bc683c6b1..510239f80c0d9f5bb173a8f71d2c784de8b60201 100644 (file)
@@ -26,7 +26,7 @@ static int e4000_init(struct dvb_frontend *fe)
        struct e4000 *s = fe->tuner_priv;
        int ret;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
        /* dummy I2C to ensure I2C wakes up */
        ret = regmap_write(s->regmap, 0x02, 0x40);
@@ -87,7 +87,7 @@ static int e4000_init(struct dvb_frontend *fe)
        s->active = true;
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -97,7 +97,7 @@ static int e4000_sleep(struct dvb_frontend *fe)
        struct e4000 *s = fe->tuner_priv;
        int ret;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
        s->active = false;
 
@@ -106,7 +106,7 @@ static int e4000_sleep(struct dvb_frontend *fe)
                goto err;
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -121,9 +121,8 @@ static int e4000_set_params(struct dvb_frontend *fe)
        u8 buf[5], i_data[4], q_data[4];
 
        dev_dbg(&s->client->dev,
-                       "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n",
-                       __func__, c->delivery_system, c->frequency,
-                       c->bandwidth_hz);
+                       "delivery_system=%d frequency=%u bandwidth_hz=%u\n",
+                       c->delivery_system, c->frequency, c->bandwidth_hz);
 
        /* gain control manual */
        ret = regmap_write(s->regmap, 0x1a, 0x00);
@@ -150,9 +149,8 @@ static int e4000_set_params(struct dvb_frontend *fe)
        buf[3] = 0x00;
        buf[4] = e4000_pll_lut[i].div;
 
-       dev_dbg(&s->client->dev,
-                       "%s: f_vco=%llu pll div=%d sigma_delta=%04x\n",
-                       __func__, f_vco, buf[0], sigma_delta);
+       dev_dbg(&s->client->dev, "f_vco=%llu pll div=%d sigma_delta=%04x\n",
+                       f_vco, buf[0], sigma_delta);
 
        ret = regmap_bulk_write(s->regmap, 0x09, buf, 5);
        if (ret)
@@ -253,7 +251,7 @@ static int e4000_set_params(struct dvb_frontend *fe)
                goto err;
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -262,7 +260,7 @@ static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
        struct e4000 *s = fe->tuner_priv;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
        *frequency = 0; /* Zero-IF */
 
@@ -276,10 +274,9 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe)
        int ret;
        u8 u8tmp;
 
-       dev_dbg(&s->client->dev, "%s: lna auto=%d->%d val=%d->%d\n",
-                       __func__, s->lna_gain_auto->cur.val,
-                       s->lna_gain_auto->val, s->lna_gain->cur.val,
-                       s->lna_gain->val);
+       dev_dbg(&s->client->dev, "lna auto=%d->%d val=%d->%d\n",
+                       s->lna_gain_auto->cur.val, s->lna_gain_auto->val,
+                       s->lna_gain->cur.val, s->lna_gain->val);
 
        if (s->lna_gain_auto->val && s->if_gain_auto->cur.val)
                u8tmp = 0x17;
@@ -301,7 +298,7 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe)
        }
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -312,10 +309,9 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe)
        int ret;
        u8 u8tmp;
 
-       dev_dbg(&s->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n",
-                       __func__, s->mixer_gain_auto->cur.val,
-                       s->mixer_gain_auto->val, s->mixer_gain->cur.val,
-                       s->mixer_gain->val);
+       dev_dbg(&s->client->dev, "mixer auto=%d->%d val=%d->%d\n",
+                       s->mixer_gain_auto->cur.val, s->mixer_gain_auto->val,
+                       s->mixer_gain->cur.val, s->mixer_gain->val);
 
        if (s->mixer_gain_auto->val)
                u8tmp = 0x15;
@@ -333,7 +329,7 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe)
        }
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -345,10 +341,9 @@ static int e4000_set_if_gain(struct dvb_frontend *fe)
        u8 buf[2];
        u8 u8tmp;
 
-       dev_dbg(&s->client->dev, "%s: if auto=%d->%d val=%d->%d\n",
-                       __func__, s->if_gain_auto->cur.val,
-                       s->if_gain_auto->val, s->if_gain->cur.val,
-                       s->if_gain->val);
+       dev_dbg(&s->client->dev, "if auto=%d->%d val=%d->%d\n",
+                       s->if_gain_auto->cur.val, s->if_gain_auto->val,
+                       s->if_gain->cur.val, s->if_gain->val);
 
        if (s->if_gain_auto->val && s->lna_gain_auto->cur.val)
                u8tmp = 0x17;
@@ -372,7 +367,7 @@ static int e4000_set_if_gain(struct dvb_frontend *fe)
        }
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -390,7 +385,7 @@ static int e4000_pll_lock(struct dvb_frontend *fe)
        s->pll_lock->val = (utmp & 0x01);
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -400,7 +395,7 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
        struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl);
        int ret;
 
-       if (s->active == false)
+       if (!s->active)
                return 0;
 
        switch (ctrl->id) {
@@ -408,8 +403,8 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
                ret = e4000_pll_lock(s->fe);
                break;
        default:
-               dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
-                               __func__, ctrl->id, ctrl->name);
+               dev_dbg(&s->client->dev, "unknown ctrl: id=%d name=%s\n",
+                               ctrl->id, ctrl->name);
                ret = -EINVAL;
        }
 
@@ -423,7 +418,7 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl)
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret;
 
-       if (s->active == false)
+       if (!s->active)
                return 0;
 
        switch (ctrl->id) {
@@ -445,8 +440,8 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl)
                ret = e4000_set_if_gain(s->fe);
                break;
        default:
-               dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
-                               __func__, ctrl->id, ctrl->name);
+               dev_dbg(&s->client->dev, "unknown ctrl: id=%d name=%s\n",
+                               ctrl->id, ctrl->name);
                ret = -EINVAL;
        }
 
@@ -494,7 +489,7 @@ static int e4000_probe(struct i2c_client *client,
        s = kzalloc(sizeof(struct e4000), GFP_KERNEL);
        if (!s) {
                ret = -ENOMEM;
-               dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+               dev_err(&client->dev, "kzalloc() failed\n");
                goto err;
        }
 
@@ -512,7 +507,7 @@ static int e4000_probe(struct i2c_client *client,
        if (ret)
                goto err;
 
-       dev_dbg(&s->client->dev, "%s: chip id=%02x\n", __func__, utmp);
+       dev_dbg(&s->client->dev, "chip id=%02x\n", utmp);
 
        if (utmp != 0x40) {
                ret = -ENODEV;
@@ -559,9 +554,7 @@ static int e4000_probe(struct i2c_client *client,
        s->sd.ctrl_handler = &s->hdl;
 #endif
 
-       dev_info(&s->client->dev,
-                       "%s: Elonics E4000 successfully identified\n",
-                       KBUILD_MODNAME);
+       dev_info(&s->client->dev, "Elonics E4000 successfully identified\n");
 
        fe->tuner_priv = s;
        memcpy(&fe->ops.tuner_ops, &e4000_tuner_ops,
@@ -573,7 +566,7 @@ static int e4000_probe(struct i2c_client *client,
        return 0;
 err:
        if (ret) {
-               dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&client->dev, "failed=%d\n", ret);
                kfree(s);
        }
 
@@ -586,7 +579,7 @@ static int e4000_remove(struct i2c_client *client)
        struct e4000 *s = container_of(sd, struct e4000, sd);
        struct dvb_frontend *fe = s->fe;
 
-       dev_dbg(&client->dev, "%s:\n", __func__);
+       dev_dbg(&client->dev, "\n");
 
 #if IS_ENABLED(CONFIG_VIDEO_V4L2)
        v4l2_ctrl_handler_free(&s->hdl);
diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c
new file mode 100644 (file)
index 0000000..a076c87
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * ITE IT913X silicon tuner driver
+ *
+ *  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 "it913x.h"
+#include <linux/regmap.h>
+
+struct it913x_dev {
+       struct i2c_client *client;
+       struct regmap *regmap;
+       struct dvb_frontend *fe;
+       u8 chip_ver:2;
+       u8 role:2;
+       u16 xtal;
+       u8 fdiv;
+       u8 clk_mode;
+       u32 fn_min;
+       bool active;
+};
+
+static int it913x_init(struct dvb_frontend *fe)
+{
+       struct it913x_dev *dev = fe->tuner_priv;
+       int ret;
+       unsigned int utmp;
+       u8 iqik_m_cal, nv_val, buf[2];
+       static const u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
+       unsigned long timeout;
+
+       dev_dbg(&dev->client->dev, "role %u\n", dev->role);
+
+       ret = regmap_write(dev->regmap, 0x80ec4c, 0x68);
+       if (ret)
+               goto err;
+
+       usleep_range(10000, 100000);
+
+       ret = regmap_read(dev->regmap, 0x80ec86, &utmp);
+       if (ret)
+               goto err;
+
+       switch (utmp) {
+       case 0:
+               /* 12.000 MHz */
+               dev->clk_mode = utmp;
+               dev->xtal = 2000;
+               dev->fdiv = 3;
+               iqik_m_cal = 16;
+               break;
+       case 1:
+               /* 20.480 MHz */
+               dev->clk_mode = utmp;
+               dev->xtal = 640;
+               dev->fdiv = 1;
+               iqik_m_cal = 6;
+               break;
+       default:
+               dev_err(&dev->client->dev, "unknown clock identifier %d\n", utmp);
+               goto err;
+       }
+
+       ret = regmap_read(dev->regmap, 0x80ed03,  &utmp);
+       if (ret)
+               goto err;
+
+       else if (utmp < ARRAY_SIZE(nv))
+               nv_val = nv[utmp];
+       else
+               nv_val = 2;
+
+       #define TIMEOUT 50
+       timeout = jiffies + msecs_to_jiffies(TIMEOUT);
+       while (!time_after(jiffies, timeout)) {
+               ret = regmap_bulk_read(dev->regmap, 0x80ed23, buf, 2);
+               if (ret)
+                       goto err;
+
+               utmp = (buf[1] << 8) | (buf[0] << 0);
+               if (utmp)
+                       break;
+       }
+
+       dev_dbg(&dev->client->dev, "r_fbc_m_bdry took %u ms, val %u\n",
+                       jiffies_to_msecs(jiffies) -
+                       (jiffies_to_msecs(timeout) - TIMEOUT), utmp);
+
+       dev->fn_min = dev->xtal * utmp;
+       dev->fn_min /= (dev->fdiv * nv_val);
+       dev->fn_min *= 1000;
+       dev_dbg(&dev->client->dev, "fn_min %u\n", dev->fn_min);
+
+       /*
+        * Chip version BX never sets that flag so we just wait 50ms in that
+        * case. It is possible poll BX similarly than AX and then timeout in
+        * order to get 50ms delay, but that causes about 120 extra I2C
+        * messages. As for now, we just wait and reduce IO.
+        */
+       if (dev->chip_ver == 1) {
+               #define TIMEOUT 50
+               timeout = jiffies + msecs_to_jiffies(TIMEOUT);
+               while (!time_after(jiffies, timeout)) {
+                       ret = regmap_read(dev->regmap, 0x80ec82, &utmp);
+                       if (ret)
+                               goto err;
+
+                       if (utmp)
+                               break;
+               }
+
+               dev_dbg(&dev->client->dev, "p_tsm_init_mode took %u ms, val %u\n",
+                               jiffies_to_msecs(jiffies) -
+                               (jiffies_to_msecs(timeout) - TIMEOUT), utmp);
+       } else {
+               msleep(50);
+       }
+
+       ret = regmap_write(dev->regmap, 0x80ed81, iqik_m_cal);
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80ec57, 0x00);
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80ec58, 0x00);
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80ec40, 0x01);
+       if (ret)
+               goto err;
+
+       dev->active = true;
+
+       return 0;
+err:
+       dev_dbg(&dev->client->dev, "failed %d\n", ret);
+       return ret;
+}
+
+static int it913x_sleep(struct dvb_frontend *fe)
+{
+       struct it913x_dev *dev = fe->tuner_priv;
+       int ret, len;
+
+       dev_dbg(&dev->client->dev, "role %u\n", dev->role);
+
+       dev->active = false;
+
+       ret  = regmap_bulk_write(dev->regmap, 0x80ec40, "\x00", 1);
+       if (ret)
+               goto err;
+
+       /*
+        * Writing '0x00' to master tuner register '0x80ec08' causes slave tuner
+        * communication lost. Due to that, we cannot put master full sleep.
+        */
+       if (dev->role == IT913X_ROLE_DUAL_MASTER)
+               len = 4;
+       else
+               len = 15;
+
+       dev_dbg(&dev->client->dev, "role %u, len %d\n", dev->role, len);
+
+       ret = regmap_bulk_write(dev->regmap, 0x80ec02,
+                       "\x3f\x1f\x3f\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+                       len);
+       if (ret)
+               goto err;
+
+       ret = regmap_bulk_write(dev->regmap, 0x80ec12, "\x00\x00\x00\x00", 4);
+       if (ret)
+               goto err;
+
+       ret = regmap_bulk_write(dev->regmap, 0x80ec17,
+                       "\x00\x00\x00\x00\x00\x00\x00\x00\x00", 9);
+       if (ret)
+               goto err;
+
+       ret = regmap_bulk_write(dev->regmap, 0x80ec22,
+                       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 10);
+       if (ret)
+               goto err;
+
+       ret = regmap_bulk_write(dev->regmap, 0x80ec20, "\x00", 1);
+       if (ret)
+               goto err;
+
+       ret = regmap_bulk_write(dev->regmap, 0x80ec3f, "\x01", 1);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dev_dbg(&dev->client->dev, "failed %d\n", ret);
+       return ret;
+}
+
+static int it913x_set_params(struct dvb_frontend *fe)
+{
+       struct it913x_dev *dev = fe->tuner_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret;
+       unsigned int utmp;
+       u32 pre_lo_freq, t_cal_freq;
+       u16 iqik_m_cal, n_div;
+       u8 u8tmp, n, l_band, lna_band;
+
+       dev_dbg(&dev->client->dev, "role=%u, frequency %u, bandwidth_hz %u\n",
+                       dev->role, c->frequency, c->bandwidth_hz);
+
+       if (!dev->active) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       if (c->frequency <=         74000000) {
+               n_div = 48;
+               n = 0;
+       } else if (c->frequency <= 111000000) {
+               n_div = 32;
+               n = 1;
+       } else if (c->frequency <= 148000000) {
+               n_div = 24;
+               n = 2;
+       } else if (c->frequency <= 222000000) {
+               n_div = 16;
+               n = 3;
+       } else if (c->frequency <= 296000000) {
+               n_div = 12;
+               n = 4;
+       } else if (c->frequency <= 445000000) {
+               n_div = 8;
+               n = 5;
+       } else if (c->frequency <= dev->fn_min) {
+               n_div = 6;
+               n = 6;
+       } else if (c->frequency <= 950000000) {
+               n_div = 4;
+               n = 7;
+       } else {
+               n_div = 2;
+               n = 0;
+       }
+
+       ret = regmap_read(dev->regmap, 0x80ed81, &utmp);
+       if (ret)
+               goto err;
+
+       iqik_m_cal = utmp * n_div;
+
+       if (utmp < 0x20) {
+               if (dev->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 (dev->clk_mode == 0)
+                       iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
+               else
+                       iqik_m_cal = ~(iqik_m_cal >> 1);
+       }
+
+       t_cal_freq = (c->frequency / 1000) * n_div * dev->fdiv;
+       pre_lo_freq = t_cal_freq / dev->xtal;
+       utmp = pre_lo_freq * dev->xtal;
+
+       if ((t_cal_freq - utmp) >= (dev->xtal >> 1))
+               pre_lo_freq++;
+
+       pre_lo_freq += (u32) n << 13;
+       /* Frequency OMEGA_IQIK_M_CAL_MID*/
+       t_cal_freq = pre_lo_freq + (u32)iqik_m_cal;
+       dev_dbg(&dev->client->dev, "t_cal_freq %u, pre_lo_freq %u\n",
+                       t_cal_freq, pre_lo_freq);
+
+       if (c->frequency <=         440000000) {
+               l_band = 0;
+               lna_band = 0;
+       } else if (c->frequency <=  484000000) {
+               l_band = 1;
+               lna_band = 1;
+       } else if (c->frequency <=  533000000) {
+               l_band = 1;
+               lna_band = 2;
+       } else if (c->frequency <=  587000000) {
+               l_band = 1;
+               lna_band = 3;
+       } else if (c->frequency <=  645000000) {
+               l_band = 1;
+               lna_band = 4;
+       } else if (c->frequency <=  710000000) {
+               l_band = 1;
+               lna_band = 5;
+       } else if (c->frequency <=  782000000) {
+               l_band = 1;
+               lna_band = 6;
+       } else if (c->frequency <=  860000000) {
+               l_band = 1;
+               lna_band = 7;
+       } else if (c->frequency <= 1492000000) {
+               l_band = 1;
+               lna_band = 0;
+       } else if (c->frequency <= 1685000000) {
+               l_band = 1;
+               lna_band = 1;
+       } else {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* XXX: latest windows driver does not set that at all */
+       ret = regmap_write(dev->regmap, 0x80ee06, lna_band);
+       if (ret)
+               goto err;
+
+       if (c->bandwidth_hz <=      5000000)
+               u8tmp = 0;
+       else if (c->bandwidth_hz <= 6000000)
+               u8tmp = 2;
+       else if (c->bandwidth_hz <= 7000000)
+               u8tmp = 4;
+       else
+               u8tmp = 6;       /* 8000000 */
+
+       ret = regmap_write(dev->regmap, 0x80ec56, u8tmp);
+       if (ret)
+               goto err;
+
+       /* XXX: latest windows driver sets different value (a8 != 68) */
+       ret = regmap_write(dev->regmap, 0x80ec4c, 0xa0 | (l_band << 3));
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80ec4d, (t_cal_freq >> 0) & 0xff);
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80ec4e, (t_cal_freq >> 8) & 0xff);
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80011e, (pre_lo_freq >> 0) & 0xff);
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80011f, (pre_lo_freq >> 8) & 0xff);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dev_dbg(&dev->client->dev, "failed %d\n", ret);
+       return ret;
+}
+
+static const struct dvb_tuner_ops it913x_tuner_ops = {
+       .info = {
+               .name           = "ITE IT913X",
+               .frequency_min  = 174000000,
+               .frequency_max  = 862000000,
+       },
+
+       .init = it913x_init,
+       .sleep = it913x_sleep,
+       .set_params = it913x_set_params,
+};
+
+static int it913x_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct it913x_config *cfg = client->dev.platform_data;
+       struct dvb_frontend *fe = cfg->fe;
+       struct it913x_dev *dev;
+       int ret;
+       char *chip_ver_str;
+       static const struct regmap_config regmap_config = {
+               .reg_bits = 24,
+               .val_bits = 8,
+       };
+
+       dev = kzalloc(sizeof(struct it913x_dev), GFP_KERNEL);
+       if (dev == NULL) {
+               ret = -ENOMEM;
+               dev_err(&client->dev, "kzalloc() failed\n");
+               goto err;
+       }
+
+       dev->client = client;
+       dev->fe = cfg->fe;
+       dev->chip_ver = cfg->chip_ver;
+       dev->role = cfg->role;
+       dev->regmap = regmap_init_i2c(client, &regmap_config);
+       if (IS_ERR(dev->regmap)) {
+               ret = PTR_ERR(dev->regmap);
+               goto err_kfree;
+       }
+
+       fe->tuner_priv = dev;
+       memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops,
+                       sizeof(struct dvb_tuner_ops));
+       i2c_set_clientdata(client, dev);
+
+       if (dev->chip_ver == 1)
+               chip_ver_str = "AX";
+       else if (dev->chip_ver == 2)
+               chip_ver_str = "BX";
+       else
+               chip_ver_str = "??";
+
+       dev_info(&dev->client->dev, "ITE IT913X %s successfully attached\n",
+                       chip_ver_str);
+       dev_dbg(&dev->client->dev, "chip_ver %u, role %u\n",
+                       dev->chip_ver, dev->role);
+       return 0;
+
+err_kfree:
+       kfree(dev);
+err:
+       dev_dbg(&client->dev, "failed %d\n", ret);
+       return ret;
+}
+
+static int it913x_remove(struct i2c_client *client)
+{
+       struct it913x_dev *dev = i2c_get_clientdata(client);
+       struct dvb_frontend *fe = dev->fe;
+
+       dev_dbg(&client->dev, "\n");
+
+       memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
+       fe->tuner_priv = NULL;
+       regmap_exit(dev->regmap);
+       kfree(dev);
+
+       return 0;
+}
+
+static const struct i2c_device_id it913x_id_table[] = {
+       {"it913x", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, it913x_id_table);
+
+static struct i2c_driver it913x_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "it913x",
+       },
+       .probe          = it913x_probe,
+       .remove         = it913x_remove,
+       .id_table       = it913x_id_table,
+};
+
+module_i2c_driver(it913x_driver);
+
+MODULE_DESCRIPTION("ITE IT913X silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/it913x.h b/drivers/media/tuners/it913x.h
new file mode 100644 (file)
index 0000000..33de53d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * ITE Tech IT9137 silicon tuner driver
+ *
+ *  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.=
+ */
+
+#ifndef IT913X_H
+#define IT913X_H
+
+#include "dvb_frontend.h"
+
+/*
+ * I2C address
+ * 0x38, 0x3a, 0x3c, 0x3e
+ */
+struct it913x_config {
+       /*
+        * pointer to DVB frontend
+        */
+       struct dvb_frontend *fe;
+
+       /*
+        * chip version
+        * 1 = IT9135 AX
+        * 2 = IT9135 BX
+        */
+       unsigned int chip_ver:2;
+
+       /*
+        * tuner role
+        */
+#define IT913X_ROLE_SINGLE         0
+#define IT913X_ROLE_DUAL_MASTER    1
+#define IT913X_ROLE_DUAL_SLAVE     2
+       unsigned int role:2;
+};
+
+#endif
index 40c42dec721b9de556dacc6cadc12a80ba3cc06b..caa542346891f630074ec26d1aa11d046f85e261 100644 (file)
 
 #include "m88ts2022_priv.h"
 
-/* write multiple registers */
-static int m88ts2022_wr_regs(struct m88ts2022_priv *priv,
-               u8 reg, const u8 *val, int len)
+static int m88ts2022_cmd(struct m88ts2022_dev *dev, int op, int sleep, u8 reg,
+               u8 mask, u8 val, u8 *reg_val)
 {
-#define MAX_WR_LEN 3
-#define MAX_WR_XFER_LEN (MAX_WR_LEN + 1)
-       int ret;
-       u8 buf[MAX_WR_XFER_LEN];
-       struct i2c_msg msg[1] = {
-               {
-                       .addr = priv->client->addr,
-                       .flags = 0,
-                       .len = 1 + len,
-                       .buf = buf,
-               }
-       };
-
-       if (WARN_ON(len > MAX_WR_LEN))
-               return -EINVAL;
-
-       buf[0] = reg;
-       memcpy(&buf[1], val, len);
-
-       ret = i2c_transfer(priv->client->adapter, msg, 1);
-       if (ret == 1) {
-               ret = 0;
-       } else {
-               dev_warn(&priv->client->dev,
-                               "%s: i2c wr failed=%d reg=%02x len=%d\n",
-                               KBUILD_MODNAME, ret, reg, len);
-               ret = -EREMOTEIO;
-       }
-
-       return ret;
-}
-
-/* read multiple registers */
-static int m88ts2022_rd_regs(struct m88ts2022_priv *priv, u8 reg,
-               u8 *val, int len)
-{
-#define MAX_RD_LEN 1
-#define MAX_RD_XFER_LEN (MAX_RD_LEN)
-       int ret;
-       u8 buf[MAX_RD_XFER_LEN];
-       struct i2c_msg msg[2] = {
-               {
-                       .addr = priv->client->addr,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = &reg,
-               }, {
-                       .addr = priv->client->addr,
-                       .flags = I2C_M_RD,
-                       .len = len,
-                       .buf = buf,
-               }
-       };
-
-       if (WARN_ON(len > MAX_RD_LEN))
-               return -EINVAL;
-
-       ret = i2c_transfer(priv->client->adapter, msg, 2);
-       if (ret == 2) {
-               memcpy(val, buf, len);
-               ret = 0;
-       } else {
-               dev_warn(&priv->client->dev,
-                               "%s: i2c rd failed=%d reg=%02x len=%d\n",
-                               KBUILD_MODNAME, ret, reg, len);
-               ret = -EREMOTEIO;
-       }
-
-       return ret;
-}
-
-/* write single register */
-static int m88ts2022_wr_reg(struct m88ts2022_priv *priv, u8 reg, u8 val)
-{
-       return m88ts2022_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int m88ts2022_rd_reg(struct m88ts2022_priv *priv, u8 reg, u8 *val)
-{
-       return m88ts2022_rd_regs(priv, reg, val, 1);
-}
-
-/* write single register with mask */
-static int m88ts2022_wr_reg_mask(struct m88ts2022_priv *priv,
-               u8 reg, u8 val, u8 mask)
-{
-       int ret;
-       u8 u8tmp;
-
-       /* no need for read if whole reg is written */
-       if (mask != 0xff) {
-               ret = m88ts2022_rd_regs(priv, reg, &u8tmp, 1);
-               if (ret)
-                       return ret;
-
-               val &= mask;
-               u8tmp &= ~mask;
-               val |= u8tmp;
-       }
-
-       return m88ts2022_wr_regs(priv, reg, &val, 1);
-}
-
-static int m88ts2022_cmd(struct dvb_frontend *fe,
-               int op, int sleep, u8 reg, u8 mask, u8 val, u8 *reg_val)
-{
-       struct m88ts2022_priv *priv = fe->tuner_priv;
        int ret, i;
-       u8 u8tmp;
+       unsigned int utmp;
        struct m88ts2022_reg_val reg_vals[] = {
                {0x51, 0x1f - op},
                {0x51, 0x1f},
@@ -140,12 +31,12 @@ static int m88ts2022_cmd(struct dvb_frontend *fe,
        };
 
        for (i = 0; i < 2; i++) {
-               dev_dbg(&priv->client->dev,
-                               "%s: i=%d op=%02x reg=%02x mask=%02x val=%02x\n",
-                               __func__, i, op, reg, mask, val);
+               dev_dbg(&dev->client->dev,
+                               "i=%d op=%02x reg=%02x mask=%02x val=%02x\n",
+                               i, op, reg, mask, val);
 
                for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
-                       ret = m88ts2022_wr_reg(priv, reg_vals[i].reg,
+                       ret = regmap_write(dev->regmap, reg_vals[i].reg,
                                        reg_vals[i].val);
                        if (ret)
                                goto err;
@@ -153,37 +44,38 @@ static int m88ts2022_cmd(struct dvb_frontend *fe,
 
                usleep_range(sleep * 1000, sleep * 10000);
 
-               ret = m88ts2022_rd_reg(priv, reg, &u8tmp);
+               ret = regmap_read(dev->regmap, reg, &utmp);
                if (ret)
                        goto err;
 
-               if ((u8tmp & mask) != val)
+               if ((utmp & mask) != val)
                        break;
        }
 
        if (reg_val)
-               *reg_val = u8tmp;
+               *reg_val = utmp;
 err:
        return ret;
 }
 
 static int m88ts2022_set_params(struct dvb_frontend *fe)
 {
-       struct m88ts2022_priv *priv = fe->tuner_priv;
+       struct m88ts2022_dev *dev = fe->tuner_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret;
-       unsigned int frequency_khz, frequency_offset_khz, f_3db_hz;
+       unsigned int utmp, frequency_khz, frequency_offset_khz, f_3db_hz;
        unsigned int f_ref_khz, f_vco_khz, div_ref, div_out, pll_n, gdiv28;
        u8 buf[3], u8tmp, cap_code, lpf_gm, lpf_mxdiv, div_max, div_min;
        u16 u16tmp;
-       dev_dbg(&priv->client->dev,
-                       "%s: frequency=%d symbol_rate=%d rolloff=%d\n",
-                       __func__, c->frequency, c->symbol_rate, c->rolloff);
+
+       dev_dbg(&dev->client->dev,
+                       "frequency=%d symbol_rate=%d rolloff=%d\n",
+                       c->frequency, c->symbol_rate, c->rolloff);
        /*
         * Integer-N PLL synthesizer
         * kHz is used for all calculations to keep calculations within 32-bit
         */
-       f_ref_khz = DIV_ROUND_CLOSEST(priv->cfg.clock, 1000);
+       f_ref_khz = DIV_ROUND_CLOSEST(dev->cfg.clock, 1000);
        div_ref = DIV_ROUND_CLOSEST(f_ref_khz, 2000);
 
        if (c->symbol_rate < 5000000)
@@ -203,14 +95,14 @@ static int m88ts2022_set_params(struct dvb_frontend *fe)
 
        buf[0] = u8tmp;
        buf[1] = 0x40;
-       ret = m88ts2022_wr_regs(priv, 0x10, buf, 2);
+       ret = regmap_bulk_write(dev->regmap, 0x10, buf, 2);
        if (ret)
                goto err;
 
        f_vco_khz = frequency_khz * div_out;
        pll_n = f_vco_khz * div_ref / f_ref_khz;
        pll_n += pll_n % 2;
-       priv->frequency_khz = pll_n * f_ref_khz / div_ref / div_out;
+       dev->frequency_khz = pll_n * f_ref_khz / div_ref / div_out;
 
        if (pll_n < 4095)
                u16tmp = pll_n - 1024;
@@ -222,88 +114,87 @@ static int m88ts2022_set_params(struct dvb_frontend *fe)
        buf[0] = (u16tmp >> 8) & 0x3f;
        buf[1] = (u16tmp >> 0) & 0xff;
        buf[2] = div_ref - 8;
-       ret = m88ts2022_wr_regs(priv, 0x01, buf, 3);
+       ret = regmap_bulk_write(dev->regmap, 0x01, buf, 3);
        if (ret)
                goto err;
 
-       dev_dbg(&priv->client->dev,
-                       "%s: frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n",
-                       __func__, priv->frequency_khz,
-                       priv->frequency_khz - c->frequency, f_vco_khz, pll_n,
-                       div_ref, div_out);
+       dev_dbg(&dev->client->dev,
+                       "frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n",
+                       dev->frequency_khz, dev->frequency_khz - c->frequency,
+                       f_vco_khz, pll_n, div_ref, div_out);
 
-       ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL);
+       ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL);
        if (ret)
                goto err;
 
-       ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp);
+       ret = regmap_read(dev->regmap, 0x14, &utmp);
        if (ret)
                goto err;
 
-       u8tmp &= 0x7f;
-       if (u8tmp < 64) {
-               ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x80, 0x80);
+       utmp &= 0x7f;
+       if (utmp < 64) {
+               ret = regmap_update_bits(dev->regmap, 0x10, 0x80, 0x80);
                if (ret)
                        goto err;
 
-               ret = m88ts2022_wr_reg(priv, 0x11, 0x6f);
+               ret = regmap_write(dev->regmap, 0x11, 0x6f);
                if (ret)
                        goto err;
 
-               ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL);
+               ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL);
                if (ret)
                        goto err;
        }
 
-       ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp);
+       ret = regmap_read(dev->regmap, 0x14, &utmp);
        if (ret)
                goto err;
 
-       u8tmp &= 0x1f;
-       if (u8tmp > 19) {
-               ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x00, 0x02);
+       utmp &= 0x1f;
+       if (utmp > 19) {
+               ret = regmap_update_bits(dev->regmap, 0x10, 0x02, 0x00);
                if (ret)
                        goto err;
        }
 
-       ret = m88ts2022_cmd(fe, 0x08, 5, 0x3c, 0xff, 0x00, NULL);
+       ret = m88ts2022_cmd(dev, 0x08, 5, 0x3c, 0xff, 0x00, NULL);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x25, 0x00);
+       ret = regmap_write(dev->regmap, 0x25, 0x00);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x27, 0x70);
+       ret = regmap_write(dev->regmap, 0x27, 0x70);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x41, 0x09);
+       ret = regmap_write(dev->regmap, 0x41, 0x09);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x08, 0x0b);
+       ret = regmap_write(dev->regmap, 0x08, 0x0b);
        if (ret)
                goto err;
 
        /* filters */
        gdiv28 = DIV_ROUND_CLOSEST(f_ref_khz * 1694U, 1000000U);
 
-       ret = m88ts2022_wr_reg(priv, 0x04, gdiv28);
+       ret = regmap_write(dev->regmap, 0x04, gdiv28);
        if (ret)
                goto err;
 
-       ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+       ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
        if (ret)
                goto err;
 
        cap_code = u8tmp & 0x3f;
 
-       ret = m88ts2022_wr_reg(priv, 0x41, 0x0d);
+       ret = regmap_write(dev->regmap, 0x41, 0x0d);
        if (ret)
                goto err;
 
-       ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+       ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
        if (ret)
                goto err;
 
@@ -314,7 +205,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe)
        div_min = gdiv28 * 78 / 100;
        div_max = clamp_val(div_max, 0U, 63U);
 
-       f_3db_hz = c->symbol_rate * 135UL / 200UL;
+       f_3db_hz = mult_frac(c->symbol_rate, 135, 200);
        f_3db_hz +=  2000000U + (frequency_offset_khz * 1000U);
        f_3db_hz = clamp(f_3db_hz, 7000000U, 40000000U);
 
@@ -327,25 +218,25 @@ static int m88ts2022_set_params(struct dvb_frontend *fe)
                lpf_mxdiv = DIV_ROUND_CLOSEST(++lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz);
        lpf_mxdiv = clamp_val(lpf_mxdiv, 0U, div_max);
 
-       ret = m88ts2022_wr_reg(priv, 0x04, lpf_mxdiv);
+       ret = regmap_write(dev->regmap, 0x04, lpf_mxdiv);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x06, lpf_gm);
+       ret = regmap_write(dev->regmap, 0x06, lpf_gm);
        if (ret)
                goto err;
 
-       ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+       ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
        if (ret)
                goto err;
 
        cap_code = u8tmp & 0x3f;
 
-       ret = m88ts2022_wr_reg(priv, 0x41, 0x09);
+       ret = regmap_write(dev->regmap, 0x41, 0x09);
        if (ret)
                goto err;
 
-       ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+       ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
        if (ret)
                goto err;
 
@@ -353,31 +244,31 @@ static int m88ts2022_set_params(struct dvb_frontend *fe)
        cap_code = (cap_code + u8tmp) / 2;
 
        u8tmp = cap_code | 0x80;
-       ret = m88ts2022_wr_reg(priv, 0x25, u8tmp);
+       ret = regmap_write(dev->regmap, 0x25, u8tmp);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x27, 0x30);
+       ret = regmap_write(dev->regmap, 0x27, 0x30);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x08, 0x09);
+       ret = regmap_write(dev->regmap, 0x08, 0x09);
        if (ret)
                goto err;
 
-       ret = m88ts2022_cmd(fe, 0x01, 20, 0x21, 0xff, 0x00, NULL);
+       ret = m88ts2022_cmd(dev, 0x01, 20, 0x21, 0xff, 0x00, NULL);
        if (ret)
                goto err;
 err:
        if (ret)
-               dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int m88ts2022_init(struct dvb_frontend *fe)
 {
-       struct m88ts2022_priv *priv = fe->tuner_priv;
+       struct m88ts2022_dev *dev = fe->tuner_priv;
        int ret, i;
        u8 u8tmp;
        static const struct m88ts2022_reg_val reg_vals[] = {
@@ -393,23 +284,24 @@ static int m88ts2022_init(struct dvb_frontend *fe)
                {0x24, 0x02},
                {0x12, 0xa0},
        };
-       dev_dbg(&priv->client->dev, "%s:\n", __func__);
 
-       ret = m88ts2022_wr_reg(priv, 0x00, 0x01);
+       dev_dbg(&dev->client->dev, "\n");
+
+       ret = regmap_write(dev->regmap, 0x00, 0x01);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x00, 0x03);
+       ret = regmap_write(dev->regmap, 0x00, 0x03);
        if (ret)
                goto err;
 
-       switch (priv->cfg.clock_out) {
+       switch (dev->cfg.clock_out) {
        case M88TS2022_CLOCK_OUT_DISABLED:
                u8tmp = 0x60;
                break;
        case M88TS2022_CLOCK_OUT_ENABLED:
                u8tmp = 0x70;
-               ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg.clock_out_div);
+               ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div);
                if (ret)
                        goto err;
                break;
@@ -420,58 +312,61 @@ static int m88ts2022_init(struct dvb_frontend *fe)
                goto err;
        }
 
-       ret = m88ts2022_wr_reg(priv, 0x42, u8tmp);
+       ret = regmap_write(dev->regmap, 0x42, u8tmp);
        if (ret)
                goto err;
 
-       if (priv->cfg.loop_through)
+       if (dev->cfg.loop_through)
                u8tmp = 0xec;
        else
                u8tmp = 0x6c;
 
-       ret = m88ts2022_wr_reg(priv, 0x62, u8tmp);
+       ret = regmap_write(dev->regmap, 0x62, u8tmp);
        if (ret)
                goto err;
 
        for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
-               ret = m88ts2022_wr_reg(priv, reg_vals[i].reg, reg_vals[i].val);
+               ret = regmap_write(dev->regmap, reg_vals[i].reg, reg_vals[i].val);
                if (ret)
                        goto err;
        }
 err:
        if (ret)
-               dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&dev->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static int m88ts2022_sleep(struct dvb_frontend *fe)
 {
-       struct m88ts2022_priv *priv = fe->tuner_priv;
+       struct m88ts2022_dev *dev = fe->tuner_priv;
        int ret;
-       dev_dbg(&priv->client->dev, "%s:\n", __func__);
 
-       ret = m88ts2022_wr_reg(priv, 0x00, 0x00);
+       dev_dbg(&dev->client->dev, "\n");
+
+       ret = regmap_write(dev->regmap, 0x00, 0x00);
        if (ret)
                goto err;
 err:
        if (ret)
-               dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&dev->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static int m88ts2022_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-       struct m88ts2022_priv *priv = fe->tuner_priv;
-       dev_dbg(&priv->client->dev, "%s:\n", __func__);
+       struct m88ts2022_dev *dev = fe->tuner_priv;
 
-       *frequency = priv->frequency_khz;
+       dev_dbg(&dev->client->dev, "\n");
+
+       *frequency = dev->frequency_khz;
        return 0;
 }
 
 static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-       struct m88ts2022_priv *priv = fe->tuner_priv;
-       dev_dbg(&priv->client->dev, "%s:\n", __func__);
+       struct m88ts2022_dev *dev = fe->tuner_priv;
+
+       dev_dbg(&dev->client->dev, "\n");
 
        *frequency = 0; /* Zero-IF */
        return 0;
@@ -479,31 +374,30 @@ static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 
 static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
 {
-       struct m88ts2022_priv *priv = fe->tuner_priv;
+       struct m88ts2022_dev *dev = fe->tuner_priv;
        int ret;
-       u8 u8tmp;
        u16 gain, u16tmp;
-       unsigned int gain1, gain2, gain3;
+       unsigned int utmp, gain1, gain2, gain3;
 
-       ret = m88ts2022_rd_reg(priv, 0x3d, &u8tmp);
+       ret = regmap_read(dev->regmap, 0x3d, &utmp);
        if (ret)
                goto err;
 
-       gain1 = (u8tmp >> 0) & 0x1f;
+       gain1 = (utmp >> 0) & 0x1f;
        gain1 = clamp(gain1, 0U, 15U);
 
-       ret = m88ts2022_rd_reg(priv, 0x21, &u8tmp);
+       ret = regmap_read(dev->regmap, 0x21, &utmp);
        if (ret)
                goto err;
 
-       gain2 = (u8tmp >> 0) & 0x1f;
+       gain2 = (utmp >> 0) & 0x1f;
        gain2 = clamp(gain2, 2U, 16U);
 
-       ret = m88ts2022_rd_reg(priv, 0x66, &u8tmp);
+       ret = regmap_read(dev->regmap, 0x66, &utmp);
        if (ret)
                goto err;
 
-       gain3 = (u8tmp >> 3) & 0x07;
+       gain3 = (utmp >> 3) & 0x07;
        gain3 = clamp(gain3, 0U, 6U);
 
        gain = gain1 * 265 + gain2 * 338 + gain3 * 285;
@@ -515,7 +409,7 @@ static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
        *strength = (u16tmp - 59000) * 0xffff / (61500 - 59000);
 err:
        if (ret)
-               dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&dev->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -540,46 +434,56 @@ static int m88ts2022_probe(struct i2c_client *client,
 {
        struct m88ts2022_config *cfg = client->dev.platform_data;
        struct dvb_frontend *fe = cfg->fe;
-       struct m88ts2022_priv *priv;
+       struct m88ts2022_dev *dev;
        int ret;
-       u8 chip_id, u8tmp;
+       u8 u8tmp;
+       unsigned int utmp;
+       static const struct regmap_config regmap_config = {
+               .reg_bits = 8,
+               .val_bits = 8,
+       };
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
                ret = -ENOMEM;
-               dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+               dev_err(&client->dev, "kzalloc() failed\n");
                goto err;
        }
 
-       memcpy(&priv->cfg, cfg, sizeof(struct m88ts2022_config));
-       priv->client = client;
+       memcpy(&dev->cfg, cfg, sizeof(struct m88ts2022_config));
+       dev->client = client;
+       dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
+       if (IS_ERR(dev->regmap)) {
+               ret = PTR_ERR(dev->regmap);
+               goto err;
+       }
 
        /* check if the tuner is there */
-       ret = m88ts2022_rd_reg(priv, 0x00, &u8tmp);
+       ret = regmap_read(dev->regmap, 0x00, &utmp);
        if (ret)
                goto err;
 
-       if ((u8tmp & 0x03) == 0x00) {
-               ret = m88ts2022_wr_reg(priv, 0x00, 0x01);
-               if (ret < 0)
+       if ((utmp & 0x03) == 0x00) {
+               ret = regmap_write(dev->regmap, 0x00, 0x01);
+               if (ret)
                        goto err;
 
                usleep_range(2000, 50000);
        }
 
-       ret = m88ts2022_wr_reg(priv, 0x00, 0x03);
+       ret = regmap_write(dev->regmap, 0x00, 0x03);
        if (ret)
                goto err;
 
        usleep_range(2000, 50000);
 
-       ret = m88ts2022_rd_reg(priv, 0x00, &chip_id);
+       ret = regmap_read(dev->regmap, 0x00, &utmp);
        if (ret)
                goto err;
 
-       dev_dbg(&priv->client->dev, "%s: chip_id=%02x\n", __func__, chip_id);
+       dev_dbg(&dev->client->dev, "chip_id=%02x\n", utmp);
 
-       switch (chip_id) {
+       switch (utmp) {
        case 0xc3:
        case 0x83:
                break;
@@ -587,13 +491,13 @@ static int m88ts2022_probe(struct i2c_client *client,
                goto err;
        }
 
-       switch (priv->cfg.clock_out) {
+       switch (dev->cfg.clock_out) {
        case M88TS2022_CLOCK_OUT_DISABLED:
                u8tmp = 0x60;
                break;
        case M88TS2022_CLOCK_OUT_ENABLED:
                u8tmp = 0x70;
-               ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg.clock_out_div);
+               ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div);
                if (ret)
                        goto err;
                break;
@@ -604,49 +508,48 @@ static int m88ts2022_probe(struct i2c_client *client,
                goto err;
        }
 
-       ret = m88ts2022_wr_reg(priv, 0x42, u8tmp);
+       ret = regmap_write(dev->regmap, 0x42, u8tmp);
        if (ret)
                goto err;
 
-       if (priv->cfg.loop_through)
+       if (dev->cfg.loop_through)
                u8tmp = 0xec;
        else
                u8tmp = 0x6c;
 
-       ret = m88ts2022_wr_reg(priv, 0x62, u8tmp);
+       ret = regmap_write(dev->regmap, 0x62, u8tmp);
        if (ret)
                goto err;
 
        /* sleep */
-       ret = m88ts2022_wr_reg(priv, 0x00, 0x00);
+       ret = regmap_write(dev->regmap, 0x00, 0x00);
        if (ret)
                goto err;
 
-       dev_info(&priv->client->dev,
-                       "%s: Montage M88TS2022 successfully identified\n",
-                       KBUILD_MODNAME);
+       dev_info(&dev->client->dev, "Montage M88TS2022 successfully identified\n");
 
-       fe->tuner_priv = priv;
+       fe->tuner_priv = dev;
        memcpy(&fe->ops.tuner_ops, &m88ts2022_tuner_ops,
                        sizeof(struct dvb_tuner_ops));
 
-       i2c_set_clientdata(client, priv);
+       i2c_set_clientdata(client, dev);
        return 0;
 err:
-       dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
-       kfree(priv);
+       dev_dbg(&client->dev, "failed=%d\n", ret);
+       kfree(dev);
        return ret;
 }
 
 static int m88ts2022_remove(struct i2c_client *client)
 {
-       struct m88ts2022_priv *priv = i2c_get_clientdata(client);
-       struct dvb_frontend *fe = priv->cfg.fe;
-       dev_dbg(&client->dev, "%s:\n", __func__);
+       struct m88ts2022_dev *dev = i2c_get_clientdata(client);
+       struct dvb_frontend *fe = dev->cfg.fe;
+
+       dev_dbg(&client->dev, "\n");
 
        memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
        fe->tuner_priv = NULL;
-       kfree(priv);
+       kfree(dev);
 
        return 0;
 }
index 0363dd866a2dab01ba9a19c2e7d4a85d59e53a99..feeb5ad6beef879c357612e708cc6c8e265c7f75 100644 (file)
 #define M88TS2022_PRIV_H
 
 #include "m88ts2022.h"
+#include <linux/regmap.h>
 
-struct m88ts2022_priv {
+struct m88ts2022_dev {
        struct m88ts2022_config cfg;
        struct i2c_client *client;
-       struct dvb_frontend *fe;
+       struct regmap *regmap;
        u32 frequency_khz;
 };
 
index ee99e372c943455a9aec8439dc3cab06c848867c..26019e73199314b779e788bfd6a57905c9c68457 100644 (file)
@@ -67,7 +67,8 @@ static int msi001_set_gain(struct msi001 *s, int lna_gain, int mixer_gain,
 {
        int ret;
        u32 reg;
-       dev_dbg(&s->spi->dev, "%s: lna=%d mixer=%d if=%d\n", __func__,
+
+       dev_dbg(&s->spi->dev, "lna=%d mixer=%d if=%d\n",
                        lna_gain, mixer_gain, if_gain);
 
        reg = 1 << 0;
@@ -83,7 +84,7 @@ static int msi001_set_gain(struct msi001 *s, int lna_gain, int mixer_gain,
 
        return 0;
 err:
-       dev_dbg(&s->spi->dev, "%s: failed %d\n", __func__, ret);
+       dev_dbg(&s->spi->dev, "failed %d\n", ret);
        return ret;
 };
 
@@ -94,6 +95,7 @@ static int msi001_set_tuner(struct msi001 *s)
        u32 reg;
        u64 f_vco, tmp64;
        u8 mode, filter_mode, lo_div;
+
        static const struct {
                u32 rf;
                u8 mode;
@@ -145,9 +147,7 @@ static int msi001_set_tuner(struct msi001 *s)
        #define R_REF 4
        #define F_OUT_STEP 1
 
-       dev_dbg(&s->spi->dev,
-                       "%s: f_rf=%d f_if=%d\n",
-                       __func__, f_rf, f_if);
+       dev_dbg(&s->spi->dev, "f_rf=%d f_if=%d\n", f_rf, f_if);
 
        for (i = 0; i < ARRAY_SIZE(band_lut); i++) {
                if (f_rf <= band_lut[i].rf) {
@@ -198,8 +198,7 @@ static int msi001_set_tuner(struct msi001 *s)
 
        s->bandwidth->val = bandwidth_lut[i].freq;
 
-       dev_dbg(&s->spi->dev, "%s: bandwidth selected=%d\n",
-                       __func__, bandwidth_lut[i].freq);
+       dev_dbg(&s->spi->dev, "bandwidth selected=%d\n", bandwidth_lut[i].freq);
 
        f_vco = (u64) (f_rf + f_if + f_if1) * lo_div;
        tmp64 = f_vco;
@@ -225,9 +224,8 @@ static int msi001_set_tuner(struct msi001 *s)
        tmp += 1ul * F_REF * R_REF * frac / thresh;
        tmp /= lo_div;
 
-       dev_dbg(&s->spi->dev,
-                       "%s: rf=%u:%u n=%d thresh=%d frac=%d\n",
-                               __func__, f_rf, tmp, n, thresh, frac);
+       dev_dbg(&s->spi->dev, "rf=%u:%u n=%d thresh=%d frac=%d\n",
+                               f_rf, tmp, n, thresh, frac);
 
        ret = msi001_wreg(s, 0x00000e);
        if (ret)
@@ -276,7 +274,7 @@ static int msi001_set_tuner(struct msi001 *s)
 
        return 0;
 err:
-       dev_dbg(&s->spi->dev, "%s: failed %d\n", __func__, ret);
+       dev_dbg(&s->spi->dev, "failed %d\n", ret);
        return ret;
 };
 
@@ -284,7 +282,8 @@ static int msi001_s_power(struct v4l2_subdev *sd, int on)
 {
        struct msi001 *s = sd_to_msi001(sd);
        int ret;
-       dev_dbg(&s->spi->dev, "%s: on=%d\n", __func__, on);
+
+       dev_dbg(&s->spi->dev, "on=%d\n", on);
 
        if (on)
                ret = 0;
@@ -301,7 +300,8 @@ static const struct v4l2_subdev_core_ops msi001_core_ops = {
 static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
 {
        struct msi001 *s = sd_to_msi001(sd);
-       dev_dbg(&s->spi->dev, "%s: index=%d\n", __func__, v->index);
+
+       dev_dbg(&s->spi->dev, "index=%d\n", v->index);
 
        strlcpy(v->name, "Mirics MSi001", sizeof(v->name));
        v->type = V4L2_TUNER_RF;
@@ -315,14 +315,16 @@ static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
 static int msi001_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v)
 {
        struct msi001 *s = sd_to_msi001(sd);
-       dev_dbg(&s->spi->dev, "%s: index=%d\n", __func__, v->index);
+
+       dev_dbg(&s->spi->dev, "index=%d\n", v->index);
        return 0;
 }
 
 static int msi001_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
 {
        struct msi001 *s = sd_to_msi001(sd);
-       dev_dbg(&s->spi->dev, "%s: tuner=%d\n", __func__, f->tuner);
+
+       dev_dbg(&s->spi->dev, "tuner=%d\n", f->tuner);
        f->frequency = s->f_tuner;
        return 0;
 }
@@ -332,8 +334,9 @@ static int msi001_s_frequency(struct v4l2_subdev *sd,
 {
        struct msi001 *s = sd_to_msi001(sd);
        unsigned int band;
-       dev_dbg(&s->spi->dev, "%s: tuner=%d type=%d frequency=%u\n",
-                       __func__, f->tuner, f->type, f->frequency);
+
+       dev_dbg(&s->spi->dev, "tuner=%d type=%d frequency=%u\n",
+                       f->tuner, f->type, f->frequency);
 
        if (f->frequency < ((bands[0].rangehigh + bands[1].rangelow) / 2))
                band = 0;
@@ -349,8 +352,9 @@ static int msi001_enum_freq_bands(struct v4l2_subdev *sd,
                struct v4l2_frequency_band *band)
 {
        struct msi001 *s = sd_to_msi001(sd);
-       dev_dbg(&s->spi->dev, "%s: tuner=%d type=%d index=%d\n",
-                       __func__, band->tuner, band->type, band->index);
+
+       dev_dbg(&s->spi->dev, "tuner=%d type=%d index=%d\n",
+                       band->tuner, band->type, band->index);
 
        if (band->index >= ARRAY_SIZE(bands))
                return -EINVAL;
@@ -380,9 +384,10 @@ static int msi001_s_ctrl(struct v4l2_ctrl *ctrl)
        struct msi001 *s = container_of(ctrl->handler, struct msi001, hdl);
 
        int ret;
+
        dev_dbg(&s->spi->dev,
-                       "%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
-                       __func__, ctrl->id, ctrl->name, ctrl->val,
+                       "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
+                       ctrl->id, ctrl->name, ctrl->val,
                        ctrl->minimum, ctrl->maximum, ctrl->step);
 
        switch (ctrl->id) {
@@ -403,8 +408,7 @@ static int msi001_s_ctrl(struct v4l2_ctrl *ctrl)
                                s->mixer_gain->cur.val, s->if_gain->val);
                break;
        default:
-               dev_dbg(&s->spi->dev, "%s: unkown control %d\n",
-                               __func__, ctrl->id);
+               dev_dbg(&s->spi->dev, "unkown control %d\n", ctrl->id);
                ret = -EINVAL;
        }
 
@@ -419,7 +423,8 @@ static int msi001_probe(struct spi_device *spi)
 {
        struct msi001 *s;
        int ret;
-       dev_dbg(&spi->dev, "%s:\n", __func__);
+
+       dev_dbg(&spi->dev, "\n");
 
        s = kzalloc(sizeof(struct msi001), GFP_KERNEL);
        if (s == NULL) {
@@ -466,7 +471,8 @@ static int msi001_remove(struct spi_device *spi)
 {
        struct v4l2_subdev *sd = spi_get_drvdata(spi);
        struct msi001 *s = sd_to_msi001(sd);
-       dev_dbg(&spi->dev, "%s:\n", __func__);
+
+       dev_dbg(&spi->dev, "\n");
 
        /*
         * Registered by v4l2_spi_new_subdev() from master driver, but we must
index 13381de58a843a4b8f4997705bdfc62c40ae34f5..b87b2549d58d6eab5b202dca2abb8645a04a6141 100644 (file)
@@ -157,7 +157,6 @@ static int mt2060_set_params(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct mt2060_priv *priv;
-       int ret=0;
        int i=0;
        u32 freq;
        u8  lnaband;
@@ -240,7 +239,7 @@ static int mt2060_set_params(struct dvb_frontend *fe)
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
 
-       return ret;
+       return 0;
 }
 
 static void mt2060_calibrate(struct mt2060_priv *priv)
index f640dcf4a81d8a7e204bba0a015f126b9d8756bc..9e9c5eb4cb66949a7e84a9789a9829f6f1f913d9 100644 (file)
@@ -1216,7 +1216,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
        if (status >= 0) {
                val =
                    (state->
-                    reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode]
+                    reg[MT2063_REG_PD1_TGT] & ~0x40) | (RFAGCEN[Mode]
                                                                   ? 0x40 :
                                                                   0x00);
                if (state->reg[MT2063_REG_PD1_TGT] != val)
@@ -1225,7 +1225,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* LNARin */
        if (status >= 0) {
-               u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) |
+               u8 val = (state->reg[MT2063_REG_CTRL_2C] & ~0x03) |
                         (LNARIN[Mode] & 0x03);
                if (state->reg[MT2063_REG_CTRL_2C] != val)
                        status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val);
@@ -1235,19 +1235,19 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
        if (status >= 0) {
                val =
                    (state->
-                    reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) |
+                    reg[MT2063_REG_FIFF_CTRL2] & ~0xF0) |
                    (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
                if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
                        status |=
                            mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
                        /* trigger FIFF calibration, needed after changing FIFFQ */
                        val =
-                           (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
+                           (state->reg[MT2063_REG_FIFF_CTRL] | 0x01);
                        status |=
                            mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
                        val =
                            (state->
-                            reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01);
+                            reg[MT2063_REG_FIFF_CTRL] & ~0x01);
                        status |=
                            mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
                }
@@ -1259,7 +1259,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* acLNAmax */
        if (status >= 0) {
-               u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) |
+               u8 val = (state->reg[MT2063_REG_LNA_OV] & ~0x1F) |
                         (ACLNAMAX[Mode] & 0x1F);
                if (state->reg[MT2063_REG_LNA_OV] != val)
                        status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
@@ -1267,7 +1267,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* LNATGT */
        if (status >= 0) {
-               u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) |
+               u8 val = (state->reg[MT2063_REG_LNA_TGT] & ~0x3F) |
                         (LNATGT[Mode] & 0x3F);
                if (state->reg[MT2063_REG_LNA_TGT] != val)
                        status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
@@ -1275,7 +1275,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* ACRF */
        if (status >= 0) {
-               u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) |
+               u8 val = (state->reg[MT2063_REG_RF_OV] & ~0x1F) |
                         (ACRFMAX[Mode] & 0x1F);
                if (state->reg[MT2063_REG_RF_OV] != val)
                        status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
@@ -1283,7 +1283,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* PD1TGT */
        if (status >= 0) {
-               u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) |
+               u8 val = (state->reg[MT2063_REG_PD1_TGT] & ~0x3F) |
                         (PD1TGT[Mode] & 0x3F);
                if (state->reg[MT2063_REG_PD1_TGT] != val)
                        status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
@@ -1294,7 +1294,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
                u8 val = ACFIFMAX[Mode];
                if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
                        val = 5;
-               val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) |
+               val = (state->reg[MT2063_REG_FIF_OV] & ~0x1F) |
                      (val & 0x1F);
                if (state->reg[MT2063_REG_FIF_OV] != val)
                        status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
@@ -1302,7 +1302,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* PD2TGT */
        if (status >= 0) {
-               u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) |
+               u8 val = (state->reg[MT2063_REG_PD2_TGT] & ~0x3F) |
                    (PD2TGT[Mode] & 0x3F);
                if (state->reg[MT2063_REG_PD2_TGT] != val)
                        status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
@@ -1310,7 +1310,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* Ignore ATN Overload */
        if (status >= 0) {
-               val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) |
+               val = (state->reg[MT2063_REG_LNA_TGT] & ~0x80) |
                      (RFOVDIS[Mode] ? 0x80 : 0x00);
                if (state->reg[MT2063_REG_LNA_TGT] != val)
                        status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
@@ -1318,7 +1318,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* Ignore FIF Overload */
        if (status >= 0) {
-               val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) |
+               val = (state->reg[MT2063_REG_PD1_TGT] & ~0x80) |
                      (FIFOVDIS[Mode] ? 0x80 : 0x00);
                if (state->reg[MT2063_REG_PD1_TGT] != val)
                        status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
diff --git a/drivers/media/tuners/mxl301rf.c b/drivers/media/tuners/mxl301rf.c
new file mode 100644 (file)
index 0000000..1575a5d
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * MaxLinear MxL301RF OFDM tuner driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@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.
+ */
+
+/*
+ * NOTICE:
+ * This driver is incomplete and lacks init/config of the chips,
+ * as the necessary info is not disclosed.
+ * Other features like get_if_frequency() are missing as well.
+ * It assumes that users of this driver (such as a PCI bridge of
+ * DTV receiver cards) properly init and configure the chip
+ * via I2C *before* calling this driver's init() function.
+ *
+ * Currently, PT3 driver is the only one that uses this driver,
+ * and contains init/config code in its firmware.
+ * Thus some part of the code might be dependent on PT3 specific config.
+ */
+
+#include <linux/kernel.h>
+#include "mxl301rf.h"
+
+struct mxl301rf_state {
+       struct mxl301rf_config cfg;
+       struct i2c_client *i2c;
+};
+
+static struct mxl301rf_state *cfg_to_state(struct mxl301rf_config *c)
+{
+       return container_of(c, struct mxl301rf_state, cfg);
+}
+
+static int raw_write(struct mxl301rf_state *state, const u8 *buf, int len)
+{
+       int ret;
+
+       ret = i2c_master_send(state->i2c, buf, len);
+       if (ret >= 0 && ret < len)
+               ret = -EIO;
+       return (ret == len) ? 0 : ret;
+}
+
+static int reg_write(struct mxl301rf_state *state, u8 reg, u8 val)
+{
+       u8 buf[2] = { reg, val };
+
+       return raw_write(state, buf, 2);
+}
+
+static int reg_read(struct mxl301rf_state *state, u8 reg, u8 *val)
+{
+       u8 wbuf[2] = { 0xfb, reg };
+       int ret;
+
+       ret = raw_write(state, wbuf, sizeof(wbuf));
+       if (ret == 0)
+               ret = i2c_master_recv(state->i2c, val, 1);
+       if (ret >= 0 && ret < 1)
+               ret = -EIO;
+       return (ret == 1) ? 0 : ret;
+}
+
+/* tuner_ops */
+
+/* get RSSI and update propery cache, set to *out in % */
+static int mxl301rf_get_rf_strength(struct dvb_frontend *fe, u16 *out)
+{
+       struct mxl301rf_state *state;
+       int ret;
+       u8  rf_in1, rf_in2, rf_off1, rf_off2;
+       u16 rf_in, rf_off;
+       s64 level;
+       struct dtv_fe_stats *rssi;
+
+       rssi = &fe->dtv_property_cache.strength;
+       rssi->len = 1;
+       rssi->stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       *out = 0;
+
+       state = fe->tuner_priv;
+       ret = reg_write(state, 0x14, 0x01);
+       if (ret < 0)
+               return ret;
+       usleep_range(1000, 2000);
+
+       ret = reg_read(state, 0x18, &rf_in1);
+       if (ret == 0)
+               ret = reg_read(state, 0x19, &rf_in2);
+       if (ret == 0)
+               ret = reg_read(state, 0xd6, &rf_off1);
+       if (ret == 0)
+               ret = reg_read(state, 0xd7, &rf_off2);
+       if (ret != 0)
+               return ret;
+
+       rf_in = (rf_in2 & 0x07) << 8 | rf_in1;
+       rf_off = (rf_off2 & 0x0f) << 5 | (rf_off1 >> 3);
+       level = rf_in - rf_off - (113 << 3); /* x8 dBm */
+       level = level * 1000 / 8;
+       rssi->stat[0].svalue = level;
+       rssi->stat[0].scale = FE_SCALE_DECIBEL;
+       /* *out = (level - min) * 100 / (max - min) */
+       *out = (rf_in - rf_off + (1 << 9) - 1) * 100 / ((5 << 9) - 2);
+       return 0;
+}
+
+/* spur shift parameters */
+struct shf {
+       u32     freq;           /* Channel center frequency */
+       u32     ofst_th;        /* Offset frequency threshold */
+       u8      shf_val;        /* Spur shift value */
+       u8      shf_dir;        /* Spur shift direction */
+};
+
+static const struct shf shf_tab[] = {
+       {  64500, 500, 0x92, 0x07 },
+       { 191500, 300, 0xe2, 0x07 },
+       { 205500, 500, 0x2c, 0x04 },
+       { 212500, 500, 0x1e, 0x04 },
+       { 226500, 500, 0xd4, 0x07 },
+       {  99143, 500, 0x9c, 0x07 },
+       { 173143, 500, 0xd4, 0x07 },
+       { 191143, 300, 0xd4, 0x07 },
+       { 207143, 500, 0xce, 0x07 },
+       { 225143, 500, 0xce, 0x07 },
+       { 243143, 500, 0xd4, 0x07 },
+       { 261143, 500, 0xd4, 0x07 },
+       { 291143, 500, 0xd4, 0x07 },
+       { 339143, 500, 0x2c, 0x04 },
+       { 117143, 500, 0x7a, 0x07 },
+       { 135143, 300, 0x7a, 0x07 },
+       { 153143, 500, 0x01, 0x07 }
+};
+
+struct reg_val {
+       u8 reg;
+       u8 val;
+} __attribute__ ((__packed__));
+
+static const struct reg_val set_idac[] = {
+       { 0x0d, 0x00 },
+       { 0x0c, 0x67 },
+       { 0x6f, 0x89 },
+       { 0x70, 0x0c },
+       { 0x6f, 0x8a },
+       { 0x70, 0x0e },
+       { 0x6f, 0x8b },
+       { 0x70, 0x1c },
+};
+
+static int mxl301rf_set_params(struct dvb_frontend *fe)
+{
+       struct reg_val tune0[] = {
+               { 0x13, 0x00 },         /* abort tuning */
+               { 0x3b, 0xc0 },
+               { 0x3b, 0x80 },
+               { 0x10, 0x95 },         /* BW */
+               { 0x1a, 0x05 },
+               { 0x61, 0x00 },         /* spur shift value (placeholder) */
+               { 0x62, 0xa0 }          /* spur shift direction (placeholder) */
+       };
+
+       struct reg_val tune1[] = {
+               { 0x11, 0x40 },         /* RF frequency L (placeholder) */
+               { 0x12, 0x0e },         /* RF frequency H (placeholder) */
+               { 0x13, 0x01 }          /* start tune */
+       };
+
+       struct mxl301rf_state *state;
+       u32 freq;
+       u16 f;
+       u32 tmp, div;
+       int i, ret;
+
+       state = fe->tuner_priv;
+       freq = fe->dtv_property_cache.frequency;
+
+       /* spur shift function (for analog) */
+       for (i = 0; i < ARRAY_SIZE(shf_tab); i++) {
+               if (freq >= (shf_tab[i].freq - shf_tab[i].ofst_th) * 1000 &&
+                   freq <= (shf_tab[i].freq + shf_tab[i].ofst_th) * 1000) {
+                       tune0[5].val = shf_tab[i].shf_val;
+                       tune0[6].val = 0xa0 | shf_tab[i].shf_dir;
+                       break;
+               }
+       }
+       ret = raw_write(state, (u8 *) tune0, sizeof(tune0));
+       if (ret < 0)
+               goto failed;
+       usleep_range(3000, 4000);
+
+       /* convert freq to 10.6 fixed point float [MHz] */
+       f = freq / 1000000;
+       tmp = freq % 1000000;
+       div = 1000000;
+       for (i = 0; i < 6; i++) {
+               f <<= 1;
+               div >>= 1;
+               if (tmp > div) {
+                       tmp -= div;
+                       f |= 1;
+               }
+       }
+       if (tmp > 7812)
+               f++;
+       tune1[0].val = f & 0xff;
+       tune1[1].val = f >> 8;
+       ret = raw_write(state, (u8 *) tune1, sizeof(tune1));
+       if (ret < 0)
+               goto failed;
+       msleep(31);
+
+       ret = reg_write(state, 0x1a, 0x0d);
+       if (ret < 0)
+               goto failed;
+       ret = raw_write(state, (u8 *) set_idac, sizeof(set_idac));
+       if (ret < 0)
+               goto failed;
+       return 0;
+
+failed:
+       dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+               __func__, fe->dvb->num, fe->id);
+       return ret;
+}
+
+static const struct reg_val standby_data[] = {
+       { 0x01, 0x00 },
+       { 0x13, 0x00 }
+};
+
+static int mxl301rf_sleep(struct dvb_frontend *fe)
+{
+       struct mxl301rf_state *state;
+       int ret;
+
+       state = fe->tuner_priv;
+       ret = raw_write(state, (u8 *)standby_data, sizeof(standby_data));
+       if (ret < 0)
+               dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+                       __func__, fe->dvb->num, fe->id);
+       return ret;
+}
+
+
+/* init sequence is not public.
+ * the parent must have init'ed the device.
+ * just wake up here.
+ */
+static int mxl301rf_init(struct dvb_frontend *fe)
+{
+       struct mxl301rf_state *state;
+       int ret;
+
+       state = fe->tuner_priv;
+
+       ret = reg_write(state, 0x01, 0x01);
+       if (ret < 0) {
+               dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+                        __func__, fe->dvb->num, fe->id);
+               return ret;
+       }
+       return 0;
+}
+
+/* I2C driver functions */
+
+static const struct dvb_tuner_ops mxl301rf_ops = {
+       .info = {
+               .name = "MaxLinear MxL301RF",
+
+               .frequency_min =  93000000,
+               .frequency_max = 803142857,
+       },
+
+       .init = mxl301rf_init,
+       .sleep = mxl301rf_sleep,
+
+       .set_params = mxl301rf_set_params,
+       .get_rf_strength = mxl301rf_get_rf_strength,
+};
+
+
+static int mxl301rf_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct mxl301rf_state *state;
+       struct mxl301rf_config *cfg;
+       struct dvb_frontend *fe;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+
+       state->i2c = client;
+       cfg = client->dev.platform_data;
+
+       memcpy(&state->cfg, cfg, sizeof(state->cfg));
+       fe = cfg->fe;
+       fe->tuner_priv = state;
+       memcpy(&fe->ops.tuner_ops, &mxl301rf_ops, sizeof(mxl301rf_ops));
+
+       i2c_set_clientdata(client, &state->cfg);
+       dev_info(&client->dev, "MaxLinear MxL301RF attached.\n");
+       return 0;
+}
+
+static int mxl301rf_remove(struct i2c_client *client)
+{
+       struct mxl301rf_state *state;
+
+       state = cfg_to_state(i2c_get_clientdata(client));
+       state->cfg.fe->tuner_priv = NULL;
+       kfree(state);
+       return 0;
+}
+
+
+static const struct i2c_device_id mxl301rf_id[] = {
+       {"mxl301rf", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, mxl301rf_id);
+
+static struct i2c_driver mxl301rf_driver = {
+       .driver = {
+               .name   = "mxl301rf",
+       },
+       .probe          = mxl301rf_probe,
+       .remove         = mxl301rf_remove,
+       .id_table       = mxl301rf_id,
+};
+
+module_i2c_driver(mxl301rf_driver);
+
+MODULE_DESCRIPTION("MaxLinear MXL301RF tuner");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/mxl301rf.h b/drivers/media/tuners/mxl301rf.h
new file mode 100644 (file)
index 0000000..19e6840
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * MaxLinear MxL301RF OFDM tuner driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@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.
+ */
+
+#ifndef MXL301RF_H
+#define MXL301RF_H
+
+#include "dvb_frontend.h"
+
+struct mxl301rf_config {
+       struct dvb_frontend *fe;
+};
+
+#endif /* MXL301RF_H */
index b473b76cb278b52f316cdb6249cba5da667e7d41..92a3be4fde870be4707ab5b8b3cecb8c734d635a 100644 (file)
@@ -1692,7 +1692,6 @@ static u16 MXL5005_TunerConfig(struct dvb_frontend *fe,
        )
 {
        struct mxl5005s_state *state = fe->tuner_priv;
-       u16 status = 0;
 
        state->Mode = Mode;
        state->IF_Mode = IF_mode;
@@ -1715,7 +1714,7 @@ static u16 MXL5005_TunerConfig(struct dvb_frontend *fe,
        /* Synthesizer LO frequency calculation */
        MXL_SynthIFLO_Calc(fe);
 
-       return status;
+       return 0;
 }
 
 static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe)
diff --git a/drivers/media/tuners/qm1d1c0042.c b/drivers/media/tuners/qm1d1c0042.c
new file mode 100644 (file)
index 0000000..18bc745
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ * Sharp QM1D1C0042 8PSK tuner driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@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.
+ */
+
+/*
+ * NOTICE:
+ * As the disclosed information on the chip is very limited,
+ * this driver lacks some features, including chip config like IF freq.
+ * It assumes that users of this driver (such as a PCI bridge of
+ * DTV receiver cards) know the relevant info and
+ * configure the chip via I2C if necessary.
+ *
+ * Currently, PT3 driver is the only one that uses this driver,
+ * and contains init/config code in its firmware.
+ * Thus some part of the code might be dependent on PT3 specific config.
+ */
+
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include "qm1d1c0042.h"
+
+#define QM1D1C0042_NUM_REGS 0x20
+
+static const u8 reg_initval[QM1D1C0042_NUM_REGS] = {
+       0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33,
+       0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+       0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86,
+       0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00
+};
+
+static const struct qm1d1c0042_config default_cfg = {
+       .xtal_freq = 16000,
+       .lpf = 1,
+       .fast_srch = 0,
+       .lpf_wait = 20,
+       .fast_srch_wait = 4,
+       .normal_srch_wait = 15,
+};
+
+struct qm1d1c0042_state {
+       struct qm1d1c0042_config cfg;
+       struct i2c_client *i2c;
+       u8 regs[QM1D1C0042_NUM_REGS];
+};
+
+static struct qm1d1c0042_state *cfg_to_state(struct qm1d1c0042_config *c)
+{
+       return container_of(c, struct qm1d1c0042_state, cfg);
+}
+
+static int reg_write(struct qm1d1c0042_state *state, u8 reg, u8 val)
+{
+       u8 wbuf[2] = { reg, val };
+       int ret;
+
+       ret = i2c_master_send(state->i2c, wbuf, sizeof(wbuf));
+       if (ret >= 0 && ret < sizeof(wbuf))
+               ret = -EIO;
+       return (ret == sizeof(wbuf)) ? 0 : ret;
+}
+
+static int reg_read(struct qm1d1c0042_state *state, u8 reg, u8 *val)
+{
+       struct i2c_msg msgs[2] = {
+               {
+                       .addr = state->i2c->addr,
+                       .flags = 0,
+                       .buf = &reg,
+                       .len = 1,
+               },
+               {
+                       .addr = state->i2c->addr,
+                       .flags = I2C_M_RD,
+                       .buf = val,
+                       .len = 1,
+               },
+       };
+       int ret;
+
+       ret = i2c_transfer(state->i2c->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret >= 0 && ret < ARRAY_SIZE(msgs))
+               ret = -EIO;
+       return (ret == ARRAY_SIZE(msgs)) ? 0 : ret;
+}
+
+
+static int qm1d1c0042_set_srch_mode(struct qm1d1c0042_state *state, bool fast)
+{
+       if (fast)
+               state->regs[0x03] |= 0x01; /* set fast search mode */
+       else
+               state->regs[0x03] &= ~0x01 & 0xff;
+
+       return reg_write(state, 0x03, state->regs[0x03]);
+}
+
+static int qm1d1c0042_wakeup(struct qm1d1c0042_state *state)
+{
+       int ret;
+
+       state->regs[0x01] |= 1 << 3;             /* BB_Reg_enable */
+       state->regs[0x01] &= (~(1 << 0)) & 0xff; /* NORMAL (wake-up) */
+       state->regs[0x05] &= (~(1 << 3)) & 0xff; /* pfd_rst NORMAL */
+       ret = reg_write(state, 0x01, state->regs[0x01]);
+       if (ret == 0)
+               ret = reg_write(state, 0x05, state->regs[0x05]);
+
+       if (ret < 0)
+               dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+                       __func__, state->cfg.fe->dvb->num, state->cfg.fe->id);
+       return ret;
+}
+
+/* tuner_ops */
+
+static int qm1d1c0042_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+       struct qm1d1c0042_state *state;
+       struct qm1d1c0042_config *cfg;
+
+       state = fe->tuner_priv;
+       cfg = priv_cfg;
+
+       if (cfg->fe)
+               state->cfg.fe = cfg->fe;
+
+       if (cfg->xtal_freq != QM1D1C0042_CFG_XTAL_DFLT)
+               dev_warn(&state->i2c->dev,
+                       "(%s) changing xtal_freq not supported. ", __func__);
+       state->cfg.xtal_freq = default_cfg.xtal_freq;
+
+       state->cfg.lpf = cfg->lpf;
+       state->cfg.fast_srch = cfg->fast_srch;
+
+       if (cfg->lpf_wait != QM1D1C0042_CFG_WAIT_DFLT)
+               state->cfg.lpf_wait = cfg->lpf_wait;
+       else
+               state->cfg.lpf_wait = default_cfg.lpf_wait;
+
+       if (cfg->fast_srch_wait != QM1D1C0042_CFG_WAIT_DFLT)
+               state->cfg.fast_srch_wait = cfg->fast_srch_wait;
+       else
+               state->cfg.fast_srch_wait = default_cfg.fast_srch_wait;
+
+       if (cfg->normal_srch_wait != QM1D1C0042_CFG_WAIT_DFLT)
+               state->cfg.normal_srch_wait = cfg->normal_srch_wait;
+       else
+               state->cfg.normal_srch_wait = default_cfg.normal_srch_wait;
+       return 0;
+}
+
+/* divisor, vco_band parameters */
+/*  {maxfreq,  param1(band?), param2(div?) */
+static const u32 conv_table[9][3] = {
+       { 2151000, 1, 7 },
+       { 1950000, 1, 6 },
+       { 1800000, 1, 5 },
+       { 1600000, 1, 4 },
+       { 1450000, 1, 3 },
+       { 1250000, 1, 2 },
+       { 1200000, 0, 7 },
+       {  975000, 0, 6 },
+       {  950000, 0, 0 }
+};
+
+static int qm1d1c0042_set_params(struct dvb_frontend *fe)
+{
+       struct qm1d1c0042_state *state;
+       u32 freq;
+       int i, ret;
+       u8 val, mask;
+       u32 a, sd;
+       s32 b;
+
+       state = fe->tuner_priv;
+       freq = fe->dtv_property_cache.frequency;
+
+       state->regs[0x08] &= 0xf0;
+       state->regs[0x08] |= 0x09;
+
+       state->regs[0x13] &= 0x9f;
+       state->regs[0x13] |= 0x20;
+
+       /* div2/vco_band */
+       val = state->regs[0x02] & 0x0f;
+       for (i = 0; i < 8; i++)
+               if (freq < conv_table[i][0] && freq >= conv_table[i + 1][0]) {
+                       val |= conv_table[i][1] << 7;
+                       val |= conv_table[i][2] << 4;
+                       break;
+               }
+       ret = reg_write(state, 0x02, val);
+       if (ret < 0)
+               return ret;
+
+       a = (freq + state->cfg.xtal_freq / 2) / state->cfg.xtal_freq;
+
+       state->regs[0x06] &= 0x40;
+       state->regs[0x06] |= (a - 12) / 4;
+       ret = reg_write(state, 0x06, state->regs[0x06]);
+       if (ret < 0)
+               return ret;
+
+       state->regs[0x07] &= 0xf0;
+       state->regs[0x07] |= (a - 4 * ((a - 12) / 4 + 1) - 5) & 0x0f;
+       ret = reg_write(state, 0x07, state->regs[0x07]);
+       if (ret < 0)
+               return ret;
+
+       /* LPF */
+       val = state->regs[0x08];
+       if (state->cfg.lpf) {
+               /* LPF_CLK, LPF_FC */
+               val &= 0xf0;
+               val |= 0x02;
+       }
+       ret = reg_write(state, 0x08, val);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * b = (freq / state->cfg.xtal_freq - a) << 20;
+        * sd = b          (b >= 0)
+        *      1<<22 + b  (b < 0)
+        */
+       b = (s32)div64_s64(((s64) freq) << 20, state->cfg.xtal_freq)
+                          - (((s64) a) << 20);
+
+       if (b >= 0)
+               sd = b;
+       else
+               sd = (1 << 22) + b;
+
+       state->regs[0x09] &= 0xc0;
+       state->regs[0x09] |= (sd >> 16) & 0x3f;
+       state->regs[0x0a] = (sd >> 8) & 0xff;
+       state->regs[0x0b] = sd & 0xff;
+       ret = reg_write(state, 0x09, state->regs[0x09]);
+       if (ret == 0)
+               ret = reg_write(state, 0x0a, state->regs[0x0a]);
+       if (ret == 0)
+               ret = reg_write(state, 0x0b, state->regs[0x0b]);
+       if (ret != 0)
+               return ret;
+
+       if (!state->cfg.lpf) {
+               /* CSEL_Offset */
+               ret = reg_write(state, 0x13, state->regs[0x13]);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* VCO_TM, LPF_TM */
+       mask = state->cfg.lpf ? 0x3f : 0x7f;
+       val = state->regs[0x0c] & mask;
+       ret = reg_write(state, 0x0c, val);
+       if (ret < 0)
+               return ret;
+       usleep_range(2000, 3000);
+       val = state->regs[0x0c] | ~mask;
+       ret = reg_write(state, 0x0c, val);
+       if (ret < 0)
+               return ret;
+
+       if (state->cfg.lpf)
+               msleep(state->cfg.lpf_wait);
+       else if (state->regs[0x03] & 0x01)
+               msleep(state->cfg.fast_srch_wait);
+       else
+               msleep(state->cfg.normal_srch_wait);
+
+       if (state->cfg.lpf) {
+               /* LPF_FC */
+               ret = reg_write(state, 0x08, 0x09);
+               if (ret < 0)
+                       return ret;
+
+               /* CSEL_Offset */
+               ret = reg_write(state, 0x13, state->regs[0x13]);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static int qm1d1c0042_sleep(struct dvb_frontend *fe)
+{
+       struct qm1d1c0042_state *state;
+       int ret;
+
+       state = fe->tuner_priv;
+       state->regs[0x01] &= (~(1 << 3)) & 0xff; /* BB_Reg_disable */
+       state->regs[0x01] |= 1 << 0;             /* STDBY */
+       state->regs[0x05] |= 1 << 3;             /* pfd_rst STANDBY */
+       ret = reg_write(state, 0x05, state->regs[0x05]);
+       if (ret == 0)
+               ret = reg_write(state, 0x01, state->regs[0x01]);
+       if (ret < 0)
+               dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+                       __func__, fe->dvb->num, fe->id);
+       return ret;
+}
+
+static int qm1d1c0042_init(struct dvb_frontend *fe)
+{
+       struct qm1d1c0042_state *state;
+       u8 val;
+       int i, ret;
+
+       state = fe->tuner_priv;
+       memcpy(state->regs, reg_initval, sizeof(reg_initval));
+
+       reg_write(state, 0x01, 0x0c);
+       reg_write(state, 0x01, 0x0c);
+
+       ret = reg_write(state, 0x01, 0x0c); /* soft reset on */
+       if (ret < 0)
+               goto failed;
+       usleep_range(2000, 3000);
+
+       val = state->regs[0x01] | 0x10;
+       ret = reg_write(state, 0x01, val); /* soft reset off */
+       if (ret < 0)
+               goto failed;
+
+       /* check ID */
+       ret = reg_read(state, 0x00, &val);
+       if (ret < 0 || val != 0x48)
+               goto failed;
+       usleep_range(2000, 3000);
+
+       state->regs[0x0c] |= 0x40;
+       ret = reg_write(state, 0x0c, state->regs[0x0c]);
+       if (ret < 0)
+               goto failed;
+       msleep(state->cfg.lpf_wait);
+
+       /* set all writable registers */
+       for (i = 1; i <= 0x0c ; i++) {
+               ret = reg_write(state, i, state->regs[i]);
+               if (ret < 0)
+                       goto failed;
+       }
+       for (i = 0x11; i < QM1D1C0042_NUM_REGS; i++) {
+               ret = reg_write(state, i, state->regs[i]);
+               if (ret < 0)
+                       goto failed;
+       }
+
+       ret = qm1d1c0042_wakeup(state);
+       if (ret < 0)
+               goto failed;
+
+       ret = qm1d1c0042_set_srch_mode(state, state->cfg.fast_srch);
+       if (ret < 0)
+               goto failed;
+
+       return ret;
+
+failed:
+       dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+               __func__, fe->dvb->num, fe->id);
+       return ret;
+}
+
+/* I2C driver functions */
+
+static const struct dvb_tuner_ops qm1d1c0042_ops = {
+       .info = {
+               .name = "Sharp QM1D1C0042",
+
+               .frequency_min =  950000,
+               .frequency_max = 2150000,
+       },
+
+       .init = qm1d1c0042_init,
+       .sleep = qm1d1c0042_sleep,
+       .set_config = qm1d1c0042_set_config,
+       .set_params = qm1d1c0042_set_params,
+};
+
+
+static int qm1d1c0042_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       struct qm1d1c0042_state *state;
+       struct qm1d1c0042_config *cfg;
+       struct dvb_frontend *fe;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+       state->i2c = client;
+
+       cfg = client->dev.platform_data;
+       fe = cfg->fe;
+       fe->tuner_priv = state;
+       qm1d1c0042_set_config(fe, cfg);
+       memcpy(&fe->ops.tuner_ops, &qm1d1c0042_ops, sizeof(qm1d1c0042_ops));
+
+       i2c_set_clientdata(client, &state->cfg);
+       dev_info(&client->dev, "Sharp QM1D1C0042 attached.\n");
+       return 0;
+}
+
+static int qm1d1c0042_remove(struct i2c_client *client)
+{
+       struct qm1d1c0042_state *state;
+
+       state = cfg_to_state(i2c_get_clientdata(client));
+       state->cfg.fe->tuner_priv = NULL;
+       kfree(state);
+       return 0;
+}
+
+
+static const struct i2c_device_id qm1d1c0042_id[] = {
+       {"qm1d1c0042", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, qm1d1c0042_id);
+
+static struct i2c_driver qm1d1c0042_driver = {
+       .driver = {
+               .name   = "qm1d1c0042",
+       },
+       .probe          = qm1d1c0042_probe,
+       .remove         = qm1d1c0042_remove,
+       .id_table       = qm1d1c0042_id,
+};
+
+module_i2c_driver(qm1d1c0042_driver);
+
+MODULE_DESCRIPTION("Sharp QM1D1C0042 tuner");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/qm1d1c0042.h b/drivers/media/tuners/qm1d1c0042.h
new file mode 100644 (file)
index 0000000..4f5c188
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Sharp QM1D1C0042 8PSK tuner driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@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.
+ */
+
+#ifndef QM1D1C0042_H
+#define QM1D1C0042_H
+
+#include "dvb_frontend.h"
+
+
+struct qm1d1c0042_config {
+       struct dvb_frontend *fe;
+
+       u32  xtal_freq;    /* [kHz] */ /* currently ignored */
+       bool lpf;          /* enable LPF */
+       bool fast_srch;    /* enable fast search mode, no LPF */
+       u32  lpf_wait;         /* wait in tuning with LPF enabled. [ms] */
+       u32  fast_srch_wait;   /* with fast-search mode, no LPF. [ms] */
+       u32  normal_srch_wait; /* with no LPF/fast-search mode. [ms] */
+};
+/* special values indicating to use the default in qm1d1c0042_config */
+#define QM1D1C0042_CFG_XTAL_DFLT 0
+#define QM1D1C0042_CFG_WAIT_DFLT 0
+
+#endif /* QM1D1C0042_H */
index 6c53edb73a632ed0c43ade3acf363c9b580bff3d..cf97142e01e6a34c3ebd30cf6e143c5599dab919 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2157/2158 silicon tuner driver
+ * Silicon Labs Si2147/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
@@ -55,8 +55,7 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd)
                                break;
                }
 
-               dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n",
-                               __func__,
+               dev_dbg(&s->client->dev, "cmd execution took %d ms\n",
                                jiffies_to_msecs(jiffies) -
                                (jiffies_to_msecs(timeout) - TIMEOUT));
 
@@ -75,7 +74,7 @@ err_mutex_unlock:
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -88,9 +87,12 @@ static int si2157_init(struct dvb_frontend *fe)
        u8 *fw_file;
        unsigned int chip_id;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
-       /* configure? */
+       if (s->fw_loaded)
+               goto warm;
+
+       /* power up */
        memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15);
        cmd.wlen = 15;
        cmd.rlen = 1;
@@ -111,45 +113,47 @@ static int si2157_init(struct dvb_frontend *fe)
 
        #define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0)
        #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
+       #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
 
        switch (chip_id) {
        case SI2158_A20:
                fw_file = SI2158_A20_FIRMWARE;
                break;
        case SI2157_A30:
+       case SI2147_A30:
                goto skip_fw_download;
                break;
        default:
                dev_err(&s->client->dev,
-                               "%s: unkown chip version Si21%d-%c%c%c\n",
-                               KBUILD_MODNAME, cmd.args[2], cmd.args[1],
+                               "unknown chip version Si21%d-%c%c%c\n",
+                               cmd.args[2], cmd.args[1],
                                cmd.args[3], cmd.args[4]);
                ret = -EINVAL;
                goto err;
        }
 
        /* cold state - try to download firmware */
-       dev_info(&s->client->dev, "%s: found a '%s' in cold state\n",
-                       KBUILD_MODNAME, si2157_ops.info.name);
+       dev_info(&s->client->dev, "found a '%s' in cold state\n",
+                       si2157_ops.info.name);
 
        /* request the firmware, this will block and timeout */
        ret = request_firmware(&fw, fw_file, &s->client->dev);
        if (ret) {
-               dev_err(&s->client->dev, "%s: firmware file '%s' not found\n",
-                               KBUILD_MODNAME, fw_file);
+               dev_err(&s->client->dev, "firmware file '%s' not found\n",
+                               fw_file);
                goto err;
        }
 
        /* firmware should be n chunks of 17 bytes */
        if (fw->size % 17 != 0) {
-               dev_err(&s->client->dev, "%s: firmware file '%s' is invalid\n",
-                               KBUILD_MODNAME, fw_file);
+               dev_err(&s->client->dev, "firmware file '%s' is invalid\n",
+                               fw_file);
                ret = -EINVAL;
                goto err;
        }
 
-       dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n",
-                       KBUILD_MODNAME, fw_file);
+       dev_info(&s->client->dev, "downloading firmware from file '%s'\n",
+                       fw_file);
 
        for (remaining = fw->size; remaining > 0; remaining -= 17) {
                len = fw->data[fw->size - remaining];
@@ -159,8 +163,8 @@ static int si2157_init(struct dvb_frontend *fe)
                ret = si2157_cmd_execute(s, &cmd);
                if (ret) {
                        dev_err(&s->client->dev,
-                                       "%s: firmware download failed=%d\n",
-                                       KBUILD_MODNAME, ret);
+                                       "firmware download failed=%d\n",
+                                       ret);
                        goto err;
                }
        }
@@ -177,14 +181,17 @@ skip_fw_download:
        if (ret)
                goto err;
 
-       s->active = true;
+       s->fw_loaded = true;
 
+warm:
+       s->active = true;
        return 0;
+
 err:
        if (fw)
                release_firmware(fw);
 
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -194,20 +201,21 @@ static int si2157_sleep(struct dvb_frontend *fe)
        int ret;
        struct si2157_cmd cmd;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
        s->active = false;
 
-       memcpy(cmd.args, "\x13", 1);
-       cmd.wlen = 1;
-       cmd.rlen = 0;
+       /* standby */
+       memcpy(cmd.args, "\x16\x00", 2);
+       cmd.wlen = 2;
+       cmd.rlen = 1;
        ret = si2157_cmd_execute(s, &cmd);
        if (ret)
                goto err;
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -220,8 +228,8 @@ static int si2157_set_params(struct dvb_frontend *fe)
        u8 bandwidth, delivery_system;
 
        dev_dbg(&s->client->dev,
-                       "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n",
-                       __func__, c->delivery_system, c->frequency,
+                       "delivery_system=%d frequency=%u bandwidth_hz=%u\n",
+                       c->delivery_system, c->frequency,
                        c->bandwidth_hz);
 
        if (!s->active) {
@@ -239,6 +247,9 @@ static int si2157_set_params(struct dvb_frontend *fe)
                bandwidth = 0x0f;
 
        switch (c->delivery_system) {
+       case SYS_ATSC:
+                       delivery_system = 0x00;
+                       break;
        case SYS_DVBT:
        case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */
                        delivery_system = 0x20;
@@ -256,7 +267,14 @@ static int si2157_set_params(struct dvb_frontend *fe)
        if (s->inversion)
                cmd.args[5] = 0x01;
        cmd.wlen = 6;
-       cmd.rlen = 1;
+       cmd.rlen = 4;
+       ret = si2157_cmd_execute(s, &cmd);
+       if (ret)
+               goto err;
+
+       memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6);
+       cmd.wlen = 6;
+       cmd.rlen = 4;
        ret = si2157_cmd_execute(s, &cmd);
        if (ret)
                goto err;
@@ -275,7 +293,7 @@ static int si2157_set_params(struct dvb_frontend *fe)
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -310,13 +328,14 @@ static int si2157_probe(struct i2c_client *client,
        s = kzalloc(sizeof(struct si2157), GFP_KERNEL);
        if (!s) {
                ret = -ENOMEM;
-               dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+               dev_err(&client->dev, "kzalloc() failed\n");
                goto err;
        }
 
        s->client = client;
        s->fe = cfg->fe;
        s->inversion = cfg->inversion;
+       s->fw_loaded = false;
        mutex_init(&s->i2c_mutex);
 
        /* check if the tuner is there */
@@ -333,11 +352,10 @@ static int si2157_probe(struct i2c_client *client,
        i2c_set_clientdata(client, s);
 
        dev_info(&s->client->dev,
-                       "%s: Silicon Labs Si2157/Si2158 successfully attached\n",
-                       KBUILD_MODNAME);
+                       "Silicon Labs Si2157/Si2158 successfully attached\n");
        return 0;
 err:
-       dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        kfree(s);
 
        return ret;
@@ -348,7 +366,7 @@ static int si2157_remove(struct i2c_client *client)
        struct si2157 *s = i2c_get_clientdata(client);
        struct dvb_frontend *fe = s->fe;
 
-       dev_dbg(&client->dev, "%s:\n", __func__);
+       dev_dbg(&client->dev, "\n");
 
        memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
        fe->tuner_priv = NULL;
index 6da4d5d1c8178b25ad5e3965e5a90b06dbd2865f..d3b19cadb4a16d04fa83fbafd7e483514bfc6e1e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2157/2158 silicon tuner driver
+ * Silicon Labs Si2147/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
index 3ddab5e6b50038cbb9034f556fb6f77edec5308f..e71ffafed951b804f7a272a5ecc12795e86f30d5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2157/2158 silicon tuner driver
+ * Silicon Labs Si2147/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
@@ -26,6 +26,7 @@ struct si2157 {
        struct i2c_client *client;
        struct dvb_frontend *fe;
        bool active;
+       bool fw_loaded;
        bool inversion;
 };
 
index 05a4ac9edb6b0559eedde3f39273bb958df9cfd8..d93e0667b46b65b78d67105f8acd7ffe929863d5 100644 (file)
  */
 
 #include "tda18212.h"
+#include <linux/regmap.h>
 
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE  64
-
-struct tda18212_priv {
-       struct tda18212_config *cfg;
-       struct i2c_adapter *i2c;
+struct tda18212_dev {
+       struct tda18212_config cfg;
+       struct i2c_client *client;
+       struct regmap *regmap;
 
        u32 if_frequency;
 };
 
-/* write multiple registers */
-static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
-       int len)
-{
-       int ret;
-       u8 buf[MAX_XFER_SIZE];
-       struct i2c_msg msg[1] = {
-               {
-                       .addr = priv->cfg->i2c_address,
-                       .flags = 0,
-                       .len = 1 + len,
-                       .buf = buf,
-               }
-       };
-
-       if (1 + len > sizeof(buf)) {
-               dev_warn(&priv->i2c->dev,
-                        "%s: i2c wr reg=%04x: len=%d is too big!\n",
-                        KBUILD_MODNAME, reg, len);
-               return -EINVAL;
-       }
-
-       buf[0] = reg;
-       memcpy(&buf[1], val, len);
-
-       ret = i2c_transfer(priv->i2c, msg, 1);
-       if (ret == 1) {
-               ret = 0;
-       } else {
-               dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
-                               "len=%d\n", KBUILD_MODNAME, ret, reg, len);
-               ret = -EREMOTEIO;
-       }
-       return ret;
-}
-
-/* read multiple registers */
-static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
-       int len)
-{
-       int ret;
-       u8 buf[MAX_XFER_SIZE];
-       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 = len,
-                       .buf = buf,
-               }
-       };
-
-       if (len > sizeof(buf)) {
-               dev_warn(&priv->i2c->dev,
-                        "%s: i2c rd reg=%04x: len=%d is too big!\n",
-                        KBUILD_MODNAME, reg, len);
-               return -EINVAL;
-       }
-
-       ret = i2c_transfer(priv->i2c, msg, 2);
-       if (ret == 2) {
-               memcpy(val, buf, len);
-               ret = 0;
-       } else {
-               dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
-                               "len=%d\n", KBUILD_MODNAME, ret, reg, len);
-               ret = -EREMOTEIO;
-       }
-
-       return ret;
-}
-
-/* write single register */
-static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val)
-{
-       return tda18212_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val)
-{
-       return tda18212_rd_regs(priv, reg, val, 1);
-}
-
-#if 0 /* keep, useful when developing driver */
-static void tda18212_dump_regs(struct tda18212_priv *priv)
-{
-       int i;
-       u8 buf[256];
-
-       #define TDA18212_RD_LEN 32
-       for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN)
-               tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN);
-
-       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf,
-               sizeof(buf), true);
-
-       return;
-}
-#endif
-
 static int tda18212_set_params(struct dvb_frontend *fe)
 {
-       struct tda18212_priv *priv = fe->tuner_priv;
+       struct tda18212_dev *dev = fe->tuner_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret, i;
        u32 if_khz;
@@ -166,9 +60,9 @@ static int tda18212_set_params(struct dvb_frontend *fe)
                [ATSC_QAM] = { 0x7d, 0x20, 0x63 },
        };
 
-       dev_dbg(&priv->i2c->dev,
-                       "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
-                       __func__, c->delivery_system, c->frequency,
+       dev_dbg(&dev->client->dev,
+                       "delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+                       c->delivery_system, c->frequency,
                        c->bandwidth_hz);
 
        if (fe->ops.i2c_gate_ctrl)
@@ -176,25 +70,25 @@ static int tda18212_set_params(struct dvb_frontend *fe)
 
        switch (c->delivery_system) {
        case SYS_ATSC:
-               if_khz = priv->cfg->if_atsc_vsb;
+               if_khz = dev->cfg.if_atsc_vsb;
                i = ATSC_VSB;
                break;
        case SYS_DVBC_ANNEX_B:
-               if_khz = priv->cfg->if_atsc_qam;
+               if_khz = dev->cfg.if_atsc_qam;
                i = ATSC_QAM;
                break;
        case SYS_DVBT:
                switch (c->bandwidth_hz) {
                case 6000000:
-                       if_khz = priv->cfg->if_dvbt_6;
+                       if_khz = dev->cfg.if_dvbt_6;
                        i = DVBT_6;
                        break;
                case 7000000:
-                       if_khz = priv->cfg->if_dvbt_7;
+                       if_khz = dev->cfg.if_dvbt_7;
                        i = DVBT_7;
                        break;
                case 8000000:
-                       if_khz = priv->cfg->if_dvbt_8;
+                       if_khz = dev->cfg.if_dvbt_8;
                        i = DVBT_8;
                        break;
                default:
@@ -205,15 +99,15 @@ static int tda18212_set_params(struct dvb_frontend *fe)
        case SYS_DVBT2:
                switch (c->bandwidth_hz) {
                case 6000000:
-                       if_khz = priv->cfg->if_dvbt2_6;
+                       if_khz = dev->cfg.if_dvbt2_6;
                        i = DVBT2_6;
                        break;
                case 7000000:
-                       if_khz = priv->cfg->if_dvbt2_7;
+                       if_khz = dev->cfg.if_dvbt2_7;
                        i = DVBT2_7;
                        break;
                case 8000000:
-                       if_khz = priv->cfg->if_dvbt2_8;
+                       if_khz = dev->cfg.if_dvbt2_8;
                        i = DVBT2_8;
                        break;
                default:
@@ -223,7 +117,7 @@ static int tda18212_set_params(struct dvb_frontend *fe)
                break;
        case SYS_DVBC_ANNEX_A:
        case SYS_DVBC_ANNEX_C:
-               if_khz = priv->cfg->if_dvbc;
+               if_khz = dev->cfg.if_dvbc;
                i = DVBC_8;
                break;
        default:
@@ -231,15 +125,15 @@ static int tda18212_set_params(struct dvb_frontend *fe)
                goto error;
        }
 
-       ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]);
+       ret = regmap_write(dev->regmap, 0x23, bw_params[i][2]);
        if (ret)
                goto error;
 
-       ret = tda18212_wr_reg(priv, 0x06, 0x00);
+       ret = regmap_write(dev->regmap, 0x06, 0x00);
        if (ret)
                goto error;
 
-       ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]);
+       ret = regmap_write(dev->regmap, 0x0f, bw_params[i][0]);
        if (ret)
                goto error;
 
@@ -252,12 +146,12 @@ static int tda18212_set_params(struct dvb_frontend *fe)
        buf[6] = ((c->frequency / 1000) >>  0) & 0xff;
        buf[7] = 0xc1;
        buf[8] = 0x01;
-       ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf));
+       ret = regmap_bulk_write(dev->regmap, 0x12, buf, sizeof(buf));
        if (ret)
                goto error;
 
        /* actual IF rounded as it is on register */
-       priv->if_frequency = buf[3] * 50 * 1000;
+       dev->if_frequency = buf[3] * 50 * 1000;
 
 exit:
        if (fe->ops.i2c_gate_ctrl)
@@ -266,26 +160,19 @@ exit:
        return ret;
 
 error:
-       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
        goto exit;
 }
 
 static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-       struct tda18212_priv *priv = fe->tuner_priv;
+       struct tda18212_dev *dev = fe->tuner_priv;
 
-       *frequency = priv->if_frequency;
+       *frequency = dev->if_frequency;
 
        return 0;
 }
 
-static int tda18212_release(struct dvb_frontend *fe)
-{
-       kfree(fe->tuner_priv);
-       fe->tuner_priv = NULL;
-       return 0;
-}
-
 static const struct dvb_tuner_ops tda18212_tuner_ops = {
        .info = {
                .name           = "NXP TDA18212",
@@ -295,53 +182,110 @@ static const struct dvb_tuner_ops tda18212_tuner_ops = {
                .frequency_step =      1000,
        },
 
-       .release       = tda18212_release,
-
        .set_params    = tda18212_set_params,
        .get_if_frequency = tda18212_get_if_frequency,
 };
 
-struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
-       struct i2c_adapter *i2c, struct tda18212_config *cfg)
+static int tda18212_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
 {
-       struct tda18212_priv *priv = NULL;
+       struct tda18212_config *cfg = client->dev.platform_data;
+       struct dvb_frontend *fe = cfg->fe;
+       struct tda18212_dev *dev;
        int ret;
-       u8 val;
+       unsigned int chip_id;
+       char *version;
+       static const struct regmap_config regmap_config = {
+               .reg_bits = 8,
+               .val_bits = 8,
+       };
 
-       priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
-       if (priv == NULL)
-               return NULL;
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               ret = -ENOMEM;
+               dev_err(&client->dev, "kzalloc() failed\n");
+               goto err;
+       }
 
-       priv->cfg = cfg;
-       priv->i2c = i2c;
-       fe->tuner_priv = priv;
+       memcpy(&dev->cfg, cfg, sizeof(struct tda18212_config));
+       dev->client = client;
+       dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
+       if (IS_ERR(dev->regmap)) {
+               ret = PTR_ERR(dev->regmap);
+               goto err;
+       }
 
+       /* check if the tuner is there */
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 
-       /* check if the tuner is there */
-       ret = tda18212_rd_reg(priv, 0x00, &val);
+       ret = regmap_read(dev->regmap, 0x00, &chip_id);
+       dev_dbg(&dev->client->dev, "chip_id=%02x\n", chip_id);
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 
-       if (!ret)
-               dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, val);
-       if (ret || val != 0xc7) {
-               kfree(priv);
-               return NULL;
+       if (ret)
+               goto err;
+
+       switch (chip_id) {
+       case 0xc7:
+               version = "M"; /* master */
+               break;
+       case 0x47:
+               version = "S"; /* slave */
+               break;
+       default:
+               ret = -ENODEV;
+               goto err;
        }
 
-       dev_info(&priv->i2c->dev,
-                       "%s: NXP TDA18212HN successfully identified\n",
-                       KBUILD_MODNAME);
+       dev_info(&dev->client->dev,
+                       "NXP TDA18212HN/%s successfully identified\n", version);
 
+       fe->tuner_priv = dev;
        memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
-               sizeof(struct dvb_tuner_ops));
+                       sizeof(struct dvb_tuner_ops));
+       i2c_set_clientdata(client, dev);
 
-       return fe;
+       return 0;
+err:
+       dev_dbg(&client->dev, "failed=%d\n", ret);
+       kfree(dev);
+       return ret;
 }
-EXPORT_SYMBOL(tda18212_attach);
+
+static int tda18212_remove(struct i2c_client *client)
+{
+       struct tda18212_dev *dev = i2c_get_clientdata(client);
+       struct dvb_frontend *fe = dev->cfg.fe;
+
+       dev_dbg(&client->dev, "\n");
+
+       memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
+       fe->tuner_priv = NULL;
+       kfree(dev);
+
+       return 0;
+}
+
+static const struct i2c_device_id tda18212_id[] = {
+       {"tda18212", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, tda18212_id);
+
+static struct i2c_driver tda18212_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tda18212",
+       },
+       .probe          = tda18212_probe,
+       .remove         = tda18212_remove,
+       .id_table       = tda18212_id,
+};
+
+module_i2c_driver(tda18212_driver);
 
 MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
index c36b49e4b2742a8f8cf12f1dd99e253c69d89ac6..e58c9096d79c5e5a08a6bcdb5a644fa19490edbf 100644 (file)
@@ -25,8 +25,6 @@
 #include "dvb_frontend.h"
 
 struct tda18212_config {
-       u8 i2c_address;
-
        u16 if_dvbt_6;
        u16 if_dvbt_7;
        u16 if_dvbt_8;
@@ -37,18 +35,11 @@ struct tda18212_config {
        u16 if_dvbc;
        u16 if_atsc_vsb;
        u16 if_atsc_qam;
-};
 
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18212)
-extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
-       struct i2c_adapter *i2c, struct tda18212_config *cfg);
-#else
-static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
-       struct i2c_adapter *i2c, struct tda18212_config *cfg)
-{
-       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-       return NULL;
-}
-#endif
+       /*
+        * pointer to DVB frontend
+        */
+       struct dvb_frontend *fe;
+};
 
 #endif
index 18c77afe2e4ff8f32345a56d6aae199de1062c74..86e5e31101186ef37b30055b9f43e0725fc7ba01 100644 (file)
@@ -714,12 +714,11 @@ fail:
        return ret;
 }
 
-int _tda_printk(struct tda18271_priv *state, const char *level,
-               const char *func, const char *fmt, ...)
+void _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);
 
@@ -727,15 +726,13 @@ int _tda_printk(struct tda18271_priv *state, const char *level,
        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);
+               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);
+               printk("%s%s: %pV", level, func, &vaf);
 
        va_end(args);
-
-       return rtn;
 }
index 454c152ccaa023d66423591108ca16616c058660..b36a7b75477253ad6cc1e678579833d8476354fb 100644 (file)
@@ -139,8 +139,8 @@ extern int tda18271_debug;
 #define DBG_CAL  16
 
 __attribute__((format(printf, 4, 5)))
-int _tda_printk(struct tda18271_priv *state, const char *level,
-               const char *func, const char *fmt, ...);
+void _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)
index 565eeebb3aebc990fc89b7e4fafc98c0e876e487..d12f5e4ad8bf42e0138de60316f1a16ae419a2b8 100644 (file)
@@ -178,67 +178,67 @@ static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
 #define dump_firm_type(t)      dump_firm_type_and_int_freq(t, 0)
 static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
 {
-        if (type & BASE)
+       if (type & BASE)
                printk("BASE ");
-        if (type & INIT1)
+       if (type & INIT1)
                printk("INIT1 ");
-        if (type & F8MHZ)
+       if (type & F8MHZ)
                printk("F8MHZ ");
-        if (type & MTS)
+       if (type & MTS)
                printk("MTS ");
-        if (type & D2620)
+       if (type & D2620)
                printk("D2620 ");
-        if (type & D2633)
+       if (type & D2633)
                printk("D2633 ");
-        if (type & DTV6)
+       if (type & DTV6)
                printk("DTV6 ");
-        if (type & QAM)
+       if (type & QAM)
                printk("QAM ");
-        if (type & DTV7)
+       if (type & DTV7)
                printk("DTV7 ");
-        if (type & DTV78)
+       if (type & DTV78)
                printk("DTV78 ");
-        if (type & DTV8)
+       if (type & DTV8)
                printk("DTV8 ");
-        if (type & FM)
+       if (type & FM)
                printk("FM ");
-        if (type & INPUT1)
+       if (type & INPUT1)
                printk("INPUT1 ");
-        if (type & LCD)
+       if (type & LCD)
                printk("LCD ");
-        if (type & NOGD)
+       if (type & NOGD)
                printk("NOGD ");
-        if (type & MONO)
+       if (type & MONO)
                printk("MONO ");
-        if (type & ATSC)
+       if (type & ATSC)
                printk("ATSC ");
-        if (type & IF)
+       if (type & IF)
                printk("IF ");
-        if (type & LG60)
+       if (type & LG60)
                printk("LG60 ");
-        if (type & ATI638)
+       if (type & ATI638)
                printk("ATI638 ");
-        if (type & OREN538)
+       if (type & OREN538)
                printk("OREN538 ");
-        if (type & OREN36)
+       if (type & OREN36)
                printk("OREN36 ");
-        if (type & TOYOTA388)
+       if (type & TOYOTA388)
                printk("TOYOTA388 ");
-        if (type & TOYOTA794)
+       if (type & TOYOTA794)
                printk("TOYOTA794 ");
-        if (type & DIBCOM52)
+       if (type & DIBCOM52)
                printk("DIBCOM52 ");
-        if (type & ZARLINK456)
+       if (type & ZARLINK456)
                printk("ZARLINK456 ");
-        if (type & CHINA)
+       if (type & CHINA)
                printk("CHINA ");
-        if (type & F6MHZ)
+       if (type & F6MHZ)
                printk("F6MHZ ");
-        if (type & INPUT2)
+       if (type & INPUT2)
                printk("INPUT2 ");
-        if (type & SCODE)
+       if (type & SCODE)
                printk("SCODE ");
-        if (type & HAS_IF)
+       if (type & HAS_IF)
                printk("HAS_IF_%d ", int_freq);
 }
 
diff --git a/drivers/media/tuners/tuner_it913x.c b/drivers/media/tuners/tuner_it913x.c
deleted file mode 100644 (file)
index 3d83c42..0000000
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * ITE Tech IT9137 silicon tuner driver
- *
- *  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 "tuner_it913x_priv.h"
-
-struct it913x_state {
-       struct i2c_adapter *i2c_adap;
-       u8 i2c_addr;
-       u8 chip_ver;
-       u8 tuner_type;
-       u8 firmware_ver;
-       u16 tun_xtal;
-       u8 tun_fdiv;
-       u8 tun_clk_mode;
-       u32 tun_fn_min;
-};
-
-/* read multiple registers */
-static int it913x_rd_regs(struct it913x_state *state,
-               u32 reg, u8 *data, u8 count)
-{
-       int ret;
-       u8 b[3];
-       struct i2c_msg msg[2] = {
-               { .addr = state->i2c_addr, .flags = 0,
-                       .buf = b, .len = sizeof(b) },
-               { .addr = state->i2c_addr, .flags = I2C_M_RD,
-                       .buf = data, .len = count }
-       };
-       b[0] = (u8)(reg >> 16) & 0xff;
-       b[1] = (u8)(reg >> 8) & 0xff;
-       b[2] = (u8) reg & 0xff;
-       b[0] |= 0x80; /* All reads from demodulator */
-
-       ret = i2c_transfer(state->i2c_adap, msg, 2);
-
-       return ret;
-}
-
-/* read single register */
-static int it913x_rd_reg(struct it913x_state *state, u32 reg)
-{
-       int ret;
-       u8 b[1];
-       ret = it913x_rd_regs(state, reg, &b[0], sizeof(b));
-       return (ret < 0) ? -ENODEV : b[0];
-}
-
-/* write multiple registers */
-static int it913x_wr_regs(struct it913x_state *state,
-               u8 pro, u32 reg, u8 buf[], u8 count)
-{
-       u8 b[256];
-       struct i2c_msg msg[1] = {
-               { .addr = state->i2c_addr, .flags = 0,
-                 .buf = b, .len = 3 + count }
-       };
-       int ret;
-       b[0] = (u8)(reg >> 16) & 0xff;
-       b[1] = (u8)(reg >> 8) & 0xff;
-       b[2] = (u8) reg & 0xff;
-       memcpy(&b[3], buf, count);
-
-       if (pro == PRO_DMOD)
-               b[0] |= 0x80;
-
-       ret = i2c_transfer(state->i2c_adap, msg, 1);
-
-       if (ret < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* write single register */
-static int it913x_wr_reg(struct it913x_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_wr_regs(state, pro, reg, &b[s], sizeof(b) - s);
-
-       return ret;
-}
-
-static int it913x_script_loader(struct it913x_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_wr_regs(state, loadscript[i].pro,
-                       loadscript[i].address,
-                       loadscript[i].reg, loadscript[i].count);
-               if (ret < 0)
-                       return -ENODEV;
-       }
-       return 0;
-}
-
-static int it913x_init(struct dvb_frontend *fe)
-{
-       struct it913x_state *state = fe->tuner_priv;
-       int ret, i, reg;
-       u8 val, nv_val;
-       u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
-       u8 b[2];
-
-       reg = it913x_rd_reg(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_rd_reg(state, 0xed03);
-
-       if (reg < 0)
-               return -ENODEV;
-       else if (reg < ARRAY_SIZE(nv))
-               nv_val = nv[reg];
-       else
-               nv_val = 2;
-
-       for (i = 0; i < 50; i++) {
-               ret = it913x_rd_regs(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);
-       dev_dbg(&state->i2c_adap->dev, "%s: Tuner fn_min %d\n", __func__,
-                       state->tun_fn_min);
-
-       if (state->chip_ver > 1)
-               msleep(50);
-       else {
-               for (i = 0; i < 50; i++) {
-                       reg = it913x_rd_reg(state, 0xec82);
-                       if (reg > 0)
-                               break;
-                       if (reg < 0)
-                               return -ENODEV;
-                       udelay(2000);
-               }
-       }
-
-       /* Power Up Tuner - common all versions */
-       ret = it913x_wr_reg(state, PRO_DMOD, 0xec40, 0x1);
-       ret |= it913x_wr_reg(state, PRO_DMOD, 0xfba8, 0x0);
-       ret |= it913x_wr_reg(state, PRO_DMOD, 0xec57, 0x0);
-       ret |= it913x_wr_reg(state, PRO_DMOD, 0xec58, 0x0);
-
-       return it913x_wr_reg(state, PRO_DMOD, 0xed81, val);
-}
-
-static int it9137_set_params(struct dvb_frontend *fe)
-{
-       struct it913x_state *state = fe->tuner_priv;
-       struct it913xset *set_tuner = set_it9137_template;
-       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-       u32 bandwidth = p->bandwidth_hz;
-       u32 frequency_m = p->frequency;
-       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;
-
-       if (state->firmware_ver == 1)
-               set_tuner = set_it9135_template;
-       else
-               set_tuner = set_it9137_template;
-
-       dev_dbg(&state->i2c_adap->dev, "%s: Tuner Frequency %d Bandwidth %d\n",
-                       __func__, 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;
-
-       switch (bandwidth) {
-       case 5000000:
-               bw = 0;
-               break;
-       case 6000000:
-               bw = 2;
-               break;
-       case 7000000:
-               bw = 4;
-               break;
-       default:
-       case 8000000:
-               bw = 6;
-               break;
-       }
-
-       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_rd_reg(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;
-
-       dev_dbg(&state->i2c_adap->dev, "%s: High Frequency = %04x\n",
-                       __func__, temp_f);
-
-       /* Lower frequency */
-       set_tuner[5].reg[0] =  freq & 0xff;
-       set_tuner[6].reg[0] =  (freq >> 8) & 0xff;
-
-       dev_dbg(&state->i2c_adap->dev, "%s: low Frequency = %04x\n",
-                       __func__, freq);
-
-       ret = it913x_script_loader(state, set_tuner);
-
-       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_sleep(struct dvb_frontend *fe)
-{
-       struct it913x_state *state = fe->tuner_priv;
-       return it913x_script_loader(state, it9137_tuner_off);
-}
-
-static int it913x_release(struct dvb_frontend *fe)
-{
-       kfree(fe->tuner_priv);
-       return 0;
-}
-
-static const struct dvb_tuner_ops it913x_tuner_ops = {
-       .info = {
-               .name           = "ITE Tech IT913X",
-               .frequency_min  = 174000000,
-               .frequency_max  = 862000000,
-       },
-
-       .release = it913x_release,
-
-       .init = it913x_init,
-       .sleep = it913x_sleep,
-       .set_params = it9137_set_params,
-};
-
-struct dvb_frontend *it913x_attach(struct dvb_frontend *fe,
-               struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 config)
-{
-       struct it913x_state *state = NULL;
-       int ret;
-
-       /* allocate memory for the internal state */
-       state = kzalloc(sizeof(struct it913x_state), GFP_KERNEL);
-       if (state == NULL)
-               return NULL;
-
-       state->i2c_adap = i2c_adap;
-       state->i2c_addr = i2c_addr;
-
-       switch (config) {
-       case AF9033_TUNER_IT9135_38:
-       case AF9033_TUNER_IT9135_51:
-       case AF9033_TUNER_IT9135_52:
-               state->chip_ver = 0x01;
-               break;
-       case AF9033_TUNER_IT9135_60:
-       case AF9033_TUNER_IT9135_61:
-       case AF9033_TUNER_IT9135_62:
-               state->chip_ver = 0x02;
-               break;
-       default:
-               dev_dbg(&i2c_adap->dev,
-                               "%s: invalid config=%02x\n", __func__, config);
-               goto error;
-       }
-
-       state->tuner_type = config;
-       state->firmware_ver = 1;
-
-       /* tuner RF initial */
-       ret = it913x_wr_reg(state, PRO_DMOD, 0xec4c, 0x68);
-       if (ret < 0)
-               goto error;
-
-       fe->tuner_priv = state;
-       memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops,
-                       sizeof(struct dvb_tuner_ops));
-
-       dev_info(&i2c_adap->dev,
-                       "%s: ITE Tech IT913X successfully attached\n",
-                       KBUILD_MODNAME);
-       dev_dbg(&i2c_adap->dev, "%s: config=%02x chip_ver=%02x\n",
-                       __func__, config, state->chip_ver);
-
-       return fe;
-error:
-       kfree(state);
-       return NULL;
-}
-EXPORT_SYMBOL(it913x_attach);
-
-MODULE_DESCRIPTION("ITE Tech IT913X silicon tuner driver");
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tuner_it913x.h b/drivers/media/tuners/tuner_it913x.h
deleted file mode 100644 (file)
index 12dd36b..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * ITE Tech IT9137 silicon tuner driver
- *
- *  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.=
- */
-
-#ifndef IT913X_H
-#define IT913X_H
-
-#include "dvb_frontend.h"
-
-#if defined(CONFIG_MEDIA_TUNER_IT913X) || \
-       (defined(CONFIG_MEDIA_TUNER_IT913X_MODULE) && defined(MODULE))
-extern struct dvb_frontend *it913x_attach(struct dvb_frontend *fe,
-       struct i2c_adapter *i2c_adap,
-       u8 i2c_addr,
-       u8 config);
-#else
-static inline struct dvb_frontend *it913x_attach(struct dvb_frontend *fe,
-       struct i2c_adapter *i2c_adap,
-       u8 i2c_addr,
-       u8 config)
-{
-       pr_warn("%s: driver disabled by Kconfig\n", __func__);
-       return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/tuners/tuner_it913x_priv.h b/drivers/media/tuners/tuner_it913x_priv.h
deleted file mode 100644 (file)
index ce65210..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * ITE Tech IT9137 silicon tuner driver
- *
- *  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.=
- */
-
-#ifndef IT913X_PRIV_H
-#define IT913X_PRIV_H
-
-#include "tuner_it913x.h"
-#include "af9033.h"
-
-#define PRO_LINK               0x0
-#define PRO_DMOD               0x1
-#define TRIGGER_OFSM           0x0000
-
-struct it913xset {     u32 pro;
-                       u32 address;
-                       u8 reg[15];
-                       u8 count;
-};
-
-/* Tuner setting scripts (still keeping it9137) */
-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, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00}, 0x0c},
-       {PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04},
-       {PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00}, 0x09},
-       {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00}, 0x0a},
-       {PRO_DMOD, 0xec20, {0x00}, 0x01},
-       {PRO_DMOD, 0xec3f, {0x01}, 0x01},
-       {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-static struct it913xset set_it9135_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, 0x011e, {0x00}, 0x01}, /* Older Devices */
-       {PRO_DMOD, 0x011f, {0x00}, 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 */
-};
-
-#endif
index f9ab79e3432d9cb4018fcd017548a9f457724b9c..219ebafae70fd3f9b8d1f5541d43100e7a73aa64 100644 (file)
@@ -569,67 +569,67 @@ static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val)
 #define dump_firm_type(t)      dump_firm_type_and_int_freq(t, 0)
 static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
 {
-        if (type & BASE)
+       if (type & BASE)
                printk(KERN_CONT "BASE ");
-        if (type & INIT1)
+       if (type & INIT1)
                printk(KERN_CONT "INIT1 ");
-        if (type & F8MHZ)
+       if (type & F8MHZ)
                printk(KERN_CONT "F8MHZ ");
-        if (type & MTS)
+       if (type & MTS)
                printk(KERN_CONT "MTS ");
-        if (type & D2620)
+       if (type & D2620)
                printk(KERN_CONT "D2620 ");
-        if (type & D2633)
+       if (type & D2633)
                printk(KERN_CONT "D2633 ");
-        if (type & DTV6)
+       if (type & DTV6)
                printk(KERN_CONT "DTV6 ");
-        if (type & QAM)
+       if (type & QAM)
                printk(KERN_CONT "QAM ");
-        if (type & DTV7)
+       if (type & DTV7)
                printk(KERN_CONT "DTV7 ");
-        if (type & DTV78)
+       if (type & DTV78)
                printk(KERN_CONT "DTV78 ");
-        if (type & DTV8)
+       if (type & DTV8)
                printk(KERN_CONT "DTV8 ");
-        if (type & FM)
+       if (type & FM)
                printk(KERN_CONT "FM ");
-        if (type & INPUT1)
+       if (type & INPUT1)
                printk(KERN_CONT "INPUT1 ");
-        if (type & LCD)
+       if (type & LCD)
                printk(KERN_CONT "LCD ");
-        if (type & NOGD)
+       if (type & NOGD)
                printk(KERN_CONT "NOGD ");
-        if (type & MONO)
+       if (type & MONO)
                printk(KERN_CONT "MONO ");
-        if (type & ATSC)
+       if (type & ATSC)
                printk(KERN_CONT "ATSC ");
-        if (type & IF)
+       if (type & IF)
                printk(KERN_CONT "IF ");
-        if (type & LG60)
+       if (type & LG60)
                printk(KERN_CONT "LG60 ");
-        if (type & ATI638)
+       if (type & ATI638)
                printk(KERN_CONT "ATI638 ");
-        if (type & OREN538)
+       if (type & OREN538)
                printk(KERN_CONT "OREN538 ");
-        if (type & OREN36)
+       if (type & OREN36)
                printk(KERN_CONT "OREN36 ");
-        if (type & TOYOTA388)
+       if (type & TOYOTA388)
                printk(KERN_CONT "TOYOTA388 ");
-        if (type & TOYOTA794)
+       if (type & TOYOTA794)
                printk(KERN_CONT "TOYOTA794 ");
-        if (type & DIBCOM52)
+       if (type & DIBCOM52)
                printk(KERN_CONT "DIBCOM52 ");
-        if (type & ZARLINK456)
+       if (type & ZARLINK456)
                printk(KERN_CONT "ZARLINK456 ");
-        if (type & CHINA)
+       if (type & CHINA)
                printk(KERN_CONT "CHINA ");
-        if (type & F6MHZ)
+       if (type & F6MHZ)
                printk(KERN_CONT "F6MHZ ");
-        if (type & INPUT2)
+       if (type & INPUT2)
                printk(KERN_CONT "INPUT2 ");
-        if (type & SCODE)
+       if (type & SCODE)
                printk(KERN_CONT "SCODE ");
-        if (type & HAS_IF)
+       if (type & HAS_IF)
                printk(KERN_CONT "HAS_IF_%d ", int_freq);
 }
 
index e135760f7d486d5bb6061fb0452bbbb5f87545af..e44c8aba6074c0667181d9e7a7daab2f7db4d1bc 100644 (file)
@@ -59,6 +59,7 @@ struct xc5000_priv {
        u32 freq_hz, freq_offset;
        u32 bandwidth;
        u8  video_standard;
+       unsigned int mode;
        u8  rf_mode;
        u8  radio_input;
 
@@ -69,6 +70,8 @@ struct xc5000_priv {
 
        struct dvb_frontend *fe;
        struct delayed_work timer_sleep;
+
+       const struct firmware   *firmware;
 };
 
 /* Misc Defines */
@@ -712,9 +715,50 @@ static void xc_debug_dump(struct xc5000_priv *priv)
        }
 }
 
-static int xc5000_set_params(struct dvb_frontend *fe)
+static int xc5000_tune_digital(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret;
+       u32 bw = fe->dtv_property_cache.bandwidth_hz;
+
+       ret = xc_set_signal_source(priv, priv->rf_mode);
+       if (ret != 0) {
+               printk(KERN_ERR
+                       "xc5000: xc_set_signal_source(%d) failed\n",
+                       priv->rf_mode);
+               return -EREMOTEIO;
+       }
+
+       ret = xc_set_tv_standard(priv,
+               xc5000_standard[priv->video_standard].video_mode,
+               xc5000_standard[priv->video_standard].audio_mode, 0);
+       if (ret != 0) {
+               printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n");
+               return -EREMOTEIO;
+       }
+
+       ret = xc_set_IF_frequency(priv, priv->if_khz);
+       if (ret != 0) {
+               printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
+                      priv->if_khz);
+               return -EIO;
+       }
+
+       xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a);
+
+       xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
+
+       if (debug)
+               xc_debug_dump(priv);
+
+       priv->bandwidth = bw;
+
+       return 0;
+}
+
+static int xc5000_set_digital_params(struct dvb_frontend *fe)
 {
-       int ret, b;
+       int b;
        struct xc5000_priv *priv = fe->tuner_priv;
        u32 bw = fe->dtv_property_cache.bandwidth_hz;
        u32 freq = fe->dtv_property_cache.frequency;
@@ -794,43 +838,12 @@ static int xc5000_set_params(struct dvb_frontend *fe)
        }
 
        priv->freq_hz = freq - priv->freq_offset;
+       priv->mode = V4L2_TUNER_DIGITAL_TV;
 
        dprintk(1, "%s() frequency=%d (compensated to %d)\n",
                __func__, freq, priv->freq_hz);
 
-       ret = xc_set_signal_source(priv, priv->rf_mode);
-       if (ret != 0) {
-               printk(KERN_ERR
-                       "xc5000: xc_set_signal_source(%d) failed\n",
-                       priv->rf_mode);
-               return -EREMOTEIO;
-       }
-
-       ret = xc_set_tv_standard(priv,
-               xc5000_standard[priv->video_standard].video_mode,
-               xc5000_standard[priv->video_standard].audio_mode, 0);
-       if (ret != 0) {
-               printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n");
-               return -EREMOTEIO;
-       }
-
-       ret = xc_set_IF_frequency(priv, priv->if_khz);
-       if (ret != 0) {
-               printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
-                      priv->if_khz);
-               return -EIO;
-       }
-
-       xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a);
-
-       xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
-
-       if (debug)
-               xc_debug_dump(priv);
-
-       priv->bandwidth = bw;
-
-       return 0;
+       return xc5000_tune_digital(fe);
 }
 
 static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
@@ -852,12 +865,10 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
        return ret;
 }
 
-static int xc5000_set_tv_freq(struct dvb_frontend *fe,
-       struct analog_parameters *params)
+static void xc5000_config_tv(struct dvb_frontend *fe,
+                            struct analog_parameters *params)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
-       u16 pll_lock_status;
-       int ret;
 
        dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
                __func__, params->frequency);
@@ -876,42 +887,49 @@ static int xc5000_set_tv_freq(struct dvb_frontend *fe,
        if (params->std & V4L2_STD_MN) {
                /* default to BTSC audio standard */
                priv->video_standard = MN_NTSC_PAL_BTSC;
-               goto tune_channel;
+               return;
        }
 
        if (params->std & V4L2_STD_PAL_BG) {
                /* default to NICAM audio standard */
                priv->video_standard = BG_PAL_NICAM;
-               goto tune_channel;
+               return;
        }
 
        if (params->std & V4L2_STD_PAL_I) {
                /* default to NICAM audio standard */
                priv->video_standard = I_PAL_NICAM;
-               goto tune_channel;
+               return;
        }
 
        if (params->std & V4L2_STD_PAL_DK) {
                /* default to NICAM audio standard */
                priv->video_standard = DK_PAL_NICAM;
-               goto tune_channel;
+               return;
        }
 
        if (params->std & V4L2_STD_SECAM_DK) {
                /* default to A2 DK1 audio standard */
                priv->video_standard = DK_SECAM_A2DK1;
-               goto tune_channel;
+               return;
        }
 
        if (params->std & V4L2_STD_SECAM_L) {
                priv->video_standard = L_SECAM_NICAM;
-               goto tune_channel;
+               return;
        }
 
        if (params->std & V4L2_STD_SECAM_LC) {
                priv->video_standard = LC_SECAM_NICAM;
-               goto tune_channel;
+               return;
        }
+}
+
+static int xc5000_set_tv_freq(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       u16 pll_lock_status;
+       int ret;
 
 tune_channel:
        ret = xc_set_signal_source(priv, priv->rf_mode);
@@ -955,12 +973,11 @@ tune_channel:
        return 0;
 }
 
-static int xc5000_set_radio_freq(struct dvb_frontend *fe,
-       struct analog_parameters *params)
+static int xc5000_config_radio(struct dvb_frontend *fe,
+                              struct analog_parameters *params)
+
 {
        struct xc5000_priv *priv = fe->tuner_priv;
-       int ret = -EINVAL;
-       u8 radio_input;
 
        dprintk(1, "%s() frequency=%d (in units of khz)\n",
                __func__, params->frequency);
@@ -970,6 +987,18 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe,
                return -EINVAL;
        }
 
+       priv->freq_hz = params->frequency * 125 / 2;
+       priv->rf_mode = XC_RF_MODE_AIR;
+
+       return 0;
+}
+
+static int xc5000_set_radio_freq(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret;
+       u8 radio_input;
+
        if (priv->radio_input == XC5000_RADIO_FM1)
                radio_input = FM_RADIO_INPUT1;
        else if  (priv->radio_input == XC5000_RADIO_FM2)
@@ -982,10 +1011,6 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe,
                return -EINVAL;
        }
 
-       priv->freq_hz = params->frequency * 125 / 2;
-
-       priv->rf_mode = XC_RF_MODE_AIR;
-
        ret = xc_set_tv_standard(priv, xc5000_standard[radio_input].video_mode,
                               xc5000_standard[radio_input].audio_mode, radio_input);
 
@@ -1013,34 +1038,53 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe,
        return 0;
 }
 
-static int xc5000_set_analog_params(struct dvb_frontend *fe,
-                            struct analog_parameters *params)
+static int xc5000_set_params(struct dvb_frontend *fe)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
-       int ret = -EINVAL;
-
-       if (priv->i2c_props.adap == NULL)
-               return -EINVAL;
 
        if (xc_load_fw_and_init_tuner(fe, 0) != 0) {
                dprintk(1, "Unable to load firmware and init tuner\n");
                return -EINVAL;
        }
 
+       switch (priv->mode) {
+       case V4L2_TUNER_RADIO:
+               return xc5000_set_radio_freq(fe);
+       case V4L2_TUNER_ANALOG_TV:
+               return xc5000_set_tv_freq(fe);
+       case V4L2_TUNER_DIGITAL_TV:
+               return xc5000_tune_digital(fe);
+       }
+
+       return 0;
+}
+
+static int xc5000_set_analog_params(struct dvb_frontend *fe,
+                            struct analog_parameters *params)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret;
+
+       if (priv->i2c_props.adap == NULL)
+               return -EINVAL;
+
        switch (params->mode) {
        case V4L2_TUNER_RADIO:
-               ret = xc5000_set_radio_freq(fe, params);
+               ret = xc5000_config_radio(fe, params);
+               if (ret)
+                       return ret;
                break;
        case V4L2_TUNER_ANALOG_TV:
-       case V4L2_TUNER_DIGITAL_TV:
-               ret = xc5000_set_tv_freq(fe, params);
+               xc5000_config_tv(fe, params);
+               break;
+       default:
                break;
        }
+       priv->mode = params->mode;
 
-       return ret;
+       return xc5000_set_params(fe);
 }
 
-
 static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
@@ -1094,20 +1138,23 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force)
        if (!force && xc5000_is_firmware_loaded(fe) == 0)
                return 0;
 
-       ret = request_firmware(&fw, desired_fw->name,
-                              priv->i2c_props.adap->dev.parent);
-       if (ret) {
-               printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
-               return ret;
-       }
-
-       dprintk(1, "firmware read %Zu bytes.\n", fw->size);
+       if (!priv->firmware) {
+               ret = request_firmware(&fw, desired_fw->name,
+                                       priv->i2c_props.adap->dev.parent);
+               if (ret) {
+                       pr_err("xc5000: Upload failed. rc %d\n", ret);
+                       return ret;
+               }
+               dprintk(1, "firmware read %Zu bytes.\n", fw->size);
 
-       if (fw->size != desired_fw->size) {
-               printk(KERN_ERR "xc5000: Firmware file with incorrect size\n");
-               ret = -EINVAL;
-               goto err;
-       }
+               if (fw->size != desired_fw->size) {
+                       pr_err("xc5000: Firmware file with incorrect size\n");
+                       release_firmware(fw);
+                       return -EINVAL;
+               }
+               priv->firmware = fw;
+       } else
+               fw = priv->firmware;
 
        /* Try up to 5 times to load firmware */
        for (i = 0; i < 5; i++) {
@@ -1190,7 +1237,6 @@ err:
        else
                printk(KERN_CONT " - too many retries. Giving up\n");
 
-       release_firmware(fw);
        return ret;
 }
 
@@ -1229,6 +1275,38 @@ static int xc5000_sleep(struct dvb_frontend *fe)
        return 0;
 }
 
+static int xc5000_suspend(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret;
+
+       dprintk(1, "%s()\n", __func__);
+
+       cancel_delayed_work(&priv->timer_sleep);
+
+       ret = xc5000_tuner_reset(fe);
+       if (ret != 0)
+               printk(KERN_ERR
+                       "xc5000: %s() unable to shutdown tuner\n",
+                       __func__);
+
+       return 0;
+}
+
+static int xc5000_resume(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+
+       dprintk(1, "%s()\n", __func__);
+
+       /* suspended before firmware is loaded.
+          Avoid firmware load in resume path. */
+       if (!priv->firmware)
+               return 0;
+
+       return xc5000_set_params(fe);
+}
+
 static int xc5000_init(struct dvb_frontend *fe)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
@@ -1256,6 +1334,8 @@ static int xc5000_release(struct dvb_frontend *fe)
        if (priv) {
                cancel_delayed_work(&priv->timer_sleep);
                hybrid_tuner_release_state(priv);
+               if (priv->firmware)
+                       release_firmware(priv->firmware);
        }
 
        mutex_unlock(&xc5000_list_mutex);
@@ -1293,9 +1373,11 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
        .release           = xc5000_release,
        .init              = xc5000_init,
        .sleep             = xc5000_sleep,
+       .suspend           = xc5000_suspend,
+       .resume            = xc5000_resume,
 
        .set_config        = xc5000_set_config,
-       .set_params        = xc5000_set_params,
+       .set_params        = xc5000_set_digital_params,
        .set_analog_params = xc5000_set_analog_params,
        .get_frequency     = xc5000_get_frequency,
        .get_if_frequency  = xc5000_get_if_frequency,
index 94d51e092db34a4df56fb49570dd5e2de3af0895..056181f2f5694864be2740c05f95069e8aa923d1 100644 (file)
@@ -46,6 +46,7 @@ source "drivers/media/usb/ttusb-budget/Kconfig"
 source "drivers/media/usb/ttusb-dec/Kconfig"
 source "drivers/media/usb/siano/Kconfig"
 source "drivers/media/usb/b2c2/Kconfig"
+source "drivers/media/usb/as102/Kconfig"
 endif
 
 if (MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT)
@@ -55,8 +56,9 @@ endif
 
 if MEDIA_SDR_SUPPORT
        comment "Software defined radio USB devices"
-source "drivers/media/usb/msi2500/Kconfig"
 source "drivers/media/usb/airspy/Kconfig"
+source "drivers/media/usb/hackrf/Kconfig"
+source "drivers/media/usb/msi2500/Kconfig"
 endif
 
 endif #MEDIA_USB_SUPPORT
index f438efffefc59e027a1241fc7a30b42774b416c8..6f2eb7c8416c47844eeb2977122f554b0513668c 100644 (file)
@@ -9,8 +9,9 @@ obj-y += zr364xx/ stkwebcam/ s2255/
 obj-$(CONFIG_USB_VIDEO_CLASS)  += uvc/
 obj-$(CONFIG_USB_GSPCA)         += gspca/
 obj-$(CONFIG_USB_PWC)           += pwc/
-obj-$(CONFIG_USB_MSI2500)       += msi2500/
 obj-$(CONFIG_USB_AIRSPY)        += airspy/
+obj-$(CONFIG_USB_HACKRF)        += hackrf/
+obj-$(CONFIG_USB_MSI2500)       += msi2500/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 obj-$(CONFIG_VIDEO_HDPVR)      += hdpvr/
@@ -23,3 +24,4 @@ obj-$(CONFIG_VIDEO_TM6000) += tm6000/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_USBTV) += usbtv/
 obj-$(CONFIG_VIDEO_GO7007) += go7007/
+obj-$(CONFIG_DVB_AS102) += as102/
index cb0e515d80ae378e7e26edecfa196c4024d7dd4b..4069234abed5432c7fbf2f867da9c0235d4eba37 100644 (file)
@@ -107,6 +107,7 @@ struct airspy {
 #define USB_STATE_URB_BUF  (1 << 3)
        unsigned long flags;
 
+       struct device *dev;
        struct usb_device *udev;
        struct video_device vdev;
        struct v4l2_device v4l2_dev;
@@ -154,16 +155,15 @@ struct airspy {
        unsigned int sample_measured;
 };
 
-#define airspy_dbg_usb_control_msg(_udev, _r, _t, _v, _i, _b, _l) { \
+#define airspy_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \
        char *_direction; \
        if (_t & USB_DIR_IN) \
                _direction = "<<<"; \
        else \
                _direction = ">>>"; \
-       dev_dbg(&_udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \
-                       "%s %*ph\n",  __func__, _t, _r, _v & 0xff, _v >> 8, \
-                       _i & 0xff, _i >> 8, _l & 0xff, _l >> 8, _direction, \
-                       _l, _b); \
+       dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \
+                       _t, _r, _v & 0xff, _v >> 8, _i & 0xff, _i >> 8, \
+                       _l & 0xff, _l >> 8, _direction, _l, _b); \
 }
 
 /* execute firmware command */
@@ -192,7 +192,7 @@ static int airspy_ctrl_msg(struct airspy *s, u8 request, u16 value, u16 index,
                requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
                break;
        default:
-               dev_err(&s->udev->dev, "Unknown command %02x\n", request);
+               dev_err(s->dev, "Unknown command %02x\n", request);
                ret = -EINVAL;
                goto err;
        }
@@ -203,11 +203,10 @@ static int airspy_ctrl_msg(struct airspy *s, u8 request, u16 value, u16 index,
 
        ret = usb_control_msg(s->udev, pipe, request, requesttype, value,
                        index, s->buf, size, 1000);
-       airspy_dbg_usb_control_msg(s->udev, request, requesttype, value,
+       airspy_dbg_usb_control_msg(s->dev, request, requesttype, value,
                        index, s->buf, size);
        if (ret < 0) {
-               dev_err(&s->udev->dev,
-                               "usb_control_msg() failed %d request %02x\n",
+               dev_err(s->dev, "usb_control_msg() failed %d request %02x\n",
                                ret, request);
                goto err;
        }
@@ -224,7 +223,7 @@ err:
 /* Private functions */
 static struct airspy_frame_buf *airspy_get_next_fill_buf(struct airspy *s)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
        struct airspy_frame_buf *buf = NULL;
 
        spin_lock_irqsave(&s->queued_bufs_lock, flags);
@@ -251,16 +250,18 @@ static unsigned int airspy_convert_stream(struct airspy *s,
                dst_len = 0;
        }
 
-       /* calculate samping rate and output it in 10 seconds intervals */
+       /* calculate sample rate and output it in 10 seconds intervals */
        if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
                #define MSECS 10000UL
+               unsigned int msecs = jiffies_to_msecs(jiffies -
+                               s->jiffies_next + msecs_to_jiffies(MSECS));
                unsigned int samples = s->sample - s->sample_measured;
+
                s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
                s->sample_measured = s->sample;
-               dev_dbg(&s->udev->dev,
-                               "slen=%d samples=%u msecs=%lu sample rate=%lu\n",
-                               src_len, samples, MSECS,
-                               samples * 1000UL / MSECS);
+               dev_dbg(s->dev, "slen=%u samples=%u msecs=%u sample rate=%lu\n",
+                               src_len, samples, msecs,
+                               samples * 1000UL / msecs);
        }
 
        /* total number of samples */
@@ -278,9 +279,8 @@ static void airspy_urb_complete(struct urb *urb)
        struct airspy *s = urb->context;
        struct airspy_frame_buf *fbuf;
 
-       dev_dbg_ratelimited(&s->udev->dev,
-                       "%s: status=%d length=%d/%d errors=%d\n",
-                       __func__, urb->status, urb->actual_length,
+       dev_dbg_ratelimited(s->dev, "status=%d length=%d/%d errors=%d\n",
+                       urb->status, urb->actual_length,
                        urb->transfer_buffer_length, urb->error_count);
 
        switch (urb->status) {
@@ -292,8 +292,7 @@ static void airspy_urb_complete(struct urb *urb)
        case -ESHUTDOWN:
                return;
        default:            /* error */
-               dev_err_ratelimited(&s->udev->dev, "URB failed %d\n",
-                               urb->status);
+               dev_err_ratelimited(s->dev, "URB failed %d\n", urb->status);
                break;
        }
 
@@ -304,7 +303,7 @@ static void airspy_urb_complete(struct urb *urb)
                fbuf = airspy_get_next_fill_buf(s);
                if (unlikely(fbuf == NULL)) {
                        s->vb_full++;
-                       dev_notice_ratelimited(&s->udev->dev,
+                       dev_notice_ratelimited(s->dev,
                                        "videobuf is full, %d packets dropped\n",
                                        s->vb_full);
                        goto skip;
@@ -328,7 +327,7 @@ static int airspy_kill_urbs(struct airspy *s)
        int i;
 
        for (i = s->urbs_submitted - 1; i >= 0; i--) {
-               dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i);
+               dev_dbg(s->dev, "kill urb=%d\n", i);
                /* stop the URB */
                usb_kill_urb(s->urb_list[i]);
        }
@@ -342,11 +341,10 @@ static int airspy_submit_urbs(struct airspy *s)
        int i, ret;
 
        for (i = 0; i < s->urbs_initialized; i++) {
-               dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i);
+               dev_dbg(s->dev, "submit urb=%d\n", i);
                ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC);
                if (ret) {
-                       dev_err(&s->udev->dev,
-                                       "Could not submit URB no. %d - get them all back\n",
+                       dev_err(s->dev, "Could not submit URB no. %d - get them all back\n",
                                        i);
                        airspy_kill_urbs(s);
                        return ret;
@@ -362,8 +360,7 @@ static int airspy_free_stream_bufs(struct airspy *s)
        if (s->flags & USB_STATE_URB_BUF) {
                while (s->buf_num) {
                        s->buf_num--;
-                       dev_dbg(&s->udev->dev, "%s: free buf=%d\n",
-                                       __func__, s->buf_num);
+                       dev_dbg(s->dev, "free buf=%d\n", s->buf_num);
                        usb_free_coherent(s->udev, s->buf_size,
                                          s->buf_list[s->buf_num],
                                          s->dma_addr[s->buf_num]);
@@ -379,23 +376,20 @@ static int airspy_alloc_stream_bufs(struct airspy *s)
        s->buf_num = 0;
        s->buf_size = BULK_BUFFER_SIZE;
 
-       dev_dbg(&s->udev->dev,
-                       "%s: all in all I will use %u bytes for streaming\n",
-                       __func__,  MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+       dev_dbg(s->dev, "all in all I will use %u bytes for streaming\n",
+                       MAX_BULK_BUFS * BULK_BUFFER_SIZE);
 
        for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) {
                s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev,
                                BULK_BUFFER_SIZE, GFP_ATOMIC,
                                &s->dma_addr[s->buf_num]);
                if (!s->buf_list[s->buf_num]) {
-                       dev_dbg(&s->udev->dev, "%s: alloc buf=%d failed\n",
-                                       __func__, s->buf_num);
+                       dev_dbg(s->dev, "alloc buf=%d failed\n", s->buf_num);
                        airspy_free_stream_bufs(s);
                        return -ENOMEM;
                }
 
-               dev_dbg(&s->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
-                               __func__, s->buf_num,
+               dev_dbg(s->dev, "alloc buf=%d %p (dma %llu)\n", s->buf_num,
                                s->buf_list[s->buf_num],
                                (long long)s->dma_addr[s->buf_num]);
                s->flags |= USB_STATE_URB_BUF;
@@ -412,8 +406,7 @@ static int airspy_free_urbs(struct airspy *s)
 
        for (i = s->urbs_initialized - 1; i >= 0; i--) {
                if (s->urb_list[i]) {
-                       dev_dbg(&s->udev->dev, "%s: free urb=%d\n",
-                                       __func__, i);
+                       dev_dbg(s->dev, "free urb=%d\n", i);
                        /* free the URBs */
                        usb_free_urb(s->urb_list[i]);
                }
@@ -429,10 +422,10 @@ static int airspy_alloc_urbs(struct airspy *s)
 
        /* allocate the URBs */
        for (i = 0; i < MAX_BULK_BUFS; i++) {
-               dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+               dev_dbg(s->dev, "alloc urb=%d\n", i);
                s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
                if (!s->urb_list[i]) {
-                       dev_dbg(&s->udev->dev, "%s: failed\n", __func__);
+                       dev_dbg(s->dev, "failed\n");
                        for (j = 0; j < i; j++)
                                usb_free_urb(s->urb_list[j]);
                        return -ENOMEM;
@@ -455,13 +448,14 @@ static int airspy_alloc_urbs(struct airspy *s)
 /* Must be called with vb_queue_lock hold */
 static void airspy_cleanup_queued_bufs(struct airspy *s)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        spin_lock_irqsave(&s->queued_bufs_lock, flags);
        while (!list_empty(&s->queued_bufs)) {
                struct airspy_frame_buf *buf;
+
                buf = list_entry(s->queued_bufs.next,
                                struct airspy_frame_buf, list);
                list_del(&buf->list);
@@ -476,7 +470,7 @@ static void airspy_disconnect(struct usb_interface *intf)
        struct v4l2_device *v = usb_get_intfdata(intf);
        struct airspy *s = container_of(v, struct airspy, v4l2_dev);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        mutex_lock(&s->vb_queue_lock);
        mutex_lock(&s->v4l2_lock);
@@ -497,7 +491,7 @@ static int airspy_queue_setup(struct vb2_queue *vq,
 {
        struct airspy *s = vb2_get_drv_priv(vq);
 
-       dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
+       dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers);
 
        /* Need at least 8 buffers */
        if (vq->num_buffers + *nbuffers < 8)
@@ -505,8 +499,7 @@ static int airspy_queue_setup(struct vb2_queue *vq,
        *nplanes = 1;
        sizes[0] = PAGE_ALIGN(s->buffersize);
 
-       dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
-                       __func__, *nbuffers, sizes[0]);
+       dev_dbg(s->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
        return 0;
 }
 
@@ -515,7 +508,7 @@ static void airspy_buf_queue(struct vb2_buffer *vb)
        struct airspy *s = vb2_get_drv_priv(vb->vb2_queue);
        struct airspy_frame_buf *buf =
                        container_of(vb, struct airspy_frame_buf, vb);
-       unsigned long flags = 0;
+       unsigned long flags;
 
        /* Check the device has not disconnected between prep and queuing */
        if (unlikely(!s->udev)) {
@@ -533,34 +526,56 @@ static int airspy_start_streaming(struct vb2_queue *vq, unsigned int count)
        struct airspy *s = vb2_get_drv_priv(vq);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        if (!s->udev)
                return -ENODEV;
 
        mutex_lock(&s->v4l2_lock);
 
-       set_bit(POWER_ON, &s->flags);
-
        s->sequence = 0;
 
+       set_bit(POWER_ON, &s->flags);
+
        ret = airspy_alloc_stream_bufs(s);
        if (ret)
-               goto err;
+               goto err_clear_bit;
 
        ret = airspy_alloc_urbs(s);
        if (ret)
-               goto err;
+               goto err_free_stream_bufs;
 
        ret = airspy_submit_urbs(s);
        if (ret)
-               goto err;
+               goto err_free_urbs;
 
        /* start hardware streaming */
        ret = airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 1, 0, NULL, 0);
        if (ret)
-               goto err;
-err:
+               goto err_kill_urbs;
+
+       goto exit_mutex_unlock;
+
+err_kill_urbs:
+       airspy_kill_urbs(s);
+err_free_urbs:
+       airspy_free_urbs(s);
+err_free_stream_bufs:
+       airspy_free_stream_bufs(s);
+err_clear_bit:
+       clear_bit(POWER_ON, &s->flags);
+
+       /* return all queued buffers to vb2 */
+       {
+               struct airspy_frame_buf *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &s->queued_bufs, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+
+exit_mutex_unlock:
        mutex_unlock(&s->v4l2_lock);
 
        return ret;
@@ -570,7 +585,7 @@ static void airspy_stop_streaming(struct vb2_queue *vq)
 {
        struct airspy *s = vb2_get_drv_priv(vq);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        mutex_lock(&s->v4l2_lock);
 
@@ -602,8 +617,6 @@ static int airspy_querycap(struct file *file, void *fh,
 {
        struct airspy *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
-
        strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
        strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
        usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info));
@@ -617,10 +630,6 @@ static int airspy_querycap(struct file *file, void *fh,
 static int airspy_enum_fmt_sdr_cap(struct file *file, void *priv,
                struct v4l2_fmtdesc *f)
 {
-       struct airspy *s = video_drvdata(file);
-
-       dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, f->index);
-
        if (f->index >= NUM_FORMATS)
                return -EINVAL;
 
@@ -635,9 +644,6 @@ static int airspy_g_fmt_sdr_cap(struct file *file, void *priv,
 {
        struct airspy *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
-                       (char *)&s->pixelformat);
-
        f->fmt.sdr.pixelformat = s->pixelformat;
        f->fmt.sdr.buffersize = s->buffersize;
        memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
@@ -652,9 +658,6 @@ static int airspy_s_fmt_sdr_cap(struct file *file, void *priv,
        struct vb2_queue *q = &s->vb_queue;
        int i;
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
-                       (char *)&f->fmt.sdr.pixelformat);
-
        if (vb2_is_busy(q))
                return -EBUSY;
 
@@ -679,12 +682,8 @@ static int airspy_s_fmt_sdr_cap(struct file *file, void *priv,
 static int airspy_try_fmt_sdr_cap(struct file *file, void *priv,
                struct v4l2_format *f)
 {
-       struct airspy *s = video_drvdata(file);
        int i;
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
-                       (char *)&f->fmt.sdr.pixelformat);
-
        memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        for (i = 0; i < NUM_FORMATS; i++) {
                if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
@@ -702,11 +701,8 @@ static int airspy_try_fmt_sdr_cap(struct file *file, void *priv,
 static int airspy_s_tuner(struct file *file, void *priv,
                const struct v4l2_tuner *v)
 {
-       struct airspy *s = video_drvdata(file);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
-
        if (v->index == 0)
                ret = 0;
        else if (v->index == 1)
@@ -719,11 +715,8 @@ static int airspy_s_tuner(struct file *file, void *priv,
 
 static int airspy_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
 {
-       struct airspy *s = video_drvdata(file);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
-
        if (v->index == 0) {
                strlcpy(v->name, "AirSpy ADC", sizeof(v->name));
                v->type = V4L2_TUNER_ADC;
@@ -749,17 +742,18 @@ static int airspy_g_frequency(struct file *file, void *priv,
                struct v4l2_frequency *f)
 {
        struct airspy *s = video_drvdata(file);
-       int ret  = 0;
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
-                       __func__, f->tuner, f->type);
+       int ret;
 
        if (f->tuner == 0) {
                f->type = V4L2_TUNER_ADC;
                f->frequency = s->f_adc;
+               dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc);
                ret = 0;
        } else if (f->tuner == 1) {
                f->type = V4L2_TUNER_RF;
                f->frequency = s->f_rf;
+               dev_dbg(s->dev, "RF frequency=%u Hz\n", s->f_rf);
+               ret = 0;
        } else {
                ret = -EINVAL;
        }
@@ -774,22 +768,17 @@ static int airspy_s_frequency(struct file *file, void *priv,
        int ret;
        u8 buf[4];
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
-                       __func__, f->tuner, f->type, f->frequency);
-
        if (f->tuner == 0) {
                s->f_adc = clamp_t(unsigned int, f->frequency,
                                bands[0].rangelow,
                                bands[0].rangehigh);
-               dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
-                               __func__, s->f_adc);
+               dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc);
                ret = 0;
        } else if (f->tuner == 1) {
                s->f_rf = clamp_t(unsigned int, f->frequency,
                                bands_rf[0].rangelow,
                                bands_rf[0].rangehigh);
-               dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n",
-                               __func__, s->f_rf);
+               dev_dbg(s->dev, "RF frequency=%u Hz\n", s->f_rf);
                buf[0] = (s->f_rf >>  0) & 0xff;
                buf[1] = (s->f_rf >>  8) & 0xff;
                buf[2] = (s->f_rf >> 16) & 0xff;
@@ -805,10 +794,7 @@ static int airspy_s_frequency(struct file *file, void *priv,
 static int airspy_enum_freq_bands(struct file *file, void *priv,
                struct v4l2_frequency_band *band)
 {
-       struct airspy *s = video_drvdata(file);
        int ret;
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
-                       __func__, band->tuner, band->type, band->index);
 
        if (band->tuner == 0) {
                if (band->index >= ARRAY_SIZE(bands)) {
@@ -892,10 +878,9 @@ static int airspy_set_lna_gain(struct airspy *s)
        int ret;
        u8 u8tmp;
 
-       dev_dbg(&s->udev->dev, "%s: lna auto=%d->%d val=%d->%d\n",
-                       __func__, s->lna_gain_auto->cur.val,
-                       s->lna_gain_auto->val, s->lna_gain->cur.val,
-                       s->lna_gain->val);
+       dev_dbg(s->dev, "lna auto=%d->%d val=%d->%d\n",
+                       s->lna_gain_auto->cur.val, s->lna_gain_auto->val,
+                       s->lna_gain->cur.val, s->lna_gain->val);
 
        ret = airspy_ctrl_msg(s, CMD_SET_LNA_AGC, 0, s->lna_gain_auto->val,
                        &u8tmp, 1);
@@ -910,7 +895,7 @@ static int airspy_set_lna_gain(struct airspy *s)
        }
 err:
        if (ret)
-               dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(s->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -920,10 +905,9 @@ static int airspy_set_mixer_gain(struct airspy *s)
        int ret;
        u8 u8tmp;
 
-       dev_dbg(&s->udev->dev, "%s: mixer auto=%d->%d val=%d->%d\n",
-                       __func__, s->mixer_gain_auto->cur.val,
-                       s->mixer_gain_auto->val, s->mixer_gain->cur.val,
-                       s->mixer_gain->val);
+       dev_dbg(s->dev, "mixer auto=%d->%d val=%d->%d\n",
+                       s->mixer_gain_auto->cur.val, s->mixer_gain_auto->val,
+                       s->mixer_gain->cur.val, s->mixer_gain->val);
 
        ret = airspy_ctrl_msg(s, CMD_SET_MIXER_AGC, 0, s->mixer_gain_auto->val,
                        &u8tmp, 1);
@@ -938,7 +922,7 @@ static int airspy_set_mixer_gain(struct airspy *s)
        }
 err:
        if (ret)
-               dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(s->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -948,8 +932,7 @@ static int airspy_set_if_gain(struct airspy *s)
        int ret;
        u8 u8tmp;
 
-       dev_dbg(&s->udev->dev, "%s: val=%d->%d\n",
-                       __func__, s->if_gain->cur.val, s->if_gain->val);
+       dev_dbg(s->dev, "val=%d->%d\n", s->if_gain->cur.val, s->if_gain->val);
 
        ret = airspy_ctrl_msg(s, CMD_SET_VGA_GAIN, 0, s->if_gain->val,
                        &u8tmp, 1);
@@ -957,7 +940,7 @@ static int airspy_set_if_gain(struct airspy *s)
                goto err;
 err:
        if (ret)
-               dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(s->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -980,8 +963,8 @@ static int airspy_s_ctrl(struct v4l2_ctrl *ctrl)
                ret = airspy_set_if_gain(s);
                break;
        default:
-               dev_dbg(&s->udev->dev, "%s: unknown ctrl: id=%d name=%s\n",
-                               __func__, ctrl->id, ctrl->name);
+               dev_dbg(s->dev, "unknown ctrl: id=%d name=%s\n",
+                               ctrl->id, ctrl->name);
                ret = -EINVAL;
        }
 
@@ -995,15 +978,13 @@ static const struct v4l2_ctrl_ops airspy_ctrl_ops = {
 static int airspy_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct airspy *s = NULL;
+       struct airspy *s;
        int ret;
        u8 u8tmp, buf[BUF_SIZE];
 
        s = kzalloc(sizeof(struct airspy), GFP_KERNEL);
        if (s == NULL) {
-               dev_err(&udev->dev,
-                               "Could not allocate memory for airspy state\n");
+               dev_err(&intf->dev, "Could not allocate memory for state\n");
                return -ENOMEM;
        }
 
@@ -1011,7 +992,8 @@ static int airspy_probe(struct usb_interface *intf,
        mutex_init(&s->vb_queue_lock);
        spin_lock_init(&s->queued_bufs_lock);
        INIT_LIST_HEAD(&s->queued_bufs);
-       s->udev = udev;
+       s->dev = &intf->dev;
+       s->udev = interface_to_usbdev(intf);
        s->f_adc = bands[0].rangelow;
        s->f_rf = bands_rf[0].rangelow;
        s->pixelformat = formats[0].pixelformat;
@@ -1023,14 +1005,14 @@ static int airspy_probe(struct usb_interface *intf,
                ret = airspy_ctrl_msg(s, CMD_VERSION_STRING_READ, 0, 0,
                                buf, BUF_SIZE);
        if (ret) {
-               dev_err(&s->udev->dev, "Could not detect board\n");
+               dev_err(s->dev, "Could not detect board\n");
                goto err_free_mem;
        }
 
        buf[BUF_SIZE - 1] = '\0';
 
-       dev_info(&s->udev->dev, "Board ID: %02x\n", u8tmp);
-       dev_info(&s->udev->dev, "Firmware version: %s\n", buf);
+       dev_info(s->dev, "Board ID: %02x\n", u8tmp);
+       dev_info(s->dev, "Firmware version: %s\n", buf);
 
        /* Init videobuf2 queue structure */
        s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
@@ -1042,7 +1024,7 @@ static int airspy_probe(struct usb_interface *intf,
        s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
        ret = vb2_queue_init(&s->vb_queue);
        if (ret) {
-               dev_err(&s->udev->dev, "Could not initialize vb2 queue\n");
+               dev_err(s->dev, "Could not initialize vb2 queue\n");
                goto err_free_mem;
        }
 
@@ -1056,8 +1038,7 @@ static int airspy_probe(struct usb_interface *intf,
        s->v4l2_dev.release = airspy_video_release;
        ret = v4l2_device_register(&intf->dev, &s->v4l2_dev);
        if (ret) {
-               dev_err(&s->udev->dev,
-                               "Failed to register v4l2-device (%d)\n", ret);
+               dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret);
                goto err_free_mem;
        }
 
@@ -1077,7 +1058,7 @@ static int airspy_probe(struct usb_interface *intf,
                        V4L2_CID_RF_TUNER_IF_GAIN, 0, 15, 1, 0);
        if (s->hdl.error) {
                ret = s->hdl.error;
-               dev_err(&s->udev->dev, "Could not initialize controls\n");
+               dev_err(s->dev, "Could not initialize controls\n");
                goto err_free_controls;
        }
 
@@ -1089,16 +1070,13 @@ static int airspy_probe(struct usb_interface *intf,
 
        ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
        if (ret) {
-               dev_err(&s->udev->dev,
-                               "Failed to register as video device (%d)\n",
+               dev_err(s->dev, "Failed to register as video device (%d)\n",
                                ret);
                goto err_unregister_v4l2_dev;
        }
-       dev_info(&s->udev->dev, "Registered as %s\n",
+       dev_info(s->dev, "Registered as %s\n",
                        video_device_node_name(&s->vdev));
-       dev_notice(&s->udev->dev,
-                       "%s: SDR API is still slightly experimental and functionality changes may follow\n",
-                       KBUILD_MODNAME);
+       dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
        return 0;
 
 err_free_controls:
diff --git a/drivers/media/usb/as102/Kconfig b/drivers/media/usb/as102/Kconfig
new file mode 100644 (file)
index 0000000..28aba00
--- /dev/null
@@ -0,0 +1,8 @@
+config DVB_AS102
+       tristate "Abilis AS102 DVB receiver"
+       depends on DVB_CORE && USB && I2C && INPUT
+       select FW_LOADER
+       help
+         Choose Y or M here if you have a device containing an AS102
+
+         To compile this driver as a module, choose M here
diff --git a/drivers/media/usb/as102/Makefile b/drivers/media/usb/as102/Makefile
new file mode 100644 (file)
index 0000000..22f43ee
--- /dev/null
@@ -0,0 +1,7 @@
+dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \
+                 as102_usb_drv.o as10x_cmd_cfg.o
+
+obj-$(CONFIG_DVB_AS102) += dvb-as102.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/usb/as102/as102_drv.c b/drivers/media/usb/as102/as102_drv.c
new file mode 100644 (file)
index 0000000..8be1474
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/kref.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+/* header file for usb device driver*/
+#include "as102_drv.h"
+#include "as10x_cmd.h"
+#include "as102_fe.h"
+#include "as102_fw.h"
+#include "dvbdev.h"
+
+int dual_tuner;
+module_param_named(dual_tuner, dual_tuner, int, 0644);
+MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)");
+
+static int fw_upload = 1;
+module_param_named(fw_upload, fw_upload, int, 0644);
+MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)");
+
+static int pid_filtering;
+module_param_named(pid_filtering, pid_filtering, int, 0644);
+MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)");
+
+static int ts_auto_disable;
+module_param_named(ts_auto_disable, ts_auto_disable, int, 0644);
+MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)");
+
+int elna_enable = 1;
+module_param_named(elna_enable, elna_enable, int, 0644);
+MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static void as102_stop_stream(struct as102_dev_t *dev)
+{
+       struct as10x_bus_adapter_t *bus_adap;
+
+       if (dev != NULL)
+               bus_adap = &dev->bus_adap;
+       else
+               return;
+
+       if (bus_adap->ops->stop_stream != NULL)
+               bus_adap->ops->stop_stream(dev);
+
+       if (ts_auto_disable) {
+               if (mutex_lock_interruptible(&dev->bus_adap.lock))
+                       return;
+
+               if (as10x_cmd_stop_streaming(bus_adap) < 0)
+                       dev_dbg(&dev->bus_adap.usb_dev->dev,
+                               "as10x_cmd_stop_streaming failed\n");
+
+               mutex_unlock(&dev->bus_adap.lock);
+       }
+}
+
+static int as102_start_stream(struct as102_dev_t *dev)
+{
+       struct as10x_bus_adapter_t *bus_adap;
+       int ret = -EFAULT;
+
+       if (dev != NULL)
+               bus_adap = &dev->bus_adap;
+       else
+               return ret;
+
+       if (bus_adap->ops->start_stream != NULL)
+               ret = bus_adap->ops->start_stream(dev);
+
+       if (ts_auto_disable) {
+               if (mutex_lock_interruptible(&dev->bus_adap.lock))
+                       return -EFAULT;
+
+               ret = as10x_cmd_start_streaming(bus_adap);
+
+               mutex_unlock(&dev->bus_adap.lock);
+       }
+
+       return ret;
+}
+
+static int as10x_pid_filter(struct as102_dev_t *dev,
+                           int index, u16 pid, int onoff) {
+
+       struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap;
+       int ret = -EFAULT;
+
+       if (mutex_lock_interruptible(&dev->bus_adap.lock)) {
+               dev_dbg(&dev->bus_adap.usb_dev->dev,
+                       "amutex_lock_interruptible(lock) failed !\n");
+               return -EBUSY;
+       }
+
+       switch (onoff) {
+       case 0:
+               ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid);
+               dev_dbg(&dev->bus_adap.usb_dev->dev,
+                       "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n",
+                       index, pid, ret);
+               break;
+       case 1:
+       {
+               struct as10x_ts_filter filter;
+
+               filter.type = TS_PID_TYPE_TS;
+               filter.idx = 0xFF;
+               filter.pid = pid;
+
+               ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
+               dev_dbg(&dev->bus_adap.usb_dev->dev,
+                       "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
+                       index, filter.idx, filter.pid, ret);
+               break;
+       }
+       }
+
+       mutex_unlock(&dev->bus_adap.lock);
+       return ret;
+}
+
+static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       int ret = 0;
+       struct dvb_demux *demux = dvbdmxfeed->demux;
+       struct as102_dev_t *as102_dev = demux->priv;
+
+       if (mutex_lock_interruptible(&as102_dev->sem))
+               return -ERESTARTSYS;
+
+       if (pid_filtering)
+               as10x_pid_filter(as102_dev, dvbdmxfeed->index,
+                                dvbdmxfeed->pid, 1);
+
+       if (as102_dev->streaming++ == 0)
+               ret = as102_start_stream(as102_dev);
+
+       mutex_unlock(&as102_dev->sem);
+       return ret;
+}
+
+static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct dvb_demux *demux = dvbdmxfeed->demux;
+       struct as102_dev_t *as102_dev = demux->priv;
+
+       if (mutex_lock_interruptible(&as102_dev->sem))
+               return -ERESTARTSYS;
+
+       if (--as102_dev->streaming == 0)
+               as102_stop_stream(as102_dev);
+
+       if (pid_filtering)
+               as10x_pid_filter(as102_dev, dvbdmxfeed->index,
+                                dvbdmxfeed->pid, 0);
+
+       mutex_unlock(&as102_dev->sem);
+       return 0;
+}
+
+static int as102_set_tune(void *priv, struct as10x_tune_args *tune_args)
+{
+       struct as10x_bus_adapter_t *bus_adap = priv;
+       int ret;
+
+       /* Set frontend arguments */
+       if (mutex_lock_interruptible(&bus_adap->lock))
+               return -EBUSY;
+
+       ret =  as10x_cmd_set_tune(bus_adap, tune_args);
+       if (ret != 0)
+               dev_dbg(&bus_adap->usb_dev->dev,
+                       "as10x_cmd_set_tune failed. (err = %d)\n", ret);
+
+       mutex_unlock(&bus_adap->lock);
+
+       return ret;
+}
+
+static int as102_get_tps(void *priv, struct as10x_tps *tps)
+{
+       struct as10x_bus_adapter_t *bus_adap = priv;
+       int ret;
+
+       if (mutex_lock_interruptible(&bus_adap->lock))
+               return -EBUSY;
+
+       /* send abilis command: GET_TPS */
+       ret = as10x_cmd_get_tps(bus_adap, tps);
+
+       mutex_unlock(&bus_adap->lock);
+
+       return ret;
+}
+
+static int as102_get_status(void *priv, struct as10x_tune_status *tstate)
+{
+       struct as10x_bus_adapter_t *bus_adap = priv;
+       int ret;
+
+       if (mutex_lock_interruptible(&bus_adap->lock))
+               return -EBUSY;
+
+       /* send abilis command: GET_TUNE_STATUS */
+       ret = as10x_cmd_get_tune_status(bus_adap, tstate);
+       if (ret < 0) {
+               dev_dbg(&bus_adap->usb_dev->dev,
+                       "as10x_cmd_get_tune_status failed (err = %d)\n",
+                       ret);
+       }
+
+       mutex_unlock(&bus_adap->lock);
+
+       return ret;
+}
+
+static int as102_get_stats(void *priv, struct as10x_demod_stats *demod_stats)
+{
+       struct as10x_bus_adapter_t *bus_adap = priv;
+       int ret;
+
+       if (mutex_lock_interruptible(&bus_adap->lock))
+               return -EBUSY;
+
+       /* send abilis command: GET_TUNE_STATUS */
+       ret = as10x_cmd_get_demod_stats(bus_adap, demod_stats);
+       if (ret < 0) {
+               dev_dbg(&bus_adap->usb_dev->dev,
+                       "as10x_cmd_get_demod_stats failed (probably not tuned)\n");
+       } else {
+               dev_dbg(&bus_adap->usb_dev->dev,
+                       "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n",
+                       demod_stats->frame_count,
+                       demod_stats->bad_frame_count,
+                       demod_stats->bytes_fixed_by_rs,
+                       demod_stats->mer);
+       }
+       mutex_unlock(&bus_adap->lock);
+
+       return ret;
+}
+
+static int as102_stream_ctrl(void *priv, int acquire, uint32_t elna_cfg)
+{
+       struct as10x_bus_adapter_t *bus_adap = priv;
+       int ret;
+
+       if (mutex_lock_interruptible(&bus_adap->lock))
+               return -EBUSY;
+
+       if (acquire) {
+               if (elna_enable)
+                       as10x_cmd_set_context(bus_adap,
+                                             CONTEXT_LNA, elna_cfg);
+
+               ret = as10x_cmd_turn_on(bus_adap);
+       } else {
+               ret = as10x_cmd_turn_off(bus_adap);
+       }
+
+       mutex_unlock(&bus_adap->lock);
+
+       return ret;
+}
+
+static const struct as102_fe_ops as102_fe_ops = {
+       .set_tune = as102_set_tune,
+       .get_tps  = as102_get_tps,
+       .get_status = as102_get_status,
+       .get_stats = as102_get_stats,
+       .stream_ctrl = as102_stream_ctrl,
+};
+
+int as102_dvb_register(struct as102_dev_t *as102_dev)
+{
+       struct device *dev = &as102_dev->bus_adap.usb_dev->dev;
+       int ret;
+
+       ret = dvb_register_adapter(&as102_dev->dvb_adap,
+                          as102_dev->name, THIS_MODULE,
+                          dev, adapter_nr);
+       if (ret < 0) {
+               dev_err(dev, "%s: dvb_register_adapter() failed: %d\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       as102_dev->dvb_dmx.priv = as102_dev;
+       as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256;
+       as102_dev->dvb_dmx.feednum = 256;
+       as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed;
+       as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed;
+
+       as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING |
+                                             DMX_SECTION_FILTERING;
+
+       as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum;
+       as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx;
+       as102_dev->dvb_dmxdev.capabilities = 0;
+
+       ret = dvb_dmx_init(&as102_dev->dvb_dmx);
+       if (ret < 0) {
+               dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret);
+               goto edmxinit;
+       }
+
+       ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap);
+       if (ret < 0) {
+               dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n",
+                       __func__, ret);
+               goto edmxdinit;
+       }
+
+       /* Attach the frontend */
+       as102_dev->dvb_fe = dvb_attach(as102_attach, as102_dev->name,
+                                      &as102_fe_ops,
+                                      &as102_dev->bus_adap,
+                                      as102_dev->elna_cfg);
+       if (!as102_dev->dvb_fe) {
+               dev_err(dev, "%s: as102_attach() failed: %d",
+                   __func__, ret);
+               goto efereg;
+       }
+
+       ret =  dvb_register_frontend(&as102_dev->dvb_adap, as102_dev->dvb_fe);
+       if (ret < 0) {
+               dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d",
+                   __func__, ret);
+               goto efereg;
+       }
+
+       /* init bus mutex for token locking */
+       mutex_init(&as102_dev->bus_adap.lock);
+
+       /* init start / stop stream mutex */
+       mutex_init(&as102_dev->sem);
+
+       /*
+        * try to load as102 firmware. If firmware upload failed, we'll be
+        * able to upload it later.
+        */
+       if (fw_upload)
+               try_then_request_module(as102_fw_upload(&as102_dev->bus_adap),
+                               "firmware_class");
+
+       pr_info("Registered device %s", as102_dev->name);
+       return 0;
+
+efereg:
+       dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
+edmxdinit:
+       dvb_dmx_release(&as102_dev->dvb_dmx);
+edmxinit:
+       dvb_unregister_adapter(&as102_dev->dvb_adap);
+       return ret;
+}
+
+void as102_dvb_unregister(struct as102_dev_t *as102_dev)
+{
+       /* unregister as102 frontend */
+       dvb_unregister_frontend(as102_dev->dvb_fe);
+
+       /* detach frontend */
+       dvb_frontend_detach(as102_dev->dvb_fe);
+
+       /* unregister demux device */
+       dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
+       dvb_dmx_release(&as102_dev->dvb_dmx);
+
+       /* unregister dvb adapter */
+       dvb_unregister_adapter(&as102_dev->dvb_adap);
+
+       pr_info("Unregistered device %s", as102_dev->name);
+}
+
+module_usb_driver(as102_usb_driver);
+
+/* modinfo details */
+MODULE_DESCRIPTION(DRIVER_FULL_NAME);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
diff --git a/drivers/media/usb/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h
new file mode 100644 (file)
index 0000000..aee2d76
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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.
+ */
+
+#ifndef _AS102_DRV_H
+#define _AS102_DRV_H
+#include <linux/usb.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
+#include <dmxdev.h>
+#include "as10x_handle.h"
+#include "as10x_cmd.h"
+#include "as102_usb_drv.h"
+
+#define DRIVER_FULL_NAME "Abilis Systems as10x usb driver"
+#define DRIVER_NAME "as10x_usb"
+
+#define debug  as102_debug
+extern struct usb_driver as102_usb_driver;
+extern int elna_enable;
+
+#define AS102_DEVICE_MAJOR     192
+
+#define AS102_USB_BUF_SIZE     512
+#define MAX_STREAM_URB         32
+
+struct as10x_bus_adapter_t {
+       struct usb_device *usb_dev;
+       /* bus token lock */
+       struct mutex lock;
+       /* low level interface for bus adapter */
+       union as10x_bus_token_t {
+               /* usb token */
+               struct as10x_usb_token_cmd_t usb;
+       } token;
+
+       /* token cmd xfer id */
+       uint16_t cmd_xid;
+
+       /* as10x command and response for dvb interface*/
+       struct as10x_cmd_t *cmd, *rsp;
+
+       /* bus adapter private ops callback */
+       struct as102_priv_ops_t *ops;
+};
+
+struct as102_dev_t {
+       const char *name;
+       struct as10x_bus_adapter_t bus_adap;
+       struct list_head device_entry;
+       struct kref kref;
+       uint8_t elna_cfg;
+
+       struct dvb_adapter dvb_adap;
+       struct dvb_frontend *dvb_fe;
+       struct dvb_demux dvb_dmx;
+       struct dmxdev dvb_dmxdev;
+
+       /* timer handle to trig ts stream download */
+       struct timer_list timer_handle;
+
+       struct mutex sem;
+       dma_addr_t dma_addr;
+       void *stream;
+       int streaming;
+       struct urb *stream_urb[MAX_STREAM_URB];
+};
+
+int as102_dvb_register(struct as102_dev_t *dev);
+void as102_dvb_unregister(struct as102_dev_t *dev);
+
+#endif
diff --git a/drivers/media/usb/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c
new file mode 100644 (file)
index 0000000..07d08c4
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+
+#include "as102_drv.h"
+#include "as102_fw.h"
+
+static const char as102_st_fw1[] = "as102_data1_st.hex";
+static const char as102_st_fw2[] = "as102_data2_st.hex";
+static const char as102_dt_fw1[] = "as102_data1_dt.hex";
+static const char as102_dt_fw2[] = "as102_data2_dt.hex";
+
+static unsigned char atohx(unsigned char *dst, char *src)
+{
+       unsigned char value = 0;
+
+       char msb = tolower(*src) - '0';
+       char lsb = tolower(*(src + 1)) - '0';
+
+       if (msb > 9)
+               msb -= 7;
+       if (lsb > 9)
+               lsb -= 7;
+
+       *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
+       return value;
+}
+
+/*
+ * Parse INTEL HEX firmware file to extract address and data.
+ */
+static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
+                         unsigned char *data, int *dataLength,
+                         unsigned char *addr_has_changed) {
+
+       int count = 0;
+       unsigned char *src, dst;
+
+       if (*fw_data++ != ':') {
+               pr_err("invalid firmware file\n");
+               return -EFAULT;
+       }
+
+       /* locate end of line */
+       for (src = fw_data; *src != '\n'; src += 2) {
+               atohx(&dst, src);
+               /* parse line to split addr / data */
+               switch (count) {
+               case 0:
+                       *dataLength = dst;
+                       break;
+               case 1:
+                       addr[2] = dst;
+                       break;
+               case 2:
+                       addr[3] = dst;
+                       break;
+               case 3:
+                       /* check if data is an address */
+                       if (dst == 0x04)
+                               *addr_has_changed = 1;
+                       else
+                               *addr_has_changed = 0;
+                       break;
+               case  4:
+               case  5:
+                       if (*addr_has_changed)
+                               addr[(count - 4)] = dst;
+                       else
+                               data[(count - 4)] = dst;
+                       break;
+               default:
+                       data[(count - 4)] = dst;
+                       break;
+               }
+               count++;
+       }
+
+       /* return read value + ':' + '\n' */
+       return (count * 2) + 2;
+}
+
+static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
+                                unsigned char *cmd,
+                                const struct firmware *firmware) {
+
+       struct as10x_fw_pkt_t fw_pkt;
+       int total_read_bytes = 0, errno = 0;
+       unsigned char addr_has_changed = 0;
+
+       for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
+               int read_bytes = 0, data_len = 0;
+
+               /* parse intel hex line */
+               read_bytes = parse_hex_line(
+                               (u8 *) (firmware->data + total_read_bytes),
+                               fw_pkt.raw.address,
+                               fw_pkt.raw.data,
+                               &data_len,
+                               &addr_has_changed);
+
+               if (read_bytes <= 0)
+                       goto error;
+
+               /* detect the end of file */
+               total_read_bytes += read_bytes;
+               if (total_read_bytes == firmware->size) {
+                       fw_pkt.u.request[0] = 0x00;
+                       fw_pkt.u.request[1] = 0x03;
+
+                       /* send EOF command */
+                       errno = bus_adap->ops->upload_fw_pkt(bus_adap,
+                                                            (uint8_t *)
+                                                            &fw_pkt, 2, 0);
+                       if (errno < 0)
+                               goto error;
+               } else {
+                       if (!addr_has_changed) {
+                               /* prepare command to send */
+                               fw_pkt.u.request[0] = 0x00;
+                               fw_pkt.u.request[1] = 0x01;
+
+                               data_len += sizeof(fw_pkt.u.request);
+                               data_len += sizeof(fw_pkt.raw.address);
+
+                               /* send cmd to device */
+                               errno = bus_adap->ops->upload_fw_pkt(bus_adap,
+                                                                    (uint8_t *)
+                                                                    &fw_pkt,
+                                                                    data_len,
+                                                                    0);
+                               if (errno < 0)
+                                       goto error;
+                       }
+               }
+       }
+error:
+       return (errno == 0) ? total_read_bytes : errno;
+}
+
+int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
+{
+       int errno = -EFAULT;
+       const struct firmware *firmware = NULL;
+       unsigned char *cmd_buf = NULL;
+       const char *fw1, *fw2;
+       struct usb_device *dev = bus_adap->usb_dev;
+
+       /* select fw file to upload */
+       if (dual_tuner) {
+               fw1 = as102_dt_fw1;
+               fw2 = as102_dt_fw2;
+       } else {
+               fw1 = as102_st_fw1;
+               fw2 = as102_st_fw2;
+       }
+
+       /* allocate buffer to store firmware upload command and data */
+       cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
+       if (cmd_buf == NULL) {
+               errno = -ENOMEM;
+               goto error;
+       }
+
+       /* request kernel to locate firmware file: part1 */
+       errno = request_firmware(&firmware, fw1, &dev->dev);
+       if (errno < 0) {
+               pr_err("%s: unable to locate firmware file: %s\n",
+                      DRIVER_NAME, fw1);
+               goto error;
+       }
+
+       /* initiate firmware upload */
+       errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
+       if (errno < 0) {
+               pr_err("%s: error during firmware upload part1\n",
+                      DRIVER_NAME);
+               goto error;
+       }
+
+       pr_info("%s: firmware: %s loaded with success\n",
+               DRIVER_NAME, fw1);
+       release_firmware(firmware);
+
+       /* wait for boot to complete */
+       mdelay(100);
+
+       /* request kernel to locate firmware file: part2 */
+       errno = request_firmware(&firmware, fw2, &dev->dev);
+       if (errno < 0) {
+               pr_err("%s: unable to locate firmware file: %s\n",
+                      DRIVER_NAME, fw2);
+               goto error;
+       }
+
+       /* initiate firmware upload */
+       errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
+       if (errno < 0) {
+               pr_err("%s: error during firmware upload part2\n",
+                      DRIVER_NAME);
+               goto error;
+       }
+
+       pr_info("%s: firmware: %s loaded with success\n",
+               DRIVER_NAME, fw2);
+error:
+       kfree(cmd_buf);
+       release_firmware(firmware);
+
+       return errno;
+}
diff --git a/drivers/media/usb/as102/as102_fw.h b/drivers/media/usb/as102/as102_fw.h
new file mode 100644 (file)
index 0000000..2732b78
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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.
+ */
+#define MAX_FW_PKT_SIZE        64
+
+extern int dual_tuner;
+
+struct as10x_raw_fw_pkt {
+       unsigned char address[4];
+       unsigned char data[MAX_FW_PKT_SIZE - 6];
+} __packed;
+
+struct as10x_fw_pkt_t {
+       union {
+               unsigned char request[2];
+               unsigned char length[2];
+       } __packed u;
+       struct as10x_raw_fw_pkt raw;
+} __packed;
+
+#ifdef __KERNEL__
+int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap);
+#endif
diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c
new file mode 100644 (file)
index 0000000..3f66906
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+
+#include "as102_drv.h"
+#include "as102_usb_drv.h"
+#include "as102_fw.h"
+
+static void as102_usb_disconnect(struct usb_interface *interface);
+static int as102_usb_probe(struct usb_interface *interface,
+                          const struct usb_device_id *id);
+
+static int as102_usb_start_stream(struct as102_dev_t *dev);
+static void as102_usb_stop_stream(struct as102_dev_t *dev);
+
+static int as102_open(struct inode *inode, struct file *file);
+static int as102_release(struct inode *inode, struct file *file);
+
+static struct usb_device_id as102_usb_id_table[] = {
+       { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) },
+       { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) },
+       { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) },
+       { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) },
+       { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) },
+       { } /* Terminating entry */
+};
+
+/* Note that this table must always have the same number of entries as the
+   as102_usb_id_table struct */
+static const char * const as102_device_names[] = {
+       AS102_REFERENCE_DESIGN,
+       AS102_PCTV_74E,
+       AS102_ELGATO_EYETV_DTT_NAME,
+       AS102_NBOX_DVBT_DONGLE_NAME,
+       AS102_SKY_IT_DIGITAL_KEY_NAME,
+       NULL /* Terminating entry */
+};
+
+/* eLNA configuration: devices built on the reference design work best
+   with 0xA0, while custom designs seem to require 0xC0 */
+static uint8_t const as102_elna_cfg[] = {
+       0xA0,
+       0xC0,
+       0xC0,
+       0xA0,
+       0xA0,
+       0x00 /* Terminating entry */
+};
+
+struct usb_driver as102_usb_driver = {
+       .name           = DRIVER_FULL_NAME,
+       .probe          = as102_usb_probe,
+       .disconnect     = as102_usb_disconnect,
+       .id_table       = as102_usb_id_table
+};
+
+static const struct file_operations as102_dev_fops = {
+       .owner          = THIS_MODULE,
+       .open           = as102_open,
+       .release        = as102_release,
+};
+
+static struct usb_class_driver as102_usb_class_driver = {
+       .name           = "aton2-%d",
+       .fops           = &as102_dev_fops,
+       .minor_base     = AS102_DEVICE_MAJOR,
+};
+
+static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap,
+                             unsigned char *send_buf, int send_buf_len,
+                             unsigned char *recv_buf, int recv_buf_len)
+{
+       int ret = 0;
+
+       if (send_buf != NULL) {
+               ret = usb_control_msg(bus_adap->usb_dev,
+                                     usb_sndctrlpipe(bus_adap->usb_dev, 0),
+                                     AS102_USB_DEVICE_TX_CTRL_CMD,
+                                     USB_DIR_OUT | USB_TYPE_VENDOR |
+                                     USB_RECIP_DEVICE,
+                                     bus_adap->cmd_xid, /* value */
+                                     0, /* index */
+                                     send_buf, send_buf_len,
+                                     USB_CTRL_SET_TIMEOUT /* 200 */);
+               if (ret < 0) {
+                       dev_dbg(&bus_adap->usb_dev->dev,
+                               "usb_control_msg(send) failed, err %i\n", ret);
+                       return ret;
+               }
+
+               if (ret != send_buf_len) {
+                       dev_dbg(&bus_adap->usb_dev->dev,
+                       "only wrote %d of %d bytes\n", ret, send_buf_len);
+                       return -1;
+               }
+       }
+
+       if (recv_buf != NULL) {
+#ifdef TRACE
+               dev_dbg(bus_adap->usb_dev->dev,
+                       "want to read: %d bytes\n", recv_buf_len);
+#endif
+               ret = usb_control_msg(bus_adap->usb_dev,
+                                     usb_rcvctrlpipe(bus_adap->usb_dev, 0),
+                                     AS102_USB_DEVICE_RX_CTRL_CMD,
+                                     USB_DIR_IN | USB_TYPE_VENDOR |
+                                     USB_RECIP_DEVICE,
+                                     bus_adap->cmd_xid, /* value */
+                                     0, /* index */
+                                     recv_buf, recv_buf_len,
+                                     USB_CTRL_GET_TIMEOUT /* 200 */);
+               if (ret < 0) {
+                       dev_dbg(&bus_adap->usb_dev->dev,
+                               "usb_control_msg(recv) failed, err %i\n", ret);
+                       return ret;
+               }
+#ifdef TRACE
+               dev_dbg(bus_adap->usb_dev->dev,
+                       "read %d bytes\n", recv_buf_len);
+#endif
+       }
+
+       return ret;
+}
+
+static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap,
+                         unsigned char *send_buf,
+                         int send_buf_len,
+                         int swap32)
+{
+       int ret, actual_len;
+
+       ret = usb_bulk_msg(bus_adap->usb_dev,
+                          usb_sndbulkpipe(bus_adap->usb_dev, 1),
+                          send_buf, send_buf_len, &actual_len, 200);
+       if (ret) {
+               dev_dbg(&bus_adap->usb_dev->dev,
+                       "usb_bulk_msg(send) failed, err %i\n", ret);
+               return ret;
+       }
+
+       if (actual_len != send_buf_len) {
+               dev_dbg(&bus_adap->usb_dev->dev, "only wrote %d of %d bytes\n",
+                       actual_len, send_buf_len);
+               return -1;
+       }
+       return actual_len;
+}
+
+static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap,
+                  unsigned char *recv_buf, int recv_buf_len)
+{
+       int ret, actual_len;
+
+       if (recv_buf == NULL)
+               return -EINVAL;
+
+       ret = usb_bulk_msg(bus_adap->usb_dev,
+                          usb_rcvbulkpipe(bus_adap->usb_dev, 2),
+                          recv_buf, recv_buf_len, &actual_len, 200);
+       if (ret) {
+               dev_dbg(&bus_adap->usb_dev->dev,
+                       "usb_bulk_msg(recv) failed, err %i\n", ret);
+               return ret;
+       }
+
+       if (actual_len != recv_buf_len) {
+               dev_dbg(&bus_adap->usb_dev->dev, "only read %d of %d bytes\n",
+                       actual_len, recv_buf_len);
+               return -1;
+       }
+       return actual_len;
+}
+
+static struct as102_priv_ops_t as102_priv_ops = {
+       .upload_fw_pkt  = as102_send_ep1,
+       .xfer_cmd       = as102_usb_xfer_cmd,
+       .as102_read_ep2 = as102_read_ep2,
+       .start_stream   = as102_usb_start_stream,
+       .stop_stream    = as102_usb_stop_stream,
+};
+
+static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb)
+{
+       int err;
+
+       usb_fill_bulk_urb(urb,
+                         dev->bus_adap.usb_dev,
+                         usb_rcvbulkpipe(dev->bus_adap.usb_dev, 0x2),
+                         urb->transfer_buffer,
+                         AS102_USB_BUF_SIZE,
+                         as102_urb_stream_irq,
+                         dev);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err)
+               dev_dbg(&urb->dev->dev,
+                       "%s: usb_submit_urb failed\n", __func__);
+
+       return err;
+}
+
+void as102_urb_stream_irq(struct urb *urb)
+{
+       struct as102_dev_t *as102_dev = urb->context;
+
+       if (urb->actual_length > 0) {
+               dvb_dmx_swfilter(&as102_dev->dvb_dmx,
+                                urb->transfer_buffer,
+                                urb->actual_length);
+       } else {
+               if (urb->actual_length == 0)
+                       memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE);
+       }
+
+       /* is not stopped, re-submit urb */
+       if (as102_dev->streaming)
+               as102_submit_urb_stream(as102_dev, urb);
+}
+
+static void as102_free_usb_stream_buffer(struct as102_dev_t *dev)
+{
+       int i;
+
+       for (i = 0; i < MAX_STREAM_URB; i++)
+               usb_free_urb(dev->stream_urb[i]);
+
+       usb_free_coherent(dev->bus_adap.usb_dev,
+                       MAX_STREAM_URB * AS102_USB_BUF_SIZE,
+                       dev->stream,
+                       dev->dma_addr);
+}
+
+static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev)
+{
+       int i;
+
+       dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev,
+                                      MAX_STREAM_URB * AS102_USB_BUF_SIZE,
+                                      GFP_KERNEL,
+                                      &dev->dma_addr);
+       if (!dev->stream) {
+               dev_dbg(&dev->bus_adap.usb_dev->dev,
+                       "%s: usb_buffer_alloc failed\n", __func__);
+               return -ENOMEM;
+       }
+
+       memset(dev->stream, 0, MAX_STREAM_URB * AS102_USB_BUF_SIZE);
+
+       /* init urb buffers */
+       for (i = 0; i < MAX_STREAM_URB; i++) {
+               struct urb *urb;
+
+               urb = usb_alloc_urb(0, GFP_ATOMIC);
+               if (urb == NULL) {
+                       dev_dbg(&dev->bus_adap.usb_dev->dev,
+                               "%s: usb_alloc_urb failed\n", __func__);
+                       as102_free_usb_stream_buffer(dev);
+                       return -ENOMEM;
+               }
+
+               urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE);
+               urb->transfer_dma = dev->dma_addr + (i * AS102_USB_BUF_SIZE);
+               urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+               urb->transfer_buffer_length = AS102_USB_BUF_SIZE;
+
+               dev->stream_urb[i] = urb;
+       }
+       return 0;
+}
+
+static void as102_usb_stop_stream(struct as102_dev_t *dev)
+{
+       int i;
+
+       for (i = 0; i < MAX_STREAM_URB; i++)
+               usb_kill_urb(dev->stream_urb[i]);
+}
+
+static int as102_usb_start_stream(struct as102_dev_t *dev)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < MAX_STREAM_URB; i++) {
+               ret = as102_submit_urb_stream(dev, dev->stream_urb[i]);
+               if (ret) {
+                       as102_usb_stop_stream(dev);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void as102_usb_release(struct kref *kref)
+{
+       struct as102_dev_t *as102_dev;
+
+       as102_dev = container_of(kref, struct as102_dev_t, kref);
+       if (as102_dev != NULL) {
+               usb_put_dev(as102_dev->bus_adap.usb_dev);
+               kfree(as102_dev);
+       }
+}
+
+static void as102_usb_disconnect(struct usb_interface *intf)
+{
+       struct as102_dev_t *as102_dev;
+
+       /* extract as102_dev_t from usb_device private data */
+       as102_dev = usb_get_intfdata(intf);
+
+       /* unregister dvb layer */
+       as102_dvb_unregister(as102_dev);
+
+       /* free usb buffers */
+       as102_free_usb_stream_buffer(as102_dev);
+
+       usb_set_intfdata(intf, NULL);
+
+       /* usb unregister device */
+       usb_deregister_dev(intf, &as102_usb_class_driver);
+
+       /* decrement usage counter */
+       kref_put(&as102_dev->kref, as102_usb_release);
+
+       pr_info("%s: device has been disconnected\n", DRIVER_NAME);
+}
+
+static int as102_usb_probe(struct usb_interface *intf,
+                          const struct usb_device_id *id)
+{
+       int ret;
+       struct as102_dev_t *as102_dev;
+       int i;
+
+       /* This should never actually happen */
+       if (ARRAY_SIZE(as102_usb_id_table) !=
+           (sizeof(as102_device_names) / sizeof(const char *))) {
+               pr_err("Device names table invalid size");
+               return -EINVAL;
+       }
+
+       as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL);
+       if (as102_dev == NULL)
+               return -ENOMEM;
+
+       /* Assign the user-friendly device name */
+       for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) {
+               if (id == &as102_usb_id_table[i]) {
+                       as102_dev->name = as102_device_names[i];
+                       as102_dev->elna_cfg = as102_elna_cfg[i];
+               }
+       }
+
+       if (as102_dev->name == NULL)
+               as102_dev->name = "Unknown AS102 device";
+
+       /* set private callback functions */
+       as102_dev->bus_adap.ops = &as102_priv_ops;
+
+       /* init cmd token for usb bus */
+       as102_dev->bus_adap.cmd = &as102_dev->bus_adap.token.usb.c;
+       as102_dev->bus_adap.rsp = &as102_dev->bus_adap.token.usb.r;
+
+       /* init kernel device reference */
+       kref_init(&as102_dev->kref);
+
+       /* store as102 device to usb_device private data */
+       usb_set_intfdata(intf, (void *) as102_dev);
+
+       /* store in as102 device the usb_device pointer */
+       as102_dev->bus_adap.usb_dev = usb_get_dev(interface_to_usbdev(intf));
+
+       /* we can register the device now, as it is ready */
+       ret = usb_register_dev(intf, &as102_usb_class_driver);
+       if (ret < 0) {
+               /* something prevented us from registering this driver */
+               dev_err(&intf->dev,
+                       "%s: usb_register_dev() failed (errno = %d)\n",
+                       __func__, ret);
+               goto failed;
+       }
+
+       pr_info("%s: device has been detected\n", DRIVER_NAME);
+
+       /* request buffer allocation for streaming */
+       ret = as102_alloc_usb_stream_buffer(as102_dev);
+       if (ret != 0)
+               goto failed_stream;
+
+       /* register dvb layer */
+       ret = as102_dvb_register(as102_dev);
+       if (ret != 0)
+               goto failed_dvb;
+
+       return ret;
+
+failed_dvb:
+       as102_free_usb_stream_buffer(as102_dev);
+failed_stream:
+       usb_deregister_dev(intf, &as102_usb_class_driver);
+failed:
+       usb_put_dev(as102_dev->bus_adap.usb_dev);
+       usb_set_intfdata(intf, NULL);
+       kfree(as102_dev);
+       return ret;
+}
+
+static int as102_open(struct inode *inode, struct file *file)
+{
+       int ret = 0, minor = 0;
+       struct usb_interface *intf = NULL;
+       struct as102_dev_t *dev = NULL;
+
+       /* read minor from inode */
+       minor = iminor(inode);
+
+       /* fetch device from usb interface */
+       intf = usb_find_interface(&as102_usb_driver, minor);
+       if (intf == NULL) {
+               pr_err("%s: can't find device for minor %d\n",
+                      __func__, minor);
+               ret = -ENODEV;
+               goto exit;
+       }
+
+       /* get our device */
+       dev = usb_get_intfdata(intf);
+       if (dev == NULL) {
+               ret = -EFAULT;
+               goto exit;
+       }
+
+       /* save our device object in the file's private structure */
+       file->private_data = dev;
+
+       /* increment our usage count for the device */
+       kref_get(&dev->kref);
+
+exit:
+       return ret;
+}
+
+static int as102_release(struct inode *inode, struct file *file)
+{
+       struct as102_dev_t *dev = NULL;
+
+       dev = file->private_data;
+       if (dev != NULL) {
+               /* decrement the count on our device */
+               kref_put(&dev->kref, as102_usb_release);
+       }
+
+       return 0;
+}
+
+MODULE_DEVICE_TABLE(usb, as102_usb_id_table);
diff --git a/drivers/media/usb/as102/as102_usb_drv.h b/drivers/media/usb/as102/as102_usb_drv.h
new file mode 100644 (file)
index 0000000..4fb1baa
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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.
+ */
+#ifndef _AS102_USB_DRV_H_
+#define _AS102_USB_DRV_H_
+
+#define AS102_USB_DEVICE_TX_CTRL_CMD   0xF1
+#define AS102_USB_DEVICE_RX_CTRL_CMD   0xF2
+
+/* define these values to match the supported devices */
+
+/* Abilis system: "TITAN" */
+#define AS102_REFERENCE_DESIGN         "Abilis Systems DVB-Titan"
+#define AS102_USB_DEVICE_VENDOR_ID     0x1BA6
+#define AS102_USB_DEVICE_PID_0001      0x0001
+
+/* PCTV Systems: PCTV picoStick (74e) */
+#define AS102_PCTV_74E                 "PCTV Systems picoStick (74e)"
+#define PCTV_74E_USB_VID               0x2013
+#define PCTV_74E_USB_PID               0x0246
+
+/* Elgato: EyeTV DTT Deluxe */
+#define AS102_ELGATO_EYETV_DTT_NAME    "Elgato EyeTV DTT Deluxe"
+#define ELGATO_EYETV_DTT_USB_VID       0x0fd9
+#define ELGATO_EYETV_DTT_USB_PID       0x002c
+
+/* nBox: nBox DVB-T Dongle */
+#define AS102_NBOX_DVBT_DONGLE_NAME    "nBox DVB-T Dongle"
+#define NBOX_DVBT_DONGLE_USB_VID       0x0b89
+#define NBOX_DVBT_DONGLE_USB_PID       0x0007
+
+/* Sky Italia: Digital Key (green led) */
+#define AS102_SKY_IT_DIGITAL_KEY_NAME  "Sky IT Digital Key (green led)"
+#define SKY_IT_DIGITAL_KEY_USB_VID     0x2137
+#define SKY_IT_DIGITAL_KEY_USB_PID     0x0001
+
+void as102_urb_stream_irq(struct urb *urb);
+
+struct as10x_usb_token_cmd_t {
+       /* token cmd */
+       struct as10x_cmd_t c;
+       /* token response */
+       struct as10x_cmd_t r;
+};
+#endif
diff --git a/drivers/media/usb/as102/as10x_cmd.c b/drivers/media/usb/as102/as10x_cmd.c
new file mode 100644 (file)
index 0000000..8706179
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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.
+ */
+
+#include <linux/kernel.h>
+#include "as102_drv.h"
+#include "as10x_cmd.h"
+
+/**
+ * as10x_cmd_turn_on - send turn on command to AS10x
+ * @adap:   pointer to AS10x bus adapter
+ *
+ * Return 0 when no error, < 0 in case of error.
+ */
+int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.turn_on.req));
+
+       /* fill command */
+       pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                                           sizeof(pcmd->body.turn_on.req) +
+                                           HEADER_SIZE,
+                                           (uint8_t *) prsp,
+                                           sizeof(prsp->body.turn_on.rsp) +
+                                           HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_turn_off - send turn off command to AS10x
+ * @adap:   pointer to AS10x bus adapter
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.turn_off.req));
+
+       /* fill command */
+       pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(
+                       adap, (uint8_t *) pcmd,
+                       sizeof(pcmd->body.turn_off.req) + HEADER_SIZE,
+                       (uint8_t *) prsp,
+                       sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_set_tune - send set tune command to AS10x
+ * @adap:    pointer to AS10x bus adapter
+ * @ptune:   tune parameters
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
+                      struct as10x_tune_args *ptune)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t *preq, *prsp;
+
+       preq = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(preq, (++adap->cmd_xid),
+                       sizeof(preq->body.set_tune.req));
+
+       /* fill command */
+       preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE);
+       preq->body.set_tune.req.args.freq = (__force __u32)cpu_to_le32(ptune->freq);
+       preq->body.set_tune.req.args.bandwidth = ptune->bandwidth;
+       preq->body.set_tune.req.args.hier_select = ptune->hier_select;
+       preq->body.set_tune.req.args.modulation = ptune->modulation;
+       preq->body.set_tune.req.args.hierarchy = ptune->hierarchy;
+       preq->body.set_tune.req.args.interleaving_mode  =
+               ptune->interleaving_mode;
+       preq->body.set_tune.req.args.code_rate  = ptune->code_rate;
+       preq->body.set_tune.req.args.guard_interval = ptune->guard_interval;
+       preq->body.set_tune.req.args.transmission_mode  =
+               ptune->transmission_mode;
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap,
+                                           (uint8_t *) preq,
+                                           sizeof(preq->body.set_tune.req)
+                                           + HEADER_SIZE,
+                                           (uint8_t *) prsp,
+                                           sizeof(prsp->body.set_tune.rsp)
+                                           + HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_get_tune_status - send get tune status command to AS10x
+ * @adap: pointer to AS10x bus adapter
+ * @pstatus: pointer to updated status structure of the current tune
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
+                             struct as10x_tune_status *pstatus)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t  *preq, *prsp;
+
+       preq = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(preq, (++adap->cmd_xid),
+                       sizeof(preq->body.get_tune_status.req));
+
+       /* fill command */
+       preq->body.get_tune_status.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_GETTUNESTAT);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(
+                       adap,
+                       (uint8_t *) preq,
+                       sizeof(preq->body.get_tune_status.req) + HEADER_SIZE,
+                       (uint8_t *) prsp,
+                       sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTUNESTAT_RSP);
+       if (error < 0)
+               goto out;
+
+       /* Response OK -> get response data */
+       pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state;
+       pstatus->signal_strength  =
+               le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.signal_strength);
+       pstatus->PER = le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.PER);
+       pstatus->BER = le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.BER);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_get_tps - send get TPS command to AS10x
+ * @adap:      pointer to AS10x handle
+ * @ptps:      pointer to TPS parameters structure
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.get_tps.req));
+
+       /* fill command */
+       pcmd->body.get_tune_status.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_GETTPS);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap,
+                                           (uint8_t *) pcmd,
+                                           sizeof(pcmd->body.get_tps.req) +
+                                           HEADER_SIZE,
+                                           (uint8_t *) prsp,
+                                           sizeof(prsp->body.get_tps.rsp) +
+                                           HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTPS_RSP);
+       if (error < 0)
+               goto out;
+
+       /* Response OK -> get response data */
+       ptps->modulation = prsp->body.get_tps.rsp.tps.modulation;
+       ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy;
+       ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode;
+       ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP;
+       ptps->code_rate_LP = prsp->body.get_tps.rsp.tps.code_rate_LP;
+       ptps->guard_interval = prsp->body.get_tps.rsp.tps.guard_interval;
+       ptps->transmission_mode  = prsp->body.get_tps.rsp.tps.transmission_mode;
+       ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP;
+       ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP;
+       ptps->cell_ID = le16_to_cpu((__force __le16)prsp->body.get_tps.rsp.tps.cell_ID);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_get_demod_stats - send get demod stats command to AS10x
+ * @adap:          pointer to AS10x bus adapter
+ * @pdemod_stats:  pointer to demod stats parameters structure
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap,
+                             struct as10x_demod_stats *pdemod_stats)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.get_demod_stats.req));
+
+       /* fill command */
+       pcmd->body.get_demod_stats.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap,
+                               (uint8_t *) pcmd,
+                               sizeof(pcmd->body.get_demod_stats.req)
+                               + HEADER_SIZE,
+                               (uint8_t *) prsp,
+                               sizeof(prsp->body.get_demod_stats.rsp)
+                               + HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_DEMOD_STATS_RSP);
+       if (error < 0)
+               goto out;
+
+       /* Response OK -> get response data */
+       pdemod_stats->frame_count =
+               le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.frame_count);
+       pdemod_stats->bad_frame_count =
+               le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.bad_frame_count);
+       pdemod_stats->bytes_fixed_by_rs =
+               le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs);
+       pdemod_stats->mer =
+               le16_to_cpu((__force __le16)prsp->body.get_demod_stats.rsp.stats.mer);
+       pdemod_stats->has_started =
+               prsp->body.get_demod_stats.rsp.stats.has_started;
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x
+ * @adap:     pointer to AS10x bus adapter
+ * @is_ready: pointer to value indicating when impulse
+ *           response data is ready
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
+                              uint8_t *is_ready)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.get_impulse_rsp.req));
+
+       /* fill command */
+       pcmd->body.get_impulse_rsp.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap,
+                                       (uint8_t *) pcmd,
+                                       sizeof(pcmd->body.get_impulse_rsp.req)
+                                       + HEADER_SIZE,
+                                       (uint8_t *) prsp,
+                                       sizeof(prsp->body.get_impulse_rsp.rsp)
+                                       + HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_IMPULSE_RESP_RSP);
+       if (error < 0)
+               goto out;
+
+       /* Response OK -> get response data */
+       *is_ready = prsp->body.get_impulse_rsp.rsp.is_ready;
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_build - build AS10x command header
+ * @pcmd:     pointer to AS10x command buffer
+ * @xid:      sequence id of the command
+ * @cmd_len:  length of the command
+ */
+void as10x_cmd_build(struct as10x_cmd_t *pcmd,
+                    uint16_t xid, uint16_t cmd_len)
+{
+       pcmd->header.req_id = cpu_to_le16(xid);
+       pcmd->header.prog = cpu_to_le16(SERVICE_PROG_ID);
+       pcmd->header.version = cpu_to_le16(SERVICE_PROG_VERSION);
+       pcmd->header.data_len = cpu_to_le16(cmd_len);
+}
+
+/**
+ * as10x_rsp_parse - Parse command response
+ * @prsp:       pointer to AS10x command buffer
+ * @proc_id:    id of the command
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id)
+{
+       int error;
+
+       /* extract command error code */
+       error = prsp->body.common.rsp.error;
+
+       if ((error == 0) &&
+           (le16_to_cpu(prsp->body.common.rsp.proc_id) == proc_id)) {
+               return 0;
+       }
+
+       return AS10X_CMD_ERROR;
+}
diff --git a/drivers/media/usb/as102/as10x_cmd.h b/drivers/media/usb/as102/as10x_cmd.h
new file mode 100644 (file)
index 0000000..e06b84e
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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.
+ */
+#ifndef _AS10X_CMD_H_
+#define _AS10X_CMD_H_
+
+#include <linux/kernel.h>
+
+#include "as102_fe_types.h"
+
+/*********************************/
+/*       MACRO DEFINITIONS       */
+/*********************************/
+#define AS10X_CMD_ERROR                -1
+
+#define SERVICE_PROG_ID                0x0002
+#define SERVICE_PROG_VERSION   0x0001
+
+#define HIER_NONE              0x00
+#define HIER_LOW_PRIORITY      0x01
+
+#define HEADER_SIZE (sizeof(struct as10x_cmd_header_t))
+
+/* context request types */
+#define GET_CONTEXT_DATA       1
+#define SET_CONTEXT_DATA       2
+
+/* ODSP suspend modes */
+#define CFG_MODE_ODSP_RESUME   0
+#define CFG_MODE_ODSP_SUSPEND  1
+
+/* Dump memory size */
+#define DUMP_BLOCK_SIZE_MAX    0x20
+
+/*********************************/
+/*     TYPE DEFINITION           */
+/*********************************/
+enum control_proc {
+       CONTROL_PROC_TURNON                     = 0x0001,
+       CONTROL_PROC_TURNON_RSP                 = 0x0100,
+       CONTROL_PROC_SET_REGISTER               = 0x0002,
+       CONTROL_PROC_SET_REGISTER_RSP           = 0x0200,
+       CONTROL_PROC_GET_REGISTER               = 0x0003,
+       CONTROL_PROC_GET_REGISTER_RSP           = 0x0300,
+       CONTROL_PROC_SETTUNE                    = 0x000A,
+       CONTROL_PROC_SETTUNE_RSP                = 0x0A00,
+       CONTROL_PROC_GETTUNESTAT                = 0x000B,
+       CONTROL_PROC_GETTUNESTAT_RSP            = 0x0B00,
+       CONTROL_PROC_GETTPS                     = 0x000D,
+       CONTROL_PROC_GETTPS_RSP                 = 0x0D00,
+       CONTROL_PROC_SETFILTER                  = 0x000E,
+       CONTROL_PROC_SETFILTER_RSP              = 0x0E00,
+       CONTROL_PROC_REMOVEFILTER               = 0x000F,
+       CONTROL_PROC_REMOVEFILTER_RSP           = 0x0F00,
+       CONTROL_PROC_GET_IMPULSE_RESP           = 0x0012,
+       CONTROL_PROC_GET_IMPULSE_RESP_RSP       = 0x1200,
+       CONTROL_PROC_START_STREAMING            = 0x0013,
+       CONTROL_PROC_START_STREAMING_RSP        = 0x1300,
+       CONTROL_PROC_STOP_STREAMING             = 0x0014,
+       CONTROL_PROC_STOP_STREAMING_RSP         = 0x1400,
+       CONTROL_PROC_GET_DEMOD_STATS            = 0x0015,
+       CONTROL_PROC_GET_DEMOD_STATS_RSP        = 0x1500,
+       CONTROL_PROC_ELNA_CHANGE_MODE           = 0x0016,
+       CONTROL_PROC_ELNA_CHANGE_MODE_RSP       = 0x1600,
+       CONTROL_PROC_ODSP_CHANGE_MODE           = 0x0017,
+       CONTROL_PROC_ODSP_CHANGE_MODE_RSP       = 0x1700,
+       CONTROL_PROC_AGC_CHANGE_MODE            = 0x0018,
+       CONTROL_PROC_AGC_CHANGE_MODE_RSP        = 0x1800,
+
+       CONTROL_PROC_CONTEXT                    = 0x00FC,
+       CONTROL_PROC_CONTEXT_RSP                = 0xFC00,
+       CONTROL_PROC_DUMP_MEMORY                = 0x00FD,
+       CONTROL_PROC_DUMP_MEMORY_RSP            = 0xFD00,
+       CONTROL_PROC_DUMPLOG_MEMORY             = 0x00FE,
+       CONTROL_PROC_DUMPLOG_MEMORY_RSP         = 0xFE00,
+       CONTROL_PROC_TURNOFF                    = 0x00FF,
+       CONTROL_PROC_TURNOFF_RSP                = 0xFF00
+};
+
+union as10x_turn_on {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_turn_off {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t err;
+       } __packed rsp;
+} __packed;
+
+union as10x_set_tune {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+               /* tune params */
+               struct as10x_tune_args args;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* response error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_get_tune_status {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* response error */
+               uint8_t error;
+               /* tune status */
+               struct as10x_tune_status sts;
+       } __packed rsp;
+} __packed;
+
+union as10x_get_tps {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* response error */
+               uint8_t error;
+               /* tps details */
+               struct as10x_tps tps;
+       } __packed rsp;
+} __packed;
+
+union as10x_common {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16  proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* response error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_add_pid_filter {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16  proc_id;
+               /* PID to filter */
+               __le16  pid;
+               /* stream type (MPE, PSI/SI or PES )*/
+               uint8_t stream_type;
+               /* PID index in filter table */
+               uint8_t idx;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* response error */
+               uint8_t error;
+               /* Filter id */
+               uint8_t filter_id;
+       } __packed rsp;
+} __packed;
+
+union as10x_del_pid_filter {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16  proc_id;
+               /* PID to remove */
+               __le16  pid;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* response error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_start_streaming {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_stop_streaming {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_get_demod_stats {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+               /* demod stats */
+               struct as10x_demod_stats stats;
+       } __packed rsp;
+} __packed;
+
+union as10x_get_impulse_resp {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+               /* impulse response ready */
+               uint8_t is_ready;
+       } __packed rsp;
+} __packed;
+
+union as10x_fw_context {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+               /* value to write (for set context)*/
+               struct as10x_register_value reg_val;
+               /* context tag */
+               __le16 tag;
+               /* context request type */
+               __le16 type;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* value read (for get context) */
+               struct as10x_register_value reg_val;
+               /* context request type */
+               __le16 type;
+               /* error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_set_register {
+       /* request */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* register description */
+               struct as10x_register_addr reg_addr;
+               /* register content */
+               struct as10x_register_value reg_val;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_get_register {
+       /* request */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* register description */
+               struct as10x_register_addr reg_addr;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+               /* register content */
+               struct as10x_register_value reg_val;
+       } __packed rsp;
+} __packed;
+
+union as10x_cfg_change_mode {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+               /* mode */
+               uint8_t mode;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+struct as10x_cmd_header_t {
+       __le16 req_id;
+       __le16 prog;
+       __le16 version;
+       __le16 data_len;
+} __packed;
+
+#define DUMP_BLOCK_SIZE 16
+
+union as10x_dump_memory {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+               /* dump memory type request */
+               uint8_t dump_req;
+               /* register description */
+               struct as10x_register_addr reg_addr;
+               /* nb blocks to read */
+               __le16 num_blocks;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+               /* dump response */
+               uint8_t dump_rsp;
+               /* data */
+               union {
+                       uint8_t  data8[DUMP_BLOCK_SIZE];
+                       __le16 data16[DUMP_BLOCK_SIZE / sizeof(__le16)];
+                       __le32 data32[DUMP_BLOCK_SIZE / sizeof(__le32)];
+               } __packed u;
+       } __packed rsp;
+} __packed;
+
+union as10x_dumplog_memory {
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+               /* dump memory type request */
+               uint8_t dump_req;
+       } __packed req;
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+               /* dump response */
+               uint8_t dump_rsp;
+               /* dump data */
+               uint8_t data[DUMP_BLOCK_SIZE];
+       } __packed rsp;
+} __packed;
+
+union as10x_raw_data {
+       /* request */
+       struct {
+               __le16 proc_id;
+               uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
+                            - 2 /* proc_id */];
+       } __packed req;
+       /* response */
+       struct {
+               __le16 proc_id;
+               uint8_t error;
+               uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
+                            - 2 /* proc_id */ - 1 /* rc */];
+       } __packed rsp;
+} __packed;
+
+struct as10x_cmd_t {
+       struct as10x_cmd_header_t header;
+       union {
+               union as10x_turn_on             turn_on;
+               union as10x_turn_off            turn_off;
+               union as10x_set_tune            set_tune;
+               union as10x_get_tune_status     get_tune_status;
+               union as10x_get_tps             get_tps;
+               union as10x_common              common;
+               union as10x_add_pid_filter      add_pid_filter;
+               union as10x_del_pid_filter      del_pid_filter;
+               union as10x_start_streaming     start_streaming;
+               union as10x_stop_streaming      stop_streaming;
+               union as10x_get_demod_stats     get_demod_stats;
+               union as10x_get_impulse_resp    get_impulse_rsp;
+               union as10x_fw_context          context;
+               union as10x_set_register        set_register;
+               union as10x_get_register        get_register;
+               union as10x_cfg_change_mode     cfg_change_mode;
+               union as10x_dump_memory         dump_memory;
+               union as10x_dumplog_memory      dumplog_memory;
+               union as10x_raw_data            raw_data;
+       } __packed body;
+} __packed;
+
+struct as10x_token_cmd_t {
+       /* token cmd */
+       struct as10x_cmd_t c;
+       /* token response */
+       struct as10x_cmd_t r;
+} __packed;
+
+
+/**************************/
+/* FUNCTION DECLARATION   */
+/**************************/
+
+void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t proc_id,
+                     uint16_t cmd_len);
+int as10x_rsp_parse(struct as10x_cmd_t *r, uint16_t proc_id);
+
+/* as10x cmd */
+int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap);
+int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap);
+
+int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
+                      struct as10x_tune_args *ptune);
+
+int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
+                             struct as10x_tune_status *pstatus);
+
+int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap,
+                     struct as10x_tps *ptps);
+
+int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t  *adap,
+                             struct as10x_demod_stats *pdemod_stats);
+
+int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
+                              uint8_t *is_ready);
+
+/* as10x cmd stream */
+int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
+                            struct as10x_ts_filter *filter);
+int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
+                            uint16_t pid_value);
+
+int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap);
+int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap);
+
+/* as10x cmd cfg */
+int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap,
+                         uint16_t tag,
+                         uint32_t value);
+int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap,
+                         uint16_t tag,
+                         uint32_t *pvalue);
+
+int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode);
+int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id);
+#endif
diff --git a/drivers/media/usb/as102/as10x_cmd_cfg.c b/drivers/media/usb/as102/as10x_cmd_cfg.c
new file mode 100644 (file)
index 0000000..c87f2ca
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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.
+ */
+
+#include <linux/kernel.h>
+#include "as102_drv.h"
+#include "as10x_cmd.h"
+
+/***************************/
+/* FUNCTION DEFINITION     */
+/***************************/
+
+/**
+ * as10x_cmd_get_context - Send get context command to AS10x
+ * @adap:      pointer to AS10x bus adapter
+ * @tag:       context tag
+ * @pvalue:    pointer where to store context value read
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
+                         uint32_t *pvalue)
+{
+       int  error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.context.req));
+
+       /* fill command */
+       pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT);
+       pcmd->body.context.req.tag = cpu_to_le16(tag);
+       pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error  = adap->ops->xfer_cmd(adap,
+                                            (uint8_t *) pcmd,
+                                            sizeof(pcmd->body.context.req)
+                                            + HEADER_SIZE,
+                                            (uint8_t *) prsp,
+                                            sizeof(prsp->body.context.rsp)
+                                            + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response: context command do not follow the common response */
+       /* structure -> specific handling response parse required            */
+       error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
+
+       if (error == 0) {
+               /* Response OK -> get response data */
+               *pvalue = le32_to_cpu((__force __le32)prsp->body.context.rsp.reg_val.u.value32);
+               /* value returned is always a 32-bit value */
+       }
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_set_context - send set context command to AS10x
+ * @adap:      pointer to AS10x bus adapter
+ * @tag:       context tag
+ * @value:     value to set in context
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
+                         uint32_t value)
+{
+       int error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.context.req));
+
+       /* fill command */
+       pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT);
+       /* pcmd->body.context.req.reg_val.mode initialization is not required */
+       pcmd->body.context.req.reg_val.u.value32 = (__force u32)cpu_to_le32(value);
+       pcmd->body.context.req.tag = cpu_to_le16(tag);
+       pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error  = adap->ops->xfer_cmd(adap,
+                                            (uint8_t *) pcmd,
+                                            sizeof(pcmd->body.context.req)
+                                            + HEADER_SIZE,
+                                            (uint8_t *) prsp,
+                                            sizeof(prsp->body.context.rsp)
+                                            + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response: context command do not follow the common response */
+       /* structure -> specific handling response parse required            */
+       error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x
+ * @adap:      pointer to AS10x bus adapter
+ * @mode:      mode selected:
+ *             - ON    : 0x0 => eLNA always ON
+ *             - OFF   : 0x1 => eLNA always OFF
+ *             - AUTO  : 0x2 => eLNA follow hysteresis parameters
+ *                              to be ON or OFF
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode)
+{
+       int error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.cfg_change_mode.req));
+
+       /* fill command */
+       pcmd->body.cfg_change_mode.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE);
+       pcmd->body.cfg_change_mode.req.mode = mode;
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error  = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                               sizeof(pcmd->body.cfg_change_mode.req)
+                               + HEADER_SIZE, (uint8_t *) prsp,
+                               sizeof(prsp->body.cfg_change_mode.rsp)
+                               + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_context_rsp_parse - Parse context command response
+ * @prsp:       pointer to AS10x command response buffer
+ * @proc_id:    id of the command
+ *
+ * Since the contex command response does not follow the common
+ * response, a specific parse function is required.
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id)
+{
+       int err;
+
+       err = prsp->body.context.rsp.error;
+
+       if ((err == 0) &&
+           (le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) {
+               return 0;
+       }
+       return AS10X_CMD_ERROR;
+}
diff --git a/drivers/media/usb/as102/as10x_cmd_stream.c b/drivers/media/usb/as102/as10x_cmd_stream.c
new file mode 100644 (file)
index 0000000..126aea9
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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.
+ */
+
+#include <linux/kernel.h>
+#include "as102_drv.h"
+#include "as10x_cmd.h"
+
+/**
+ * as10x_cmd_add_PID_filter - send add filter command to AS10x
+ * @adap:      pointer to AS10x bus adapter
+ * @filter:    TSFilter filter for DVB-T
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
+                            struct as10x_ts_filter *filter)
+{
+       int error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.add_pid_filter.req));
+
+       /* fill command */
+       pcmd->body.add_pid_filter.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_SETFILTER);
+       pcmd->body.add_pid_filter.req.pid = cpu_to_le16(filter->pid);
+       pcmd->body.add_pid_filter.req.stream_type = filter->type;
+
+       if (filter->idx < 16)
+               pcmd->body.add_pid_filter.req.idx = filter->idx;
+       else
+               pcmd->body.add_pid_filter.req.idx = 0xFF;
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                               sizeof(pcmd->body.add_pid_filter.req)
+                               + HEADER_SIZE, (uint8_t *) prsp,
+                               sizeof(prsp->body.add_pid_filter.rsp)
+                               + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_SETFILTER_RSP);
+
+       if (error == 0) {
+               /* Response OK -> get response data */
+               filter->idx = prsp->body.add_pid_filter.rsp.filter_id;
+       }
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_del_PID_filter - Send delete filter command to AS10x
+ * @adap:         pointer to AS10x bus adapte
+ * @pid_value:    PID to delete
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
+                            uint16_t pid_value)
+{
+       int error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.del_pid_filter.req));
+
+       /* fill command */
+       pcmd->body.del_pid_filter.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_REMOVEFILTER);
+       pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                               sizeof(pcmd->body.del_pid_filter.req)
+                               + HEADER_SIZE, (uint8_t *) prsp,
+                               sizeof(prsp->body.del_pid_filter.rsp)
+                               + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_start_streaming - Send start streaming command to AS10x
+ * @adap:   pointer to AS10x bus adapter
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap)
+{
+       int error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.start_streaming.req));
+
+       /* fill command */
+       pcmd->body.start_streaming.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_START_STREAMING);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                               sizeof(pcmd->body.start_streaming.req)
+                               + HEADER_SIZE, (uint8_t *) prsp,
+                               sizeof(prsp->body.start_streaming.rsp)
+                               + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_stop_streaming - Send stop streaming command to AS10x
+ * @adap:   pointer to AS10x bus adapter
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap)
+{
+       int8_t error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.stop_streaming.req));
+
+       /* fill command */
+       pcmd->body.stop_streaming.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_STOP_STREAMING);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                               sizeof(pcmd->body.stop_streaming.req)
+                               + HEADER_SIZE, (uint8_t *) prsp,
+                               sizeof(prsp->body.stop_streaming.rsp)
+                               + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP);
+
+out:
+       return error;
+}
diff --git a/drivers/media/usb/as102/as10x_handle.h b/drivers/media/usb/as102/as10x_handle.h
new file mode 100644 (file)
index 0000000..d6b58c7
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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.
+ */
+#ifndef _AS10X_HANDLE_H
+#define _AS10X_HANDLE_H
+struct as10x_bus_adapter_t;
+struct as102_dev_t;
+
+#include "as10x_cmd.h"
+
+/* values for "mode" field */
+#define REGMODE8       8
+#define REGMODE16      16
+#define REGMODE32      32
+
+struct as102_priv_ops_t {
+       int (*upload_fw_pkt)(struct as10x_bus_adapter_t *bus_adap,
+                             unsigned char *buf, int buflen, int swap32);
+
+       int (*send_cmd)(struct as10x_bus_adapter_t *bus_adap,
+                        unsigned char *buf, int buflen);
+
+       int (*xfer_cmd)(struct as10x_bus_adapter_t *bus_adap,
+                        unsigned char *send_buf, int send_buf_len,
+                        unsigned char *recv_buf, int recv_buf_len);
+
+       int (*start_stream)(struct as102_dev_t *dev);
+       void (*stop_stream)(struct as102_dev_t *dev);
+
+       int (*reset_target)(struct as10x_bus_adapter_t *bus_adap);
+
+       int (*read_write)(struct as10x_bus_adapter_t *bus_adap, uint8_t mode,
+                         uint32_t rd_addr, uint16_t rd_len,
+                         uint32_t wr_addr, uint16_t wr_len);
+
+       int (*as102_read_ep2)(struct as10x_bus_adapter_t *bus_adap,
+                              unsigned char *recv_buf,
+                              int recv_buf_len);
+};
+#endif
index 2c6b7da137ed1bc2b20236c1336b1acec097d190..9eb77ac2153b06a60e65c781994901ba12208d6d 100644 (file)
@@ -46,6 +46,8 @@ struct au0828_board au0828_boards[] = {
                .name   = "Hauppauge HVR850",
                .tuner_type = TUNER_XC5000,
                .tuner_addr = 0x61,
+               .has_ir_i2c = 1,
+               .has_analog = 1,
                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
                .input = {
                        {
@@ -72,12 +74,7 @@ struct au0828_board au0828_boards[] = {
                .tuner_type = TUNER_XC5000,
                .tuner_addr = 0x61,
                .has_ir_i2c = 1,
-               /* The au0828 hardware i2c implementation does not properly
-                  support the xc5000's i2c clock stretching.  So we need to
-                  lower the clock frequency enough where the 15us clock
-                  stretch fits inside of a normal clock cycle, or else the
-                  au0828 fails to set the STOP bit.  A 30 KHz clock puts the
-                  clock pulse width at 18us */
+               .has_analog = 1,
                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
                .input = {
                        {
@@ -101,20 +98,20 @@ struct au0828_board au0828_boards[] = {
        },
        [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
                .name   = "Hauppauge HVR950Q rev xxF8",
-               .tuner_type = UNSET,
-               .tuner_addr = ADDR_UNSET,
+               .tuner_type = TUNER_XC5000,
+               .tuner_addr = 0x61,
                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
        },
        [AU0828_BOARD_DVICO_FUSIONHDTV7] = {
                .name   = "DViCO FusionHDTV USB",
-               .tuner_type = UNSET,
-               .tuner_addr = ADDR_UNSET,
+               .tuner_type = TUNER_XC5000,
+               .tuner_addr = 0x61,
                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
        },
        [AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
                .name = "Hauppauge Woodbury",
-               .tuner_type = UNSET,
-               .tuner_addr = ADDR_UNSET,
+               .tuner_type = TUNER_NXP_TDA18271,
+               .tuner_addr = 0x60,
                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
        },
 };
@@ -142,8 +139,7 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg)
                        mdelay(10);
                        return 0;
                } else {
-                       printk(KERN_ERR
-                               "%s(): Unknown command.\n", __func__);
+                       pr_err("%s(): Unknown command.\n", __func__);
                        return -EINVAL;
                }
                break;
@@ -177,12 +173,12 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
        case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
                break;
        default:
-               printk(KERN_WARNING "%s: warning: "
-                      "unknown hauppauge model #%d\n", __func__, tv.model);
+               pr_warn("%s: warning: unknown hauppauge model #%d\n",
+                       __func__, tv.model);
                break;
        }
 
-       printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+       pr_info("%s: hauppauge eeprom: model=%d\n",
               __func__, tv.model);
 }
 
@@ -228,16 +224,16 @@ void au0828_card_analog_fe_setup(struct au0828_dev *dev)
                sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
                                "au8522", 0x8e >> 1, NULL);
                if (sd == NULL)
-                       printk(KERN_ERR "analog subdev registration failed\n");
+                       pr_err("analog subdev registration failed\n");
        }
 
        /* Setup tuners */
-       if (dev->board.tuner_type != TUNER_ABSENT) {
+       if (dev->board.tuner_type != TUNER_ABSENT && dev->board.has_analog) {
                /* Load the tuner module, which does the attach */
                sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
                                "tuner", dev->board.tuner_addr, NULL);
                if (sd == NULL)
-                       printk(KERN_ERR "tuner subdev registration fail\n");
+                       pr_err("tuner subdev registration fail\n");
 
                tun_setup.mode_mask      = mode_mask;
                tun_setup.type           = dev->board.tuner_type;
index 56025e6894421e59db3dd2acf8a72b015b12c0ef..bc064803b6c7f6c2c6fb05b93c8fba7efb5cda22 100644 (file)
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
-#include "au0828.h"
-
 /*
  * 1 = General debug messages
  * 2 = USB handling
@@ -90,7 +90,7 @@ static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
                status = min(status, 0);
 
                if (status < 0) {
-                       printk(KERN_ERR "%s() Failed sending control message, error %d.\n",
+                       pr_err("%s() Failed sending control message, error %d.\n",
                                __func__, status);
                }
 
@@ -115,7 +115,7 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
                status = min(status, 0);
 
                if (status < 0) {
-                       printk(KERN_ERR "%s() Failed receiving control message, error %d.\n",
+                       pr_err("%s() Failed receiving control message, error %d.\n",
                                __func__, status);
                }
 
@@ -153,9 +153,7 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
 
        dprintk(1, "%s()\n", __func__);
 
-#ifdef CONFIG_VIDEO_AU0828_RC
        au0828_rc_unregister(dev);
-#endif
        /* Digital TV */
        au0828_dvb_unregister(dev);
 
@@ -199,15 +197,14 @@ static int au0828_usb_probe(struct usb_interface *interface,
         * not enough even for most Digital TV streams.
         */
        if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
-               printk(KERN_ERR "au0828: Device initialization failed.\n");
-               printk(KERN_ERR "au0828: Device must be connected to a "
-                      "high-speed USB 2.0 port.\n");
+               pr_err("au0828: Device initialization failed.\n");
+               pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n");
                return -ENODEV;
        }
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
-               printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
+               pr_err("%s() Unable to allocate memory\n", __func__);
                return -ENOMEM;
        }
 
@@ -266,10 +263,8 @@ static int au0828_usb_probe(struct usb_interface *interface,
                pr_err("%s() au0282_dev_register failed\n",
                       __func__);
 
-#ifdef CONFIG_VIDEO_AU0828_RC
        /* Remote controller */
        au0828_rc_register(dev);
-#endif
 
        /*
         * Store the pointer to the au0828_dev so it can be accessed in
@@ -277,7 +272,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
         */
        usb_set_intfdata(interface, dev);
 
-       printk(KERN_INFO "Registered device AU0828 [%s]\n",
+       pr_info("Registered device AU0828 [%s]\n",
                dev->board.name == NULL ? "Unset" : dev->board.name);
 
        mutex_unlock(&dev->lock);
@@ -285,13 +280,56 @@ static int au0828_usb_probe(struct usb_interface *interface,
        return retval;
 }
 
+static int au0828_suspend(struct usb_interface *interface,
+                               pm_message_t message)
+{
+       struct au0828_dev *dev = usb_get_intfdata(interface);
+
+       if (!dev)
+               return 0;
+
+       pr_info("Suspend\n");
+
+       au0828_rc_suspend(dev);
+       au0828_v4l2_suspend(dev);
+       au0828_dvb_suspend(dev);
+
+       /* FIXME: should suspend also ATV/DTV */
+
+       return 0;
+}
+
+static int au0828_resume(struct usb_interface *interface)
+{
+       struct au0828_dev *dev = usb_get_intfdata(interface);
+       if (!dev)
+               return 0;
+
+       pr_info("Resume\n");
+
+       /* Power Up the bridge */
+       au0828_write(dev, REG_600, 1 << 4);
+
+       /* Bring up the GPIO's and supporting devices */
+       au0828_gpio_setup(dev);
+
+       au0828_rc_resume(dev);
+       au0828_v4l2_resume(dev);
+       au0828_dvb_resume(dev);
+
+       /* FIXME: should resume also ATV/DTV */
+
+       return 0;
+}
+
 static struct usb_driver au0828_usb_driver = {
-       .name           = DRIVER_NAME,
+       .name           = KBUILD_MODNAME,
        .probe          = au0828_usb_probe,
        .disconnect     = au0828_usb_disconnect,
        .id_table       = au0828_usb_id_table,
-
-       /* FIXME: Add suspend and resume functions */
+       .suspend        = au0828_suspend,
+       .resume         = au0828_resume,
+       .reset_resume   = au0828_resume,
 };
 
 static int __init au0828_init(void)
@@ -299,27 +337,27 @@ static int __init au0828_init(void)
        int ret;
 
        if (au0828_debug & 1)
-               printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
+               pr_info("%s() Debugging is enabled\n", __func__);
 
        if (au0828_debug & 2)
-               printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
+               pr_info("%s() USB Debugging is enabled\n", __func__);
 
        if (au0828_debug & 4)
-               printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
+               pr_info("%s() I2C Debugging is enabled\n", __func__);
 
        if (au0828_debug & 8)
-               printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
+               pr_info("%s() Bridge Debugging is enabled\n",
                       __func__);
 
        if (au0828_debug & 16)
-               printk(KERN_INFO "%s() IR Debugging is enabled\n",
+               pr_info("%s() IR Debugging is enabled\n",
                       __func__);
 
-       printk(KERN_INFO "au0828 driver loaded\n");
+       pr_info("au0828 driver loaded\n");
 
        ret = usb_register(&au0828_usb_driver);
        if (ret)
-               printk(KERN_ERR "usb_register failed, error = %d\n", ret);
+               pr_err("usb_register failed, error = %d\n", ret);
 
        return ret;
 }
index d8b5d9480279a29441f0cadb47a4e36c59936855..00ab1563d142ed682dc91e76a80db44112504595 100644 (file)
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/device.h>
-#include <linux/suspend.h>
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
 
-#include "au0828.h"
 #include "au8522.h"
 #include "xc5000.h"
 #include "mxl5007t.h"
@@ -121,13 +121,13 @@ static void urb_completion(struct urb *purb)
                return;
        }
 
-       if (dev->urb_streaming == 0) {
+       if (!dev->urb_streaming) {
                dprintk(2, "%s: not streaming!\n", __func__);
                return;
        }
 
        if (ptype != PIPE_BULK) {
-               printk(KERN_ERR "%s: Unsupported URB type %d\n",
+               pr_err("%s: Unsupported URB type %d\n",
                       __func__, ptype);
                return;
        }
@@ -159,7 +159,10 @@ static int stop_urb_transfer(struct au0828_dev *dev)
 
        dprintk(2, "%s()\n", __func__);
 
-       dev->urb_streaming = 0;
+       if (!dev->urb_streaming)
+               return 0;
+
+       dev->urb_streaming = false;
        for (i = 0; i < URB_COUNT; i++) {
                if (dev->urbs[i]) {
                        usb_kill_urb(dev->urbs[i]);
@@ -202,8 +205,7 @@ static int start_urb_transfer(struct au0828_dev *dev)
                if (!purb->transfer_buffer) {
                        usb_free_urb(purb);
                        dev->urbs[i] = NULL;
-                       printk(KERN_ERR
-                              "%s: failed big buffer allocation, err = %d\n",
+                       pr_err("%s: failed big buffer allocation, err = %d\n",
                               __func__, ret);
                        goto err;
                }
@@ -224,13 +226,13 @@ static int start_urb_transfer(struct au0828_dev *dev)
                ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);
                if (ret != 0) {
                        stop_urb_transfer(dev);
-                       printk(KERN_ERR "%s: failed urb submission, "
-                              "err = %d\n", __func__, ret);
+                       pr_err("%s: failed urb submission, err = %d\n",
+                              __func__, ret);
                        return ret;
                }
        }
 
-       dev->urb_streaming = 1;
+       dev->urb_streaming = true;
        ret = 0;
 
 err:
@@ -268,7 +270,7 @@ static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
        if (!demux->dmx.frontend)
                return -EINVAL;
 
-       if (dvb) {
+       if (dvb->frontend) {
                mutex_lock(&dvb->lock);
                dvb->start_count++;
                dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
@@ -297,7 +299,7 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
 
        dprintk(1, "%s()\n", __func__);
 
-       if (dvb) {
+       if (dvb->frontend) {
                cancel_work_sync(&dev->restart_streaming);
 
                mutex_lock(&dvb->lock);
@@ -324,7 +326,7 @@ static void au0828_restart_dvb_streaming(struct work_struct *work)
                                              restart_streaming);
        struct au0828_dvb *dvb = &dev->dvb;
 
-       if (dev->urb_streaming == 0)
+       if (!dev->urb_streaming)
                return;
 
        dprintk(1, "Restarting streaming...!\n");
@@ -393,9 +395,8 @@ static int dvb_register(struct au0828_dev *dev)
                        if (!dev->dig_transfer_buffer[i]) {
                                result = -ENOMEM;
 
-                               printk(KERN_ERR
-                                      "%s: failed buffer allocation (errno = %d)\n",
-                                      DRIVER_NAME, result);
+                               pr_err("failed buffer allocation (errno = %d)\n",
+                                      result);
                                goto fail_adapter;
                        }
                }
@@ -404,11 +405,12 @@ static int dvb_register(struct au0828_dev *dev)
        INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming);
 
        /* register adapter */
-       result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
+       result = dvb_register_adapter(&dvb->adapter,
+                                     KBUILD_MODNAME, THIS_MODULE,
                                      &dev->usbdev->dev, adapter_nr);
        if (result < 0) {
-               printk(KERN_ERR "%s: dvb_register_adapter failed "
-                      "(errno = %d)\n", DRIVER_NAME, result);
+               pr_err("dvb_register_adapter failed (errno = %d)\n",
+                      result);
                goto fail_adapter;
        }
        dvb->adapter.priv = dev;
@@ -416,8 +418,8 @@ static int dvb_register(struct au0828_dev *dev)
        /* register frontend */
        result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
        if (result < 0) {
-               printk(KERN_ERR "%s: dvb_register_frontend failed "
-                      "(errno = %d)\n", DRIVER_NAME, result);
+               pr_err("dvb_register_frontend failed (errno = %d)\n",
+                      result);
                goto fail_frontend;
        }
 
@@ -436,8 +438,7 @@ static int dvb_register(struct au0828_dev *dev)
        dvb->demux.stop_feed  = au0828_dvb_stop_feed;
        result = dvb_dmx_init(&dvb->demux);
        if (result < 0) {
-               printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",
-                      DRIVER_NAME, result);
+               pr_err("dvb_dmx_init failed (errno = %d)\n", result);
                goto fail_dmx;
        }
 
@@ -446,31 +447,29 @@ static int dvb_register(struct au0828_dev *dev)
        dvb->dmxdev.capabilities = 0;
        result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
        if (result < 0) {
-               printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
-                      DRIVER_NAME, result);
+               pr_err("dvb_dmxdev_init failed (errno = %d)\n", result);
                goto fail_dmxdev;
        }
 
        dvb->fe_hw.source = DMX_FRONTEND_0;
        result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
        if (result < 0) {
-               printk(KERN_ERR "%s: add_frontend failed "
-                      "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);
+               pr_err("add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+                      result);
                goto fail_fe_hw;
        }
 
        dvb->fe_mem.source = DMX_MEMORY_FE;
        result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
        if (result < 0) {
-               printk(KERN_ERR "%s: add_frontend failed "
-                      "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);
+               pr_err("add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+                      result);
                goto fail_fe_mem;
        }
 
        result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
        if (result < 0) {
-               printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",
-                      DRIVER_NAME, result);
+               pr_err("connect_frontend failed (errno = %d)\n", result);
                goto fail_fe_conn;
        }
 
@@ -530,8 +529,7 @@ void au0828_dvb_unregister(struct au0828_dev *dev)
                for (i = 0; i < URB_COUNT; i++)
                        kfree(dev->dig_transfer_buffer[i]);
        }
-
-
+       dvb->frontend = NULL;
 }
 
 /* All the DVB attach calls go here, this function get's modified
@@ -596,12 +594,11 @@ int au0828_dvb_register(struct au0828_dev *dev)
                }
                break;
        default:
-               printk(KERN_WARNING "The frontend of your DVB/ATSC card "
-                      "isn't supported yet\n");
+               pr_warn("The frontend of your DVB/ATSC card isn't supported yet\n");
                break;
        }
        if (NULL == dvb->frontend) {
-               printk(KERN_ERR "%s() Frontend initialization failed\n",
+               pr_err("%s() Frontend initialization failed\n",
                       __func__);
                return -1;
        }
@@ -613,8 +610,49 @@ int au0828_dvb_register(struct au0828_dev *dev)
        if (ret < 0) {
                if (dvb->frontend->ops.release)
                        dvb->frontend->ops.release(dvb->frontend);
+               dvb->frontend = NULL;
                return ret;
        }
 
        return 0;
 }
+
+void au0828_dvb_suspend(struct au0828_dev *dev)
+{
+       struct au0828_dvb *dvb = &dev->dvb;
+       int rc;
+
+       if (dvb->frontend) {
+               if (dev->urb_streaming) {
+                       cancel_work_sync(&dev->restart_streaming);
+                       /* Stop transport */
+                       mutex_lock(&dvb->lock);
+                       stop_urb_transfer(dev);
+                       au0828_stop_transport(dev, 1);
+                       mutex_unlock(&dvb->lock);
+                       dev->need_urb_start = true;
+               }
+               /* suspend frontend - does tuner and fe to sleep */
+               rc = dvb_frontend_suspend(dvb->frontend);
+               pr_info("au0828_dvb_suspend(): Suspending DVB fe %d\n", rc);
+       }
+}
+
+void au0828_dvb_resume(struct au0828_dev *dev)
+{
+       struct au0828_dvb *dvb = &dev->dvb;
+       int rc;
+
+       if (dvb->frontend) {
+               /* resume frontend - does fe and tuner init */
+               rc = dvb_frontend_resume(dvb->frontend);
+               pr_info("au0828_dvb_resume(): Resuming DVB fe %d\n", rc);
+               if (dev->need_urb_start) {
+                       /* Start transport */
+                       mutex_lock(&dvb->lock);
+                       au0828_start_transport(dev);
+                       start_urb_transfer(dev);
+                       mutex_unlock(&dvb->lock);
+               }
+       }
+}
index daaeaf1b089cf1976c6204dacd53551af2b6ebb9..ae7ac6669769f3cdcc2d2ba01db5cc0c73ce5039 100644 (file)
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 
-#include "au0828.h"
 #include "media/tuner.h"
 #include <media/v4l2-common.h>
 
@@ -340,7 +341,7 @@ static struct i2c_algorithm au0828_i2c_algo_template = {
 /* ----------------------------------------------------------------------- */
 
 static struct i2c_adapter au0828_i2c_adap_template = {
-       .name              = DRIVER_NAME,
+       .name              = KBUILD_MODNAME,
        .owner             = THIS_MODULE,
        .algo              = &au0828_i2c_algo_template,
 };
@@ -365,7 +366,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
                rc = i2c_master_recv(c, &buf, 0);
                if (rc < 0)
                        continue;
-               printk(KERN_INFO "%s: i2c scan: found device @ 0x%x  [%s]\n",
+               pr_info("%s: i2c scan: found device @ 0x%x  [%s]\n",
                       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
        }
 }
@@ -381,7 +382,7 @@ int au0828_i2c_register(struct au0828_dev *dev)
 
        dev->i2c_adap.dev.parent = &dev->usbdev->dev;
 
-       strlcpy(dev->i2c_adap.name, DRIVER_NAME,
+       strlcpy(dev->i2c_adap.name, KBUILD_MODNAME,
                sizeof(dev->i2c_adap.name));
 
        dev->i2c_adap.algo = &dev->i2c_algo;
@@ -396,11 +397,11 @@ int au0828_i2c_register(struct au0828_dev *dev)
        dev->i2c_client.adapter = &dev->i2c_adap;
 
        if (0 == dev->i2c_rc) {
-               printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME);
+               pr_info("i2c bus registered\n");
                if (i2c_scan)
-                       do_i2c_scan(DRIVER_NAME, &dev->i2c_client);
+                       do_i2c_scan(KBUILD_MODNAME, &dev->i2c_client);
        } else
-               printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME);
+               pr_info("i2c bus register FAILED\n");
 
        return dev->i2c_rc;
 }
index fd0d3a90ce7d0294cd2f2bc3d0bdc3cdf7d25e21..63995f97dc653276abd5aaaab44e08c3dde0ba69 100644 (file)
@@ -17,6 +17,8 @@
   GNU General Public License for more details.
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -25,7 +27,9 @@
 #include <linux/slab.h>
 #include <media/rc-core.h>
 
-#include "au0828.h"
+static int disable_ir;
+module_param(disable_ir,        int, 0444);
+MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
 
 struct au0828_rc {
        struct au0828_dev *dev;
@@ -90,14 +94,19 @@ static int au8522_rc_read(struct au0828_rc *ir, u16 reg, int val,
 static int au8522_rc_andor(struct au0828_rc *ir, u16 reg, u8 mask, u8 value)
 {
        int rc;
-       char buf;
+       char buf, oldbuf;
 
        rc = au8522_rc_read(ir, reg, -1, &buf, 1);
        if (rc < 0)
                return rc;
 
+       oldbuf = buf;
        buf = (buf & ~mask) | (value & mask);
 
+       /* Nothing to do, just return */
+       if (buf == oldbuf)
+               return 0;
+
        return au8522_rc_write(ir, reg, buf);
 }
 
@@ -122,8 +131,11 @@ static int au0828_get_key_au8522(struct au0828_rc *ir)
 
        /* Check IR int */
        rc = au8522_rc_read(ir, 0xe1, -1, buf, 1);
-       if (rc < 0 || !(buf[0] & (1 << 4)))
+       if (rc < 0 || !(buf[0] & (1 << 4))) {
+               /* Be sure that IR is enabled */
+               au8522_rc_set(ir, 0xe0, 1 << 4);
                return 0;
+       }
 
        /* Something arrived. Get the data */
        rc = au8522_rc_read(ir, 0xe3, 0x11, buf, sizeof(buf));
@@ -135,8 +147,6 @@ static int au0828_get_key_au8522(struct au0828_rc *ir)
        /* Disable IR */
        au8522_rc_clear(ir, 0xe0, 1 << 4);
 
-       usleep_range(45000, 46000);
-
        /* Enable IR */
        au8522_rc_set(ir, 0xe0, 1 << 4);
 
@@ -243,10 +253,10 @@ static void au0828_rc_stop(struct rc_dev *rc)
 {
        struct au0828_rc *ir = rc->priv;
 
+       cancel_delayed_work_sync(&ir->work);
+
        /* Disable IR */
        au8522_rc_clear(ir, 0xe0, 1 << 4);
-
-       cancel_delayed_work_sync(&ir->work);
 }
 
 static int au0828_probe_i2c_ir(struct au0828_dev *dev)
@@ -273,7 +283,7 @@ int au0828_rc_register(struct au0828_dev *dev)
        int err = -ENOMEM;
        u16 i2c_rc_dev_addr = 0;
 
-       if (!dev->board.has_ir_i2c)
+       if (!dev->board.has_ir_i2c || disable_ir)
                return 0;
 
        i2c_rc_dev_addr = au0828_probe_i2c_ir(dev);
@@ -368,8 +378,13 @@ int au0828_rc_suspend(struct au0828_dev *dev)
        if (!ir)
                return 0;
 
+       pr_info("Stopping RC\n");
+
        cancel_delayed_work_sync(&ir->work);
 
+       /* Disable IR */
+       au8522_rc_clear(ir, 0xe0, 1 << 4);
+
        return 0;
 }
 
@@ -380,6 +395,11 @@ int au0828_rc_resume(struct au0828_dev *dev)
        if (!ir)
                return 0;
 
+       pr_info("Restarting RC\n");
+
+       /* Enable IR */
+       au8522_rc_set(ir, 0xe0, 1 << 4);
+
        schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
 
        return 0;
index 63f593070ee8b14be8f98e70dc1ab8e8c28c644e..932d24f42b247d7f13ee83534961fcf281aaf1cc 100644 (file)
    02110-1301, USA.
  */
 
+#include "au0828.h"
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 
-#include "au0828.h"
-
 static unsigned int vbibufs = 5;
 module_param(vbibufs, int, 0644);
 MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
index 98f7ea1d6d6382109cfb119ffb62c6789693597b..5f337b118bffe36e9969c3a8963e9871034ffce1 100644 (file)
  *
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/device.h>
-#include <linux/suspend.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
 #include <media/tuner.h>
-#include "au0828.h"
 #include "au0828-reg.h"
 
 static DEFINE_MUTEX(au0828_sysfs_lock);
@@ -53,7 +53,7 @@ MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
 #define au0828_isocdbg(fmt, arg...) \
 do {\
        if (isoc_debug) { \
-               printk(KERN_INFO "au0828 %s :"fmt, \
+               pr_info("au0828 %s :"fmt, \
                       __func__ , ##arg);          \
        } \
   } while (0)
@@ -106,12 +106,12 @@ static inline void print_err_status(struct au0828_dev *dev,
 static int check_dev(struct au0828_dev *dev)
 {
        if (dev->dev_state & DEV_DISCONNECTED) {
-               printk(KERN_INFO "v4l2 ioctl: device not present\n");
+               pr_info("v4l2 ioctl: device not present\n");
                return -ENODEV;
        }
 
        if (dev->dev_state & DEV_MISCONFIGURED) {
-               printk(KERN_INFO "v4l2 ioctl: device is misconfigured; "
+               pr_info("v4l2 ioctl: device is misconfigured; "
                       "close and open it again\n");
                return -EIO;
        }
@@ -159,6 +159,7 @@ static void au0828_irq_callback(struct urb *urb)
                au0828_isocdbg("urb resubmit failed (error=%i)\n",
                               urb->status);
        }
+       dev->stream_state = STREAM_ON;
 }
 
 /*
@@ -198,6 +199,8 @@ static void au0828_uninit_isoc(struct au0828_dev *dev)
        dev->isoc_ctl.urb = NULL;
        dev->isoc_ctl.transfer_buffer = NULL;
        dev->isoc_ctl.num_bufs = 0;
+
+       dev->stream_state = STREAM_OFF;
 }
 
 /*
@@ -717,7 +720,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
        if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                rc = videobuf_iolock(vq, &buf->vb, NULL);
                if (rc < 0) {
-                       printk(KERN_INFO "videobuf_iolock failed\n");
+                       pr_info("videobuf_iolock failed\n");
                        goto fail;
                }
        }
@@ -730,7 +733,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                                      AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
                                      au0828_isoc_copy);
                if (rc < 0) {
-                       printk(KERN_INFO "au0828_init_isoc failed\n");
+                       pr_info("au0828_init_isoc failed\n");
                        goto fail;
                }
        }
@@ -801,7 +804,7 @@ static int au0828_analog_stream_enable(struct au0828_dev *d)
                /* set au0828 interface0 to AS5 here again */
                ret = usb_set_interface(d->usbdev, 0, 5);
                if (ret < 0) {
-                       printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
+                       pr_info("Au0828 can't set alt setting to 5!\n");
                        return -EBUSY;
                }
        }
@@ -1090,7 +1093,7 @@ static int au0828_v4l2_close(struct file *filp)
                   USB bandwidth */
                ret = usb_set_interface(dev->usbdev, 0, 0);
                if (ret < 0)
-                       printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
+                       pr_info("Au0828 can't set alternate to 0!\n");
        }
        mutex_unlock(&dev->lock);
 
@@ -1344,7 +1347,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                return rc;
 
        if (videobuf_queue_is_busy(&fh->vb_vidq)) {
-               printk(KERN_INFO "%s queue busy\n", __func__);
+               pr_info("%s queue busy\n", __func__);
                rc = -EBUSY;
                goto out;
        }
@@ -1868,6 +1871,69 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
        return rc;
 }
 
+void au0828_v4l2_suspend(struct au0828_dev *dev)
+{
+       struct urb *urb;
+       int i;
+
+       pr_info("stopping V4L2\n");
+
+       if (dev->stream_state == STREAM_ON) {
+               pr_info("stopping V4L2 active URBs\n");
+               au0828_analog_stream_disable(dev);
+               /* stop urbs */
+               for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+                       urb = dev->isoc_ctl.urb[i];
+                       if (urb) {
+                               if (!irqs_disabled())
+                                       usb_kill_urb(urb);
+                               else
+                                       usb_unlink_urb(urb);
+                       }
+               }
+       }
+
+       if (dev->vid_timeout_running)
+               del_timer_sync(&dev->vid_timeout);
+       if (dev->vbi_timeout_running)
+               del_timer_sync(&dev->vbi_timeout);
+}
+
+void au0828_v4l2_resume(struct au0828_dev *dev)
+{
+       int i, rc;
+
+       pr_info("restarting V4L2\n");
+
+       if (dev->stream_state == STREAM_ON) {
+               au0828_stream_interrupt(dev);
+               au0828_init_tuner(dev);
+       }
+
+       if (dev->vid_timeout_running)
+               mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+       if (dev->vbi_timeout_running)
+               mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+
+       /* If we were doing ac97 instead of i2s, it would go here...*/
+       au0828_i2s_init(dev);
+
+       au0828_analog_stream_enable(dev);
+
+       if (!(dev->stream_state == STREAM_ON)) {
+               au0828_analog_stream_reset(dev);
+               /* submit urbs */
+               for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+                       rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+                       if (rc) {
+                               au0828_isocdbg("submit of urb %i failed (error=%i)\n",
+                                              i, rc);
+                               au0828_uninit_isoc(dev);
+                       }
+               }
+       }
+}
+
 static struct v4l2_file_operations au0828_v4l_fops = {
        .owner      = THIS_MODULE,
        .open       = au0828_v4l2_open,
@@ -1939,7 +2005,7 @@ int au0828_analog_register(struct au0828_dev *dev,
        retval = usb_set_interface(dev->usbdev,
                        interface->cur_altsetting->desc.bInterfaceNumber, 5);
        if (retval != 0) {
-               printk(KERN_INFO "Failure setting usb interface0 to as5\n");
+               pr_info("Failure setting usb interface0 to as5\n");
                return retval;
        }
 
@@ -1963,7 +2029,7 @@ int au0828_analog_register(struct au0828_dev *dev,
                }
        }
        if (!(dev->isoc_in_endpointaddr)) {
-               printk(KERN_INFO "Could not locate isoc endpoint\n");
+               pr_info("Could not locate isoc endpoint\n");
                kfree(dev);
                return -ENODEV;
        }
index 96bec05d7dac1abd153baa53cfa84b25c1d7a27b..36815a369c68f860fc910b9e49e79e3247acfcba 100644 (file)
@@ -19,6 +19,8 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/usb.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -42,7 +44,6 @@
 #include "au0828-reg.h"
 #include "au0828-cards.h"
 
-#define DRIVER_NAME "au0828"
 #define URB_COUNT   16
 #define URB_BUFSIZE (0xe522)
 
@@ -89,6 +90,7 @@ struct au0828_board {
        unsigned char tuner_addr;
        unsigned char i2c_clk_divider;
        unsigned char has_ir_i2c:1;
+       unsigned char has_analog:1;
        struct au0828_input input[AU0828_MAX_INPUT];
 
 };
@@ -266,8 +268,8 @@ struct au0828_dev {
        char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc
                                                   transfer */
 
-       /* USB / URB Related */
-       int             urb_streaming;
+       /* DVB USB / URB Related */
+       bool            urb_streaming, need_urb_start;
        struct urb      *urbs[URB_COUNT];
 
        /* Preallocated transfer digital transfer buffers */
@@ -311,22 +313,38 @@ int au0828_analog_register(struct au0828_dev *dev,
                           struct usb_interface *interface);
 int au0828_analog_stream_disable(struct au0828_dev *d);
 void au0828_analog_unregister(struct au0828_dev *dev);
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+void au0828_v4l2_suspend(struct au0828_dev *dev);
+void au0828_v4l2_resume(struct au0828_dev *dev);
+#else
+static inline void au0828_v4l2_suspend(struct au0828_dev *dev) { };
+static inline void au0828_v4l2_resume(struct au0828_dev *dev) { };
+#endif
 
 /* ----------------------------------------------------------- */
 /* au0828-dvb.c */
 extern int au0828_dvb_register(struct au0828_dev *dev);
 extern void au0828_dvb_unregister(struct au0828_dev *dev);
+void au0828_dvb_suspend(struct au0828_dev *dev);
+void au0828_dvb_resume(struct au0828_dev *dev);
 
 /* au0828-vbi.c */
 extern struct videobuf_queue_ops au0828_vbi_qops;
 
 #define dprintk(level, fmt, arg...)\
        do { if (au0828_debug & level)\
-               printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
+               printk(KERN_DEBUG pr_fmt(fmt), ## arg);\
        } while (0)
 
 /* au0828-input.c */
-int au0828_rc_register(struct au0828_dev *dev);
-void au0828_rc_unregister(struct au0828_dev *dev);
-int au0828_rc_suspend(struct au0828_dev *dev);
-int au0828_rc_resume(struct au0828_dev *dev);
+#ifdef CONFIG_VIDEO_AU0828_RC
+extern int au0828_rc_register(struct au0828_dev *dev);
+extern void au0828_rc_unregister(struct au0828_dev *dev);
+extern int au0828_rc_suspend(struct au0828_dev *dev);
+extern int au0828_rc_resume(struct au0828_dev *dev);
+#else
+static inline int au0828_rc_register(struct au0828_dev *dev) { return 0; }
+static inline void au0828_rc_unregister(struct au0828_dev *dev) { }
+static inline int au0828_rc_suspend(struct au0828_dev *dev) { return 0; }
+static inline int au0828_rc_resume(struct au0828_dev *dev) { return 0; }
+#endif
index a428c10e1a1657dbcb1f767c90993f66fcba1ea4..40a69879fc0ad91993e375637b2e41a6b32e0156 100644 (file)
@@ -1595,7 +1595,7 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
                if_freq = 16000000;
        }
 
-       cx231xx_info("Enter IF=%zd\n",
+       cx231xx_info("Enter IF=%zu\n",
                        ARRAY_SIZE(Dif_set_array));
        for (i = 0; i < ARRAY_SIZE(Dif_set_array); i++) {
                if (Dif_set_array[i].if_freq == if_freq) {
@@ -2223,7 +2223,7 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
        if (status < 0)
                return status;
 
-       tmp = le32_to_cpu(*((u32 *) value));
+       tmp = le32_to_cpu(*((__le32 *) value));
 
        switch (mode) {
        case POLARIS_AVMODE_ENXTERNAL_AV:
@@ -2444,7 +2444,7 @@ int cx231xx_power_suspend(struct cx231xx *dev)
        if (status > 0)
                return status;
 
-       tmp = le32_to_cpu(*((u32 *) value));
+       tmp = le32_to_cpu(*((__le32 *) value));
        tmp &= (~PWR_MODE_MASK);
 
        value[0] = (u8) tmp;
@@ -2472,7 +2472,7 @@ int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask)
        if (status < 0)
                return status;
 
-       tmp = le32_to_cpu(*((u32 *) value));
+       tmp = le32_to_cpu(*((__le32 *) value));
        tmp |= ep_mask;
        value[0] = (u8) tmp;
        value[1] = (u8) (tmp >> 8);
@@ -2497,7 +2497,7 @@ int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask)
        if (status < 0)
                return status;
 
-       tmp = le32_to_cpu(*((u32 *) value));
+       tmp = le32_to_cpu(*((__le32 *) value));
        tmp &= (~ep_mask);
        value[0] = (u8) tmp;
        value[1] = (u8) (tmp >> 8);
@@ -2644,7 +2644,7 @@ static int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 gpio_val)
 {
        int status = 0;
 
-       gpio_val = cpu_to_le32(gpio_val);
+       gpio_val = (__force u32)cpu_to_le32(gpio_val);
        status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&gpio_val, 4, 0, 0);
 
        return status;
@@ -2652,7 +2652,7 @@ static int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 gpio_val)
 
 static int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 *gpio_val)
 {
-       u32 tmp;
+       __le32 tmp;
        int status = 0;
 
        status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&tmp, 4, 0, 1);
index 8039b769f2580fd7409d56b0a4e7cd1078a75ee4..791f00c6276b1e489e38f019d4e7bbe40362a0e2 100644 (file)
@@ -705,7 +705,7 @@ struct cx231xx_board cx231xx_boards[] = {
                },
        },
        [CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx] = {
-               .name = "Hauppauge WinTV 930C-HD (1113xx) / PCTV QuatroStick 521e",
+               .name = "Hauppauge WinTV 930C-HD (1113xx) / HVR-900H (111xxx) / PCTV QuatroStick 521e",
                .tuner_type = TUNER_NXP_TDA18271,
                .tuner_addr = 0x60,
                .tuner_gpio = RDE250_XCV_TUNER,
@@ -744,7 +744,7 @@ struct cx231xx_board cx231xx_boards[] = {
                } },
        },
        [CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx] = {
-               .name = "Hauppauge WinTV 930C-HD (1114xx) / PCTV QuatroStick 522e",
+               .name = "Hauppauge WinTV 930C-HD (1114xx) / HVR-901H (1114xx) / PCTV QuatroStick 522e",
                .tuner_type = TUNER_ABSENT,
                .tuner_addr = 0x60,
                .tuner_gpio = RDE250_XCV_TUNER,
@@ -815,6 +815,12 @@ struct usb_device_id cx231xx_id_table[] = {
         .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx},
        {USB_DEVICE(0x2040, 0xb131),
         .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx},
+       /* Hauppauge WinTV-HVR-900-H */
+       {USB_DEVICE(0x2040, 0xb138),
+        .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx},
+       /* Hauppauge WinTV-HVR-901-H */
+       {USB_DEVICE(0x2040, 0xb139),
+        .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx},
        {USB_DEVICE(0x2040, 0xb140),
         .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
        {USB_DEVICE(0x2040, 0xc200),
index 513194aa6561c76d70f45a7286a6456c52153325..180103e48036727e322399c53437599ced61b8c5 100644 (file)
@@ -1491,7 +1491,7 @@ int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode)
        if (status < 0)
                return status;
 
-       tmp = le32_to_cpu(*((u32 *) value));
+       tmp = le32_to_cpu(*((__le32 *) value));
        tmp |= mode;
 
        value[0] = (u8) tmp;
index 1fa79741d1991f0709cfebfb961d5f11d54fb166..6c7b5e250eed7fc2903eae3f56039ed195fd4d33 100644 (file)
@@ -403,8 +403,6 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
 
 int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
 {
-       int status = 0;
-
        if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
 
                struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
@@ -423,7 +421,7 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
 
        }
 
-       return status;
+       return 0;
 }
 
 int cx231xx_reset_analog_tuner(struct cx231xx *dev)
@@ -740,7 +738,7 @@ static int dvb_init(struct cx231xx *dev)
                        goto out_free;
                }
 
-               dev->dvb->frontend->ops.i2c_gate_ctrl = 0;
+               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
 
                /* define general-purpose callback pointer */
                dvb->frontend->callback = cx231xx_tuner_callback;
@@ -773,7 +771,7 @@ static int dvb_init(struct cx231xx *dev)
                        goto out_free;
                }
 
-               dev->dvb->frontend->ops.i2c_gate_ctrl = 0;
+               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
 
                /* define general-purpose callback pointer */
                dvb->frontend->callback = cx231xx_tuner_callback;
index 66645b02c854dd66435f9bfcb2e5f2f8e390506e..5b34323ad207950e3025ee9226b7456f358ddecc 100644 (file)
@@ -141,3 +141,10 @@ config DVB_USB_RTL28XXU
        help
          Say Y here to support the Realtek RTL28xxU DVB USB receiver.
 
+config DVB_USB_DVBSKY
+       tristate "DVBSky USB support"
+       depends on DVB_USB_V2
+       select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
+       help
+         Say Y here to support the USB receivers from DVBSky.
index bc38f03394cda0e1a397b390f354b620fe486a73..f10d4df0eae5c2962e4a20de60de3145a082ea83 100644 (file)
@@ -37,6 +37,9 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
 dvb-usb-rtl28xxu-objs := rtl28xxu.o
 obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
 
+dvb-usb-dvbsky-objs := dvbsky.o
+obj-$(CONFIG_DVB_USB_DVBSKY) += dvb-usb-dvbsky.o
+
 ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
 ccflags-y += -I$(srctree)/drivers/media/tuners
index 5ca738ab44e000911dec36cecdc1f6818ec6a7c2..16c0b7d4f8e701e58bb23191d66ca74951a0fa1e 100644 (file)
@@ -419,7 +419,7 @@ static int af9015_eeprom_hash(struct dvb_usb_device *d)
        /* calculate checksum */
        for (i = 0; i < AF9015_EEPROM_SIZE / sizeof(u32); i++) {
                state->eeprom_sum *= GOLDEN_RATIO_PRIME_32;
-               state->eeprom_sum += le32_to_cpu(((u32 *)buf)[i]);
+               state->eeprom_sum += le32_to_cpu(((__le32 *)buf)[i]);
        }
 
        for (i = 0; i < AF9015_EEPROM_SIZE; i += 16)
index c82beac0e0cbfd1fa9f3225bf044e55eab7de410..00758c83eec733475be5596818a5347868cde089 100644 (file)
@@ -193,6 +193,92 @@ static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val,
        return af9035_wr_regs(d, reg, &val, 1);
 }
 
+static int af9035_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr,
+               void *platform_data, struct i2c_adapter *adapter)
+{
+       int ret, num;
+       struct state *state = d_to_priv(d);
+       struct i2c_client *client;
+       struct i2c_board_info board_info = {
+               .addr = addr,
+               .platform_data = platform_data,
+       };
+
+       strlcpy(board_info.type, type, I2C_NAME_SIZE);
+
+       /* find first free client */
+       for (num = 0; num < AF9035_I2C_CLIENT_MAX; num++) {
+               if (state->i2c_client[num] == NULL)
+                       break;
+       }
+
+       dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
+
+       if (num == AF9035_I2C_CLIENT_MAX) {
+               dev_err(&d->udev->dev, "%s: I2C client out of index\n",
+                               KBUILD_MODNAME);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       request_module(board_info.type);
+
+       /* register I2C device */
+       client = i2c_new_device(adapter, &board_info);
+       if (client == NULL || client->dev.driver == NULL) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       /* increase I2C driver usage count */
+       if (!try_module_get(client->dev.driver->owner)) {
+               i2c_unregister_device(client);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       state->i2c_client[num] = client;
+       return 0;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static void af9035_del_i2c_dev(struct dvb_usb_device *d)
+{
+       int num;
+       struct state *state = d_to_priv(d);
+       struct i2c_client *client;
+
+       /* find last used client */
+       num = AF9035_I2C_CLIENT_MAX;
+       while (num--) {
+               if (state->i2c_client[num] != NULL)
+                       break;
+       }
+
+       dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
+
+       if (num == -1) {
+               dev_err(&d->udev->dev, "%s: I2C client out of index\n",
+                               KBUILD_MODNAME);
+               goto err;
+       }
+
+       client = state->i2c_client[num];
+
+       /* decrease I2C driver usage count */
+       module_put(client->dev.driver->owner);
+
+       /* unregister I2C device */
+       i2c_unregister_device(client);
+
+       state->i2c_client[num] = NULL;
+       return;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed\n", __func__);
+}
+
 static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
                struct i2c_msg msg[], int num)
 {
@@ -204,7 +290,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
                return -EAGAIN;
 
        /*
-        * I2C sub header is 5 bytes long. Meaning of those bytes are:
+        * AF9035 I2C sub header is 5 bytes long. Meaning of those bytes are:
         * 0: data len
         * 1: I2C addr << 1
         * 2: reg addr len
@@ -218,110 +304,156 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
         * NOTE: As a firmware knows tuner type there is very small possibility
         * there could be some tuner I2C hacks done by firmware and this may
         * lead problems if firmware expects those bytes are used.
+        *
+        * TODO: Here is few hacks. AF9035 chip integrates AF9033 demodulator.
+        * IT9135 chip integrates AF9033 demodulator and RF tuner. For dual
+        * tuner devices, there is also external AF9033 demodulator connected
+        * via external I2C bus. All AF9033 demod I2C traffic, both single and
+        * dual tuner configuration, is covered by firmware - actual USB IO
+        * looks just like a memory access.
+        * In case of IT913x chip, there is own tuner driver. It is implemented
+        * currently as a I2C driver, even tuner IP block is likely build
+        * directly into the demodulator memory space and there is no own I2C
+        * bus. I2C subsystem does not allow register multiple devices to same
+        * bus, having same slave address. Due to that we reuse demod address,
+        * shifted by one bit, on that case.
+        *
+        * For IT930x we use a different command and the sub header is
+        * different as well:
+        * 0: data len
+        * 1: I2C bus (0x03 seems to be only value used)
+        * 2: I2C addr << 1
         */
-       if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
-                       (msg[1].flags & I2C_M_RD)) {
+#define AF9035_IS_I2C_XFER_WRITE_READ(_msg, _num) \
+       (_num == 2 && !(_msg[0].flags & I2C_M_RD) && (_msg[1].flags & I2C_M_RD))
+#define AF9035_IS_I2C_XFER_WRITE(_msg, _num) \
+       (_num == 1 && !(_msg[0].flags & I2C_M_RD))
+#define AF9035_IS_I2C_XFER_READ(_msg, _num) \
+       (_num == 1 && (_msg[0].flags & I2C_M_RD))
+
+       if (AF9035_IS_I2C_XFER_WRITE_READ(msg, num)) {
                if (msg[0].len > 40 || msg[1].len > 40) {
                        /* TODO: correct limits > 40 */
                        ret = -EOPNOTSUPP;
-               } else if ((msg[0].addr == state->af9033_config[0].i2c_addr) ||
-                          (msg[0].addr == state->af9033_config[1].i2c_addr)) {
+               } else if ((msg[0].addr == state->af9033_i2c_addr[0]) ||
+                          (msg[0].addr == state->af9033_i2c_addr[1]) ||
+                          (state->chip_type == 0x9135)) {
                        /* demod access via firmware interface */
                        u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
                                        msg[0].buf[2];
 
-                       if (msg[0].addr == state->af9033_config[1].i2c_addr)
+                       if (msg[0].addr == state->af9033_i2c_addr[1] ||
+                           msg[0].addr == (state->af9033_i2c_addr[1] >> 1))
                                reg |= 0x100000;
 
                        ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
                                        msg[1].len);
                } else {
-                       /* I2C */
+                       /* I2C write + read */
                        u8 buf[MAX_XFER_SIZE];
                        struct usb_req req = { CMD_I2C_RD, 0, 5 + msg[0].len,
                                        buf, msg[1].len, msg[1].buf };
 
-                       if (5 + msg[0].len > sizeof(buf)) {
-                               dev_warn(&d->udev->dev,
-                                        "%s: i2c xfer: len=%d is too big!\n",
-                                        KBUILD_MODNAME, msg[0].len);
-                               ret = -EOPNOTSUPP;
-                               goto unlock;
+                       if (state->chip_type == 0x9306) {
+                               req.cmd = CMD_GENERIC_I2C_RD;
+                               req.wlen = 3 + msg[0].len;
                        }
                        req.mbox |= ((msg[0].addr & 0x80)  >>  3);
+
                        buf[0] = msg[1].len;
-                       buf[1] = msg[0].addr << 1;
-                       buf[2] = 0x00; /* reg addr len */
-                       buf[3] = 0x00; /* reg addr MSB */
-                       buf[4] = 0x00; /* reg addr LSB */
-                       memcpy(&buf[5], msg[0].buf, msg[0].len);
+                       if (state->chip_type == 0x9306) {
+                               buf[1] = 0x03; /* I2C bus */
+                               buf[2] = msg[0].addr << 1;
+                               memcpy(&buf[3], msg[0].buf, msg[0].len);
+                       } else {
+                               buf[1] = msg[0].addr << 1;
+                               buf[2] = 0x00; /* reg addr len */
+                               buf[3] = 0x00; /* reg addr MSB */
+                               buf[4] = 0x00; /* reg addr LSB */
+                               memcpy(&buf[5], msg[0].buf, msg[0].len);
+                       }
                        ret = af9035_ctrl_msg(d, &req);
                }
-       } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+       } else if (AF9035_IS_I2C_XFER_WRITE(msg, num)) {
                if (msg[0].len > 40) {
                        /* TODO: correct limits > 40 */
                        ret = -EOPNOTSUPP;
-               } else if ((msg[0].addr == state->af9033_config[0].i2c_addr) ||
-                          (msg[0].addr == state->af9033_config[1].i2c_addr)) {
+               } else if ((msg[0].addr == state->af9033_i2c_addr[0]) ||
+                          (msg[0].addr == state->af9033_i2c_addr[1]) ||
+                          (state->chip_type == 0x9135)) {
                        /* demod access via firmware interface */
                        u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
                                        msg[0].buf[2];
 
-                       if (msg[0].addr == state->af9033_config[1].i2c_addr)
+                       if (msg[0].addr == state->af9033_i2c_addr[1] ||
+                           msg[0].addr == (state->af9033_i2c_addr[1] >> 1))
                                reg |= 0x100000;
 
                        ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
                                        msg[0].len - 3);
                } else {
-                       /* I2C */
+                       /* I2C write */
                        u8 buf[MAX_XFER_SIZE];
                        struct usb_req req = { CMD_I2C_WR, 0, 5 + msg[0].len,
                                        buf, 0, NULL };
 
-                       if (5 + msg[0].len > sizeof(buf)) {
-                               dev_warn(&d->udev->dev,
-                                        "%s: i2c xfer: len=%d is too big!\n",
-                                        KBUILD_MODNAME, msg[0].len);
-                               ret = -EOPNOTSUPP;
-                               goto unlock;
+                       if (state->chip_type == 0x9306) {
+                               req.cmd = CMD_GENERIC_I2C_WR;
+                               req.wlen = 3 + msg[0].len;
                        }
+
                        req.mbox |= ((msg[0].addr & 0x80)  >>  3);
                        buf[0] = msg[0].len;
-                       buf[1] = msg[0].addr << 1;
-                       buf[2] = 0x00; /* reg addr len */
-                       buf[3] = 0x00; /* reg addr MSB */
-                       buf[4] = 0x00; /* reg addr LSB */
-                       memcpy(&buf[5], msg[0].buf, msg[0].len);
+                       if (state->chip_type == 0x9306) {
+                               buf[1] = 0x03; /* I2C bus */
+                               buf[2] = msg[0].addr << 1;
+                               memcpy(&buf[3], msg[0].buf, msg[0].len);
+                       } else {
+                               buf[1] = msg[0].addr << 1;
+                               buf[2] = 0x00; /* reg addr len */
+                               buf[3] = 0x00; /* reg addr MSB */
+                               buf[4] = 0x00; /* reg addr LSB */
+                               memcpy(&buf[5], msg[0].buf, msg[0].len);
+                       }
                        ret = af9035_ctrl_msg(d, &req);
                }
-       } else if (num == 1 && (msg[0].flags & I2C_M_RD)) {
+       } else if (AF9035_IS_I2C_XFER_READ(msg, num)) {
                if (msg[0].len > 40) {
                        /* TODO: correct limits > 40 */
                        ret = -EOPNOTSUPP;
                } else {
-                       /* I2C */
+                       /* I2C read */
                        u8 buf[5];
                        struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
-                                       buf, msg[0].len, msg[0].buf };
+                                               buf, msg[0].len, msg[0].buf };
+
+                       if (state->chip_type == 0x9306) {
+                               req.cmd = CMD_GENERIC_I2C_RD;
+                               req.wlen = 3;
+                       }
                        req.mbox |= ((msg[0].addr & 0x80)  >>  3);
                        buf[0] = msg[0].len;
-                       buf[1] = msg[0].addr << 1;
-                       buf[2] = 0x00; /* reg addr len */
-                       buf[3] = 0x00; /* reg addr MSB */
-                       buf[4] = 0x00; /* reg addr LSB */
+                       if (state->chip_type == 0x9306) {
+                               buf[1] = 0x03; /* I2C bus */
+                               buf[2] = msg[0].addr << 1;
+                       } else {
+                               buf[1] = msg[0].addr << 1;
+                               buf[2] = 0x00; /* reg addr len */
+                               buf[3] = 0x00; /* reg addr MSB */
+                               buf[4] = 0x00; /* reg addr LSB */
+                       }
                        ret = af9035_ctrl_msg(d, &req);
                }
        } else {
                /*
                 * We support only three kind of I2C transactions:
-                * 1) 1 x read + 1 x write (repeated start)
+                * 1) 1 x write + 1 x read (repeated start)
                 * 2) 1 x write
                 * 3) 1 x read
                 */
                ret = -EOPNOTSUPP;
        }
 
-unlock:
        mutex_unlock(&d->i2c_mutex);
 
        if (ret < 0)
@@ -371,6 +503,9 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
                else
                        *name = AF9035_FIRMWARE_IT9135_V1;
                state->eeprom_addr = EEPROM_BASE_IT9135;
+       } else if (state->chip_type == 0x9306) {
+               *name = AF9035_FIRMWARE_IT9303;
+               state->eeprom_addr = EEPROM_BASE_IT9135;
        } else {
                *name = AF9035_FIRMWARE_AF9035;
                state->eeprom_addr = EEPROM_BASE_AF9035;
@@ -536,6 +671,7 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
        u8 tmp;
        struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
        struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf };
+
        dev_dbg(&d->udev->dev, "%s:\n", __func__);
 
        /*
@@ -579,7 +715,8 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
                if (!tmp)
                        tmp = 0x3a;
 
-               if (state->chip_type == 0x9135) {
+               if ((state->chip_type == 0x9135) ||
+                               (state->chip_type == 0x9306)) {
                        ret = af9035_wr_reg(d, 0x004bfb, tmp);
                        if (ret < 0)
                                goto err;
@@ -640,23 +777,26 @@ static int af9035_read_config(struct dvb_usb_device *d)
        u16 tmp16, addr;
 
        /* demod I2C "address" */
-       state->af9033_config[0].i2c_addr = 0x38;
-       state->af9033_config[1].i2c_addr = 0x3a;
+       state->af9033_i2c_addr[0] = 0x38;
+       state->af9033_i2c_addr[1] = 0x3a;
        state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
        state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
        state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
        state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
 
-       /* eeprom memory mapped location */
        if (state->chip_type == 0x9135) {
+               /* feed clock for integrated RF tuner */
+               state->af9033_config[0].dyn0_clk = true;
+               state->af9033_config[1].dyn0_clk = true;
+
                if (state->chip_version == 0x02) {
                        state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60;
                        state->af9033_config[1].tuner = AF9033_TUNER_IT9135_60;
-                       tmp16 = 0x00461d;
+                       tmp16 = 0x00461d; /* eeprom memory mapped location */
                } else {
                        state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38;
                        state->af9033_config[1].tuner = AF9033_TUNER_IT9135_38;
-                       tmp16 = 0x00461b;
+                       tmp16 = 0x00461b; /* eeprom memory mapped location */
                }
 
                /* check if eeprom exists */
@@ -668,8 +808,16 @@ static int af9035_read_config(struct dvb_usb_device *d)
                        dev_dbg(&d->udev->dev, "%s: no eeprom\n", __func__);
                        goto skip_eeprom;
                }
+       } else if (state->chip_type == 0x9306) {
+               /*
+                * IT930x is an USB bridge, only single demod-single tuner
+                * configurations seen so far.
+                */
+               return 0;
        }
 
+
+
        /* check if there is dual tuners */
        ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp);
        if (ret < 0)
@@ -690,7 +838,7 @@ static int af9035_read_config(struct dvb_usb_device *d)
                        goto err;
 
                if (tmp)
-                       state->af9033_config[1].i2c_addr = tmp;
+                       state->af9033_i2c_addr[1] = tmp;
 
                dev_dbg(&d->udev->dev, "%s: 2nd demod I2C addr=%02x\n",
                                __func__, tmp);
@@ -799,25 +947,6 @@ static int af9035_read_config(struct dvb_usb_device *d)
                addr += 0x10; /* shift for the 2nd tuner params */
        }
 
-       /*
-        * These AVerMedia devices has a bad EEPROM content :-(
-        * Override some wrong values here.
-        */
-       if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA) {
-               switch (le16_to_cpu(d->udev->descriptor.idProduct)) {
-               case USB_PID_AVERMEDIA_A835B_1835:
-               case USB_PID_AVERMEDIA_A835B_2835:
-               case USB_PID_AVERMEDIA_A835B_3835:
-                       dev_info(&d->udev->dev,
-                                "%s: overriding tuner from %02x to %02x\n",
-                                KBUILD_MODNAME, state->af9033_config[0].tuner,
-                                AF9033_TUNER_IT9135_60);
-
-                       state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60;
-                       break;
-               }
-       }
-
 skip_eeprom:
        /* get demod clock */
        ret = af9035_rd_reg(d, 0x00d800, &tmp);
@@ -990,6 +1119,7 @@ static int af9035_frontend_callback(void *adapter_priv, int component,
 static int af9035_get_adapter_count(struct dvb_usb_device *d)
 {
        struct state *state = d_to_priv(d);
+
        return state->dual_mode + 1;
 }
 
@@ -998,7 +1128,8 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
        struct state *state = adap_to_priv(adap);
        struct dvb_usb_device *d = adap_to_d(adap);
        int ret;
-       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
 
        if (!state->af9033_config[adap->id].tuner) {
                /* unsupported tuner */
@@ -1006,9 +1137,13 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
                goto err;
        }
 
-       /* attach demodulator */
-       adap->fe[0] = dvb_attach(af9033_attach, &state->af9033_config[adap->id],
-                       &d->i2c_adap, &state->ops);
+       state->af9033_config[adap->id].fe = &adap->fe[0];
+       state->af9033_config[adap->id].ops = &state->ops;
+       ret = af9035_add_i2c_dev(d, "af9033", state->af9033_i2c_addr[adap->id],
+                       &state->af9033_config[adap->id], &d->i2c_adap);
+       if (ret)
+               goto err;
+
        if (adap->fe[0] == NULL) {
                ret = -ENODEV;
                goto err;
@@ -1026,6 +1161,78 @@ err:
        return ret;
 }
 
+static int it930x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+       int ret;
+       struct si2168_config si2168_config;
+       struct i2c_adapter *adapter;
+
+       dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
+
+       si2168_config.i2c_adapter = &adapter;
+       si2168_config.fe = &adap->fe[0];
+       si2168_config.ts_mode = SI2168_TS_SERIAL;
+
+       state->af9033_config[adap->id].fe = &adap->fe[0];
+       state->af9033_config[adap->id].ops = &state->ops;
+       ret = af9035_add_i2c_dev(d, "si2168", 0x67, &si2168_config,
+                               &d->i2c_adap);
+       if (ret)
+               goto err;
+
+       if (adap->fe[0] == NULL) {
+               ret = -ENODEV;
+               goto err;
+       }
+       state->i2c_adapter_demod = adapter;
+
+       return 0;
+
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+       return ret;
+}
+
+static int af9035_frontend_detach(struct dvb_usb_adapter *adap)
+{
+       struct state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+       int demod2;
+
+       dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
+
+       /*
+        * For dual tuner devices we have to resolve 2nd demod client, as there
+        * is two different kind of tuner drivers; one is using I2C binding
+        * and the other is using DVB attach/detach binding.
+        */
+       switch (state->af9033_config[adap->id].tuner) {
+       case AF9033_TUNER_IT9135_38:
+       case AF9033_TUNER_IT9135_51:
+       case AF9033_TUNER_IT9135_52:
+       case AF9033_TUNER_IT9135_60:
+       case AF9033_TUNER_IT9135_61:
+       case AF9033_TUNER_IT9135_62:
+               demod2 = 2;
+               break;
+       default:
+               demod2 = 1;
+       }
+
+       if (adap->id == 1) {
+               if (state->i2c_client[demod2])
+                       af9035_del_i2c_dev(d);
+       } else if (adap->id == 0) {
+               if (state->i2c_client[0])
+                       af9035_del_i2c_dev(d);
+       }
+
+       return 0;
+}
+
 static struct tua9001_config af9035_tua9001_config = {
        .i2c_addr = 0x60,
 };
@@ -1084,7 +1291,8 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
        struct dvb_frontend *fe;
        struct i2c_msg msg[1];
        u8 tuner_addr;
-       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
 
        /*
         * XXX: Hack used in that function: we abuse unused I2C address bit [7]
@@ -1243,14 +1451,53 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
        case AF9033_TUNER_IT9135_38:
        case AF9033_TUNER_IT9135_51:
        case AF9033_TUNER_IT9135_52:
+       {
+               struct it913x_config it913x_config = {
+                       .fe = adap->fe[0],
+                       .chip_ver = 1,
+               };
+
+               if (state->dual_mode) {
+                       if (adap->id == 0)
+                               it913x_config.role = IT913X_ROLE_DUAL_MASTER;
+                       else
+                               it913x_config.role = IT913X_ROLE_DUAL_SLAVE;
+               }
+
+               ret = af9035_add_i2c_dev(d, "it913x",
+                               state->af9033_i2c_addr[adap->id] >> 1,
+                               &it913x_config, &d->i2c_adap);
+               if (ret)
+                       goto err;
+
+               fe = adap->fe[0];
+               break;
+       }
        case AF9033_TUNER_IT9135_60:
        case AF9033_TUNER_IT9135_61:
        case AF9033_TUNER_IT9135_62:
-               /* attach tuner */
-               fe = dvb_attach(it913x_attach, adap->fe[0], &d->i2c_adap,
-                               state->af9033_config[adap->id].i2c_addr,
-                               state->af9033_config[0].tuner);
+       {
+               struct it913x_config it913x_config = {
+                       .fe = adap->fe[0],
+                       .chip_ver = 2,
+               };
+
+               if (state->dual_mode) {
+                       if (adap->id == 0)
+                               it913x_config.role = IT913X_ROLE_DUAL_MASTER;
+                       else
+                               it913x_config.role = IT913X_ROLE_DUAL_SLAVE;
+               }
+
+               ret = af9035_add_i2c_dev(d, "it913x",
+                               state->af9033_i2c_addr[adap->id] >> 1,
+                               &it913x_config, &d->i2c_adap);
+               if (ret)
+                       goto err;
+
+               fe = adap->fe[0];
                break;
+       }
        default:
                fe = NULL;
        }
@@ -1268,6 +1515,119 @@ err:
        return ret;
 }
 
+static int it930x_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+       int ret;
+       struct si2157_config si2157_config;
+
+       dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
+
+       /* I2C master bus 2 clock speed 300k */
+       ret = af9035_wr_reg(d, 0x00f6a7, 0x07);
+       if (ret < 0)
+               goto err;
+
+       /* I2C master bus 1,3 clock speed 300k */
+       ret = af9035_wr_reg(d, 0x00f103, 0x07);
+       if (ret < 0)
+               goto err;
+
+       /* set gpio11 low */
+       ret = af9035_wr_reg_mask(d, 0xd8d4, 0x01, 0x01);
+       if (ret < 0)
+               goto err;
+
+       ret = af9035_wr_reg_mask(d, 0xd8d5, 0x01, 0x01);
+       if (ret < 0)
+               goto err;
+
+       ret = af9035_wr_reg_mask(d, 0xd8d3, 0x01, 0x01);
+       if (ret < 0)
+               goto err;
+
+       /* Tuner enable using gpiot2_en, gpiot2_on and gpiot2_o (reset) */
+       ret = af9035_wr_reg_mask(d, 0xd8b8, 0x01, 0x01);
+       if (ret < 0)
+               goto err;
+
+       ret = af9035_wr_reg_mask(d, 0xd8b9, 0x01, 0x01);
+       if (ret < 0)
+               goto err;
+
+       ret = af9035_wr_reg_mask(d, 0xd8b7, 0x00, 0x01);
+       if (ret < 0)
+               goto err;
+
+       msleep(200);
+
+       ret = af9035_wr_reg_mask(d, 0xd8b7, 0x01, 0x01);
+       if (ret < 0)
+               goto err;
+
+       memset(&si2157_config, 0, sizeof(si2157_config));
+       si2157_config.fe = adap->fe[0];
+       ret = af9035_add_i2c_dev(d, "si2157", 0x63,
+                       &si2157_config, state->i2c_adapter_demod);
+
+       if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+       return ret;
+}
+
+
+static int it930x_tuner_detach(struct dvb_usb_adapter *adap)
+{
+       struct state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+
+       dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
+
+       if (adap->id == 1) {
+               if (state->i2c_client[3])
+                       af9035_del_i2c_dev(d);
+       } else if (adap->id == 0) {
+               if (state->i2c_client[1])
+                       af9035_del_i2c_dev(d);
+       }
+
+       return 0;
+}
+
+
+static int af9035_tuner_detach(struct dvb_usb_adapter *adap)
+{
+       struct state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+
+       dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
+
+       switch (state->af9033_config[adap->id].tuner) {
+       case AF9033_TUNER_IT9135_38:
+       case AF9033_TUNER_IT9135_51:
+       case AF9033_TUNER_IT9135_52:
+       case AF9033_TUNER_IT9135_60:
+       case AF9033_TUNER_IT9135_61:
+       case AF9033_TUNER_IT9135_62:
+               if (adap->id == 1) {
+                       if (state->i2c_client[3])
+                               af9035_del_i2c_dev(d);
+               } else if (adap->id == 0) {
+                       if (state->i2c_client[1])
+                               af9035_del_i2c_dev(d);
+               }
+       }
+
+       return 0;
+}
+
 static int af9035_init(struct dvb_usb_device *d)
 {
        struct state *state = d_to_priv(d);
@@ -1315,6 +1675,89 @@ err:
        return ret;
 }
 
+static int it930x_init(struct dvb_usb_device *d)
+{
+       struct state *state = d_to_priv(d);
+       int ret, i;
+       u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 816) * 188 / 4;
+       u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4;
+       struct reg_val_mask tab[] = {
+               { 0x00da1a, 0x00, 0x01 }, /* ignore_sync_byte */
+               { 0x00f41f, 0x04, 0x04 }, /* dvbt_inten */
+               { 0x00da10, 0x00, 0x01 }, /* mpeg_full_speed */
+               { 0x00f41a, 0x01, 0x01 }, /* dvbt_en */
+               { 0x00da1d, 0x01, 0x01 }, /* mp2_sw_rst, reset EP4 */
+               { 0x00dd11, 0x00, 0x20 }, /* ep4_tx_en, disable EP4 */
+               { 0x00dd13, 0x00, 0x20 }, /* ep4_tx_nak, disable EP4 NAK */
+               { 0x00dd11, 0x20, 0x20 }, /* ep4_tx_en, enable EP4 */
+               { 0x00dd11, 0x00, 0x40 }, /* ep5_tx_en, disable EP5 */
+               { 0x00dd13, 0x00, 0x40 }, /* ep5_tx_nak, disable EP5 NAK */
+               { 0x00dd11, state->dual_mode << 6, 0x40 }, /* enable EP5 */
+               { 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
+               { 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
+               { 0x00dd0c, packet_size, 0xff},
+               { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
+               { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
+               { 0x00dd0d, packet_size, 0xff },
+               { 0x00da1d, 0x00, 0x01 }, /* mp2_sw_rst, disable */
+               { 0x00d833, 0x01, 0xff }, /* slew rate ctrl: slew rate boosts */
+               { 0x00d830, 0x00, 0xff }, /* Bit 0 of output driving control */
+               { 0x00d831, 0x01, 0xff }, /* Bit 1 of output driving control */
+               { 0x00d832, 0x00, 0xff }, /* Bit 2 of output driving control */
+
+               /* suspend gpio1 for TS-C */
+               { 0x00d8b0, 0x01, 0xff }, /* gpio1 */
+               { 0x00d8b1, 0x01, 0xff }, /* gpio1 */
+               { 0x00d8af, 0x00, 0xff }, /* gpio1 */
+
+               /* suspend gpio7 for TS-D */
+               { 0x00d8c4, 0x01, 0xff }, /* gpio7 */
+               { 0x00d8c5, 0x01, 0xff }, /* gpio7 */
+               { 0x00d8c3, 0x00, 0xff }, /* gpio7 */
+
+               /* suspend gpio13 for TS-B */
+               { 0x00d8dc, 0x01, 0xff }, /* gpio13 */
+               { 0x00d8dd, 0x01, 0xff }, /* gpio13 */
+               { 0x00d8db, 0x00, 0xff }, /* gpio13 */
+
+               /* suspend gpio14 for TS-E */
+               { 0x00d8e4, 0x01, 0xff }, /* gpio14 */
+               { 0x00d8e5, 0x01, 0xff }, /* gpio14 */
+               { 0x00d8e3, 0x00, 0xff }, /* gpio14 */
+
+               /* suspend gpio15 for TS-A */
+               { 0x00d8e8, 0x01, 0xff }, /* gpio15 */
+               { 0x00d8e9, 0x01, 0xff }, /* gpio15 */
+               { 0x00d8e7, 0x00, 0xff }, /* gpio15 */
+
+               { 0x00da58, 0x00, 0x01 }, /* ts_in_src, serial */
+               { 0x00da73, 0x01, 0xff }, /* ts0_aggre_mode */
+               { 0x00da78, 0x47, 0xff }, /* ts0_sync_byte */
+               { 0x00da4c, 0x01, 0xff }, /* ts0_en */
+               { 0x00da5a, 0x1f, 0xff }, /* ts_fail_ignore */
+       };
+
+       dev_dbg(&d->udev->dev,
+                       "%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
+                       __func__, d->udev->speed, frame_size, packet_size);
+
+       /* init endpoints */
+       for (i = 0; i < ARRAY_SIZE(tab); i++) {
+               ret = af9035_wr_reg_mask(d, tab[i].reg,
+                               tab[i].val, tab[i].mask);
+
+               if (ret < 0)
+                       goto err;
+       }
+
+       return 0;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+       return ret;
+}
+
+
 #if IS_ENABLED(CONFIG_RC_CORE)
 static int af9035_rc_query(struct dvb_usb_device *d)
 {
@@ -1409,6 +1852,7 @@ static int af9035_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
                struct usb_data_stream_properties *stream)
 {
        struct dvb_usb_device *d = fe_to_d(fe);
+
        dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, fe_to_adap(fe)->id);
 
        if (d->udev->speed == USB_SPEED_FULL)
@@ -1486,7 +1930,9 @@ static const struct dvb_usb_device_properties af9035_props = {
        .i2c_algo = &af9035_i2c_algo,
        .read_config = af9035_read_config,
        .frontend_attach = af9035_frontend_attach,
+       .frontend_detach = af9035_frontend_detach,
        .tuner_attach = af9035_tuner_attach,
+       .tuner_detach = af9035_tuner_detach,
        .init = af9035_init,
        .get_rc_config = af9035_get_rc_config,
        .get_stream_config = af9035_get_stream_config,
@@ -1515,6 +1961,37 @@ static const struct dvb_usb_device_properties af9035_props = {
        },
 };
 
+static const struct dvb_usb_device_properties it930x_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct state),
+
+       .generic_bulk_ctrl_endpoint = 0x02,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+
+       .identify_state = af9035_identify_state,
+       .download_firmware = af9035_download_firmware,
+
+       .i2c_algo = &af9035_i2c_algo,
+       .read_config = af9035_read_config,
+       .frontend_attach = it930x_frontend_attach,
+       .frontend_detach = af9035_frontend_detach,
+       .tuner_attach = it930x_tuner_attach,
+       .tuner_detach = it930x_tuner_detach,
+       .init = it930x_init,
+       .get_stream_config = af9035_get_stream_config,
+
+       .get_adapter_count = af9035_get_adapter_count,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_BULK(0x84, 4, 816 * 188),
+               }, {
+                       .stream = DVB_USB_STREAM_BULK(0x85, 4, 816 * 188),
+               },
+       },
+};
+
 static const struct usb_device_id af9035_id_table[] = {
        /* AF9035 devices */
        { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035,
@@ -1568,17 +2045,21 @@ static const struct usb_device_id af9035_id_table[] = {
        { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
                &af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2",
                                                        RC_MAP_IT913X_V1) },
+       /* IT930x devices */
+       { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303,
+               &it930x_props, "ITE 9303 Generic", NULL) },
        /* XXX: that same ID [0ccd:0099] is used by af9015 driver too */
        { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099,
-               &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", NULL) },
+               &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)",
+               NULL) },
        { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a05,
                &af9035_props, "Leadtek WinFast DTV Dongle Dual", NULL) },
        { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xf900,
                &af9035_props, "Hauppauge WinTV-MiniStick 2", NULL) },
        { DVB_USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_78E,
-               &af9035_props, "PCTV 78e", RC_MAP_IT913X_V1) },
+               &af9035_props, "PCTV AndroiDTV (78e)", RC_MAP_IT913X_V1) },
        { DVB_USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_79E,
-               &af9035_props, "PCTV 79e", RC_MAP_IT913X_V2) },
+               &af9035_props, "PCTV microStick (79e)", RC_MAP_IT913X_V2) },
        { }
 };
 MODULE_DEVICE_TABLE(usb, af9035_id_table);
@@ -1603,3 +2084,4 @@ MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(AF9035_FIRMWARE_AF9035);
 MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V1);
 MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V2);
+MODULE_FIRMWARE(AF9035_FIRMWARE_IT9303);
index c21902fdd4c44e8d04ecce5962487921f4a92c16..416a97f05ec8539fbc2c11dad23e1261a819650c 100644 (file)
@@ -30,7 +30,9 @@
 #include "mxl5007t.h"
 #include "tda18218.h"
 #include "fc2580.h"
-#include "tuner_it913x.h"
+#include "it913x.h"
+#include "si2168.h"
+#include "si2157.h"
 
 struct reg_val {
        u32 reg;
@@ -61,9 +63,12 @@ struct state {
        u16 chip_type;
        u8 dual_mode:1;
        u16 eeprom_addr;
+       u8 af9033_i2c_addr[2];
        struct af9033_config af9033_config[2];
-
        struct af9033_ops ops;
+       #define AF9035_I2C_CLIENT_MAX 4
+       struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX];
+       struct i2c_adapter *i2c_adapter_demod;
 };
 
 static const u32 clock_lut_af9035[] = {
@@ -97,6 +102,7 @@ static const u32 clock_lut_it9135[] = {
 #define AF9035_FIRMWARE_AF9035 "dvb-usb-af9035-02.fw"
 #define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw"
 #define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw"
+#define AF9035_FIRMWARE_IT9303 "dvb-usb-it9303-01.fw"
 
 /*
  * eeprom is memory mapped as read only. Writing that memory mapped address
@@ -138,5 +144,7 @@ static const u32 clock_lut_it9135[] = {
 #define CMD_FW_DL_BEGIN             0x24
 #define CMD_FW_DL_END               0x25
 #define CMD_FW_SCATTER_WR           0x29
+#define CMD_GENERIC_I2C_RD          0x2a
+#define CMD_GENERIC_I2C_WR          0x2b
 
 #endif
index e4a2382196f0b98dba2cf82cba61879357ad397b..d3c5f230e97a7272f69e7cbba367c3a18c9cbe8b 100644 (file)
@@ -332,7 +332,6 @@ static struct tda10023_config anysee_tda10023_tda18212_config = {
 };
 
 static struct tda18212_config anysee_tda18212_config = {
-       .i2c_address = (0xc0 >> 1),
        .if_dvbt_6 = 4150,
        .if_dvbt_7 = 4150,
        .if_dvbt_8 = 4150,
@@ -340,7 +339,6 @@ static struct tda18212_config anysee_tda18212_config = {
 };
 
 static struct tda18212_config anysee_tda18212_config2 = {
-       .i2c_address = 0x60 /* (0xc0 >> 1) */,
        .if_dvbt_6 = 3550,
        .if_dvbt_7 = 3700,
        .if_dvbt_8 = 4150,
@@ -632,6 +630,92 @@ error:
        return ret;
 }
 
+static int anysee_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr,
+               void *platform_data)
+{
+       int ret, num;
+       struct anysee_state *state = d_to_priv(d);
+       struct i2c_client *client;
+       struct i2c_adapter *adapter = &d->i2c_adap;
+       struct i2c_board_info board_info = {
+               .addr = addr,
+               .platform_data = platform_data,
+       };
+
+       strlcpy(board_info.type, type, I2C_NAME_SIZE);
+
+       /* find first free client */
+       for (num = 0; num < ANYSEE_I2C_CLIENT_MAX; num++) {
+               if (state->i2c_client[num] == NULL)
+                       break;
+       }
+
+       dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
+
+       if (num == ANYSEE_I2C_CLIENT_MAX) {
+               dev_err(&d->udev->dev, "%s: I2C client out of index\n",
+                               KBUILD_MODNAME);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       request_module(board_info.type);
+
+       /* register I2C device */
+       client = i2c_new_device(adapter, &board_info);
+       if (client == NULL || client->dev.driver == NULL) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       /* increase I2C driver usage count */
+       if (!try_module_get(client->dev.driver->owner)) {
+               i2c_unregister_device(client);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       state->i2c_client[num] = client;
+       return 0;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static void anysee_del_i2c_dev(struct dvb_usb_device *d)
+{
+       int num;
+       struct anysee_state *state = d_to_priv(d);
+       struct i2c_client *client;
+
+       /* find last used client */
+       num = ANYSEE_I2C_CLIENT_MAX;
+       while (num--) {
+               if (state->i2c_client[num] != NULL)
+                       break;
+       }
+
+       dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
+
+       if (num == -1) {
+               dev_err(&d->udev->dev, "%s: I2C client out of index\n",
+                               KBUILD_MODNAME);
+               goto err;
+       }
+
+       client = state->i2c_client[num];
+
+       /* decrease I2C driver usage count */
+       module_put(client->dev.driver->owner);
+
+       /* unregister I2C device */
+       i2c_unregister_device(client);
+
+       state->i2c_client[num] = NULL;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed\n", __func__);
+}
+
 static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
 {
        struct anysee_state *state = adap_to_priv(adap);
@@ -640,12 +724,12 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
        u8 tmp;
        struct i2c_msg msg[2] = {
                {
-                       .addr = anysee_tda18212_config.i2c_address,
+                       .addr = 0x60,
                        .flags = 0,
                        .len = 1,
                        .buf = "\x00",
                }, {
-                       .addr = anysee_tda18212_config.i2c_address,
+                       .addr = 0x60,
                        .flags = I2C_M_RD,
                        .len = 1,
                        .buf = &tmp,
@@ -723,9 +807,11 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                /* probe TDA18212 */
                tmp = 0;
                ret = i2c_transfer(&d->i2c_adap, msg, 2);
-               if (ret == 2 && tmp == 0xc7)
+               if (ret == 2 && tmp == 0xc7) {
                        dev_dbg(&d->udev->dev, "%s: TDA18212 found\n",
                                        __func__);
+                       state->has_tda18212 = true;
+               }
                else
                        tmp = 0;
 
@@ -939,46 +1025,63 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                 * fails attach old simple PLL. */
 
                /* attach tuner */
-               fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
-                               &anysee_tda18212_config);
+               if (state->has_tda18212) {
+                       struct tda18212_config tda18212_config =
+                                       anysee_tda18212_config;
 
-               if (fe && adap->fe[1]) {
-                       /* attach tuner for 2nd FE */
-                       fe = dvb_attach(tda18212_attach, adap->fe[1],
-                                       &d->i2c_adap, &anysee_tda18212_config);
-                       break;
-               } else if (fe) {
-                       break;
-               }
-
-               /* attach tuner */
-               fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1),
-                               &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+                       tda18212_config.fe = adap->fe[0];
+                       ret = anysee_add_i2c_dev(d, "tda18212", 0x60,
+                                       &tda18212_config);
+                       if (ret)
+                               goto err;
+
+                       /* copy tuner ops for 2nd FE as tuner is shared */
+                       if (adap->fe[1]) {
+                               adap->fe[1]->tuner_priv =
+                                               adap->fe[0]->tuner_priv;
+                               memcpy(&adap->fe[1]->ops.tuner_ops,
+                                               &adap->fe[0]->ops.tuner_ops,
+                                               sizeof(struct dvb_tuner_ops));
+                       }
 
-               if (fe && adap->fe[1]) {
-                       /* attach tuner for 2nd FE */
-                       fe = dvb_attach(dvb_pll_attach, adap->fe[1],
+                       return 0;
+               } else {
+                       /* attach tuner */
+                       fe = dvb_attach(dvb_pll_attach, adap->fe[0],
                                        (0xc0 >> 1), &d->i2c_adap,
                                        DVB_PLL_SAMSUNG_DTOS403IH102A);
+
+                       if (fe && adap->fe[1]) {
+                               /* attach tuner for 2nd FE */
+                               fe = dvb_attach(dvb_pll_attach, adap->fe[1],
+                                               (0xc0 >> 1), &d->i2c_adap,
+                                               DVB_PLL_SAMSUNG_DTOS403IH102A);
+                       }
                }
 
                break;
        case ANYSEE_HW_508TC: /* 18 */
        case ANYSEE_HW_508PTC: /* 21 */
+       {
                /* E7 TC */
                /* E7 PTC */
+               struct tda18212_config tda18212_config = anysee_tda18212_config;
 
-               /* attach tuner */
-               fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
-                               &anysee_tda18212_config);
-
-               if (fe) {
-                       /* attach tuner for 2nd FE */
-                       fe = dvb_attach(tda18212_attach, adap->fe[1],
-                                       &d->i2c_adap, &anysee_tda18212_config);
+               tda18212_config.fe = adap->fe[0];
+               ret = anysee_add_i2c_dev(d, "tda18212", 0x60, &tda18212_config);
+               if (ret)
+                       goto err;
+
+               /* copy tuner ops for 2nd FE as tuner is shared */
+               if (adap->fe[1]) {
+                       adap->fe[1]->tuner_priv = adap->fe[0]->tuner_priv;
+                       memcpy(&adap->fe[1]->ops.tuner_ops,
+                                       &adap->fe[0]->ops.tuner_ops,
+                                       sizeof(struct dvb_tuner_ops));
                }
 
-               break;
+               return 0;
+       }
        case ANYSEE_HW_508S2: /* 19 */
        case ANYSEE_HW_508PS2: /* 22 */
                /* E7 S2 */
@@ -997,13 +1100,18 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                break;
 
        case ANYSEE_HW_508T2C: /* 20 */
+       {
                /* E7 T2C */
+               struct tda18212_config tda18212_config =
+                               anysee_tda18212_config2;
 
-               /* attach tuner */
-               fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
-                               &anysee_tda18212_config2);
+               tda18212_config.fe = adap->fe[0];
+               ret = anysee_add_i2c_dev(d, "tda18212", 0x60, &tda18212_config);
+               if (ret)
+                       goto err;
 
-               break;
+               return 0;
+       }
        default:
                fe = NULL;
        }
@@ -1012,7 +1120,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                ret = 0;
        else
                ret = -ENODEV;
-
+err:
        return ret;
 }
 
@@ -1270,6 +1378,11 @@ static int anysee_init(struct dvb_usb_device *d)
 
 static void anysee_exit(struct dvb_usb_device *d)
 {
+       struct anysee_state *state = d_to_priv(d);
+
+       if (state->i2c_client[0])
+               anysee_del_i2c_dev(d);
+
        return anysee_ci_release(d);
 }
 
index 8f426d9fc6e1110b14c521deb770e35bbc837843..3ca2bca4ebafacc581bfd3cc3aa17c3d087c209b 100644 (file)
@@ -55,8 +55,11 @@ struct anysee_state {
        u8 buf[64];
        u8 seq;
        u8 hw; /* PCB ID */
+       #define ANYSEE_I2C_CLIENT_MAX 1
+       struct i2c_client *i2c_client[ANYSEE_I2C_CLIENT_MAX];
        u8 fe_id:1; /* frondend ID */
        u8 has_ci:1;
+       u8 has_tda18212:1;
        u8 ci_attached:1;
        struct dvb_ca_en50221 ci;
        unsigned long ci_cam_ready; /* jiffies */
index 124b4baa7e975d9ec63ac8c243d3e2741fd8d4c7..14e111e13e54c31eae02814b9602e1cf06564e4d 100644 (file)
@@ -214,6 +214,7 @@ struct dvb_usb_adapter_properties {
  * @read_config: called to resolve device configuration
  * @read_mac_address: called to resolve adapter mac-address
  * @frontend_attach: called to attach the possible frontends
+ * @frontend_detach: called to detach the possible frontends
  * @tuner_attach: called to attach the possible tuners
  * @frontend_ctrl: called to power on/off active frontend
  * @streaming_ctrl: called to start/stop the usb streaming of adapter
@@ -254,7 +255,9 @@ struct dvb_usb_device_properties {
        int (*read_config) (struct dvb_usb_device *d);
        int (*read_mac_address) (struct dvb_usb_adapter *, u8 []);
        int (*frontend_attach) (struct dvb_usb_adapter *);
+       int (*frontend_detach)(struct dvb_usb_adapter *);
        int (*tuner_attach) (struct dvb_usb_adapter *);
+       int (*tuner_detach)(struct dvb_usb_adapter *);
        int (*frontend_ctrl) (struct dvb_frontend *, int);
        int (*streaming_ctrl) (struct dvb_frontend *, int);
        int (*init) (struct dvb_usb_device *);
index 2e90310be2afd7d9ae954b63c55301ae5d25bac0..1950f37df835187c0ac0e153231b316adcaea106 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "dvb_usb_common.h"
 
-int dvb_usbv2_disable_rc_polling;
+static int dvb_usbv2_disable_rc_polling;
 module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644);
 MODULE_PARM_DESC(disable_rc_polling,
                "disable remote control polling (default: 0)");
@@ -664,9 +664,10 @@ err:
 
 static int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap)
 {
-       int i;
-       dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
-                       adap->id);
+       int ret, i;
+       struct dvb_usb_device *d = adap_to_d(adap);
+
+       dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
 
        for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
                if (adap->fe[i]) {
@@ -675,6 +676,23 @@ static int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap)
                }
        }
 
+       if (d->props->tuner_detach) {
+               ret = d->props->tuner_detach(adap);
+               if (ret < 0) {
+                       dev_dbg(&d->udev->dev, "%s: tuner_detach() failed=%d\n",
+                                       __func__, ret);
+               }
+       }
+
+       if (d->props->frontend_detach) {
+               ret = d->props->frontend_detach(adap);
+               if (ret < 0) {
+                       dev_dbg(&d->udev->dev,
+                                       "%s: frontend_detach() failed=%d\n",
+                                       __func__, ret);
+               }
+       }
+
        return 0;
 }
 
@@ -762,9 +780,9 @@ static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d)
 
        for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) {
                if (d->adapter[i].props) {
-                       dvb_usbv2_adapter_frontend_exit(&d->adapter[i]);
                        dvb_usbv2_adapter_dvb_exit(&d->adapter[i]);
                        dvb_usbv2_adapter_stream_exit(&d->adapter[i]);
+                       dvb_usbv2_adapter_frontend_exit(&d->adapter[i]);
                }
        }
 
index 33ff97e708e3a8c2defa22491ab56cd1619fac8a..22bdce15ecf31fcd351309ca7fa5794cb228869d 100644 (file)
@@ -26,7 +26,7 @@ static int dvb_usb_v2_generic_io(struct dvb_usb_device *d,
 {
        int ret, actual_length;
 
-       if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint ||
+       if (!wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint ||
                        !d->props->generic_bulk_ctrl_endpoint_response) {
                dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL);
                return -EINVAL;
diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c
new file mode 100644 (file)
index 0000000..34688c8
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Driver for DVBSky USB2.0 receiver
+ *
+ * Copyright (C) 2013 Max nibble <nibble.max@gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dvb_usb.h"
+#include "m88ds3103.h"
+#include "m88ts2022.h"
+
+#define DVBSKY_MSG_DELAY       0/*2000*/
+#define DVBSKY_BUF_LEN 64
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct dvbsky_state {
+       struct mutex stream_mutex;
+       u8 ibuf[DVBSKY_BUF_LEN];
+       u8 obuf[DVBSKY_BUF_LEN];
+       u8 last_lock;
+       struct i2c_client *i2c_client_tuner;
+
+       /* fe hook functions*/
+       int (*fe_set_voltage)(struct dvb_frontend *fe,
+               fe_sec_voltage_t voltage);
+       int (*fe_read_status)(struct dvb_frontend *fe,
+               fe_status_t *status);
+};
+
+static int dvbsky_usb_generic_rw(struct dvb_usb_device *d,
+               u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+       int ret;
+       struct dvbsky_state *state = d_to_priv(d);
+
+       mutex_lock(&d->usb_mutex);
+       if (wlen != 0)
+               memcpy(state->obuf, wbuf, wlen);
+
+       ret = dvb_usbv2_generic_rw_locked(d, state->obuf, wlen,
+                       state->ibuf, rlen);
+
+       if (!ret && (rlen != 0))
+               memcpy(rbuf, state->ibuf, rlen);
+
+       mutex_unlock(&d->usb_mutex);
+       return ret;
+}
+
+static int dvbsky_stream_ctrl(struct dvb_usb_device *d, u8 onoff)
+{
+       struct dvbsky_state *state = d_to_priv(d);
+       int ret;
+       u8 obuf_pre[3] = { 0x37, 0, 0 };
+       u8 obuf_post[3] = { 0x36, 3, 0 };
+
+       mutex_lock(&state->stream_mutex);
+       ret = dvbsky_usb_generic_rw(d, obuf_pre, 3, NULL, 0);
+       if (!ret && onoff) {
+               msleep(20);
+               ret = dvbsky_usb_generic_rw(d, obuf_post, 3, NULL, 0);
+       }
+       mutex_unlock(&state->stream_mutex);
+       return ret;
+}
+
+static int dvbsky_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+       struct dvb_usb_device *d = fe_to_d(fe);
+
+       return dvbsky_stream_ctrl(d, (onoff == 0) ? 0 : 1);
+}
+
+/* GPIO */
+static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value)
+{
+       int ret;
+       u8 obuf[3], ibuf[2];
+
+       obuf[0] = 0x0e;
+       obuf[1] = gport;
+       obuf[2] = value;
+       ret = dvbsky_usb_generic_rw(d, obuf, 3, ibuf, 1);
+       if (ret)
+               dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+                       KBUILD_MODNAME, __func__, ret);
+       return ret;
+}
+
+/* I2C */
+static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+       int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret = 0;
+       u8 ibuf[64], obuf[64];
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       if (num > 2) {
+               dev_err(&d->udev->dev,
+               "dvbsky_usb: too many i2c messages[%d] than 2.", num);
+               ret = -EOPNOTSUPP;
+               goto i2c_error;
+       }
+
+       if (num == 1) {
+               if (msg[0].len > 60) {
+                       dev_err(&d->udev->dev,
+                       "dvbsky_usb: too many i2c bytes[%d] than 60.",
+                       msg[0].len);
+                       ret = -EOPNOTSUPP;
+                       goto i2c_error;
+               }
+               if (msg[0].flags & I2C_M_RD) {
+                       /* single read */
+                       obuf[0] = 0x09;
+                       obuf[1] = 0;
+                       obuf[2] = msg[0].len;
+                       obuf[3] = msg[0].addr;
+                       ret = dvbsky_usb_generic_rw(d, obuf, 4,
+                                       ibuf, msg[0].len + 1);
+                       if (ret)
+                               dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+                                       KBUILD_MODNAME, __func__, ret);
+                       if (!ret)
+                               memcpy(msg[0].buf, &ibuf[1], msg[0].len);
+               } else {
+                       /* write */
+                       obuf[0] = 0x08;
+                       obuf[1] = msg[0].addr;
+                       obuf[2] = msg[0].len;
+                       memcpy(&obuf[3], msg[0].buf, msg[0].len);
+                       ret = dvbsky_usb_generic_rw(d, obuf,
+                                       msg[0].len + 3, ibuf, 1);
+                       if (ret)
+                               dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+                                       KBUILD_MODNAME, __func__, ret);
+               }
+       } else {
+               if ((msg[0].len > 60) || (msg[1].len > 60)) {
+                       dev_err(&d->udev->dev,
+                       "dvbsky_usb: too many i2c bytes[w-%d][r-%d] than 60.",
+                       msg[0].len, msg[1].len);
+                       ret = -EOPNOTSUPP;
+                       goto i2c_error;
+               }
+               /* write then read */
+               obuf[0] = 0x09;
+               obuf[1] = msg[0].len;
+               obuf[2] = msg[1].len;
+               obuf[3] = msg[0].addr;
+               memcpy(&obuf[4], msg[0].buf, msg[0].len);
+               ret = dvbsky_usb_generic_rw(d, obuf,
+                       msg[0].len + 4, ibuf, msg[1].len + 1);
+               if (ret)
+                       dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+                               KBUILD_MODNAME, __func__, ret);
+
+               if (!ret)
+                       memcpy(msg[1].buf, &ibuf[1], msg[1].len);
+       }
+i2c_error:
+       mutex_unlock(&d->i2c_mutex);
+       return (ret) ? ret : num;
+}
+
+static u32 dvbsky_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dvbsky_i2c_algo = {
+       .master_xfer   = dvbsky_i2c_xfer,
+       .functionality = dvbsky_i2c_func,
+};
+
+#if IS_ENABLED(CONFIG_RC_CORE)
+static int dvbsky_rc_query(struct dvb_usb_device *d)
+{
+       u32 code = 0xffff, scancode;
+       u8 rc5_command, rc5_system;
+       u8 obuf[2], ibuf[2], toggle;
+       int ret;
+
+       obuf[0] = 0x10;
+       ret = dvbsky_usb_generic_rw(d, obuf, 1, ibuf, 2);
+       if (ret)
+               dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+                       KBUILD_MODNAME, __func__, ret);
+       if (ret == 0)
+               code = (ibuf[0] << 8) | ibuf[1];
+       if (code != 0xffff) {
+               dev_dbg(&d->udev->dev, "rc code: %x\n", code);
+               rc5_command = code & 0x3F;
+               rc5_system = (code & 0x7C0) >> 6;
+               toggle = (code & 0x800) ? 1 : 0;
+               scancode = rc5_system << 8 | rc5_command;
+               rc_keydown(d->rc_dev, RC_TYPE_RC5, scancode, toggle);
+       }
+       return 0;
+}
+
+static int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+       rc->allowed_protos = RC_BIT_RC5;
+       rc->query          = dvbsky_rc_query;
+       rc->interval       = 300;
+       return 0;
+}
+#else
+       #define dvbsky_get_rc_config NULL
+#endif
+
+static int dvbsky_usb_set_voltage(struct dvb_frontend *fe,
+       fe_sec_voltage_t voltage)
+{
+       struct dvb_usb_device *d = fe_to_d(fe);
+       struct dvbsky_state *state = d_to_priv(d);
+       u8 value;
+
+       if (voltage == SEC_VOLTAGE_OFF)
+               value = 0;
+       else
+               value = 1;
+       dvbsky_gpio_ctrl(d, 0x80, value);
+
+       return state->fe_set_voltage(fe, voltage);
+}
+
+static int dvbsky_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
+{
+       struct dvb_usb_device *d = adap_to_d(adap);
+       u8 obuf[] = { 0x1e, 0x00 };
+       u8 ibuf[6] = { 0 };
+       struct i2c_msg msg[] = {
+               {
+                       .addr = 0x51,
+                       .flags = 0,
+                       .buf = obuf,
+                       .len = 2,
+               }, {
+                       .addr = 0x51,
+                       .flags = I2C_M_RD,
+                       .buf = ibuf,
+                       .len = 6,
+               }
+       };
+
+       if (i2c_transfer(&d->i2c_adap, msg, 2) == 2)
+               memcpy(mac, ibuf, 6);
+
+       dev_info(&d->udev->dev, "dvbsky_usb MAC address=%pM\n", mac);
+
+       return 0;
+}
+
+static int dvbsky_usb_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct dvb_usb_device *d = fe_to_d(fe);
+       struct dvbsky_state *state = d_to_priv(d);
+       int ret;
+
+       ret = state->fe_read_status(fe, status);
+
+       /* it need resync slave fifo when signal change from unlock to lock.*/
+       if ((*status & FE_HAS_LOCK) && (!state->last_lock))
+               dvbsky_stream_ctrl(d, 1);
+
+       state->last_lock = (*status & FE_HAS_LOCK) ? 1 : 0;
+       return ret;
+}
+
+static const struct m88ds3103_config dvbsky_s960_m88ds3103_config = {
+       .i2c_addr = 0x68,
+       .clock = 27000000,
+       .i2c_wr_max = 33,
+       .clock_out = 0,
+       .ts_mode = M88DS3103_TS_CI,
+       .ts_clk = 16000,
+       .ts_clk_pol = 0,
+       .agc = 0x99,
+       .lnb_hv_pol = 1,
+       .lnb_en_pol = 1,
+};
+
+static int dvbsky_s960_attach(struct dvb_usb_adapter *adap)
+{
+       struct dvbsky_state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+       int ret = 0;
+       /* demod I2C adapter */
+       struct i2c_adapter *i2c_adapter;
+       struct i2c_client *client;
+       struct i2c_board_info info;
+       struct m88ts2022_config m88ts2022_config = {
+                       .clock = 27000000,
+               };
+       memset(&info, 0, sizeof(struct i2c_board_info));
+
+       /* attach demod */
+       adap->fe[0] = dvb_attach(m88ds3103_attach,
+                       &dvbsky_s960_m88ds3103_config,
+                       &d->i2c_adap,
+                       &i2c_adapter);
+       if (!adap->fe[0]) {
+               dev_err(&d->udev->dev, "dvbsky_s960_attach fail.\n");
+               ret = -ENODEV;
+               goto fail_attach;
+       }
+
+       /* attach tuner */
+       m88ts2022_config.fe = adap->fe[0];
+       strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+       info.addr = 0x60;
+       info.platform_data = &m88ts2022_config;
+       request_module("m88ts2022");
+       client = i2c_new_device(i2c_adapter, &info);
+       if (client == NULL || client->dev.driver == NULL) {
+               dvb_frontend_detach(adap->fe[0]);
+               ret = -ENODEV;
+               goto fail_attach;
+       }
+
+       if (!try_module_get(client->dev.driver->owner)) {
+               i2c_unregister_device(client);
+               dvb_frontend_detach(adap->fe[0]);
+               ret = -ENODEV;
+               goto fail_attach;
+       }
+
+       /* delegate signal strength measurement to tuner */
+       adap->fe[0]->ops.read_signal_strength =
+                       adap->fe[0]->ops.tuner_ops.get_rf_strength;
+
+       /* hook fe: need to resync the slave fifo when signal locks. */
+       state->fe_read_status = adap->fe[0]->ops.read_status;
+       adap->fe[0]->ops.read_status = dvbsky_usb_read_status;
+
+       /* hook fe: LNB off/on is control by Cypress usb chip. */
+       state->fe_set_voltage = adap->fe[0]->ops.set_voltage;
+       adap->fe[0]->ops.set_voltage = dvbsky_usb_set_voltage;
+
+       state->i2c_client_tuner = client;
+
+fail_attach:
+       return ret;
+}
+
+static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name)
+{
+       dvbsky_gpio_ctrl(d, 0x04, 1);
+       msleep(20);
+       dvbsky_gpio_ctrl(d, 0x83, 0);
+       dvbsky_gpio_ctrl(d, 0xc0, 1);
+       msleep(100);
+       dvbsky_gpio_ctrl(d, 0x83, 1);
+       dvbsky_gpio_ctrl(d, 0xc0, 0);
+       msleep(50);
+
+       return WARM;
+}
+
+static int dvbsky_init(struct dvb_usb_device *d)
+{
+       struct dvbsky_state *state = d_to_priv(d);
+
+       /* use default interface */
+       /*
+       ret = usb_set_interface(d->udev, 0, 0);
+       if (ret)
+               return ret;
+       */
+       mutex_init(&state->stream_mutex);
+
+       state->last_lock = 0;
+
+       return 0;
+}
+
+static void dvbsky_exit(struct dvb_usb_device *d)
+{
+       struct dvbsky_state *state = d_to_priv(d);
+       struct i2c_client *client;
+
+       client = state->i2c_client_tuner;
+       /* remove I2C tuner */
+       if (client) {
+               module_put(client->dev.driver->owner);
+               i2c_unregister_device(client);
+       }
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties dvbsky_s960_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct dvbsky_state),
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+       .generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
+
+       .i2c_algo         = &dvbsky_i2c_algo,
+       .frontend_attach  = dvbsky_s960_attach,
+       .init             = dvbsky_init,
+       .get_rc_config    = dvbsky_get_rc_config,
+       .streaming_ctrl   = dvbsky_streaming_ctrl,
+       .identify_state   = dvbsky_identify_state,
+       .exit             = dvbsky_exit,
+       .read_mac_address = dvbsky_read_mac_addr,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
+               }
+       }
+};
+
+static const struct usb_device_id dvbsky_id_table[] = {
+       { DVB_USB_DEVICE(0x0572, 0x6831,
+               &dvbsky_s960_props, "DVBSky S960/S860", RC_MAP_DVBSKY) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, dvbsky_id_table);
+
+static struct usb_driver dvbsky_usb_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = dvbsky_id_table,
+       .probe = dvb_usbv2_probe,
+       .disconnect = dvb_usbv2_disconnect,
+       .suspend = dvb_usbv2_suspend,
+       .resume = dvb_usbv2_resume,
+       .reset_resume = dvb_usbv2_reset_resume,
+       .no_dynamic_id = 1,
+       .soft_unbind = 1,
+};
+
+module_usb_driver(dvbsky_usb_driver);
+
+MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
+MODULE_DESCRIPTION("Driver for DVBSky USB");
+MODULE_LICENSE("GPL");
index e332af7311872c162333a386021cd89be3e2b1ca..9f2c5459b73a672485e118e4e17df4f671c6b776 100644 (file)
@@ -1252,7 +1252,7 @@ static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
 
        /* Turn PID filter on the fly by module option */
        if (pid_filter == 2) {
-               adap->pid_filtering  = 1;
+               adap->pid_filtering  = true;
                adap->max_feed_count = 15;
        }
 
index b8a707e57b994c6d7863941402d91350b990ea0e..c3447eaf11047339eafc14edc8ce2d573b7d96be 100644 (file)
@@ -31,11 +31,11 @@ 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;
+static 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).");
 
-int dvb_usb_mxl111sf_spi;
+static int dvb_usb_mxl111sf_spi;
 module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644);
 MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
 
@@ -43,7 +43,7 @@ MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
 #define ANT_PATH_EXTERNAL 1
 #define ANT_PATH_INTERNAL 2
 
-int dvb_usb_mxl111sf_rfswitch =
+static int dvb_usb_mxl111sf_rfswitch =
 #if 0
                ANT_PATH_AUTO;
 #else
@@ -887,7 +887,7 @@ static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter)
        return I2C_FUNC_I2C;
 }
 
-struct i2c_algorithm mxl111sf_i2c_algo = {
+static struct i2c_algorithm mxl111sf_i2c_algo = {
        .master_xfer   = mxl111sf_i2c_xfer,
        .functionality = mxl111sf_i2c_func,
 #ifdef NEED_ALGO_CONTROL
index 10aef2188fbe764deb206320d1db71beb386f2aa..41d3eb922a006d5f4649adb34b64707eaac02759 100644 (file)
@@ -130,7 +130,7 @@ config DVB_USB_CXUSB
 
          Medion MD95700 hybrid USB2.0 device.
          DViCO FusionHDTV (Bluebird) USB2.0 devices
-         TechnoTrend TVStick CT2-4400
+         TechnoTrend TVStick CT2-4400 and CT2-4650 CI devices
 
 config DVB_USB_M920X
        tristate "Uli m920x DVB-T USB2.0 support"
index af176b6ce738e78d4dc366ae0d56597f833f4e59..3f4361e48a32ef98dd3faf6970a32127df549d4e 100644 (file)
@@ -30,7 +30,7 @@ MODULE_PARM_DESC(debug,
                 "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
                 DVB_USB_DEBUG_STATUS);
 /* enable obnoxious led */
-bool dvb_usb_af9005_led = 1;
+bool dvb_usb_af9005_led = true;
 module_param_named(led, dvb_usb_af9005_led, bool, 0644);
 MODULE_PARM_DESC(led, "enable led (default: 1).");
 
index 16bc579d1404e836e7bb287a1744c1e52fec48d7..356abb369c20b6cd07649fd1f75252f939d0a6e0 100644 (file)
@@ -44,6 +44,7 @@
 #include "atbm8830.h"
 #include "si2168.h"
 #include "si2157.h"
+#include "sp2.h"
 
 /* Max transfer size done by I2C transfer functions */
 #define MAX_XFER_SIZE  80
@@ -175,7 +176,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 
        for (i = 0; i < num; i++) {
 
-               if (d->udev->descriptor.idVendor == USB_VID_MEDION)
+               if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_MEDION)
                        switch (msg[i].addr) {
                        case 0x63:
                                cxusb_gpio_tuner(d, 0);
@@ -672,6 +673,70 @@ static struct rc_map_table rc_map_d680_dmb_table[] = {
        { 0x0025, KEY_POWER },
 };
 
+static int cxusb_tt_ct2_4400_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+       u8 wbuf[2];
+       u8 rbuf[6];
+       int ret;
+       struct i2c_msg msg[] = {
+               {
+                       .addr = 0x51,
+                       .flags = 0,
+                       .buf = wbuf,
+                       .len = 2,
+               }, {
+                       .addr = 0x51,
+                       .flags = I2C_M_RD,
+                       .buf = rbuf,
+                       .len = 6,
+               }
+       };
+
+       wbuf[0] = 0x1e;
+       wbuf[1] = 0x00;
+       ret = cxusb_i2c_xfer(&d->i2c_adap, msg, 2);
+
+       if (ret == 2) {
+               memcpy(mac, rbuf, 6);
+               return 0;
+       } else {
+               if (ret < 0)
+                       return ret;
+               return -EIO;
+       }
+}
+
+static int cxusb_tt_ct2_4650_ci_ctrl(void *priv, u8 read, int addr,
+                                       u8 data, int *mem)
+{
+       struct dvb_usb_device *d = priv;
+       u8 wbuf[3];
+       u8 rbuf[2];
+       int ret;
+
+       wbuf[0] = (addr >> 8) & 0xff;
+       wbuf[1] = addr & 0xff;
+
+       if (read) {
+               ret = cxusb_ctrl_msg(d, CMD_SP2_CI_READ, wbuf, 2, rbuf, 2);
+       } else {
+               wbuf[2] = data;
+               ret = cxusb_ctrl_msg(d, CMD_SP2_CI_WRITE, wbuf, 3, rbuf, 1);
+       }
+
+       if (ret)
+               goto err;
+
+       if (read)
+               *mem = rbuf[1];
+
+       return 0;
+err:
+       deb_info("%s: ci usb write returned %d\n", __func__, ret);
+       return ret;
+
+}
+
 static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
 {
        static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x28 };
@@ -1350,9 +1415,12 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap)
        struct i2c_adapter *adapter;
        struct i2c_client *client_demod;
        struct i2c_client *client_tuner;
+       struct i2c_client *client_ci;
        struct i2c_board_info info;
        struct si2168_config si2168_config;
        struct si2157_config si2157_config;
+       struct sp2_config sp2_config;
+       u8 o[2], i;
 
        /* reset the tuner */
        if (cxusb_tt_ct2_4400_gpio_tuner(d, 0) < 0) {
@@ -1369,6 +1437,7 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap)
        /* attach frontend */
        si2168_config.i2c_adapter = &adapter;
        si2168_config.fe = &adap->fe_adap[0].fe;
+       si2168_config.ts_mode = SI2168_TS_PARALLEL;
        memset(&info, 0, sizeof(struct i2c_board_info));
        strlcpy(info.type, "si2168", I2C_NAME_SIZE);
        info.addr = 0x64;
@@ -1408,6 +1477,48 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap)
 
        st->i2c_client_tuner = client_tuner;
 
+       /* initialize CI */
+       if (d->udev->descriptor.idProduct ==
+               USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI) {
+
+               memcpy(o, "\xc0\x01", 2);
+               cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+               msleep(100);
+
+               memcpy(o, "\xc0\x00", 2);
+               cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+               msleep(100);
+
+               memset(&sp2_config, 0, sizeof(sp2_config));
+               sp2_config.dvb_adap = &adap->dvb_adap;
+               sp2_config.priv = d;
+               sp2_config.ci_control = cxusb_tt_ct2_4650_ci_ctrl;
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "sp2", I2C_NAME_SIZE);
+               info.addr = 0x40;
+               info.platform_data = &sp2_config;
+               request_module(info.type);
+               client_ci = i2c_new_device(&d->i2c_adap, &info);
+               if (client_ci == NULL || client_ci->dev.driver == NULL) {
+                       module_put(client_tuner->dev.driver->owner);
+                       i2c_unregister_device(client_tuner);
+                       module_put(client_demod->dev.driver->owner);
+                       i2c_unregister_device(client_demod);
+                       return -ENODEV;
+               }
+               if (!try_module_get(client_ci->dev.driver->owner)) {
+                       i2c_unregister_device(client_ci);
+                       module_put(client_tuner->dev.driver->owner);
+                       i2c_unregister_device(client_tuner);
+                       module_put(client_demod->dev.driver->owner);
+                       i2c_unregister_device(client_demod);
+                       return -ENODEV;
+               }
+
+               st->i2c_client_ci = client_ci;
+
+       }
+
        return 0;
 }
 
@@ -1537,6 +1648,13 @@ static void cxusb_disconnect(struct usb_interface *intf)
        struct cxusb_state *st = d->priv;
        struct i2c_client *client;
 
+       /* remove I2C client for CI */
+       client = st->i2c_client_ci;
+       if (client) {
+               module_put(client->dev.driver->owner);
+               i2c_unregister_device(client);
+       }
+
        /* remove I2C client for tuner */
        client = st->i2c_client_tuner;
        if (client) {
@@ -1576,6 +1694,7 @@ static struct usb_device_id cxusb_table [] = {
        { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
        { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) },
        { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_TVSTICK_CT2_4400) },
+       { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI) },
        {}              /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -2230,6 +2349,8 @@ static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = {
        .size_of_priv     = sizeof(struct cxusb_state),
 
        .num_adapters = 1,
+       .read_mac_address = cxusb_tt_ct2_4400_read_mac_address,
+
        .adapter = {
                {
                .num_frontends = 1,
@@ -2265,13 +2386,18 @@ static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = {
                .rc_interval    = 150,
        },
 
-       .num_device_descs = 1,
+       .num_device_descs = 2,
        .devices = {
                {
                        "TechnoTrend TVStick CT2-4400",
                        { NULL },
                        { &cxusb_table[20], NULL },
                },
+               {
+                       "TechnoTrend TT-connect CT2-4650 CI",
+                       { NULL },
+                       { &cxusb_table[21], NULL },
+               },
        }
 };
 
index 527ff7905e1590961b64b8edd3b62b859a9f903a..29f3e2ea2476a21394dcc60e7ba2cc70b9d2cdad 100644 (file)
 #define CMD_ANALOG        0x50
 #define CMD_DIGITAL       0x51
 
+#define CMD_SP2_CI_WRITE  0x70
+#define CMD_SP2_CI_READ   0x71
+
 struct cxusb_state {
        u8 gpio_write_state[3];
        struct i2c_client *i2c_client_demod;
        struct i2c_client *i2c_client_tuner;
+       struct i2c_client *i2c_client_ci;
 };
 
 #endif
index ce47d3f1c8502a1774a3eee1b518d0cd5821247d..e1757b8f5f5d0e7775abbc91c40bba817fec9d3d 100644 (file)
@@ -220,12 +220,21 @@ static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = {
 };
 
 static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = {
-       60000, 30000,
-       1, 8, 3, 1, 0,
-       0, 0, 1, 1, 2,
-       (3 << 14) | (1 << 12) | (524 << 0),
-       0,
-       20452225,
+       .internal = 60000,
+       .sampling = 30000,
+       .pll_prediv = 1,
+       .pll_ratio = 8,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 2,
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+       .ifreq = 0,
+       .timf = 20452225,
 };
 
 static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = {
@@ -342,57 +351,57 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
 
 /* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */
 static struct dibx000_agc_config xc3028_agc_config = {
-       BAND_VHF | BAND_UHF,       /* band_caps */
-
+       .band_caps = BAND_VHF | BAND_UHF,
        /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
         * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
         * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-       (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
-       (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
-
-       712,    /* inv_gain */
-       21,     /* time_stabiliz */
-
-       0,      /* alpha_level */
-       118,    /* thlock */
-
-       0,      /* wbd_inv */
-       2867,   /* wbd_ref */
-       0,      /* wbd_sel */
-       2,      /* wbd_alpha */
-
-       0,      /* agc1_max */
-       0,      /* agc1_min */
-       39718,  /* agc2_max */
-       9930,   /* agc2_min */
-       0,      /* agc1_pt1 */
-       0,      /* agc1_pt2 */
-       0,      /* agc1_pt3 */
-       0,      /* agc1_slope1 */
-       0,      /* agc1_slope2 */
-       0,      /* agc2_pt1 */
-       128,    /* agc2_pt2 */
-       29,     /* agc2_slope1 */
-       29,     /* agc2_slope2 */
-
-       17,     /* alpha_mant */
-       27,     /* alpha_exp */
-       23,     /* beta_mant */
-       51,     /* beta_exp */
-
-       1,      /* perform_agc_softsplit */
+       .setup = (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
+       .inv_gain = 712,
+       .time_stabiliz = 21,
+       .alpha_level = 0,
+       .thlock = 118,
+       .wbd_inv = 0,
+       .wbd_ref = 2867,
+       .wbd_sel = 0,
+       .wbd_alpha = 2,
+       .agc1_max = 0,
+       .agc1_min = 0,
+       .agc2_max = 39718,
+       .agc2_min = 9930,
+       .agc1_pt1 = 0,
+       .agc1_pt2 = 0,
+       .agc1_pt3 = 0,
+       .agc1_slope1 = 0,
+       .agc1_slope2 = 0,
+       .agc2_pt1 = 0,
+       .agc2_pt2 = 128,
+       .agc2_slope1 = 29,
+       .agc2_slope2 = 29,
+       .alpha_mant = 17,
+       .alpha_exp = 27,
+       .beta_mant = 23,
+       .beta_exp = 51,
+       .perform_agc_softsplit = 1,
 };
 
 /* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */
 static struct dibx000_bandwidth_config xc3028_bw_config = {
-       60000, 30000, /* internal, sampling */
-       1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */
-       0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc,
-                         modulo */
-       (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
-       (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
-       20452225, /* timf */
-       30000000, /* xtal_hz */
+       .internal = 60000,
+       .sampling = 30000,
+       .pll_prediv = 1,
+       .pll_ratio = 8,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 0,
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
+       .ifreq = (1 << 25) | 5816102,  /* ifreq = 5.200000 MHz */
+       .timf = 20452225,
+       .xtal_hz = 30000000,
 };
 
 static struct dib7000p_config stk7700ph_dib7700_xc3028_config = {
@@ -614,59 +623,55 @@ static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
 };
 
 static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = {
-       BAND_UHF | BAND_VHF,
-
+       .band_caps = BAND_UHF | BAND_VHF,
        /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
         * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-       (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
-       | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
-
-       712,
-       41,
-
-       0,
-       118,
-
-       0,
-       4095,
-       0,
-       0,
-
-       42598,
-       16384,
-       42598,
-           0,
-
-         0,
-       137,
-       255,
-
-         0,
-       255,
-
-       0,
-       0,
-
-        0,
-       41,
-
-       15,
-       25,
-
-       28,
-       48,
-
-       0,
+       .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
+       .inv_gain = 712,
+       .time_stabiliz = 41,
+       .alpha_level = 0,
+       .thlock = 118,
+       .wbd_inv = 0,
+       .wbd_ref = 4095,
+       .wbd_sel = 0,
+       .wbd_alpha = 0,
+       .agc1_max = 42598,
+       .agc1_min = 16384,
+       .agc2_max = 42598,
+       .agc2_min = 0,
+       .agc1_pt1 = 0,
+       .agc1_pt2 = 137,
+       .agc1_pt3 = 255,
+       .agc1_slope1 = 0,
+       .agc1_slope2 = 255,
+       .agc2_pt1 = 0,
+       .agc2_pt2 = 0,
+       .agc2_slope1 = 0,
+       .agc2_slope2 = 41,
+       .alpha_mant = 15,
+       .alpha_exp = 25,
+       .beta_mant = 28,
+       .beta_exp = 48,
+       .perform_agc_softsplit = 0,
 };
 
 static struct dibx000_bandwidth_config stk7700p_pll_config = {
-       60000, 30000,
-       1, 8, 3, 1, 0,
-       0, 0, 1, 1, 0,
-       (3 << 14) | (1 << 12) | (524 << 0),
-       60258167,
-       20452225,
-       30000000,
+       .internal = 60000,
+       .sampling = 30000,
+       .pll_prediv = 1,
+       .pll_ratio = 8,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 0,
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+       .ifreq = 60258167,
+       .timf = 20452225,
+       .xtal_hz = 30000000,
 };
 
 static struct dib7000m_config stk7700p_dib7000m_config = {
@@ -758,45 +763,36 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
 
 /* DIB7070 generic */
 static struct dibx000_agc_config dib7070_agc_config = {
-       BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+       .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
        /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
         * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
-       (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
-       | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
-
-       600,
-       10,
-
-       0,
-       118,
-
-       0,
-       3530,
-       1,
-       5,
-
-       65535,
-               0,
-
-       65535,
-       0,
-
-       0,
-       40,
-       183,
-       206,
-       255,
-       72,
-       152,
-       88,
-       90,
-
-       17,
-       27,
-       23,
-       51,
-
-       0,
+       .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+       .inv_gain = 600,
+       .time_stabiliz = 10,
+       .alpha_level = 0,
+       .thlock = 118,
+       .wbd_inv = 0,
+       .wbd_ref = 3530,
+       .wbd_sel = 1,
+       .wbd_alpha = 5,
+       .agc1_max = 65535,
+       .agc1_min = 0,
+       .agc2_max = 65535,
+       .agc2_min = 0,
+       .agc1_pt1 = 0,
+       .agc1_pt2 = 40,
+       .agc1_pt3 = 183,
+       .agc1_slope1 = 206,
+       .agc1_slope2 = 255,
+       .agc2_pt1 = 72,
+       .agc2_pt2 = 152,
+       .agc2_slope1 = 88,
+       .agc2_slope2 = 90,
+       .alpha_mant = 17,
+       .alpha_exp = 27,
+       .beta_mant = 23,
+       .beta_exp = 51,
+       .perform_agc_softsplit = 0,
 };
 
 static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
@@ -952,13 +948,22 @@ static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
 }
 
 static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
-       60000, 15000,
-       1, 20, 3, 1, 0,
-       0, 0, 1, 1, 2,
-       (3 << 14) | (1 << 12) | (524 << 0),
-       (0 << 25) | 0,
-       20452225,
-       12000000,
+       .internal = 60000,
+       .sampling = 15000,
+       .pll_prediv = 1,
+       .pll_ratio = 20,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 2,
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+       .ifreq = (0 << 25) | 0,
+       .timf = 20452225,
+       .xtal_hz = 12000000,
 };
 
 static struct dib7000p_config dib7070p_dib7000p_config = {
@@ -1169,14 +1174,22 @@ static struct dibx000_agc_config dib807x_agc_config[2] = {
 };
 
 static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = {
-       60000, 15000, /* internal, sampling*/
-       1, 20, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass*/
-       0, 0, 1, 1, 2, /* misc: refdiv, bypclk_div, IO_CLK_en_core,
-                         ADClkSrc, modulo */
-       (3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/
-       (0 << 25) | 0, /* ifreq = 0.000000 MHz*/
-       18179755, /* timf*/
-       12000000, /* xtal_hz*/
+       .internal = 60000,
+       .sampling = 15000,
+       .pll_prediv = 1,
+       .pll_ratio = 20,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 2,
+       .sad_cfg = (3 << 14) | (1 << 12) | (599 << 0),  /* sad_cfg: refsel, sel, freq_15k*/
+       .ifreq = (0 << 25) | 0,                         /* ifreq = 0.000000 MHz*/
+       .timf = 18179755,
+       .xtal_hz = 12000000,
 };
 
 static struct dib8000_config dib807x_dib8000_config[2] = {
@@ -1921,13 +1934,22 @@ static struct dibx000_agc_config dib8096p_agc_config[2] = {
 };
 
 static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = {
-       108000, 13500,
-       1, 9, 1, 0, 0,
-       0, 0, 0, 0, 2,
-       (3 << 14) | (1 << 12) | (524 << 0),
-       (0 << 25) | 0,
-       20199729,
-       12000000,
+       .internal = 108000,
+       .sampling = 13500,
+       .pll_prediv = 1,
+       .pll_ratio = 9,
+       .pll_range = 1,
+       .pll_reset = 0,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 0,
+       .ADClkSrc = 0,
+       .modulo = 2,
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+       .ifreq = (0 << 25) | 0,
+       .timf = 20199729,
+       .xtal_hz = 12000000,
 };
 
 static struct dib8000_config tfe8096p_dib8000_config = {
@@ -2724,13 +2746,22 @@ static struct dibx000_agc_config dib7090_agc_config[2] = {
 };
 
 static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = {
-       60000, 15000,
-       1, 5, 0, 0, 0,
-       0, 0, 1, 1, 2,
-       (3 << 14) | (1 << 12) | (524 << 0),
-       (0 << 25) | 0,
-       20452225,
-       15000000,
+       .internal = 60000,
+       .sampling = 15000,
+       .pll_prediv = 1,
+       .pll_ratio = 5,
+       .pll_range = 0,
+       .pll_reset = 0,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 2,
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+       .ifreq = (0 << 25) | 0,
+       .timf = 20452225,
+       .xtal_hz = 15000000,
 };
 
 static struct dib7000p_config nim7090_dib7000p_config = {
@@ -3498,14 +3529,22 @@ static struct dibx000_agc_config stk7700p_7000p_xc4000_agc_config = {
 };
 
 static struct dibx000_bandwidth_config stk7700p_xc4000_pll_config = {
-       60000, 30000,   /* internal, sampling */
-       1, 8, 3, 1, 0,  /* pll_cfg: prediv, ratio, range, reset, bypass */
-       0, 0, 1, 1, 0,  /* misc: refdiv, bypclk_div, IO_CLK_en_core, */
-                       /* ADClkSrc, modulo */
-       (3 << 14) | (1 << 12) | 524,    /* sad_cfg: refsel, sel, freq_15k */
-       39370534,       /* ifreq */
-       20452225,       /* timf */
-       30000000        /* xtal */
+       .internal = 60000,
+       .sampling = 30000,
+       .pll_prediv = 1,
+       .pll_ratio = 8,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 0,
+       .sad_cfg = (3 << 14) | (1 << 12) | 524, /* sad_cfg: refsel, sel, freq_15k */
+       .ifreq = 39370534,
+       .timf = 20452225,
+       .xtal_hz = 30000000
 };
 
 /* FIXME: none of these inputs are validated yet */
index 6d68af0c49c83ecab8d542eb0a3942902e70e7e8..ef3a8f75f82ebe21b4ee5b7963aed9bbf8449c32 100644 (file)
@@ -258,8 +258,8 @@ static struct dib3000mc_config mod3000p_dib3000p_config = {
 
 int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       if (adap->dev->udev->descriptor.idVendor  == USB_VID_LITEON &&
-                       adap->dev->udev->descriptor.idProduct ==
+       if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON &&
+           le16_to_cpu(adap->dev->udev->descriptor.idProduct) ==
                        USB_PID_LITEON_DVB_T_WARM) {
                msleep(1000);
        }
@@ -297,8 +297,8 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
        struct i2c_adapter *tun_i2c;
 
        // First IF calibration for Liteon Sticks
-       if (adap->dev->udev->descriptor.idVendor  == USB_VID_LITEON &&
-               adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) {
+       if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON &&
+           le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_LITEON_DVB_T_WARM) {
 
                dibusb_read_eeprom_byte(adap->dev,0x7E,&a);
                dibusb_read_eeprom_byte(adap->dev,0x7F,&b);
@@ -310,8 +310,8 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
                else
                        warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b);
 
-       } else if (adap->dev->udev->descriptor.idVendor  == USB_VID_DIBCOM &&
-                  adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) {
+       } else if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_DIBCOM &&
+                  le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_DIBCOM_MOD3001_WARM) {
                u8 desc;
                dibusb_read_eeprom_byte(adap->dev, 7, &desc);
                if (desc == 2) {
index 2add8c507ec9ecd6cf2d27b7097a9c7e98fe9d2d..1a3df10d6bad5e1c1354874c8d715a7f6e5629c0 100644 (file)
@@ -667,7 +667,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                obuf[1] = (msg[j].addr << 1);
                                memcpy(obuf + 2, msg[j].buf, msg[j].len);
                                dw210x_op_rw(d->udev,
-                                               udev->descriptor.idProduct ==
+                                               le16_to_cpu(udev->descriptor.idProduct) ==
                                                0x7500 ? 0x92 : 0x90, 0, 0,
                                                obuf, msg[j].len + 2,
                                                DW210X_WRITE_MSG);
@@ -1598,7 +1598,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
        u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
        const struct firmware *fw;
 
-       switch (dev->descriptor.idProduct) {
+       switch (le16_to_cpu(dev->descriptor.idProduct)) {
        case 0x2101:
                ret = request_firmware(&fw, DW2101_FIRMWARE, &dev->dev);
                if (ret != 0) {
@@ -1641,7 +1641,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
                        ret = -EINVAL;
                }
                /* init registers */
-               switch (dev->descriptor.idProduct) {
+               switch (le16_to_cpu(dev->descriptor.idProduct)) {
                case USB_PID_TEVII_S650:
                        dw2104_properties.rc.core.rc_codes = RC_MAP_TEVII_NEC;
                case USB_PID_DW2104:
@@ -1901,14 +1901,14 @@ static struct dvb_usb_device_properties s6x0_properties = {
        }
 };
 
-struct dvb_usb_device_properties *p1100;
+static struct dvb_usb_device_properties *p1100;
 static struct dvb_usb_device_description d1100 = {
        "Prof 1100 USB ",
        {&dw2102_table[PROF_1100], NULL},
        {NULL},
 };
 
-struct dvb_usb_device_properties *s660;
+static struct dvb_usb_device_properties *s660;
 static struct dvb_usb_device_description d660 = {
        "TeVii S660 USB",
        {&dw2102_table[TEVII_S660], NULL},
@@ -1927,14 +1927,14 @@ static struct dvb_usb_device_description d480_2 = {
        {NULL},
 };
 
-struct dvb_usb_device_properties *p7500;
+static struct dvb_usb_device_properties *p7500;
 static struct dvb_usb_device_description d7500 = {
        "Prof 7500 USB DVB-S2",
        {&dw2102_table[PROF_7500], NULL},
        {NULL},
 };
 
-struct dvb_usb_device_properties *s421;
+static struct dvb_usb_device_properties *s421;
 static struct dvb_usb_device_description d421 = {
        "TeVii S421 PCI",
        {&dw2102_table[TEVII_S421], NULL},
index 16ba90acf5396ff54395497e9180b5f883adfc37..14a2119912ba5246474c6b249a855f5815c34331 100644 (file)
@@ -554,8 +554,8 @@ static int opera1_probe(struct usb_interface *intf,
 {
        struct usb_device *udev = interface_to_usbdev(intf);
 
-       if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
-               udev->descriptor.idVendor == USB_VID_OPERA1 &&
+       if (le16_to_cpu(udev->descriptor.idProduct) == USB_PID_OPERA1_WARM &&
+           le16_to_cpu(udev->descriptor.idVendor) == USB_VID_OPERA1 &&
                opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
            ) {
                return -EINVAL;
index bdfe8963591cbac6dfe69028ead20993421b118e..d17618fe8f5c80528bb8f6febc202449b5ad2999 100644 (file)
@@ -883,7 +883,7 @@ static int pctv452e_frontend_attach(struct dvb_usb_adapter *a)
        if (!a->fe_adap[0].fe)
                return -ENODEV;
        if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe,
-                                       &a->dev->i2c_adap)) == 0)
+                                       &a->dev->i2c_adap)) == NULL)
                err("Cannot attach lnbp22\n");
 
        id = a->dev->desc->warm_ids[0];
@@ -900,7 +900,7 @@ 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) {
+                                       &a->dev->i2c_adap) == NULL) {
                err("%s failed\n", __func__);
                return -ENODEV;
        }
@@ -965,7 +965,7 @@ static struct dvb_usb_device_properties pctv452e_properties = {
                  .cold_ids = { NULL, NULL }, /* this is a warm only device */
                  .warm_ids = { &pctv452e_usb_table[0], NULL }
                },
-               { 0 },
+               { NULL },
        }
 };
 
@@ -1023,7 +1023,7 @@ static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
                  .cold_ids = { NULL, NULL },
                  .warm_ids = { &pctv452e_usb_table[2], NULL }
                },
-               { 0 },
+               { NULL },
        }
 };
 
index e881ef7b64451060f39627ece2cb79c0f49330f7..957c7ae30efe5f5d724908f9b231e8a0b780e406 100644 (file)
@@ -268,7 +268,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
        nonblock = !!(substream->f_flags & O_NONBLOCK);
        if (nonblock) {
                if (!mutex_trylock(&dev->lock))
-               return -EAGAIN;
+                       return -EAGAIN;
        } else
                mutex_lock(&dev->lock);
 
@@ -893,7 +893,7 @@ static int em28xx_audio_init(struct em28xx *dev)
        static int          devnr;
        int                 err;
 
-       if (!dev->has_alsa_audio) {
+       if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) {
                /* This device does not support the extension (in this case
                   the device is expecting the snd-usb-audio module or
                   doesn't have analog audio support at all) */
@@ -975,7 +975,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
        if (dev == NULL)
                return 0;
 
-       if (!dev->has_alsa_audio) {
+       if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) {
                /* This device does not support the extension (in this case
                   the device is expecting the snd-usb-audio module or
                   doesn't have analog audio support at all) */
@@ -1003,7 +1003,7 @@ static int em28xx_audio_suspend(struct em28xx *dev)
        if (dev == NULL)
                return 0;
 
-       if (!dev->has_alsa_audio)
+       if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR)
                return 0;
 
        em28xx_info("Suspending audio extension");
@@ -1017,7 +1017,7 @@ static int em28xx_audio_resume(struct em28xx *dev)
        if (dev == NULL)
                return 0;
 
-       if (!dev->has_alsa_audio)
+       if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR)
                return 0;
 
        em28xx_info("Resuming audio extension");
index 9da812b8a7861de75722cf5fcfdbe29e3baf39eb..71fa51e7984e462115d0bb7564ea6871a9c012b9 100644 (file)
@@ -2246,7 +2246,7 @@ struct em28xx_board em28xx_boards[] = {
 };
 EXPORT_SYMBOL_GPL(em28xx_boards);
 
-const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
+static const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
 /* table of devices that work with this driver */
 struct usb_device_id em28xx_id_table[] = {
@@ -2931,9 +2931,9 @@ static void request_module_async(struct work_struct *work)
 #if defined(CONFIG_MODULES) && defined(MODULE)
        if (dev->has_video)
                request_module("em28xx-v4l");
-       if (dev->has_audio_class)
+       if (dev->usb_audio_type == EM28XX_USB_AUDIO_CLASS)
                request_module("snd-usb-audio");
-       else if (dev->has_alsa_audio)
+       else if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR)
                request_module("em28xx-alsa");
        if (dev->board.has_dvb)
                request_module("em28xx-dvb");
@@ -3098,16 +3098,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
                }
        }
 
-       if (dev->chip_id == CHIP_ID_EM2870 ||
-           dev->chip_id == CHIP_ID_EM2874 ||
-           dev->chip_id == CHIP_ID_EM28174 ||
-           dev->chip_id == CHIP_ID_EM28178) {
-               /* Digital only device - don't load any alsa module */
-               dev->audio_mode.has_audio = false;
-               dev->has_audio_class = false;
-               dev->has_alsa_audio = false;
-       }
-
        if (chip_name != default_chip_name)
                printk(KERN_INFO DRIVER_NAME
                       ": chip ID is %s\n", chip_name);
@@ -3190,7 +3180,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        struct usb_device *udev;
        struct em28xx *dev = NULL;
        int retval;
-       bool has_audio = false, has_video = false, has_dvb = false;
+       bool has_vendor_audio = false, has_video = false, has_dvb = false;
        int i, nr, try_bulk;
        const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
        char *speed;
@@ -3272,7 +3262,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                                        break;
                                case 0x83:
                                        if (usb_endpoint_xfer_isoc(e)) {
-                                               has_audio = true;
+                                               has_vendor_audio = true;
                                        } else {
                                                printk(KERN_INFO DRIVER_NAME
                                                ": error: skipping audio endpoint 0x83, because it uses bulk transfers !\n");
@@ -3328,7 +3318,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                }
        }
 
-       if (!(has_audio || has_video || has_dvb)) {
+       if (!(has_vendor_audio || has_video || has_dvb)) {
                retval = -ENODEV;
                goto err_free;
        }
@@ -3375,26 +3365,27 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        dev->devno = nr;
        dev->model = id->driver_info;
        dev->alt   = -1;
-       dev->is_audio_only = has_audio && !(has_video || has_dvb);
-       dev->has_alsa_audio = has_audio;
-       dev->audio_mode.has_audio = has_audio;
+       dev->is_audio_only = has_vendor_audio && !(has_video || has_dvb);
        dev->has_video = has_video;
        dev->ifnum = ifnum;
 
-       /* Checks if audio is provided by some interface */
+       if (has_vendor_audio) {
+               printk(KERN_INFO DRIVER_NAME ": Audio interface %i found %s\n",
+                      ifnum, "(Vendor Class)");
+               dev->usb_audio_type = EM28XX_USB_AUDIO_VENDOR;
+       }
+       /* Checks if audio is provided by a USB Audio Class interface */
        for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
                struct usb_interface *uif = udev->config->interface[i];
                if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
-                       dev->has_audio_class = 1;
+                       if (has_vendor_audio)
+                               em28xx_err("em28xx: device seems to have vendor AND usb audio class interfaces !\n"
+                                          "\t\tThe vendor interface will be ignored. Please contact the developers <linux-media@vger.kernel.org>\n");
+                       dev->usb_audio_type = EM28XX_USB_AUDIO_CLASS;
                        break;
                }
        }
 
-       if (has_audio)
-               printk(KERN_INFO DRIVER_NAME
-                      ": Audio interface %i found %s\n",
-                      ifnum,
-                      dev->has_audio_class ? "(USB Audio Class)" : "(Vendor Class)");
        if (has_video)
                printk(KERN_INFO DRIVER_NAME
                       ": Video interface %i found:%s%s\n",
index 523d7e92bf47b7974515a1d9acd2fc19ab131b51..b5e52fe7957aff0d047abb1f89caab275fcb1afd 100644 (file)
@@ -279,7 +279,7 @@ int em28xx_read_ac97(struct em28xx *dev, u8 reg)
 {
        int ret;
        u8 addr = (reg & 0x7f) | 0x80;
-       u16 val;
+       __le16 val;
 
        ret = em28xx_is_ac97_ready(dev);
        if (ret < 0)
@@ -433,7 +433,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
        int ret, i;
        u8 xclk;
 
-       if (!dev->audio_mode.has_audio)
+       if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE)
                return 0;
 
        /* It is assumed that all devices use master volume for output.
@@ -505,37 +505,48 @@ int em28xx_audio_setup(struct em28xx *dev)
 {
        int vid1, vid2, feat, cfg;
        u32 vid;
+       u8 i2s_samplerates;
 
-       if (!dev->audio_mode.has_audio)
+       if (dev->chip_id == CHIP_ID_EM2870 ||
+           dev->chip_id == CHIP_ID_EM2874 ||
+           dev->chip_id == CHIP_ID_EM28174 ||
+           dev->chip_id == CHIP_ID_EM28178) {
+               /* Digital only device - don't load any alsa module */
+               dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
+               dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
                return 0;
+       }
 
        /* See how this device is configured */
        cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
        em28xx_info("Config register raw data: 0x%02x\n", cfg);
-       if (cfg < 0) {
-               /* Register read error?  */
-               cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
+       if (cfg < 0) { /* Register read error */
+               /* Be conservative */
+               dev->int_audio_type = EM28XX_INT_AUDIO_AC97;
        } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
                /* The device doesn't have vendor audio at all */
-               dev->has_alsa_audio = false;
-               dev->audio_mode.has_audio = false;
+               dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
+               dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
                return 0;
        } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+               dev->int_audio_type = EM28XX_INT_AUDIO_I2S;
                if (dev->chip_id < CHIP_ID_EM2860 &&
                    (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
                    EM2820_CHIPCFG_I2S_1_SAMPRATE)
-                       dev->audio_mode.i2s_samplerates = 1;
+                       i2s_samplerates = 1;
                else if (dev->chip_id >= CHIP_ID_EM2860 &&
                         (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
                         EM2860_CHIPCFG_I2S_5_SAMPRATES)
-                       dev->audio_mode.i2s_samplerates = 5;
+                       i2s_samplerates = 5;
                else
-                       dev->audio_mode.i2s_samplerates = 3;
+                       i2s_samplerates = 3;
                em28xx_info("I2S Audio (%d sample rate(s))\n",
-                                              dev->audio_mode.i2s_samplerates);
+                                              i2s_samplerates);
                /* Skip the code that does AC97 vendor detection */
                dev->audio_mode.ac97 = EM28XX_NO_AC97;
                goto init_audio;
+       } else {
+               dev->int_audio_type = EM28XX_INT_AUDIO_AC97;
        }
 
        dev->audio_mode.ac97 = EM28XX_AC97_OTHER;
@@ -549,8 +560,9 @@ int em28xx_audio_setup(struct em28xx *dev)
                 */
                em28xx_warn("AC97 chip type couldn't be determined\n");
                dev->audio_mode.ac97 = EM28XX_NO_AC97;
-               dev->has_alsa_audio = false;
-               dev->audio_mode.has_audio = false;
+               if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR)
+                       dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
+               dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
                goto init_audio;
        }
 
@@ -559,15 +571,12 @@ int em28xx_audio_setup(struct em28xx *dev)
                goto init_audio;
 
        vid = vid1 << 16 | vid2;
-
-       dev->audio_mode.ac97_vendor_id = vid;
        em28xx_warn("AC97 vendor ID = 0x%08x\n", vid);
 
        feat = em28xx_read_ac97(dev, AC97_RESET);
        if (feat < 0)
                goto init_audio;
 
-       dev->audio_mode.ac97_feat = feat;
        em28xx_warn("AC97 features = 0x%04x\n", feat);
 
        /* Try to identify what audio processor we have */
@@ -586,8 +595,8 @@ init_audio:
                em28xx_info("Empia 202 AC97 audio processor detected\n");
                break;
        case EM28XX_AC97_SIGMATEL:
-               em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n",
-                           dev->audio_mode.ac97_vendor_id & 0xff);
+               em28xx_info("Sigmatel audio processor detected (stac 97%02x)\n",
+                           vid & 0xff);
                break;
        case EM28XX_AC97_OTHER:
                em28xx_warn("Unknown AC97 audio processor detected!\n");
index 3a3e243edf89df29982f632cb06e0f53af6ad515..9682c52d67d17b3be3d52e9fc9f878f73d2aed9d 100644 (file)
@@ -373,7 +373,6 @@ static struct tda18271_config kworld_ub435q_v2_config = {
 };
 
 static struct tda18212_config kworld_ub435q_v3_config = {
-       .i2c_address    = 0x60,
        .if_atsc_vsb    = 3600,
        .if_atsc_qam    = 3600,
 };
@@ -856,7 +855,9 @@ static const struct m88ds3103_config pctv_461e_m88ds3103_config = {
        .clock = 27000000,
        .i2c_wr_max = 33,
        .clock_out = 0,
-       .ts_mode = M88DS3103_TS_PARALLEL_16,
+       .ts_mode = M88DS3103_TS_PARALLEL,
+       .ts_clk = 16000,
+       .ts_clk_pol = 1,
        .agc = 0x99,
 };
 
@@ -1435,6 +1436,15 @@ static int em28xx_dvb_init(struct em28xx *dev)
                }
                break;
        case EM2874_BOARD_KWORLD_UB435Q_V3:
+       {
+               struct i2c_client *client;
+               struct i2c_adapter *adapter = &dev->i2c_adap[dev->def_i2c_bus];
+               struct i2c_board_info board_info = {
+                       .type = "tda18212",
+                       .addr = 0x60,
+                       .platform_data = &kworld_ub435q_v3_config,
+               };
+
                dvb->fe[0] = dvb_attach(lgdt3305_attach,
                                        &em2874_lgdt3305_nogate_dev,
                                        &dev->i2c_adap[dev->def_i2c_bus]);
@@ -1443,14 +1453,26 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        goto out_free;
                }
 
-               /* Attach the demodulator. */
-               if (!dvb_attach(tda18212_attach, dvb->fe[0],
-                               &dev->i2c_adap[dev->def_i2c_bus],
-                               &kworld_ub435q_v3_config)) {
-                       result = -EINVAL;
+               /* attach tuner */
+               kworld_ub435q_v3_config.fe = dvb->fe[0];
+               request_module("tda18212");
+               client = i2c_new_device(adapter, &board_info);
+               if (client == NULL || client->dev.driver == NULL) {
+                       dvb_frontend_detach(dvb->fe[0]);
+                       result = -ENODEV;
                        goto out_free;
                }
+
+               if (!try_module_get(client->dev.driver->owner)) {
+                       i2c_unregister_device(client);
+                       dvb_frontend_detach(dvb->fe[0]);
+                       result = -ENODEV;
+                       goto out_free;
+               }
+
+               dvb->i2c_client_tuner = client;
                break;
+       }
        case EM2874_BOARD_PCTV_HD_MINI_80E:
                dvb->fe[0] = dvb_attach(drx39xxj_attach, &dev->i2c_adap[dev->def_i2c_bus]);
                if (dvb->fe[0] != NULL) {
@@ -1533,6 +1555,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        /* attach demod */
                        si2168_config.i2c_adapter = &adapter;
                        si2168_config.fe = &dvb->fe[0];
+                       si2168_config.ts_mode = SI2168_TS_PARALLEL;
                        memset(&info, 0, sizeof(struct i2c_board_info));
                        strlcpy(info.type, "si2168", I2C_NAME_SIZE);
                        info.addr = 0x64;
index ed843bd221eaec8a9bb3307d965a0b49275e50f1..581f6dad4ca9deef0fa5a0820372238b8a4e3bbd 100644 (file)
@@ -71,8 +71,7 @@ struct em28xx_IR {
        unsigned int last_readcount;
        u64 rc_type;
 
-       /* i2c slave address of external device (if used) */
-       u16 i2c_dev_addr;
+       struct i2c_client *i2c_client;
 
        int  (*get_key_i2c)(struct i2c_client *ir, enum rc_type *protocol, u32 *scancode);
        int  (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
@@ -294,16 +293,11 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
 
 static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
 {
-       struct em28xx *dev = ir->dev;
        static u32 scancode;
        enum rc_type protocol;
        int rc;
-       struct i2c_client client;
-
-       client.adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
-       client.addr = ir->i2c_dev_addr;
 
-       rc = ir->get_key_i2c(&client, &protocol, &scancode);
+       rc = ir->get_key_i2c(ir->i2c_client, &protocol, &scancode);
        if (rc < 0) {
                dprintk("ir->get_key_i2c() failed: %d\n", rc);
                return rc;
@@ -361,7 +355,7 @@ static void em28xx_ir_work(struct work_struct *work)
 {
        struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);
 
-       if (ir->i2c_dev_addr) /* external i2c device */
+       if (ir->i2c_client) /* external i2c device */
                em28xx_i2c_ir_handle_key(ir);
        else /* internal device */
                em28xx_ir_handle_key(ir);
@@ -609,17 +603,17 @@ static int em28xx_register_snapshot_button(struct em28xx *dev)
 static void em28xx_init_buttons(struct em28xx *dev)
 {
        u8  i = 0, j = 0;
-       bool addr_new = 0;
+       bool addr_new = false;
 
        dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL;
        while (dev->board.buttons[i].role >= 0 &&
                         dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) {
                struct em28xx_button *button = &dev->board.buttons[i];
                /* Check if polling address is already on the list */
-               addr_new = 1;
+               addr_new = true;
                for (j = 0; j < dev->num_button_polling_addresses; j++) {
                        if (button->reg_r == dev->button_polling_addresses[j]) {
-                               addr_new = 0;
+                               addr_new = false;
                                break;
                        }
                }
@@ -756,7 +750,13 @@ static int em28xx_ir_init(struct em28xx *dev)
                        goto error;
                }
 
-               ir->i2c_dev_addr = i2c_rc_dev_addr;
+               ir->i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+               if (!ir->i2c_client)
+                       goto error;
+               ir->i2c_client->adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
+               ir->i2c_client->addr = i2c_rc_dev_addr;
+               ir->i2c_client->flags = 0;
+               /* NOTE: all other fields of i2c_client are unused */
        } else {        /* internal device */
                switch (dev->chip_id) {
                case CHIP_ID_EM2860:
@@ -815,6 +815,7 @@ static int em28xx_ir_init(struct em28xx *dev)
        return 0;
 
 error:
+       kfree(ir->i2c_client);
        dev->ir = NULL;
        rc_free_device(rc);
        kfree(ir);
@@ -841,6 +842,8 @@ static int em28xx_ir_fini(struct em28xx *dev)
        if (ir->rc)
                rc_unregister_device(ir->rc);
 
+       kfree(ir->i2c_client);
+
        /* done */
        kfree(ir);
        dev->ir = NULL;
index 6d7f657f6f55cad6e19a72a1b0ff0477751a909c..34ee1e03a73283b3cc1e4100140ee343984a7b0d 100644 (file)
 #include "em28xx.h"
 #include "em28xx-v4l.h"
 
-static unsigned int vbibufs = 5;
-module_param(vbibufs, int, 0644);
-MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
-
-static unsigned int vbi_debug;
-module_param(vbi_debug, int, 0644);
-MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
-
-#define dprintk(level, fmt, arg...)    if (vbi_debug >= level) \
-       printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg)
-
 /* ------------------------------------------------------------------ */
 
 static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
index 29abc379551e5d6f79483520a892006dca848ed7..03d5ece0319c63e748f669635889769fc64ea210 100644 (file)
@@ -435,7 +435,10 @@ static inline void finish_buffer(struct em28xx *dev,
        em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
 
        buf->vb.v4l2_buf.sequence = dev->v4l2->field_count++;
-       buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+       if (dev->v4l2->progressive)
+               buf->vb.v4l2_buf.field = V4L2_FIELD_NONE;
+       else
+               buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
        v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
 
        vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
@@ -478,7 +481,7 @@ static void em28xx_copy_video(struct em28xx *dev,
        lencopy = lencopy > remain ? remain : lencopy;
 
        if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->length) {
-               em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+               em28xx_isocdbg("Overflow of %zu bytes past buffer end (1)\n",
                              ((char *)startwrite + lencopy) -
                              ((char *)buf->vb_buf + buf->length));
                remain = (char *)buf->vb_buf + buf->length -
@@ -504,7 +507,7 @@ static void em28xx_copy_video(struct em28xx *dev,
 
                if ((char *)startwrite + lencopy > (char *)buf->vb_buf +
                    buf->length) {
-                       em28xx_isocdbg("Overflow of %zi bytes past buffer end"
+                       em28xx_isocdbg("Overflow of %zu bytes past buffer end"
                                       "(2)\n",
                                       ((char *)startwrite + lencopy) -
                                       ((char *)buf->vb_buf + buf->length));
@@ -718,7 +721,7 @@ static inline void process_frame_data_em25xx(struct em28xx *dev,
        struct em28xx_buffer    *buf = dev->usb_ctl.vid_buf;
        struct em28xx_dmaqueue  *dmaq = &dev->vidq;
        struct em28xx_v4l2      *v4l2 = dev->v4l2;
-       bool frame_end = 0;
+       bool frame_end = false;
 
        /* Check for header */
        /* NOTE: at least with bulk transfers, only the first packet
@@ -994,13 +997,16 @@ static void em28xx_stop_streaming(struct vb2_queue *vq)
        }
 
        spin_lock_irqsave(&dev->slock, flags);
+       if (dev->usb_ctl.vid_buf != NULL) {
+               vb2_buffer_done(&dev->usb_ctl.vid_buf->vb, VB2_BUF_STATE_ERROR);
+               dev->usb_ctl.vid_buf = NULL;
+       }
        while (!list_empty(&vidq->active)) {
                struct em28xx_buffer *buf;
                buf = list_entry(vidq->active.next, struct em28xx_buffer, list);
                list_del(&buf->list);
                vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
        }
-       dev->usb_ctl.vid_buf = NULL;
        spin_unlock_irqrestore(&dev->slock, flags);
 }
 
@@ -1021,13 +1027,16 @@ void em28xx_stop_vbi_streaming(struct vb2_queue *vq)
        }
 
        spin_lock_irqsave(&dev->slock, flags);
+       if (dev->usb_ctl.vbi_buf != NULL) {
+               vb2_buffer_done(&dev->usb_ctl.vbi_buf->vb, VB2_BUF_STATE_ERROR);
+               dev->usb_ctl.vbi_buf = NULL;
+       }
        while (!list_empty(&vbiq->active)) {
                struct em28xx_buffer *buf;
                buf = list_entry(vbiq->active.next, struct em28xx_buffer, list);
                list_del(&buf->list);
                vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
        }
-       dev->usb_ctl.vbi_buf = NULL;
        spin_unlock_irqrestore(&dev->slock, flags);
 }
 
@@ -1711,7 +1720,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
        else
                cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
 
-       if (dev->audio_mode.has_audio)
+       if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE)
                cap->device_caps |= V4L2_CAP_AUDIO;
 
        if (dev->tuner_type != TUNER_ABSENT)
@@ -2296,7 +2305,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
        v4l2->v4l2_dev.ctrl_handler = hdl;
 
        if (dev->board.is_webcam)
-               v4l2->progressive = 1;
+               v4l2->progressive = true;
 
        /*
         * Default format, used for tvp5150 or saa711x output formats
@@ -2502,7 +2511,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
                v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_FREQUENCY);
                v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_FREQUENCY);
        }
-       if (!dev->audio_mode.has_audio) {
+       if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) {
                v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_AUDIO);
                v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_AUDIO);
        }
@@ -2532,7 +2541,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
                        v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_FREQUENCY);
                        v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_FREQUENCY);
                }
-               if (!dev->audio_mode.has_audio) {
+               if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) {
                        v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_AUDIO);
                        v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_AUDIO);
                }
index 4360338e7b310a2ab985eca427ef34124ddf15a5..a21a7463b557913ff0c97eb41f203a1f1d95c930 100644 (file)
@@ -309,13 +309,18 @@ enum em28xx_ac97_mode {
 
 struct em28xx_audio_mode {
        enum em28xx_ac97_mode ac97;
+};
 
-       u16 ac97_feat;
-       u32 ac97_vendor_id;
-
-       unsigned int has_audio:1;
+enum em28xx_int_audio_type {
+       EM28XX_INT_AUDIO_NONE = 0,
+       EM28XX_INT_AUDIO_AC97,
+       EM28XX_INT_AUDIO_I2S,
+};
 
-       u8 i2s_samplerates;
+enum em28xx_usb_audio_type {
+       EM28XX_USB_AUDIO_NONE = 0,
+       EM28XX_USB_AUDIO_CLASS,
+       EM28XX_USB_AUDIO_VENDOR,
 };
 
 /* em28xx has two audio inputs: tuner and line in.
@@ -608,9 +613,9 @@ struct em28xx {
        unsigned int is_em25xx:1;       /* em25xx/em276x/7x/8x family bridge */
        unsigned char disconnected:1;   /* device has been diconnected */
        unsigned int has_video:1;
-       unsigned int has_audio_class:1;
-       unsigned int has_alsa_audio:1;
        unsigned int is_audio_only:1;
+       enum em28xx_int_audio_type int_audio_type;
+       enum em28xx_usb_audio_type usb_audio_type;
 
        struct em28xx_board board;
 
index ece27ece81158f0c17b1125f3a8e27616082a45b..3f986e1178ce4fa5f821eadf489b3e5f15ff2e33 100644 (file)
@@ -696,7 +696,7 @@ static int go7007_usb_ezusb_write_interrupt(struct go7007 *go,
                                sizeof(status_reg), timeout);
                if (r < 0)
                        break;
-               status_reg = le16_to_cpu(*((u16 *)go->usb_buf));
+               status_reg = le16_to_cpu(*((__le16 *)go->usb_buf));
                if (!(status_reg & 0x0010))
                        break;
                msleep(10);
@@ -751,7 +751,7 @@ static int go7007_usb_onboard_write_interrupt(struct go7007 *go,
 static void go7007_usb_readinterrupt_complete(struct urb *urb)
 {
        struct go7007 *go = (struct go7007 *)urb->context;
-       u16 *regs = (u16 *)urb->transfer_buffer;
+       __le16 *regs = (__le16 *)urb->transfer_buffer;
        int status = urb->status;
 
        if (status) {
index e8cf23c91cefc0b570391f5146b831733f5d14be..43d65057a5fe657464d5e7709c769e9fa4b93115 100644 (file)
@@ -876,9 +876,8 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                ep_tb[0].alt = gspca_dev->alt;
                alt_idx = 1;
        } else {
-
-       /* else, compute the minimum bandwidth
-        * and build the endpoint table */
+               /* else, compute the minimum bandwidth
+                * and build the endpoint table */
                alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb);
                if (alt_idx <= 0) {
                        pr_err("no transfer endpoint found\n");
index f06253cd746901bfbeca0521e42c465db4241fa9..d39adf90303b9a4371fd3ed878705ae7754535d8 100644 (file)
@@ -235,6 +235,6 @@ int gspca_resume(struct usb_interface *intf);
 int gspca_expo_autogain(struct gspca_dev *gspca_dev, int avg_lum,
        int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee);
 int gspca_coarse_grained_expo_autogain(struct gspca_dev *gspca_dev,
-        int avg_lum, int desired_avg_lum, int deadzone);
+       int avg_lum, int desired_avg_lum, int deadzone);
 
 #endif /* GSPCAV2_H */
index 45bc1f51c5d8c14ed0fe6d6dd71690d7b990c530..3cb30a37d6ac90818521dc646b48b9f9bfcabb95 100644 (file)
@@ -51,9 +51,9 @@ struct pkt_hdr {
 
 struct cam_hdr {
        uint8_t magic[2];
-       uint16_t len;
-       uint16_t cmd;
-       uint16_t tag;
+       __le16 len;
+       __le16 cmd;
+       __le16 tag;
 };
 
 /* specific webcam descriptor */
@@ -188,9 +188,9 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf,
                       rhdr->tag, chdr->tag);
                return -1;
        }
-       if (cpu_to_le16(rhdr->len) != (actual_len/2)) {
+       if (le16_to_cpu(rhdr->len) != (actual_len/2)) {
                pr_err("send_cmd: Bad len %04x != %04x\n",
-                      cpu_to_le16(rhdr->len), (int)(actual_len/2));
+                      le16_to_cpu(rhdr->len), (int)(actual_len/2));
                return -1;
        }
 
@@ -211,7 +211,7 @@ static int write_register(struct gspca_dev *gspca_dev, uint16_t reg,
                        uint16_t data)
 {
        uint16_t reply[2];
-       uint16_t cmd[2];
+       __le16 cmd[2];
        int res;
 
        cmd[0] = cpu_to_le16(reg);
index 41a9a892f79c546c4a6b54edbee1ac09408897f6..d0ee899584a9f1188d44613ec6f21228a0e94e7a 100644 (file)
@@ -1297,7 +1297,7 @@ static void set_cmatrix(struct gspca_dev *gspca_dev,
        s32 hue_coord, hue_index = 180 + hue;
        u8 cmatrix[21];
 
-       memset(cmatrix, 0, sizeof cmatrix);
+       memset(cmatrix, 0, sizeof(cmatrix));
        cmatrix[2] = (contrast * 0x25 / 0x100) + 0x26;
        cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
        cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
@@ -1787,8 +1787,9 @@ static int sd_init(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int i;
        u8 value;
-       u8 i2c_init[9] =
-               {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
+       u8 i2c_init[9] = {
+               0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03
+       };
 
        for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
                value = bridge_init[i][1];
@@ -2242,8 +2243,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int avg_lum, is_jpeg;
-       static const u8 frame_header[] =
-               {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
+       static const u8 frame_header[] = {
+               0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96
+       };
 
        is_jpeg = (sd->fmt & 0x03) == 0;
        if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
diff --git a/drivers/media/usb/hackrf/Kconfig b/drivers/media/usb/hackrf/Kconfig
new file mode 100644 (file)
index 0000000..937e6f5
--- /dev/null
@@ -0,0 +1,10 @@
+config USB_HACKRF
+       tristate "HackRF"
+       depends on VIDEO_V4L2
+       select VIDEOBUF2_VMALLOC
+       ---help---
+         This is a video4linux2 driver for HackRF SDR device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called hackrf
+
diff --git a/drivers/media/usb/hackrf/Makefile b/drivers/media/usb/hackrf/Makefile
new file mode 100644 (file)
index 0000000..73064a2
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_USB_HACKRF)              += hackrf.o
diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
new file mode 100644 (file)
index 0000000..328b5ba
--- /dev/null
@@ -0,0 +1,1142 @@
+/*
+ * HackRF driver
+ *
+ * Copyright (C) 2014 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.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-vmalloc.h>
+
+/* HackRF USB API commands (from HackRF Library) */
+enum {
+       CMD_SET_TRANSCEIVER_MODE           = 0x01,
+       CMD_SAMPLE_RATE_SET                = 0x06,
+       CMD_BASEBAND_FILTER_BANDWIDTH_SET  = 0x07,
+       CMD_BOARD_ID_READ                  = 0x0e,
+       CMD_VERSION_STRING_READ            = 0x0f,
+       CMD_SET_FREQ                       = 0x10,
+       CMD_SET_LNA_GAIN                   = 0x13,
+       CMD_SET_VGA_GAIN                   = 0x14,
+};
+
+/*
+ *       bEndpointAddress     0x81  EP 1 IN
+ *         Transfer Type            Bulk
+ *       wMaxPacketSize     0x0200  1x 512 bytes
+ */
+#define MAX_BULK_BUFS            (6)
+#define BULK_BUFFER_SIZE         (128 * 512)
+
+static const struct v4l2_frequency_band bands_adc[] = {
+       {
+               .tuner = 0,
+               .type = V4L2_TUNER_ADC,
+               .index = 0,
+               .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   =   200000,
+               .rangehigh  = 24000000,
+       },
+};
+
+static const struct v4l2_frequency_band bands_rf[] = {
+       {
+               .tuner = 1,
+               .type = V4L2_TUNER_RF,
+               .index = 0,
+               .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   =          1,
+               .rangehigh  = 4294967294LL, /* max u32, hw goes over 7GHz */
+       },
+};
+
+/* stream formats */
+struct hackrf_format {
+       char    *name;
+       u32     pixelformat;
+       u32     buffersize;
+};
+
+/* format descriptions for capture and preview */
+static struct hackrf_format formats[] = {
+       {
+               .name           = "Complex S8",
+               .pixelformat    = V4L2_SDR_FMT_CS8,
+               .buffersize     = BULK_BUFFER_SIZE,
+       },
+};
+
+static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats);
+
+/* intermediate buffers with raw data from the USB device */
+struct hackrf_frame_buf {
+       struct vb2_buffer vb;   /* common v4l buffer stuff -- must be first */
+       struct list_head list;
+};
+
+struct hackrf_dev {
+#define POWER_ON           (1 << 1)
+#define URB_BUF            (1 << 2)
+#define USB_STATE_URB_BUF  (1 << 3)
+       unsigned long flags;
+
+       struct device *dev;
+       struct usb_device *udev;
+       struct video_device vdev;
+       struct v4l2_device v4l2_dev;
+
+       /* videobuf2 queue and queued buffers list */
+       struct vb2_queue vb_queue;
+       struct list_head queued_bufs;
+       spinlock_t queued_bufs_lock; /* Protects queued_bufs */
+       unsigned sequence;           /* Buffer sequence counter */
+       unsigned int vb_full;        /* vb is full and packets dropped */
+
+       /* Note if taking both locks v4l2_lock must always be locked first! */
+       struct mutex v4l2_lock;      /* Protects everything else */
+       struct mutex vb_queue_lock;  /* Protects vb_queue */
+
+       struct urb     *urb_list[MAX_BULK_BUFS];
+       int            buf_num;
+       unsigned long  buf_size;
+       u8             *buf_list[MAX_BULK_BUFS];
+       dma_addr_t     dma_addr[MAX_BULK_BUFS];
+       int            urbs_initialized;
+       int            urbs_submitted;
+
+       /* USB control message buffer */
+       #define BUF_SIZE 24
+       u8 buf[BUF_SIZE];
+
+       /* Current configuration */
+       unsigned int f_adc;
+       unsigned int f_rf;
+       u32 pixelformat;
+       u32 buffersize;
+
+       /* Controls */
+       struct v4l2_ctrl_handler hdl;
+       struct v4l2_ctrl *bandwidth_auto;
+       struct v4l2_ctrl *bandwidth;
+       struct v4l2_ctrl *lna_gain;
+       struct v4l2_ctrl *if_gain;
+
+       /* Sample rate calc */
+       unsigned long jiffies_next;
+       unsigned int sample;
+       unsigned int sample_measured;
+};
+
+#define hackrf_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \
+       char *_direction; \
+       if (_t & USB_DIR_IN) \
+               _direction = "<<<"; \
+       else \
+               _direction = ">>>"; \
+       dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \
+                       _t, _r, _v & 0xff, _v >> 8, _i & 0xff, \
+                       _i >> 8, _l & 0xff, _l >> 8, _direction, _l, _b); \
+}
+
+/* execute firmware command */
+static int hackrf_ctrl_msg(struct hackrf_dev *dev, u8 request, u16 value,
+               u16 index, u8 *data, u16 size)
+{
+       int ret;
+       unsigned int pipe;
+       u8 requesttype;
+
+       switch (request) {
+       case CMD_SET_TRANSCEIVER_MODE:
+       case CMD_SET_FREQ:
+       case CMD_SAMPLE_RATE_SET:
+       case CMD_BASEBAND_FILTER_BANDWIDTH_SET:
+               pipe = usb_sndctrlpipe(dev->udev, 0);
+               requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+               break;
+       case CMD_BOARD_ID_READ:
+       case CMD_VERSION_STRING_READ:
+       case CMD_SET_LNA_GAIN:
+       case CMD_SET_VGA_GAIN:
+               pipe = usb_rcvctrlpipe(dev->udev, 0);
+               requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+               break;
+       default:
+               dev_err(dev->dev, "Unknown command %02x\n", request);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* write request */
+       if (!(requesttype & USB_DIR_IN))
+               memcpy(dev->buf, data, size);
+
+       ret = usb_control_msg(dev->udev, pipe, request, requesttype, value,
+                       index, dev->buf, size, 1000);
+       hackrf_dbg_usb_control_msg(dev->dev, request, requesttype, value,
+                       index, dev->buf, size);
+       if (ret < 0) {
+               dev_err(dev->dev, "usb_control_msg() failed %d request %02x\n",
+                               ret, request);
+               goto err;
+       }
+
+       /* read request */
+       if (requesttype & USB_DIR_IN)
+               memcpy(data, dev->buf, size);
+
+       return 0;
+err:
+       return ret;
+}
+
+/* Private functions */
+static struct hackrf_frame_buf *hackrf_get_next_fill_buf(struct hackrf_dev *dev)
+{
+       unsigned long flags;
+       struct hackrf_frame_buf *buf = NULL;
+
+       spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+       if (list_empty(&dev->queued_bufs))
+               goto leave;
+
+       buf = list_entry(dev->queued_bufs.next, struct hackrf_frame_buf, list);
+       list_del(&buf->list);
+leave:
+       spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
+       return buf;
+}
+
+static unsigned int hackrf_convert_stream(struct hackrf_dev *dev,
+               void *dst, void *src, unsigned int src_len)
+{
+       memcpy(dst, src, src_len);
+
+       /* calculate sample rate and output it in 10 seconds intervals */
+       if (unlikely(time_is_before_jiffies(dev->jiffies_next))) {
+               #define MSECS 10000UL
+               unsigned int msecs = jiffies_to_msecs(jiffies -
+                               dev->jiffies_next + msecs_to_jiffies(MSECS));
+               unsigned int samples = dev->sample - dev->sample_measured;
+
+               dev->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
+               dev->sample_measured = dev->sample;
+               dev_dbg(dev->dev, "slen=%u samples=%u msecs=%u sample rate=%lu\n",
+                               src_len, samples, msecs,
+                               samples * 1000UL / msecs);
+       }
+
+       /* total number of samples */
+       dev->sample += src_len / 2;
+
+       return src_len;
+}
+
+/*
+ * This gets called for the bulk stream pipe. This is done in interrupt
+ * time, so it has to be fast, not crash, and not stall. Neat.
+ */
+static void hackrf_urb_complete(struct urb *urb)
+{
+       struct hackrf_dev *dev = urb->context;
+       struct hackrf_frame_buf *fbuf;
+
+       dev_dbg_ratelimited(dev->dev, "status=%d length=%d/%d errors=%d\n",
+                       urb->status, urb->actual_length,
+                       urb->transfer_buffer_length, urb->error_count);
+
+       switch (urb->status) {
+       case 0:             /* success */
+       case -ETIMEDOUT:    /* NAK */
+               break;
+       case -ECONNRESET:   /* kill */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       default:            /* error */
+               dev_err_ratelimited(dev->dev, "URB failed %d\n", urb->status);
+               break;
+       }
+
+       if (likely(urb->actual_length > 0)) {
+               void *ptr;
+               unsigned int len;
+               /* get free framebuffer */
+               fbuf = hackrf_get_next_fill_buf(dev);
+               if (unlikely(fbuf == NULL)) {
+                       dev->vb_full++;
+                       dev_notice_ratelimited(dev->dev,
+                                       "videobuf is full, %d packets dropped\n",
+                                       dev->vb_full);
+                       goto skip;
+               }
+
+               /* fill framebuffer */
+               ptr = vb2_plane_vaddr(&fbuf->vb, 0);
+               len = hackrf_convert_stream(dev, ptr, urb->transfer_buffer,
+                               urb->actual_length);
+               vb2_set_plane_payload(&fbuf->vb, 0, len);
+               v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp);
+               fbuf->vb.v4l2_buf.sequence = dev->sequence++;
+               vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
+       }
+skip:
+       usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int hackrf_kill_urbs(struct hackrf_dev *dev)
+{
+       int i;
+
+       for (i = dev->urbs_submitted - 1; i >= 0; i--) {
+               dev_dbg(dev->dev, "kill urb=%d\n", i);
+               /* stop the URB */
+               usb_kill_urb(dev->urb_list[i]);
+       }
+       dev->urbs_submitted = 0;
+
+       return 0;
+}
+
+static int hackrf_submit_urbs(struct hackrf_dev *dev)
+{
+       int i, ret;
+
+       for (i = 0; i < dev->urbs_initialized; i++) {
+               dev_dbg(dev->dev, "submit urb=%d\n", i);
+               ret = usb_submit_urb(dev->urb_list[i], GFP_ATOMIC);
+               if (ret) {
+                       dev_err(dev->dev, "Could not submit URB no. %d - get them all back\n",
+                                       i);
+                       hackrf_kill_urbs(dev);
+                       return ret;
+               }
+               dev->urbs_submitted++;
+       }
+
+       return 0;
+}
+
+static int hackrf_free_stream_bufs(struct hackrf_dev *dev)
+{
+       if (dev->flags & USB_STATE_URB_BUF) {
+               while (dev->buf_num) {
+                       dev->buf_num--;
+                       dev_dbg(dev->dev, "free buf=%d\n", dev->buf_num);
+                       usb_free_coherent(dev->udev, dev->buf_size,
+                                         dev->buf_list[dev->buf_num],
+                                         dev->dma_addr[dev->buf_num]);
+               }
+       }
+       dev->flags &= ~USB_STATE_URB_BUF;
+
+       return 0;
+}
+
+static int hackrf_alloc_stream_bufs(struct hackrf_dev *dev)
+{
+       dev->buf_num = 0;
+       dev->buf_size = BULK_BUFFER_SIZE;
+
+       dev_dbg(dev->dev, "all in all I will use %u bytes for streaming\n",
+                       MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+
+       for (dev->buf_num = 0; dev->buf_num < MAX_BULK_BUFS; dev->buf_num++) {
+               dev->buf_list[dev->buf_num] = usb_alloc_coherent(dev->udev,
+                               BULK_BUFFER_SIZE, GFP_ATOMIC,
+                               &dev->dma_addr[dev->buf_num]);
+               if (!dev->buf_list[dev->buf_num]) {
+                       dev_dbg(dev->dev, "alloc buf=%d failed\n",
+                                       dev->buf_num);
+                       hackrf_free_stream_bufs(dev);
+                       return -ENOMEM;
+               }
+
+               dev_dbg(dev->dev, "alloc buf=%d %p (dma %llu)\n", dev->buf_num,
+                               dev->buf_list[dev->buf_num],
+                               (long long)dev->dma_addr[dev->buf_num]);
+               dev->flags |= USB_STATE_URB_BUF;
+       }
+
+       return 0;
+}
+
+static int hackrf_free_urbs(struct hackrf_dev *dev)
+{
+       int i;
+
+       hackrf_kill_urbs(dev);
+
+       for (i = dev->urbs_initialized - 1; i >= 0; i--) {
+               if (dev->urb_list[i]) {
+                       dev_dbg(dev->dev, "free urb=%d\n", i);
+                       /* free the URBs */
+                       usb_free_urb(dev->urb_list[i]);
+               }
+       }
+       dev->urbs_initialized = 0;
+
+       return 0;
+}
+
+static int hackrf_alloc_urbs(struct hackrf_dev *dev)
+{
+       int i, j;
+
+       /* allocate the URBs */
+       for (i = 0; i < MAX_BULK_BUFS; i++) {
+               dev_dbg(dev->dev, "alloc urb=%d\n", i);
+               dev->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
+               if (!dev->urb_list[i]) {
+                       dev_dbg(dev->dev, "failed\n");
+                       for (j = 0; j < i; j++)
+                               usb_free_urb(dev->urb_list[j]);
+                       return -ENOMEM;
+               }
+               usb_fill_bulk_urb(dev->urb_list[i],
+                               dev->udev,
+                               usb_rcvbulkpipe(dev->udev, 0x81),
+                               dev->buf_list[i],
+                               BULK_BUFFER_SIZE,
+                               hackrf_urb_complete, dev);
+
+               dev->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+               dev->urb_list[i]->transfer_dma = dev->dma_addr[i];
+               dev->urbs_initialized++;
+       }
+
+       return 0;
+}
+
+/* Must be called with vb_queue_lock hold */
+static void hackrf_cleanup_queued_bufs(struct hackrf_dev *dev)
+{
+       unsigned long flags;
+
+       dev_dbg(dev->dev, "\n");
+
+       spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+       while (!list_empty(&dev->queued_bufs)) {
+               struct hackrf_frame_buf *buf;
+
+               buf = list_entry(dev->queued_bufs.next,
+                               struct hackrf_frame_buf, list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+       spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
+}
+
+/* The user yanked out the cable... */
+static void hackrf_disconnect(struct usb_interface *intf)
+{
+       struct v4l2_device *v = usb_get_intfdata(intf);
+       struct hackrf_dev *dev = container_of(v, struct hackrf_dev, v4l2_dev);
+
+       dev_dbg(dev->dev, "\n");
+
+       mutex_lock(&dev->vb_queue_lock);
+       mutex_lock(&dev->v4l2_lock);
+       /* No need to keep the urbs around after disconnection */
+       dev->udev = NULL;
+       v4l2_device_disconnect(&dev->v4l2_dev);
+       video_unregister_device(&dev->vdev);
+       mutex_unlock(&dev->v4l2_lock);
+       mutex_unlock(&dev->vb_queue_lock);
+
+       v4l2_device_put(&dev->v4l2_dev);
+}
+
+/* Videobuf2 operations */
+static int hackrf_queue_setup(struct vb2_queue *vq,
+               const struct v4l2_format *fmt, unsigned int *nbuffers,
+               unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+
+       dev_dbg(dev->dev, "nbuffers=%d\n", *nbuffers);
+
+       /* Need at least 8 buffers */
+       if (vq->num_buffers + *nbuffers < 8)
+               *nbuffers = 8 - vq->num_buffers;
+       *nplanes = 1;
+       sizes[0] = PAGE_ALIGN(dev->buffersize);
+
+       dev_dbg(dev->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
+       return 0;
+}
+
+static void hackrf_buf_queue(struct vb2_buffer *vb)
+{
+       struct hackrf_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct hackrf_frame_buf *buf =
+                       container_of(vb, struct hackrf_frame_buf, vb);
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+       list_add_tail(&buf->list, &dev->queued_bufs);
+       spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
+}
+
+static int hackrf_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+       int ret;
+
+       dev_dbg(dev->dev, "\n");
+
+       if (!dev->udev)
+               return -ENODEV;
+
+       mutex_lock(&dev->v4l2_lock);
+
+       dev->sequence = 0;
+
+       set_bit(POWER_ON, &dev->flags);
+
+       ret = hackrf_alloc_stream_bufs(dev);
+       if (ret)
+               goto err;
+
+       ret = hackrf_alloc_urbs(dev);
+       if (ret)
+               goto err;
+
+       ret = hackrf_submit_urbs(dev);
+       if (ret)
+               goto err;
+
+       /* start hardware streaming */
+       ret = hackrf_ctrl_msg(dev, CMD_SET_TRANSCEIVER_MODE, 1, 0, NULL, 0);
+       if (ret)
+               goto err;
+
+       goto exit_mutex_unlock;
+err:
+       hackrf_kill_urbs(dev);
+       hackrf_free_urbs(dev);
+       hackrf_free_stream_bufs(dev);
+       clear_bit(POWER_ON, &dev->flags);
+
+       /* return all queued buffers to vb2 */
+       {
+               struct hackrf_frame_buf *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &dev->queued_bufs, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+
+exit_mutex_unlock:
+       mutex_unlock(&dev->v4l2_lock);
+
+       return ret;
+}
+
+static void hackrf_stop_streaming(struct vb2_queue *vq)
+{
+       struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+
+       dev_dbg(dev->dev, "\n");
+
+       mutex_lock(&dev->v4l2_lock);
+
+       /* stop hardware streaming */
+       hackrf_ctrl_msg(dev, CMD_SET_TRANSCEIVER_MODE, 0, 0, NULL, 0);
+
+       hackrf_kill_urbs(dev);
+       hackrf_free_urbs(dev);
+       hackrf_free_stream_bufs(dev);
+
+       hackrf_cleanup_queued_bufs(dev);
+
+       clear_bit(POWER_ON, &dev->flags);
+
+       mutex_unlock(&dev->v4l2_lock);
+}
+
+static struct vb2_ops hackrf_vb2_ops = {
+       .queue_setup            = hackrf_queue_setup,
+       .buf_queue              = hackrf_buf_queue,
+       .start_streaming        = hackrf_start_streaming,
+       .stop_streaming         = hackrf_stop_streaming,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+};
+
+static int hackrf_querycap(struct file *file, void *fh,
+               struct v4l2_capability *cap)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+
+       dev_dbg(dev->dev, "\n");
+
+       strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+       strlcpy(cap->card, dev->vdev.name, sizeof(cap->card));
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+       cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
+                       V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+       return 0;
+}
+
+static int hackrf_s_fmt_sdr_cap(struct file *file, void *priv,
+               struct v4l2_format *f)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       struct vb2_queue *q = &dev->vb_queue;
+       int i;
+
+       dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
+                       (char *)&f->fmt.sdr.pixelformat);
+
+       if (vb2_is_busy(q))
+               return -EBUSY;
+
+       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+       for (i = 0; i < NUM_FORMATS; i++) {
+               if (f->fmt.sdr.pixelformat == formats[i].pixelformat) {
+                       dev->pixelformat = formats[i].pixelformat;
+                       dev->buffersize = formats[i].buffersize;
+                       f->fmt.sdr.buffersize = formats[i].buffersize;
+                       return 0;
+               }
+       }
+
+       dev->pixelformat = formats[0].pixelformat;
+       dev->buffersize = formats[0].buffersize;
+       f->fmt.sdr.pixelformat = formats[0].pixelformat;
+       f->fmt.sdr.buffersize = formats[0].buffersize;
+
+       return 0;
+}
+
+static int hackrf_g_fmt_sdr_cap(struct file *file, void *priv,
+               struct v4l2_format *f)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+
+       dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
+                       (char *)&dev->pixelformat);
+
+       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+       f->fmt.sdr.pixelformat = dev->pixelformat;
+       f->fmt.sdr.buffersize = dev->buffersize;
+
+       return 0;
+}
+
+static int hackrf_try_fmt_sdr_cap(struct file *file, void *priv,
+               struct v4l2_format *f)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       int i;
+
+       dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
+                       (char *)&f->fmt.sdr.pixelformat);
+
+       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+       for (i = 0; i < NUM_FORMATS; i++) {
+               if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
+                       f->fmt.sdr.buffersize = formats[i].buffersize;
+                       return 0;
+               }
+       }
+
+       f->fmt.sdr.pixelformat = formats[0].pixelformat;
+       f->fmt.sdr.buffersize = formats[0].buffersize;
+
+       return 0;
+}
+
+static int hackrf_enum_fmt_sdr_cap(struct file *file, void *priv,
+               struct v4l2_fmtdesc *f)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+
+       dev_dbg(dev->dev, "index=%d\n", f->index);
+
+       if (f->index >= NUM_FORMATS)
+               return -EINVAL;
+
+       strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+       f->pixelformat = formats[f->index].pixelformat;
+
+       return 0;
+}
+
+static int hackrf_s_tuner(struct file *file, void *priv,
+               const struct v4l2_tuner *v)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       int ret;
+
+       dev_dbg(dev->dev, "index=%d\n", v->index);
+
+       if (v->index == 0)
+               ret = 0;
+       else if (v->index == 1)
+               ret = 0;
+       else
+               ret = -EINVAL;
+
+       return ret;
+}
+
+static int hackrf_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       int ret;
+
+       dev_dbg(dev->dev, "index=%d\n", v->index);
+
+       if (v->index == 0) {
+               strlcpy(v->name, "HackRF ADC", sizeof(v->name));
+               v->type = V4L2_TUNER_ADC;
+               v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+               v->rangelow  = bands_adc[0].rangelow;
+               v->rangehigh = bands_adc[0].rangehigh;
+               ret = 0;
+       } else if (v->index == 1) {
+               strlcpy(v->name, "HackRF RF", sizeof(v->name));
+               v->type = V4L2_TUNER_RF;
+               v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+               v->rangelow  = bands_rf[0].rangelow;
+               v->rangehigh = bands_rf[0].rangehigh;
+               ret = 0;
+       } else {
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int hackrf_s_frequency(struct file *file, void *priv,
+               const struct v4l2_frequency *f)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       int ret;
+       unsigned int upper, lower;
+       u8 buf[8];
+
+       dev_dbg(dev->dev, "tuner=%d type=%d frequency=%u\n",
+                       f->tuner, f->type, f->frequency);
+
+       if (f->tuner == 0) {
+               dev->f_adc = clamp_t(unsigned int, f->frequency,
+                               bands_adc[0].rangelow, bands_adc[0].rangehigh);
+               dev_dbg(dev->dev, "ADC frequency=%u Hz\n", dev->f_adc);
+               upper = dev->f_adc;
+               lower = 1;
+               buf[0] = (upper >>  0) & 0xff;
+               buf[1] = (upper >>  8) & 0xff;
+               buf[2] = (upper >> 16) & 0xff;
+               buf[3] = (upper >> 24) & 0xff;
+               buf[4] = (lower >>  0) & 0xff;
+               buf[5] = (lower >>  8) & 0xff;
+               buf[6] = (lower >> 16) & 0xff;
+               buf[7] = (lower >> 24) & 0xff;
+               ret = hackrf_ctrl_msg(dev, CMD_SAMPLE_RATE_SET, 0, 0, buf, 8);
+       } else if (f->tuner == 1) {
+               dev->f_rf = clamp_t(unsigned int, f->frequency,
+                               bands_rf[0].rangelow, bands_rf[0].rangehigh);
+               dev_dbg(dev->dev, "RF frequency=%u Hz\n", dev->f_rf);
+               upper = dev->f_rf / 1000000;
+               lower = dev->f_rf % 1000000;
+               buf[0] = (upper >>  0) & 0xff;
+               buf[1] = (upper >>  8) & 0xff;
+               buf[2] = (upper >> 16) & 0xff;
+               buf[3] = (upper >> 24) & 0xff;
+               buf[4] = (lower >>  0) & 0xff;
+               buf[5] = (lower >>  8) & 0xff;
+               buf[6] = (lower >> 16) & 0xff;
+               buf[7] = (lower >> 24) & 0xff;
+               ret = hackrf_ctrl_msg(dev, CMD_SET_FREQ, 0, 0, buf, 8);
+       } else {
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int hackrf_g_frequency(struct file *file, void *priv,
+               struct v4l2_frequency *f)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       int ret;
+
+       dev_dbg(dev->dev, "tuner=%d type=%d\n", f->tuner, f->type);
+
+       if (f->tuner == 0) {
+               f->type = V4L2_TUNER_ADC;
+               f->frequency = dev->f_adc;
+               ret = 0;
+       } else if (f->tuner == 1) {
+               f->type = V4L2_TUNER_RF;
+               f->frequency = dev->f_rf;
+               ret = 0;
+       } else {
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int hackrf_enum_freq_bands(struct file *file, void *priv,
+               struct v4l2_frequency_band *band)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       int ret;
+
+       dev_dbg(dev->dev, "tuner=%d type=%d index=%d\n",
+                       band->tuner, band->type, band->index);
+
+       if (band->tuner == 0) {
+               if (band->index >= ARRAY_SIZE(bands_adc)) {
+                       ret = -EINVAL;
+               } else {
+                       *band = bands_adc[band->index];
+                       ret = 0;
+               }
+       } else if (band->tuner == 1) {
+               if (band->index >= ARRAY_SIZE(bands_rf)) {
+                       ret = -EINVAL;
+               } else {
+                       *band = bands_rf[band->index];
+                       ret = 0;
+               }
+       } else {
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_ioctl_ops hackrf_ioctl_ops = {
+       .vidioc_querycap          = hackrf_querycap,
+
+       .vidioc_s_fmt_sdr_cap     = hackrf_s_fmt_sdr_cap,
+       .vidioc_g_fmt_sdr_cap     = hackrf_g_fmt_sdr_cap,
+       .vidioc_enum_fmt_sdr_cap  = hackrf_enum_fmt_sdr_cap,
+       .vidioc_try_fmt_sdr_cap   = hackrf_try_fmt_sdr_cap,
+
+       .vidioc_reqbufs           = vb2_ioctl_reqbufs,
+       .vidioc_create_bufs       = vb2_ioctl_create_bufs,
+       .vidioc_prepare_buf       = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf          = vb2_ioctl_querybuf,
+       .vidioc_qbuf              = vb2_ioctl_qbuf,
+       .vidioc_dqbuf             = vb2_ioctl_dqbuf,
+
+       .vidioc_streamon          = vb2_ioctl_streamon,
+       .vidioc_streamoff         = vb2_ioctl_streamoff,
+
+       .vidioc_s_tuner           = hackrf_s_tuner,
+       .vidioc_g_tuner           = hackrf_g_tuner,
+
+       .vidioc_s_frequency       = hackrf_s_frequency,
+       .vidioc_g_frequency       = hackrf_g_frequency,
+       .vidioc_enum_freq_bands   = hackrf_enum_freq_bands,
+
+       .vidioc_subscribe_event   = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+       .vidioc_log_status        = v4l2_ctrl_log_status,
+};
+
+static const struct v4l2_file_operations hackrf_fops = {
+       .owner                    = THIS_MODULE,
+       .open                     = v4l2_fh_open,
+       .release                  = vb2_fop_release,
+       .read                     = vb2_fop_read,
+       .poll                     = vb2_fop_poll,
+       .mmap                     = vb2_fop_mmap,
+       .unlocked_ioctl           = video_ioctl2,
+};
+
+static struct video_device hackrf_template = {
+       .name                     = "HackRF One",
+       .release                  = video_device_release_empty,
+       .fops                     = &hackrf_fops,
+       .ioctl_ops                = &hackrf_ioctl_ops,
+};
+
+static void hackrf_video_release(struct v4l2_device *v)
+{
+       struct hackrf_dev *dev = container_of(v, struct hackrf_dev, v4l2_dev);
+
+       v4l2_ctrl_handler_free(&dev->hdl);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       kfree(dev);
+}
+
+static int hackrf_set_bandwidth(struct hackrf_dev *dev)
+{
+       int ret, i;
+       u16 u16tmp, u16tmp2;
+       unsigned int bandwidth;
+
+       static const struct {
+               u32 freq;
+       } bandwidth_lut[] = {
+               { 1750000}, /*  1.75 MHz */
+               { 2500000}, /*  2.5  MHz */
+               { 3500000}, /*  3.5  MHz */
+               { 5000000}, /*  5    MHz */
+               { 5500000}, /*  5.5  MHz */
+               { 6000000}, /*  6    MHz */
+               { 7000000}, /*  7    MHz */
+               { 8000000}, /*  8    MHz */
+               { 9000000}, /*  9    MHz */
+               {10000000}, /* 10    MHz */
+               {12000000}, /* 12    MHz */
+               {14000000}, /* 14    MHz */
+               {15000000}, /* 15    MHz */
+               {20000000}, /* 20    MHz */
+               {24000000}, /* 24    MHz */
+               {28000000}, /* 28    MHz */
+       };
+
+       dev_dbg(dev->dev, "bandwidth auto=%d->%d val=%d->%d f_adc=%u\n",
+                       dev->bandwidth_auto->cur.val,
+                       dev->bandwidth_auto->val, dev->bandwidth->cur.val,
+                       dev->bandwidth->val, dev->f_adc);
+
+       if (dev->bandwidth_auto->val == true)
+               bandwidth = dev->f_adc;
+       else
+               bandwidth = dev->bandwidth->val;
+
+       for (i = 0; i < ARRAY_SIZE(bandwidth_lut); i++) {
+               if (bandwidth <= bandwidth_lut[i].freq) {
+                       bandwidth = bandwidth_lut[i].freq;
+                       break;
+               }
+       }
+
+       dev->bandwidth->val = bandwidth;
+       dev->bandwidth->cur.val = bandwidth;
+
+       dev_dbg(dev->dev, "bandwidth selected=%d\n", bandwidth_lut[i].freq);
+
+       u16tmp = 0;
+       u16tmp |= ((bandwidth >> 0) & 0xff) << 0;
+       u16tmp |= ((bandwidth >> 8) & 0xff) << 8;
+       u16tmp2 = 0;
+       u16tmp2 |= ((bandwidth >> 16) & 0xff) << 0;
+       u16tmp2 |= ((bandwidth >> 24) & 0xff) << 8;
+
+       ret = hackrf_ctrl_msg(dev, CMD_BASEBAND_FILTER_BANDWIDTH_SET,
+                               u16tmp, u16tmp2, NULL, 0);
+       if (ret)
+               dev_dbg(dev->dev, "failed=%d\n", ret);
+
+       return ret;
+}
+
+static int hackrf_set_lna_gain(struct hackrf_dev *dev)
+{
+       int ret;
+       u8 u8tmp;
+
+       dev_dbg(dev->dev, "lna val=%d->%d\n",
+                       dev->lna_gain->cur.val, dev->lna_gain->val);
+
+       ret = hackrf_ctrl_msg(dev, CMD_SET_LNA_GAIN, 0, dev->lna_gain->val,
+                       &u8tmp, 1);
+       if (ret)
+               dev_dbg(dev->dev, "failed=%d\n", ret);
+
+       return ret;
+}
+
+static int hackrf_set_if_gain(struct hackrf_dev *dev)
+{
+       int ret;
+       u8 u8tmp;
+
+       dev_dbg(dev->dev, "val=%d->%d\n",
+                       dev->if_gain->cur.val, dev->if_gain->val);
+
+       ret = hackrf_ctrl_msg(dev, CMD_SET_VGA_GAIN, 0, dev->if_gain->val,
+                       &u8tmp, 1);
+       if (ret)
+               dev_dbg(dev->dev, "failed=%d\n", ret);
+
+       return ret;
+}
+
+static int hackrf_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct hackrf_dev *dev = container_of(ctrl->handler,
+                       struct hackrf_dev, hdl);
+       int ret;
+
+       switch (ctrl->id) {
+       case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
+       case V4L2_CID_RF_TUNER_BANDWIDTH:
+               ret = hackrf_set_bandwidth(dev);
+               break;
+       case  V4L2_CID_RF_TUNER_LNA_GAIN:
+               ret = hackrf_set_lna_gain(dev);
+               break;
+       case  V4L2_CID_RF_TUNER_IF_GAIN:
+               ret = hackrf_set_if_gain(dev);
+               break;
+       default:
+               dev_dbg(dev->dev, "unknown ctrl: id=%d name=%s\n",
+                               ctrl->id, ctrl->name);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops hackrf_ctrl_ops = {
+       .s_ctrl = hackrf_s_ctrl,
+};
+
+static int hackrf_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       struct hackrf_dev *dev;
+       int ret;
+       u8 u8tmp, buf[BUF_SIZE];
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL)
+               return -ENOMEM;
+
+       mutex_init(&dev->v4l2_lock);
+       mutex_init(&dev->vb_queue_lock);
+       spin_lock_init(&dev->queued_bufs_lock);
+       INIT_LIST_HEAD(&dev->queued_bufs);
+       dev->dev = &intf->dev;
+       dev->udev = interface_to_usbdev(intf);
+       dev->f_adc = bands_adc[0].rangelow;
+       dev->f_rf = bands_rf[0].rangelow;
+       dev->pixelformat = formats[0].pixelformat;
+       dev->buffersize = formats[0].buffersize;
+
+       /* Detect device */
+       ret = hackrf_ctrl_msg(dev, CMD_BOARD_ID_READ, 0, 0, &u8tmp, 1);
+       if (ret == 0)
+               ret = hackrf_ctrl_msg(dev, CMD_VERSION_STRING_READ, 0, 0,
+                               buf, BUF_SIZE);
+       if (ret) {
+               dev_err(dev->dev, "Could not detect board\n");
+               goto err_free_mem;
+       }
+
+       buf[BUF_SIZE - 1] = '\0';
+
+       dev_info(dev->dev, "Board ID: %02x\n", u8tmp);
+       dev_info(dev->dev, "Firmware version: %s\n", buf);
+
+       /* Init videobuf2 queue structure */
+       dev->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
+       dev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+       dev->vb_queue.drv_priv = dev;
+       dev->vb_queue.buf_struct_size = sizeof(struct hackrf_frame_buf);
+       dev->vb_queue.ops = &hackrf_vb2_ops;
+       dev->vb_queue.mem_ops = &vb2_vmalloc_memops;
+       dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       ret = vb2_queue_init(&dev->vb_queue);
+       if (ret) {
+               dev_err(dev->dev, "Could not initialize vb2 queue\n");
+               goto err_free_mem;
+       }
+
+       /* Init video_device structure */
+       dev->vdev = hackrf_template;
+       dev->vdev.queue = &dev->vb_queue;
+       dev->vdev.queue->lock = &dev->vb_queue_lock;
+       video_set_drvdata(&dev->vdev, dev);
+
+       /* Register the v4l2_device structure */
+       dev->v4l2_dev.release = hackrf_video_release;
+       ret = v4l2_device_register(&intf->dev, &dev->v4l2_dev);
+       if (ret) {
+               dev_err(dev->dev, "Failed to register v4l2-device (%d)\n", ret);
+               goto err_free_mem;
+       }
+
+       /* Register controls */
+       v4l2_ctrl_handler_init(&dev->hdl, 4);
+       dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+                       V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
+       dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+                       V4L2_CID_RF_TUNER_BANDWIDTH,
+                       1750000, 28000000, 50000, 1750000);
+       v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
+       dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+                       V4L2_CID_RF_TUNER_LNA_GAIN, 0, 40, 8, 0);
+       dev->if_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+                       V4L2_CID_RF_TUNER_IF_GAIN, 0, 62, 2, 0);
+       if (dev->hdl.error) {
+               ret = dev->hdl.error;
+               dev_err(dev->dev, "Could not initialize controls\n");
+               goto err_free_controls;
+       }
+
+       v4l2_ctrl_handler_setup(&dev->hdl);
+
+       dev->v4l2_dev.ctrl_handler = &dev->hdl;
+       dev->vdev.v4l2_dev = &dev->v4l2_dev;
+       dev->vdev.lock = &dev->v4l2_lock;
+
+       ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1);
+       if (ret) {
+               dev_err(dev->dev, "Failed to register as video device (%d)\n",
+                               ret);
+               goto err_unregister_v4l2_dev;
+       }
+       dev_info(dev->dev, "Registered as %s\n",
+                       video_device_node_name(&dev->vdev));
+       dev_notice(dev->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
+       return 0;
+
+err_free_controls:
+       v4l2_ctrl_handler_free(&dev->hdl);
+err_unregister_v4l2_dev:
+       v4l2_device_unregister(&dev->v4l2_dev);
+err_free_mem:
+       kfree(dev);
+       return ret;
+}
+
+/* USB device ID list */
+static struct usb_device_id hackrf_id_table[] = {
+       { USB_DEVICE(0x1d50, 0x6089) }, /* HackRF One */
+       { }
+};
+MODULE_DEVICE_TABLE(usb, hackrf_id_table);
+
+/* USB subsystem interface */
+static struct usb_driver hackrf_driver = {
+       .name                     = KBUILD_MODNAME,
+       .probe                    = hackrf_probe,
+       .disconnect               = hackrf_disconnect,
+       .id_table                 = hackrf_id_table,
+};
+
+module_usb_driver(hackrf_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("HackRF");
+MODULE_LICENSE("GPL");
index 6053661dc04bd39727021c311f7d80f1d37ca60a..6e86032ea5dba481e41fa1713852ce05cb120f67 100644 (file)
@@ -59,13 +59,10 @@ int get_video_info(struct hdpvr_device *dev, struct hdpvr_video_info *vidinf)
                              1000);
 
 #ifdef HDPVR_DEBUG
-       if (hdpvr_debug & MSG_INFO) {
-               char print_buf[15];
-               hex_dump_to_buffer(dev->usbc_buf, 5, 16, 1, print_buf,
-                                  sizeof(print_buf), 0);
+       if (hdpvr_debug & MSG_INFO)
                v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
-                        "get video info returned: %d, %s\n", ret, print_buf);
-       }
+                        "get video info returned: %d, %5ph\n", ret,
+                        dev->usbc_buf);
 #endif
        mutex_unlock(&dev->usbc_mutex);
 
@@ -82,9 +79,6 @@ int get_video_info(struct hdpvr_device *dev, struct hdpvr_video_info *vidinf)
 
 int get_input_lines_info(struct hdpvr_device *dev)
 {
-#ifdef HDPVR_DEBUG
-       char print_buf[9];
-#endif
        int ret, lines;
 
        mutex_lock(&dev->usbc_mutex);
@@ -96,13 +90,10 @@ int get_input_lines_info(struct hdpvr_device *dev)
                              1000);
 
 #ifdef HDPVR_DEBUG
-       if (hdpvr_debug & MSG_INFO) {
-               hex_dump_to_buffer(dev->usbc_buf, 3, 16, 1, print_buf,
-                                  sizeof(print_buf), 0);
+       if (hdpvr_debug & MSG_INFO)
                v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
-                        "get input lines info returned: %d, %s\n", ret,
-                        print_buf);
-       }
+                        "get input lines info returned: %d, %3ph\n", ret,
+                        dev->usbc_buf);
 #else
        (void)ret;      /* suppress compiler warning */
 #endif
index c5638964c3f286665e0cd57ae1e713be0506e881..42b4cdf28cfd9d24e89e38a7ca3eb84a0354b57e 100644 (file)
@@ -124,14 +124,6 @@ static int device_authorization(struct hdpvr_device *dev)
        int ret, retval = -ENOMEM;
        char request_type = 0x38, rcv_request = 0x81;
        char *response;
-#ifdef HDPVR_DEBUG
-       size_t buf_size = 46;
-       char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL);
-       if (!print_buf) {
-               v4l2_err(&dev->v4l2_dev, "Out of memory\n");
-               return retval;
-       }
-#endif
 
        mutex_lock(&dev->usbc_mutex);
        ret = usb_control_msg(dev->udev,
@@ -147,11 +139,9 @@ static int device_authorization(struct hdpvr_device *dev)
        }
 #ifdef HDPVR_DEBUG
        else {
-               hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf,
-                                  5*buf_size+1, 0);
                v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
-                        "Status request returned, len %d: %s\n",
-                        ret, print_buf);
+                        "Status request returned, len %d: %46ph\n",
+                        ret, dev->usbc_buf);
        }
 #endif
 
@@ -189,15 +179,13 @@ static int device_authorization(struct hdpvr_device *dev)
 
        response = dev->usbc_buf+38;
 #ifdef HDPVR_DEBUG
-       hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0);
-       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n",
-                print_buf);
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %8ph\n",
+                response);
 #endif
        challenge(response);
 #ifdef HDPVR_DEBUG
-       hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0);
-       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n",
-                print_buf);
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %8ph\n",
+                response);
 #endif
 
        msleep(100);
@@ -213,9 +201,6 @@ static int device_authorization(struct hdpvr_device *dev)
        retval = ret != 8;
 unlock:
        mutex_unlock(&dev->usbc_mutex);
-#ifdef HDPVR_DEBUG
-       kfree(print_buf);
-#endif
        return retval;
 }
 
index 26b133414032bcaf3f6b48a4da78f1809f9d4872..efc761c78f7250e5b27a93b0fcb18bbc3fb142a5 100644 (file)
@@ -120,6 +120,7 @@ struct msi2500_frame_buf {
 };
 
 struct msi2500_state {
+       struct device *dev;
        struct video_device vdev;
        struct v4l2_device v4l2_dev;
        struct v4l2_subdev *v4l2_subdev;
@@ -153,14 +154,13 @@ struct msi2500_state {
        u32 next_sample; /* for track lost packets */
        u32 sample; /* for sample rate calc */
        unsigned long jiffies_next;
-       unsigned int sample_ctrl_bit[4];
 };
 
 /* Private functions */
 static struct msi2500_frame_buf *msi2500_get_next_fill_buf(
                struct msi2500_state *s)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
        struct msi2500_frame_buf *buf = NULL;
 
        spin_lock_irqsave(&s->queued_bufs_lock, flags);
@@ -269,7 +269,7 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src,
                sample[i] = src[3] << 24 | src[2] << 16 | src[1] << 8 |
                                src[0] << 0;
                if (i == 0 && s->next_sample != sample[0]) {
-                       dev_dbg_ratelimited(&s->udev->dev,
+                       dev_dbg_ratelimited(s->dev,
                                        "%d samples lost, %d %08x:%08x\n",
                                        sample[0] - s->next_sample,
                                        src_len, s->next_sample, sample[0]);
@@ -279,7 +279,7 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src,
                 * Dump all unknown 'garbage' data - maybe we will discover
                 * someday if there is something rational...
                 */
-               dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]);
+               dev_dbg_ratelimited(s->dev, "%*ph\n", 12, &src[4]);
 
                src += 16; /* skip header */
 
@@ -322,8 +322,7 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src,
                }
                case MSI2500_PIX_FMT_SDR_MSI2500_384: /* 384 x IQ samples */
                        /* Dump unknown 'garbage' data */
-                       dev_dbg_ratelimited(&s->udev->dev,
-                                       "%*ph\n", 24, &src[1000]);
+                       dev_dbg_ratelimited(s->dev, "%*ph\n", 24, &src[1000]);
                        memcpy(dst, src, 984);
                        src += 984 + 24;
                        dst += 984;
@@ -365,8 +364,7 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src,
 
                s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
                s->sample = s->next_sample;
-               dev_dbg(&s->udev->dev,
-                               "size=%u samples=%u msecs=%u sample rate=%lu\n",
+               dev_dbg(s->dev, "size=%u samples=%u msecs=%u sample rate=%lu\n",
                                src_len, samples, msecs,
                                samples * 1000UL / msecs);
        }
@@ -387,19 +385,16 @@ static void msi2500_isoc_handler(struct urb *urb)
 
        if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET ||
                        urb->status == -ESHUTDOWN)) {
-               dev_dbg(&s->udev->dev, "URB (%p) unlinked %ssynchronuously\n",
+               dev_dbg(s->dev, "URB (%p) unlinked %ssynchronuously\n",
                                urb, urb->status == -ENOENT ? "" : "a");
                return;
        }
 
        if (unlikely(urb->status != 0)) {
-               dev_dbg(&s->udev->dev,
-                               "msi2500_isoc_handler() called with status %d\n",
-                               urb->status);
+               dev_dbg(s->dev, "called with status %d\n", urb->status);
                /* Give up after a number of contiguous errors */
                if (++s->isoc_errors > MAX_ISOC_ERRORS)
-                       dev_dbg(&s->udev->dev,
-                                       "Too many ISOC errors, bailing out\n");
+                       dev_dbg(s->dev, "Too many ISOC errors, bailing out\n");
                goto handler_end;
        } else {
                /* Reset ISOC error counter. We did get here, after all. */
@@ -413,7 +408,7 @@ static void msi2500_isoc_handler(struct urb *urb)
                /* Check frame error */
                fstatus = urb->iso_frame_desc[i].status;
                if (unlikely(fstatus)) {
-                       dev_dbg_ratelimited(&s->udev->dev,
+                       dev_dbg_ratelimited(s->dev,
                                        "frame=%d/%d has error %d skipping\n",
                                        i, urb->number_of_packets, fstatus);
                        continue;
@@ -430,7 +425,7 @@ static void msi2500_isoc_handler(struct urb *urb)
                fbuf = msi2500_get_next_fill_buf(s);
                if (unlikely(fbuf == NULL)) {
                        s->vb_full++;
-                       dev_dbg_ratelimited(&s->udev->dev,
+                       dev_dbg_ratelimited(s->dev,
                                        "videobuf is full, %d packets dropped\n",
                                        s->vb_full);
                        continue;
@@ -446,22 +441,19 @@ static void msi2500_isoc_handler(struct urb *urb)
 handler_end:
        i = usb_submit_urb(urb, GFP_ATOMIC);
        if (unlikely(i != 0))
-               dev_dbg(&s->udev->dev,
-                               "Error (%d) re-submitting urb in msi2500_isoc_handler\n",
-                               i);
+               dev_dbg(s->dev, "Error (%d) re-submitting urb\n", i);
 }
 
 static void msi2500_iso_stop(struct msi2500_state *s)
 {
        int i;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        /* Unlinking ISOC buffers one by one */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                if (s->urbs[i]) {
-                       dev_dbg(&s->udev->dev, "Unlinking URB %p\n",
-                                       s->urbs[i]);
+                       dev_dbg(s->dev, "Unlinking URB %p\n", s->urbs[i]);
                        usb_kill_urb(s->urbs[i]);
                }
        }
@@ -471,12 +463,12 @@ static void msi2500_iso_free(struct msi2500_state *s)
 {
        int i;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        /* Freeing ISOC buffers one by one */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                if (s->urbs[i]) {
-                       dev_dbg(&s->udev->dev, "Freeing URB\n");
+                       dev_dbg(s->dev, "Freeing URB\n");
                        if (s->urbs[i]->transfer_buffer) {
                                usb_free_coherent(s->udev,
                                        s->urbs[i]->transfer_buffer_length,
@@ -492,7 +484,7 @@ static void msi2500_iso_free(struct msi2500_state *s)
 /* Both v4l2_lock and vb_queue_lock should be locked when calling this */
 static void msi2500_isoc_cleanup(struct msi2500_state *s)
 {
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        msi2500_iso_stop(s);
        msi2500_iso_free(s);
@@ -501,14 +493,12 @@ static void msi2500_isoc_cleanup(struct msi2500_state *s)
 /* Both v4l2_lock and vb_queue_lock should be locked when calling this */
 static int msi2500_isoc_init(struct msi2500_state *s)
 {
-       struct usb_device *udev;
        struct urb *urb;
        int i, j, ret;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        s->isoc_errors = 0;
-       udev = s->udev;
 
        ret = usb_set_interface(s->udev, 0, 1);
        if (ret)
@@ -518,23 +508,22 @@ static int msi2500_isoc_init(struct msi2500_state *s)
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
                if (urb == NULL) {
-                       dev_err(&s->udev->dev,
-                                       "Failed to allocate urb %d\n", i);
+                       dev_err(s->dev, "Failed to allocate urb %d\n", i);
                        msi2500_isoc_cleanup(s);
                        return -ENOMEM;
                }
                s->urbs[i] = urb;
-               dev_dbg(&s->udev->dev, "Allocated URB at 0x%p\n", urb);
+               dev_dbg(s->dev, "Allocated URB at 0x%p\n", urb);
 
                urb->interval = 1;
-               urb->dev = udev;
-               urb->pipe = usb_rcvisocpipe(udev, 0x81);
+               urb->dev = s->udev;
+               urb->pipe = usb_rcvisocpipe(s->udev, 0x81);
                urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-               urb->transfer_buffer = usb_alloc_coherent(udev, ISO_BUFFER_SIZE,
+               urb->transfer_buffer = usb_alloc_coherent(s->udev,
+                               ISO_BUFFER_SIZE,
                                GFP_KERNEL, &urb->transfer_dma);
                if (urb->transfer_buffer == NULL) {
-                       dev_err(&s->udev->dev,
-                                       "Failed to allocate urb buffer %d\n",
+                       dev_err(s->dev, "Failed to allocate urb buffer %d\n",
                                        i);
                        msi2500_isoc_cleanup(s);
                        return -ENOMEM;
@@ -554,13 +543,12 @@ static int msi2500_isoc_init(struct msi2500_state *s)
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                ret = usb_submit_urb(s->urbs[i], GFP_KERNEL);
                if (ret) {
-                       dev_err(&s->udev->dev,
-                                       "isoc_init() submit_urb %d failed with error %d\n",
+                       dev_err(s->dev, "usb_submit_urb %d failed with error %d\n",
                                        i, ret);
                        msi2500_isoc_cleanup(s);
                        return ret;
                }
-               dev_dbg(&s->udev->dev, "URB 0x%p submitted.\n", s->urbs[i]);
+               dev_dbg(s->dev, "URB 0x%p submitted.\n", s->urbs[i]);
        }
 
        /* All is done... */
@@ -570,9 +558,9 @@ static int msi2500_isoc_init(struct msi2500_state *s)
 /* Must be called with vb_queue_lock hold */
 static void msi2500_cleanup_queued_bufs(struct msi2500_state *s)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        spin_lock_irqsave(&s->queued_bufs_lock, flags);
        while (!list_empty(&s->queued_bufs)) {
@@ -593,7 +581,7 @@ static void msi2500_disconnect(struct usb_interface *intf)
        struct msi2500_state *s =
                        container_of(v, struct msi2500_state, v4l2_dev);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        mutex_lock(&s->vb_queue_lock);
        mutex_lock(&s->v4l2_lock);
@@ -613,7 +601,7 @@ static int msi2500_querycap(struct file *file, void *fh,
 {
        struct msi2500_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
        strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
@@ -631,14 +619,13 @@ static int msi2500_queue_setup(struct vb2_queue *vq,
 {
        struct msi2500_state *s = vb2_get_drv_priv(vq);
 
-       dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
+       dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers);
 
        /* Absolute min and max number of buffers available for mmap() */
        *nbuffers = clamp_t(unsigned int, *nbuffers, 8, 32);
        *nplanes = 1;
        sizes[0] = PAGE_ALIGN(s->buffersize);
-       dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
-                       __func__, *nbuffers, sizes[0]);
+       dev_dbg(s->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
        return 0;
 }
 
@@ -647,7 +634,7 @@ static void msi2500_buf_queue(struct vb2_buffer *vb)
        struct msi2500_state *s = vb2_get_drv_priv(vb->vb2_queue);
        struct msi2500_frame_buf *buf =
                        container_of(vb, struct msi2500_frame_buf, vb);
-       unsigned long flags = 0;
+       unsigned long flags;
 
        /* Check the device has not disconnected between prep and queuing */
        if (unlikely(!s->udev)) {
@@ -665,16 +652,15 @@ static void msi2500_buf_queue(struct vb2_buffer *vb)
 #define CMD_STOP_STREAMING     0x45
 #define CMD_READ_UNKNOW        0x48
 
-#define msi2500_dbg_usb_control_msg(_udev, _r, _t, _v, _i, _b, _l) { \
+#define msi2500_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \
        char *_direction; \
        if (_t & USB_DIR_IN) \
                _direction = "<<<"; \
        else \
                _direction = ">>>"; \
-       dev_dbg(&_udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \
-                       "%s %*ph\n",  __func__, _t, _r, _v & 0xff, _v >> 8, \
-                       _i & 0xff, _i >> 8, _l & 0xff, _l >> 8, _direction, \
-                       _l, _b); \
+       dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \
+                       _t, _r, _v & 0xff, _v >> 8, _i & 0xff, _i >> 8, \
+                       _l & 0xff, _l >> 8, _direction, _l, _b); \
 }
 
 static int msi2500_ctrl_msg(struct msi2500_state *s, u8 cmd, u32 data)
@@ -685,18 +671,16 @@ static int msi2500_ctrl_msg(struct msi2500_state *s, u8 cmd, u32 data)
        u16 value = (data >> 0) & 0xffff;
        u16 index = (data >> 16) & 0xffff;
 
-       msi2500_dbg_usb_control_msg(s->udev,
+       msi2500_dbg_usb_control_msg(s->dev,
                        request, requesttype, value, index, NULL, 0);
-
        ret = usb_control_msg(s->udev, usb_sndctrlpipe(s->udev, 0),
                        request, requesttype, value, index, NULL, 0, 2000);
-
        if (ret)
-               dev_err(&s->udev->dev, "%s: failed %d, cmd %02x, data %04x\n",
-                               __func__, ret, cmd, data);
+               dev_err(s->dev, "failed %d, cmd %02x, data %04x\n",
+                               ret, cmd, data);
 
        return ret;
-};
+}
 
 #define F_REF 24000000
 #define DIV_R_IN 2
@@ -785,8 +769,7 @@ static int msi2500_set_usb_adc(struct msi2500_state *s)
 
        for (div_r_out = 4; div_r_out < 16; div_r_out += 2) {
                f_vco = f_sr * div_r_out * 12;
-               dev_dbg(&s->udev->dev, "%s: div_r_out=%d f_vco=%d\n",
-                               __func__, div_r_out, f_vco);
+               dev_dbg(s->dev, "div_r_out=%d f_vco=%d\n", div_r_out, f_vco);
                if (f_vco >= 202000000)
                        break;
        }
@@ -800,10 +783,8 @@ static int msi2500_set_usb_adc(struct msi2500_state *s)
        reg3 |= ((fract >> 20) & 0x000001) << 15; /* [20] */
        reg4 |= ((fract >>  0) & 0x0fffff) <<  8; /* [19:0] */
 
-       dev_dbg(&s->udev->dev,
-                       "%s: f_sr=%d f_vco=%d div_n=%d div_m=%d div_r_out=%d reg3=%08x reg4=%08x\n",
-                       __func__, f_sr, f_vco, div_n, div_m, div_r_out, reg3,
-                       reg4);
+       dev_dbg(s->dev, "f_sr=%d f_vco=%d div_n=%d div_m=%d div_r_out=%d reg3=%08x reg4=%08x\n",
+                       f_sr, f_vco, div_n, div_m, div_r_out, reg3, reg4);
 
        ret = msi2500_ctrl_msg(s, CMD_WREG, 0x00608008);
        if (ret)
@@ -838,14 +819,14 @@ static int msi2500_set_usb_adc(struct msi2500_state *s)
                goto err;
 err:
        return ret;
-};
+}
 
 static int msi2500_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct msi2500_state *s = vb2_get_drv_priv(vq);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        if (!s->udev)
                return -ENODEV;
@@ -873,7 +854,7 @@ static void msi2500_stop_streaming(struct vb2_queue *vq)
 {
        struct msi2500_state *s = vb2_get_drv_priv(vq);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        mutex_lock(&s->v4l2_lock);
 
@@ -909,7 +890,7 @@ static int msi2500_enum_fmt_sdr_cap(struct file *file, void *priv,
 {
        struct msi2500_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, f->index);
+       dev_dbg(s->dev, "index=%d\n", f->index);
 
        if (f->index >= s->num_formats)
                return -EINVAL;
@@ -925,7 +906,7 @@ static int msi2500_g_fmt_sdr_cap(struct file *file, void *priv,
 {
        struct msi2500_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+       dev_dbg(s->dev, "pixelformat fourcc %4.4s\n",
                        (char *)&s->pixelformat);
 
        f->fmt.sdr.pixelformat = s->pixelformat;
@@ -942,7 +923,7 @@ static int msi2500_s_fmt_sdr_cap(struct file *file, void *priv,
        struct vb2_queue *q = &s->vb_queue;
        int i;
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+       dev_dbg(s->dev, "pixelformat fourcc %4.4s\n",
                        (char *)&f->fmt.sdr.pixelformat);
 
        if (vb2_is_busy(q))
@@ -972,7 +953,7 @@ static int msi2500_try_fmt_sdr_cap(struct file *file, void *priv,
        struct msi2500_state *s = video_drvdata(file);
        int i;
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+       dev_dbg(s->dev, "pixelformat fourcc %4.4s\n",
                        (char *)&f->fmt.sdr.pixelformat);
 
        memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
@@ -995,7 +976,7 @@ static int msi2500_s_tuner(struct file *file, void *priv,
        struct msi2500_state *s = video_drvdata(file);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
+       dev_dbg(s->dev, "index=%d\n", v->index);
 
        if (v->index == 0)
                ret = 0;
@@ -1012,7 +993,7 @@ static int msi2500_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
        struct msi2500_state *s = video_drvdata(file);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
+       dev_dbg(s->dev, "index=%d\n", v->index);
 
        if (v->index == 0) {
                strlcpy(v->name, "Mirics MSi2500", sizeof(v->name));
@@ -1036,8 +1017,7 @@ static int msi2500_g_frequency(struct file *file, void *priv,
        struct msi2500_state *s = video_drvdata(file);
        int ret  = 0;
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
-                       __func__, f->tuner, f->type);
+       dev_dbg(s->dev, "tuner=%d type=%d\n", f->tuner, f->type);
 
        if (f->tuner == 0) {
                f->frequency = s->f_adc;
@@ -1058,15 +1038,14 @@ static int msi2500_s_frequency(struct file *file, void *priv,
        struct msi2500_state *s = video_drvdata(file);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
-                       __func__, f->tuner, f->type, f->frequency);
+       dev_dbg(s->dev, "tuner=%d type=%d frequency=%u\n",
+                       f->tuner, f->type, f->frequency);
 
        if (f->tuner == 0) {
                s->f_adc = clamp_t(unsigned int, f->frequency,
                                bands[0].rangelow,
                                bands[0].rangehigh);
-               dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
-                               __func__, s->f_adc);
+               dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc);
                ret = msi2500_set_usb_adc(s);
        } else if (f->tuner == 1) {
                ret = v4l2_subdev_call(s->v4l2_subdev, tuner, s_frequency, f);
@@ -1083,8 +1062,8 @@ static int msi2500_enum_freq_bands(struct file *file, void *priv,
        struct msi2500_state *s = video_drvdata(file);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
-                       __func__, band->tuner, band->type, band->index);
+       dev_dbg(s->dev, "tuner=%d type=%d index=%d\n",
+                       band->tuner, band->type, band->index);
 
        if (band->tuner == 0) {
                if (band->index >= ARRAY_SIZE(bands)) {
@@ -1169,8 +1148,7 @@ static int msi2500_transfer_one_message(struct spi_master *master,
        u32 data;
 
        list_for_each_entry(t, &m->transfers, transfer_list) {
-               dev_dbg(&s->udev->dev, "%s: msg=%*ph\n",
-                               __func__, t->len, t->tx_buf);
+               dev_dbg(s->dev, "msg=%*ph\n", t->len, t->tx_buf);
                data = 0x09; /* reg 9 is SPI adapter */
                data |= ((u8 *)t->tx_buf)[0] << 8;
                data |= ((u8 *)t->tx_buf)[1] << 16;
@@ -1186,8 +1164,7 @@ static int msi2500_transfer_one_message(struct spi_master *master,
 static int msi2500_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct msi2500_state *s = NULL;
+       struct msi2500_state *s;
        struct v4l2_subdev *sd;
        struct spi_master *master;
        int ret;
@@ -1200,7 +1177,7 @@ static int msi2500_probe(struct usb_interface *intf,
 
        s = kzalloc(sizeof(struct msi2500_state), GFP_KERNEL);
        if (s == NULL) {
-               pr_err("Could not allocate memory for msi2500_state\n");
+               dev_err(&intf->dev, "Could not allocate memory for state\n");
                return -ENOMEM;
        }
 
@@ -1208,12 +1185,13 @@ static int msi2500_probe(struct usb_interface *intf,
        mutex_init(&s->vb_queue_lock);
        spin_lock_init(&s->queued_bufs_lock);
        INIT_LIST_HEAD(&s->queued_bufs);
-       s->udev = udev;
+       s->dev = &intf->dev;
+       s->udev = interface_to_usbdev(intf);
        s->f_adc = bands[0].rangelow;
        s->pixelformat = formats[0].pixelformat;
        s->buffersize = formats[0].buffersize;
        s->num_formats = NUM_FORMATS;
-       if (msi2500_emulated_fmt == false)
+       if (!msi2500_emulated_fmt)
                s->num_formats -= 2;
 
        /* Init videobuf2 queue structure */
@@ -1226,7 +1204,7 @@ static int msi2500_probe(struct usb_interface *intf,
        s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
        ret = vb2_queue_init(&s->vb_queue);
        if (ret) {
-               dev_err(&s->udev->dev, "Could not initialize vb2 queue\n");
+               dev_err(s->dev, "Could not initialize vb2 queue\n");
                goto err_free_mem;
        }
 
@@ -1240,13 +1218,12 @@ static int msi2500_probe(struct usb_interface *intf,
        s->v4l2_dev.release = msi2500_video_release;
        ret = v4l2_device_register(&intf->dev, &s->v4l2_dev);
        if (ret) {
-               dev_err(&s->udev->dev,
-                               "Failed to register v4l2-device (%d)\n", ret);
+               dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret);
                goto err_free_mem;
        }
 
        /* SPI master adapter */
-       master = spi_alloc_master(&s->udev->dev, 0);
+       master = spi_alloc_master(s->dev, 0);
        if (master == NULL) {
                ret = -ENOMEM;
                goto err_unregister_v4l2_dev;
@@ -1267,7 +1244,7 @@ static int msi2500_probe(struct usb_interface *intf,
        sd = v4l2_spi_new_subdev(&s->v4l2_dev, master, &board_info);
        s->v4l2_subdev = sd;
        if (sd == NULL) {
-               dev_err(&s->udev->dev, "cannot get v4l2 subdevice\n");
+               dev_err(s->dev, "cannot get v4l2 subdevice\n");
                ret = -ENODEV;
                goto err_unregister_master;
        }
@@ -1276,7 +1253,7 @@ static int msi2500_probe(struct usb_interface *intf,
        v4l2_ctrl_handler_init(&s->hdl, 0);
        if (s->hdl.error) {
                ret = s->hdl.error;
-               dev_err(&s->udev->dev, "Could not initialize controls\n");
+               dev_err(s->dev, "Could not initialize controls\n");
                goto err_free_controls;
        }
 
@@ -1289,16 +1266,13 @@ static int msi2500_probe(struct usb_interface *intf,
 
        ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
        if (ret) {
-               dev_err(&s->udev->dev,
-                               "Failed to register as video device (%d)\n",
+               dev_err(s->dev, "Failed to register as video device (%d)\n",
                                ret);
                goto err_unregister_v4l2_dev;
        }
-       dev_info(&s->udev->dev, "Registered as %s\n",
+       dev_info(s->dev, "Registered as %s\n",
                        video_device_node_name(&s->vdev));
-       dev_notice(&s->udev->dev,
-                       "%s: SDR API is still slightly experimental and functionality changes may follow\n",
-                       KBUILD_MODNAME);
+       dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
 
        return 0;
 
index aa7449eaca08d027ba752aeddffa9ea883ad7e86..3d987984602f1bad2042a778aeef9b79c39dab32 100644 (file)
@@ -52,7 +52,7 @@ enum { custom_autocontour, custom_contour, custom_noise_reduction,
        custom_awb_speed, custom_awb_delay,
        custom_save_user, custom_restore_user, custom_restore_factory };
 
-const char * const pwc_auto_whitebal_qmenu[] = {
+static const char * const pwc_auto_whitebal_qmenu[] = {
        "Indoor (Incandescant Lighting) Mode",
        "Outdoor (Sunlight) Mode",
        "Indoor (Fluorescent Lighting) Mode",
index 2c901861034afd746a6fec9540e1ebf47f2c0156..ccc00099b26144e4bd1c5b99cbfccbf266a50ad7 100644 (file)
@@ -2245,7 +2245,7 @@ static int s2255_probe(struct usb_interface *interface,
        }
 
        atomic_set(&dev->num_channels, 0);
-       dev->pid = le16_to_cpu(id->idProduct);
+       dev->pid = id->idProduct;
        dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
        if (!dev->fw_data)
                goto errorFWDATA1;
index 1836a416d80646151e80c67d8896f96fa6fd1fe2..94e10b10b66e8c41c95672a702bcb84c91f5b05b 100644 (file)
@@ -277,14 +277,14 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
                rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
                                  fw_buffer, fw->size, &dummy, 1000);
 
-               sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
+               sms_info("sent %zu(%d) bytes, rc %d", fw->size, dummy, rc);
 
                kfree(fw_buffer);
        } else {
                sms_err("failed to allocate firmware buffer");
                rc = -ENOMEM;
        }
-       sms_info("read FW %s, size=%zd", fw_filename, fw->size);
+       sms_info("read FW %s, size=%zu", fw_filename, fw->size);
 
        release_firmware(fw);
 
@@ -655,6 +655,8 @@ static const struct usb_device_id smsusb_id_table[] = {
                .driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD },
        { USB_DEVICE(0x3275, 0x0080),
                .driver_info = SMS1XXX_BOARD_SIANO_RIO },
+       { USB_DEVICE(0x2013, 0x0257),
+               .driver_info = SMS1XXX_BOARD_PCTV_77E },
        { } /* Terminating entry */
        };
 
index 5c45c9d0712ddf949f0ac571b5649111585046ae..9c29552aedec2e7b1a08447619671cd65c170b77 100644 (file)
@@ -156,6 +156,9 @@ static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struc
                   0x00, 0x00, 0x00, 0x00,
                   0x00, 0x00 };
 
+       if (cmd->msg_len > sizeof(b) - 4)
+               return -EINVAL;
+
        memcpy(&b[4], cmd->msg, cmd->msg_len);
 
        state->config->send_command(fe, 0x72,
index 7c5b86006ee627c43a52003fb816c7fceb10b6f4..b833c5b9094edb33fbac7fd167a09710b065fbd2 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_USBTV
         tristate "USBTV007 video capture support"
-        depends on VIDEO_V4L2
+        depends on VIDEO_V4L2 && SND
+        select SND_PCM
         select VIDEOBUF2_VMALLOC
 
         ---help---
index 775316a88ea6953210befcabf71e4a005c67bc15..f555cf8a3dd2ea886ad9ad3f2b41b69d61444922 100644 (file)
@@ -1,4 +1,5 @@
 usbtv-y := usbtv-core.o \
-       usbtv-video.o
+       usbtv-video.o \
+       usbtv-audio.o
 
 obj-$(CONFIG_VIDEO_USBTV) += usbtv.o
diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c
new file mode 100644 (file)
index 0000000..78c12d2
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * Fushicai USBTV007 Audio-Video Grabber Driver
+ *
+ * Product web site:
+ * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
+ *
+ * Copyright (c) 2013 Federico Simoncelli
+ * All rights reserved.
+ * No physical hardware was harmed running Windows during the
+ * reverse-engineering activity
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ */
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+#include <sound/pcm_params.h>
+
+#include "usbtv.h"
+
+static struct snd_pcm_hardware snd_usbtv_digital_hw = {
+       .info = SNDRV_PCM_INFO_BATCH |
+               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,
+       .period_bytes_min = 11059,
+       .period_bytes_max = 13516,
+       .periods_min = 2,
+       .periods_max = 98,
+       .buffer_bytes_max = 62720 * 8, /* value in usbaudio.c */
+};
+
+static int snd_usbtv_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct usbtv *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       chip->snd_substream = substream;
+       runtime->hw = snd_usbtv_digital_hw;
+
+       return 0;
+}
+
+static int snd_usbtv_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+       if (atomic_read(&chip->snd_stream)) {
+               atomic_set(&chip->snd_stream, 0);
+               schedule_work(&chip->snd_trigger);
+       }
+
+       return 0;
+}
+
+static int snd_usbtv_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *hw_params)
+{
+       int rv;
+       struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+       rv = snd_pcm_lib_malloc_pages(substream,
+               params_buffer_bytes(hw_params));
+
+       if (rv < 0) {
+               dev_warn(chip->dev, "pcm audio buffer allocation failure %i\n",
+                       rv);
+               return rv;
+       }
+
+       return 0;
+}
+
+static int snd_usbtv_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_lib_free_pages(substream);
+       return 0;
+}
+
+static int snd_usbtv_prepare(struct snd_pcm_substream *substream)
+{
+       struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+       chip->snd_buffer_pos = 0;
+       chip->snd_period_pos = 0;
+
+       return 0;
+}
+
+static void usbtv_audio_urb_received(struct urb *urb)
+{
+       struct usbtv *chip = urb->context;
+       struct snd_pcm_substream *substream = chip->snd_substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       size_t i, frame_bytes, chunk_length, buffer_pos, period_pos;
+       int period_elapsed;
+       void *urb_current;
+
+       switch (urb->status) {
+       case 0:
+       case -ETIMEDOUT:
+               break;
+       case -ENOENT:
+       case -EPROTO:
+       case -ECONNRESET:
+       case -ESHUTDOWN:
+               return;
+       default:
+               dev_warn(chip->dev, "unknown audio urb status %i\n",
+                       urb->status);
+       }
+
+       if (!atomic_read(&chip->snd_stream))
+               return;
+
+       frame_bytes = runtime->frame_bits >> 3;
+       chunk_length = USBTV_CHUNK / frame_bytes;
+
+       buffer_pos = chip->snd_buffer_pos;
+       period_pos = chip->snd_period_pos;
+       period_elapsed = 0;
+
+       for (i = 0; i < urb->actual_length; i += USBTV_CHUNK_SIZE) {
+               urb_current = urb->transfer_buffer + i + USBTV_AUDIO_HDRSIZE;
+
+               if (buffer_pos + chunk_length >= runtime->buffer_size) {
+                       size_t cnt = (runtime->buffer_size - buffer_pos) *
+                               frame_bytes;
+                       memcpy(runtime->dma_area + buffer_pos * frame_bytes,
+                               urb_current, cnt);
+                       memcpy(runtime->dma_area, urb_current + cnt,
+                               chunk_length * frame_bytes - cnt);
+               } else {
+                       memcpy(runtime->dma_area + buffer_pos * frame_bytes,
+                               urb_current, chunk_length * frame_bytes);
+               }
+
+               buffer_pos += chunk_length;
+               period_pos += chunk_length;
+
+               if (buffer_pos >= runtime->buffer_size)
+                       buffer_pos -= runtime->buffer_size;
+
+               if (period_pos >= runtime->period_size) {
+                       period_pos -= runtime->period_size;
+                       period_elapsed = 1;
+               }
+       }
+
+       snd_pcm_stream_lock(substream);
+
+       chip->snd_buffer_pos = buffer_pos;
+       chip->snd_period_pos = period_pos;
+
+       snd_pcm_stream_unlock(substream);
+
+       if (period_elapsed)
+               snd_pcm_period_elapsed(substream);
+
+       usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int usbtv_audio_start(struct usbtv *chip)
+{
+       unsigned int pipe;
+       static const u16 setup[][2] = {
+               /* These seem to enable the device. */
+               { USBTV_BASE + 0x0008, 0x0001 },
+               { USBTV_BASE + 0x01d0, 0x00ff },
+               { USBTV_BASE + 0x01d9, 0x0002 },
+
+               { USBTV_BASE + 0x01da, 0x0013 },
+               { USBTV_BASE + 0x01db, 0x0012 },
+               { USBTV_BASE + 0x01e9, 0x0002 },
+               { USBTV_BASE + 0x01ec, 0x006c },
+               { USBTV_BASE + 0x0294, 0x0020 },
+               { USBTV_BASE + 0x0255, 0x00cf },
+               { USBTV_BASE + 0x0256, 0x0020 },
+               { USBTV_BASE + 0x01eb, 0x0030 },
+               { USBTV_BASE + 0x027d, 0x00a6 },
+               { USBTV_BASE + 0x0280, 0x0011 },
+               { USBTV_BASE + 0x0281, 0x0040 },
+               { USBTV_BASE + 0x0282, 0x0011 },
+               { USBTV_BASE + 0x0283, 0x0040 },
+               { 0xf891, 0x0010 },
+
+               /* this sets the input from composite */
+               { USBTV_BASE + 0x0284, 0x00aa },
+       };
+
+       chip->snd_bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (chip->snd_bulk_urb == NULL)
+               goto err_alloc_urb;
+
+       pipe = usb_rcvbulkpipe(chip->udev, USBTV_AUDIO_ENDP);
+
+       chip->snd_bulk_urb->transfer_buffer = kzalloc(
+               USBTV_AUDIO_URBSIZE, GFP_KERNEL);
+       if (chip->snd_bulk_urb->transfer_buffer == NULL)
+               goto err_transfer_buffer;
+
+       usb_fill_bulk_urb(chip->snd_bulk_urb, chip->udev, pipe,
+               chip->snd_bulk_urb->transfer_buffer, USBTV_AUDIO_URBSIZE,
+               usbtv_audio_urb_received, chip);
+
+       /* starting the stream */
+       usbtv_set_regs(chip, setup, ARRAY_SIZE(setup));
+
+       usb_clear_halt(chip->udev, pipe);
+       usb_submit_urb(chip->snd_bulk_urb, GFP_ATOMIC);
+
+       return 0;
+
+err_transfer_buffer:
+       usb_free_urb(chip->snd_bulk_urb);
+       chip->snd_bulk_urb = NULL;
+
+err_alloc_urb:
+       return -ENOMEM;
+}
+
+static int usbtv_audio_stop(struct usbtv *chip)
+{
+       static const u16 setup[][2] = {
+       /* The original windows driver sometimes sends also:
+        *   { USBTV_BASE + 0x00a2, 0x0013 }
+        * but it seems useless and its real effects are untested at
+        * the moment.
+        */
+               { USBTV_BASE + 0x027d, 0x0000 },
+               { USBTV_BASE + 0x0280, 0x0010 },
+               { USBTV_BASE + 0x0282, 0x0010 },
+       };
+
+       if (chip->snd_bulk_urb) {
+               usb_kill_urb(chip->snd_bulk_urb);
+               kfree(chip->snd_bulk_urb->transfer_buffer);
+               usb_free_urb(chip->snd_bulk_urb);
+               chip->snd_bulk_urb = NULL;
+       }
+
+       usbtv_set_regs(chip, setup, ARRAY_SIZE(setup));
+
+       return 0;
+}
+
+void usbtv_audio_suspend(struct usbtv *usbtv)
+{
+       if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb)
+               usb_kill_urb(usbtv->snd_bulk_urb);
+}
+
+void usbtv_audio_resume(struct usbtv *usbtv)
+{
+       if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb)
+               usb_submit_urb(usbtv->snd_bulk_urb, GFP_ATOMIC);
+}
+
+static void snd_usbtv_trigger(struct work_struct *work)
+{
+       struct usbtv *chip = container_of(work, struct usbtv, snd_trigger);
+
+       if (atomic_read(&chip->snd_stream))
+               usbtv_audio_start(chip);
+       else
+               usbtv_audio_stop(chip);
+}
+
+static int snd_usbtv_card_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               atomic_set(&chip->snd_stream, 1);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               atomic_set(&chip->snd_stream, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       schedule_work(&chip->snd_trigger);
+
+       return 0;
+}
+
+static snd_pcm_uframes_t snd_usbtv_pointer(struct snd_pcm_substream *substream)
+{
+       struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+       return chip->snd_buffer_pos;
+}
+
+static struct snd_pcm_ops snd_usbtv_pcm_ops = {
+       .open = snd_usbtv_pcm_open,
+       .close = snd_usbtv_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_usbtv_hw_params,
+       .hw_free = snd_usbtv_hw_free,
+       .prepare = snd_usbtv_prepare,
+       .trigger = snd_usbtv_card_trigger,
+       .pointer = snd_usbtv_pointer,
+};
+
+int usbtv_audio_init(struct usbtv *usbtv)
+{
+       int rv;
+       struct snd_card *card;
+       struct snd_pcm *pcm;
+
+       INIT_WORK(&usbtv->snd_trigger, snd_usbtv_trigger);
+       atomic_set(&usbtv->snd_stream, 0);
+
+       rv = snd_card_new(&usbtv->udev->dev, SNDRV_DEFAULT_IDX1, "usbtv",
+               THIS_MODULE, 0, &card);
+       if (rv < 0)
+               return rv;
+
+       strlcpy(card->driver, usbtv->dev->driver->name, sizeof(card->driver));
+       strlcpy(card->shortname, "usbtv", sizeof(card->shortname));
+       snprintf(card->longname, sizeof(card->longname),
+               "USBTV Audio at bus %d device %d", usbtv->udev->bus->busnum,
+               usbtv->udev->devnum);
+
+       snd_card_set_dev(card, usbtv->dev);
+
+       usbtv->snd = card;
+
+       rv = snd_pcm_new(card, "USBTV Audio", 0, 0, 1, &pcm);
+       if (rv < 0)
+               goto err;
+
+       strlcpy(pcm->name, "USBTV Audio Input", sizeof(pcm->name));
+       pcm->info_flags = 0;
+       pcm->private_data = usbtv;
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usbtv_pcm_ops);
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+               snd_dma_continuous_data(GFP_KERNEL), USBTV_AUDIO_BUFFER,
+               USBTV_AUDIO_BUFFER);
+
+       rv = snd_card_register(card);
+       if (rv)
+               goto err;
+
+       return 0;
+
+err:
+       usbtv->snd = NULL;
+       snd_card_free(card);
+
+       return rv;
+}
+
+void usbtv_audio_free(struct usbtv *usbtv)
+{
+       if (usbtv->snd && usbtv->udev) {
+               snd_card_free(usbtv->snd);
+               usbtv->snd = NULL;
+       }
+}
index 473fab81b602276b85cc2320eb76854611fe16ee..29428bef272c657346f2850f6372f55cb33208d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Fushicai USBTV007 Video Grabber Driver
+ * Fushicai USBTV007 Audio-Video Grabber Driver
  *
  * Product web site:
  * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
@@ -84,12 +84,19 @@ static int usbtv_probe(struct usb_interface *intf,
        if (ret < 0)
                goto usbtv_video_fail;
 
+       ret = usbtv_audio_init(usbtv);
+       if (ret < 0)
+               goto usbtv_audio_fail;
+
        /* for simplicity we exploit the v4l2_device reference counting */
        v4l2_device_get(&usbtv->v4l2_dev);
 
-       dev_info(dev, "Fushicai USBTV007 Video Grabber\n");
+       dev_info(dev, "Fushicai USBTV007 Audio-Video Grabber\n");
        return 0;
 
+usbtv_audio_fail:
+       usbtv_video_free(usbtv);
+
 usbtv_video_fail:
        usb_set_intfdata(intf, NULL);
        usb_put_dev(usbtv->udev);
@@ -101,11 +108,13 @@ usbtv_video_fail:
 static void usbtv_disconnect(struct usb_interface *intf)
 {
        struct usbtv *usbtv = usb_get_intfdata(intf);
+
        usb_set_intfdata(intf, NULL);
 
        if (!usbtv)
                return;
 
+       usbtv_audio_free(usbtv);
        usbtv_video_free(usbtv);
 
        usb_put_dev(usbtv->udev);
@@ -122,8 +131,8 @@ static struct usb_device_id usbtv_id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, usbtv_id_table);
 
-MODULE_AUTHOR("Lubomir Rintel");
-MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver");
+MODULE_AUTHOR("Lubomir Rintel, Federico Simoncelli");
+MODULE_DESCRIPTION("Fushicai USBTV007 Audio-Video Grabber Driver");
 MODULE_LICENSE("Dual BSD/GPL");
 
 static struct usb_driver usbtv_usb_driver = {
index 030c5854b4b3e45913a6a5d70bb03cb3a5bcf51c..9d3525f659f066d3c013105052e9fc31a76874aa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Fushicai USBTV007 Video Grabber Driver
+ * Fushicai USBTV007 Audio-Video Grabber Driver
  *
  * Product web site:
  * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
@@ -79,7 +79,6 @@ static int usbtv_select_input(struct usbtv *usbtv, int input)
                { USBTV_BASE + 0x011f, 0x00f2 },
                { USBTV_BASE + 0x0127, 0x0060 },
                { USBTV_BASE + 0x00ae, 0x0010 },
-               { USBTV_BASE + 0x0284, 0x00aa },
                { USBTV_BASE + 0x0239, 0x0060 },
        };
 
@@ -88,7 +87,6 @@ static int usbtv_select_input(struct usbtv *usbtv, int input)
                { USBTV_BASE + 0x011f, 0x00ff },
                { USBTV_BASE + 0x0127, 0x0060 },
                { USBTV_BASE + 0x00ae, 0x0030 },
-               { USBTV_BASE + 0x0284, 0x0088 },
                { USBTV_BASE + 0x0239, 0x0060 },
        };
 
@@ -225,7 +223,6 @@ static int usbtv_setup_capture(struct usbtv *usbtv)
                { USBTV_BASE + 0x0159, 0x0006 },
                { USBTV_BASE + 0x015d, 0x0000 },
 
-               { USBTV_BASE + 0x0284, 0x0088 },
                { USBTV_BASE + 0x0003, 0x0004 },
                { USBTV_BASE + 0x0100, 0x00d3 },
                { USBTV_BASE + 0x0115, 0x0015 },
@@ -256,7 +253,7 @@ static int usbtv_setup_capture(struct usbtv *usbtv)
  * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels.
  * Therefore, we break down the chunk into two halves before copyting,
  * so that we can interleave a line if needed. */
-static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd)
+static void usbtv_chunk_to_vbuf(u32 *frame, __be32 *src, int chunk_no, int odd)
 {
        int half;
 
@@ -266,6 +263,7 @@ static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd)
                int part_index = (line * 2 + !odd) * 3 + (part_no % 3);
 
                u32 *dst = &frame[part_index * USBTV_CHUNK/2];
+
                memcpy(dst, src, USBTV_CHUNK/2 * sizeof(*src));
                src += USBTV_CHUNK/2;
        }
@@ -274,7 +272,7 @@ static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd)
 /* Called for each 256-byte image chunk.
  * First word identifies the chunk, followed by 240 words of image
  * data and padding. */
-static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
+static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk)
 {
        int frame_id, odd, chunk_no;
        u32 *frame;
@@ -365,7 +363,7 @@ static void usbtv_iso_cb(struct urb *ip)
 
                for (offset = 0; USBTV_CHUNK_SIZE * offset < size; offset++)
                        usbtv_image_chunk(usbtv,
-                               (u32 *)&data[USBTV_CHUNK_SIZE * offset]);
+                               (__be32 *)&data[USBTV_CHUNK_SIZE * offset]);
        }
 
 resubmit:
@@ -410,6 +408,7 @@ static void usbtv_stop(struct usbtv *usbtv)
        /* Cancel running transfers. */
        for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) {
                struct urb *ip = usbtv->isoc_urbs[i];
+
                if (ip == NULL)
                        continue;
                usb_kill_urb(ip);
@@ -434,6 +433,8 @@ static int usbtv_start(struct usbtv *usbtv)
        int i;
        int ret;
 
+       usbtv_audio_suspend(usbtv);
+
        ret = usb_set_interface(usbtv->udev, 0, 0);
        if (ret < 0)
                return ret;
@@ -446,6 +447,8 @@ static int usbtv_start(struct usbtv *usbtv)
        if (ret < 0)
                return ret;
 
+       usbtv_audio_resume(usbtv);
+
        for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) {
                struct urb *ip;
 
@@ -559,6 +562,7 @@ static int usbtv_g_input(struct file *file, void *priv, unsigned int *i)
 static int usbtv_s_input(struct file *file, void *priv, unsigned int i)
 {
        struct usbtv *usbtv = video_drvdata(file);
+
        return usbtv_select_input(usbtv, i);
 }
 
index cb1d388cc647703d12736c4d37c5b98b67a1457b..968119581fab3e95adad4771576c3249ff56b0d5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Fushicai USBTV007 Video Grabber Driver
+ * Fushicai USBTV007 Audio-Video Grabber Driver
  *
  * Copyright (c) 2013 Lubomir Rintel
  * All rights reserved.
@@ -28,6 +28,7 @@
 
 /* Hardware. */
 #define USBTV_VIDEO_ENDP       0x81
+#define USBTV_AUDIO_ENDP       0x83
 #define USBTV_BASE             0xc000
 #define USBTV_REQUEST_REG      12
 
 #define USBTV_CHUNK_SIZE       256
 #define USBTV_CHUNK            240
 
+#define USBTV_AUDIO_URBSIZE    20480
+#define USBTV_AUDIO_HDRSIZE    4
+#define USBTV_AUDIO_BUFFER     65536
+
 /* Chunk header. */
 #define USBTV_MAGIC_OK(chunk)  ((be32_to_cpu(chunk[0]) & 0xff000000) \
                                                        == 0x88000000)
@@ -91,9 +96,23 @@ struct usbtv {
        int iso_size;
        unsigned int sequence;
        struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
+
+       /* audio */
+       struct snd_card *snd;
+       struct snd_pcm_substream *snd_substream;
+       atomic_t snd_stream;
+       struct work_struct snd_trigger;
+       struct urb *snd_bulk_urb;
+       size_t snd_buffer_pos;
+       size_t snd_period_pos;
 };
 
 int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size);
 
 int usbtv_video_init(struct usbtv *usbtv);
 void usbtv_video_free(struct usbtv *usbtv);
+
+int usbtv_audio_init(struct usbtv *usbtv);
+void usbtv_audio_free(struct usbtv *usbtv);
+void usbtv_audio_suspend(struct usbtv *usbtv);
+void usbtv_audio_resume(struct usbtv *usbtv);
index 0eb82106d2ff4015bc8cee2e0159626b8ba4ad8e..3e59b288b8a89cc70d9b4c086c5784e922ff1e65 100644 (file)
@@ -309,9 +309,8 @@ static struct uvc_control_info uvc_ctrls[] = {
                .selector       = UVC_CT_PANTILT_RELATIVE_CONTROL,
                .index          = 12,
                .size           = 4,
-               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
-                               | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
-                               | UVC_CTRL_FLAG_GET_DEF
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
                                | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
@@ -391,6 +390,35 @@ static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
        data[2] = min((int)abs(value), 0xff);
 }
 
+static __s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
+       __u8 query, const __u8 *data)
+{
+       unsigned int first = mapping->offset / 8;
+       __s8 rel = (__s8)data[first];
+
+       switch (query) {
+       case UVC_GET_CUR:
+               return (rel == 0) ? 0 : (rel > 0 ? data[first+1]
+                                                : -data[first+1]);
+       case UVC_GET_MIN:
+               return -data[first+1];
+       case UVC_GET_MAX:
+       case UVC_GET_RES:
+       case UVC_GET_DEF:
+       default:
+               return data[first+1];
+       }
+}
+
+static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
+       __s32 value, __u8 *data)
+{
+       unsigned int first = mapping->offset / 8;
+
+       data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
+       data[first+1] = min_t(int, abs(value), 0xff);
+}
+
 static struct uvc_control_mapping uvc_ctrl_mappings[] = {
        {
                .id             = V4L2_CID_BRIGHTNESS,
@@ -676,6 +704,30 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
                .data_type      = UVC_CTRL_DATA_TYPE_SIGNED,
        },
+       {
+               .id             = V4L2_CID_PAN_SPEED,
+               .name           = "Pan (Speed)",
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = UVC_CT_PANTILT_RELATIVE_CONTROL,
+               .size           = 16,
+               .offset         = 0,
+               .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
+               .data_type      = UVC_CTRL_DATA_TYPE_SIGNED,
+               .get            = uvc_ctrl_get_rel_speed,
+               .set            = uvc_ctrl_set_rel_speed,
+       },
+       {
+               .id             = V4L2_CID_TILT_SPEED,
+               .name           = "Tilt (Speed)",
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = UVC_CT_PANTILT_RELATIVE_CONTROL,
+               .size           = 16,
+               .offset         = 16,
+               .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
+               .data_type      = UVC_CTRL_DATA_TYPE_SIGNED,
+               .get            = uvc_ctrl_get_rel_speed,
+               .set            = uvc_ctrl_set_rel_speed,
+       },
        {
                .id             = V4L2_CID_PRIVACY,
                .name           = "Privacy",
@@ -1795,7 +1847,7 @@ done:
  * - Handle restore order (Auto-Exposure Mode should be restored before
  *   Exposure Time).
  */
-int uvc_ctrl_resume_device(struct uvc_device *dev)
+int uvc_ctrl_restore_values(struct uvc_device *dev)
 {
        struct uvc_control *ctrl;
        struct uvc_entity *entity;
index f8135f4e3b5262793e511193033d9b9bb9ad5abb..7c8322d4fc63fae2e2e65f24f080d1db7fd604a4 100644 (file)
@@ -2000,7 +2000,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
                int ret = 0;
 
                if (reset) {
-                       ret = uvc_ctrl_resume_device(dev);
+                       ret = uvc_ctrl_restore_values(dev);
                        if (ret < 0)
                                return ret;
                }
@@ -2175,6 +2175,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceClass      = USB_CLASS_VENDOR_SPEC,
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0 },
+       /* Logitech HD Pro Webcam C920 */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x046d,
+         .idProduct            = 0x082d,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_RESTORE_CTRLS_ON_INIT },
        /* Chicony CNF7129 (Asus EEE 100HE) */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2229,6 +2238,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_DEF },
+       /* Dell XPS M1330 (OmniVision OV7670 webcam) */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x05a9,
+         .idProduct            = 0x7670,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_DEF },
        /* Apple Built-In iSight */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
index 378ae02e593b93a19bb9010a23f62175029bbefd..60a8e2c3631e0b155b241e624092ccef271ae030 100644 (file)
@@ -318,6 +318,7 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream,
        stream->ctrl = probe;
        stream->cur_format = format;
        stream->cur_frame = frame;
+       stream->frame_size = fmt->fmt.pix.sizeimage;
 
 done:
        mutex_unlock(&stream->mutex);
index 9144a2f3ed826c541ef9d5d1b3286e00ce7c1d6d..9ace520bb079792b840d8aff38b68945fef0eeb0 100644 (file)
@@ -1143,7 +1143,7 @@ static int uvc_video_encode_data(struct uvc_streaming *stream,
 static void uvc_video_validate_buffer(const struct uvc_streaming *stream,
                                      struct uvc_buffer *buf)
 {
-       if (buf->length != buf->bytesused &&
+       if (stream->frame_size != buf->bytesused &&
            !(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED))
                buf->error = 1;
 }
@@ -1463,7 +1463,7 @@ static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev,
 
        switch (dev->speed) {
        case USB_SPEED_SUPER:
-               return ep->ss_ep_comp.wBytesPerInterval;
+               return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
        case USB_SPEED_HIGH:
                psize = usb_endpoint_maxp(&ep->desc);
                return (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
@@ -1678,6 +1678,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
                }
        }
 
+       /* The Logitech C920 temporarily forgets that it should not be adjusting
+        * Exposure Absolute during init so restore controls to stored values.
+        */
+       if (stream->dev->quirks & UVC_QUIRK_RESTORE_CTRLS_ON_INIT)
+               uvc_ctrl_restore_values(stream->dev);
+
        return 0;
 }
 
index b1f69a6d4068f1c64aec057142efcf02b9b6f82e..6f676c29ec09fd997b8833d78df1b8b72fdf0d91 100644 (file)
 #define UVC_QUIRK_FIX_BANDWIDTH                0x00000080
 #define UVC_QUIRK_PROBE_DEF            0x00000100
 #define UVC_QUIRK_RESTRICT_FRAME_RATE  0x00000200
+#define UVC_QUIRK_RESTORE_CTRLS_ON_INIT        0x00000400
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED                0x00000001
@@ -456,6 +457,8 @@ struct uvc_streaming {
        struct uvc_format *def_format;
        struct uvc_format *cur_format;
        struct uvc_frame *cur_frame;
+       size_t frame_size;
+
        /* Protect access to ctrl, cur_format, cur_frame and hardware video
         * probe control.
         */
@@ -688,7 +691,7 @@ extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
                const struct uvc_control_mapping *mapping);
 extern int uvc_ctrl_init_device(struct uvc_device *dev);
 extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
-extern int uvc_ctrl_resume_device(struct uvc_device *dev);
+extern int uvc_ctrl_restore_values(struct uvc_device *dev);
 
 extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
 extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
index 06c18ba16fa0427cc71fff76f08c140f55b05384..559f8372e2eb3d9bfc021da1196582d3f438ba21 100644 (file)
@@ -601,7 +601,7 @@ static int tuner_probe(struct i2c_client *client,
        t->name = "(tuner unset)";
        t->type = UNSET;
        t->audmode = V4L2_TUNER_MODE_STEREO;
-       t->standby = 1;
+       t->standby = true;
        t->radio_freq = 87.5 * 16000;   /* Initial freq range */
        t->tv_freq = 400 * 16; /* Sets freq to VHF High - needed for some PLL's to properly start */
 
@@ -1260,7 +1260,9 @@ static int tuner_suspend(struct device *dev)
 
        tuner_dbg("suspend\n");
 
-       if (!t->standby && analog_ops->standby)
+       if (t->fe.ops.tuner_ops.suspend)
+               t->fe.ops.tuner_ops.suspend(&t->fe);
+       else if (!t->standby && analog_ops->standby)
                analog_ops->standby(&t->fe);
 
        return 0;
@@ -1273,7 +1275,9 @@ static int tuner_resume(struct device *dev)
 
        tuner_dbg("resume\n");
 
-       if (!t->standby)
+       if (t->fe.ops.tuner_ops.resume)
+               t->fe.ops.tuner_ops.resume(&t->fe);
+       else if (!t->standby)
                if (set_mode(t, t->mode) == 0)
                        set_freq(t, 0);
 
index ccaa38f65cf189cf1874e9ed514ea62aa603d50f..2e9d81f4c1a57e9f51cd728b991c887558d11c72 100644 (file)
@@ -435,16 +435,13 @@ static unsigned int clamp_align(unsigned int x, unsigned int min,
        /* Bits that must be zero to be aligned */
        unsigned int mask = ~((1 << align) - 1);
 
+       /* Clamp to aligned min and max */
+       x = clamp(x, (min + ~mask) & mask, max & mask);
+
        /* Round to nearest aligned value */
        if (align)
                x = (x + (1 << (align - 1))) & mask;
 
-       /* Clamp to aligned value of min and max */
-       if (x < min)
-               x = (min + ~mask) & mask;
-       else if (x > max)
-               x = max & mask;
-
        return x;
 }
 
index cca6c2f76b3a3ed75c4398a2f67d302be41ee384..e502a5fb299471b2912bf15f25b5aada4aede3dd 100644 (file)
@@ -328,7 +328,7 @@ struct v4l2_buffer32 {
        __u32                   reserved;
 };
 
-static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
                                enum v4l2_memory memory)
 {
        void __user *up_pln;
@@ -357,7 +357,7 @@ static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
        return 0;
 }
 
-static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
                                enum v4l2_memory memory)
 {
        if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
@@ -427,7 +427,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                 * by passing a very big num_planes value */
                uplane = compat_alloc_user_space(num_planes *
                                                sizeof(struct v4l2_plane));
-               kp->m.planes = uplane;
+               kp->m.planes = (__force struct v4l2_plane *)uplane;
 
                while (--num_planes >= 0) {
                        ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
@@ -498,7 +498,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                if (num_planes == 0)
                        return 0;
 
-               uplane = kp->m.planes;
+               uplane = (__force struct v4l2_plane __user *)kp->m.planes;
                if (get_user(p, &up->m.planes))
                        return -EFAULT;
                uplane32 = compat_ptr(p);
@@ -562,7 +562,7 @@ static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame
                get_user(kp->flags, &up->flags) ||
                copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
                        return -EFAULT;
-       kp->base = compat_ptr(tmp);
+       kp->base = (__force void *)compat_ptr(tmp);
        return 0;
 }
 
@@ -667,11 +667,15 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
                        n * sizeof(struct v4l2_ext_control32)))
                return -EFAULT;
        kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
-       kp->controls = kcontrols;
+       kp->controls = (__force struct v4l2_ext_control *)kcontrols;
        while (--n >= 0) {
+               u32 id;
+
                if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
                        return -EFAULT;
-               if (ctrl_is_pointer(kcontrols->id)) {
+               if (get_user(id, &kcontrols->id))
+                       return -EFAULT;
+               if (ctrl_is_pointer(id)) {
                        void __user *s;
 
                        if (get_user(p, &ucontrols->string))
@@ -689,7 +693,8 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
 static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
 {
        struct v4l2_ext_control32 __user *ucontrols;
-       struct v4l2_ext_control __user *kcontrols = kp->controls;
+       struct v4l2_ext_control __user *kcontrols =
+               (__force struct v4l2_ext_control __user *)kp->controls;
        int n = kp->count;
        compat_caddr_t p;
 
@@ -711,11 +716,14 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
 
        while (--n >= 0) {
                unsigned size = sizeof(*ucontrols);
+               u32 id;
 
+               if (get_user(id, &kcontrols->id))
+                       return -EFAULT;
                /* Do not modify the pointer when copying a pointer control.
                   The contents of the pointer was changed, not the pointer
                   itself. */
-               if (ctrl_is_pointer(kcontrols->id))
+               if (ctrl_is_pointer(id))
                        size -= sizeof(ucontrols->value64);
                if (copy_in_user(ucontrols, kcontrols, size))
                        return -EFAULT;
@@ -770,7 +778,7 @@ static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
                get_user(tmp, &up->edid) ||
                copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
                        return -EFAULT;
-       kp->edid = compat_ptr(tmp);
+       kp->edid = (__force u8 *)compat_ptr(tmp);
        return 0;
 }
 
@@ -783,7 +791,7 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
                put_user(kp->start_block, &up->start_block) ||
                put_user(kp->blocks, &up->blocks) ||
                put_user(tmp, &up->edid) ||
-               copy_to_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+               copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
                        return -EFAULT;
        return 0;
 }
index f030d6a9e04421f2fcd63c9fce6fc713cdc897f1..86012140923fcf57526952c975a9516084f174f1 100644 (file)
@@ -796,6 +796,8 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_AUTO_FOCUS_STOP:          return "Auto Focus, Stop";
        case V4L2_CID_AUTO_FOCUS_STATUS:        return "Auto Focus, Status";
        case V4L2_CID_AUTO_FOCUS_RANGE:         return "Auto Focus, Range";
+       case V4L2_CID_PAN_SPEED:                return "Pan, Speed";
+       case V4L2_CID_TILT_SPEED:               return "Tilt, Speed";
 
        /* FM Radio Modulator controls */
        /* Keep the order of the 'case's the same as in v4l2-controls.h! */
@@ -859,6 +861,10 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_VBLANK:                   return "Vertical Blanking";
        case V4L2_CID_HBLANK:                   return "Horizontal Blanking";
        case V4L2_CID_ANALOGUE_GAIN:            return "Analogue Gain";
+       case V4L2_CID_TEST_PATTERN_RED:         return "Red Pixel Value";
+       case V4L2_CID_TEST_PATTERN_GREENR:      return "Green (Red) Pixel Value";
+       case V4L2_CID_TEST_PATTERN_BLUE:        return "Blue Pixel Value";
+       case V4L2_CID_TEST_PATTERN_GREENB:      return "Green (Blue) Pixel Value";
 
        /* Image processing controls */
        /* Keep the order of the 'case's the same as in v4l2-controls.h! */
index ce1c9f5d9dee1040c43f798b5163c4821feabbfd..b1d8dbb39665eab512f8dd59abdfac63fbed43e2 100644 (file)
@@ -164,7 +164,8 @@ bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t,
            bt->width > cap->max_width ||
            bt->pixelclock < cap->min_pixelclock ||
            bt->pixelclock > cap->max_pixelclock ||
-           (cap->standards && !(bt->standards & cap->standards)) ||
+           (cap->standards && bt->standards &&
+            !(bt->standards & cap->standards)) ||
            (bt->interlaced && !(caps & V4L2_DV_BT_CAP_INTERLACED)) ||
            (!bt->interlaced && !(caps & V4L2_DV_BT_CAP_PROGRESSIVE)))
                return false;
index d15e16737eef4e0fd6d58d9babcba00ddcd2df77..9ccb19a435ef7a04a7d125af5a5b86c3b130a79d 100644 (file)
@@ -562,7 +562,7 @@ static void v4l_print_ext_controls(const void *arg, bool write_only)
        pr_cont("class=0x%x, count=%d, error_idx=%d",
                        p->ctrl_class, p->count, p->error_idx);
        for (i = 0; i < p->count; i++) {
-               if (p->controls[i].size)
+               if (!p->controls[i].size)
                        pr_cont(", id/val=0x%x/0x%x",
                                p->controls[i].id, p->controls[i].value);
                else
@@ -1153,9 +1153,9 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
        switch (p->type) {
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
-               struct v4l2_clip *clips = p->fmt.win.clips;
+               struct v4l2_clip __user *clips = p->fmt.win.clips;
                u32 clipcount = p->fmt.win.clipcount;
-               void *bitmap = p->fmt.win.bitmap;
+               void __user *bitmap = p->fmt.win.bitmap;
 
                memset(&p->fmt, 0, sizeof(p->fmt));
                p->fmt.win.clips = clips;
index b4d235c13fbfc43d12decce919e9dc367e094ea5..543631c3557ab94ec264164532403d33b0eb5497 100644 (file)
@@ -501,11 +501,20 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
                                      struct v4l2_subdev_format *source_fmt,
                                      struct v4l2_subdev_format *sink_fmt)
 {
+       /* The width, height and code must match. */
        if (source_fmt->format.width != sink_fmt->format.width
            || source_fmt->format.height != sink_fmt->format.height
            || source_fmt->format.code != sink_fmt->format.code)
                return -EINVAL;
 
+       /* The field order must match, or the sink field order must be NONE
+        * to support interlaced hardware connected to bridges that support
+        * progressive formats only.
+        */
+       if (source_fmt->format.field != sink_fmt->format.field &&
+           sink_fmt->format.field != V4L2_FIELD_NONE)
+               return -EINVAL;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
index fb5ee5dd8fe933cbdd371aeecf41a3047d2e0e39..b91a266d0b7efcced9ad3bbca2b08cb398377505 100644 (file)
@@ -441,11 +441,6 @@ int videobuf_reqbufs(struct videobuf_queue *q,
        unsigned int size, count;
        int retval;
 
-       if (req->count < 1) {
-               dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
-               return -EINVAL;
-       }
-
        if (req->memory != V4L2_MEMORY_MMAP     &&
            req->memory != V4L2_MEMORY_USERPTR  &&
            req->memory != V4L2_MEMORY_OVERLAY) {
@@ -471,6 +466,12 @@ int videobuf_reqbufs(struct videobuf_queue *q,
                goto done;
        }
 
+       if (req->count == 0) {
+               dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
+               retval = __videobuf_free(q);
+               goto done;
+       }
+
        count = req->count;
        if (count > VIDEO_MAX_FRAME)
                count = VIDEO_MAX_FRAME;
index 3c8cc023a5a5e3c2718545b8814664fbf02be291..3ff15f1c9d702219b33a43e3df0e9eb07fab93e6 100644 (file)
@@ -253,9 +253,11 @@ int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
        return 0;
 out_free_pages:
        while (i > 0) {
-               void *addr = page_address(dma->vaddr_pages[i]);
-               dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]);
+               void *addr;
+
                i--;
+               addr = page_address(dma->vaddr_pages[i]);
+               dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]);
        }
        kfree(dma->dma_addr);
        dma->dma_addr = NULL;
index 25d3ae2188cb29fc2338e0dc976d21db17829447..f2e43de3dd879330fbc6a230d6d267f5c6efdf0d 100644 (file)
@@ -36,7 +36,7 @@ module_param(debug, int, 0644);
 #define dprintk(level, fmt, arg...)                                          \
        do {                                                                  \
                if (debug >= level)                                           \
-                       pr_debug("vb2: %s: " fmt, __func__, ## arg); \
+                       pr_info("vb2: %s: " fmt, __func__, ## arg); \
        } while (0)
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -882,7 +882,9 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
                 * We already have buffers allocated, so first check if they
                 * are not in use and can be freed.
                 */
+               mutex_lock(&q->mmap_lock);
                if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
+                       mutex_unlock(&q->mmap_lock);
                        dprintk(1, "memory in use, cannot free\n");
                        return -EBUSY;
                }
@@ -894,6 +896,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
                 */
                __vb2_queue_cancel(q);
                ret = __vb2_queue_free(q, q->num_buffers);
+               mutex_unlock(&q->mmap_lock);
                if (ret)
                        return ret;
 
@@ -955,6 +958,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
                 */
        }
 
+       mutex_lock(&q->mmap_lock);
        q->num_buffers = allocated_buffers;
 
        if (ret < 0) {
@@ -963,8 +967,10 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
                 * from q->num_buffers.
                 */
                __vb2_queue_free(q, allocated_buffers);
+               mutex_unlock(&q->mmap_lock);
                return ret;
        }
+       mutex_unlock(&q->mmap_lock);
 
        /*
         * Return the number of successfully allocated buffers
@@ -1063,6 +1069,7 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
                 */
        }
 
+       mutex_lock(&q->mmap_lock);
        q->num_buffers += allocated_buffers;
 
        if (ret < 0) {
@@ -1071,8 +1078,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
                 * from q->num_buffers.
                 */
                __vb2_queue_free(q, allocated_buffers);
+               mutex_unlock(&q->mmap_lock);
                return -ENOMEM;
        }
+       mutex_unlock(&q->mmap_lock);
 
        /*
         * Return the number of successfully allocated buffers
@@ -1581,7 +1590,6 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
 static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 {
        struct vb2_queue *q = vb->vb2_queue;
-       struct rw_semaphore *mmap_sem;
        int ret;
 
        ret = __verify_length(vb, b);
@@ -1618,26 +1626,9 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
                ret = __qbuf_mmap(vb, b);
                break;
        case V4L2_MEMORY_USERPTR:
-               /*
-                * In case of user pointer buffers vb2 allocators need to get
-                * direct access to userspace pages. This requires getting
-                * the mmap semaphore for read access in the current process
-                * structure. The same semaphore is taken before calling mmap
-                * operation, while both qbuf/prepare_buf and mmap are called
-                * by the driver or v4l2 core with the driver's lock held.
-                * To avoid an AB-BA deadlock (mmap_sem then driver's lock in
-                * mmap and driver's lock then mmap_sem in qbuf/prepare_buf),
-                * the videobuf2 core releases the driver's lock, takes
-                * mmap_sem and then takes the driver's lock again.
-                */
-               mmap_sem = &current->mm->mmap_sem;
-               call_void_qop(q, wait_prepare, q);
-               down_read(mmap_sem);
-               call_void_qop(q, wait_finish, q);
-
+               down_read(&current->mm->mmap_sem);
                ret = __qbuf_userptr(vb, b);
-
-               up_read(mmap_sem);
+               up_read(&current->mm->mmap_sem);
                break;
        case V4L2_MEMORY_DMABUF:
                ret = __qbuf_dmabuf(vb, b);
@@ -2504,7 +2495,9 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
                return -EINVAL;
        }
 
+       mutex_lock(&q->mmap_lock);
        ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
+       mutex_unlock(&q->mmap_lock);
        if (ret)
                return ret;
 
@@ -2523,6 +2516,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
        unsigned long off = pgoff << PAGE_SHIFT;
        struct vb2_buffer *vb;
        unsigned int buffer, plane;
+       void *vaddr;
        int ret;
 
        if (q->memory != V4L2_MEMORY_MMAP) {
@@ -2539,7 +2533,8 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
 
        vb = q->bufs[buffer];
 
-       return (unsigned long)vb2_plane_vaddr(vb, plane);
+       vaddr = vb2_plane_vaddr(vb, plane);
+       return vaddr ? (unsigned long)vaddr : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(vb2_get_unmapped_area);
 #endif
@@ -2686,6 +2681,7 @@ int vb2_queue_init(struct vb2_queue *q)
        INIT_LIST_HEAD(&q->queued_list);
        INIT_LIST_HEAD(&q->done_list);
        spin_lock_init(&q->done_lock);
+       mutex_init(&q->mmap_lock);
        init_waitqueue_head(&q->done_wq);
 
        if (q->buf_struct_size == 0)
@@ -2707,7 +2703,9 @@ void vb2_queue_release(struct vb2_queue *q)
 {
        __vb2_cleanup_fileio(q);
        __vb2_queue_cancel(q);
+       mutex_lock(&q->mmap_lock);
        __vb2_queue_free(q, q->num_buffers);
+       mutex_unlock(&q->mmap_lock);
 }
 EXPORT_SYMBOL_GPL(vb2_queue_release);
 
@@ -2985,6 +2983,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
                buf->queued = 0;
                buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
                                 : vb2_plane_size(q->bufs[index], 0);
+               /* Compensate for data_offset on read in the multiplanar case. */
+               if (is_multiplanar && read &&
+                   fileio->b.m.planes[0].data_offset < buf->size) {
+                       buf->pos = fileio->b.m.planes[0].data_offset;
+                       buf->size -= buf->pos;
+               }
        } else {
                buf = &fileio->bufs[index];
        }
@@ -3372,15 +3376,8 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_expbuf);
 int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct video_device *vdev = video_devdata(file);
-       struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
-       int err;
 
-       if (lock && mutex_lock_interruptible(lock))
-               return -ERESTARTSYS;
-       err = vb2_mmap(vdev->queue, vma);
-       if (lock)
-               mutex_unlock(lock);
-       return err;
+       return vb2_mmap(vdev->queue, vma);
 }
 EXPORT_SYMBOL_GPL(vb2_fop_mmap);
 
@@ -3499,15 +3496,8 @@ unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr,
                unsigned long len, unsigned long pgoff, unsigned long flags)
 {
        struct video_device *vdev = video_devdata(file);
-       struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
-       int ret;
 
-       if (lock && mutex_lock_interruptible(lock))
-               return -ERESTARTSYS;
-       ret = vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
-       if (lock)
-               mutex_unlock(lock);
-       return ret;
+       return vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
 }
 EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area);
 #endif
index 3323eb5e77b07ea1e56367c21ff9497e2143f661..655cf5037b0b9f2d5e2e88f4dc37ee399bf21d95 100644 (file)
@@ -19,8 +19,6 @@ menuconfig STAGING_MEDIA
 if STAGING_MEDIA
 
 # Please keep them in alphabetic order
-source "drivers/staging/media/as102/Kconfig"
-
 source "drivers/staging/media/bcm2048/Kconfig"
 
 source "drivers/staging/media/cxd2099/Kconfig"
index 7db83f373f63010c8618255415146c9a1d9dd03e..6dbe578178cdcdbb4d988809c40c3241a36816a2 100644 (file)
@@ -1,4 +1,3 @@
-obj-$(CONFIG_DVB_AS102)                += as102/
 obj-$(CONFIG_I2C_BCM2048)      += bcm2048/
 obj-$(CONFIG_DVB_CXD2099)      += cxd2099/
 obj-$(CONFIG_LIRC_STAGING)     += lirc/
diff --git a/drivers/staging/media/as102/Kconfig b/drivers/staging/media/as102/Kconfig
deleted file mode 100644 (file)
index 28aba00..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-config DVB_AS102
-       tristate "Abilis AS102 DVB receiver"
-       depends on DVB_CORE && USB && I2C && INPUT
-       select FW_LOADER
-       help
-         Choose Y or M here if you have a device containing an AS102
-
-         To compile this driver as a module, choose M here
diff --git a/drivers/staging/media/as102/Makefile b/drivers/staging/media/as102/Makefile
deleted file mode 100644 (file)
index 8916d8a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \
-               as102_fe.o as102_usb_drv.o as10x_cmd_cfg.o
-
-obj-$(CONFIG_DVB_AS102) += dvb-as102.o
-
-ccflags-y += -Idrivers/media/dvb-core
diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c
deleted file mode 100644 (file)
index 09d64cd..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/kref.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-
-/* header file for usb device driver*/
-#include "as102_drv.h"
-#include "as102_fw.h"
-#include "dvbdev.h"
-
-int as102_debug;
-module_param_named(debug, as102_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default: off)");
-
-int dual_tuner;
-module_param_named(dual_tuner, dual_tuner, int, 0644);
-MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)");
-
-static int fw_upload = 1;
-module_param_named(fw_upload, fw_upload, int, 0644);
-MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)");
-
-static int pid_filtering;
-module_param_named(pid_filtering, pid_filtering, int, 0644);
-MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)");
-
-static int ts_auto_disable;
-module_param_named(ts_auto_disable, ts_auto_disable, int, 0644);
-MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)");
-
-int elna_enable = 1;
-module_param_named(elna_enable, elna_enable, int, 0644);
-MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static void as102_stop_stream(struct as102_dev_t *dev)
-{
-       struct as10x_bus_adapter_t *bus_adap;
-
-       if (dev != NULL)
-               bus_adap = &dev->bus_adap;
-       else
-               return;
-
-       if (bus_adap->ops->stop_stream != NULL)
-               bus_adap->ops->stop_stream(dev);
-
-       if (ts_auto_disable) {
-               if (mutex_lock_interruptible(&dev->bus_adap.lock))
-                       return;
-
-               if (as10x_cmd_stop_streaming(bus_adap) < 0)
-                       dprintk(debug, "as10x_cmd_stop_streaming failed\n");
-
-               mutex_unlock(&dev->bus_adap.lock);
-       }
-}
-
-static int as102_start_stream(struct as102_dev_t *dev)
-{
-       struct as10x_bus_adapter_t *bus_adap;
-       int ret = -EFAULT;
-
-       if (dev != NULL)
-               bus_adap = &dev->bus_adap;
-       else
-               return ret;
-
-       if (bus_adap->ops->start_stream != NULL)
-               ret = bus_adap->ops->start_stream(dev);
-
-       if (ts_auto_disable) {
-               if (mutex_lock_interruptible(&dev->bus_adap.lock))
-                       return -EFAULT;
-
-               ret = as10x_cmd_start_streaming(bus_adap);
-
-               mutex_unlock(&dev->bus_adap.lock);
-       }
-
-       return ret;
-}
-
-static int as10x_pid_filter(struct as102_dev_t *dev,
-                           int index, u16 pid, int onoff) {
-
-       struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap;
-       int ret = -EFAULT;
-
-       if (mutex_lock_interruptible(&dev->bus_adap.lock)) {
-               dprintk(debug, "mutex_lock_interruptible(lock) failed !\n");
-               return -EBUSY;
-       }
-
-       switch (onoff) {
-       case 0:
-               ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid);
-               dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n",
-                       index, pid, ret);
-               break;
-       case 1:
-       {
-               struct as10x_ts_filter filter;
-
-               filter.type = TS_PID_TYPE_TS;
-               filter.idx = 0xFF;
-               filter.pid = pid;
-
-               ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
-               dprintk(debug,
-                       "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
-                       index, filter.idx, filter.pid, ret);
-               break;
-       }
-       }
-
-       mutex_unlock(&dev->bus_adap.lock);
-       return ret;
-}
-
-static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-       int ret = 0;
-       struct dvb_demux *demux = dvbdmxfeed->demux;
-       struct as102_dev_t *as102_dev = demux->priv;
-
-       if (mutex_lock_interruptible(&as102_dev->sem))
-               return -ERESTARTSYS;
-
-       if (pid_filtering)
-               as10x_pid_filter(as102_dev, dvbdmxfeed->index,
-                                dvbdmxfeed->pid, 1);
-
-       if (as102_dev->streaming++ == 0)
-               ret = as102_start_stream(as102_dev);
-
-       mutex_unlock(&as102_dev->sem);
-       return ret;
-}
-
-static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-       struct dvb_demux *demux = dvbdmxfeed->demux;
-       struct as102_dev_t *as102_dev = demux->priv;
-
-       if (mutex_lock_interruptible(&as102_dev->sem))
-               return -ERESTARTSYS;
-
-       if (--as102_dev->streaming == 0)
-               as102_stop_stream(as102_dev);
-
-       if (pid_filtering)
-               as10x_pid_filter(as102_dev, dvbdmxfeed->index,
-                                dvbdmxfeed->pid, 0);
-
-       mutex_unlock(&as102_dev->sem);
-       return 0;
-}
-
-int as102_dvb_register(struct as102_dev_t *as102_dev)
-{
-       struct device *dev = &as102_dev->bus_adap.usb_dev->dev;
-       int ret;
-
-       ret = dvb_register_adapter(&as102_dev->dvb_adap,
-                          as102_dev->name, THIS_MODULE,
-                          dev, adapter_nr);
-       if (ret < 0) {
-               dev_err(dev, "%s: dvb_register_adapter() failed: %d\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       as102_dev->dvb_dmx.priv = as102_dev;
-       as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256;
-       as102_dev->dvb_dmx.feednum = 256;
-       as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed;
-       as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed;
-
-       as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING |
-                                             DMX_SECTION_FILTERING;
-
-       as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum;
-       as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx;
-       as102_dev->dvb_dmxdev.capabilities = 0;
-
-       ret = dvb_dmx_init(&as102_dev->dvb_dmx);
-       if (ret < 0) {
-               dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret);
-               goto edmxinit;
-       }
-
-       ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap);
-       if (ret < 0) {
-               dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n",
-                       __func__, ret);
-               goto edmxdinit;
-       }
-
-       ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe);
-       if (ret < 0) {
-               dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d",
-                   __func__, ret);
-               goto efereg;
-       }
-
-       /* init bus mutex for token locking */
-       mutex_init(&as102_dev->bus_adap.lock);
-
-       /* init start / stop stream mutex */
-       mutex_init(&as102_dev->sem);
-
-       /*
-        * try to load as102 firmware. If firmware upload failed, we'll be
-        * able to upload it later.
-        */
-       if (fw_upload)
-               try_then_request_module(as102_fw_upload(&as102_dev->bus_adap),
-                               "firmware_class");
-
-       pr_info("Registered device %s", as102_dev->name);
-       return 0;
-
-efereg:
-       dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
-edmxdinit:
-       dvb_dmx_release(&as102_dev->dvb_dmx);
-edmxinit:
-       dvb_unregister_adapter(&as102_dev->dvb_adap);
-       return ret;
-}
-
-void as102_dvb_unregister(struct as102_dev_t *as102_dev)
-{
-       /* unregister as102 frontend */
-       as102_dvb_unregister_fe(&as102_dev->dvb_fe);
-
-       /* unregister demux device */
-       dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
-       dvb_dmx_release(&as102_dev->dvb_dmx);
-
-       /* unregister dvb adapter */
-       dvb_unregister_adapter(&as102_dev->dvb_adap);
-
-       pr_info("Unregistered device %s", as102_dev->name);
-}
-
-module_usb_driver(as102_usb_driver);
-
-/* modinfo details */
-MODULE_DESCRIPTION(DRIVER_FULL_NAME);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h
deleted file mode 100644 (file)
index a06837d..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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/usb.h>
-#include <dvb_demux.h>
-#include <dvb_frontend.h>
-#include <dmxdev.h>
-#include "as10x_cmd.h"
-#include "as102_usb_drv.h"
-
-#define DRIVER_FULL_NAME "Abilis Systems as10x usb driver"
-#define DRIVER_NAME "as10x_usb"
-
-extern int as102_debug;
-#define debug  as102_debug
-extern struct usb_driver as102_usb_driver;
-extern int elna_enable;
-
-#define dprintk(debug, args...) \
-       do { if (debug) {       \
-               pr_debug("%s: ", __func__);     \
-               printk(args);   \
-       } } while (0)
-
-#define AS102_DEVICE_MAJOR     192
-
-#define AS102_USB_BUF_SIZE     512
-#define MAX_STREAM_URB         32
-
-struct as10x_bus_adapter_t {
-       struct usb_device *usb_dev;
-       /* bus token lock */
-       struct mutex lock;
-       /* low level interface for bus adapter */
-       union as10x_bus_token_t {
-               /* usb token */
-               struct as10x_usb_token_cmd_t usb;
-       } token;
-
-       /* token cmd xfer id */
-       uint16_t cmd_xid;
-
-       /* as10x command and response for dvb interface*/
-       struct as10x_cmd_t *cmd, *rsp;
-
-       /* bus adapter private ops callback */
-       struct as102_priv_ops_t *ops;
-};
-
-struct as102_dev_t {
-       const char *name;
-       struct as10x_bus_adapter_t bus_adap;
-       struct list_head device_entry;
-       struct kref kref;
-       uint8_t elna_cfg;
-
-       struct dvb_adapter dvb_adap;
-       struct dvb_frontend dvb_fe;
-       struct dvb_demux dvb_dmx;
-       struct dmxdev dvb_dmxdev;
-
-       /* demodulator stats */
-       struct as10x_demod_stats demod_stats;
-       /* signal strength */
-       uint16_t signal_strength;
-       /* bit error rate */
-       uint32_t ber;
-
-       /* timer handle to trig ts stream download */
-       struct timer_list timer_handle;
-
-       struct mutex sem;
-       dma_addr_t dma_addr;
-       void *stream;
-       int streaming;
-       struct urb *stream_urb[MAX_STREAM_URB];
-};
-
-int as102_dvb_register(struct as102_dev_t *dev);
-void as102_dvb_unregister(struct as102_dev_t *dev);
-
-int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe);
-int as102_dvb_unregister_fe(struct dvb_frontend *dev);
diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c
deleted file mode 100644 (file)
index b686b76..0000000
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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 "as102_drv.h"
-#include "as10x_types.h"
-#include "as10x_cmd.h"
-
-static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *dst,
-                                        struct as10x_tps *src);
-
-static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst,
-                                         struct dtv_frontend_properties *src);
-
-static int as102_fe_set_frontend(struct dvb_frontend *fe)
-{
-       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-       int ret = 0;
-       struct as102_dev_t *dev;
-       struct as10x_tune_args tune_args = { 0 };
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       if (mutex_lock_interruptible(&dev->bus_adap.lock))
-               return -EBUSY;
-
-       as102_fe_copy_tune_parameters(&tune_args, p);
-
-       /* send abilis command: SET_TUNE */
-       ret =  as10x_cmd_set_tune(&dev->bus_adap, &tune_args);
-       if (ret != 0)
-               dprintk(debug, "as10x_cmd_set_tune failed. (err = %d)\n", ret);
-
-       mutex_unlock(&dev->bus_adap.lock);
-
-       return (ret < 0) ? -EINVAL : 0;
-}
-
-static int as102_fe_get_frontend(struct dvb_frontend *fe)
-{
-       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-       int ret = 0;
-       struct as102_dev_t *dev;
-       struct as10x_tps tps = { 0 };
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -EINVAL;
-
-       if (mutex_lock_interruptible(&dev->bus_adap.lock))
-               return -EBUSY;
-
-       /* send abilis command: GET_TPS */
-       ret = as10x_cmd_get_tps(&dev->bus_adap, &tps);
-
-       if (ret == 0)
-               as10x_fe_copy_tps_parameters(p, &tps);
-
-       mutex_unlock(&dev->bus_adap.lock);
-
-       return (ret < 0) ? -EINVAL : 0;
-}
-
-static int as102_fe_get_tune_settings(struct dvb_frontend *fe,
-                       struct dvb_frontend_tune_settings *settings) {
-
-#if 0
-       dprintk(debug, "step_size    = %d\n", settings->step_size);
-       dprintk(debug, "max_drift    = %d\n", settings->max_drift);
-       dprintk(debug, "min_delay_ms = %d -> %d\n", settings->min_delay_ms,
-               1000);
-#endif
-
-       settings->min_delay_ms = 1000;
-
-       return 0;
-}
-
-
-static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-       int ret = 0;
-       struct as102_dev_t *dev;
-       struct as10x_tune_status tstate = { 0 };
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       if (mutex_lock_interruptible(&dev->bus_adap.lock))
-               return -EBUSY;
-
-       /* send abilis command: GET_TUNE_STATUS */
-       ret = as10x_cmd_get_tune_status(&dev->bus_adap, &tstate);
-       if (ret < 0) {
-               dprintk(debug, "as10x_cmd_get_tune_status failed (err = %d)\n",
-                       ret);
-               goto out;
-       }
-
-       dev->signal_strength  = tstate.signal_strength;
-       dev->ber  = tstate.BER;
-
-       switch (tstate.tune_state) {
-       case TUNE_STATUS_SIGNAL_DVB_OK:
-               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
-               break;
-       case TUNE_STATUS_STREAM_DETECTED:
-               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC;
-               break;
-       case TUNE_STATUS_STREAM_TUNED:
-               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
-                       FE_HAS_LOCK;
-               break;
-       default:
-               *status = TUNE_STATUS_NOT_TUNED;
-       }
-
-       dprintk(debug, "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n",
-                       tstate.tune_state, tstate.signal_strength,
-                       tstate.PER, tstate.BER);
-
-       if (*status & FE_HAS_LOCK) {
-               if (as10x_cmd_get_demod_stats(&dev->bus_adap,
-                       (struct as10x_demod_stats *) &dev->demod_stats) < 0) {
-                       memset(&dev->demod_stats, 0, sizeof(dev->demod_stats));
-                       dprintk(debug,
-                               "as10x_cmd_get_demod_stats failed (probably not tuned)\n");
-               } else {
-                       dprintk(debug,
-                               "demod status: fc: 0x%08x, bad fc: 0x%08x, "
-                               "bytes corrected: 0x%08x , MER: 0x%04x\n",
-                               dev->demod_stats.frame_count,
-                               dev->demod_stats.bad_frame_count,
-                               dev->demod_stats.bytes_fixed_by_rs,
-                               dev->demod_stats.mer);
-               }
-       } else {
-               memset(&dev->demod_stats, 0, sizeof(dev->demod_stats));
-       }
-
-out:
-       mutex_unlock(&dev->bus_adap.lock);
-       return ret;
-}
-
-/*
- * Note:
- * - in AS102 SNR=MER
- *   - the SNR will be returned in linear terms, i.e. not in dB
- *   - the accuracy equals Â±2dB for a SNR range from 4dB to 30dB
- *   - the accuracy is >2dB for SNR values outside this range
- */
-static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-       struct as102_dev_t *dev;
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       *snr = dev->demod_stats.mer;
-
-       return 0;
-}
-
-static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-       struct as102_dev_t *dev;
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       *ber = dev->ber;
-
-       return 0;
-}
-
-static int as102_fe_read_signal_strength(struct dvb_frontend *fe,
-                                        u16 *strength)
-{
-       struct as102_dev_t *dev;
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       *strength = (((0xffff * 400) * dev->signal_strength + 41000) * 2);
-
-       return 0;
-}
-
-static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-       struct as102_dev_t *dev;
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       if (dev->demod_stats.has_started)
-               *ucblocks = dev->demod_stats.bad_frame_count;
-       else
-               *ucblocks = 0;
-
-       return 0;
-}
-
-static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
-{
-       struct as102_dev_t *dev;
-       int ret;
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       if (mutex_lock_interruptible(&dev->bus_adap.lock))
-               return -EBUSY;
-
-       if (acquire) {
-               if (elna_enable)
-                       as10x_cmd_set_context(&dev->bus_adap,
-                                             CONTEXT_LNA, dev->elna_cfg);
-
-               ret = as10x_cmd_turn_on(&dev->bus_adap);
-       } else {
-               ret = as10x_cmd_turn_off(&dev->bus_adap);
-       }
-
-       mutex_unlock(&dev->bus_adap.lock);
-
-       return ret;
-}
-
-static struct dvb_frontend_ops as102_fe_ops = {
-       .delsys = { SYS_DVBT },
-       .info = {
-               .name                   = "Unknown AS102 device",
-               .frequency_min          = 174000000,
-               .frequency_max          = 862000000,
-               .frequency_stepsize     = 166667,
-               .caps = FE_CAN_INVERSION_AUTO
-                       | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
-                       | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO
-                       | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK
-                       | FE_CAN_QAM_AUTO
-                       | FE_CAN_TRANSMISSION_MODE_AUTO
-                       | FE_CAN_GUARD_INTERVAL_AUTO
-                       | FE_CAN_HIERARCHY_AUTO
-                       | FE_CAN_RECOVER
-                       | FE_CAN_MUTE_TS
-       },
-
-       .set_frontend           = as102_fe_set_frontend,
-       .get_frontend           = as102_fe_get_frontend,
-       .get_tune_settings      = as102_fe_get_tune_settings,
-
-       .read_status            = as102_fe_read_status,
-       .read_snr               = as102_fe_read_snr,
-       .read_ber               = as102_fe_read_ber,
-       .read_signal_strength   = as102_fe_read_signal_strength,
-       .read_ucblocks          = as102_fe_read_ucblocks,
-       .ts_bus_ctrl            = as102_fe_ts_bus_ctrl,
-};
-
-int as102_dvb_unregister_fe(struct dvb_frontend *fe)
-{
-       /* unregister frontend */
-       dvb_unregister_frontend(fe);
-
-       /* detach frontend */
-       dvb_frontend_detach(fe);
-
-       return 0;
-}
-
-int as102_dvb_register_fe(struct as102_dev_t *as102_dev,
-                         struct dvb_frontend *dvb_fe)
-{
-       int errno;
-       struct dvb_adapter *dvb_adap;
-
-       if (as102_dev == NULL)
-               return -EINVAL;
-
-       /* extract dvb_adapter */
-       dvb_adap = &as102_dev->dvb_adap;
-
-       /* init frontend callback ops */
-       memcpy(&dvb_fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops));
-       strncpy(dvb_fe->ops.info.name, as102_dev->name,
-               sizeof(dvb_fe->ops.info.name));
-
-       /* register dvb frontend */
-       errno = dvb_register_frontend(dvb_adap, dvb_fe);
-       if (errno == 0)
-               dvb_fe->tuner_priv = as102_dev;
-
-       return errno;
-}
-
-static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps,
-                                        struct as10x_tps *as10x_tps)
-{
-
-       /* extract constellation */
-       switch (as10x_tps->modulation) {
-       case CONST_QPSK:
-               fe_tps->modulation = QPSK;
-               break;
-       case CONST_QAM16:
-               fe_tps->modulation = QAM_16;
-               break;
-       case CONST_QAM64:
-               fe_tps->modulation = QAM_64;
-               break;
-       }
-
-       /* extract hierarchy */
-       switch (as10x_tps->hierarchy) {
-       case HIER_NONE:
-               fe_tps->hierarchy = HIERARCHY_NONE;
-               break;
-       case HIER_ALPHA_1:
-               fe_tps->hierarchy = HIERARCHY_1;
-               break;
-       case HIER_ALPHA_2:
-               fe_tps->hierarchy = HIERARCHY_2;
-               break;
-       case HIER_ALPHA_4:
-               fe_tps->hierarchy = HIERARCHY_4;
-               break;
-       }
-
-       /* extract code rate HP */
-       switch (as10x_tps->code_rate_HP) {
-       case CODE_RATE_1_2:
-               fe_tps->code_rate_HP = FEC_1_2;
-               break;
-       case CODE_RATE_2_3:
-               fe_tps->code_rate_HP = FEC_2_3;
-               break;
-       case CODE_RATE_3_4:
-               fe_tps->code_rate_HP = FEC_3_4;
-               break;
-       case CODE_RATE_5_6:
-               fe_tps->code_rate_HP = FEC_5_6;
-               break;
-       case CODE_RATE_7_8:
-               fe_tps->code_rate_HP = FEC_7_8;
-               break;
-       }
-
-       /* extract code rate LP */
-       switch (as10x_tps->code_rate_LP) {
-       case CODE_RATE_1_2:
-               fe_tps->code_rate_LP = FEC_1_2;
-               break;
-       case CODE_RATE_2_3:
-               fe_tps->code_rate_LP = FEC_2_3;
-               break;
-       case CODE_RATE_3_4:
-               fe_tps->code_rate_LP = FEC_3_4;
-               break;
-       case CODE_RATE_5_6:
-               fe_tps->code_rate_LP = FEC_5_6;
-               break;
-       case CODE_RATE_7_8:
-               fe_tps->code_rate_LP = FEC_7_8;
-               break;
-       }
-
-       /* extract guard interval */
-       switch (as10x_tps->guard_interval) {
-       case GUARD_INT_1_32:
-               fe_tps->guard_interval = GUARD_INTERVAL_1_32;
-               break;
-       case GUARD_INT_1_16:
-               fe_tps->guard_interval = GUARD_INTERVAL_1_16;
-               break;
-       case GUARD_INT_1_8:
-               fe_tps->guard_interval = GUARD_INTERVAL_1_8;
-               break;
-       case GUARD_INT_1_4:
-               fe_tps->guard_interval = GUARD_INTERVAL_1_4;
-               break;
-       }
-
-       /* extract transmission mode */
-       switch (as10x_tps->transmission_mode) {
-       case TRANS_MODE_2K:
-               fe_tps->transmission_mode = TRANSMISSION_MODE_2K;
-               break;
-       case TRANS_MODE_8K:
-               fe_tps->transmission_mode = TRANSMISSION_MODE_8K;
-               break;
-       }
-}
-
-static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg)
-{
-       uint8_t c;
-
-       switch (arg) {
-       case FEC_1_2:
-               c = CODE_RATE_1_2;
-               break;
-       case FEC_2_3:
-               c = CODE_RATE_2_3;
-               break;
-       case FEC_3_4:
-               c = CODE_RATE_3_4;
-               break;
-       case FEC_5_6:
-               c = CODE_RATE_5_6;
-               break;
-       case FEC_7_8:
-               c = CODE_RATE_7_8;
-               break;
-       default:
-               c = CODE_RATE_UNKNOWN;
-               break;
-       }
-
-       return c;
-}
-
-static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args,
-                         struct dtv_frontend_properties *params)
-{
-
-       /* set frequency */
-       tune_args->freq = params->frequency / 1000;
-
-       /* fix interleaving_mode */
-       tune_args->interleaving_mode = INTLV_NATIVE;
-
-       switch (params->bandwidth_hz) {
-       case 8000000:
-               tune_args->bandwidth = BW_8_MHZ;
-               break;
-       case 7000000:
-               tune_args->bandwidth = BW_7_MHZ;
-               break;
-       case 6000000:
-               tune_args->bandwidth = BW_6_MHZ;
-               break;
-       default:
-               tune_args->bandwidth = BW_8_MHZ;
-       }
-
-       switch (params->guard_interval) {
-       case GUARD_INTERVAL_1_32:
-               tune_args->guard_interval = GUARD_INT_1_32;
-               break;
-       case GUARD_INTERVAL_1_16:
-               tune_args->guard_interval = GUARD_INT_1_16;
-               break;
-       case GUARD_INTERVAL_1_8:
-               tune_args->guard_interval = GUARD_INT_1_8;
-               break;
-       case GUARD_INTERVAL_1_4:
-               tune_args->guard_interval = GUARD_INT_1_4;
-               break;
-       case GUARD_INTERVAL_AUTO:
-       default:
-               tune_args->guard_interval = GUARD_UNKNOWN;
-               break;
-       }
-
-       switch (params->modulation) {
-       case QPSK:
-               tune_args->modulation = CONST_QPSK;
-               break;
-       case QAM_16:
-               tune_args->modulation = CONST_QAM16;
-               break;
-       case QAM_64:
-               tune_args->modulation = CONST_QAM64;
-               break;
-       default:
-               tune_args->modulation = CONST_UNKNOWN;
-               break;
-       }
-
-       switch (params->transmission_mode) {
-       case TRANSMISSION_MODE_2K:
-               tune_args->transmission_mode = TRANS_MODE_2K;
-               break;
-       case TRANSMISSION_MODE_8K:
-               tune_args->transmission_mode = TRANS_MODE_8K;
-               break;
-       default:
-               tune_args->transmission_mode = TRANS_MODE_UNKNOWN;
-       }
-
-       switch (params->hierarchy) {
-       case HIERARCHY_NONE:
-               tune_args->hierarchy = HIER_NONE;
-               break;
-       case HIERARCHY_1:
-               tune_args->hierarchy = HIER_ALPHA_1;
-               break;
-       case HIERARCHY_2:
-               tune_args->hierarchy = HIER_ALPHA_2;
-               break;
-       case HIERARCHY_4:
-               tune_args->hierarchy = HIER_ALPHA_4;
-               break;
-       case HIERARCHY_AUTO:
-               tune_args->hierarchy = HIER_UNKNOWN;
-               break;
-       }
-
-       dprintk(debug, "tuner parameters: freq: %d  bw: 0x%02x  gi: 0x%02x\n",
-                       params->frequency,
-                       tune_args->bandwidth,
-                       tune_args->guard_interval);
-
-       /*
-        * Detect a hierarchy selection
-        * if HP/LP are both set to FEC_NONE, HP will be selected.
-        */
-       if ((tune_args->hierarchy != HIER_NONE) &&
-                      ((params->code_rate_LP == FEC_NONE) ||
-                       (params->code_rate_HP == FEC_NONE))) {
-
-               if (params->code_rate_LP == FEC_NONE) {
-                       tune_args->hier_select = HIER_HIGH_PRIORITY;
-                       tune_args->code_rate =
-                          as102_fe_get_code_rate(params->code_rate_HP);
-               }
-
-               if (params->code_rate_HP == FEC_NONE) {
-                       tune_args->hier_select = HIER_LOW_PRIORITY;
-                       tune_args->code_rate =
-                          as102_fe_get_code_rate(params->code_rate_LP);
-               }
-
-               dprintk(debug,
-                       "\thierarchy: 0x%02x  selected: %s  code_rate_%s: 0x%02x\n",
-                       tune_args->hierarchy,
-                       tune_args->hier_select == HIER_HIGH_PRIORITY ?
-                       "HP" : "LP",
-                       tune_args->hier_select == HIER_HIGH_PRIORITY ?
-                       "HP" : "LP",
-                       tune_args->code_rate);
-       } else {
-               tune_args->code_rate =
-                       as102_fe_get_code_rate(params->code_rate_HP);
-       }
-}
diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c
deleted file mode 100644 (file)
index f33f752..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/ctype.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-
-#include "as102_drv.h"
-#include "as102_fw.h"
-
-static const char as102_st_fw1[] = "as102_data1_st.hex";
-static const char as102_st_fw2[] = "as102_data2_st.hex";
-static const char as102_dt_fw1[] = "as102_data1_dt.hex";
-static const char as102_dt_fw2[] = "as102_data2_dt.hex";
-
-static unsigned char atohx(unsigned char *dst, char *src)
-{
-       unsigned char value = 0;
-
-       char msb = tolower(*src) - '0';
-       char lsb = tolower(*(src + 1)) - '0';
-
-       if (msb > 9)
-               msb -= 7;
-       if (lsb > 9)
-               lsb -= 7;
-
-       *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
-       return value;
-}
-
-/*
- * Parse INTEL HEX firmware file to extract address and data.
- */
-static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
-                         unsigned char *data, int *dataLength,
-                         unsigned char *addr_has_changed) {
-
-       int count = 0;
-       unsigned char *src, dst;
-
-       if (*fw_data++ != ':') {
-               pr_err("invalid firmware file\n");
-               return -EFAULT;
-       }
-
-       /* locate end of line */
-       for (src = fw_data; *src != '\n'; src += 2) {
-               atohx(&dst, src);
-               /* parse line to split addr / data */
-               switch (count) {
-               case 0:
-                       *dataLength = dst;
-                       break;
-               case 1:
-                       addr[2] = dst;
-                       break;
-               case 2:
-                       addr[3] = dst;
-                       break;
-               case 3:
-                       /* check if data is an address */
-                       if (dst == 0x04)
-                               *addr_has_changed = 1;
-                       else
-                               *addr_has_changed = 0;
-                       break;
-               case  4:
-               case  5:
-                       if (*addr_has_changed)
-                               addr[(count - 4)] = dst;
-                       else
-                               data[(count - 4)] = dst;
-                       break;
-               default:
-                       data[(count - 4)] = dst;
-                       break;
-               }
-               count++;
-       }
-
-       /* return read value + ':' + '\n' */
-       return (count * 2) + 2;
-}
-
-static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
-                                unsigned char *cmd,
-                                const struct firmware *firmware) {
-
-       struct as10x_fw_pkt_t fw_pkt;
-       int total_read_bytes = 0, errno = 0;
-       unsigned char addr_has_changed = 0;
-
-       for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
-               int read_bytes = 0, data_len = 0;
-
-               /* parse intel hex line */
-               read_bytes = parse_hex_line(
-                               (u8 *) (firmware->data + total_read_bytes),
-                               fw_pkt.raw.address,
-                               fw_pkt.raw.data,
-                               &data_len,
-                               &addr_has_changed);
-
-               if (read_bytes <= 0)
-                       goto error;
-
-               /* detect the end of file */
-               total_read_bytes += read_bytes;
-               if (total_read_bytes == firmware->size) {
-                       fw_pkt.u.request[0] = 0x00;
-                       fw_pkt.u.request[1] = 0x03;
-
-                       /* send EOF command */
-                       errno = bus_adap->ops->upload_fw_pkt(bus_adap,
-                                                            (uint8_t *)
-                                                            &fw_pkt, 2, 0);
-                       if (errno < 0)
-                               goto error;
-               } else {
-                       if (!addr_has_changed) {
-                               /* prepare command to send */
-                               fw_pkt.u.request[0] = 0x00;
-                               fw_pkt.u.request[1] = 0x01;
-
-                               data_len += sizeof(fw_pkt.u.request);
-                               data_len += sizeof(fw_pkt.raw.address);
-
-                               /* send cmd to device */
-                               errno = bus_adap->ops->upload_fw_pkt(bus_adap,
-                                                                    (uint8_t *)
-                                                                    &fw_pkt,
-                                                                    data_len,
-                                                                    0);
-                               if (errno < 0)
-                                       goto error;
-                       }
-               }
-       }
-error:
-       return (errno == 0) ? total_read_bytes : errno;
-}
-
-int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
-{
-       int errno = -EFAULT;
-       const struct firmware *firmware = NULL;
-       unsigned char *cmd_buf = NULL;
-       const char *fw1, *fw2;
-       struct usb_device *dev = bus_adap->usb_dev;
-
-       /* select fw file to upload */
-       if (dual_tuner) {
-               fw1 = as102_dt_fw1;
-               fw2 = as102_dt_fw2;
-       } else {
-               fw1 = as102_st_fw1;
-               fw2 = as102_st_fw2;
-       }
-
-       /* allocate buffer to store firmware upload command and data */
-       cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
-       if (cmd_buf == NULL) {
-               errno = -ENOMEM;
-               goto error;
-       }
-
-       /* request kernel to locate firmware file: part1 */
-       errno = request_firmware(&firmware, fw1, &dev->dev);
-       if (errno < 0) {
-               pr_err("%s: unable to locate firmware file: %s\n",
-                      DRIVER_NAME, fw1);
-               goto error;
-       }
-
-       /* initiate firmware upload */
-       errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
-       if (errno < 0) {
-               pr_err("%s: error during firmware upload part1\n",
-                      DRIVER_NAME);
-               goto error;
-       }
-
-       pr_info("%s: firmware: %s loaded with success\n",
-               DRIVER_NAME, fw1);
-       release_firmware(firmware);
-
-       /* wait for boot to complete */
-       mdelay(100);
-
-       /* request kernel to locate firmware file: part2 */
-       errno = request_firmware(&firmware, fw2, &dev->dev);
-       if (errno < 0) {
-               pr_err("%s: unable to locate firmware file: %s\n",
-                      DRIVER_NAME, fw2);
-               goto error;
-       }
-
-       /* initiate firmware upload */
-       errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
-       if (errno < 0) {
-               pr_err("%s: error during firmware upload part2\n",
-                      DRIVER_NAME);
-               goto error;
-       }
-
-       pr_info("%s: firmware: %s loaded with success\n",
-               DRIVER_NAME, fw2);
-error:
-       kfree(cmd_buf);
-       release_firmware(firmware);
-
-       return errno;
-}
diff --git a/drivers/staging/media/as102/as102_fw.h b/drivers/staging/media/as102/as102_fw.h
deleted file mode 100644 (file)
index 4bfc684..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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.
- */
-#define MAX_FW_PKT_SIZE        64
-
-extern int dual_tuner;
-
-struct as10x_raw_fw_pkt {
-       unsigned char address[4];
-       unsigned char data[MAX_FW_PKT_SIZE - 6];
-} __packed;
-
-struct as10x_fw_pkt_t {
-       union {
-               unsigned char request[2];
-               unsigned char length[2];
-       } __packed u;
-       struct as10x_raw_fw_pkt raw;
-} __packed;
-
-#ifdef __KERNEL__
-int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap);
-#endif
diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c
deleted file mode 100644 (file)
index e6f6278..0000000
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/usb.h>
-
-#include "as102_drv.h"
-#include "as102_usb_drv.h"
-#include "as102_fw.h"
-
-static void as102_usb_disconnect(struct usb_interface *interface);
-static int as102_usb_probe(struct usb_interface *interface,
-                          const struct usb_device_id *id);
-
-static int as102_usb_start_stream(struct as102_dev_t *dev);
-static void as102_usb_stop_stream(struct as102_dev_t *dev);
-
-static int as102_open(struct inode *inode, struct file *file);
-static int as102_release(struct inode *inode, struct file *file);
-
-static struct usb_device_id as102_usb_id_table[] = {
-       { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) },
-       { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) },
-       { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) },
-       { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) },
-       { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) },
-       { } /* Terminating entry */
-};
-
-/* Note that this table must always have the same number of entries as the
-   as102_usb_id_table struct */
-static const char * const as102_device_names[] = {
-       AS102_REFERENCE_DESIGN,
-       AS102_PCTV_74E,
-       AS102_ELGATO_EYETV_DTT_NAME,
-       AS102_NBOX_DVBT_DONGLE_NAME,
-       AS102_SKY_IT_DIGITAL_KEY_NAME,
-       NULL /* Terminating entry */
-};
-
-/* eLNA configuration: devices built on the reference design work best
-   with 0xA0, while custom designs seem to require 0xC0 */
-static uint8_t const as102_elna_cfg[] = {
-       0xA0,
-       0xC0,
-       0xC0,
-       0xA0,
-       0xA0,
-       0x00 /* Terminating entry */
-};
-
-struct usb_driver as102_usb_driver = {
-       .name           = DRIVER_FULL_NAME,
-       .probe          = as102_usb_probe,
-       .disconnect     = as102_usb_disconnect,
-       .id_table       = as102_usb_id_table
-};
-
-static const struct file_operations as102_dev_fops = {
-       .owner          = THIS_MODULE,
-       .open           = as102_open,
-       .release        = as102_release,
-};
-
-static struct usb_class_driver as102_usb_class_driver = {
-       .name           = "aton2-%d",
-       .fops           = &as102_dev_fops,
-       .minor_base     = AS102_DEVICE_MAJOR,
-};
-
-static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap,
-                             unsigned char *send_buf, int send_buf_len,
-                             unsigned char *recv_buf, int recv_buf_len)
-{
-       int ret = 0;
-
-       if (send_buf != NULL) {
-               ret = usb_control_msg(bus_adap->usb_dev,
-                                     usb_sndctrlpipe(bus_adap->usb_dev, 0),
-                                     AS102_USB_DEVICE_TX_CTRL_CMD,
-                                     USB_DIR_OUT | USB_TYPE_VENDOR |
-                                     USB_RECIP_DEVICE,
-                                     bus_adap->cmd_xid, /* value */
-                                     0, /* index */
-                                     send_buf, send_buf_len,
-                                     USB_CTRL_SET_TIMEOUT /* 200 */);
-               if (ret < 0) {
-                       dprintk(debug, "usb_control_msg(send) failed, err %i\n",
-                                       ret);
-                       return ret;
-               }
-
-               if (ret != send_buf_len) {
-                       dprintk(debug, "only wrote %d of %d bytes\n",
-                                       ret, send_buf_len);
-                       return -1;
-               }
-       }
-
-       if (recv_buf != NULL) {
-#ifdef TRACE
-               dprintk(debug, "want to read: %d bytes\n", recv_buf_len);
-#endif
-               ret = usb_control_msg(bus_adap->usb_dev,
-                                     usb_rcvctrlpipe(bus_adap->usb_dev, 0),
-                                     AS102_USB_DEVICE_RX_CTRL_CMD,
-                                     USB_DIR_IN | USB_TYPE_VENDOR |
-                                     USB_RECIP_DEVICE,
-                                     bus_adap->cmd_xid, /* value */
-                                     0, /* index */
-                                     recv_buf, recv_buf_len,
-                                     USB_CTRL_GET_TIMEOUT /* 200 */);
-               if (ret < 0) {
-                       dprintk(debug, "usb_control_msg(recv) failed, err %i\n",
-                                       ret);
-                       return ret;
-               }
-#ifdef TRACE
-               dprintk(debug, "read %d bytes\n", recv_buf_len);
-#endif
-       }
-
-       return ret;
-}
-
-static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap,
-                         unsigned char *send_buf,
-                         int send_buf_len,
-                         int swap32)
-{
-       int ret = 0, actual_len;
-
-       ret = usb_bulk_msg(bus_adap->usb_dev,
-                          usb_sndbulkpipe(bus_adap->usb_dev, 1),
-                          send_buf, send_buf_len, &actual_len, 200);
-       if (ret) {
-               dprintk(debug, "usb_bulk_msg(send) failed, err %i\n", ret);
-               return ret;
-       }
-
-       if (actual_len != send_buf_len) {
-               dprintk(debug, "only wrote %d of %d bytes\n",
-                               actual_len, send_buf_len);
-               return -1;
-       }
-       return ret ? ret : actual_len;
-}
-
-static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap,
-                  unsigned char *recv_buf, int recv_buf_len)
-{
-       int ret = 0, actual_len;
-
-       if (recv_buf == NULL)
-               return -EINVAL;
-
-       ret = usb_bulk_msg(bus_adap->usb_dev,
-                          usb_rcvbulkpipe(bus_adap->usb_dev, 2),
-                          recv_buf, recv_buf_len, &actual_len, 200);
-       if (ret) {
-               dprintk(debug, "usb_bulk_msg(recv) failed, err %i\n", ret);
-               return ret;
-       }
-
-       if (actual_len != recv_buf_len) {
-               dprintk(debug, "only read %d of %d bytes\n",
-                               actual_len, recv_buf_len);
-               return -1;
-       }
-       return ret ? ret : actual_len;
-}
-
-static struct as102_priv_ops_t as102_priv_ops = {
-       .upload_fw_pkt  = as102_send_ep1,
-       .xfer_cmd       = as102_usb_xfer_cmd,
-       .as102_read_ep2 = as102_read_ep2,
-       .start_stream   = as102_usb_start_stream,
-       .stop_stream    = as102_usb_stop_stream,
-};
-
-static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb)
-{
-       int err;
-
-       usb_fill_bulk_urb(urb,
-                         dev->bus_adap.usb_dev,
-                         usb_rcvbulkpipe(dev->bus_adap.usb_dev, 0x2),
-                         urb->transfer_buffer,
-                         AS102_USB_BUF_SIZE,
-                         as102_urb_stream_irq,
-                         dev);
-
-       err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (err)
-               dprintk(debug, "%s: usb_submit_urb failed\n", __func__);
-
-       return err;
-}
-
-void as102_urb_stream_irq(struct urb *urb)
-{
-       struct as102_dev_t *as102_dev = urb->context;
-
-       if (urb->actual_length > 0) {
-               dvb_dmx_swfilter(&as102_dev->dvb_dmx,
-                                urb->transfer_buffer,
-                                urb->actual_length);
-       } else {
-               if (urb->actual_length == 0)
-                       memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE);
-       }
-
-       /* is not stopped, re-submit urb */
-       if (as102_dev->streaming)
-               as102_submit_urb_stream(as102_dev, urb);
-}
-
-static void as102_free_usb_stream_buffer(struct as102_dev_t *dev)
-{
-       int i;
-
-       for (i = 0; i < MAX_STREAM_URB; i++)
-               usb_free_urb(dev->stream_urb[i]);
-
-       usb_free_coherent(dev->bus_adap.usb_dev,
-                       MAX_STREAM_URB * AS102_USB_BUF_SIZE,
-                       dev->stream,
-                       dev->dma_addr);
-}
-
-static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev)
-{
-       int i;
-
-       dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev,
-                                      MAX_STREAM_URB * AS102_USB_BUF_SIZE,
-                                      GFP_KERNEL,
-                                      &dev->dma_addr);
-       if (!dev->stream) {
-               dprintk(debug, "%s: usb_buffer_alloc failed\n", __func__);
-               return -ENOMEM;
-       }
-
-       memset(dev->stream, 0, MAX_STREAM_URB * AS102_USB_BUF_SIZE);
-
-       /* init urb buffers */
-       for (i = 0; i < MAX_STREAM_URB; i++) {
-               struct urb *urb;
-
-               urb = usb_alloc_urb(0, GFP_ATOMIC);
-               if (urb == NULL) {
-                       dprintk(debug, "%s: usb_alloc_urb failed\n", __func__);
-                       as102_free_usb_stream_buffer(dev);
-                       return -ENOMEM;
-               }
-
-               urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE);
-               urb->transfer_dma = dev->dma_addr + (i * AS102_USB_BUF_SIZE);
-               urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
-               urb->transfer_buffer_length = AS102_USB_BUF_SIZE;
-
-               dev->stream_urb[i] = urb;
-       }
-       return 0;
-}
-
-static void as102_usb_stop_stream(struct as102_dev_t *dev)
-{
-       int i;
-
-       for (i = 0; i < MAX_STREAM_URB; i++)
-               usb_kill_urb(dev->stream_urb[i]);
-}
-
-static int as102_usb_start_stream(struct as102_dev_t *dev)
-{
-       int i, ret = 0;
-
-       for (i = 0; i < MAX_STREAM_URB; i++) {
-               ret = as102_submit_urb_stream(dev, dev->stream_urb[i]);
-               if (ret) {
-                       as102_usb_stop_stream(dev);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-static void as102_usb_release(struct kref *kref)
-{
-       struct as102_dev_t *as102_dev;
-
-       as102_dev = container_of(kref, struct as102_dev_t, kref);
-       if (as102_dev != NULL) {
-               usb_put_dev(as102_dev->bus_adap.usb_dev);
-               kfree(as102_dev);
-       }
-}
-
-static void as102_usb_disconnect(struct usb_interface *intf)
-{
-       struct as102_dev_t *as102_dev;
-
-       /* extract as102_dev_t from usb_device private data */
-       as102_dev = usb_get_intfdata(intf);
-
-       /* unregister dvb layer */
-       as102_dvb_unregister(as102_dev);
-
-       /* free usb buffers */
-       as102_free_usb_stream_buffer(as102_dev);
-
-       usb_set_intfdata(intf, NULL);
-
-       /* usb unregister device */
-       usb_deregister_dev(intf, &as102_usb_class_driver);
-
-       /* decrement usage counter */
-       kref_put(&as102_dev->kref, as102_usb_release);
-
-       pr_info("%s: device has been disconnected\n", DRIVER_NAME);
-}
-
-static int as102_usb_probe(struct usb_interface *intf,
-                          const struct usb_device_id *id)
-{
-       int ret;
-       struct as102_dev_t *as102_dev;
-       int i;
-
-       /* This should never actually happen */
-       if (ARRAY_SIZE(as102_usb_id_table) !=
-           (sizeof(as102_device_names) / sizeof(const char *))) {
-               pr_err("Device names table invalid size");
-               return -EINVAL;
-       }
-
-       as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL);
-       if (as102_dev == NULL)
-               return -ENOMEM;
-
-       /* Assign the user-friendly device name */
-       for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) {
-               if (id == &as102_usb_id_table[i]) {
-                       as102_dev->name = as102_device_names[i];
-                       as102_dev->elna_cfg = as102_elna_cfg[i];
-               }
-       }
-
-       if (as102_dev->name == NULL)
-               as102_dev->name = "Unknown AS102 device";
-
-       /* set private callback functions */
-       as102_dev->bus_adap.ops = &as102_priv_ops;
-
-       /* init cmd token for usb bus */
-       as102_dev->bus_adap.cmd = &as102_dev->bus_adap.token.usb.c;
-       as102_dev->bus_adap.rsp = &as102_dev->bus_adap.token.usb.r;
-
-       /* init kernel device reference */
-       kref_init(&as102_dev->kref);
-
-       /* store as102 device to usb_device private data */
-       usb_set_intfdata(intf, (void *) as102_dev);
-
-       /* store in as102 device the usb_device pointer */
-       as102_dev->bus_adap.usb_dev = usb_get_dev(interface_to_usbdev(intf));
-
-       /* we can register the device now, as it is ready */
-       ret = usb_register_dev(intf, &as102_usb_class_driver);
-       if (ret < 0) {
-               /* something prevented us from registering this driver */
-               dev_err(&intf->dev,
-                       "%s: usb_register_dev() failed (errno = %d)\n",
-                       __func__, ret);
-               goto failed;
-       }
-
-       pr_info("%s: device has been detected\n", DRIVER_NAME);
-
-       /* request buffer allocation for streaming */
-       ret = as102_alloc_usb_stream_buffer(as102_dev);
-       if (ret != 0)
-               goto failed_stream;
-
-       /* register dvb layer */
-       ret = as102_dvb_register(as102_dev);
-       if (ret != 0)
-               goto failed_dvb;
-
-       return ret;
-
-failed_dvb:
-       as102_free_usb_stream_buffer(as102_dev);
-failed_stream:
-       usb_deregister_dev(intf, &as102_usb_class_driver);
-failed:
-       usb_put_dev(as102_dev->bus_adap.usb_dev);
-       usb_set_intfdata(intf, NULL);
-       kfree(as102_dev);
-       return ret;
-}
-
-static int as102_open(struct inode *inode, struct file *file)
-{
-       int ret = 0, minor = 0;
-       struct usb_interface *intf = NULL;
-       struct as102_dev_t *dev = NULL;
-
-       /* read minor from inode */
-       minor = iminor(inode);
-
-       /* fetch device from usb interface */
-       intf = usb_find_interface(&as102_usb_driver, minor);
-       if (intf == NULL) {
-               pr_err("%s: can't find device for minor %d\n",
-                      __func__, minor);
-               ret = -ENODEV;
-               goto exit;
-       }
-
-       /* get our device */
-       dev = usb_get_intfdata(intf);
-       if (dev == NULL) {
-               ret = -EFAULT;
-               goto exit;
-       }
-
-       /* save our device object in the file's private structure */
-       file->private_data = dev;
-
-       /* increment our usage count for the device */
-       kref_get(&dev->kref);
-
-exit:
-       return ret;
-}
-
-static int as102_release(struct inode *inode, struct file *file)
-{
-       struct as102_dev_t *dev = NULL;
-
-       dev = file->private_data;
-       if (dev != NULL) {
-               /* decrement the count on our device */
-               kref_put(&dev->kref, as102_usb_release);
-       }
-
-       return 0;
-}
-
-MODULE_DEVICE_TABLE(usb, as102_usb_id_table);
diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h
deleted file mode 100644 (file)
index 1ad1ec5..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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 _AS102_USB_DRV_H_
-#define _AS102_USB_DRV_H_
-
-#define AS102_USB_DEVICE_TX_CTRL_CMD   0xF1
-#define AS102_USB_DEVICE_RX_CTRL_CMD   0xF2
-
-/* define these values to match the supported devices */
-
-/* Abilis system: "TITAN" */
-#define AS102_REFERENCE_DESIGN         "Abilis Systems DVB-Titan"
-#define AS102_USB_DEVICE_VENDOR_ID     0x1BA6
-#define AS102_USB_DEVICE_PID_0001      0x0001
-
-/* PCTV Systems: PCTV picoStick (74e) */
-#define AS102_PCTV_74E                 "PCTV Systems picoStick (74e)"
-#define PCTV_74E_USB_VID               0x2013
-#define PCTV_74E_USB_PID               0x0246
-
-/* Elgato: EyeTV DTT Deluxe */
-#define AS102_ELGATO_EYETV_DTT_NAME    "Elgato EyeTV DTT Deluxe"
-#define ELGATO_EYETV_DTT_USB_VID       0x0fd9
-#define ELGATO_EYETV_DTT_USB_PID       0x002c
-
-/* nBox: nBox DVB-T Dongle */
-#define AS102_NBOX_DVBT_DONGLE_NAME    "nBox DVB-T Dongle"
-#define NBOX_DVBT_DONGLE_USB_VID       0x0b89
-#define NBOX_DVBT_DONGLE_USB_PID       0x0007
-
-/* Sky Italia: Digital Key (green led) */
-#define AS102_SKY_IT_DIGITAL_KEY_NAME  "Sky IT Digital Key (green led)"
-#define SKY_IT_DIGITAL_KEY_USB_VID     0x2137
-#define SKY_IT_DIGITAL_KEY_USB_PID     0x0001
-
-void as102_urb_stream_irq(struct urb *urb);
-
-struct as10x_usb_token_cmd_t {
-       /* token cmd */
-       struct as10x_cmd_t c;
-       /* token response */
-       struct as10x_cmd_t r;
-};
-#endif
diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/staging/media/as102/as10x_cmd.c
deleted file mode 100644 (file)
index 9e49f15..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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 "as102_drv.h"
-#include "as10x_types.h"
-#include "as10x_cmd.h"
-
-/**
- * as10x_cmd_turn_on - send turn on command to AS10x
- * @adap:   pointer to AS10x bus adapter
- *
- * Return 0 when no error, < 0 in case of error.
- */
-int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.turn_on.req));
-
-       /* fill command */
-       pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
-                                           sizeof(pcmd->body.turn_on.req) +
-                                           HEADER_SIZE,
-                                           (uint8_t *) prsp,
-                                           sizeof(prsp->body.turn_on.rsp) +
-                                           HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_turn_off - send turn off command to AS10x
- * @adap:   pointer to AS10x bus adapter
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.turn_off.req));
-
-       /* fill command */
-       pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(
-                       adap, (uint8_t *) pcmd,
-                       sizeof(pcmd->body.turn_off.req) + HEADER_SIZE,
-                       (uint8_t *) prsp,
-                       sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_set_tune - send set tune command to AS10x
- * @adap:    pointer to AS10x bus adapter
- * @ptune:   tune parameters
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
-                      struct as10x_tune_args *ptune)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t *preq, *prsp;
-
-       preq = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(preq, (++adap->cmd_xid),
-                       sizeof(preq->body.set_tune.req));
-
-       /* fill command */
-       preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE);
-       preq->body.set_tune.req.args.freq = cpu_to_le32(ptune->freq);
-       preq->body.set_tune.req.args.bandwidth = ptune->bandwidth;
-       preq->body.set_tune.req.args.hier_select = ptune->hier_select;
-       preq->body.set_tune.req.args.modulation = ptune->modulation;
-       preq->body.set_tune.req.args.hierarchy = ptune->hierarchy;
-       preq->body.set_tune.req.args.interleaving_mode  =
-               ptune->interleaving_mode;
-       preq->body.set_tune.req.args.code_rate  = ptune->code_rate;
-       preq->body.set_tune.req.args.guard_interval = ptune->guard_interval;
-       preq->body.set_tune.req.args.transmission_mode  =
-               ptune->transmission_mode;
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap,
-                                           (uint8_t *) preq,
-                                           sizeof(preq->body.set_tune.req)
-                                           + HEADER_SIZE,
-                                           (uint8_t *) prsp,
-                                           sizeof(prsp->body.set_tune.rsp)
-                                           + HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_get_tune_status - send get tune status command to AS10x
- * @adap: pointer to AS10x bus adapter
- * @pstatus: pointer to updated status structure of the current tune
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
-                             struct as10x_tune_status *pstatus)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t  *preq, *prsp;
-
-       preq = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(preq, (++adap->cmd_xid),
-                       sizeof(preq->body.get_tune_status.req));
-
-       /* fill command */
-       preq->body.get_tune_status.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_GETTUNESTAT);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(
-                       adap,
-                       (uint8_t *) preq,
-                       sizeof(preq->body.get_tune_status.req) + HEADER_SIZE,
-                       (uint8_t *) prsp,
-                       sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTUNESTAT_RSP);
-       if (error < 0)
-               goto out;
-
-       /* Response OK -> get response data */
-       pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state;
-       pstatus->signal_strength  =
-               le16_to_cpu(prsp->body.get_tune_status.rsp.sts.signal_strength);
-       pstatus->PER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.PER);
-       pstatus->BER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.BER);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_get_tps - send get TPS command to AS10x
- * @adap:      pointer to AS10x handle
- * @ptps:      pointer to TPS parameters structure
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.get_tps.req));
-
-       /* fill command */
-       pcmd->body.get_tune_status.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_GETTPS);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap,
-                                           (uint8_t *) pcmd,
-                                           sizeof(pcmd->body.get_tps.req) +
-                                           HEADER_SIZE,
-                                           (uint8_t *) prsp,
-                                           sizeof(prsp->body.get_tps.rsp) +
-                                           HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTPS_RSP);
-       if (error < 0)
-               goto out;
-
-       /* Response OK -> get response data */
-       ptps->modulation = prsp->body.get_tps.rsp.tps.modulation;
-       ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy;
-       ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode;
-       ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP;
-       ptps->code_rate_LP = prsp->body.get_tps.rsp.tps.code_rate_LP;
-       ptps->guard_interval = prsp->body.get_tps.rsp.tps.guard_interval;
-       ptps->transmission_mode  = prsp->body.get_tps.rsp.tps.transmission_mode;
-       ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP;
-       ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP;
-       ptps->cell_ID = le16_to_cpu(prsp->body.get_tps.rsp.tps.cell_ID);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_get_demod_stats - send get demod stats command to AS10x
- * @adap:          pointer to AS10x bus adapter
- * @pdemod_stats:  pointer to demod stats parameters structure
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap,
-                             struct as10x_demod_stats *pdemod_stats)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.get_demod_stats.req));
-
-       /* fill command */
-       pcmd->body.get_demod_stats.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap,
-                               (uint8_t *) pcmd,
-                               sizeof(pcmd->body.get_demod_stats.req)
-                               + HEADER_SIZE,
-                               (uint8_t *) prsp,
-                               sizeof(prsp->body.get_demod_stats.rsp)
-                               + HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_DEMOD_STATS_RSP);
-       if (error < 0)
-               goto out;
-
-       /* Response OK -> get response data */
-       pdemod_stats->frame_count =
-               le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.frame_count);
-       pdemod_stats->bad_frame_count =
-               le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bad_frame_count);
-       pdemod_stats->bytes_fixed_by_rs =
-               le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs);
-       pdemod_stats->mer =
-               le16_to_cpu(prsp->body.get_demod_stats.rsp.stats.mer);
-       pdemod_stats->has_started =
-               prsp->body.get_demod_stats.rsp.stats.has_started;
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x
- * @adap:     pointer to AS10x bus adapter
- * @is_ready: pointer to value indicating when impulse
- *           response data is ready
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
-                              uint8_t *is_ready)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.get_impulse_rsp.req));
-
-       /* fill command */
-       pcmd->body.get_impulse_rsp.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap,
-                                       (uint8_t *) pcmd,
-                                       sizeof(pcmd->body.get_impulse_rsp.req)
-                                       + HEADER_SIZE,
-                                       (uint8_t *) prsp,
-                                       sizeof(prsp->body.get_impulse_rsp.rsp)
-                                       + HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_IMPULSE_RESP_RSP);
-       if (error < 0)
-               goto out;
-
-       /* Response OK -> get response data */
-       *is_ready = prsp->body.get_impulse_rsp.rsp.is_ready;
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_build - build AS10x command header
- * @pcmd:     pointer to AS10x command buffer
- * @xid:      sequence id of the command
- * @cmd_len:  length of the command
- */
-void as10x_cmd_build(struct as10x_cmd_t *pcmd,
-                    uint16_t xid, uint16_t cmd_len)
-{
-       pcmd->header.req_id = cpu_to_le16(xid);
-       pcmd->header.prog = cpu_to_le16(SERVICE_PROG_ID);
-       pcmd->header.version = cpu_to_le16(SERVICE_PROG_VERSION);
-       pcmd->header.data_len = cpu_to_le16(cmd_len);
-}
-
-/**
- * as10x_rsp_parse - Parse command response
- * @prsp:       pointer to AS10x command buffer
- * @proc_id:    id of the command
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id)
-{
-       int error;
-
-       /* extract command error code */
-       error = prsp->body.common.rsp.error;
-
-       if ((error == 0) &&
-           (le16_to_cpu(prsp->body.common.rsp.proc_id) == proc_id)) {
-               return 0;
-       }
-
-       return AS10X_CMD_ERROR;
-}
diff --git a/drivers/staging/media/as102/as10x_cmd.h b/drivers/staging/media/as102/as10x_cmd.h
deleted file mode 100644 (file)
index e21ec6c..0000000
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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 _AS10X_CMD_H_
-#define _AS10X_CMD_H_
-
-#ifdef __KERNEL__
-#include <linux/kernel.h>
-#endif
-
-#include "as10x_types.h"
-
-/*********************************/
-/*       MACRO DEFINITIONS       */
-/*********************************/
-#define AS10X_CMD_ERROR                -1
-
-#define SERVICE_PROG_ID                0x0002
-#define SERVICE_PROG_VERSION   0x0001
-
-#define HIER_NONE              0x00
-#define HIER_LOW_PRIORITY      0x01
-
-#define HEADER_SIZE (sizeof(struct as10x_cmd_header_t))
-
-/* context request types */
-#define GET_CONTEXT_DATA       1
-#define SET_CONTEXT_DATA       2
-
-/* ODSP suspend modes */
-#define CFG_MODE_ODSP_RESUME   0
-#define CFG_MODE_ODSP_SUSPEND  1
-
-/* Dump memory size */
-#define DUMP_BLOCK_SIZE_MAX    0x20
-
-/*********************************/
-/*     TYPE DEFINITION           */
-/*********************************/
-enum control_proc {
-       CONTROL_PROC_TURNON                     = 0x0001,
-       CONTROL_PROC_TURNON_RSP                 = 0x0100,
-       CONTROL_PROC_SET_REGISTER               = 0x0002,
-       CONTROL_PROC_SET_REGISTER_RSP           = 0x0200,
-       CONTROL_PROC_GET_REGISTER               = 0x0003,
-       CONTROL_PROC_GET_REGISTER_RSP           = 0x0300,
-       CONTROL_PROC_SETTUNE                    = 0x000A,
-       CONTROL_PROC_SETTUNE_RSP                = 0x0A00,
-       CONTROL_PROC_GETTUNESTAT                = 0x000B,
-       CONTROL_PROC_GETTUNESTAT_RSP            = 0x0B00,
-       CONTROL_PROC_GETTPS                     = 0x000D,
-       CONTROL_PROC_GETTPS_RSP                 = 0x0D00,
-       CONTROL_PROC_SETFILTER                  = 0x000E,
-       CONTROL_PROC_SETFILTER_RSP              = 0x0E00,
-       CONTROL_PROC_REMOVEFILTER               = 0x000F,
-       CONTROL_PROC_REMOVEFILTER_RSP           = 0x0F00,
-       CONTROL_PROC_GET_IMPULSE_RESP           = 0x0012,
-       CONTROL_PROC_GET_IMPULSE_RESP_RSP       = 0x1200,
-       CONTROL_PROC_START_STREAMING            = 0x0013,
-       CONTROL_PROC_START_STREAMING_RSP        = 0x1300,
-       CONTROL_PROC_STOP_STREAMING             = 0x0014,
-       CONTROL_PROC_STOP_STREAMING_RSP         = 0x1400,
-       CONTROL_PROC_GET_DEMOD_STATS            = 0x0015,
-       CONTROL_PROC_GET_DEMOD_STATS_RSP        = 0x1500,
-       CONTROL_PROC_ELNA_CHANGE_MODE           = 0x0016,
-       CONTROL_PROC_ELNA_CHANGE_MODE_RSP       = 0x1600,
-       CONTROL_PROC_ODSP_CHANGE_MODE           = 0x0017,
-       CONTROL_PROC_ODSP_CHANGE_MODE_RSP       = 0x1700,
-       CONTROL_PROC_AGC_CHANGE_MODE            = 0x0018,
-       CONTROL_PROC_AGC_CHANGE_MODE_RSP        = 0x1800,
-
-       CONTROL_PROC_CONTEXT                    = 0x00FC,
-       CONTROL_PROC_CONTEXT_RSP                = 0xFC00,
-       CONTROL_PROC_DUMP_MEMORY                = 0x00FD,
-       CONTROL_PROC_DUMP_MEMORY_RSP            = 0xFD00,
-       CONTROL_PROC_DUMPLOG_MEMORY             = 0x00FE,
-       CONTROL_PROC_DUMPLOG_MEMORY_RSP         = 0xFE00,
-       CONTROL_PROC_TURNOFF                    = 0x00FF,
-       CONTROL_PROC_TURNOFF_RSP                = 0xFF00
-};
-
-union as10x_turn_on {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_turn_off {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t err;
-       } __packed rsp;
-} __packed;
-
-union as10x_set_tune {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-               /* tune params */
-               struct as10x_tune_args args;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* response error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_get_tune_status {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* response error */
-               uint8_t error;
-               /* tune status */
-               struct as10x_tune_status sts;
-       } __packed rsp;
-} __packed;
-
-union as10x_get_tps {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* response error */
-               uint8_t error;
-               /* tps details */
-               struct as10x_tps tps;
-       } __packed rsp;
-} __packed;
-
-union as10x_common {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t  proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* response error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_add_pid_filter {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t  proc_id;
-               /* PID to filter */
-               uint16_t  pid;
-               /* stream type (MPE, PSI/SI or PES )*/
-               uint8_t stream_type;
-               /* PID index in filter table */
-               uint8_t idx;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* response error */
-               uint8_t error;
-               /* Filter id */
-               uint8_t filter_id;
-       } __packed rsp;
-} __packed;
-
-union as10x_del_pid_filter {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t  proc_id;
-               /* PID to remove */
-               uint16_t  pid;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* response error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_start_streaming {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_stop_streaming {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_get_demod_stats {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-               /* demod stats */
-               struct as10x_demod_stats stats;
-       } __packed rsp;
-} __packed;
-
-union as10x_get_impulse_resp {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-               /* impulse response ready */
-               uint8_t is_ready;
-       } __packed rsp;
-} __packed;
-
-union as10x_fw_context {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-               /* value to write (for set context)*/
-               struct as10x_register_value reg_val;
-               /* context tag */
-               uint16_t tag;
-               /* context request type */
-               uint16_t type;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* value read (for get context) */
-               struct as10x_register_value reg_val;
-               /* context request type */
-               uint16_t type;
-               /* error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_set_register {
-       /* request */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* register description */
-               struct as10x_register_addr reg_addr;
-               /* register content */
-               struct as10x_register_value reg_val;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_get_register {
-       /* request */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* register description */
-               struct as10x_register_addr reg_addr;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-               /* register content */
-               struct as10x_register_value reg_val;
-       } __packed rsp;
-} __packed;
-
-union as10x_cfg_change_mode {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-               /* mode */
-               uint8_t mode;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-struct as10x_cmd_header_t {
-       uint16_t req_id;
-       uint16_t prog;
-       uint16_t version;
-       uint16_t data_len;
-} __packed;
-
-#define DUMP_BLOCK_SIZE 16
-
-union as10x_dump_memory {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-               /* dump memory type request */
-               uint8_t dump_req;
-               /* register description */
-               struct as10x_register_addr reg_addr;
-               /* nb blocks to read */
-               uint16_t num_blocks;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-               /* dump response */
-               uint8_t dump_rsp;
-               /* data */
-               union {
-                       uint8_t  data8[DUMP_BLOCK_SIZE];
-                       uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)];
-                       uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)];
-               } __packed u;
-       } __packed rsp;
-} __packed;
-
-union as10x_dumplog_memory {
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-               /* dump memory type request */
-               uint8_t dump_req;
-       } __packed req;
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-               /* dump response */
-               uint8_t dump_rsp;
-               /* dump data */
-               uint8_t data[DUMP_BLOCK_SIZE];
-       } __packed rsp;
-} __packed;
-
-union as10x_raw_data {
-       /* request */
-       struct {
-               uint16_t proc_id;
-               uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
-                            - 2 /* proc_id */];
-       } __packed req;
-       /* response */
-       struct {
-               uint16_t proc_id;
-               uint8_t error;
-               uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
-                            - 2 /* proc_id */ - 1 /* rc */];
-       } __packed rsp;
-} __packed;
-
-struct as10x_cmd_t {
-       struct as10x_cmd_header_t header;
-       union {
-               union as10x_turn_on             turn_on;
-               union as10x_turn_off            turn_off;
-               union as10x_set_tune            set_tune;
-               union as10x_get_tune_status     get_tune_status;
-               union as10x_get_tps             get_tps;
-               union as10x_common              common;
-               union as10x_add_pid_filter      add_pid_filter;
-               union as10x_del_pid_filter      del_pid_filter;
-               union as10x_start_streaming     start_streaming;
-               union as10x_stop_streaming      stop_streaming;
-               union as10x_get_demod_stats     get_demod_stats;
-               union as10x_get_impulse_resp    get_impulse_rsp;
-               union as10x_fw_context          context;
-               union as10x_set_register        set_register;
-               union as10x_get_register        get_register;
-               union as10x_cfg_change_mode     cfg_change_mode;
-               union as10x_dump_memory         dump_memory;
-               union as10x_dumplog_memory      dumplog_memory;
-               union as10x_raw_data            raw_data;
-       } __packed body;
-} __packed;
-
-struct as10x_token_cmd_t {
-       /* token cmd */
-       struct as10x_cmd_t c;
-       /* token response */
-       struct as10x_cmd_t r;
-} __packed;
-
-
-/**************************/
-/* FUNCTION DECLARATION   */
-/**************************/
-
-void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t proc_id,
-                     uint16_t cmd_len);
-int as10x_rsp_parse(struct as10x_cmd_t *r, uint16_t proc_id);
-
-/* as10x cmd */
-int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap);
-int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap);
-
-int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
-                      struct as10x_tune_args *ptune);
-
-int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
-                             struct as10x_tune_status *pstatus);
-
-int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap,
-                     struct as10x_tps *ptps);
-
-int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t  *adap,
-                             struct as10x_demod_stats *pdemod_stats);
-
-int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
-                              uint8_t *is_ready);
-
-/* as10x cmd stream */
-int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
-                            struct as10x_ts_filter *filter);
-int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
-                            uint16_t pid_value);
-
-int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap);
-int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap);
-
-/* as10x cmd cfg */
-int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap,
-                         uint16_t tag,
-                         uint32_t value);
-int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap,
-                         uint16_t tag,
-                         uint32_t *pvalue);
-
-int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode);
-int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id);
-#endif
diff --git a/drivers/staging/media/as102/as10x_cmd_cfg.c b/drivers/staging/media/as102/as10x_cmd_cfg.c
deleted file mode 100644 (file)
index b1e300d..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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 "as102_drv.h"
-#include "as10x_types.h"
-#include "as10x_cmd.h"
-
-/***************************/
-/* FUNCTION DEFINITION     */
-/***************************/
-
-/**
- * as10x_cmd_get_context - Send get context command to AS10x
- * @adap:      pointer to AS10x bus adapter
- * @tag:       context tag
- * @pvalue:    pointer where to store context value read
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
-                         uint32_t *pvalue)
-{
-       int  error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.context.req));
-
-       /* fill command */
-       pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT);
-       pcmd->body.context.req.tag = cpu_to_le16(tag);
-       pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error  = adap->ops->xfer_cmd(adap,
-                                            (uint8_t *) pcmd,
-                                            sizeof(pcmd->body.context.req)
-                                            + HEADER_SIZE,
-                                            (uint8_t *) prsp,
-                                            sizeof(prsp->body.context.rsp)
-                                            + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response: context command do not follow the common response */
-       /* structure -> specific handling response parse required            */
-       error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
-
-       if (error == 0) {
-               /* Response OK -> get response data */
-               *pvalue = le32_to_cpu(prsp->body.context.rsp.reg_val.u.value32);
-               /* value returned is always a 32-bit value */
-       }
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_set_context - send set context command to AS10x
- * @adap:      pointer to AS10x bus adapter
- * @tag:       context tag
- * @value:     value to set in context
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
-                         uint32_t value)
-{
-       int error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.context.req));
-
-       /* fill command */
-       pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT);
-       /* pcmd->body.context.req.reg_val.mode initialization is not required */
-       pcmd->body.context.req.reg_val.u.value32 = cpu_to_le32(value);
-       pcmd->body.context.req.tag = cpu_to_le16(tag);
-       pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error  = adap->ops->xfer_cmd(adap,
-                                            (uint8_t *) pcmd,
-                                            sizeof(pcmd->body.context.req)
-                                            + HEADER_SIZE,
-                                            (uint8_t *) prsp,
-                                            sizeof(prsp->body.context.rsp)
-                                            + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response: context command do not follow the common response */
-       /* structure -> specific handling response parse required            */
-       error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x
- * @adap:      pointer to AS10x bus adapter
- * @mode:      mode selected:
- *             - ON    : 0x0 => eLNA always ON
- *             - OFF   : 0x1 => eLNA always OFF
- *             - AUTO  : 0x2 => eLNA follow hysteresis parameters
- *                              to be ON or OFF
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode)
-{
-       int error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.cfg_change_mode.req));
-
-       /* fill command */
-       pcmd->body.cfg_change_mode.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE);
-       pcmd->body.cfg_change_mode.req.mode = mode;
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error  = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
-                               sizeof(pcmd->body.cfg_change_mode.req)
-                               + HEADER_SIZE, (uint8_t *) prsp,
-                               sizeof(prsp->body.cfg_change_mode.rsp)
-                               + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_context_rsp_parse - Parse context command response
- * @prsp:       pointer to AS10x command response buffer
- * @proc_id:    id of the command
- *
- * Since the contex command response does not follow the common
- * response, a specific parse function is required.
- * Return 0 on success or negative value in case of error.
- */
-int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id)
-{
-       int err;
-
-       err = prsp->body.context.rsp.error;
-
-       if ((err == 0) &&
-           (le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) {
-               return 0;
-       }
-       return AS10X_CMD_ERROR;
-}
diff --git a/drivers/staging/media/as102/as10x_cmd_stream.c b/drivers/staging/media/as102/as10x_cmd_stream.c
deleted file mode 100644 (file)
index 1088ca1..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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 "as102_drv.h"
-#include "as10x_cmd.h"
-
-/**
- * as10x_cmd_add_PID_filter - send add filter command to AS10x
- * @adap:      pointer to AS10x bus adapter
- * @filter:    TSFilter filter for DVB-T
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
-                            struct as10x_ts_filter *filter)
-{
-       int error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.add_pid_filter.req));
-
-       /* fill command */
-       pcmd->body.add_pid_filter.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_SETFILTER);
-       pcmd->body.add_pid_filter.req.pid = cpu_to_le16(filter->pid);
-       pcmd->body.add_pid_filter.req.stream_type = filter->type;
-
-       if (filter->idx < 16)
-               pcmd->body.add_pid_filter.req.idx = filter->idx;
-       else
-               pcmd->body.add_pid_filter.req.idx = 0xFF;
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
-                               sizeof(pcmd->body.add_pid_filter.req)
-                               + HEADER_SIZE, (uint8_t *) prsp,
-                               sizeof(prsp->body.add_pid_filter.rsp)
-                               + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_SETFILTER_RSP);
-
-       if (error == 0) {
-               /* Response OK -> get response data */
-               filter->idx = prsp->body.add_pid_filter.rsp.filter_id;
-       }
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_del_PID_filter - Send delete filter command to AS10x
- * @adap:         pointer to AS10x bus adapte
- * @pid_value:    PID to delete
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
-                            uint16_t pid_value)
-{
-       int error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.del_pid_filter.req));
-
-       /* fill command */
-       pcmd->body.del_pid_filter.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_REMOVEFILTER);
-       pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
-                               sizeof(pcmd->body.del_pid_filter.req)
-                               + HEADER_SIZE, (uint8_t *) prsp,
-                               sizeof(prsp->body.del_pid_filter.rsp)
-                               + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_start_streaming - Send start streaming command to AS10x
- * @adap:   pointer to AS10x bus adapter
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap)
-{
-       int error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.start_streaming.req));
-
-       /* fill command */
-       pcmd->body.start_streaming.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_START_STREAMING);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
-                               sizeof(pcmd->body.start_streaming.req)
-                               + HEADER_SIZE, (uint8_t *) prsp,
-                               sizeof(prsp->body.start_streaming.rsp)
-                               + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_stop_streaming - Send stop streaming command to AS10x
- * @adap:   pointer to AS10x bus adapter
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap)
-{
-       int8_t error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.stop_streaming.req));
-
-       /* fill command */
-       pcmd->body.stop_streaming.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_STOP_STREAMING);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
-                               sizeof(pcmd->body.stop_streaming.req)
-                               + HEADER_SIZE, (uint8_t *) prsp,
-                               sizeof(prsp->body.stop_streaming.rsp)
-                               + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP);
-
-out:
-       return error;
-}
diff --git a/drivers/staging/media/as102/as10x_handle.h b/drivers/staging/media/as102/as10x_handle.h
deleted file mode 100644 (file)
index 5638b19..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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.
- */
-#ifdef __KERNEL__
-struct as10x_bus_adapter_t;
-struct as102_dev_t;
-
-#include "as10x_cmd.h"
-
-/* values for "mode" field */
-#define REGMODE8       8
-#define REGMODE16      16
-#define REGMODE32      32
-
-struct as102_priv_ops_t {
-       int (*upload_fw_pkt)(struct as10x_bus_adapter_t *bus_adap,
-                             unsigned char *buf, int buflen, int swap32);
-
-       int (*send_cmd)(struct as10x_bus_adapter_t *bus_adap,
-                        unsigned char *buf, int buflen);
-
-       int (*xfer_cmd)(struct as10x_bus_adapter_t *bus_adap,
-                        unsigned char *send_buf, int send_buf_len,
-                        unsigned char *recv_buf, int recv_buf_len);
-
-       int (*start_stream)(struct as102_dev_t *dev);
-       void (*stop_stream)(struct as102_dev_t *dev);
-
-       int (*reset_target)(struct as10x_bus_adapter_t *bus_adap);
-
-       int (*read_write)(struct as10x_bus_adapter_t *bus_adap, uint8_t mode,
-                         uint32_t rd_addr, uint16_t rd_len,
-                         uint32_t wr_addr, uint16_t wr_len);
-
-       int (*as102_read_ep2)(struct as10x_bus_adapter_t *bus_adap,
-                              unsigned char *recv_buf,
-                              int recv_buf_len);
-};
-#endif
diff --git a/drivers/staging/media/as102/as10x_types.h b/drivers/staging/media/as102/as10x_types.h
deleted file mode 100644 (file)
index af26e05..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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 _AS10X_TYPES_H_
-#define _AS10X_TYPES_H_
-
-#include "as10x_handle.h"
-
-/*********************************/
-/*       MACRO DEFINITIONS       */
-/*********************************/
-
-/* bandwidth constant values */
-#define BW_5_MHZ               0x00
-#define BW_6_MHZ               0x01
-#define BW_7_MHZ               0x02
-#define BW_8_MHZ               0x03
-
-/* hierarchy priority selection values */
-#define HIER_NO_PRIORITY       0x00
-#define HIER_LOW_PRIORITY      0x01
-#define HIER_HIGH_PRIORITY     0x02
-
-/* constellation available values */
-#define CONST_QPSK             0x00
-#define CONST_QAM16            0x01
-#define CONST_QAM64            0x02
-#define CONST_UNKNOWN          0xFF
-
-/* hierarchy available values */
-#define HIER_NONE              0x00
-#define HIER_ALPHA_1           0x01
-#define HIER_ALPHA_2           0x02
-#define HIER_ALPHA_4           0x03
-#define HIER_UNKNOWN           0xFF
-
-/* interleaving available values */
-#define INTLV_NATIVE           0x00
-#define INTLV_IN_DEPTH         0x01
-#define INTLV_UNKNOWN          0xFF
-
-/* code rate available values */
-#define CODE_RATE_1_2          0x00
-#define CODE_RATE_2_3          0x01
-#define CODE_RATE_3_4          0x02
-#define CODE_RATE_5_6          0x03
-#define CODE_RATE_7_8          0x04
-#define CODE_RATE_UNKNOWN      0xFF
-
-/* guard interval available values */
-#define GUARD_INT_1_32         0x00
-#define GUARD_INT_1_16         0x01
-#define GUARD_INT_1_8          0x02
-#define GUARD_INT_1_4          0x03
-#define GUARD_UNKNOWN          0xFF
-
-/* transmission mode available values */
-#define TRANS_MODE_2K          0x00
-#define TRANS_MODE_8K          0x01
-#define TRANS_MODE_4K          0x02
-#define TRANS_MODE_UNKNOWN     0xFF
-
-/* DVBH signalling available values */
-#define TIMESLICING_PRESENT    0x01
-#define MPE_FEC_PRESENT                0x02
-
-/* tune state available */
-#define TUNE_STATUS_NOT_TUNED          0x00
-#define TUNE_STATUS_IDLE               0x01
-#define TUNE_STATUS_LOCKING            0x02
-#define TUNE_STATUS_SIGNAL_DVB_OK      0x03
-#define TUNE_STATUS_STREAM_DETECTED    0x04
-#define TUNE_STATUS_STREAM_TUNED       0x05
-#define TUNE_STATUS_ERROR              0xFF
-
-/* available TS FID filter types */
-#define TS_PID_TYPE_TS         0
-#define TS_PID_TYPE_PSI_SI     1
-#define TS_PID_TYPE_MPE                2
-
-/* number of echos available */
-#define MAX_ECHOS      15
-
-/* Context types */
-#define CONTEXT_LNA                    1010
-#define CONTEXT_ELNA_HYSTERESIS                4003
-#define CONTEXT_ELNA_GAIN              4004
-#define CONTEXT_MER_THRESHOLD          5005
-#define CONTEXT_MER_OFFSET             5006
-#define CONTEXT_IR_STATE               7000
-#define CONTEXT_TSOUT_MSB_FIRST                7004
-#define CONTEXT_TSOUT_FALLING_EDGE     7005
-
-/* Configuration modes */
-#define CFG_MODE_ON    0
-#define CFG_MODE_OFF   1
-#define CFG_MODE_AUTO  2
-
-struct as10x_tps {
-       uint8_t modulation;
-       uint8_t hierarchy;
-       uint8_t interleaving_mode;
-       uint8_t code_rate_HP;
-       uint8_t code_rate_LP;
-       uint8_t guard_interval;
-       uint8_t transmission_mode;
-       uint8_t DVBH_mask_HP;
-       uint8_t DVBH_mask_LP;
-       uint16_t cell_ID;
-} __packed;
-
-struct as10x_tune_args {
-       /* frequency */
-       uint32_t freq;
-       /* bandwidth */
-       uint8_t bandwidth;
-       /* hierarchy selection */
-       uint8_t hier_select;
-       /* constellation */
-       uint8_t modulation;
-       /* hierarchy */
-       uint8_t hierarchy;
-       /* interleaving mode */
-       uint8_t interleaving_mode;
-       /* code rate */
-       uint8_t code_rate;
-       /* guard interval */
-       uint8_t guard_interval;
-       /* transmission mode */
-       uint8_t transmission_mode;
-} __packed;
-
-struct as10x_tune_status {
-       /* tune status */
-       uint8_t tune_state;
-       /* signal strength */
-       int16_t signal_strength;
-       /* packet error rate 10^-4 */
-       uint16_t PER;
-       /* bit error rate 10^-4 */
-       uint16_t BER;
-} __packed;
-
-struct as10x_demod_stats {
-       /* frame counter */
-       uint32_t frame_count;
-       /* Bad frame counter */
-       uint32_t bad_frame_count;
-       /* Number of wrong bytes fixed by Reed-Solomon */
-       uint32_t bytes_fixed_by_rs;
-       /* Averaged MER */
-       uint16_t mer;
-       /* statistics calculation state indicator (started or not) */
-       uint8_t has_started;
-} __packed;
-
-struct as10x_ts_filter {
-       uint16_t pid;  /* valid PID value 0x00 : 0x2000 */
-       uint8_t  type; /* Red TS_PID_TYPE_<N> values */
-       uint8_t  idx;  /* index in filtering table */
-} __packed;
-
-struct as10x_register_value {
-       uint8_t mode;
-       union {
-               uint8_t  value8;   /* 8 bit value */
-               uint16_t value16;  /* 16 bit value */
-               uint32_t value32;  /* 32 bit value */
-       } __packed u;
-} __packed;
-
-struct as10x_register_addr {
-       /* register addr */
-       uint32_t addr;
-       /* register mode access */
-       uint8_t mode;
-};
-
-#endif
index 12f321dd23993ea8a1d35c54e6d14b733470484c..4de2f082491d8a007cac94b17f2fb55096b9c371 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_DM365_VPFE
        tristate "DM365 VPFE Media Controller Capture Driver"
        depends on VIDEO_V4L2 && ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        help
          Support for DM365 VPFE based Media Controller Capture driver.
index 226a1ca90b3c6a11098dd9846559db986c5506e0..2d496001b6e84d5d04e44b64274d4431f2c56ff2 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_DT3155
        tristate "DT3155 frame grabber, Video4Linux interface"
        depends on PCI && VIDEO_DEV && VIDEO_V4L2
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        default n
        ---help---
index 726cc3a31856673952525e0343fa0be95d7f41ec..7aca44f28c5ad54087b9a6fdd2dbe0fc6ff1bb20 100644 (file)
@@ -414,6 +414,7 @@ static ssize_t vfd_write(struct file *file, const char __user *buf,
        data_buf = memdup_user(buf, n_bytes);
        if (IS_ERR(data_buf)) {
                retval = PTR_ERR(data_buf);
+               data_buf = NULL;
                goto exit;
        }
 
index 86ad811fda24c1723e91ad816e97d4ca761c3f32..c20ef56202bf05ab9c8c72860c01f08ef813beeb 100644 (file)
@@ -392,6 +392,7 @@ static ssize_t vfd_write(struct file *file, const char __user *buf,
        data_buf = memdup_user((void const __user *)buf, n_bytes);
        if (IS_ERR(data_buf)) {
                retval = PTR_ERR(data_buf);
+               data_buf = NULL;
                goto exit;
        }
 
index 8afc6fee40c547ccca5f5c106e651c3fbfce9942..b78643f907e7a4e7cd4974a877c3ddd98a19a77e 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_OMAP4
        bool "OMAP 4 Camera support"
        depends on VIDEO_V4L2=y && VIDEO_V4L2_SUBDEV_API && I2C=y && ARCH_OMAP4
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          Driver for an OMAP 4 ISS controller.
index 852e96c4bb46b56d89ddb76d8b440bee01d20ce7..984fb79031de62274363cde081341daea3688593 100644 (file)
@@ -114,7 +114,7 @@ struct ccdc_fault_pixel {
        /* Number of fault pixel */
        unsigned short fp_num;
        /* Address of fault pixel table */
-       unsigned int fpc_table_addr;
+       unsigned long fpc_table_addr;
 };
 
 /* Structure for CCDC configuration parameters for raw capture mode passed
index c9d06d9f7e6eaa823eb4eb8b286ada0008abc176..398279dd1922b4b41959aa7966b0991d19fbb24b 100644 (file)
@@ -57,6 +57,8 @@ enum {
  *             0 - Active high, 1 - Active low
  * @vs_pol: Vertical synchronization polarity
  *             0 - Active high, 1 - Active low
+ * @fld_pol: Field signal polarity
+ *             0 - Positive, 1 - Negative
  * @data_pol: Data polarity
  *             0 - Normal, 1 - One's complement
  */
@@ -65,6 +67,7 @@ struct isp_parallel_platform_data {
        unsigned int clk_pol:1;
        unsigned int hs_pol:1;
        unsigned int vs_pol:1;
+       unsigned int fld_pol:1;
        unsigned int data_pol:1;
 };
 
index 80f951890b4cd1b8397de08e9f82442b97be5c19..e7a1514075ecfc8a3ac11d85fd5f9eb82a848e49 100644 (file)
@@ -135,6 +135,7 @@ void rc_map_init(void);
 #define RC_MAP_DM1105_NEC                "rc-dm1105-nec"
 #define RC_MAP_DNTV_LIVE_DVBT_PRO        "rc-dntv-live-dvbt-pro"
 #define RC_MAP_DNTV_LIVE_DVB_T           "rc-dntv-live-dvb-t"
+#define RC_MAP_DVBSKY                    "rc-dvbsky"
 #define RC_MAP_EMPTY                     "rc-empty"
 #define RC_MAP_EM_TERRATEC               "rc-em-terratec"
 #define RC_MAP_ENCORE_ENLTV2             "rc-encore-enltv2"
index 2fefcf491aa853f8ed868a92f39e8da594422c9b..6ef2d01197da95db59aea39eddc1d0b80592b0b6 100644 (file)
@@ -356,8 +356,8 @@ struct v4l2_fh;
  * @buf_struct_size: size of the driver-specific buffer structure;
  *             "0" indicates the driver doesn't want to use a custom buffer
  *             structure type, so sizeof(struct vb2_buffer) will is used
- * @timestamp_flags: Timestamp flags; V4L2_BUF_FLAGS_TIMESTAMP_* and
- *             V4L2_BUF_FLAGS_TSTAMP_SRC_*
+ * @timestamp_flags: Timestamp flags; V4L2_BUF_FLAG_TIMESTAMP_* and
+ *             V4L2_BUF_FLAG_TSTAMP_SRC_*
  * @gfp_flags: additional gfp flags used when allocating the buffers.
  *             Typically this is 0, but it may be e.g. GFP_DMA or __GFP_DMA32
  *             to force the buffer allocation to a specific memory zone.
@@ -366,6 +366,7 @@ struct v4l2_fh;
  *             cannot be started unless at least this number of buffers
  *             have been queued into the driver.
  *
+ * @mmap_lock: private mutex used when buffers are allocated/freed/mmapped
  * @memory:    current memory type used
  * @bufs:      videobuf buffer structures
  * @num_buffers: number of allocated/used buffers
@@ -402,6 +403,7 @@ struct vb2_queue {
        u32                             min_buffers_needed;
 
 /* private: internal use only */
+       struct mutex                    mmap_lock;
        enum v4l2_memory                memory;
        struct vb2_buffer               *bufs[VIDEO_MAX_FRAME];
        unsigned int                    num_buffers;
@@ -592,6 +594,15 @@ vb2_plane_size(struct vb2_buffer *vb, unsigned int plane_no)
        return 0;
 }
 
+/**
+ * vb2_start_streaming_called() - return streaming status of driver
+ * @q:         videobuf queue
+ */
+static inline bool vb2_start_streaming_called(struct vb2_queue *q)
+{
+       return q->start_streaming_called;
+}
+
 /*
  * The following functions are not part of the vb2 core API, but are simple
  * helper functions that you can use in your struct v4l2_file_operations,
index 70e150ebc6c9392f4d49aa3744925a82af2561c5..3cc8e1c2b99602fdfbaf24d34612613fcc073149 100644 (file)
@@ -355,6 +355,7 @@ header-y += serio.h
 header-y += shm.h
 header-y += signal.h
 header-y += signalfd.h
+header-y += smiapp.h
 header-y += snmp.h
 header-y += sock_diag.h
 header-y += socket.h
diff --git a/include/uapi/linux/smiapp.h b/include/uapi/linux/smiapp.h
new file mode 100644 (file)
index 0000000..53938f4
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * include/uapi/linux/smiapp.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2014 Intel Corporation
+ * Contact: 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.
+ *
+ */
+
+#ifndef __UAPI_LINUX_SMIAPP_H_
+#define __UAPI_LINUX_SMIAPP_H_
+
+#define V4L2_SMIAPP_TEST_PATTERN_MODE_DISABLED                 0
+#define V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR             1
+#define V4L2_SMIAPP_TEST_PATTERN_MODE_COLOUR_BARS              2
+#define V4L2_SMIAPP_TEST_PATTERN_MODE_COLOUR_BARS_GREY         3
+#define V4L2_SMIAPP_TEST_PATTERN_MODE_PN9                      4
+
+#endif /* __UAPI_LINUX_SMIAPP_H_ */
index e946e43fb8d51a80073b25ca88bf023228e8d39c..661f119a51b858e3bc4f4e5f2029ce3fa5f3f6d4 100644 (file)
@@ -746,6 +746,8 @@ enum v4l2_auto_focus_range {
        V4L2_AUTO_FOCUS_RANGE_INFINITY          = 3,
 };
 
+#define V4L2_CID_PAN_SPEED                     (V4L2_CID_CAMERA_CLASS_BASE+32)
+#define V4L2_CID_TILT_SPEED                    (V4L2_CID_CAMERA_CLASS_BASE+33)
 
 /* FM Modulator class control IDs */
 
@@ -865,6 +867,10 @@ enum v4l2_jpeg_chroma_subsampling {
 #define V4L2_CID_VBLANK                                (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 1)
 #define V4L2_CID_HBLANK                                (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2)
 #define V4L2_CID_ANALOGUE_GAIN                 (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3)
+#define V4L2_CID_TEST_PATTERN_RED              (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 4)
+#define V4L2_CID_TEST_PATTERN_GREENR           (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 5)
+#define V4L2_CID_TEST_PATTERN_BLUE             (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 6)
+#define V4L2_CID_TEST_PATTERN_GREENB           (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7)
 
 
 /* Image processing controls */
index 6c8f159e416eea1b2781b4e00139b4b3afe2ea9a..6a0764c89fcbeaf29cee9bf5dcba996ed9bc3c98 100644 (file)
 #ifndef _V4L2_DV_TIMINGS_H
 #define _V4L2_DV_TIMINGS_H
 
-#if __GNUC__ < 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ < 6))
-/* Sadly gcc versions older than 4.6 have a bug in how they initialize
-   anonymous unions where they require additional curly brackets.
-   This violates the C1x standard. This workaround adds the curly brackets
-   if needed. */
 #define V4L2_INIT_BT_TIMINGS(_width, args...) \
        { .bt = { _width , ## args } }
-#else
-#define V4L2_INIT_BT_TIMINGS(_width, args...) \
-       .bt = { _width , ## args }
-#endif
 
 /* CEA-861-E timings (i.e. standard HDTV timings) */
 
index 778a3298fb3441d4ab001afe7e920c249109bf83..1c2f84fd4d99b08e58d6a3dcf2c25667ad03d7e8 100644 (file)
@@ -79,6 +79,7 @@
 /*  Four-character-code (FOURCC) */
 #define v4l2_fourcc(a, b, c, d)\
        ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24))
+#define v4l2_fourcc_be(a, b, c, d)     (v4l2_fourcc(a, b, c, d) | (1 << 31))
 
 /*
  *     E N U M S
@@ -307,6 +308,8 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_XRGB555 v4l2_fourcc('X', 'R', '1', '5') /* 16  XRGB-1-5-5-5  */
 #define V4L2_PIX_FMT_RGB565  v4l2_fourcc('R', 'G', 'B', 'P') /* 16  RGB-5-6-5     */
 #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16  RGB-5-5-5 BE  */
+#define V4L2_PIX_FMT_ARGB555X v4l2_fourcc_be('A', 'R', '1', '5') /* 16  ARGB-5-5-5 BE */
+#define V4L2_PIX_FMT_XRGB555X v4l2_fourcc_be('X', 'R', '1', '5') /* 16  XRGB-5-5-5 BE */
 #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16  RGB-5-6-5 BE  */
 #define V4L2_PIX_FMT_BGR666  v4l2_fourcc('B', 'G', 'R', 'H') /* 18  BGR-6-6-6    */
 #define V4L2_PIX_FMT_BGR24   v4l2_fourcc('B', 'G', 'R', '3') /* 24  BGR-8-8-8     */
@@ -1285,11 +1288,11 @@ struct v4l2_ext_control {
        union {
                __s32 value;
                __s64 value64;
-               char *string;
-               __u8 *p_u8;
-               __u16 *p_u16;
-               __u32 *p_u32;
-               void *ptr;
+               char __user *string;
+               __u8 __user *p_u8;
+               __u16 __user *p_u16;
+               __u32 __user *p_u32;
+               void __user *ptr;
        };
 } __attribute__ ((packed));