aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/DocBook/media/v4l/controls.xml34
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-dqevent.xml7
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-edid.xml12
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml2
-rw-r--r--Documentation/video4linux/vivid.txt1109
-rw-r--r--MAINTAINERS8
-rw-r--r--drivers/media/common/siano/sms-cards.c6
-rw-r--r--drivers/media/common/siano/sms-cards.h1
-rw-r--r--drivers/media/common/siano/smscoreapi.c4
-rw-r--r--drivers/media/dvb-core/dmxdev.c7
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h1
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c25
-rw-r--r--drivers/media/dvb-core/dvb_frontend.h2
-rw-r--r--drivers/media/dvb-core/dvb_ringbuffer.c26
-rw-r--r--drivers/media/dvb-core/dvb_ringbuffer.h2
-rw-r--r--drivers/media/dvb-frontends/Kconfig12
-rw-r--r--drivers/media/dvb-frontends/Makefile3
-rw-r--r--drivers/media/dvb-frontends/af9013.c24
-rw-r--r--drivers/media/dvb-frontends/as102_fe.c480
-rw-r--r--drivers/media/dvb-frontends/as102_fe.h29
-rw-r--r--drivers/media/dvb-frontends/as102_fe_types.h (renamed from drivers/staging/media/as102/as10x_types.h)6
-rw-r--r--drivers/media/dvb-frontends/bcm3510.c4
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_c.c4
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_core.c4
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_t.c4
-rw-r--r--drivers/media/dvb-frontends/dib7000p.c2
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.c38
-rw-r--r--drivers/media/dvb-frontends/drxd_hard.c3
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.c37
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.c101
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.h35
-rw-r--r--drivers/media/dvb-frontends/mb86a16.c2
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.c14
-rw-r--r--drivers/media/dvb-frontends/rtl2832.c2
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c118
-rw-r--r--drivers/media/dvb-frontends/si2165.c2
-rw-r--r--drivers/media/dvb-frontends/si2168.c126
-rw-r--r--drivers/media/dvb-frontends/si2168.h6
-rw-r--r--drivers/media/dvb-frontends/si2168_priv.h2
-rw-r--r--drivers/media/dvb-frontends/sp2.c441
-rw-r--r--drivers/media/dvb-frontends/sp2.h53
-rw-r--r--drivers/media/dvb-frontends/sp2_priv.h50
-rw-r--r--drivers/media/dvb-frontends/sp8870.c3
-rw-r--r--drivers/media/dvb-frontends/stv0367.c8
-rw-r--r--drivers/media/dvb-frontends/stv0900_core.c7
-rw-r--r--drivers/media/dvb-frontends/tda10071.c2
-rw-r--r--drivers/media/i2c/cx25840/cx25840-ir.c2
-rw-r--r--drivers/media/i2c/lm3560.c4
-rw-r--r--drivers/media/i2c/ov7670.c14
-rw-r--r--drivers/media/i2c/s5k5baf.c2
-rw-r--r--drivers/media/i2c/saa6752hs.c6
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c143
-rw-r--r--drivers/media/i2c/smiapp/smiapp.h4
-rw-r--r--drivers/media/i2c/soc_camera/mt9t112.c4
-rw-r--r--drivers/media/i2c/soc_camera/ov772x.c5
-rw-r--r--drivers/media/i2c/soc_camera/ov9740.c4
-rw-r--r--drivers/media/i2c/tda7432.c2
-rw-r--r--drivers/media/i2c/vs6624.c14
-rw-r--r--drivers/media/media-devnode.c3
-rw-r--r--drivers/media/pci/Kconfig1
-rw-r--r--drivers/media/pci/Makefile2
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c5
-rw-r--r--drivers/media/pci/bt8xx/dst_ca.c4
-rw-r--r--drivers/media/pci/cx18/cx18-firmware.c2
-rw-r--r--drivers/media/pci/cx23885/Kconfig5
-rw-r--r--drivers/media/pci/cx23885/Makefile1
-rw-r--r--drivers/media/pci/cx23885/altera-ci.c8
-rw-r--r--drivers/media/pci/cx23885/altera-ci.h4
-rw-r--r--drivers/media/pci/cx23885/cimax2.c4
-rw-r--r--drivers/media/pci/cx23885/cimax2.h4
-rw-r--r--drivers/media/pci/cx23885/cx23885-417.c501
-rw-r--r--drivers/media/pci/cx23885/cx23885-alsa.c109
-rw-r--r--drivers/media/pci/cx23885/cx23885-av.c5
-rw-r--r--drivers/media/pci/cx23885/cx23885-av.h5
-rw-r--r--drivers/media/pci/cx23885/cx23885-cards.c6
-rw-r--r--drivers/media/pci/cx23885/cx23885-core.c358
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c138
-rw-r--r--drivers/media/pci/cx23885/cx23885-f300.c4
-rw-r--r--drivers/media/pci/cx23885/cx23885-i2c.c12
-rw-r--r--drivers/media/pci/cx23885/cx23885-input.c5
-rw-r--r--drivers/media/pci/cx23885/cx23885-input.h5
-rw-r--r--drivers/media/pci/cx23885/cx23885-ioctl.c10
-rw-r--r--drivers/media/pci/cx23885/cx23885-ioctl.h4
-rw-r--r--drivers/media/pci/cx23885/cx23885-ir.c5
-rw-r--r--drivers/media/pci/cx23885/cx23885-ir.h5
-rw-r--r--drivers/media/pci/cx23885/cx23885-reg.h4
-rw-r--r--drivers/media/pci/cx23885/cx23885-vbi.c282
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c1294
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.h5
-rw-r--r--drivers/media/pci/cx23885/cx23885.h121
-rw-r--r--drivers/media/pci/cx23885/cx23888-ir.c7
-rw-r--r--drivers/media/pci/cx23885/cx23888-ir.h5
-rw-r--r--drivers/media/pci/cx23885/netup-eeprom.c4
-rw-r--r--drivers/media/pci/cx23885/netup-eeprom.h4
-rw-r--r--drivers/media/pci/cx23885/netup-init.c4
-rw-r--r--drivers/media/pci/cx23885/netup-init.h4
-rw-r--r--drivers/media/pci/cx25821/cx25821-video-upstream.c5
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c30
-rw-r--r--drivers/media/pci/ddbridge/ddbridge.h12
-rw-r--r--drivers/media/pci/dm1105/dm1105.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-irq.c12
-rw-r--r--drivers/media/pci/mantis/hopper_vp3028.c2
-rw-r--r--drivers/media/pci/mantis/mantis_common.h2
-rw-r--r--drivers/media/pci/mantis/mantis_vp1033.c4
-rw-r--r--drivers/media/pci/mantis/mantis_vp1034.c2
-rw-r--r--drivers/media/pci/mantis/mantis_vp1041.c4
-rw-r--r--drivers/media/pci/mantis/mantis_vp2033.c4
-rw-r--r--drivers/media/pci/mantis/mantis_vp2040.c4
-rw-r--r--drivers/media/pci/mantis/mantis_vp3030.c4
-rw-r--r--drivers/media/pci/ngene/ngene-cards.c2
-rw-r--r--drivers/media/pci/ngene/ngene-core.c14
-rw-r--r--drivers/media/pci/ngene/ngene-dvb.c7
-rw-r--r--drivers/media/pci/ngene/ngene.h2
-rw-r--r--drivers/media/pci/saa7164/saa7164-api.c3
-rw-r--r--drivers/media/pci/solo6x10/Kconfig1
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-disp.c4
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-eeprom.c8
-rw-r--r--drivers/media/pci/solo6x10/solo6x10.h4
-rw-r--r--drivers/media/pci/sta2x11/Kconfig1
-rw-r--r--drivers/media/pci/ttpci/Kconfig4
-rw-r--r--drivers/media/pci/ttpci/Makefile2
-rw-r--r--drivers/media/pci/ttpci/av7110.c8
-rw-r--r--drivers/media/pci/tw68/Kconfig10
-rw-r--r--drivers/media/pci/tw68/Makefile3
-rw-r--r--drivers/media/pci/tw68/tw68-core.c434
-rw-r--r--drivers/media/pci/tw68/tw68-reg.h195
-rw-r--r--drivers/media/pci/tw68/tw68-risc.c230
-rw-r--r--drivers/media/pci/tw68/tw68-video.c1051
-rw-r--r--drivers/media/pci/tw68/tw68.h231
-rw-r--r--drivers/media/pci/zoran/zoran_device.c2
-rw-r--r--drivers/media/platform/Kconfig54
-rw-r--r--drivers/media/platform/Makefile6
-rw-r--r--drivers/media/platform/blackfin/Kconfig1
-rw-r--r--drivers/media/platform/coda.c3933
-rw-r--r--drivers/media/platform/coda/Makefile3
-rw-r--r--drivers/media/platform/coda/coda-bit.c1860
-rw-r--r--drivers/media/platform/coda/coda-common.c2065
-rw-r--r--drivers/media/platform/coda/coda-h264.c37
-rw-r--r--drivers/media/platform/coda/coda.h287
-rw-r--r--drivers/media/platform/coda/coda_regs.h (renamed from drivers/media/platform/coda.h)0
-rw-r--r--drivers/media/platform/davinci/Kconfig18
-rw-r--r--drivers/media/platform/davinci/dm355_ccdc.c2
-rw-r--r--drivers/media/platform/davinci/dm644x_ccdc.c14
-rw-r--r--drivers/media/platform/davinci/vpfe_capture.c5
-rw-r--r--drivers/media/platform/davinci/vpif.c1
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c6
-rw-r--r--drivers/media/platform/davinci/vpif_display.c14
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.c6
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c3
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-regs.c8
-rw-r--r--drivers/media/platform/exynos4-is/Kconfig5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-errno.c4
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-errno.h4
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-param.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp-video.c3
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c4
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c3
-rw-r--r--drivers/media/platform/marvell-ccic/Kconfig2
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c2
-rw-r--r--drivers/media/platform/mx2_emmaprp.c2
-rw-r--r--drivers/media/platform/omap/Kconfig2
-rw-r--r--drivers/media/platform/omap/omap_vout.c16
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.c10
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.h18
-rw-r--r--drivers/media/platform/omap3isp/cfa_coef_table.h10
-rw-r--r--drivers/media/platform/omap3isp/gamma_table.h10
-rw-r--r--drivers/media/platform/omap3isp/isp.c20
-rw-r--r--drivers/media/platform/omap3isp/isp.h10
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c424
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.h21
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c10
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.h10
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c10
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.h10
-rw-r--r--drivers/media/platform/omap3isp/ispcsiphy.c10
-rw-r--r--drivers/media/platform/omap3isp/ispcsiphy.h10
-rw-r--r--drivers/media/platform/omap3isp/isph3a.h10
-rw-r--r--drivers/media/platform/omap3isp/isph3a_aewb.c10
-rw-r--r--drivers/media/platform/omap3isp/isph3a_af.c10
-rw-r--r--drivers/media/platform/omap3isp/isphist.c10
-rw-r--r--drivers/media/platform/omap3isp/isphist.h10
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c10
-rw-r--r--drivers/media/platform/omap3isp/isppreview.h10
-rw-r--r--drivers/media/platform/omap3isp/ispreg.h20
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.c80
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.h13
-rw-r--r--drivers/media/platform/omap3isp/ispstat.c10
-rw-r--r--drivers/media/platform/omap3isp/ispstat.h10
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c59
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.h12
-rw-r--r--drivers/media/platform/omap3isp/luma_enhance_table.h10
-rw-r--r--drivers/media/platform/omap3isp/noise_filter_table.h10
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c7
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c2
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c2
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c11
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c6
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c6
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c1
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c1
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_debug.h6
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c4
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c7
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c3
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_pm.c2
-rw-r--r--drivers/media/platform/s5p-tv/Kconfig4
-rw-r--r--drivers/media/platform/s5p-tv/hdmi_drv.c2
-rw-r--r--drivers/media/platform/s5p-tv/sdo_drv.c2
-rw-r--r--drivers/media/platform/s5p-tv/sii9234_drv.c2
-rw-r--r--drivers/media/platform/sh_veu.c4
-rw-r--r--drivers/media/platform/soc_camera/Kconfig16
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c13
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c3
-rw-r--r--drivers/media/platform/soc_camera/pxa_camera.c2
-rw-r--r--drivers/media/platform/soc_camera/rcar_vin.c2
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c4
-rw-r--r--drivers/media/platform/ti-vpe/vpdma.c4
-rw-r--r--drivers/media/platform/ti-vpe/vpe.c5
-rw-r--r--drivers/media/platform/via-camera.c13
-rw-r--r--drivers/media/platform/vivi.c1542
-rw-r--r--drivers/media/platform/vivid/Kconfig19
-rw-r--r--drivers/media/platform/vivid/Makefile6
-rw-r--r--drivers/media/platform/vivid/vivid-core.c1390
-rw-r--r--drivers/media/platform/vivid/vivid-core.h520
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.c1502
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.h34
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-cap.c886
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-cap.h26
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-out.c305
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-out.h26
-rw-r--r--drivers/media/platform/vivid/vivid-osd.c400
-rw-r--r--drivers/media/platform/vivid/vivid-osd.h27
-rw-r--r--drivers/media/platform/vivid/vivid-radio-common.c189
-rw-r--r--drivers/media/platform/vivid/vivid-radio-common.h40
-rw-r--r--drivers/media/platform/vivid/vivid-radio-rx.c287
-rw-r--r--drivers/media/platform/vivid/vivid-radio-rx.h31
-rw-r--r--drivers/media/platform/vivid/vivid-radio-tx.c141
-rw-r--r--drivers/media/platform/vivid/vivid-radio-tx.h29
-rw-r--r--drivers/media/platform/vivid/vivid-rds-gen.c166
-rw-r--r--drivers/media/platform/vivid/vivid-rds-gen.h53
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.c499
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.h34
-rw-r--r--drivers/media/platform/vivid/vivid-tpg-colors.c310
-rw-r--r--drivers/media/platform/vivid/vivid-tpg-colors.h64
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.c1439
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.h439
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-cap.c356
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-cap.h40
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-gen.c249
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-gen.h33
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-out.c247
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-out.h34
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.c1730
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.h71
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.c571
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.h61
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.c1146
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.h56
-rw-r--r--drivers/media/radio/radio-gemtek.c2
-rw-r--r--drivers/media/radio/radio-sf16fmi.c4
-rw-r--r--drivers/media/radio/radio-tea5764.c12
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c4
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.c11
-rw-r--r--drivers/media/radio/wl128x/fmdrv_rx.c10
-rw-r--r--drivers/media/radio/wl128x/fmdrv_tx.c2
-rw-r--r--drivers/media/rc/Kconfig5
-rw-r--r--drivers/media/rc/ene_ir.c2
-rw-r--r--drivers/media/rc/fintek-cir.c6
-rw-r--r--drivers/media/rc/img-ir/img-ir-hw.c6
-rw-r--r--drivers/media/rc/img-ir/img-ir-hw.h6
-rw-r--r--drivers/media/rc/imon.c296
-rw-r--r--drivers/media/rc/ite-cir.c3
-rw-r--r--drivers/media/rc/lirc_dev.c14
-rw-r--r--drivers/media/rc/nuvoton-cir.c6
-rw-r--r--drivers/media/tuners/Kconfig1
-rw-r--r--drivers/media/tuners/e4000.c75
-rw-r--r--drivers/media/tuners/m88ts2022.c355
-rw-r--r--drivers/media/tuners/m88ts2022_priv.h5
-rw-r--r--drivers/media/tuners/msi001.c56
-rw-r--r--drivers/media/tuners/mt2060.c3
-rw-r--r--drivers/media/tuners/mt2063.c26
-rw-r--r--drivers/media/tuners/mxl5005s.c3
-rw-r--r--drivers/media/tuners/si2157.c73
-rw-r--r--drivers/media/tuners/si2157_priv.h1
-rw-r--r--drivers/media/tuners/tda18212.c31
-rw-r--r--drivers/media/tuners/tuner-xc2028.c62
-rw-r--r--drivers/media/tuners/xc4000.c62
-rw-r--r--drivers/media/tuners/xc5000.c194
-rw-r--r--drivers/media/usb/Kconfig1
-rw-r--r--drivers/media/usb/Makefile1
-rw-r--r--drivers/media/usb/airspy/airspy.c222
-rw-r--r--drivers/media/usb/as102/Kconfig (renamed from drivers/staging/media/as102/Kconfig)0
-rw-r--r--drivers/media/usb/as102/Makefile (renamed from drivers/staging/media/as102/Makefile)3
-rw-r--r--drivers/media/usb/as102/as102_drv.c (renamed from drivers/staging/media/as102/as102_drv.c)152
-rw-r--r--drivers/media/usb/as102/as102_drv.h (renamed from drivers/staging/media/as102/as102_drv.h)26
-rw-r--r--drivers/media/usb/as102/as102_fw.c (renamed from drivers/staging/media/as102/as102_fw.c)4
-rw-r--r--drivers/media/usb/as102/as102_fw.h (renamed from drivers/staging/media/as102/as102_fw.h)4
-rw-r--r--drivers/media/usb/as102/as102_usb_drv.c (renamed from drivers/staging/media/as102/as102_usb_drv.c)45
-rw-r--r--drivers/media/usb/as102/as102_usb_drv.h (renamed from drivers/staging/media/as102/as102_usb_drv.h)4
-rw-r--r--drivers/media/usb/as102/as10x_cmd.c (renamed from drivers/staging/media/as102/as10x_cmd.c)5
-rw-r--r--drivers/media/usb/as102/as10x_cmd.h (renamed from drivers/staging/media/as102/as10x_cmd.h)8
-rw-r--r--drivers/media/usb/as102/as10x_cmd_cfg.c (renamed from drivers/staging/media/as102/as10x_cmd_cfg.c)5
-rw-r--r--drivers/media/usb/as102/as10x_cmd_stream.c (renamed from drivers/staging/media/as102/as10x_cmd_stream.c)4
-rw-r--r--drivers/media/usb/as102/as10x_handle.h (renamed from drivers/staging/media/as102/as10x_handle.h)7
-rw-r--r--drivers/media/usb/au0828/au0828-cards.c14
-rw-r--r--drivers/media/usb/au0828/au0828-core.c84
-rw-r--r--drivers/media/usb/au0828/au0828-dvb.c110
-rw-r--r--drivers/media/usb/au0828/au0828-i2c.c15
-rw-r--r--drivers/media/usb/au0828/au0828-input.c36
-rw-r--r--drivers/media/usb/au0828/au0828-vbi.c4
-rw-r--r--drivers/media/usb/au0828/au0828-video.c90
-rw-r--r--drivers/media/usb/au0828/au0828.h33
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-avcore.c12
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-core.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dvb.c8
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c4
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.c8
-rw-r--r--drivers/media/usb/dvb-usb/Kconfig2
-rw-r--r--drivers/media/usb/dvb-usb/af9005.c2
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.c130
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.h4
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-common.c12
-rw-r--r--drivers/media/usb/dvb-usb/dw2102.c14
-rw-r--r--drivers/media/usb/dvb-usb/opera1.c4
-rw-r--r--drivers/media/usb/dvb-usb/pctv452e.c8
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c2
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c2
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c5
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c6
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c19
-rw-r--r--drivers/media/usb/go7007/go7007-usb.c4
-rw-r--r--drivers/media/usb/gspca/gspca.c5
-rw-r--r--drivers/media/usb/gspca/gspca.h2
-rw-r--r--drivers/media/usb/gspca/kinect.c12
-rw-r--r--drivers/media/usb/msi2500/msi2500.c174
-rw-r--r--drivers/media/usb/pwc/pwc-v4l.c2
-rw-r--r--drivers/media/usb/s2255/s2255drv.c2
-rw-r--r--drivers/media/usb/siano/smsusb.c2
-rw-r--r--drivers/media/usb/usbtv/Kconfig3
-rw-r--r--drivers/media/usb/usbtv/Makefile3
-rw-r--r--drivers/media/usb/usbtv/usbtv-audio.c384
-rw-r--r--drivers/media/usb/usbtv/usbtv-core.c16
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c15
-rw-r--r--drivers/media/usb/usbtv/usbtv.h21
-rw-r--r--drivers/media/usb/uvc/uvc_video.c2
-rw-r--r--drivers/media/v4l2-core/tuner-core.c10
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c30
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c9
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-sg.c6
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c70
-rw-r--r--drivers/staging/media/Kconfig2
-rw-r--r--drivers/staging/media/Makefile1
-rw-r--r--drivers/staging/media/as102/as102_fe.c571
-rw-r--r--drivers/staging/media/davinci_vpfe/Kconfig1
-rw-r--r--drivers/staging/media/dt3155v4l/Kconfig1
-rw-r--r--drivers/staging/media/omap4iss/Kconfig1
-rw-r--r--include/media/davinci/dm644x_ccdc.h2
-rw-r--r--include/media/omap3isp.h3
-rw-r--r--include/media/videobuf2-core.h2
-rw-r--r--include/uapi/linux/Kbuild1
-rw-r--r--include/uapi/linux/smiapp.h29
-rw-r--r--include/uapi/linux/v4l2-controls.h4
-rw-r--r--include/uapi/linux/videodev2.h10
369 files changed, 26318 insertions, 10263 deletions
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 9f5ffd8..a7eb1bd 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -4790,6 +4790,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>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
index cb77325..b036f89 100644
--- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
@@ -76,21 +76,22 @@
<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>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml
index ce4563b..fa91651 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml
@@ -125,17 +125,17 @@
<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>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
index 9f60956..d7c9365 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
@@ -176,7 +176,7 @@
</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/video4linux/vivid.txt b/Documentation/video4linux/vivid.txt
new file mode 100644
index 0000000..4f1d442
--- /dev/null
+++ b/Documentation/video4linux/vivid.txt
@@ -0,0 +1,1109 @@
+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.
+
+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 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.
+
+
+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
+- 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.
diff --git a/MAINTAINERS b/MAINTAINERS
index aefa948..78b38e9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9227,6 +9227,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>
diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c
index 8276999..82c7a12 100644
--- a/drivers/media/common/siano/sms-cards.c
+++ b/drivers/media/common/siano/sms-cards.c
@@ -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)
diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h
index c63b544..4c4cadd 100644
--- a/drivers/media/common/siano/sms-cards.h
+++ b/drivers/media/common/siano/sms-cards.h
@@ -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;
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
index 050984c..a367743 100644
--- a/drivers/media/common/siano/smscoreapi.c
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -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)
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index c0363f1..abff803 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -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) {
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 12ce19c..d484a51 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -244,6 +244,7 @@
#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
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index c2a6a0a..c862ad7 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -2072,6 +2072,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 +2567,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 +2591,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;
diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
index d398de4..816269e 100644
--- a/drivers/media/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb-core/dvb_frontend.h
@@ -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);
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c
index a5712cd..1100e98 100644
--- a/drivers/media/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb-core/dvb_ringbuffer.c
@@ -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);
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb-core/dvb_ringbuffer.h
index 41f04da..9e1e11b 100644
--- a/drivers/media/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb-core/dvb_ringbuffer.h
@@ -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);
/**
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index fe0ddcc..704403f 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -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
@@ -720,6 +725,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
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index edf103d..1e19a74 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -107,10 +107,11 @@ 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
diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c
index ecf6388..8001690 100644
--- a/drivers/media/dvb-frontends/af9013.c
+++ b/drivers/media/dvb-frontends/af9013.c
@@ -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) {
diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c
new file mode 100644
index 0000000..4936658
--- /dev/null
+++ b/drivers/media/dvb-frontends/as102_fe.c
@@ -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
index 0000000..a7c9143
--- /dev/null
+++ b/drivers/media/dvb-frontends/as102_fe.h
@@ -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/staging/media/as102/as10x_types.h b/drivers/media/dvb-frontends/as102_fe_types.h
index af26e05..80a5398 100644
--- a/drivers/staging/media/as102/as10x_types.h
+++ b/drivers/media/dvb-frontends/as102_fe_types.h
@@ -11,16 +11,10 @@
* 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 */
/*********************************/
diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c
index 39a29dd..998d150 100644
--- a/drivers/media/dvb-frontends/bcm3510.c
+++ b/drivers/media/dvb-frontends/bcm3510.c
@@ -643,8 +643,8 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe)
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);
diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c
index 0f4657e..149fdca 100644
--- a/drivers/media/dvb-frontends/cxd2820r_c.c
+++ b/drivers/media/dvb-frontends/cxd2820r_c.c
@@ -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;
}
diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c
index 03930d5..cd2af3e 100644
--- a/drivers/media/dvb-frontends/cxd2820r_core.c
+++ b/drivers/media/dvb-frontends/cxd2820r_core.c
@@ -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;
}
diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c
index 9b5a45b..51401d0 100644
--- a/drivers/media/dvb-frontends/cxd2820r_t.c
+++ b/drivers/media/dvb-frontends/cxd2820r_t.c
@@ -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;
}
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index 661760d..589134e 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -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;
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c
index 7ca7a21..5ec221f 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -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",
diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c
index ae2276d..961641b 100644
--- a/drivers/media/dvb-frontends/drxd_hard.c
+++ b/drivers/media/dvb-frontends/drxd_hard.c
@@ -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,
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index cce94a7..6721951 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -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;
}
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index dfe0c2f..81657e9 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -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>");
diff --git a/drivers/media/dvb-frontends/m88ds3103.h b/drivers/media/dvb-frontends/m88ds3103.h
index bbb7e3a..9b3b496 100644
--- a/drivers/media/dvb-frontends/m88ds3103.h
+++ b/drivers/media/dvb-frontends/m88ds3103.h
@@ -47,14 +47,23 @@ 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;
};
/*
diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c
index 9ae40ab..1827c0a 100644
--- a/drivers/media/dvb-frontends/mb86a16.c
+++ b/drivers/media/dvb-frontends/mb86a16.c
@@ -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))
diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c
index b931179..e6f165a 100644
--- a/drivers/media/dvb-frontends/mb86a20s.c
+++ b/drivers/media/dvb-frontends/mb86a20s.c
@@ -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__);
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index fdbed35..eb737cf 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -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:
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index 023e0f4..7bf98cf 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -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);
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c
index 3a2d6c5..4386092 100644
--- a/drivers/media/dvb-frontends/si2165.c
+++ b/drivers/media/dvb-frontends/si2165.c
@@ -312,7 +312,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;
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 8f81d97..a0797fd 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -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 {
@@ -607,12 +642,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 +668,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 +686,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);
diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
index 3c5b5ab..e086d67 100644
--- a/drivers/media/dvb-frontends/si2168.h
+++ b/drivers/media/dvb-frontends/si2168.h
@@ -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
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
index ebbf502..e13983e 100644
--- a/drivers/media/dvb-frontends/si2168_priv.h
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -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 */
diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c
new file mode 100644
index 0000000..9b684d5
--- /dev/null
+++ b/drivers/media/dvb-frontends/sp2.c
@@ -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
index 0000000..6cceea0
--- /dev/null
+++ b/drivers/media/dvb-frontends/sp2.h
@@ -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
index 0000000..37fef7b
--- /dev/null
+++ b/drivers/media/dvb-frontends/sp2_priv.h
@@ -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
diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c
index 2aa8ef7..57dc2aba 100644
--- a/drivers/media/dvb-frontends/sp8870.c
+++ b/drivers/media/dvb-frontends/sp8870.c
@@ -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;
diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c
index 59b6e66..59f622a 100644
--- a/drivers/media/dvb-frontends/stv0367.c
+++ b/drivers/media/dvb-frontends/stv0367.c
@@ -554,7 +554,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 +566,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 +1935,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 +2018,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)
diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c
index e5a87b5..2c88abf 100644
--- a/drivers/media/dvb-frontends/stv0900_core.c
+++ b/drivers/media/dvb-frontends/stv0900_core.c
@@ -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;
}
diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c
index 9619be5..4a19b85 100644
--- a/drivers/media/dvb-frontends/tda10071.c
+++ b/drivers/media/dvb-frontends/tda10071.c
@@ -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;
diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
index e6588ee..4cf8f18 100644
--- a/drivers/media/i2c/cx25840/cx25840-ir.c
+++ b/drivers/media/i2c/cx25840/cx25840-ir.c
@@ -224,7 +224,7 @@ static inline unsigned int lpf_count_to_us(unsigned int count)
}
/*
- * FIFO register pulse width count compuations
+ * FIFO register pulse width count computations
*/
static u32 clock_divider_to_resolution(u16 divider)
{
diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
index c23de59..d9ece4b 100644
--- a/drivers/media/i2c/lm3560.c
+++ b/drivers/media/i2c/lm3560.c
@@ -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
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index cdd7c1b..dd3db24 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -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>");
@@ -30,19 +31,6 @@ 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
*/
#define OV7670_I2C_ADDR 0x42
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 564f05f..0e461a6 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -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;
}
diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c
index 04e9e55..4024ea6 100644
--- a/drivers/media/i2c/saa6752hs.c
+++ b/drivers/media/i2c/saa6752hs.c
@@ -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;
}
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 62acb10..932ed9b 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -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. */
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h
index 7cc5aae..874b49f 100644
--- a/drivers/media/i2c/smiapp/smiapp.h
+++ b/drivers/media/i2c/smiapp/smiapp.h
@@ -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) \
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c
index 46f431a..996d7b4 100644
--- a/drivers/media/i2c/soc_camera/mt9t112.c
+++ b/drivers/media/i2c/soc_camera/mt9t112.c
@@ -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
*/
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c
index 7f2b3c8..970a04e 100644
--- a/drivers/media/i2c/soc_camera/ov772x.c
+++ b/drivers/media/i2c/soc_camera/ov772x.c
@@ -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
@@ -360,10 +361,6 @@
#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
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c
index ea76863..ee9eb63 100644
--- a/drivers/media/i2c/soc_camera/ov9740.c
+++ b/drivers/media/i2c/soc_camera/ov9740.c
@@ -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
diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c
index 72af644..cf93021 100644
--- a/drivers/media/i2c/tda7432.c
+++ b/drivers/media/i2c/tda7432.c
@@ -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*/
diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c
index 23f4f65..373f2df 100644
--- a/drivers/media/i2c/vs6624.c
+++ b/drivers/media/i2c/vs6624.c
@@ -30,22 +30,10 @@
#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 {
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index 7acd19c..ebf9626 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -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 = {
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig
index 5c16c9c..9332807 100644
--- a/drivers/media/pci/Kconfig
+++ b/drivers/media/pci/Kconfig
@@ -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
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile
index e5b53fb..73d9c0f 100644
--- a/drivers/media/pci/Makefile
+++ b/drivers/media/pci/Makefile
@@ -10,7 +10,6 @@ obj-y += ttpci/ \
mantis/ \
ngene/ \
ddbridge/ \
- b2c2/ \
saa7146/
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
@@ -22,6 +21,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/
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 970e542..4a8176c 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -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);
diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c
index 0e788fc..c22c4ae 100644
--- a/drivers/media/pci/bt8xx/dst_ca.c
+++ b/drivers/media/pci/bt8xx/dst_ca.c
@@ -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)
diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c
index a1c1cec..53a7578 100644
--- a/drivers/media/pci/cx18/cx18-firmware.c
+++ b/drivers/media/pci/cx18/cx18-firmware.c
@@ -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]);
diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig
index e12c006..a883ea4 100644
--- a/drivers/media/pci/cx23885/Kconfig
+++ b/drivers/media/pci/cx23885/Kconfig
@@ -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
diff --git a/drivers/media/pci/cx23885/Makefile b/drivers/media/pci/cx23885/Makefile
index 2a2cafb..a2cbdcf 100644
--- a/drivers/media/pci/cx23885/Makefile
+++ b/drivers/media/pci/cx23885/Makefile
@@ -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
diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c
index 2926f7f..2bbbf54 100644
--- a/drivers/media/pci/cx23885/altera-ci.c
+++ b/drivers/media/pci/cx23885/altera-ci.c
@@ -16,10 +16,6 @@
* 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"
diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h
index 4998c96..5028f0c 100644
--- a/drivers/media/pci/cx23885/altera-ci.h
+++ b/drivers/media/pci/cx23885/altera-ci.h
@@ -16,10 +16,6 @@
* 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
diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c
index 16fa7ea..631e4f2 100644
--- a/drivers/media/pci/cx23885/cimax2.c
+++ b/drivers/media/pci/cx23885/cimax2.c
@@ -17,10 +17,6 @@
* 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"
diff --git a/drivers/media/pci/cx23885/cimax2.h b/drivers/media/pci/cx23885/cimax2.h
index 518744a..565e958 100644
--- a/drivers/media/pci/cx23885/cimax2.h
+++ b/drivers/media/pci/cx23885/cimax2.h
@@ -17,10 +17,6 @@
* 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
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index bf89fc8..6973055 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -18,10 +18,6 @@
* 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] = {
@@ -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) {
diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c
index 554798d..ae7c2e8 100644
--- a/drivers/media/pci/cx23885/cx23885-alsa.c
+++ b/drivers/media/pci/cx23885/cx23885-alsa.c
@@ -15,10 +15,6 @@
* 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;
}
diff --git a/drivers/media/pci/cx23885/cx23885-av.c b/drivers/media/pci/cx23885/cx23885-av.c
index c443b7a..877dad8 100644
--- a/drivers/media/pci/cx23885/cx23885-av.c
+++ b/drivers/media/pci/cx23885/cx23885-av.c
@@ -14,11 +14,6 @@
* 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"
diff --git a/drivers/media/pci/cx23885/cx23885-av.h b/drivers/media/pci/cx23885/cx23885-av.h
index d2915c3..97f232f 100644
--- a/drivers/media/pci/cx23885/cx23885-av.h
+++ b/drivers/media/pci/cx23885/cx23885-av.h
@@ -14,11 +14,6 @@
* 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_
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
index c2b6080..21e500b 100644
--- a/drivers/media/pci/cx23885/cx23885-cards.c
+++ b/drivers/media/pci/cx23885/cx23885-cards.c
@@ -13,10 +13,6 @@
* 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>
@@ -1970,5 +1966,3 @@ void cx23885_card_setup(struct cx23885_dev *dev)
}
}
}
-
-/* ------------------------------------------------------------------ */
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index edcd79d..cb94366b 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -13,10 +13,6 @@
* 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,10 +1217,11 @@ 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;
@@ -1254,11 +1229,11 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
* in the userland vbi payload */
if (UNSET != top_offset)
rp = cx23885_risc_field(rp, sglist, top_offset, 6,
- bpl, padding, lines, 0);
+ bpl, padding, lines, 0, true);
if (UNSET != bottom_offset)
rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207,
- bpl, padding, lines, 0);
+ 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)
-{
- __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)
+void cx23885_free_buffer(struct cx23885_dev *dev, 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);
}
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 968fecc..332e6fa 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -13,10 +13,6 @@
* 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>
@@ -91,59 +87,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 = {
@@ -863,16 +895,16 @@ 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;
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 +1424,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 +1523,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,
@@ -1532,7 +1564,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;
@@ -1581,14 +1613,14 @@ static int dvb_register(struct cx23885_tsport *port)
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 +1637,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 +1661,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,7 +1687,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
int cx23885_dvb_unregister(struct cx23885_tsport *port)
{
- struct videobuf_dvb_frontend *fe0;
+ struct vb2_dvb_frontend *fe0;
/* FIXME: in an error condition where the we have
* an expected number of frontends (attach problem)
@@ -1651,9 +1696,9 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
* This comment only applies to future boards IF they
* implement MFE support.
*/
- fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+ 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 +1713,3 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
return 0;
}
-
diff --git a/drivers/media/pci/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c
index 5444cc5..6f817d8 100644
--- a/drivers/media/pci/cx23885/cx23885-f300.c
+++ b/drivers/media/pci/cx23885/cx23885-f300.c
@@ -22,10 +22,6 @@
* 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"
diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c
index 4887314..fd71306 100644
--- a/drivers/media/pci/cx23885/cx23885-i2c.c
+++ b/drivers/media/pci/cx23885/cx23885-i2c.c
@@ -13,10 +13,6 @@
* 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:
- */
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index 1940c18..9d37fe6 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -28,11 +28,6 @@
* 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>
diff --git a/drivers/media/pci/cx23885/cx23885-input.h b/drivers/media/pci/cx23885/cx23885-input.h
index 87dc44e..6199c7e 100644
--- a/drivers/media/pci/cx23885/cx23885-input.h
+++ b/drivers/media/pci/cx23885/cx23885-input.h
@@ -14,11 +14,6 @@
* 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_
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c
index 271d69d..d2cdd40 100644
--- a/drivers/media/pci/cx23885/cx23885-ioctl.c
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.c
@@ -15,10 +15,6 @@
* 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;
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h
index 92d9f07..cc5dbb6 100644
--- a/drivers/media/pci/cx23885/cx23885-ioctl.h
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.h
@@ -15,10 +15,6 @@
* 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_
diff --git a/drivers/media/pci/cx23885/cx23885-ir.c b/drivers/media/pci/cx23885/cx23885-ir.c
index bfef193..89dc4cc 100644
--- a/drivers/media/pci/cx23885/cx23885-ir.c
+++ b/drivers/media/pci/cx23885/cx23885-ir.c
@@ -14,11 +14,6 @@
* 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>
diff --git a/drivers/media/pci/cx23885/cx23885-ir.h b/drivers/media/pci/cx23885/cx23885-ir.h
index 0c9d8bd..8e93d1f 100644
--- a/drivers/media/pci/cx23885/cx23885-ir.h
+++ b/drivers/media/pci/cx23885/cx23885-ir.h
@@ -14,11 +14,6 @@
* 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_
diff --git a/drivers/media/pci/cx23885/cx23885-reg.h b/drivers/media/pci/cx23885/cx23885-reg.h
index a99936e..2d3cbaf 100644
--- a/drivers/media/pci/cx23885/cx23885-reg.h
+++ b/drivers/media/pci/cx23885/cx23885-reg.h
@@ -13,10 +13,6 @@
* 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_
diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c
index a1154f0..67b71f9 100644
--- a/drivers/media/pci/cx23885/cx23885-vbi.c
+++ b/drivers/media/pci/cx23885/cx23885-vbi.c
@@ -13,10 +13,6 @@
* 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[1] = 272;
+ 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] = 6;
+ f->fmt.vbi.start[1] = 318;
+ 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,
+};
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 91e4cb4..f0ea904 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -13,10 +13,6 @@
* 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 = norm_maxw(dev->tvnorm);
+ 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;
}
-
diff --git a/drivers/media/pci/cx23885/cx23885-video.h b/drivers/media/pci/cx23885/cx23885-video.h
index c961a2b..291e8f3 100644
--- a/drivers/media/pci/cx23885/cx23885-video.h
+++ b/drivers/media/pci/cx23885/cx23885-video.h
@@ -12,11 +12,6 @@
* 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_
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
index 0e086c0..0e4f406 100644
--- a/drivers/media/pci/cx23885/cx23885.h
+++ b/drivers/media/pci/cx23885/cx23885.h
@@ -13,10 +13,6 @@
* 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>
@@ -25,19 +21,20 @@
#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 */
@@ -131,14 +125,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 +132,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 +151,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 +238,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 +247,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;
@@ -339,8 +306,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 +328,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 +336,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 +376,6 @@ struct cx23885_dev {
} bridge;
/* Analog video */
- u32 resources;
unsigned int input;
unsigned int audinput; /* Selectable audio input */
u32 tvaudio;
@@ -417,7 +385,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 +402,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 +495,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 +543,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 +562,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 +569,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 +601,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,
diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
index 2c951de..c1aa888 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.c
+++ b/drivers/media/pci/cx23885/cx23888-ir.c
@@ -14,11 +14,6 @@
* 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>
@@ -263,7 +258,7 @@ static inline unsigned int lpf_count_to_us(unsigned int count)
}
/*
- * FIFO register pulse width count compuations
+ * FIFO register pulse width count computations
*/
static u32 clock_divider_to_resolution(u16 divider)
{
diff --git a/drivers/media/pci/cx23885/cx23888-ir.h b/drivers/media/pci/cx23885/cx23888-ir.h
index d2de41c..ff74a93 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.h
+++ b/drivers/media/pci/cx23885/cx23888-ir.h
@@ -14,11 +14,6 @@
* 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_
diff --git a/drivers/media/pci/cx23885/netup-eeprom.c b/drivers/media/pci/cx23885/netup-eeprom.c
index 98a48f5..b6542ee 100644
--- a/drivers/media/pci/cx23885/netup-eeprom.c
+++ b/drivers/media/pci/cx23885/netup-eeprom.c
@@ -17,10 +17,6 @@
* 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.
*/
#
diff --git a/drivers/media/pci/cx23885/netup-eeprom.h b/drivers/media/pci/cx23885/netup-eeprom.h
index 13926e1..90cac5b 100644
--- a/drivers/media/pci/cx23885/netup-eeprom.h
+++ b/drivers/media/pci/cx23885/netup-eeprom.h
@@ -16,10 +16,6 @@
* 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
diff --git a/drivers/media/pci/cx23885/netup-init.c b/drivers/media/pci/cx23885/netup-init.c
index 0044fef..76d9487 100644
--- a/drivers/media/pci/cx23885/netup-init.c
+++ b/drivers/media/pci/cx23885/netup-init.c
@@ -17,10 +17,6 @@
* 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"
diff --git a/drivers/media/pci/cx23885/netup-init.h b/drivers/media/pci/cx23885/netup-init.h
index d26ae4b..daaa212 100644
--- a/drivers/media/pci/cx23885/netup-init.h
+++ b/drivers/media/pci/cx23885/netup-init.h
@@ -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);
diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c
index 1f43be0..a664997 100644
--- a/drivers/media/pci/cx25821/cx25821-video-upstream.c
+++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c
@@ -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++;
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index da8f848..c82e855 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -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;
}
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index 8b1b41d..be87fbd 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -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))
/****************************************************************************/
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index e8826c5..ed11716 100644
--- a/drivers/media/pci/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -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)
diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c
index 19a7c9b..ab6d5d2 100644
--- a/drivers/media/pci/ivtv/ivtv-irq.c
+++ b/drivers/media/pci/ivtv/ivtv-irq.c
@@ -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);
diff --git a/drivers/media/pci/mantis/hopper_vp3028.c b/drivers/media/pci/mantis/hopper_vp3028.c
index 68a29f8..1032db6 100644
--- a/drivers/media/pci/mantis/hopper_vp3028.c
+++ b/drivers/media/pci/mantis/hopper_vp3028.c
@@ -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,
};
diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h
index f2410cf..8ff448b 100644
--- a/drivers/media/pci/mantis/mantis_common.h
+++ b/drivers/media/pci/mantis/mantis_common.h
@@ -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;
diff --git a/drivers/media/pci/mantis/mantis_vp1033.c b/drivers/media/pci/mantis/mantis_vp1033.c
index 115003e8..12a6adb 100644
--- a/drivers/media/pci/mantis/mantis_vp1033.c
+++ b/drivers/media/pci/mantis/mantis_vp1033.c
@@ -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,
diff --git a/drivers/media/pci/mantis/mantis_vp1034.c b/drivers/media/pci/mantis/mantis_vp1034.c
index 430ae84..7c1bd16 100644
--- a/drivers/media/pci/mantis/mantis_vp1034.c
+++ b/drivers/media/pci/mantis/mantis_vp1034.c
@@ -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,
};
diff --git a/drivers/media/pci/mantis/mantis_vp1041.c b/drivers/media/pci/mantis/mantis_vp1041.c
index 07a2074..7082fcb 100644
--- a/drivers/media/pci/mantis/mantis_vp1041.c
+++ b/drivers/media/pci/mantis/mantis_vp1041.c
@@ -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,
};
diff --git a/drivers/media/pci/mantis/mantis_vp2033.c b/drivers/media/pci/mantis/mantis_vp2033.c
index 1ca6837..8d48b5a 100644
--- a/drivers/media/pci/mantis/mantis_vp2033.c
+++ b/drivers/media/pci/mantis/mantis_vp2033.c
@@ -37,12 +37,12 @@
#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,
};
diff --git a/drivers/media/pci/mantis/mantis_vp2040.c b/drivers/media/pci/mantis/mantis_vp2040.c
index d480741..8dd17d7 100644
--- a/drivers/media/pci/mantis/mantis_vp2040.c
+++ b/drivers/media/pci/mantis/mantis_vp2040.c
@@ -37,12 +37,12 @@
#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,
};
diff --git a/drivers/media/pci/mantis/mantis_vp3030.c b/drivers/media/pci/mantis/mantis_vp3030.c
index c09308cd..5c1dd92 100644
--- a/drivers/media/pci/mantis/mantis_vp3030.c
+++ b/drivers/media/pci/mantis/mantis_vp3030.c
@@ -35,11 +35,11 @@
#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,
diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c
index 9e82d21..039bed3 100644
--- a/drivers/media/pci/ngene/ngene-cards.c
+++ b/drivers/media/pci/ngene/ngene-cards.c
@@ -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 },
diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c
index 4930b55..e29bc3af4 100644
--- a/drivers/media/pci/ngene/ngene-core.c
+++ b/drivers/media/pci/ngene/ngene-core.c
@@ -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;
}
/***********************************/
diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c
index fcb16a6..59bb285 100644
--- a/drivers/media/pci/ngene/ngene-dvb.c
+++ b/drivers/media/pci/ngene/ngene-dvb.c
@@ -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,
diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h
index 22c39ff..51e2fbd 100644
--- a/drivers/media/pci/ngene/ngene.h
+++ b/drivers/media/pci/ngene/ngene.h
@@ -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/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c
index e042963..4f3b1dd 100644
--- a/drivers/media/pci/saa7164/saa7164-api.c
+++ b/drivers/media/pci/saa7164/saa7164-api.c
@@ -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
diff --git a/drivers/media/pci/solo6x10/Kconfig b/drivers/media/pci/solo6x10/Kconfig
index d9e06a6..0fb91dc 100644
--- a/drivers/media/pci/solo6x10/Kconfig
+++ b/drivers/media/pci/solo6x10/Kconfig
@@ -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
diff --git a/drivers/media/pci/solo6x10/solo6x10-disp.c b/drivers/media/pci/solo6x10/solo6x10-disp.c
index 5ea9cac..11c98f0 100644
--- a/drivers/media/pci/solo6x10/solo6x10-disp.c
+++ b/drivers/media/pci/solo6x10/solo6x10-disp.c
@@ -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;
diff --git a/drivers/media/pci/solo6x10/solo6x10-eeprom.c b/drivers/media/pci/solo6x10/solo6x10-eeprom.c
index af40b3a..da25ce4 100644
--- a/drivers/media/pci/solo6x10/solo6x10-eeprom.c
+++ b/drivers/media/pci/solo6x10/solo6x10-eeprom.c
@@ -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,
diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h
index c6154b0..72017b7 100644
--- a/drivers/media/pci/solo6x10/solo6x10.h
+++ b/drivers/media/pci/solo6x10/solo6x10.h
@@ -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,
diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig
index 0313015..f6f30ab 100644
--- a/drivers/media/pci/sta2x11/Kconfig
+++ b/drivers/media/pci/sta2x11/Kconfig
@@ -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
diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig
index 0dcb8cd..7b83151 100644
--- a/drivers/media/pci/ttpci/Kconfig
+++ b/drivers/media/pci/ttpci/Kconfig
@@ -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
diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile
index 9890596..49f71b1 100644
--- a/drivers/media/pci/ttpci/Makefile
+++ b/drivers/media/pci/ttpci/Makefile
@@ -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
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index f38329d..c1f0617 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -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
index 0000000..5425ba1
--- /dev/null
+++ b/drivers/media/pci/tw68/Kconfig
@@ -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
index 0000000..3d02f28
--- /dev/null
+++ b/drivers/media/pci/tw68/Makefile
@@ -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
index 0000000..a6fb48c
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68-core.c
@@ -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
index 0000000..f60b3a8
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68-reg.h
@@ -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
index 0000000..7439db2
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68-risc.c
@@ -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
index 0000000..5c94ac7
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68-video.c
@@ -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
index 0000000..2c8abe2
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68.h
@@ -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);
diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c
index bf34b93..b6801e0 100644
--- a/drivers/media/pci/zoran/zoran_device.c
+++ b/drivers/media/pci/zoran/zoran_device.c
@@ -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);
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 6d86646..bee9074 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -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"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index e5269da..8d3fcfe 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -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
@@ -49,6 +49,6 @@ obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/
obj-y += davinci/
-obj-$(CONFIG_ARCH_OMAP) += omap/
+obj-y += omap/
ccflags-y += -I$(srctree)/drivers/media/i2c
diff --git a/drivers/media/platform/blackfin/Kconfig b/drivers/media/platform/blackfin/Kconfig
index cc23997..68fa901 100644
--- a/drivers/media/platform/blackfin/Kconfig
+++ b/drivers/media/platform/blackfin/Kconfig
@@ -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
index 3a6d1d2..0000000
--- a/drivers/media/platform/coda.c
+++ /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