summaryrefslogtreecommitdiff
path: root/linux/drivers/media
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-01-02 09:35:27 -0200
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-01-02 09:35:27 -0200
commitc036738278216aac0276743b0eb1e88e5cfd1f25 (patch)
tree3415ee49f4624d59d60d3b39e0745315a8366426 /linux/drivers/media
parentfc7012444ff33c182360e0bade20bd56e2a42631 (diff)
parent70e0ec035b78cab8338a5b20518bfc1d1307b7ad (diff)
downloadmediapointer-dvb-s2-c036738278216aac0276743b0eb1e88e5cfd1f25.tar.gz
mediapointer-dvb-s2-c036738278216aac0276743b0eb1e88e5cfd1f25.tar.bz2
merge: http://linuxtv.org/hg/~mkrufky/tiger
From: Mauro Carvalho Chehab <mchehab@redhat.com> Priority: normal Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'linux/drivers/media')
-rw-r--r--linux/drivers/media/common/ir-keymaps.c61
-rw-r--r--linux/drivers/media/common/saa7146_fops.c21
-rw-r--r--linux/drivers/media/common/saa7146_i2c.c3
-rw-r--r--linux/drivers/media/common/saa7146_video.c5
-rw-r--r--linux/drivers/media/common/tuners/tda827x.c15
-rw-r--r--linux/drivers/media/common/tuners/tda8290.c63
-rw-r--r--linux/drivers/media/common/tuners/tuner-simple.c7
-rw-r--r--linux/drivers/media/common/tuners/tuner-xc2028.c23
-rw-r--r--linux/drivers/media/common/tuners/xc5000.c7
-rw-r--r--linux/drivers/media/dvb/b2c2/Kconfig3
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c2
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop-i2c.c9
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop.c2
-rw-r--r--linux/drivers/media/dvb/bt8xx/Kconfig2
-rw-r--r--linux/drivers/media/dvb/bt8xx/dst.c4
-rw-r--r--linux/drivers/media/dvb/dm1105/dm1105.c6
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_frontend.c2
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_net.c39
-rw-r--r--linux/drivers/media/dvb/dvb-usb/Kconfig46
-rw-r--r--linux/drivers/media/dvb/dvb-usb/af9005.c3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/af9015.c3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/anysee.c5
-rw-r--r--linux/drivers/media/dvb/dvb-usb/au6610.c3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/cxusb.c3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dib0700_core.c3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dib0700_devices.c6
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dibusb-common.c3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/digitv.c3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dtv5100.c3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c5
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dw2102.c14
-rw-r--r--linux/drivers/media/dvb/dvb-usb/gl861.c3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c140
-rw-r--r--linux/drivers/media/dvb/dvb-usb/gp8psk.c4
-rw-r--r--linux/drivers/media/dvb/dvb-usb/gp8psk.h1
-rw-r--r--linux/drivers/media/dvb/dvb-usb/m920x.c3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/opera1.c3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/ttusb2.c3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/usb-urb.c3
-rw-r--r--linux/drivers/media/dvb/frontends/Kconfig8
-rw-r--r--linux/drivers/media/dvb/frontends/Makefile1
-rw-r--r--linux/drivers/media/dvb/frontends/af9013.c15
-rw-r--r--linux/drivers/media/dvb/frontends/cx24113.c616
-rw-r--r--linux/drivers/media/dvb/frontends/cx24113.h8
-rw-r--r--linux/drivers/media/dvb/frontends/cx24116.c44
-rw-r--r--linux/drivers/media/dvb/frontends/cx24116.h3
-rw-r--r--linux/drivers/media/dvb/frontends/cx24123.c4
-rw-r--r--linux/drivers/media/dvb/frontends/dib7000p.h9
-rw-r--r--linux/drivers/media/dvb/frontends/dibx000_common.c4
-rw-r--r--linux/drivers/media/dvb/frontends/drx397xD.c12
-rw-r--r--linux/drivers/media/dvb/frontends/drx397xD_fw.h4
-rw-r--r--linux/drivers/media/dvb/frontends/s5h1420.c4
-rw-r--r--linux/drivers/media/dvb/frontends/stb0899_drv.c1
-rw-r--r--linux/drivers/media/dvb/frontends/zl10353.c7
-rw-r--r--linux/drivers/media/dvb/pluto2/pluto2.c3
-rw-r--r--linux/drivers/media/dvb/ttpci/Kconfig2
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110_v4l.c4
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-av.c2
-rw-r--r--linux/drivers/media/dvb/ttusb-budget/Kconfig2
-rw-r--r--linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c3
-rw-r--r--linux/drivers/media/dvb/ttusb-dec/Kconfig2
-rw-r--r--linux/drivers/media/radio/Kconfig19
-rw-r--r--linux/drivers/media/radio/Makefile1
-rw-r--r--linux/drivers/media/radio/dsbr100.c332
-rw-r--r--linux/drivers/media/radio/radio-aimslab.c10
-rw-r--r--linux/drivers/media/radio/radio-aztech.c10
-rw-r--r--linux/drivers/media/radio/radio-cadet.c10
-rw-r--r--linux/drivers/media/radio/radio-gemtek-pci.c10
-rw-r--r--linux/drivers/media/radio/radio-gemtek.c10
-rw-r--r--linux/drivers/media/radio/radio-maestro.c10
-rw-r--r--linux/drivers/media/radio/radio-maxiradio.c10
-rw-r--r--linux/drivers/media/radio/radio-mr800.c54
-rw-r--r--linux/drivers/media/radio/radio-rtrack2.c10
-rw-r--r--linux/drivers/media/radio/radio-sf16fmi.c10
-rw-r--r--linux/drivers/media/radio/radio-sf16fmr2.c10
-rw-r--r--linux/drivers/media/radio/radio-si470x.c14
-rw-r--r--linux/drivers/media/radio/radio-tea5764.c638
-rw-r--r--linux/drivers/media/radio/radio-terratec.c10
-rw-r--r--linux/drivers/media/radio/radio-trust.c10
-rw-r--r--linux/drivers/media/radio/radio-typhoon.c10
-rw-r--r--linux/drivers/media/radio/radio-zoltrix.c10
-rw-r--r--linux/drivers/media/video/Kconfig36
-rw-r--r--linux/drivers/media/video/Makefile13
-rw-r--r--linux/drivers/media/video/arv.c14
-rw-r--r--linux/drivers/media/video/au0828/au0828-i2c.c3
-rw-r--r--linux/drivers/media/video/bt8xx/bt832.c287
-rw-r--r--linux/drivers/media/video/bt8xx/bt832.h305
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-cards.c45
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-driver.c29
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-i2c.c3
-rw-r--r--linux/drivers/media/video/bw-qcam.c14
-rw-r--r--linux/drivers/media/video/c-qcam.c14
-rw-r--r--linux/drivers/media/video/cafe_ccic.c16
-rw-r--r--linux/drivers/media/video/cpia.c14
-rw-r--r--linux/drivers/media/video/cpia2/cpia2_v4l.c16
-rw-r--r--linux/drivers/media/video/cs5345.c226
-rw-r--r--linux/drivers/media/video/cs53l32a.c188
-rw-r--r--linux/drivers/media/video/cx18/Kconfig2
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-audio.c189
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.c2
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-vbi.c5
-rw-r--r--linux/drivers/media/video/cx18/cx18-cards.c8
-rw-r--r--linux/drivers/media/video/cx18/cx18-cards.h5
-rw-r--r--linux/drivers/media/video/cx18/cx18-controls.c5
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.c258
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.h27
-rw-r--r--linux/drivers/media/video/cx18/cx18-dvb.c4
-rw-r--r--linux/drivers/media/video/cx18/cx18-fileops.c43
-rw-r--r--linux/drivers/media/video/cx18/cx18-fileops.h4
-rw-r--r--linux/drivers/media/video/cx18/cx18-firmware.c170
-rw-r--r--linux/drivers/media/video/cx18/cx18-i2c.c28
-rw-r--r--linux/drivers/media/video/cx18/cx18-i2c.h1
-rw-r--r--linux/drivers/media/video/cx18/cx18-io.h6
-rw-r--r--linux/drivers/media/video/cx18/cx18-ioctl.c63
-rw-r--r--linux/drivers/media/video/cx18/cx18-ioctl.h2
-rw-r--r--linux/drivers/media/video/cx18/cx18-mailbox.c36
-rw-r--r--linux/drivers/media/video/cx18/cx18-mailbox.h7
-rw-r--r--linux/drivers/media/video/cx18/cx18-queue.c82
-rw-r--r--linux/drivers/media/video/cx18/cx18-queue.h19
-rw-r--r--linux/drivers/media/video/cx18/cx18-scb.c1
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.c126
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.h3
-rw-r--r--linux/drivers/media/video/cx18/cx18-vbi.c5
-rw-r--r--linux/drivers/media/video/cx18/cx18-version.h2
-rw-r--r--linux/drivers/media/video/cx18/cx23418.h6
-rw-r--r--linux/drivers/media/video/cx23885/Kconfig4
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-417.c15
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-cards.c12
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-dvb.c1
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-i2c.c3
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-video.c22
-rw-r--r--linux/drivers/media/video/cx23885/cx23885.h1
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-audio.c14
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-core.c446
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-core.h7
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-firmware.c2
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-vbi.c2
-rw-r--r--linux/drivers/media/video/cx88/Kconfig2
-rw-r--r--linux/drivers/media/video/cx88/cx88-alsa.c3
-rw-r--r--linux/drivers/media/video/cx88/cx88-blackbird.c25
-rw-r--r--linux/drivers/media/video/cx88/cx88-dvb.c48
-rw-r--r--linux/drivers/media/video/cx88/cx88-mpeg.c3
-rw-r--r--linux/drivers/media/video/cx88/cx88-video.c27
-rw-r--r--linux/drivers/media/video/cx88/cx88.h2
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-audio.c126
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c1311
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-core.c307
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-dvb.c14
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-i2c.c41
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-input.c4
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-reg.h38
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c865
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h85
-rw-r--r--linux/drivers/media/video/et61x251/et61x251_core.c20
-rw-r--r--linux/drivers/media/video/gspca/Kconfig1
-rw-r--r--linux/drivers/media/video/gspca/Makefile2
-rw-r--r--linux/drivers/media/video/gspca/conex.c2
-rw-r--r--linux/drivers/media/video/gspca/etoms.c4
-rw-r--r--linux/drivers/media/video/gspca/finepix.c2
-rw-r--r--linux/drivers/media/video/gspca/gspca.c93
-rw-r--r--linux/drivers/media/video/gspca/gspca.h6
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_bridge.h7
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_core.c100
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c135
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h14
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_ov9650.c282
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_ov9650.h164
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_po1030.c166
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_po1030.h10
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c202
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h19
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c213
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h25
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_sensor.h14
-rw-r--r--linux/drivers/media/video/gspca/mars.c2
-rw-r--r--linux/drivers/media/video/gspca/ov519.c17
-rw-r--r--linux/drivers/media/video/gspca/ov534.c662
-rw-r--r--linux/drivers/media/video/gspca/pac207.c7
-rw-r--r--linux/drivers/media/video/gspca/pac7311.c5
-rw-r--r--linux/drivers/media/video/gspca/sonixb.c4
-rw-r--r--linux/drivers/media/video/gspca/sonixj.c283
-rw-r--r--linux/drivers/media/video/gspca/spca500.c4
-rw-r--r--linux/drivers/media/video/gspca/spca501.c2
-rw-r--r--linux/drivers/media/video/gspca/spca505.c2
-rw-r--r--linux/drivers/media/video/gspca/spca506.c2
-rw-r--r--linux/drivers/media/video/gspca/spca508.c2
-rw-r--r--linux/drivers/media/video/gspca/spca561.c535
-rw-r--r--linux/drivers/media/video/gspca/stk014.c8
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/Kconfig9
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/Makefile9
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx.c522
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx.h107
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c535
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h263
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c430
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h297
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h92
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c251
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h315
-rw-r--r--linux/drivers/media/video/gspca/sunplus.c6
-rw-r--r--linux/drivers/media/video/gspca/t613.c4
-rw-r--r--linux/drivers/media/video/gspca/tv8532.c2
-rw-r--r--linux/drivers/media/video/gspca/vc032x.c1030
-rw-r--r--linux/drivers/media/video/gspca/zc3xx-reg.h8
-rw-r--r--linux/drivers/media/video/gspca/zc3xx.c812
-rw-r--r--linux/drivers/media/video/hexium_gemini.c2
-rw-r--r--linux/drivers/media/video/hexium_orion.c2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-controls.c16
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.c221
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.h52
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-fileops.c48
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-fileops.h4
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-gpio.c324
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-gpio.h3
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-i2c.c341
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-i2c.h13
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-ioctl.c94
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-routing.c12
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-streams.c23
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-vbi.c17
-rw-r--r--linux/drivers/media/video/ivtv/ivtvfb.c91
-rw-r--r--linux/drivers/media/video/m52790.c175
-rw-r--r--linux/drivers/media/video/meye.c12
-rw-r--r--linux/drivers/media/video/msp3400-driver.c406
-rw-r--r--linux/drivers/media/video/msp3400-driver.h7
-rw-r--r--linux/drivers/media/video/msp3400-kthreads.c34
-rw-r--r--linux/drivers/media/video/mt9m001.c79
-rw-r--r--linux/drivers/media/video/mt9m111.c140
-rw-r--r--linux/drivers/media/video/mt9t031.c744
-rw-r--r--linux/drivers/media/video/mt9v022.c65
-rw-r--r--linux/drivers/media/video/mxb.c2
-rw-r--r--linux/drivers/media/video/omap24xxcam-dma.c601
-rw-r--r--linux/drivers/media/video/omap24xxcam.c1907
-rw-r--r--linux/drivers/media/video/omap24xxcam.h593
-rw-r--r--linux/drivers/media/video/ov511.c16
-rw-r--r--linux/drivers/media/video/ov7670.c2
-rw-r--r--linux/drivers/media/video/ov772x.c247
-rw-r--r--linux/drivers/media/video/pms.c14
-rw-r--r--linux/drivers/media/video/pvrusb2/Kconfig2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c11
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h4
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c29
-rw-r--r--linux/drivers/media/video/pwc/pwc-ctrl.c4
-rw-r--r--linux/drivers/media/video/pwc/pwc-if.c20
-rw-r--r--linux/drivers/media/video/pwc/pwc-v4l.c2
-rw-r--r--linux/drivers/media/video/pwc/pwc.h4
-rw-r--r--linux/drivers/media/video/pxa_camera.c541
-rw-r--r--linux/drivers/media/video/s2255drv.c12
-rw-r--r--linux/drivers/media/video/saa5246a.c13
-rw-r--r--linux/drivers/media/video/saa5249.c16
-rw-r--r--linux/drivers/media/video/saa7115.c762
-rw-r--r--linux/drivers/media/video/saa7127.c420
-rw-r--r--linux/drivers/media/video/saa7134/Kconfig4
-rw-r--r--linux/drivers/media/video/saa7134/saa6752hs.c2
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-cards.c94
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-dvb.c18
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-empress.c23
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-i2c.c3
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-input.c15
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-video.c23
-rw-r--r--linux/drivers/media/video/saa7134/saa7134.h2
-rw-r--r--linux/drivers/media/video/saa717x.c611
-rw-r--r--linux/drivers/media/video/se401.c14
-rw-r--r--linux/drivers/media/video/sh_mobile_ceu_camera.c323
-rw-r--r--linux/drivers/media/video/sn9c102/sn9c102_core.c18
-rw-r--r--linux/drivers/media/video/soc_camera.c397
-rw-r--r--linux/drivers/media/video/soc_camera_platform.c17
-rw-r--r--linux/drivers/media/video/stk-webcam.c37
-rw-r--r--linux/drivers/media/video/stradis.c12
-rw-r--r--linux/drivers/media/video/stv680.c14
-rw-r--r--linux/drivers/media/video/tda7432.c267
-rw-r--r--linux/drivers/media/video/tda9840.c188
-rw-r--r--linux/drivers/media/video/tda9875.c354
-rw-r--r--linux/drivers/media/video/tea6415c.c49
-rw-r--r--linux/drivers/media/video/tea6420.c49
-rw-r--r--linux/drivers/media/video/tlv320aic23b.c141
-rw-r--r--linux/drivers/media/video/tuner-core.c397
-rw-r--r--linux/drivers/media/video/tvaudio.c715
-rw-r--r--linux/drivers/media/video/tvp514x.c1569
-rw-r--r--linux/drivers/media/video/tvp514x_regs.h297
-rw-r--r--linux/drivers/media/video/tvp5150.c948
-rw-r--r--linux/drivers/media/video/tw9910.c959
-rw-r--r--linux/drivers/media/video/upd64031a.c192
-rw-r--r--linux/drivers/media/video/upd64083.c169
-rw-r--r--linux/drivers/media/video/usbvideo/ibmcam.c4
-rw-r--r--linux/drivers/media/video/usbvideo/konicawc.c4
-rw-r--r--linux/drivers/media/video/usbvideo/quickcam_messenger.c9
-rw-r--r--linux/drivers/media/video/usbvideo/ultracam.c4
-rw-r--r--linux/drivers/media/video/usbvideo/usbvideo.c22
-rw-r--r--linux/drivers/media/video/usbvideo/vicam.c19
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-i2c.c3
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-video.c42
-rw-r--r--linux/drivers/media/video/uvc/uvc_ctrl.c143
-rw-r--r--linux/drivers/media/video/uvc/uvc_driver.c124
-rw-r--r--linux/drivers/media/video/uvc/uvc_queue.c23
-rw-r--r--linux/drivers/media/video/uvc/uvc_v4l2.c99
-rw-r--r--linux/drivers/media/video/uvc/uvc_video.c124
-rw-r--r--linux/drivers/media/video/uvc/uvcvideo.h24
-rw-r--r--linux/drivers/media/video/v4l1-compat.c164
-rw-r--r--linux/drivers/media/video/v4l2-common.c287
-rw-r--r--linux/drivers/media/video/v4l2-compat-ioctl32.c875
-rw-r--r--linux/drivers/media/video/v4l2-dev.c411
-rw-r--r--linux/drivers/media/video/v4l2-device.c86
-rw-r--r--linux/drivers/media/video/v4l2-ioctl.c36
-rw-r--r--linux/drivers/media/video/v4l2-subdev.c110
-rw-r--r--linux/drivers/media/video/vino.c13
-rw-r--r--linux/drivers/media/video/vivi.c12
-rw-r--r--linux/drivers/media/video/vp27smpx.c126
-rw-r--r--linux/drivers/media/video/w9966.c16
-rw-r--r--linux/drivers/media/video/w9968cf.c39
-rw-r--r--linux/drivers/media/video/wm8739.c188
-rw-r--r--linux/drivers/media/video/wm8775.c221
-rw-r--r--linux/drivers/media/video/zc0301/zc0301_core.c18
-rw-r--r--linux/drivers/media/video/zoran/zoran_card.c2
-rw-r--r--linux/drivers/media/video/zoran/zoran_driver.c25
-rw-r--r--linux/drivers/media/video/zr364xx.c7
317 files changed, 24646 insertions, 10665 deletions
diff --git a/linux/drivers/media/common/ir-keymaps.c b/linux/drivers/media/common/ir-keymaps.c
index 6c0a80f45..ee9931f56 100644
--- a/linux/drivers/media/common/ir-keymaps.c
+++ b/linux/drivers/media/common/ir-keymaps.c
@@ -2441,6 +2441,67 @@ IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel);
+/* Kworld Plus TV Analog Lite PCI IR
+ Mauro Carvalho Chehab <mchehab@infradead.org>
+ */
+IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE] = {
+ [0x0c] = KEY_PROG1, /* Kworld key */
+ [0x16] = KEY_CLOSECD, /* -> ) */
+ [0x1d] = KEY_POWER2,
+
+ [0x00] = KEY_1,
+ [0x01] = KEY_2,
+ [0x02] = KEY_3, /* Two keys have the same code: 3 and left */
+ [0x03] = KEY_4, /* Two keys have the same code: 3 and right */
+ [0x04] = KEY_5,
+ [0x05] = KEY_6,
+ [0x06] = KEY_7,
+ [0x07] = KEY_8,
+ [0x08] = KEY_9,
+ [0x0a] = KEY_0,
+
+ [0x09] = KEY_AGAIN,
+ [0x14] = KEY_MUTE,
+
+ [0x20] = KEY_UP,
+ [0x21] = KEY_DOWN,
+ [0x0b] = KEY_ENTER,
+
+ [0x10] = KEY_CHANNELUP,
+ [0x11] = KEY_CHANNELDOWN,
+
+ /* Couldn't map key left/key right since those
+ conflict with '3' and '4' scancodes
+ I dunno what the original driver does
+ */
+
+ [0x13] = KEY_VOLUMEUP,
+ [0x12] = KEY_VOLUMEDOWN,
+
+ /* The lower part of the IR
+ There are several duplicated keycodes there.
+ Most of them conflict with digits.
+ Add mappings just to the unused scancodes.
+ Somehow, the original driver has a way to know,
+ but this doesn't seem to be on some GPIO.
+ Also, it is not related to the time between keyup
+ and keydown.
+ */
+ [0x19] = KEY_PAUSE, /* Timeshift */
+ [0x1a] = KEY_STOP,
+ [0x1b] = KEY_RECORD,
+
+ [0x22] = KEY_TEXT,
+
+ [0x15] = KEY_AUDIO, /* ((*)) */
+ [0x0f] = KEY_ZOOM,
+ [0x1c] = KEY_SHUFFLE, /* snapshot */
+
+ [0x18] = KEY_RED, /* B */
+ [0x23] = KEY_GREEN, /* C */
+};
+EXPORT_SYMBOL_GPL(ir_codes_kworld_plus_tv_analog);
+
IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
[0x20] = KEY_LIST,
[0x00] = KEY_POWER,
diff --git a/linux/drivers/media/common/saa7146_fops.c b/linux/drivers/media/common/saa7146_fops.c
index cd4f95860..b1ee5e3d9 100644
--- a/linux/drivers/media/common/saa7146_fops.c
+++ b/linux/drivers/media/common/saa7146_fops.c
@@ -193,9 +193,9 @@ void saa7146_buffer_timeout(unsigned long data)
/********************************************************************************/
/* file operations */
-static int fops_open(struct inode *inode, struct file *file)
+static int fops_open(struct file *file)
{
- unsigned int minor = iminor(inode);
+ unsigned int minor = video_devdata(file)->minor;
struct saa7146_dev *h = NULL, *dev = NULL;
struct list_head *list;
struct saa7146_fh *fh = NULL;
@@ -203,7 +203,7 @@ static int fops_open(struct inode *inode, struct file *file)
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- DEB_EE(("inode:%p, file:%p, minor:%d\n",inode,file,minor));
+ DEB_EE(("file:%p, minor:%d\n", file, minor));
if (mutex_lock_interruptible(&saa7146_devices_lock))
return -ERESTARTSYS;
@@ -256,7 +256,7 @@ static int fops_open(struct inode *inode, struct file *file)
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
result = saa7146_vbi_uops.open(dev,file);
if (dev->ext_vv_data->vbi_fops.open)
- dev->ext_vv_data->vbi_fops.open(inode, file);
+ dev->ext_vv_data->vbi_fops.open(file);
} else {
DEB_S(("initializing video...\n"));
result = saa7146_video_uops.open(dev,file);
@@ -281,12 +281,12 @@ out:
return result;
}
-static int fops_release(struct inode *inode, struct file *file)
+static int fops_release(struct file *file)
{
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev;
- DEB_EE(("inode:%p, file:%p\n",inode,file));
+ DEB_EE(("file:%p\n", file));
if (mutex_lock_interruptible(&saa7146_devices_lock))
return -ERESTARTSYS;
@@ -295,7 +295,7 @@ static int fops_release(struct inode *inode, struct file *file)
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
saa7146_vbi_uops.release(dev,file);
if (dev->ext_vv_data->vbi_fops.release)
- dev->ext_vv_data->vbi_fops.release(inode, file);
+ dev->ext_vv_data->vbi_fops.release(file);
} else {
saa7146_video_uops.release(dev,file);
}
@@ -309,10 +309,10 @@ static int fops_release(struct inode *inode, struct file *file)
return 0;
}
-static int fops_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long fops_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
/*
- DEB_EE(("inode:%p, file:%p, cmd:%d, arg:%li\n",inode, file, cmd, arg));
+ DEB_EE(("file:%p, cmd:%d, arg:%li\n", file, cmd, arg));
*/
return video_usercopy(file, cmd, arg, saa7146_video_do_ioctl);
}
@@ -417,7 +417,7 @@ static ssize_t fops_write(struct file *file, const char __user *data, size_t cou
}
}
-static const struct file_operations video_fops =
+static const struct v4l2_file_operations video_fops =
{
.owner = THIS_MODULE,
.open = fops_open,
@@ -427,7 +427,6 @@ static const struct file_operations video_fops =
.poll = fops_poll,
.mmap = fops_mmap,
.ioctl = fops_ioctl,
- .llseek = no_llseek,
};
static void vv_callback(struct saa7146_dev *dev, unsigned long status)
diff --git a/linux/drivers/media/common/saa7146_i2c.c b/linux/drivers/media/common/saa7146_i2c.c
index ae20d2729..255b14551 100644
--- a/linux/drivers/media/common/saa7146_i2c.c
+++ b/linux/drivers/media/common/saa7146_i2c.c
@@ -406,6 +406,9 @@ static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, in
static struct i2c_algorithm saa7146_algo = {
.master_xfer = saa7146_i2c_xfer,
.functionality = saa7146_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
diff --git a/linux/drivers/media/common/saa7146_video.c b/linux/drivers/media/common/saa7146_video.c
index 12717058e..416a37f1b 100644
--- a/linux/drivers/media/common/saa7146_video.c
+++ b/linux/drivers/media/common/saa7146_video.c
@@ -835,13 +835,14 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
* copying is done already, arg is a kernel pointer.
*/
-int saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
- int err = 0, result = 0, ee = 0;
+ long err = 0;
+ int result = 0, ee = 0;
struct saa7146_use_ops *ops;
struct videobuf_queue *q;
diff --git a/linux/drivers/media/common/tuners/tda827x.c b/linux/drivers/media/common/tuners/tda827x.c
index 83a017c53..a14fe817d 100644
--- a/linux/drivers/media/common/tuners/tda827x.c
+++ b/linux/drivers/media/common/tuners/tda827x.c
@@ -81,10 +81,11 @@ static void tda827x_set_std(struct dvb_frontend *fe,
mode = "xx";
}
- if (params->mode == V4L2_TUNER_RADIO)
+ if (params->mode == V4L2_TUNER_RADIO) {
priv->sgIF = 88; /* if frequency is 5.5 MHz */
-
- dprintk("setting tda827x to system %s\n", mode);
+ dprintk("setting tda827x to radio FM\n");
+ } else
+ dprintk("setting tda827x to system %s\n", mode);
}
@@ -200,7 +201,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(priv->i2c_adap, &msg, 1);
- priv->frequency = tuner_freq - if_freq; // FIXME
+ priv->frequency = params->frequency;
priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
return 0;
@@ -305,7 +306,7 @@ static int tda827xo_set_analog_params(struct dvb_frontend *fe,
reg2[1] = 0x08; /* Vsync en */
i2c_transfer(priv->i2c_adap, &msg, 1);
- priv->frequency = freq * 62500;
+ priv->frequency = params->frequency;
return 0;
}
@@ -592,7 +593,7 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(priv->i2c_adap, &msg, 1);
- priv->frequency = tuner_freq - if_freq; // FIXME
+ priv->frequency = params->frequency;
priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
return 0;
@@ -692,7 +693,7 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe,
tuner_reg[1] = 0x19 + (priv->lpsel << 1);
i2c_transfer(priv->i2c_adap, &msg, 1);
- priv->frequency = freq * 62500;
+ priv->frequency = params->frequency;
return 0;
}
diff --git a/linux/drivers/media/common/tuners/tda8290.c b/linux/drivers/media/common/tuners/tda8290.c
index 637849ec8..6eaaacca0 100644
--- a/linux/drivers/media/common/tuners/tda8290.c
+++ b/linux/drivers/media/common/tuners/tda8290.c
@@ -33,6 +33,9 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
+static int deemphasis_50;
+MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis");
+
/* ---------------------------------------------------------------------- */
struct tda8290_priv {
@@ -162,9 +165,34 @@ static void set_audio(struct dvb_frontend *fe,
mode = "xx";
}
- tuner_dbg("setting tda829x to system %s\n", mode);
+ if (params->mode == V4L2_TUNER_RADIO) {
+ priv->tda8290_easy_mode = 0x01; /* Start with MN values */
+ tuner_dbg("setting to radio FM\n");
+ } else {
+ tuner_dbg("setting tda829x to system %s\n", mode);
+ }
}
+struct {
+ unsigned char seq[2];
+} fm_mode[] = {
+ { { 0x01, 0x81} }, /* Put device into expert mode */
+ { { 0x03, 0x48} }, /* Disable NOTCH and VIDEO filters */
+ { { 0x04, 0x04} }, /* Disable color carrier filter (SSIF) */
+ { { 0x05, 0x04} }, /* ADC headroom */
+ { { 0x06, 0x10} }, /* group delay flat */
+
+ { { 0x07, 0x00} }, /* use the same radio DTO values as a tda8295 */
+ { { 0x08, 0x00} },
+ { { 0x09, 0x80} },
+ { { 0x0a, 0xda} },
+ { { 0x0b, 0x4b} },
+ { { 0x0c, 0x68} },
+
+ { { 0x0d, 0x00} }, /* PLL off, no video carrier detect */
+ { { 0x14, 0x00} }, /* disable auto mute if no video */
+};
+
static void tda8290_set_params(struct dvb_frontend *fe,
struct analog_parameters *params)
{
@@ -201,15 +229,30 @@ static void tda8290_set_params(struct dvb_frontend *fe,
tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
msleep(1);
- expert_mode[1] = priv->tda8290_easy_mode + 0x80;
- tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
- if (priv->tda8290_easy_mode & 0x60)
- tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
- else
- tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+ if (params->mode == V4L2_TUNER_RADIO) {
+ int i;
+ unsigned char deemphasis[] = { 0x13, 1 };
+
+ /* FIXME: allow using a different deemphasis */
+
+ if (deemphasis_50)
+ deemphasis[1] = 2;
+
+ for (i = 0; i < ARRAY_SIZE(fm_mode); i++)
+ tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2);
+
+ tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2);
+ } else {
+ expert_mode[1] = priv->tda8290_easy_mode + 0x80;
+ tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
+ if (priv->tda8290_easy_mode & 0x60)
+ tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
+ else
+ tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+ }
tda8290_i2c_bridge(fe, 1);
diff --git a/linux/drivers/media/common/tuners/tuner-simple.c b/linux/drivers/media/common/tuners/tuner-simple.c
index 0d9fc1bb2..e65c170c8 100644
--- a/linux/drivers/media/common/tuners/tuner-simple.c
+++ b/linux/drivers/media/common/tuners/tuner-simple.c
@@ -1095,7 +1095,12 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
memcpy(&fe->ops.tuner_ops, &simple_tuner_ops,
sizeof(struct dvb_tuner_ops));
- tuner_info("type set to %d (%s)\n", type, priv->tun->name);
+ if (type != priv->type)
+ tuner_warn("couldn't set type to %d. Using %d (%s) instead\n",
+ type, priv->type, priv->tun->name);
+ else
+ tuner_info("type set to %d (%s)\n",
+ priv->type, priv->tun->name);
if ((debug) || ((atv_input[priv->nr] > 0) ||
(dtv_input[priv->nr] > 0))) {
diff --git a/linux/drivers/media/common/tuners/tuner-xc2028.c b/linux/drivers/media/common/tuners/tuner-xc2028.c
index 7f43272ca..bd010379b 100644
--- a/linux/drivers/media/common/tuners/tuner-xc2028.c
+++ b/linux/drivers/media/common/tuners/tuner-xc2028.c
@@ -32,6 +32,12 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(debug, "0 (default) powers device off when not used.\n"
+ "1 keep device energized and with tuner ready all the times.\n"
+ " Faster, but consumes more power and keeps the device hotter\n");
+
static char audio_std[8];
module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
MODULE_PARM_DESC(audio_std,
@@ -1095,16 +1101,20 @@ static int xc2028_set_params(struct dvb_frontend *fe,
T_DIGITAL_TV, type, 0, demod);
}
-#if 0
-/* This is needed at sleep (S1/S3), but not at fe_standby. Otherwise,
- firmware will be loaded on every open()
- */
static int xc2028_sleep(struct dvb_frontend *fe)
{
struct xc2028_data *priv = fe->tuner_priv;
int rc = 0;
- tuner_dbg("%s called\n", __func__);
+ /* Avoid firmware reload on slow devices */
+ if (no_poweroff)
+ return 0;
+
+ tuner_dbg("Putting xc2028/3028 into poweroff mode.\n");
+ if (debug > 1) {
+ tuner_dbg("Printing sleep stack trace:\n");
+ dump_stack();
+ }
mutex_lock(&priv->lock);
@@ -1119,7 +1129,6 @@ static int xc2028_sleep(struct dvb_frontend *fe)
return rc;
}
-#endif
static int xc2028_dvb_release(struct dvb_frontend *fe)
{
@@ -1200,9 +1209,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
.get_frequency = xc2028_get_frequency,
.get_rf_strength = xc2028_signal,
.set_params = xc2028_set_params,
-#if 0
.sleep = xc2028_sleep,
-#endif
#if 0
int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
int (*get_status)(struct dvb_frontend *fe, u32 *status);
diff --git a/linux/drivers/media/common/tuners/xc5000.c b/linux/drivers/media/common/tuners/xc5000.c
index 8cfac7002..36c81febb 100644
--- a/linux/drivers/media/common/tuners/xc5000.c
+++ b/linux/drivers/media/common/tuners/xc5000.c
@@ -36,10 +36,6 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-static int xc5000_load_fw_on_attach;
-module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
-MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
-
static DEFINE_MUTEX(xc5000_list_mutex);
static LIST_HEAD(hybrid_tuner_instance_list);
@@ -1036,9 +1032,6 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
sizeof(struct dvb_tuner_ops));
- if (xc5000_load_fw_on_attach)
- xc5000_init(fe);
-
return fe;
fail:
mutex_unlock(&xc5000_list_mutex);
diff --git a/linux/drivers/media/dvb/b2c2/Kconfig b/linux/drivers/media/dvb/b2c2/Kconfig
index 73dc2ee9b..a8c6249c4 100644
--- a/linux/drivers/media/dvb/b2c2/Kconfig
+++ b/linux/drivers/media/dvb/b2c2/Kconfig
@@ -9,11 +9,12 @@ config DVB_B2C2_FLEXCOP
select DVB_STV0297 if !DVB_FE_CUSTOMISE
select DVB_BCM3510 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
select DVB_S5H1420 if !DVB_FE_CUSTOMISE
select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
select DVB_CX24123 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+ select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE
help
Support for the digital TV receiver chip made by B2C2 Inc. included in
Technisats PCI cards and USB boxes.
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index a127a4175..5cded3708 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -628,12 +628,14 @@ int flexcop_frontend_init(struct flexcop_device *fc)
}
/* try the cable dvb (stv0297) */
+ fc->fc_i2c_adap[0].no_base_addr = 1;
fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
if (fc->fe != NULL) {
fc->dev_type = FC_CABLE;
fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
goto fe_found;
}
+ fc->fc_i2c_adap[0].no_base_addr = 0;
/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
fc->fe = dvb_attach(mt312_attach,
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c
index 43a112ec6..01d27613f 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -47,9 +47,13 @@ static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */
ret;
- r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
ret = flexcop_i2c_operation(i2c->fc, &r100);
if (ret != 0) {
+ deb_i2c("Retrying operation\n");
+ r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
+ ret = flexcop_i2c_operation(i2c->fc, &r100);
+ }
+ if (ret != 0) {
deb_i2c("read failed. %d\n", ret);
return ret;
}
@@ -205,6 +209,9 @@ static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm flexcop_algo = {
.master_xfer = flexcop_master_xfer,
.functionality = flexcop_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
int flexcop_i2c_init(struct flexcop_device *fc)
diff --git a/linux/drivers/media/dvb/b2c2/flexcop.c b/linux/drivers/media/dvb/b2c2/flexcop.c
index 5f79c8dc3..676413a91 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop.c
+++ b/linux/drivers/media/dvb/b2c2/flexcop.c
@@ -270,7 +270,7 @@ int flexcop_device_initialize(struct flexcop_device *fc)
/* do the MAC address reading after initializing the dvb_adapter */
if (fc->get_mac_addr(fc, 0) == 0) {
u8 *b = fc->dvb_adapter.proposed_mac;
- info("MAC address = %02x:%02x:%02x:%02x:%02x:%02x", b[0],b[1],b[2],b[3],b[4],b[5]);
+ info("MAC address = %pM", b);
flexcop_set_mac_filter(fc,b);
flexcop_mac_filter_ctrl(fc,1);
} else
diff --git a/linux/drivers/media/dvb/bt8xx/Kconfig b/linux/drivers/media/dvb/bt8xx/Kconfig
index 7e9c090fc..27edb0ece 100644
--- a/linux/drivers/media/dvb/bt8xx/Kconfig
+++ b/linux/drivers/media/dvb/bt8xx/Kconfig
@@ -8,7 +8,7 @@ config DVB_BT8XX
select DVB_OR51211 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
diff --git a/linux/drivers/media/dvb/bt8xx/dst.c b/linux/drivers/media/dvb/bt8xx/dst.c
index aa3db57d3..29e8f1546 100644
--- a/linux/drivers/media/dvb/bt8xx/dst.c
+++ b/linux/drivers/media/dvb/bt8xx/dst.c
@@ -917,9 +917,7 @@ static int dst_get_mac(struct dst_state *state)
}
memset(&state->mac_address, '\0', 8);
memcpy(&state->mac_address, &state->rxbuffer, 6);
- dprintk(verbose, DST_ERROR, 1, "MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]",
- state->mac_address[0], state->mac_address[1], state->mac_address[2],
- state->mac_address[4], state->mac_address[5], state->mac_address[6]);
+ dprintk(verbose, DST_ERROR, 1, "MAC Address=[%pM]", state->mac_address);
return 0;
}
diff --git a/linux/drivers/media/dvb/dm1105/dm1105.c b/linux/drivers/media/dvb/dm1105/dm1105.c
index 100a7f661..b054d056d 100644
--- a/linux/drivers/media/dvb/dm1105/dm1105.c
+++ b/linux/drivers/media/dvb/dm1105/dm1105.c
@@ -330,6 +330,9 @@ static u32 functionality(struct i2c_adapter *adap)
static struct i2c_algorithm dm1105_algo = {
.master_xfer = dm1105_i2c_xfer,
.functionality = functionality,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static inline struct dm1105dvb *feed_to_dm1105dvb(struct dvb_demux_feed *feed)
@@ -700,8 +703,7 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
};
dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
- dev_info(&dm1105dvb->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ dev_info(&dm1105dvb->pdev->dev, "MAC %pM\n", mac);
}
static int __devinit dm1105_probe(struct pci_dev *pdev,
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
index e7adf9f47..d1a9e587c 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -591,7 +591,7 @@ restart:
if (fe->ops.tune)
fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
- if (s != fepriv->status) {
+ if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
dprintk("%s: state changed, adding current state\n", __func__);
dvb_frontend_add_event(fe, s);
fepriv->status = s;
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_net.c b/linux/drivers/media/dvb/dvb-core/dvb_net.c
index e0d60cdc4..f0cd3b8ed 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_net.c
@@ -352,7 +352,7 @@ static inline void reset_ule( struct dvb_net_priv *p )
*/
static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
{
- struct dvb_net_priv *priv = dev->priv;
+ struct dvb_net_priv *priv = netdev_priv(dev);
unsigned long skipped = 0L;
const u8 *ts, *ts_end, *from_where = NULL;
u8 ts_remain = 0, how_much = 0, new_ts = 1;
@@ -467,8 +467,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
/* Drop partly decoded SNDU, reset state, resync on PUSI. */
if (priv->ule_skb) {
dev_kfree_skb( priv->ule_skb );
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_frame_errors++;
}
reset_ule(priv);
priv->need_pusi = 1;
@@ -580,7 +580,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
dev->name);
- ((struct dvb_net_priv *)dev->priv)->stats.rx_dropped++;
+ priv->stats.rx_dropped++;
return;
}
@@ -820,7 +820,8 @@ static void dvb_net_sec(struct net_device *dev,
{
u8 *eth;
struct sk_buff *skb;
- struct net_device_stats *stats = &(((struct dvb_net_priv *) dev->priv)->stats);
+ struct net_device_stats *stats =
+ &((struct dvb_net_priv *) netdev_priv(dev))->stats;
int snap = 0;
/* note: pkt_len includes a 32bit checksum */
@@ -937,7 +938,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev,
struct dmx_section_filter **secfilter,
u8 *mac, u8 *mac_mask)
{
- struct dvb_net_priv *priv = dev->priv;
+ struct dvb_net_priv *priv = netdev_priv(dev);
int ret;
*secfilter=NULL;
@@ -981,7 +982,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev,
static int dvb_net_feed_start(struct net_device *dev)
{
int ret = 0, i;
- struct dvb_net_priv *priv = dev->priv;
+ struct dvb_net_priv *priv = netdev_priv(dev);
struct dmx_demux *demux = priv->demux;
unsigned char *mac = (unsigned char *) dev->dev_addr;
@@ -1080,7 +1081,7 @@ error:
static int dvb_net_feed_stop(struct net_device *dev)
{
- struct dvb_net_priv *priv = dev->priv;
+ struct dvb_net_priv *priv = netdev_priv(dev);
int i, ret = 0;
dprintk("%s\n", __func__);
@@ -1133,7 +1134,7 @@ static int dvb_net_feed_stop(struct net_device *dev)
static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc)
{
- struct dvb_net_priv *priv = dev->priv;
+ struct dvb_net_priv *priv = netdev_priv(dev);
if (priv->multi_num == DVB_NET_MULTICAST_MAX)
return -ENOMEM;
@@ -1153,7 +1154,7 @@ static void wq_set_multicast_list (struct work_struct *work)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
struct net_device *dev = data;
- struct dvb_net_priv *priv = dev->priv;
+ struct dvb_net_priv *priv = netdev_priv(dev);
#else
struct dvb_net_priv *priv =
container_of(work, struct dvb_net_priv, set_multicast_list_wq);
@@ -1210,7 +1211,7 @@ static void wq_set_multicast_list (struct work_struct *work)
static void dvb_net_set_multicast_list (struct net_device *dev)
{
- struct dvb_net_priv *priv = dev->priv;
+ struct dvb_net_priv *priv = netdev_priv(dev);
schedule_work(&priv->set_multicast_list_wq);
}
@@ -1238,7 +1239,7 @@ static void wq_restart_net_feed (struct work_struct *work)
static int dvb_net_set_mac (struct net_device *dev, void *p)
{
- struct dvb_net_priv *priv = dev->priv;
+ struct dvb_net_priv *priv = netdev_priv(dev);
struct sockaddr *addr=p;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
@@ -1252,7 +1253,7 @@ static int dvb_net_set_mac (struct net_device *dev, void *p)
static int dvb_net_open(struct net_device *dev)
{
- struct dvb_net_priv *priv = dev->priv;
+ struct dvb_net_priv *priv = netdev_priv(dev);
priv->in_use++;
dvb_net_feed_start(dev);
@@ -1262,7 +1263,7 @@ static int dvb_net_open(struct net_device *dev)
static int dvb_net_stop(struct net_device *dev)
{
- struct dvb_net_priv *priv = dev->priv;
+ struct dvb_net_priv *priv = netdev_priv(dev);
priv->in_use--;
return dvb_net_feed_stop(dev);
@@ -1270,7 +1271,7 @@ static int dvb_net_stop(struct net_device *dev)
static struct net_device_stats * dvb_net_get_stats(struct net_device *dev)
{
- return &((struct dvb_net_priv*) dev->priv)->stats;
+ return &((struct dvb_net_priv *) netdev_priv(dev))->stats;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
@@ -1346,7 +1347,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
dvbnet->device[if_num] = net;
- priv = net->priv;
+ priv = netdev_priv(net);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
priv->net = net;
#endif
@@ -1386,7 +1387,7 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
if (!dvbnet->state[num])
return -EINVAL;
- priv = net->priv;
+ priv = netdev_priv(net);
if (priv->in_use)
return -EBUSY;
@@ -1442,7 +1443,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
netdev = dvbnet->device[dvbnetif->if_num];
- priv_data = netdev->priv;
+ priv_data = netdev_priv(netdev);
dvbnetif->pid=priv_data->pid;
dvbnetif->feedtype=priv_data->feedtype;
break;
@@ -1493,7 +1494,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
netdev = dvbnet->device[dvbnetif->if_num];
- priv_data = netdev->priv;
+ priv_data = netdev_priv(netdev);
dvbnetif->pid=priv_data->pid;
break;
}
diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig
index 62b68c291..49f7b20c2 100644
--- a/linux/drivers/media/dvb/dvb-usb/Kconfig
+++ b/linux/drivers/media/dvb/dvb-usb/Kconfig
@@ -24,8 +24,8 @@ config DVB_USB_A800
tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
depends on DVB_USB
select DVB_DIB3000MC
- select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
select DVB_PLL if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
help
Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
@@ -34,7 +34,7 @@ config DVB_USB_DIBUSB_MB
depends on DVB_USB
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_DIB3000MB
- select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
help
Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
@@ -55,7 +55,7 @@ config DVB_USB_DIBUSB_MC
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
depends on DVB_USB
select DVB_DIB3000MC
- select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
help
Support for USB2.0 DVB-T receivers based on reference designs made by
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
@@ -73,11 +73,11 @@ config DVB_USB_DIB0700
select DVB_DIB7000M
select DVB_DIB3000MC
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
select DVB_TUNER_DIB0070
+ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE
help
Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
USB bridge is also present in devices having the DiB7700 DVB-T-USB
@@ -95,7 +95,7 @@ config DVB_USB_UMT_010
depends on DVB_USB
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_DIB3000MC
- select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
help
Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
@@ -107,11 +107,11 @@ config DVB_USB_CXUSB
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
select DVB_DIB7000P if !DVB_FE_CUSTOMISE
select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
help
Say Y here to support the Conexant USB2.0 hybrid reference design.
Currently, only DVB and ATSC modes are supported, analog mode
@@ -124,9 +124,9 @@ config DVB_USB_M920X
tristate "Uli m920x DVB-T USB2.0 support"
depends on DVB_USB
select DVB_MT352 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
help
Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
Currently, only devices with a product id of
@@ -137,7 +137,7 @@ config DVB_USB_GL861
tristate "Genesys Logic GL861 USB2.0 support"
depends on DVB_USB
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
help
Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
receiver with USB ID 0db0:5581.
@@ -146,7 +146,7 @@ config DVB_USB_AU6610
tristate "Alcor Micro AU6610 USB2.0 support"
depends on DVB_USB
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
help
Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
@@ -198,8 +198,8 @@ config DVB_USB_NOVA_T_USB2
tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
depends on DVB_USB
select DVB_DIB3000MC
- select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
select DVB_PLL if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
help
Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
@@ -235,8 +235,8 @@ config DVB_USB_OPERA1
config DVB_USB_AF9005
tristate "Afatech AF9005 DVB-T USB1.1 support"
depends on DVB_USB && EXPERIMENTAL
- select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
help
Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
and the TerraTec Cinergy T USB XE (Rev.1)
@@ -284,7 +284,7 @@ config DVB_USB_DTV5100
tristate "AME DTV-5100 USB2.0 DVB-T support"
depends on DVB_USB
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
help
Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
@@ -293,9 +293,9 @@ config DVB_USB_AF9015
depends on DVB_USB && EXPERIMENTAL
select DVB_AF9013
select DVB_PLL if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
help
Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
diff --git a/linux/drivers/media/dvb/dvb-usb/af9005.c b/linux/drivers/media/dvb/dvb-usb/af9005.c
index ca5a0a4d2..fdf592625 100644
--- a/linux/drivers/media/dvb/dvb-usb/af9005.c
+++ b/linux/drivers/media/dvb/dvb-usb/af9005.c
@@ -500,6 +500,9 @@ static u32 af9005_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm af9005_i2c_algo = {
.master_xfer = af9005_i2c_xfer,
.functionality = af9005_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
diff --git a/linux/drivers/media/dvb/dvb-usb/af9015.c b/linux/drivers/media/dvb/dvb-usb/af9015.c
index e6e534e04..f0b57c739 100644
--- a/linux/drivers/media/dvb/dvb-usb/af9015.c
+++ b/linux/drivers/media/dvb/dvb-usb/af9015.c
@@ -318,6 +318,9 @@ static u32 af9015_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm af9015_i2c_algo = {
.master_xfer = af9015_i2c_xfer,
.functionality = af9015_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op)
diff --git a/linux/drivers/media/dvb/dvb-usb/anysee.c b/linux/drivers/media/dvb/dvb-usb/anysee.c
index cd2edbcaa..1dbf132a7 100644
--- a/linux/drivers/media/dvb/dvb-usb/anysee.c
+++ b/linux/drivers/media/dvb/dvb-usb/anysee.c
@@ -153,7 +153,7 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
- int ret, inc, i = 0;
+ int ret = 0, inc, i = 0;
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
@@ -199,6 +199,9 @@ static u32 anysee_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm anysee_i2c_algo = {
.master_xfer = anysee_master_xfer,
.functionality = anysee_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static int anysee_mt352_demod_init(struct dvb_frontend *fe)
diff --git a/linux/drivers/media/dvb/dvb-usb/au6610.c b/linux/drivers/media/dvb/dvb-usb/au6610.c
index eb34cc389..b2400d693 100644
--- a/linux/drivers/media/dvb/dvb-usb/au6610.c
+++ b/linux/drivers/media/dvb/dvb-usb/au6610.c
@@ -119,6 +119,9 @@ static u32 au6610_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm au6610_i2c_algo = {
.master_xfer = au6610_i2c_xfer,
.functionality = au6610_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
/* Callbacks for DVB USB */
diff --git a/linux/drivers/media/dvb/dvb-usb/cxusb.c b/linux/drivers/media/dvb/dvb-usb/cxusb.c
index 406d7fba3..f467cad8a 100644
--- a/linux/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/linux/drivers/media/dvb/dvb-usb/cxusb.c
@@ -213,6 +213,9 @@ static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm cxusb_i2c_algo = {
.master_xfer = cxusb_i2c_xfer,
.functionality = cxusb_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_core.c b/linux/drivers/media/dvb/dvb-usb/dib0700_core.c
index 2fbb7049a..807bff0e1 100644
--- a/linux/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/linux/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -252,6 +252,9 @@ static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
struct i2c_algorithm dib0700_i2c_algo = {
.master_xfer = dib0700_i2c_xfer,
.functionality = dib0700_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
index f28d3ae59..391732788 100644
--- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -446,13 +446,13 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
== NULL ? -ENODEV : 0;
}
-#define DEFAULT_RC_INTERVAL 150
+#define DEFAULT_RC_INTERVAL 50
static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
/* Number of keypresses to ignore before start repeating */
-#define RC_REPEAT_DELAY 2
-#define RC_REPEAT_DELAY_V1_20 5
+#define RC_REPEAT_DELAY 6
+#define RC_REPEAT_DELAY_V1_20 10
diff --git a/linux/drivers/media/dvb/dvb-usb/dibusb-common.c b/linux/drivers/media/dvb/dvb-usb/dibusb-common.c
index 8ee6cd4da..d774879df 100644
--- a/linux/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/linux/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -155,6 +155,9 @@ static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
struct i2c_algorithm dibusb_i2c_algo = {
.master_xfer = dibusb_i2c_xfer,
.functionality = dibusb_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
EXPORT_SYMBOL(dibusb_i2c_algo);
diff --git a/linux/drivers/media/dvb/dvb-usb/digitv.c b/linux/drivers/media/dvb/dvb-usb/digitv.c
index b545cf3ea..3a560dcdd 100644
--- a/linux/drivers/media/dvb/dvb-usb/digitv.c
+++ b/linux/drivers/media/dvb/dvb-usb/digitv.c
@@ -83,6 +83,9 @@ static u32 digitv_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm digitv_i2c_algo = {
.master_xfer = digitv_i2c_xfer,
.functionality = digitv_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
/* Callbacks for DVB USB */
diff --git a/linux/drivers/media/dvb/dvb-usb/dtv5100.c b/linux/drivers/media/dvb/dvb-usb/dtv5100.c
index 078ce92ca..e07a805f6 100644
--- a/linux/drivers/media/dvb/dvb-usb/dtv5100.c
+++ b/linux/drivers/media/dvb/dvb-usb/dtv5100.c
@@ -104,6 +104,9 @@ static u32 dtv5100_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm dtv5100_i2c_algo = {
.master_xfer = dtv5100_i2c_xfer,
.functionality = dtv5100_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
/* Callbacks for DVB USB */
diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
index ce8cd0c5d..8a7d87bcd 100644
--- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
@@ -91,10 +91,7 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
if (adap->dev->props.read_mac_address) {
if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
- info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",adap->dvb_adap.proposed_mac[0],
- adap->dvb_adap.proposed_mac[1], adap->dvb_adap.proposed_mac[2],
- adap->dvb_adap.proposed_mac[3], adap->dvb_adap.proposed_mac[4],
- adap->dvb_adap.proposed_mac[5]);
+ info("MAC address: %pM",adap->dvb_adap.proposed_mac);
else
err("MAC address reading failed.");
}
diff --git a/linux/drivers/media/dvb/dvb-usb/dw2102.c b/linux/drivers/media/dvb/dvb-usb/dw2102.c
index bc5e47a2b..2b8ee587b 100644
--- a/linux/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/linux/drivers/media/dvb/dvb-usb/dw2102.c
@@ -368,21 +368,33 @@ static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm dw2102_i2c_algo = {
.master_xfer = dw2102_i2c_transfer,
.functionality = dw210x_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static struct i2c_algorithm dw2102_serit_i2c_algo = {
.master_xfer = dw2102_serit_i2c_transfer,
.functionality = dw210x_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static struct i2c_algorithm dw2102_earda_i2c_algo = {
.master_xfer = dw2102_earda_i2c_transfer,
.functionality = dw210x_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static struct i2c_algorithm dw2104_i2c_algo = {
.master_xfer = dw2104_i2c_transfer,
.functionality = dw210x_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
@@ -660,7 +672,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
/* check STV0299 frontend */
dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
DW210X_READ_MSG);
- if (reset16[0] == 0xa1) {
+ if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
dw2102_properties.i2c_algo = &dw2102_i2c_algo;
dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach;
break;
diff --git a/linux/drivers/media/dvb/dvb-usb/gl861.c b/linux/drivers/media/dvb/dvb-usb/gl861.c
index 6f596ed41..41bec1b58 100644
--- a/linux/drivers/media/dvb/dvb-usb/gl861.c
+++ b/linux/drivers/media/dvb/dvb-usb/gl861.c
@@ -91,6 +91,9 @@ static u32 gl861_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm gl861_i2c_algo = {
.master_xfer = gl861_i2c_xfer,
.functionality = gl861_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
/* Callbacks for DVB USB */
diff --git a/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c
index 262a858c3..20eadf931 100644
--- a/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ b/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -25,6 +25,20 @@ struct gp8psk_fe_state {
unsigned long status_check_interval;
};
+static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ u8 status;
+ gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1);
+ return status & bmDCtuned;
+}
+
+static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode)
+{
+ struct gp8psk_fe_state *state = fe->demodulator_priv;
+ return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0);
+}
+
static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
{
u8 buf[6];
@@ -99,39 +113,114 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
return 0;
}
+static int gp8psk_fe_set_property(struct dvb_frontend *fe,
+ struct dtv_property *tvp)
+{
+ deb_fe("%s(..)\n", __func__);
+ return 0;
+}
+
+static int gp8psk_fe_get_property(struct dvb_frontend *fe,
+ struct dtv_property *tvp)
+{
+ deb_fe("%s(..)\n", __func__);
+ return 0;
+}
+
+
static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct gp8psk_fe_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u8 cmd[10];
u32 freq = fep->frequency * 1000;
+ int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
+
+ deb_fe("%s()\n", __func__);
cmd[4] = freq & 0xff;
cmd[5] = (freq >> 8) & 0xff;
cmd[6] = (freq >> 16) & 0xff;
cmd[7] = (freq >> 24) & 0xff;
- switch(fe->ops.info.type) {
- case FE_QPSK:
- cmd[0] = fep->u.qpsk.symbol_rate & 0xff;
- cmd[1] = (fep->u.qpsk.symbol_rate >> 8) & 0xff;
- cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
- cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
- cmd[8] = ADV_MOD_DVB_QPSK;
- cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
+ switch (c->delivery_system) {
+ case SYS_DVBS:
+ /* Only QPSK is supported for DVB-S */
+ if (c->modulation != QPSK) {
+ deb_fe("%s: unsupported modulation selected (%d)\n",
+ __func__, c->modulation);
+ return -EOPNOTSUPP;
+ }
+ c->fec_inner = FEC_AUTO;
break;
+ case SYS_DVBS2:
+ deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
+ break;
+
default:
- // other modes are unsuported right now
- cmd[0] = 0;
- cmd[1] = 0;
- cmd[2] = 0;
- cmd[3] = 0;
- cmd[8] = 0;
+ deb_fe("%s: unsupported delivery system selected (%d)\n",
+ __func__, c->delivery_system);
+ return -EOPNOTSUPP;
+ }
+
+ cmd[0] = c->symbol_rate & 0xff;
+ cmd[1] = (c->symbol_rate >> 8) & 0xff;
+ cmd[2] = (c->symbol_rate >> 16) & 0xff;
+ cmd[3] = (c->symbol_rate >> 24) & 0xff;
+ switch (c->modulation) {
+ case QPSK:
+ if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+ if (gp8psk_tuned_to_DCII(fe))
+ gp8psk_bcm4500_reload(state->d);
+ switch (c->fec_inner) {
+ case FEC_1_2:
+ cmd[9] = 0; break;
+ case FEC_2_3:
+ cmd[9] = 1; break;
+ case FEC_3_4:
+ cmd[9] = 2; break;
+ case FEC_5_6:
+ cmd[9] = 3; break;
+ case FEC_7_8:
+ cmd[9] = 4; break;
+ case FEC_AUTO:
+ cmd[9] = 5; break;
+ default:
+ cmd[9] = 5; break;
+ }
+ cmd[8] = ADV_MOD_DVB_QPSK;
+ break;
+ case PSK_8: /* PSK_8 is for compatibility with DN */
+ cmd[8] = ADV_MOD_TURBO_8PSK;
+ switch (c->fec_inner) {
+ case FEC_2_3:
+ cmd[9] = 0; break;
+ case FEC_3_4:
+ cmd[9] = 1; break;
+ case FEC_3_5:
+ cmd[9] = 2; break;
+ case FEC_5_6:
+ cmd[9] = 3; break;
+ case FEC_8_9:
+ cmd[9] = 4; break;
+ default:
+ cmd[9] = 0; break;
+ }
+ break;
+ case QAM_16: /* QAM_16 is for compatibility with DN */
+ cmd[8] = ADV_MOD_TURBO_16QAM;
cmd[9] = 0;
break;
+ default: /* Unknown modulation */
+ deb_fe("%s: unsupported modulation selected (%d)\n",
+ __func__, c->modulation);
+ return -EOPNOTSUPP;
}
- gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
+ if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+ gp8psk_set_tuner_mode(fe, 0);
+ gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10);
state->lock = 0;
state->next_status_check = jiffies;
@@ -140,13 +229,6 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
return 0;
}
-static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
-{
- return 0;
-}
-
-
static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
struct dvb_diseqc_master_cmd *m)
{
@@ -261,9 +343,13 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
.symbol_rate_max = 45000000,
.symbol_rate_tolerance = 500, /* ppm */
.caps = FE_CAN_INVERSION_AUTO |
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ /*
+ * FE_CAN_QAM_16 is for compatibility
+ * (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
+ */
+ FE_CAN_QPSK | FE_CAN_QAM_16
},
.release = gp8psk_fe_release,
@@ -271,8 +357,10 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
.init = NULL,
.sleep = NULL,
+ .set_property = gp8psk_fe_set_property,
+ .get_property = gp8psk_fe_get_property,
.set_frontend = gp8psk_fe_set_frontend,
- .get_frontend = gp8psk_fe_get_frontend,
+
.get_tune_settings = gp8psk_fe_get_tune_settings,
.read_status = gp8psk_fe_read_status,
diff --git a/linux/drivers/media/dvb/dvb-usb/gp8psk.c b/linux/drivers/media/dvb/dvb-usb/gp8psk.c
index 1b002909b..3dd684386 100644
--- a/linux/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/linux/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -174,7 +174,6 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
return 0;
}
-#if 0
int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
{
u8 buf;
@@ -188,10 +187,9 @@ int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
/* load BCM4500 firmware */
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
if (gp8psk_load_bcm4500fw(d))
- return EINVAL;
+ return -EINVAL;
return 0;
}
-#endif /* 0 */
static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
diff --git a/linux/drivers/media/dvb/dvb-usb/gp8psk.h b/linux/drivers/media/dvb/dvb-usb/gp8psk.h
index e5cd8149c..e83a57506 100644
--- a/linux/drivers/media/dvb/dvb-usb/gp8psk.h
+++ b/linux/drivers/media/dvb/dvb-usb/gp8psk.h
@@ -92,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
u16 index, u8 *b, int blen);
+extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
#endif
diff --git a/linux/drivers/media/dvb/dvb-usb/m920x.c b/linux/drivers/media/dvb/dvb-usb/m920x.c
index 54626a0db..51c1c8dba 100644
--- a/linux/drivers/media/dvb/dvb-usb/m920x.c
+++ b/linux/drivers/media/dvb/dvb-usb/m920x.c
@@ -256,6 +256,9 @@ static u32 m920x_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm m920x_i2c_algo = {
.master_xfer = m920x_i2c_xfer,
.functionality = m920x_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
/* pid filter */
diff --git a/linux/drivers/media/dvb/dvb-usb/opera1.c b/linux/drivers/media/dvb/dvb-usb/opera1.c
index cba064615..d45ceb83b 100644
--- a/linux/drivers/media/dvb/dvb-usb/opera1.c
+++ b/linux/drivers/media/dvb/dvb-usb/opera1.c
@@ -167,6 +167,9 @@ static u32 opera1_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm opera1_i2c_algo = {
.master_xfer = opera1_i2c_xfer,
.functionality = opera1_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
diff --git a/linux/drivers/media/dvb/dvb-usb/ttusb2.c b/linux/drivers/media/dvb/dvb-usb/ttusb2.c
index e79a26473..849c59478 100644
--- a/linux/drivers/media/dvb/dvb-usb/ttusb2.c
+++ b/linux/drivers/media/dvb/dvb-usb/ttusb2.c
@@ -124,6 +124,9 @@ static u32 ttusb2_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm ttusb2_i2c_algo = {
.master_xfer = ttusb2_i2c_xfer,
.functionality = ttusb2_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
/* Callbacks for DVB USB */
diff --git a/linux/drivers/media/dvb/dvb-usb/usb-urb.c b/linux/drivers/media/dvb/dvb-usb/usb-urb.c
index eb3aaaf7a..5becc5a20 100644
--- a/linux/drivers/media/dvb/dvb-usb/usb-urb.c
+++ b/linux/drivers/media/dvb/dvb-usb/usb-urb.c
@@ -160,7 +160,8 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream)
stream->props.u.bulk.buffersize,
usb_urb_complete, stream);
- stream->urb_list[i]->transfer_flags = 0;
+ stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
stream->urbs_initialized++;
}
return 0;
diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig
index 2470d88e9..002695607 100644
--- a/linux/drivers/media/dvb/frontends/Kconfig
+++ b/linux/drivers/media/dvb/frontends/Kconfig
@@ -118,6 +118,14 @@ config DVB_TUNER_ITD1000
help
A DVB-S tuner module. Say Y when you want to support this frontend.
+config DVB_TUNER_CX24113
+ tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+
config DVB_TDA826X
tristate "Philips TDA826X silicon tuner"
depends on DVB_CORE && I2C
diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile
index 7a19c0c7b..af7bdf0ad 100644
--- a/linux/drivers/media/dvb/frontends/Makefile
+++ b/linux/drivers/media/dvb/frontends/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
obj-$(CONFIG_DVB_AU8522) += au8522.o
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
+obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
diff --git a/linux/drivers/media/dvb/frontends/af9013.c b/linux/drivers/media/dvb/frontends/af9013.c
index 692b68a9e..937715a96 100644
--- a/linux/drivers/media/dvb/frontends/af9013.c
+++ b/linux/drivers/media/dvb/frontends/af9013.c
@@ -33,6 +33,7 @@
#include "dvb_frontend.h"
#include "af9013_priv.h"
#include "af9013.h"
+#include "compat.h"
int af9013_debug;
@@ -223,12 +224,12 @@ static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
int ret = 0;
u8 i = 0;
u8 buf[24];
- u32 ns_coeff1_2048nu;
- u32 ns_coeff1_8191nu;
- u32 ns_coeff1_8192nu;
- u32 ns_coeff1_8193nu;
- u32 ns_coeff2_2k;
- u32 ns_coeff2_8k;
+ u32 uninitialized_var(ns_coeff1_2048nu);
+ u32 uninitialized_var(ns_coeff1_8191nu);
+ u32 uninitialized_var(ns_coeff1_8192nu);
+ u32 uninitialized_var(ns_coeff1_8193nu);
+ u32 uninitialized_var(ns_coeff2_2k);
+ u32 uninitialized_var(ns_coeff2_8k);
deb_info("%s: adc_clock:%d bw:%d\n", __func__,
state->config.adc_clock, bw);
@@ -1009,7 +1010,7 @@ static int af9013_update_snr(struct dvb_frontend *fe)
int ret;
u8 buf[3], i, len;
u32 quant = 0;
- struct snr_table *snr_table;
+ struct snr_table *uninitialized_var(snr_table);
/* check if quantizer ready (for snr) */
ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]);
diff --git a/linux/drivers/media/dvb/frontends/cx24113.c b/linux/drivers/media/dvb/frontends/cx24113.c
new file mode 100644
index 000000000..f6e7b0380
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/cx24113.c
@@ -0,0 +1,616 @@
+/*
+ * Driver for Conexant CX24113/CX24128 Tuner (Satellite)
+ *
+ * Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * Developed for BBTI / Technisat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "dvb_frontend.h"
+#include "cx24113.h"
+
+static int debug;
+
+#define info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
+#define err(args...) do { printk(KERN_ERR "CX24113: " args); } while (0)
+
+#define dprintk(args...) \
+ do { \
+ if (debug) { \
+ printk(KERN_DEBUG "CX24113: %s: ", __func__); \
+ printk(args); \
+ } \
+ } while (0)
+
+struct cx24113_state {
+ struct i2c_adapter *i2c;
+ const struct cx24113_config *config;
+
+#define REV_CX24113 0x23
+ u8 rev;
+ u8 ver;
+
+ u8 icp_mode:1;
+
+#define ICP_LEVEL1 0
+#define ICP_LEVEL2 1
+#define ICP_LEVEL3 2
+#define ICP_LEVEL4 3
+ u8 icp_man:2;
+ u8 icp_auto_low:2;
+ u8 icp_auto_mlow:2;
+ u8 icp_auto_mhi:2;
+ u8 icp_auto_hi:2;
+ u8 icp_dig;
+
+#define LNA_MIN_GAIN 0
+#define LNA_MID_GAIN 1
+#define LNA_MAX_GAIN 2
+ u8 lna_gain:2;
+
+ u8 acp_on:1;
+
+ u8 vco_mode:2;
+ u8 vco_shift:1;
+#define VCOBANDSEL_6 0x80
+#define VCOBANDSEL_5 0x01
+#define VCOBANDSEL_4 0x02
+#define VCOBANDSEL_3 0x04
+#define VCOBANDSEL_2 0x08
+#define VCOBANDSEL_1 0x10
+ u8 vco_band;
+
+#define VCODIV4 4
+#define VCODIV2 2
+ u8 vcodiv;
+
+ u8 bs_delay:4;
+ u16 bs_freqcnt:13;
+ u16 bs_rdiv;
+ u8 prescaler_mode:1;
+
+ u8 rfvga_bias_ctrl;
+
+ s16 tuner_gain_thres;
+ u8 gain_level;
+
+ u32 frequency;
+
+ u8 refdiv;
+
+ u8 Fwindow_enabled;
+};
+
+static int cx24113_writereg(struct cx24113_state *state, int reg, int data)
+{
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = { .addr = state->config->i2c_addr,
+ .flags = 0, .buf = buf, .len = 2 };
+ int err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1) {
+ printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x,"
+ " data == 0x%02x)\n", __func__, err, reg, data);
+ return err;
+ }
+
+ return 0;
+}
+
+static int cx24113_readreg(struct cx24113_state *state, u8 reg)
+{
+ int ret;
+ u8 b;
+ struct i2c_msg msg[] = {
+ { .addr = state->config->i2c_addr,
+ .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = state->config->i2c_addr,
+ .flags = I2C_M_RD, .buf = &b, .len = 1 }
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2) {
+ printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n",
+ __func__, reg, ret);
+ return ret;
+ }
+
+ return b;
+}
+
+static void cx24113_set_parameters(struct cx24113_state *state)
+{
+ u8 r;
+
+ r = cx24113_readreg(state, 0x10) & 0x82;
+ r |= state->icp_mode;
+ r |= state->icp_man << 4;
+ r |= state->icp_dig << 2;
+ r |= state->prescaler_mode << 5;
+ cx24113_writereg(state, 0x10, r);
+
+ r = (state->icp_auto_low << 0) | (state->icp_auto_mlow << 2)
+ | (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6);
+ cx24113_writereg(state, 0x11, r);
+
+ if (state->rev == REV_CX24113) {
+ r = cx24113_readreg(state, 0x20) & 0xec;
+ r |= state->lna_gain;
+ r |= state->rfvga_bias_ctrl << 4;
+ cx24113_writereg(state, 0x20, r);
+ }
+
+ r = cx24113_readreg(state, 0x12) & 0x03;
+ r |= state->acp_on << 2;
+ r |= state->bs_delay << 4;
+ cx24113_writereg(state, 0x12, r);
+
+ r = cx24113_readreg(state, 0x18) & 0x40;
+ r |= state->vco_shift;
+ if (state->vco_band == VCOBANDSEL_6)
+ r |= (1 << 7);
+ else
+ r |= (state->vco_band << 1);
+ cx24113_writereg(state, 0x18, r);
+
+ r = cx24113_readreg(state, 0x14) & 0x20;
+ r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f);
+ cx24113_writereg(state, 0x14, r);
+ cx24113_writereg(state, 0x15, (state->bs_freqcnt & 0xff));
+
+ cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff);
+ r = (cx24113_readreg(state, 0x17) & 0x0f) |
+ ((state->bs_rdiv & 0x0f) << 4);
+ cx24113_writereg(state, 0x17, r);
+}
+
+#define VGA_0 0x00
+#define VGA_1 0x04
+#define VGA_2 0x02
+#define VGA_3 0x06
+#define VGA_4 0x01
+#define VGA_5 0x05
+#define VGA_6 0x03
+#define VGA_7 0x07
+
+#define RFVGA_0 0x00
+#define RFVGA_1 0x01
+#define RFVGA_2 0x02
+#define RFVGA_3 0x03
+
+static int cx24113_set_gain_settings(struct cx24113_state *state,
+ s16 power_estimation)
+{
+ u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0,
+ vga = cx24113_readreg(state, 0x1f) & 0x3f,
+ rfvga = cx24113_readreg(state, 0x20) & 0xf3;
+ u8 gain_level = power_estimation >= state->tuner_gain_thres;
+
+ dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n",
+ power_estimation, state->tuner_gain_thres,
+ state->gain_level, gain_level);
+
+ if (gain_level == state->gain_level)
+ return 0; /* nothing to be done */
+
+ ampout |= 0xf;
+
+ if (gain_level) {
+ rfvga |= RFVGA_0 << 2;
+ vga |= (VGA_7 << 3) | VGA_7;
+ } else {
+ rfvga |= RFVGA_2 << 2;
+ vga |= (VGA_6 << 3) | VGA_2;
+ }
+ state->gain_level = gain_level;
+
+ cx24113_writereg(state, 0x1d, ampout);
+ cx24113_writereg(state, 0x1f, vga);
+ cx24113_writereg(state, 0x20, rfvga);
+
+ return 1; /* did something */
+}
+
+static int cx24113_set_Fref(struct cx24113_state *state, u8 high)
+{
+ u8 xtal = cx24113_readreg(state, 0x02);
+ if (state->rev == 0x43 && state->vcodiv == VCODIV4)
+ high = 1;
+
+ xtal &= ~0x2;
+ if (high)
+ xtal |= high << 1;
+ return cx24113_writereg(state, 0x02, xtal);
+}
+
+static int cx24113_enable(struct cx24113_state *state, u8 enable)
+{
+ u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable;
+ if (state->rev == REV_CX24113)
+ r21 |= (1 << 1);
+ return cx24113_writereg(state, 0x21, r21);
+}
+
+static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz)
+{
+ u8 r;
+
+ if (bandwidth_khz <= 19000)
+ r = 0x03 << 6;
+ else if (bandwidth_khz <= 25000)
+ r = 0x02 << 6;
+ else
+ r = 0x01 << 6;
+
+ dprintk("bandwidth to be set: %d\n", bandwidth_khz);
+ bandwidth_khz *= 10;
+ bandwidth_khz -= 10000;
+ bandwidth_khz /= 1000;
+ bandwidth_khz += 5;
+ bandwidth_khz /= 10;
+
+ dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz);
+
+ r |= bandwidth_khz & 0x3f;
+
+ return cx24113_writereg(state, 0x1e, r);
+}
+
+static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on)
+{
+ u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7);
+ return cx24113_writereg(state, 0x10, r);
+}
+
+static int cx24113_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct cx24113_state *state = fe->tuner_priv;
+ u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1;
+ if (r)
+ *status |= TUNER_STATUS_LOCKED;
+ dprintk("PLL locked: %d\n", r);
+ return 0;
+}
+
+static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv)
+{
+ if (state->rev == 0x43 && state->vcodiv == VCODIV4)
+ refdiv = 2;
+ return state->refdiv = refdiv;
+}
+
+static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
+{
+ s32 N;
+ s64 F;
+ u8 R, r;
+ u8 vcodiv;
+ u8 factor;
+ s32 freq_hz = state->frequency * 1000;
+
+ if (state->config->xtal_khz < 20000)
+ factor = 1;
+ else
+ factor = 2;
+
+ if (state->rev == REV_CX24113) {
+ if (state->frequency >= 1100000)
+ vcodiv = VCODIV2;
+ else
+ vcodiv = VCODIV4;
+ } else {
+ if (state->frequency >= 1165000)
+ vcodiv = VCODIV2;
+ else
+ vcodiv = VCODIV4;
+ }
+ state->vcodiv = vcodiv;
+
+ dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv);
+ R = 0;
+ do {
+ R = cx24113_set_ref_div(state, R + 1);
+
+ /* calculate tuner PLL settings: */
+ N = (freq_hz / 100 * vcodiv) * R;
+ N /= (state->config->xtal_khz) * factor * 2;
+ N += 5; /* For round up. */
+ N /= 10;
+ N -= 32;
+ } while (N < 6 && R < 3);
+
+ if (N < 6) {
+ err("strange frequency: N < 6\n");
+ return;
+ }
+ F = freq_hz;
+ F *= (u64) (R * vcodiv * 262144);
+ dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+ do_div(F, state->config->xtal_khz*1000 * factor * 2);
+ dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+ F -= (N + 32) * 262144;
+
+ dprintk("3 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+
+ if (state->Fwindow_enabled) {
+ if (F > (262144 / 2 - 1638))
+ F = 262144 / 2 - 1638;
+ if (F < (-262144 / 2 + 1638))
+ F = -262144 / 2 + 1638;
+ if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) {
+ F = 0;
+ r = cx24113_readreg(state, 0x10);
+ cx24113_writereg(state, 0x10, r | (1 << 6));
+ }
+ }
+ dprintk("4 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+
+ *n = (u16) N;
+ *f = (s32) F;
+}
+
+
+static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r)
+{
+ u8 reg;
+ cx24113_writereg(state, 0x19, (n >> 1) & 0xff);
+
+ reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f);
+ cx24113_writereg(state, 0x1a, reg);
+
+ cx24113_writereg(state, 0x1b, (f >> 3) & 0xff);
+
+ reg = cx24113_readreg(state, 0x1c) & 0x1f;
+ cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5));
+
+ cx24113_set_Fref(state, r - 1);
+}
+
+static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency)
+{
+ u8 r = 1; /* or 2 */
+ u16 n = 6;
+ s32 f = 0;
+
+ r = cx24113_readreg(state, 0x14);
+ cx24113_writereg(state, 0x14, r & 0x3f);
+
+ r = cx24113_readreg(state, 0x10);
+ cx24113_writereg(state, 0x10, r & 0xbf);
+
+ state->frequency = frequency;
+
+ dprintk("tuning to frequency: %d\n", frequency);
+
+ cx24113_calc_pll_nf(state, &n, &f);
+ cx24113_set_nfr(state, n, f, state->refdiv);
+
+ r = cx24113_readreg(state, 0x18) & 0xbf;
+ if (state->vcodiv != VCODIV2)
+ r |= 1 << 6;
+ cx24113_writereg(state, 0x18, r);
+
+ /* The need for this sleep is not clear. But helps in some cases */
+ msleep(5);
+
+ r = cx24113_readreg(state, 0x1c) & 0xef;
+ cx24113_writereg(state, 0x1c, r | (1 << 4));
+ return 0;
+}
+
+static int cx24113_init(struct dvb_frontend *fe)
+{
+ struct cx24113_state *state = fe->tuner_priv;
+ int ret;
+
+ state->tuner_gain_thres = -50;
+ state->gain_level = 255; /* to force a gain-setting initialization */
+ state->icp_mode = 0;
+
+ if (state->config->xtal_khz < 11000) {
+ state->icp_auto_hi = ICP_LEVEL4;
+ state->icp_auto_mhi = ICP_LEVEL4;
+ state->icp_auto_mlow = ICP_LEVEL3;
+ state->icp_auto_low = ICP_LEVEL3;
+ } else {
+ state->icp_auto_hi = ICP_LEVEL4;
+ state->icp_auto_mhi = ICP_LEVEL4;
+ state->icp_auto_mlow = ICP_LEVEL3;
+ state->icp_auto_low = ICP_LEVEL2;
+ }
+
+ state->icp_dig = ICP_LEVEL3;
+ state->icp_man = ICP_LEVEL1;
+ state->acp_on = 1;
+ state->vco_mode = 0;
+ state->vco_shift = 0;
+ state->vco_band = VCOBANDSEL_1;
+ state->bs_delay = 8;
+ state->bs_freqcnt = 0x0fff;
+ state->bs_rdiv = 0x0fff;
+ state->prescaler_mode = 0;
+ state->lna_gain = LNA_MAX_GAIN;
+ state->rfvga_bias_ctrl = 1;
+ state->Fwindow_enabled = 1;
+
+ cx24113_set_Fref(state, 0);
+ cx24113_enable(state, 0x3d);
+ cx24113_set_parameters(state);
+
+ cx24113_set_gain_settings(state, -30);
+
+ cx24113_set_bandwidth(state, 18025);
+ cx24113_set_clk_inversion(state, 1);
+
+ if (state->config->xtal_khz >= 40000)
+ ret = cx24113_writereg(state, 0x02,
+ (cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2));
+ else
+ ret = cx24113_writereg(state, 0x02,
+ (cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2));
+
+ return ret;
+}
+
+static int cx24113_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct cx24113_state *state = fe->tuner_priv;
+ /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
+ u32 roll_off = 675;
+ u32 bw;
+
+ bw = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000;
+ bw += (10000000/100) + 5;
+ bw /= 10;
+ bw += 1000;
+ cx24113_set_bandwidth(state, bw);
+
+ cx24113_set_frequency(state, p->frequency);
+ msleep(5);
+ return cx24113_get_status(fe, &bw);
+}
+
+static s8 cx24113_agc_table[2][10] = {
+ {-54, -41, -35, -30, -25, -21, -16, -10, -6, -2},
+ {-39, -35, -30, -25, -19, -15, -11, -5, 1, 9},
+};
+
+void cx24113_agc_callback(struct dvb_frontend *fe)
+{
+ struct cx24113_state *state = fe->tuner_priv;
+ s16 s, i;
+ if (!fe->ops.read_signal_strength)
+ return;
+
+ do {
+ /* this only works with the current CX24123 implementation */
+ fe->ops.read_signal_strength(fe, (u16 *) &s);
+ s >>= 8;
+ dprintk("signal strength: %d\n", s);
+ for (i = 0; i < sizeof(cx24113_agc_table[0]); i++)
+ if (cx24113_agc_table[state->gain_level][i] > s)
+ break;
+ s = -25 - i*5;
+ } while (cx24113_set_gain_settings(state, s));
+}
+EXPORT_SYMBOL(cx24113_agc_callback);
+
+static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct cx24113_state *state = fe->tuner_priv;
+ *frequency = state->frequency;
+ return 0;
+}
+
+static int cx24113_release(struct dvb_frontend *fe)
+{
+ struct cx24113_state *state = fe->tuner_priv;
+ dprintk("\n");
+ fe->tuner_priv = NULL;
+ kfree(state);
+ return 0;
+}
+
+static const struct dvb_tuner_ops cx24113_tuner_ops = {
+ .info = {
+ .name = "Conexant CX24113",
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_step = 125,
+ },
+
+ .release = cx24113_release,
+
+ .init = cx24113_init,
+ .sleep = NULL,
+
+ .set_params = cx24113_set_params,
+ .get_frequency = cx24113_get_frequency,
+ .get_bandwidth = NULL,
+ .get_status = cx24113_get_status,
+};
+
+struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
+ const struct cx24113_config *config, struct i2c_adapter *i2c)
+{
+ /* allocate memory for the internal state */
+ struct cx24113_state *state =
+ kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
+ int rc;
+ if (state == NULL) {
+ err("Unable to kmalloc\n");
+ goto error;
+ }
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+
+ info("trying to detect myself\n");
+
+ /* making a dummy read, because of some expected troubles
+ * after power on */
+ cx24113_readreg(state, 0x00);
+
+ rc = cx24113_readreg(state, 0x00);
+ if (rc < 0) {
+ info("CX24113 not found.\n");
+ goto error;
+ }
+ state->rev = rc;
+
+ switch (rc) {
+ case 0x43:
+ info("detected CX24113 variant\n");
+ break;
+ case REV_CX24113:
+ info("sucessfully detected\n");
+ break;
+ default:
+ err("unsupported device id: %x\n", state->rev);
+ goto error;
+ }
+ state->ver = cx24113_readreg(state, 0x01);
+ info("version: %x\n", state->ver);
+
+ /* create dvb_frontend */
+ memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+ fe->tuner_priv = state;
+ return fe;
+
+error:
+ kfree(state);
+
+ return NULL;
+}
+EXPORT_SYMBOL(cx24113_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
+MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware");
+MODULE_LICENSE("GPL");
+
diff --git a/linux/drivers/media/dvb/frontends/cx24113.h b/linux/drivers/media/dvb/frontends/cx24113.h
index d549041b2..5de0f7ffd 100644
--- a/linux/drivers/media/dvb/frontends/cx24113.h
+++ b/linux/drivers/media/dvb/frontends/cx24113.h
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef CX24113_H
@@ -30,10 +30,8 @@ struct cx24113_config {
u32 xtal_khz;
};
-/* TODO: #if defined(CONFIG_DVB_TUNER_CX24113) || \
- * (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) */
-
-#if 0
+#if defined(CONFIG_DVB_TUNER_CX24113) || \
+ (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE))
extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *,
const struct cx24113_config *config, struct i2c_adapter *i2c);
diff --git a/linux/drivers/media/dvb/frontends/cx24116.c b/linux/drivers/media/dvb/frontends/cx24116.c
index 497ea635e..e2e7ff280 100644
--- a/linux/drivers/media/dvb/frontends/cx24116.c
+++ b/linux/drivers/media/dvb/frontends/cx24116.c
@@ -106,7 +106,7 @@ MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
#define CX24116_HAS_SYNCLOCK (0x08)
#define CX24116_HAS_UNKNOWN1 (0x10)
#define CX24116_HAS_UNKNOWN2 (0x20)
-#define CX24116_STATUS_MASK (0x3f)
+#define CX24116_STATUS_MASK (0x0f)
#define CX24116_SIGNAL_MASK (0xc0)
#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */
@@ -160,6 +160,7 @@ struct cx24116_tuning {
fe_spectral_inversion_t inversion;
fe_code_rate_t fec;
+ fe_delivery_system_t delsys;
fe_modulation_t modulation;
fe_pilot_t pilot;
fe_rolloff_t rolloff;
@@ -411,14 +412,15 @@ struct cx24116_modfec {
};
static int cx24116_lookup_fecmod(struct cx24116_state *state,
- fe_modulation_t m, fe_code_rate_t f)
+ fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f)
{
int i, ret = -EOPNOTSUPP;
dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
- if ((m == CX24116_MODFEC_MODES[i].modulation) &&
+ if ((d == CX24116_MODFEC_MODES[i].delivery_system) &&
+ (m == CX24116_MODFEC_MODES[i].modulation) &&
(f == CX24116_MODFEC_MODES[i].fec)) {
ret = i;
break;
@@ -429,13 +431,13 @@ static int cx24116_lookup_fecmod(struct cx24116_state *state,
}
static int cx24116_set_fec(struct cx24116_state *state,
- fe_modulation_t mod, fe_code_rate_t fec)
+ fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec)
{
int ret = 0;
dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
- ret = cx24116_lookup_fecmod(state, mod, fec);
+ ret = cx24116_lookup_fecmod(state, delsys, mod, fec);
if (ret < 0)
return ret;
@@ -679,7 +681,8 @@ static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct cx24116_state *state = fe->demodulator_priv;
- int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
+ int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) &
+ CX24116_STATUS_MASK;
dprintk("%s: status = 0x%02x\n", __func__, lock);
@@ -1222,7 +1225,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct cx24116_cmd cmd;
fe_status_t tunerstat;
- int i, status, ret, retune;
+ int i, status, ret, retune = 1;
dprintk("%s()\n", __func__);
@@ -1239,7 +1242,6 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
/* Pilot doesn't exist in DVB-S, turn bit off */
state->dnxt.pilot_val = CX24116_PILOT_OFF;
- retune = 1;
/* DVB-S only supports 0.35 */
if (c->rolloff != ROLLOFF_35) {
@@ -1267,7 +1269,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
case PILOT_AUTO: /* Not supported but emulated */
state->dnxt.pilot_val = (c->modulation == QPSK)
? CX24116_PILOT_OFF : CX24116_PILOT_ON;
- retune = 2;
+ retune++;
break;
case PILOT_OFF:
state->dnxt.pilot_val = CX24116_PILOT_OFF;
@@ -1304,6 +1306,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
__func__, c->delivery_system);
return -EOPNOTSUPP;
}
+ state->dnxt.delsys = c->delivery_system;
state->dnxt.modulation = c->modulation;
state->dnxt.frequency = c->frequency;
state->dnxt.pilot = c->pilot;
@@ -1314,7 +1317,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
return ret;
/* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
- ret = cx24116_set_fec(state, c->modulation, c->fec_inner);
+ ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner);
if (ret != 0)
return ret;
@@ -1325,6 +1328,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
/* discard the 'current' tuning parameters and prepare to tune */
cx24116_clone_params(fe);
+ dprintk("%s: delsys = %d\n", __func__, state->dcur.delsys);
dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation);
dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__,
@@ -1444,6 +1448,23 @@ tuned: /* Set/Reset B/W */
return ret;
}
+static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params,
+ unsigned int mode_flags, unsigned int *delay, fe_status_t *status)
+{
+ *delay = HZ / 5;
+ if (params) {
+ int ret = cx24116_set_frontend(fe, params);
+ if (ret)
+ return ret;
+ }
+ return cx24116_read_status(fe, status);
+}
+
+static int cx24116_get_algo(struct dvb_frontend *fe)
+{
+ return DVBFE_ALGO_HW;
+}
+
static struct dvb_frontend_ops cx24116_ops = {
.info = {
@@ -1459,6 +1480,7 @@ static struct dvb_frontend_ops cx24116_ops = {
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_2G_MODULATION |
FE_CAN_QPSK | FE_CAN_RECOVER
},
@@ -1475,6 +1497,8 @@ static struct dvb_frontend_ops cx24116_ops = {
.set_voltage = cx24116_set_voltage,
.diseqc_send_master_cmd = cx24116_send_diseqc_msg,
.diseqc_send_burst = cx24116_diseqc_send_burst,
+ .get_frontend_algo = cx24116_get_algo,
+ .tune = cx24116_tune,
.set_property = cx24116_set_property,
.get_property = cx24116_get_property,
diff --git a/linux/drivers/media/dvb/frontends/cx24116.h b/linux/drivers/media/dvb/frontends/cx24116.h
index 4cb3ddd6c..b1b76b47a 100644
--- a/linux/drivers/media/dvb/frontends/cx24116.h
+++ b/linux/drivers/media/dvb/frontends/cx24116.h
@@ -37,7 +37,8 @@ struct cx24116_config {
u8 mpg_clk_pos_pol:0x02;
};
-#if defined(CONFIG_DVB_CX24116) || defined(CONFIG_DVB_CX24116_MODULE)
+#if defined(CONFIG_DVB_CX24116) || \
+ (defined(CONFIG_DVB_CX24116_MODULE) && defined(MODULE))
extern struct dvb_frontend *cx24116_attach(
const struct cx24116_config *config,
struct i2c_adapter *i2c);
diff --git a/linux/drivers/media/dvb/frontends/cx24123.c b/linux/drivers/media/dvb/frontends/cx24123.c
index fb559369e..c9cfc8393 100644
--- a/linux/drivers/media/dvb/frontends/cx24123.c
+++ b/linux/drivers/media/dvb/frontends/cx24123.c
@@ -29,6 +29,7 @@
#include "dvb_frontend.h"
#include "cx24123.h"
+#include "compat.h"
#define XTAL 10111000
@@ -1065,6 +1066,9 @@ static u32 cx24123_tuner_i2c_func(struct i2c_adapter *adapter)
static struct i2c_algorithm cx24123_tuner_i2c_algo = {
.master_xfer = cx24123_tuner_i2c_tuner_xfer,
.functionality = cx24123_tuner_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
struct i2c_adapter *
diff --git a/linux/drivers/media/dvb/frontends/dib7000p.h b/linux/drivers/media/dvb/frontends/dib7000p.h
index 3e8126857..aab8112e2 100644
--- a/linux/drivers/media/dvb/frontends/dib7000p.h
+++ b/linux/drivers/media/dvb/frontends/dib7000p.h
@@ -66,7 +66,8 @@ struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe,
return NULL;
}
-extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
+static inline
+int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
int no_of_demods, u8 default_addr,
struct dib7000p_config cfg[])
{
@@ -74,13 +75,15 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
return -ENODEV;
}
-extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+static inline
+int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return -ENODEV;
}
-extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+static inline
+int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return -ENODEV;
diff --git a/linux/drivers/media/dvb/frontends/dibx000_common.c b/linux/drivers/media/dvb/frontends/dibx000_common.c
index a8e3a950c..6f1f41ae3 100644
--- a/linux/drivers/media/dvb/frontends/dibx000_common.c
+++ b/linux/drivers/media/dvb/frontends/dibx000_common.c
@@ -1,6 +1,7 @@
#include <linux/i2c.h>
#include "dibx000_common.h"
+#include "compat.h"
static int debug;
module_param(debug, int, 0644);
@@ -107,6 +108,9 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c
static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
.master_xfer = dibx000_i2c_gated_tuner_xfer,
.functionality = dibx000_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf, int gating)
diff --git a/linux/drivers/media/dvb/frontends/drx397xD.c b/linux/drivers/media/dvb/frontends/drx397xD.c
index 7a2b2d461..48abee27c 100644
--- a/linux/drivers/media/dvb/frontends/drx397xD.c
+++ b/linux/drivers/media/dvb/frontends/drx397xD.c
@@ -40,7 +40,7 @@ static const char mod_name[] = "drx397xD";
#define F_SET_0D4h 2
enum fw_ix {
-#define _FW_ENTRY(a, b) b
+#define _FW_ENTRY(a, b, c) b
#include "drx397xD_fw.h"
};
@@ -73,11 +73,11 @@ static struct {
int refcnt;
const u8 *data[ARRAY_SIZE(blob_name)];
} fw[] = {
-#define _FW_ENTRY(a, b) { \
- .name = a, \
- .file = 0, \
- .lock = RW_LOCK_UNLOCKED, \
- .refcnt = 0, \
+#define _FW_ENTRY(a, b, c) { \
+ .name = a, \
+ .file = 0, \
+ .lock = __RW_LOCK_UNLOCKED(fw[c].lock), \
+ .refcnt = 0, \
.data = { } }
#include "drx397xD_fw.h"
};
diff --git a/linux/drivers/media/dvb/frontends/drx397xD_fw.h b/linux/drivers/media/dvb/frontends/drx397xD_fw.h
index 01de02a81..c8b44c1e8 100644
--- a/linux/drivers/media/dvb/frontends/drx397xD_fw.h
+++ b/linux/drivers/media/dvb/frontends/drx397xD_fw.h
@@ -18,8 +18,8 @@
*/
#ifdef _FW_ENTRY
- _FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0 ),
- _FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1 ),
+ _FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0, DRXD_FW_A2 ),
+ _FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1, DRXD_FW_B1 ),
#undef _FW_ENTRY
#endif /* _FW_ENTRY */
diff --git a/linux/drivers/media/dvb/frontends/s5h1420.c b/linux/drivers/media/dvb/frontends/s5h1420.c
index 46d55e393..f357f8233 100644
--- a/linux/drivers/media/dvb/frontends/s5h1420.c
+++ b/linux/drivers/media/dvb/frontends/s5h1420.c
@@ -37,6 +37,7 @@
#include "dvb_frontend.h"
#include "s5h1420.h"
#include "s5h1420_priv.h"
+#include "compat.h"
#define TONE_FREQ 22000
@@ -904,6 +905,9 @@ static int s5h1420_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c
static struct i2c_algorithm s5h1420_tuner_i2c_algo = {
.master_xfer = s5h1420_tuner_i2c_tuner_xfer,
.functionality = s5h1420_tuner_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe)
diff --git a/linux/drivers/media/dvb/frontends/stb0899_drv.c b/linux/drivers/media/dvb/frontends/stb0899_drv.c
index 63c547f31..079bb529b 100644
--- a/linux/drivers/media/dvb/frontends/stb0899_drv.c
+++ b/linux/drivers/media/dvb/frontends/stb0899_drv.c
@@ -1913,6 +1913,7 @@ static struct dvb_frontend_ops stb0899_ops = {
.caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_AUTO |
+ FE_CAN_2G_MODULATION |
FE_CAN_QPSK
},
diff --git a/linux/drivers/media/dvb/frontends/zl10353.c b/linux/drivers/media/dvb/frontends/zl10353.c
index 2e449a457..be5d7ef7c 100644
--- a/linux/drivers/media/dvb/frontends/zl10353.c
+++ b/linux/drivers/media/dvb/frontends/zl10353.c
@@ -598,8 +598,15 @@ static int zl10353_init(struct dvb_frontend *fe)
static int zl10353_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
{
+ struct zl10353_state *state = fe->demodulator_priv;
u8 val = 0x0a;
+ if (state->config.no_tuner) {
+ /* No tuner attached to the internal I2C bus */
+ /* If set enable I2C bridge, the main I2C bus stopped hardly */
+ return 0;
+ }
+
if (enable)
val |= 0x10;
diff --git a/linux/drivers/media/dvb/pluto2/pluto2.c b/linux/drivers/media/dvb/pluto2/pluto2.c
index cb368e2e0..8522757a5 100644
--- a/linux/drivers/media/dvb/pluto2/pluto2.c
+++ b/linux/drivers/media/dvb/pluto2/pluto2.c
@@ -568,8 +568,7 @@ static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac)
mac[4] = (val >> 8) & 0xff;
mac[5] = (val >> 0) & 0xff;
- dev_info(&pluto->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ dev_info(&pluto->pdev->dev, "MAC %pM\n", mac);
}
static int __devinit pluto_read_serial(struct pluto *pluto)
diff --git a/linux/drivers/media/dvb/ttpci/Kconfig b/linux/drivers/media/dvb/ttpci/Kconfig
index 9e2ece9e4..ab0bcd208 100644
--- a/linux/drivers/media/dvb/ttpci/Kconfig
+++ b/linux/drivers/media/dvb/ttpci/Kconfig
@@ -108,7 +108,7 @@ config DVB_BUDGET_CI
select DVB_STB6100 if !DVB_FE_CUSTOMISE
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
select VIDEO_IR
help
Support for simple SAA7146 based DVB cards
diff --git a/linux/drivers/media/dvb/ttpci/av7110_v4l.c b/linux/drivers/media/dvb/ttpci/av7110_v4l.c
index b4a0cc5dc..c5b9c7056 100644
--- a/linux/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/linux/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -316,7 +316,7 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
return 0;
}
-static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct saa7146_dev *dev = fh->dev;
struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
@@ -567,7 +567,7 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return 0;
}
-static int av7110_vbi_reset(struct inode *inode, struct file *file)
+static int av7110_vbi_reset(struct file *file)
{
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev;
diff --git a/linux/drivers/media/dvb/ttpci/budget-av.c b/linux/drivers/media/dvb/ttpci/budget-av.c
index f996cef79..4182121d7 100644
--- a/linux/drivers/media/dvb/ttpci/budget-av.c
+++ b/linux/drivers/media/dvb/ttpci/budget-av.c
@@ -1493,7 +1493,7 @@ static struct saa7146_extension_ioctls ioctls[] = {
{0, 0}
};
-static int av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+static long av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct saa7146_dev *dev = fh->dev;
struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
diff --git a/linux/drivers/media/dvb/ttusb-budget/Kconfig b/linux/drivers/media/dvb/ttusb-budget/Kconfig
index f546bccdb..2663ae39b 100644
--- a/linux/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/linux/drivers/media/dvb/ttusb-budget/Kconfig
@@ -1,6 +1,6 @@
config DVB_TTUSB_BUDGET
tristate "Technotrend/Hauppauge Nova-USB devices"
- depends on DVB_CORE && USB && I2C
+ depends on DVB_CORE && USB && I2C && PCI
select DVB_CX22700 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_VES1820 if !DVB_FE_CUSTOMISE
diff --git a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 8775b78af..086b9987f 100644
--- a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -1657,6 +1657,9 @@ static void frontend_init(struct ttusb* ttusb)
static struct i2c_algorithm ttusb_dec_algo = {
.master_xfer = master_xfer,
.functionality = functionality,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
diff --git a/linux/drivers/media/dvb/ttusb-dec/Kconfig b/linux/drivers/media/dvb/ttusb-dec/Kconfig
index d5f48a310..290254ab0 100644
--- a/linux/drivers/media/dvb/ttusb-dec/Kconfig
+++ b/linux/drivers/media/dvb/ttusb-dec/Kconfig
@@ -1,6 +1,6 @@
config DVB_TTUSB_DEC
tristate "Technotrend/Hauppauge USB DEC devices"
- depends on DVB_CORE && USB && INPUT
+ depends on DVB_CORE && USB && INPUT && PCI
select CRC32
help
Support for external USB adapters designed by Technotrend and
diff --git a/linux/drivers/media/radio/Kconfig b/linux/drivers/media/radio/Kconfig
index 5189c4eb4..3315cac87 100644
--- a/linux/drivers/media/radio/Kconfig
+++ b/linux/drivers/media/radio/Kconfig
@@ -387,4 +387,23 @@ config USB_MR800
To compile this driver as a module, choose M here: the
module will be called radio-mr800.
+config RADIO_TEA5764
+ tristate "TEA5764 I2C FM radio support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ Say Y here if you want to use the TEA5764 FM chip found in
+ EZX phones. This FM chip is present in EZX phones from Motorola,
+ connected to internal pxa I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-tea5764.
+
+config RADIO_TEA5764_XTAL
+ bool "TEA5764 crystal reference"
+ depends on RADIO_TEA5764=y
+ default y
+ help
+ Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N
+ here if TEA5764 reference frequency is connected in FREQIN.
+
endif # RADIO_ADAPTERS
diff --git a/linux/drivers/media/radio/Makefile b/linux/drivers/media/radio/Makefile
index 240ec63cd..0f2b35b3e 100644
--- a/linux/drivers/media/radio/Makefile
+++ b/linux/drivers/media/radio/Makefile
@@ -19,5 +19,6 @@ obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
obj-$(CONFIG_USB_DSBR) += dsbr100.o
obj-$(CONFIG_USB_SI470X) += radio-si470x.o
obj-$(CONFIG_USB_MR800) += radio-mr800.o
+obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
EXTRA_CFLAGS += -Isound
diff --git a/linux/drivers/media/radio/dsbr100.c b/linux/drivers/media/radio/dsbr100.c
index d1865b164..bb3f5a855 100644
--- a/linux/drivers/media/radio/dsbr100.c
+++ b/linux/drivers/media/radio/dsbr100.c
@@ -1,5 +1,5 @@
-/* A driver for the D-Link DSB-R100 USB radio. The R100 plugs
- into both the USB and an analog audio input, so this thing
+/* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21.
+ The device plugs into both the USB and an analog audio input, so this thing
only deals with initialisation and frequency setting, the
audio data has to be handled by a sound driver.
@@ -33,6 +33,10 @@
History:
+ Version 0.44:
+ Add suspend/resume functions, fix unplug of device,
+ a lot of cleanups and fixes by Alexey Klimov <klimov.linux@gmail.com>
+
Version 0.43:
Oliver Neukum: avoided DMA coherency issue
@@ -94,8 +98,8 @@
*/
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
-#define DRIVER_VERSION "v0.43"
-#define RADIO_VERSION KERNEL_VERSION(0, 4, 3)
+#define DRIVER_VERSION "v0.44"
+#define RADIO_VERSION KERNEL_VERSION(0, 4, 4)
static struct v4l2_queryctrl radio_qctrl[] = {
{
@@ -146,12 +150,13 @@ devices, that would be 76 and 91. */
#define FREQ_MAX 108.0
#define FREQ_MUL 16000
+#define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
static int usb_dsbr100_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void usb_dsbr100_disconnect(struct usb_interface *intf);
-static int usb_dsbr100_open(struct inode *inode, struct file *file);
-static int usb_dsbr100_close(struct inode *inode, struct file *file);
+static int usb_dsbr100_open(struct file *file);
+static int usb_dsbr100_close(struct file *file);
static int usb_dsbr100_suspend(struct usb_interface *intf,
pm_message_t message);
static int usb_dsbr100_resume(struct usb_interface *intf);
@@ -162,8 +167,9 @@ module_param(radio_nr, int, 0);
/* Data for one (physical) device */
struct dsbr100_device {
struct usb_device *usbdev;
- struct video_device *videodev;
+ struct video_device videodev;
u8 *transfer_buffer;
+ struct mutex lock; /* buffer locking */
int curfreq;
int stereo;
int users;
@@ -171,7 +177,6 @@ struct dsbr100_device {
int muted;
};
-
static struct usb_device_id usb_dsbr100_device_table [] = {
{ USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
{ } /* Terminating entry */
@@ -198,95 +203,190 @@ static struct usb_driver usb_dsbr100_driver = {
/* switch on radio */
static int dsbr100_start(struct dsbr100_device *radio)
{
- if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
- USB_REQ_GET_STATUS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x00, 0xC7, radio->transfer_buffer, 8, 300) < 0 ||
- usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
- DSB100_ONOFF,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x01, 0x00, radio->transfer_buffer, 8, 300) < 0)
- return -1;
- radio->muted=0;
+ int retval;
+ int request;
+
+ mutex_lock(&radio->lock);
+
+ retval = usb_control_msg(radio->usbdev,
+ usb_rcvctrlpipe(radio->usbdev, 0),
+ USB_REQ_GET_STATUS,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x00, 0xC7, radio->transfer_buffer, 8, 300);
+
+ if (retval < 0) {
+ request = USB_REQ_GET_STATUS;
+ goto usb_control_msg_failed;
+ }
+
+ retval = usb_control_msg(radio->usbdev,
+ usb_rcvctrlpipe(radio->usbdev, 0),
+ DSB100_ONOFF,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x01, 0x00, radio->transfer_buffer, 8, 300);
+
+ if (retval < 0) {
+ request = DSB100_ONOFF;
+ goto usb_control_msg_failed;
+ }
+
+ radio->muted = 0;
+ mutex_unlock(&radio->lock);
return (radio->transfer_buffer)[0];
-}
+usb_control_msg_failed:
+ mutex_unlock(&radio->lock);
+ dev_err(&radio->usbdev->dev,
+ "%s - usb_control_msg returned %i, request %i\n",
+ __func__, retval, request);
+ return retval;
+
+}
/* switch off radio */
static int dsbr100_stop(struct dsbr100_device *radio)
{
- if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
- USB_REQ_GET_STATUS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x16, 0x1C, radio->transfer_buffer, 8, 300) < 0 ||
- usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
- DSB100_ONOFF,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x00, 0x00, radio->transfer_buffer, 8, 300) < 0)
- return -1;
- radio->muted=1;
+ int retval;
+ int request;
+
+ mutex_lock(&radio->lock);
+
+ retval = usb_control_msg(radio->usbdev,
+ usb_rcvctrlpipe(radio->usbdev, 0),
+ USB_REQ_GET_STATUS,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x16, 0x1C, radio->transfer_buffer, 8, 300);
+
+ if (retval < 0) {
+ request = USB_REQ_GET_STATUS;
+ goto usb_control_msg_failed;
+ }
+
+ retval = usb_control_msg(radio->usbdev,
+ usb_rcvctrlpipe(radio->usbdev, 0),
+ DSB100_ONOFF,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x00, 0x00, radio->transfer_buffer, 8, 300);
+
+ if (retval < 0) {
+ request = DSB100_ONOFF;
+ goto usb_control_msg_failed;
+ }
+
+ radio->muted = 1;
+ mutex_unlock(&radio->lock);
return (radio->transfer_buffer)[0];
+
+usb_control_msg_failed:
+ mutex_unlock(&radio->lock);
+ dev_err(&radio->usbdev->dev,
+ "%s - usb_control_msg returned %i, request %i\n",
+ __func__, retval, request);
+ return retval;
+
}
/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
{
+ int retval;
+ int request;
+
freq = (freq / 16 * 80) / 1000 + 856;
- if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
- DSB100_TUNE,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- (freq >> 8) & 0x00ff, freq & 0xff,
- radio->transfer_buffer, 8, 300) < 0 ||
- usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
- USB_REQ_GET_STATUS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x96, 0xB7, radio->transfer_buffer, 8, 300) < 0 ||
- usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
- USB_REQ_GET_STATUS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x00, 0x24, radio->transfer_buffer, 8, 300) < 0) {
- radio->stereo = -1;
- return -1;
+ mutex_lock(&radio->lock);
+
+ retval = usb_control_msg(radio->usbdev,
+ usb_rcvctrlpipe(radio->usbdev, 0),
+ DSB100_TUNE,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ (freq >> 8) & 0x00ff, freq & 0xff,
+ radio->transfer_buffer, 8, 300);
+
+ if (retval < 0) {
+ request = DSB100_TUNE;
+ goto usb_control_msg_failed;
}
+
+ retval = usb_control_msg(radio->usbdev,
+ usb_rcvctrlpipe(radio->usbdev, 0),
+ USB_REQ_GET_STATUS,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x96, 0xB7, radio->transfer_buffer, 8, 300);
+
+ if (retval < 0) {
+ request = USB_REQ_GET_STATUS;
+ goto usb_control_msg_failed;
+ }
+
+ retval = usb_control_msg(radio->usbdev,
+ usb_rcvctrlpipe(radio->usbdev, 0),
+ USB_REQ_GET_STATUS,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x00, 0x24, radio->transfer_buffer, 8, 300);
+
+ if (retval < 0) {
+ request = USB_REQ_GET_STATUS;
+ goto usb_control_msg_failed;
+ }
+
radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
+ mutex_unlock(&radio->lock);
return (radio->transfer_buffer)[0];
+
+usb_control_msg_failed:
+ radio->stereo = -1;
+ mutex_unlock(&radio->lock);
+ dev_err(&radio->usbdev->dev,
+ "%s - usb_control_msg returned %i, request %i\n",
+ __func__, retval, request);
+ return retval;
}
/* return the device status. This is, in effect, just whether it
sees a stereo signal or not. Pity. */
static void dsbr100_getstat(struct dsbr100_device *radio)
{
- if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+ int retval;
+
+ mutex_lock(&radio->lock);
+
+ retval = usb_control_msg(radio->usbdev,
+ usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x00 , 0x24, radio->transfer_buffer, 8, 300) < 0)
+ 0x00 , 0x24, radio->transfer_buffer, 8, 300);
+
+ if (retval < 0) {
radio->stereo = -1;
- else
+ dev_err(&radio->usbdev->dev,
+ "%s - usb_control_msg returned %i, request %i\n",
+ __func__, retval, USB_REQ_GET_STATUS);
+ } else {
radio->stereo = !(radio->transfer_buffer[0] & 0x01);
-}
+ }
+ mutex_unlock(&radio->lock);
+}
/* USB subsystem interface begins here */
-/* handle unplugging of the device, release data structures
-if nothing keeps us from doing it. If something is still
-keeping us busy, the release callback of v4l will take care
-of releasing it. */
+/*
+ * Handle unplugging of the device.
+ * We call video_unregister_device in any case.
+ * The last function called in this procedure is
+ * usb_dsbr100_video_device_release
+ */
static void usb_dsbr100_disconnect(struct usb_interface *intf)
{
struct dsbr100_device *radio = usb_get_intfdata(intf);
usb_set_intfdata (intf, NULL);
- if (radio) {
- video_unregister_device(radio->videodev);
- radio->videodev = NULL;
- if (radio->users) {
- kfree(radio->transfer_buffer);
- kfree(radio);
- } else {
- radio->removed = 1;
- }
- }
+
+ mutex_lock(&radio->lock);
+ radio->removed = 1;
+ mutex_unlock(&radio->lock);
+
+ video_unregister_device(&radio->videodev);
}
@@ -306,6 +406,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
{
struct dsbr100_device *radio = video_drvdata(file);
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
+
if (v->index > 0)
return -EINVAL;
@@ -327,6 +431,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
static int vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
+ struct dsbr100_device *radio = video_drvdata(file);
+
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
+
if (v->index > 0)
return -EINVAL;
@@ -337,9 +447,15 @@ static int vidioc_s_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
struct dsbr100_device *radio = video_drvdata(file);
+ int retval;
+
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
radio->curfreq = f->frequency;
- if (dsbr100_setfreq(radio, radio->curfreq) == -1)
+ retval = dsbr100_setfreq(radio, radio->curfreq);
+ if (retval < 0)
dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
return 0;
}
@@ -349,6 +465,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
{
struct dsbr100_device *radio = video_drvdata(file);
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
+
f->type = V4L2_TUNER_RADIO;
f->frequency = radio->curfreq;
return 0;
@@ -373,6 +493,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
{
struct dsbr100_device *radio = video_drvdata(file);
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
+
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
ctrl->value = radio->muted;
@@ -385,17 +509,24 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct dsbr100_device *radio = video_drvdata(file);
+ int retval;
+
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
if (ctrl->value) {
- if (dsbr100_stop(radio) == -1) {
+ retval = dsbr100_stop(radio);
+ if (retval < 0) {
dev_warn(&radio->usbdev->dev,
"Radio did not respond properly\n");
return -EBUSY;
}
} else {
- if (dsbr100_start(radio) == -1) {
+ retval = dsbr100_start(radio);
+ if (retval < 0) {
dev_warn(&radio->usbdev->dev,
"Radio did not respond properly\n");
return -EBUSY;
@@ -438,7 +569,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
return 0;
}
-static int usb_dsbr100_open(struct inode *inode, struct file *file)
+static int usb_dsbr100_open(struct file *file)
{
struct dsbr100_device *radio = video_drvdata(file);
int retval;
@@ -447,7 +578,8 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
radio->users = 1;
radio->muted = 1;
- if (dsbr100_start(radio) < 0) {
+ retval = dsbr100_start(radio);
+ if (retval < 0) {
dev_warn(&radio->usbdev->dev,
"Radio did not start up properly\n");
radio->users = 0;
@@ -456,24 +588,30 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
}
retval = dsbr100_setfreq(radio, radio->curfreq);
-
- if (retval == -1)
- printk(KERN_WARNING KBUILD_MODNAME ": Set frequency failed\n");
+ if (retval < 0)
+ dev_warn(&radio->usbdev->dev,
+ "set frequency failed\n");
unlock_kernel();
return 0;
}
-static int usb_dsbr100_close(struct inode *inode, struct file *file)
+static int usb_dsbr100_close(struct file *file)
{
struct dsbr100_device *radio = video_drvdata(file);
+ int retval;
if (!radio)
return -ENODEV;
+
radio->users = 0;
- if (radio->removed) {
- kfree(radio->transfer_buffer);
- kfree(radio);
+ if (!radio->removed) {
+ retval = dsbr100_stop(radio);
+ if (retval < 0) {
+ dev_warn(&radio->usbdev->dev,
+ "dsbr100_stop failed\n");
+ }
+
}
return 0;
}
@@ -485,7 +623,7 @@ static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
int retval;
retval = dsbr100_stop(radio);
- if (retval == -1)
+ if (retval < 0)
dev_warn(&intf->dev, "dsbr100_stop failed\n");
dev_info(&intf->dev, "going into suspend..\n");
@@ -500,7 +638,7 @@ static int usb_dsbr100_resume(struct usb_interface *intf)
int retval;
retval = dsbr100_start(radio);
- if (retval == -1)
+ if (retval < 0)
dev_warn(&intf->dev, "dsbr100_start failed\n");
dev_info(&intf->dev, "coming out of suspend..\n");
@@ -508,16 +646,21 @@ static int usb_dsbr100_resume(struct usb_interface *intf)
return 0;
}
+/* free data structures */
+static void usb_dsbr100_video_device_release(struct video_device *videodev)
+{
+ struct dsbr100_device *radio = videodev_to_radio(videodev);
+
+ kfree(radio->transfer_buffer);
+ kfree(radio);
+}
+
/* File system interface */
-static const struct file_operations usb_dsbr100_fops = {
+static const struct v4l2_file_operations usb_dsbr100_fops = {
.owner = THIS_MODULE,
.open = usb_dsbr100_open,
.release = usb_dsbr100_close,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
@@ -536,19 +679,19 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
};
/* V4L2 interface */
-static struct video_device dsbr100_videodev_template = {
+static struct video_device dsbr100_videodev_data = {
.name = "D-Link DSB-R 100",
.fops = &usb_dsbr100_fops,
.ioctl_ops = &usb_dsbr100_ioctl_ops,
- .release = video_device_release,
+ .release = usb_dsbr100_video_device_release,
};
-/* check if the device is present and register with v4l and
-usb if it is */
+/* check if the device is present and register with v4l and usb if it is */
static int usb_dsbr100_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct dsbr100_device *radio;
+ int retval;
radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL);
@@ -561,23 +704,18 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
kfree(radio);
return -ENOMEM;
}
- radio->videodev = video_device_alloc();
- if (!(radio->videodev)) {
- kfree(radio->transfer_buffer);
- kfree(radio);
- return -ENOMEM;
- }
- memcpy(radio->videodev, &dsbr100_videodev_template,
- sizeof(dsbr100_videodev_template));
+ mutex_init(&radio->lock);
+ radio->videodev = dsbr100_videodev_data;
+
radio->removed = 0;
radio->users = 0;
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = FREQ_MIN * FREQ_MUL;
- video_set_drvdata(radio->videodev, radio);
- if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) {
- dev_warn(&intf->dev, "Could not register video device\n");
- video_device_release(radio->videodev);
+ video_set_drvdata(&radio->videodev, radio);
+ retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ if (retval < 0) {
+ dev_err(&intf->dev, "couldn't register video device\n");
kfree(radio->transfer_buffer);
kfree(radio);
return -EIO;
diff --git a/linux/drivers/media/radio/radio-aimslab.c b/linux/drivers/media/radio/radio-aimslab.c
index 4f3886097..384aa928f 100644
--- a/linux/drivers/media/radio/radio-aimslab.c
+++ b/linux/drivers/media/radio/radio-aimslab.c
@@ -375,26 +375,22 @@ static int vidioc_s_audio(struct file *file, void *priv,
static struct rt_device rtrack_unit;
-static int rtrack_exclusive_open(struct inode *inode, struct file *file)
+static int rtrack_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &rtrack_unit.in_use) ? -EBUSY : 0;
}
-static int rtrack_exclusive_release(struct inode *inode, struct file *file)
+static int rtrack_exclusive_release(struct file *file)
{
clear_bit(0, &rtrack_unit.in_use);
return 0;
}
-static const struct file_operations rtrack_fops = {
+static const struct v4l2_file_operations rtrack_fops = {
.owner = THIS_MODULE,
.open = rtrack_exclusive_open,
.release = rtrack_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops rtrack_ioctl_ops = {
diff --git a/linux/drivers/media/radio/radio-aztech.c b/linux/drivers/media/radio/radio-aztech.c
index 9ce1908ac..d4d5babcd 100644
--- a/linux/drivers/media/radio/radio-aztech.c
+++ b/linux/drivers/media/radio/radio-aztech.c
@@ -339,26 +339,22 @@ static int vidioc_s_ctrl (struct file *file, void *priv,
static struct az_device aztech_unit;
-static int aztech_exclusive_open(struct inode *inode, struct file *file)
+static int aztech_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &aztech_unit.in_use) ? -EBUSY : 0;
}
-static int aztech_exclusive_release(struct inode *inode, struct file *file)
+static int aztech_exclusive_release(struct file *file)
{
clear_bit(0, &aztech_unit.in_use);
return 0;
}
-static const struct file_operations aztech_fops = {
+static const struct v4l2_file_operations aztech_fops = {
.owner = THIS_MODULE,
.open = aztech_exclusive_open,
.release = aztech_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
diff --git a/linux/drivers/media/radio/radio-cadet.c b/linux/drivers/media/radio/radio-cadet.c
index d05141fd9..7425aef88 100644
--- a/linux/drivers/media/radio/radio-cadet.c
+++ b/linux/drivers/media/radio/radio-cadet.c
@@ -559,7 +559,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
}
static int
-cadet_open(struct inode *inode, struct file *file)
+cadet_open(struct file *file)
{
users++;
if (1 == users) init_waitqueue_head(&read_queue);
@@ -567,7 +567,7 @@ cadet_open(struct inode *inode, struct file *file)
}
static int
-cadet_release(struct inode *inode, struct file *file)
+cadet_release(struct file *file)
{
users--;
if (0 == users){
@@ -587,17 +587,13 @@ cadet_poll(struct file *file, struct poll_table_struct *wait)
}
-static const struct file_operations cadet_fops = {
+static const struct v4l2_file_operations cadet_fops = {
.owner = THIS_MODULE,
.open = cadet_open,
.release = cadet_release,
.read = cadet_read,
.ioctl = video_ioctl2,
.poll = cadet_poll,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops cadet_ioctl_ops = {
diff --git a/linux/drivers/media/radio/radio-gemtek-pci.c b/linux/drivers/media/radio/radio-gemtek-pci.c
index 06a91be87..7edd3e594 100644
--- a/linux/drivers/media/radio/radio-gemtek-pci.c
+++ b/linux/drivers/media/radio/radio-gemtek-pci.c
@@ -359,26 +359,22 @@ MODULE_DEVICE_TABLE( pci, gemtek_pci_id );
static int mx = 1;
-static int gemtek_pci_exclusive_open(struct inode *inode, struct file *file)
+static int gemtek_pci_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
}
-static int gemtek_pci_exclusive_release(struct inode *inode, struct file *file)
+static int gemtek_pci_exclusive_release(struct file *file)
{
clear_bit(0, &in_use);
return 0;
}
-static const struct file_operations gemtek_pci_fops = {
+static const struct v4l2_file_operations gemtek_pci_fops = {
.owner = THIS_MODULE,
.open = gemtek_pci_exclusive_open,
.release = gemtek_pci_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = {
diff --git a/linux/drivers/media/radio/radio-gemtek.c b/linux/drivers/media/radio/radio-gemtek.c
index 5dbd342bf..a1ae890c8 100644
--- a/linux/drivers/media/radio/radio-gemtek.c
+++ b/linux/drivers/media/radio/radio-gemtek.c
@@ -395,26 +395,22 @@ static struct v4l2_queryctrl radio_qctrl[] = {
}
};
-static int gemtek_exclusive_open(struct inode *inode, struct file *file)
+static int gemtek_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
}
-static int gemtek_exclusive_release(struct inode *inode, struct file *file)
+static int gemtek_exclusive_release(struct file *file)
{
clear_bit(0, &in_use);
return 0;
}
-static const struct file_operations gemtek_fops = {
+static const struct v4l2_file_operations gemtek_fops = {
.owner = THIS_MODULE,
.open = gemtek_exclusive_open,
.release = gemtek_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek
};
static int vidioc_querycap(struct file *file, void *priv,
diff --git a/linux/drivers/media/radio/radio-maestro.c b/linux/drivers/media/radio/radio-maestro.c
index 326405d3b..7442be614 100644
--- a/linux/drivers/media/radio/radio-maestro.c
+++ b/linux/drivers/media/radio/radio-maestro.c
@@ -80,12 +80,12 @@ static unsigned long in_use;
static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
-static int maestro_exclusive_open(struct inode *inode, struct file *file)
+static int maestro_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
}
-static int maestro_exclusive_release(struct inode *inode, struct file *file)
+static int maestro_exclusive_release(struct file *file)
{
clear_bit(0, &in_use);
return 0;
@@ -111,15 +111,11 @@ static struct pci_driver maestro_r_driver = {
.remove = __devexit_p(maestro_remove),
};
-static const struct file_operations maestro_fops = {
+static const struct v4l2_file_operations maestro_fops = {
.owner = THIS_MODULE,
.open = maestro_exclusive_open,
.release = maestro_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
struct radio_device {
diff --git a/linux/drivers/media/radio/radio-maxiradio.c b/linux/drivers/media/radio/radio-maxiradio.c
index 4aea352cb..cb9d07bc7 100644
--- a/linux/drivers/media/radio/radio-maxiradio.c
+++ b/linux/drivers/media/radio/radio-maxiradio.c
@@ -101,26 +101,22 @@ static unsigned long in_use;
#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF)
-static int maxiradio_exclusive_open(struct inode *inode, struct file *file)
+static int maxiradio_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
}
-static int maxiradio_exclusive_release(struct inode *inode, struct file *file)
+static int maxiradio_exclusive_release(struct file *file)
{
clear_bit(0, &in_use);
return 0;
}
-static const struct file_operations maxiradio_fops = {
+static const struct v4l2_file_operations maxiradio_fops = {
.owner = THIS_MODULE,
.open = maxiradio_exclusive_open,
.release = maxiradio_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static struct radio_device
diff --git a/linux/drivers/media/radio/radio-mr800.c b/linux/drivers/media/radio/radio-mr800.c
index dbce57c26..6b1794989 100644
--- a/linux/drivers/media/radio/radio-mr800.c
+++ b/linux/drivers/media/radio/radio-mr800.c
@@ -128,8 +128,8 @@ static struct v4l2_queryctrl radio_qctrl[] = {
static int usb_amradio_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void usb_amradio_disconnect(struct usb_interface *intf);
-static int usb_amradio_open(struct inode *inode, struct file *file);
-static int usb_amradio_close(struct inode *inode, struct file *file);
+static int usb_amradio_open(struct file *file);
+static int usb_amradio_close(struct file *file);
static int usb_amradio_suspend(struct usb_interface *intf,
pm_message_t message);
static int usb_amradio_resume(struct usb_interface *intf);
@@ -142,7 +142,6 @@ struct amradio_device {
unsigned char *buffer;
struct mutex lock; /* buffer locking */
- struct mutex disconnect_lock;
int curfreq;
int stereo;
int users;
@@ -170,7 +169,7 @@ static struct usb_driver usb_amradio_driver = {
.reset_resume = usb_amradio_resume,
#endif
.id_table = usb_amradio_device_table,
- .supports_autosuspend = 1,
+ .supports_autosuspend = 0,
};
/* switch on radio. Send 8 bytes to device. */
@@ -305,16 +304,12 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
{
struct amradio_device *radio = usb_get_intfdata(intf);
- mutex_lock(&radio->disconnect_lock);
+ mutex_lock(&radio->lock);
radio->removed = 1;
- usb_set_intfdata(intf, NULL);
+ mutex_unlock(&radio->lock);
- if (radio->users == 0) {
- video_unregister_device(radio->videodev);
- kfree(radio->buffer);
- kfree(radio);
- }
- mutex_unlock(&radio->disconnect_lock);
+ usb_set_intfdata(intf, NULL);
+ video_unregister_device(radio->videodev);
}
/* vidioc_querycap - query device capabilities */
@@ -508,7 +503,7 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
}
/* open device - amradio_start() and amradio_setfreq() */
-static int usb_amradio_open(struct inode *inode, struct file *file)
+static int usb_amradio_open(struct file *file)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
@@ -532,8 +527,8 @@ static int usb_amradio_open(struct inode *inode, struct file *file)
return 0;
}
-/*close device - free driver structures */
-static int usb_amradio_close(struct inode *inode, struct file *file)
+/*close device */
+static int usb_amradio_close(struct file *file)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
int retval;
@@ -541,21 +536,15 @@ static int usb_amradio_close(struct inode *inode, struct file *file)
if (!radio)
return -ENODEV;
- mutex_lock(&radio->disconnect_lock);
radio->users = 0;
- if (radio->removed) {
- video_unregister_device(radio->videodev);
- kfree(radio->buffer);
- kfree(radio);
- } else {
+ if (!radio->removed) {
retval = amradio_stop(radio);
if (retval < 0)
amradio_dev_warn(&radio->videodev->dev,
"amradio_stop failed\n");
}
- mutex_unlock(&radio->disconnect_lock);
return 0;
}
@@ -586,15 +575,11 @@ static int usb_amradio_resume(struct usb_interface *intf)
}
/* File system interface */
-static const struct file_operations usb_amradio_fops = {
+static const struct v4l2_file_operations usb_amradio_fops = {
.owner = THIS_MODULE,
.open = usb_amradio_open,
.release = usb_amradio_close,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
@@ -612,12 +597,24 @@ static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
.vidioc_s_input = vidioc_s_input,
};
+static void usb_amradio_device_release(struct video_device *videodev)
+{
+ struct amradio_device *radio = video_get_drvdata(videodev);
+
+ /* we call v4l to free radio->videodev */
+ video_device_release(videodev);
+
+ /* free rest memory */
+ kfree(radio->buffer);
+ kfree(radio);
+}
+
/* V4L2 interface */
static struct video_device amradio_videodev_template = {
.name = "AverMedia MR 800 USB FM Radio",
.fops = &usb_amradio_fops,
.ioctl_ops = &usb_amradio_ioctl_ops,
- .release = video_device_release,
+ .release = usb_amradio_device_release,
};
/* check if the device is present and register with v4l and
@@ -655,7 +652,6 @@ static int usb_amradio_probe(struct usb_interface *intf,
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = 95.16 * FREQ_MUL;
- mutex_init(&radio->disconnect_lock);
mutex_init(&radio->lock);
video_set_drvdata(radio->videodev, radio);
diff --git a/linux/drivers/media/radio/radio-rtrack2.c b/linux/drivers/media/radio/radio-rtrack2.c
index 72413df42..fa9e243c8 100644
--- a/linux/drivers/media/radio/radio-rtrack2.c
+++ b/linux/drivers/media/radio/radio-rtrack2.c
@@ -281,26 +281,22 @@ static int vidioc_s_audio(struct file *file, void *priv,
static struct rt_device rtrack2_unit;
-static int rtrack2_exclusive_open(struct inode *inode, struct file *file)
+static int rtrack2_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &rtrack2_unit.in_use) ? -EBUSY : 0;
}
-static int rtrack2_exclusive_release(struct inode *inode, struct file *file)
+static int rtrack2_exclusive_release(struct file *file)
{
clear_bit(0, &rtrack2_unit.in_use);
return 0;
}
-static const struct file_operations rtrack2_fops = {
+static const struct v4l2_file_operations rtrack2_fops = {
.owner = THIS_MODULE,
.open = rtrack2_exclusive_open,
.release = rtrack2_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = {
diff --git a/linux/drivers/media/radio/radio-sf16fmi.c b/linux/drivers/media/radio/radio-sf16fmi.c
index 20326e7a5..3cce0afb4 100644
--- a/linux/drivers/media/radio/radio-sf16fmi.c
+++ b/linux/drivers/media/radio/radio-sf16fmi.c
@@ -281,26 +281,22 @@ static int vidioc_s_audio(struct file *file, void *priv,
static struct fmi_device fmi_unit;
-static int fmi_exclusive_open(struct inode *inode, struct file *file)
+static int fmi_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &fmi_unit.in_use) ? -EBUSY : 0;
}
-static int fmi_exclusive_release(struct inode *inode, struct file *file)
+static int fmi_exclusive_release(struct file *file)
{
clear_bit(0, &fmi_unit.in_use);
return 0;
}
-static const struct file_operations fmi_fops = {
+static const struct v4l2_file_operations fmi_fops = {
.owner = THIS_MODULE,
.open = fmi_exclusive_open,
.release = fmi_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
diff --git a/linux/drivers/media/radio/radio-sf16fmr2.c b/linux/drivers/media/radio/radio-sf16fmr2.c
index f5aebc9da..69a28d1ff 100644
--- a/linux/drivers/media/radio/radio-sf16fmr2.c
+++ b/linux/drivers/media/radio/radio-sf16fmr2.c
@@ -397,26 +397,22 @@ static int vidioc_s_audio(struct file *file, void *priv,
static struct fmr2_device fmr2_unit;
-static int fmr2_exclusive_open(struct inode *inode, struct file *file)
+static int fmr2_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &fmr2_unit.in_use) ? -EBUSY : 0;
}
-static int fmr2_exclusive_release(struct inode *inode, struct file *file)
+static int fmr2_exclusive_release(struct file *file)
{
clear_bit(0, &fmr2_unit.in_use);
return 0;
}
-static const struct file_operations fmr2_fops = {
+static const struct v4l2_file_operations fmr2_fops = {
.owner = THIS_MODULE,
.open = fmr2_exclusive_open,
.release = fmr2_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops fmr2_ioctl_ops = {
diff --git a/linux/drivers/media/radio/radio-si470x.c b/linux/drivers/media/radio/radio-si470x.c
index 5d6237b6d..f3cdf3af4 100644
--- a/linux/drivers/media/radio/radio-si470x.c
+++ b/linux/drivers/media/radio/radio-si470x.c
@@ -96,6 +96,8 @@
* 2008-10-20 Alexey Klimov <klimov.linux@gmail.com>
* - add support for KWorld USB FM Radio FM700
* - blacklisted KWorld radio in hid-core.c and hid-ids.h
+ * 2008-12-03 Mark Lord <mlord@pobox.com>
+ * - add support for DealExtreme USB Radio
*
* ToDo:
* - add firmware download/update support
@@ -139,6 +141,8 @@ static struct usb_device_id si470x_usb_driver_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) },
/* KWorld USB FM Radio SnapMusic Mobile 700 (FM700) */
{ USB_DEVICE_AND_INTERFACE_INFO(0x1b80, 0xd700, USB_CLASS_HID, 0, 0) },
+ /* DealExtreme USB Radio */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x10c5, 0x819a, USB_CLASS_HID, 0, 0) },
/* Terminating entry */
{ }
};
@@ -1080,7 +1084,7 @@ static unsigned int si470x_fops_poll(struct file *file,
/*
* si470x_fops_open - file open
*/
-static int si470x_fops_open(struct inode *inode, struct file *file)
+static int si470x_fops_open(struct file *file)
{
struct si470x_device *radio = video_drvdata(file);
int retval;
@@ -1110,7 +1114,7 @@ done:
/*
* si470x_fops_release - file release
*/
-static int si470x_fops_release(struct inode *inode, struct file *file)
+static int si470x_fops_release(struct file *file)
{
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
@@ -1152,15 +1156,11 @@ done:
/*
* si470x_fops - file operations interface
*/
-static const struct file_operations si470x_fops = {
+static const struct v4l2_file_operations si470x_fops = {
.owner = THIS_MODULE,
- .llseek = no_llseek,
.read = si470x_fops_read,
.poll = si470x_fops_poll,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
.open = si470x_fops_open,
.release = si470x_fops_release,
};
diff --git a/linux/drivers/media/radio/radio-tea5764.c b/linux/drivers/media/radio/radio-tea5764.c
new file mode 100644
index 000000000..328fa50ca
--- /dev/null
+++ b/linux/drivers/media/radio/radio-tea5764.c
@@ -0,0 +1,638 @@
+/*
+ * driver/media/radio/radio-tea5764.c
+ *
+ * Driver for TEA5764 radio chip for linux 2.6.
+ * This driver is for TEA5764 chip from NXP, used in EZX phones from Motorola.
+ * The I2C protocol is used for communicate with chip.
+ *
+ * Based in radio-tea5761.c Copyright (C) 2005 Nokia Corporation
+ *
+ * Copyright (c) 2008 Fabio Belavenuto <belavenuto@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * History:
+ * 2008-12-06 Fabio Belavenuto <belavenuto@gmail.com>
+ * initial code
+ *
+ * TODO:
+ * add platform_data support for IRQs platform dependencies
+ * add RDS support
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h> /* Initdata */
+#include <linux/videodev2.h> /* kernel radio structs */
+#include <linux/i2c.h> /* I2C */
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+
+#define DRIVER_VERSION "v0.01"
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 1)
+
+#define DRIVER_AUTHOR "Fabio Belavenuto <belavenuto@gmail.com>"
+#define DRIVER_DESC "A driver for the TEA5764 radio chip for EZX Phones."
+
+#define PINFO(format, ...)\
+ printk(KERN_INFO KBUILD_MODNAME ": "\
+ DRIVER_VERSION ": " format "\n", ## __VA_ARGS__)
+#define PWARN(format, ...)\
+ printk(KERN_WARNING KBUILD_MODNAME ": "\
+ DRIVER_VERSION ": " format "\n", ## __VA_ARGS__)
+#if 1
+# define PDEBUG(format, ...)\
+ printk(KERN_DEBUG KBUILD_MODNAME ": "\
+ DRIVER_VERSION ": " format "\n", ## __VA_ARGS__)
+#else
+# define PDEBUG(format, ...)
+#endif
+
+/* Frequency limits in MHz -- these are European values. For Japanese
+devices, that would be 76000 and 91000. */
+#define FREQ_MIN 87500
+#define FREQ_MAX 108000
+#define FREQ_MUL 16
+
+/* TEA5764 registers */
+#define TEA5764_MANID 0x002b
+#define TEA5764_CHIPID 0x5764
+
+#define TEA5764_INTREG_BLMSK 0x0001
+#define TEA5764_INTREG_FRRMSK 0x0002
+#define TEA5764_INTREG_LEVMSK 0x0008
+#define TEA5764_INTREG_IFMSK 0x0010
+#define TEA5764_INTREG_BLMFLAG 0x0100
+#define TEA5764_INTREG_FRRFLAG 0x0200
+#define TEA5764_INTREG_LEVFLAG 0x0800
+#define TEA5764_INTREG_IFFLAG 0x1000
+
+#define TEA5764_FRQSET_SUD 0x8000
+#define TEA5764_FRQSET_SM 0x4000
+
+#define TEA5764_TNCTRL_PUPD1 0x8000
+#define TEA5764_TNCTRL_PUPD0 0x4000
+#define TEA5764_TNCTRL_BLIM 0x2000
+#define TEA5764_TNCTRL_SWPM 0x1000
+#define TEA5764_TNCTRL_IFCTC 0x0800
+#define TEA5764_TNCTRL_AFM 0x0400
+#define TEA5764_TNCTRL_SMUTE 0x0200
+#define TEA5764_TNCTRL_SNC 0x0100
+#define TEA5764_TNCTRL_MU 0x0080
+#define TEA5764_TNCTRL_SSL1 0x0040
+#define TEA5764_TNCTRL_SSL0 0x0020
+#define TEA5764_TNCTRL_HLSI 0x0010
+#define TEA5764_TNCTRL_MST 0x0008
+#define TEA5764_TNCTRL_SWP 0x0004
+#define TEA5764_TNCTRL_DTC 0x0002
+#define TEA5764_TNCTRL_AHLSI 0x0001
+
+#define TEA5764_TUNCHK_LEVEL(x) (((x) & 0x00F0) >> 4)
+#define TEA5764_TUNCHK_IFCNT(x) (((x) & 0xFE00) >> 9)
+#define TEA5764_TUNCHK_TUNTO 0x0100
+#define TEA5764_TUNCHK_LD 0x0008
+#define TEA5764_TUNCHK_STEREO 0x0004
+
+#define TEA5764_TESTREG_TRIGFR 0x0800
+
+struct tea5764_regs {
+ u16 intreg; /* INTFLAG & INTMSK */
+ u16 frqset; /* FRQSETMSB & FRQSETLSB */
+ u16 tnctrl; /* TNCTRL1 & TNCTRL2 */
+ u16 frqchk; /* FRQCHKMSB & FRQCHKLSB */
+ u16 tunchk; /* IFCHK & LEVCHK */
+ u16 testreg; /* TESTBITS & TESTMODE */
+ u16 rdsstat; /* RDSSTAT1 & RDSSTAT2 */
+ u16 rdslb; /* RDSLBMSB & RDSLBLSB */
+ u16 rdspb; /* RDSPBMSB & RDSPBLSB */
+ u16 rdsbc; /* RDSBBC & RDSGBC */
+ u16 rdsctrl; /* RDSCTRL1 & RDSCTRL2 */
+ u16 rdsbbl; /* PAUSEDET & RDSBBL */
+ u16 manid; /* MANID1 & MANID2 */
+ u16 chipid; /* CHIPID1 & CHIPID2 */
+} __attribute__ ((packed));
+
+struct tea5764_write_regs {
+ u8 intreg; /* INTMSK */
+ u16 frqset; /* FRQSETMSB & FRQSETLSB */
+ u16 tnctrl; /* TNCTRL1 & TNCTRL2 */
+ u16 testreg; /* TESTBITS & TESTMODE */
+ u16 rdsctrl; /* RDSCTRL1 & RDSCTRL2 */
+ u16 rdsbbl; /* PAUSEDET & RDSBBL */
+} __attribute__ ((packed));
+
+#ifndef RADIO_TEA5764_XTAL
+#define RADIO_TEA5764_XTAL 1
+#endif
+
+static int radio_nr = -1;
+static int use_xtal = RADIO_TEA5764_XTAL;
+
+struct tea5764_device {
+ struct i2c_client *i2c_client;
+ struct video_device *videodev;
+ struct tea5764_regs regs;
+ struct mutex mutex;
+ int users;
+};
+
+/* I2C code related */
+int tea5764_i2c_read(struct tea5764_device *radio)
+{
+ int i;
+ u16 *p = (u16 *) &radio->regs;
+
+ struct i2c_msg msgs[1] = {
+ { radio->i2c_client->addr, I2C_M_RD, sizeof(radio->regs),
+ (void *)&radio->regs },
+ };
+ if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1)
+ return -EIO;
+ for (i = 0; i < sizeof(struct tea5764_regs) / sizeof(u16); i++)
+ p[i] = __be16_to_cpu(p[i]);
+
+ return 0;
+}
+
+int tea5764_i2c_write(struct tea5764_device *radio)
+{
+ struct tea5764_write_regs wr;
+ struct tea5764_regs *r = &radio->regs;
+ struct i2c_msg msgs[1] = {
+ { radio->i2c_client->addr, 0, sizeof(wr), (void *) &wr },
+ };
+ wr.intreg = r->intreg & 0xff;
+ wr.frqset = __cpu_to_be16(r->frqset);
+ wr.tnctrl = __cpu_to_be16(r->tnctrl);
+ wr.testreg = __cpu_to_be16(r->testreg);
+ wr.rdsctrl = __cpu_to_be16(r->rdsctrl);
+ wr.rdsbbl = __cpu_to_be16(r->rdsbbl);
+ if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+/* V4L2 code related */
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ }
+};
+
+static void tea5764_power_up(struct tea5764_device *radio)
+{
+ struct tea5764_regs *r = &radio->regs;
+
+ if (!(r->tnctrl & TEA5764_TNCTRL_PUPD0)) {
+ r->tnctrl &= ~(TEA5764_TNCTRL_AFM | TEA5764_TNCTRL_MU |
+ TEA5764_TNCTRL_HLSI);
+ if (!use_xtal)
+ r->testreg |= TEA5764_TESTREG_TRIGFR;
+ else
+ r->testreg &= ~TEA5764_TESTREG_TRIGFR;
+
+ r->tnctrl |= TEA5764_TNCTRL_PUPD0;
+ tea5764_i2c_write(radio);
+ }
+}
+
+static void tea5764_power_down(struct tea5764_device *radio)
+{
+ struct tea5764_regs *r = &radio->regs;
+
+ if (r->tnctrl & TEA5764_TNCTRL_PUPD0) {
+ r->tnctrl &= ~TEA5764_TNCTRL_PUPD0;
+ tea5764_i2c_write(radio);
+ }
+}
+
+static void tea5764_set_freq(struct tea5764_device *radio, int freq)
+{
+ struct tea5764_regs *r = &radio->regs;
+
+ /* formula: (freq [+ or -] 225000) / 8192 */
+ if (r->tnctrl & TEA5764_TNCTRL_HLSI)
+ r->frqset = (freq + 225000) / 8192;
+ else
+ r->frqset = (freq - 225000) / 8192;
+}
+
+static int tea5764_get_freq(struct tea5764_device *radio)
+{
+ struct tea5764_regs *r = &radio->regs;
+
+ if (r->tnctrl & TEA5764_TNCTRL_HLSI)
+ return (r->frqchk * 8192) - 225000;
+ else
+ return (r->frqchk * 8192) + 225000;
+}
+
+/* tune an frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+static void tea5764_tune(struct tea5764_device *radio, int freq)
+{
+ tea5764_set_freq(radio, freq);
+ if (tea5764_i2c_write(radio))
+ PWARN("Could not set frequency!");
+}
+
+static void tea5764_set_audout_mode(struct tea5764_device *radio, int audmode)
+{
+ struct tea5764_regs *r = &radio->regs;
+ int tnctrl = r->tnctrl;
+
+ if (audmode == V4L2_TUNER_MODE_MONO)
+ r->tnctrl |= TEA5764_TNCTRL_MST;
+ else
+ r->tnctrl &= ~TEA5764_TNCTRL_MST;
+ if (tnctrl != r->tnctrl)
+ tea5764_i2c_write(radio);
+}
+
+static int tea5764_get_audout_mode(struct tea5764_device *radio)
+{
+ struct tea5764_regs *r = &radio->regs;
+
+ if (r->tnctrl & TEA5764_TNCTRL_MST)
+ return V4L2_TUNER_MODE_MONO;
+ else
+ return V4L2_TUNER_MODE_STEREO;
+}
+
+static void tea5764_mute(struct tea5764_device *radio, int on)
+{
+ struct tea5764_regs *r = &radio->regs;
+ int tnctrl = r->tnctrl;
+
+ if (on)
+ r->tnctrl |= TEA5764_TNCTRL_MU;
+ else
+ r->tnctrl &= ~TEA5764_TNCTRL_MU;
+ if (tnctrl != r->tnctrl)
+ tea5764_i2c_write(radio);
+}
+
+static int tea5764_is_muted(struct tea5764_device *radio)
+{
+ return radio->regs.tnctrl & TEA5764_TNCTRL_MU;
+}
+
+/* V4L2 vidioc */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+{
+ struct tea5764_device *radio = video_drvdata(file);
+ struct video_device *dev = radio->videodev;
+
+ strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver));
+ strlcpy(v->card, dev->name, sizeof(v->card));
+ snprintf(v->bus_info, sizeof(v->bus_info), "I2C:%s", dev->dev.bus_id);
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ struct tea5764_device *radio = video_drvdata(file);
+ struct tea5764_regs *r = &radio->regs;
+
+ if (v->index > 0)
+ return -EINVAL;
+
+ memset(v, 0, sizeof(v));
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
+ tea5764_i2c_read(radio);
+ v->rangelow = FREQ_MIN * FREQ_MUL;
+ v->rangehigh = FREQ_MAX * FREQ_MUL;
+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ if (r->tunchk & TEA5764_TUNCHK_STEREO)
+ v->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ v->audmode = tea5764_get_audout_mode(radio);
+ v->signal = TEA5764_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf;
+ v->afc = TEA5764_TUNCHK_IFCNT(r->tunchk);
+
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ struct tea5764_device *radio = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+ tea5764_set_audout_mode(radio, v->audmode);
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct tea5764_device *radio = video_drvdata(file);
+
+ if (f->tuner != 0)
+ return -EINVAL;
+ if (f->frequency == 0) {
+ /* We special case this as a power down control. */
+ tea5764_power_down(radio);
+ }
+ if (f->frequency < (FREQ_MIN * FREQ_MUL))
+ return -EINVAL;
+ if (f->frequency > (FREQ_MAX * FREQ_MUL))
+ return -EINVAL;
+ tea5764_power_up(radio);
+ tea5764_tune(radio, (f->frequency * 125) / 2);
+ return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct tea5764_device *radio = video_drvdata(file);
+ struct tea5764_regs *r = &radio->regs;
+
+ tea5764_i2c_read(radio);
+ memset(f, 0, sizeof(f));
+ f->type = V4L2_TUNER_RADIO;
+ if (r->tnctrl & TEA5764_TNCTRL_PUPD0)
+ f->frequency = (tea5764_get_freq(radio) * 2) / 125;
+ else
+ f->frequency = 0;
+
+ return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct tea5764_device *radio = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ tea5764_i2c_read(radio);
+ ctrl->value = tea5764_is_muted(radio) ? 1 : 0;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct tea5764_device *radio = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ tea5764_mute(radio, ctrl->value);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ if (a->index > 1)
+ return -EINVAL;
+
+ strcpy(a->name, "Radio");
+ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ if (a->index != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int tea5764_open(struct file *file)
+{
+ /* Currently we support only one device */
+ int minor = video_devdata(file)->minor;
+ struct tea5764_device *radio = video_drvdata(file);
+
+ if (radio->videodev->minor != minor)
+ return -ENODEV;
+
+ mutex_lock(&radio->mutex);
+ /* Only exclusive access */
+ if (radio->users) {
+ mutex_unlock(&radio->mutex);
+ return -EBUSY;
+ }
+ radio->users++;
+ mutex_unlock(&radio->mutex);
+ file->private_data = radio;
+ return 0;
+}
+
+static int tea5764_close(struct file *file)
+{
+ struct tea5764_device *radio = video_drvdata(file);
+
+ if (!radio)
+ return -ENODEV;
+ mutex_lock(&radio->mutex);
+ radio->users--;
+ mutex_unlock(&radio->mutex);
+ return 0;
+}
+
+/* File system interface */
+static const struct v4l2_file_operations tea5764_fops = {
+ .owner = THIS_MODULE,
+ .open = tea5764_open,
+ .release = tea5764_close,
+ .ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops tea5764_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+};
+
+/* V4L2 interface */
+static struct video_device tea5764_radio_template = {
+ .name = "TEA5764 FM-Radio",
+ .fops = &tea5764_fops,
+ .ioctl_ops = &tea5764_ioctl_ops,
+ .release = video_device_release,
+};
+
+/* I2C probe: check if the device exists and register with v4l if it is */
+static int __devinit tea5764_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tea5764_device *radio;
+ struct tea5764_regs *r;
+ int ret;
+
+ PDEBUG("probe");
+ radio = kmalloc(sizeof(struct tea5764_device), GFP_KERNEL);
+ if (!radio)
+ return -ENOMEM;
+
+ mutex_init(&radio->mutex);
+ radio->i2c_client = client;
+ ret = tea5764_i2c_read(radio);
+ if (ret)
+ goto errfr;
+ r = &radio->regs;
+ PDEBUG("chipid = %04X, manid = %04X", r->chipid, r->manid);
+ if (r->chipid != TEA5764_CHIPID ||
+ (r->manid & 0x0fff) != TEA5764_MANID) {
+ PWARN("This chip is not a TEA5764!");
+ ret = -EINVAL;
+ goto errfr;
+ }
+
+ radio->videodev = video_device_alloc();
+ if (!(radio->videodev)) {
+ ret = -ENOMEM;
+ goto errfr;
+ }
+ memcpy(radio->videodev, &tea5764_radio_template,
+ sizeof(tea5764_radio_template));
+
+ i2c_set_clientdata(client, radio);
+ video_set_drvdata(radio->videodev, radio);
+
+ ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ if (ret < 0) {
+ PWARN("Could not register video device!");
+ goto errrel;
+ }
+
+ /* initialize and power off the chip */
+ tea5764_i2c_read(radio);
+ tea5764_set_audout_mode(radio, V4L2_TUNER_MODE_STEREO);
+ tea5764_mute(radio, 1);
+ tea5764_power_down(radio);
+
+ PINFO("registered.");
+ return 0;
+errrel:
+ video_device_release(radio->videodev);
+errfr:
+ kfree(radio);
+ return ret;
+}
+
+static int __devexit tea5764_i2c_remove(struct i2c_client *client)
+{
+ struct tea5764_device *radio = i2c_get_clientdata(client);
+
+ PDEBUG("remove");
+ if (radio) {
+ tea5764_power_down(radio);
+ video_unregister_device(radio->videodev);
+ kfree(radio);
+ }
+ return 0;
+}
+
+/* I2C subsystem interface */
+static const struct i2c_device_id tea5764_id[] = {
+ { "radio-tea5764", 0 },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(i2c, tea5764_id);
+
+static struct i2c_driver tea5764_i2c_driver = {
+ .driver = {
+ .name = "radio-tea5764",
+ .owner = THIS_MODULE,
+ },
+ .probe = tea5764_i2c_probe,
+ .remove = __devexit_p(tea5764_i2c_remove),
+ .id_table = tea5764_id,
+};
+
+/* init the driver */
+static int __init tea5764_init(void)
+{
+ int ret = i2c_add_driver(&tea5764_i2c_driver);
+
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": "
+ DRIVER_DESC "\n");
+ return ret;
+}
+
+/* cleanup the driver */
+static void __exit tea5764_exit(void)
+{
+ i2c_del_driver(&tea5764_i2c_driver);
+}
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(use_xtal, int, 1);
+MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board");
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr, "video4linux device number to use");
+
+module_init(tea5764_init);
+module_exit(tea5764_exit);
diff --git a/linux/drivers/media/radio/radio-terratec.c b/linux/drivers/media/radio/radio-terratec.c
index 3066b08f0..1c2b4db2d 100644
--- a/linux/drivers/media/radio/radio-terratec.c
+++ b/linux/drivers/media/radio/radio-terratec.c
@@ -353,26 +353,22 @@ static int vidioc_s_audio(struct file *file, void *priv,
static struct tt_device terratec_unit;
-static int terratec_exclusive_open(struct inode *inode, struct file *file)
+static int terratec_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &terratec_unit.in_use) ? -EBUSY : 0;
}
-static int terratec_exclusive_release(struct inode *inode, struct file *file)
+static int terratec_exclusive_release(struct file *file)
{
clear_bit(0, &terratec_unit.in_use);
return 0;
}
-static const struct file_operations terratec_fops = {
+static const struct v4l2_file_operations terratec_fops = {
.owner = THIS_MODULE,
.open = terratec_exclusive_open,
.release = terratec_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops terratec_ioctl_ops = {
diff --git a/linux/drivers/media/radio/radio-trust.c b/linux/drivers/media/radio/radio-trust.c
index a334ce27e..5ce7a9d1d 100644
--- a/linux/drivers/media/radio/radio-trust.c
+++ b/linux/drivers/media/radio/radio-trust.c
@@ -341,26 +341,22 @@ static int vidioc_s_audio(struct file *file, void *priv,
return 0;
}
-static int trust_exclusive_open(struct inode *inode, struct file *file)
+static int trust_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
}
-static int trust_exclusive_release(struct inode *inode, struct file *file)
+static int trust_exclusive_release(struct file *file)
{
clear_bit(0, &in_use);
return 0;
}
-static const struct file_operations trust_fops = {
+static const struct v4l2_file_operations trust_fops = {
.owner = THIS_MODULE,
.open = trust_exclusive_open,
.release = trust_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops trust_ioctl_ops = {
diff --git a/linux/drivers/media/radio/radio-typhoon.c b/linux/drivers/media/radio/radio-typhoon.c
index c7ea37389..bf812fbb5 100644
--- a/linux/drivers/media/radio/radio-typhoon.c
+++ b/linux/drivers/media/radio/radio-typhoon.c
@@ -331,26 +331,22 @@ static struct typhoon_device typhoon_unit =
.mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ,
};
-static int typhoon_exclusive_open(struct inode *inode, struct file *file)
+static int typhoon_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &typhoon_unit.in_use) ? -EBUSY : 0;
}
-static int typhoon_exclusive_release(struct inode *inode, struct file *file)
+static int typhoon_exclusive_release(struct file *file)
{
clear_bit(0, &typhoon_unit.in_use);
return 0;
}
-static const struct file_operations typhoon_fops = {
+static const struct v4l2_file_operations typhoon_fops = {
.owner = THIS_MODULE,
.open = typhoon_exclusive_open,
.release = typhoon_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
diff --git a/linux/drivers/media/radio/radio-zoltrix.c b/linux/drivers/media/radio/radio-zoltrix.c
index 61b0366ab..4654ecd8b 100644
--- a/linux/drivers/media/radio/radio-zoltrix.c
+++ b/linux/drivers/media/radio/radio-zoltrix.c
@@ -402,27 +402,23 @@ static int vidioc_s_audio(struct file *file, void *priv,
static struct zol_device zoltrix_unit;
-static int zoltrix_exclusive_open(struct inode *inode, struct file *file)
+static int zoltrix_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &zoltrix_unit.in_use) ? -EBUSY : 0;
}
-static int zoltrix_exclusive_release(struct inode *inode, struct file *file)
+static int zoltrix_exclusive_release(struct file *file)
{
clear_bit(0, &zoltrix_unit.in_use);
return 0;
}
-static const struct file_operations zoltrix_fops =
+static const struct v4l2_file_operations zoltrix_fops =
{
.owner = THIS_MODULE,
.open = zoltrix_exclusive_open,
.release = zoltrix_exclusive_release,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig
index c4ee10c37..19cf3b8f6 100644
--- a/linux/drivers/media/video/Kconfig
+++ b/linux/drivers/media/video/Kconfig
@@ -361,6 +361,17 @@ config VIDEO_SAA7191
To compile this driver as a module, choose M here: the
module will be called saa7191.
+config VIDEO_TVP514X
+ tristate "Texas Instruments TVP514x video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the TI TVP5146/47
+ decoder. It is currently working with the TI OMAP3 camera
+ controller.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tvp514x.
+
config VIDEO_TVP5150
tristate "Texas Instruments TVP5150 video decoder"
depends on VIDEO_V4L2 && I2C
@@ -725,10 +736,16 @@ config MT9M001_PCA9536_SWITCH
extender to switch between 8 and 10 bit datawidth modes
config SOC_CAMERA_MT9M111
- tristate "mt9m111 support"
+ tristate "mt9m111 and mt9m112 support"
depends on SOC_CAMERA && I2C
help
- This driver supports MT9M111 cameras from Micron
+ This driver supports MT9M111 and MT9M112 cameras from Micron
+
+config SOC_CAMERA_MT9T031
+ tristate "mt9t031 support"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports MT9T031 cameras from Micron.
config SOC_CAMERA_MT9V022
tristate "mt9v022 support"
@@ -744,6 +761,12 @@ config MT9V022_PCA9536_SWITCH
Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
extender to switch between 8 and 10 bit datawidth modes
+config SOC_CAMERA_TW9910
+ tristate "tw9910 support"
+ depends on SOC_CAMERA && I2C
+ help
+ This is a tw9910 video driver
+
config SOC_CAMERA_PLATFORM
tristate "platform camera support"
depends on SOC_CAMERA
@@ -765,11 +788,18 @@ config VIDEO_PXA27x
config VIDEO_SH_MOBILE_CEU
tristate "SuperH Mobile CEU Interface driver"
- depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA
+ depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
select VIDEOBUF_DMA_CONTIG
---help---
This is a v4l2 driver for the SuperH Mobile CEU Interface
+config VIDEO_OMAP2
+ tristate "OMAP2 Camera Capture Interface driver"
+ depends on VIDEO_DEV && ARCH_OMAP2
+ select VIDEOBUF_DMA_SG
+ ---help---
+ This is a v4l2 driver for the TI OMAP2 camera capture interface
+
#
# USB Multimedia device configuration
#
diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile
index 53d43f9e0..72f6d03d2 100644
--- a/linux/drivers/media/video/Makefile
+++ b/linux/drivers/media/video/Makefile
@@ -8,9 +8,14 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o
stkwebcam-objs := stk-webcam.o stk-sensor.o
-videodev-objs := v4l2-dev.o v4l2-ioctl.o
+omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
-obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-compat-ioctl32.o v4l2-int-device.o
+videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-subdev.o
+
+obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
+ifeq ($(CONFIG_COMPAT),y)
+ obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o
+endif
obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
@@ -67,6 +72,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
+obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
@@ -130,12 +136,15 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885/
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
+obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
+obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
+obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
obj-$(CONFIG_VIDEO_AU0828) += au0828/
diff --git a/linux/drivers/media/video/arv.c b/linux/drivers/media/video/arv.c
index c15dfd37c..6d84626e1 100644
--- a/linux/drivers/media/video/arv.c
+++ b/linux/drivers/media/video/arv.c
@@ -397,7 +397,7 @@ out_up:
return ret;
}
-static int ar_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long ar_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *dev = video_devdata(file);
struct ar_device *ar = video_get_drvdata(dev);
@@ -540,7 +540,7 @@ static int ar_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0;
}
-static int ar_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+static long ar_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
return video_usercopy(file, cmd, arg, ar_do_ioctl);
@@ -749,27 +749,23 @@ void ar_release(struct video_device *vfd)
****************************************************************************/
static struct ar_device ardev;
-static int ar_exclusive_open(struct inode *inode, struct file *file)
+static int ar_exclusive_open(struct file *file)
{
return test_and_set_bit(0, &ardev.in_use) ? -EBUSY : 0;
}
-static int ar_exclusive_release(struct inode *inode, struct file *file)
+static int ar_exclusive_release(struct file *file)
{
clear_bit(0, &ardev.in_use);
return 0;
}
-static const struct file_operations ar_fops = {
+static const struct v4l2_file_operations ar_fops = {
.owner = THIS_MODULE,
.open = ar_exclusive_open,
.release = ar_exclusive_release,
.read = ar_read,
.ioctl = ar_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static struct video_device ar_template = {
diff --git a/linux/drivers/media/video/au0828/au0828-i2c.c b/linux/drivers/media/video/au0828/au0828-i2c.c
index 03b797b9b..d8cef6ccc 100644
--- a/linux/drivers/media/video/au0828/au0828-i2c.c
+++ b/linux/drivers/media/video/au0828/au0828-i2c.c
@@ -301,6 +301,9 @@ static u32 au0828_functionality(struct i2c_adapter *adap)
static struct i2c_algorithm au0828_i2c_algo_template = {
.master_xfer = i2c_xfer,
.functionality = au0828_functionality,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
/* ----------------------------------------------------------------------- */
diff --git a/linux/drivers/media/video/bt8xx/bt832.c b/linux/drivers/media/video/bt8xx/bt832.c
deleted file mode 100644
index b677916bf..000000000
--- a/linux/drivers/media/video/bt8xx/bt832.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/* Driver for Bt832 CMOS Camera Video Processor
- i2c-addresses: 0x88 or 0x8a
-
- The BT832 interfaces to a Quartzsight Digital Camera (352x288, 25 or 30 fps)
- via a 9 pin connector ( 4-wire SDATA, 2-wire i2c, SCLK, VCC, GND).
- It outputs an 8-bit 4:2:2 YUV or YCrCb video signal which can be directly
- connected to bt848/bt878 GPIO pins on this purpose.
- (see: VLSI Vision Ltd. www.vvl.co.uk for camera datasheets)
-
- Supported Cards:
- - Pixelview Rev.4E: 0x8a
- GPIO 0x400000 toggles Bt832 RESET, and the chip changes to i2c 0x88 !
-
- (c) Gunther Mayer, 2002
-
- STATUS:
- - detect chip and hexdump
- - reset chip and leave low power mode
- - detect camera present
-
- TODO:
- - make it work (find correct setup for Bt832 and Bt878)
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/types.h>
-#include "compat.h"
-#include <linux/videodev.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <media/v4l2-common.h>
-
-#include "bttv.h"
-#include "bt832.h"
-
-MODULE_LICENSE("GPL");
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { I2C_ADDR_BT832_ALT1>>1, I2C_ADDR_BT832_ALT2>>1,
- I2C_CLIENT_END };
-I2C_CLIENT_INSMOD;
-
-int debug; /* debug output */
-module_param(debug, int, 0644);
-
-/* ---------------------------------------------------------------------- */
-
-static int bt832_detach(struct i2c_client *client);
-
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-struct bt832 {
- struct i2c_client client;
-};
-
-int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
-{
- int i,rc;
- buf[0]=0x80; // start at register 0 with auto-increment
- if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
- v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 1)\n",rc);
-
- for(i=0;i<65;i++)
- buf[i]=0;
- if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
- v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 65)\n",rc);
-
- // Note: On READ the first byte is the current index
- // (e.g. 0x80, what we just wrote)
-
- if(debug>1) {
- int i;
- v4l_dbg(2, debug,i2c_client_s,"hexdump:");
- for(i=1;i<65;i++) {
- if(i!=1) {
- if(((i-1)%8)==0) printk(" ");
- if(((i-1)%16)==0) {
- printk("\n");
- v4l_dbg(2, debug,i2c_client_s,"hexdump:");
- }
- }
- printk(" %02x",buf[i]);
- }
- printk("\n");
- }
- return 0;
-}
-
-// Return: 1 (is a bt832), 0 (No bt832 here)
-int bt832_init(struct i2c_client *i2c_client_s)
-{
- unsigned char *buf;
- int rc;
-
- buf=kmalloc(65,GFP_KERNEL);
- if (!buf) {
- v4l_err(&t->client,
- "Unable to allocate memory. Detaching.\n");
- return 0;
- }
- bt832_hexdump(i2c_client_s,buf);
-
- if(buf[0x40] != 0x31) {
- v4l_err(i2c_client_s,"This i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
- kfree(buf);
- return 0;
- }
-
- v4l_err(i2c_client_s,"Write 0 tp VPSTATUS\n");
- buf[0]=BT832_VP_STATUS; // Reg.52
- buf[1]= 0x00;
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
-
- bt832_hexdump(i2c_client_s,buf);
-
-
- // Leave low power mode:
- v4l_err(i2c_client_s,"leave low power mode.\n");
- buf[0]=BT832_CAM_SETUP0; //0x39 57
- buf[1]=0x08;
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- v4l_err(i2c_client_s,"i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
-
- bt832_hexdump(i2c_client_s,buf);
-
- v4l_info(i2c_client_s,"Write 0 tp VPSTATUS\n");
- buf[0]=BT832_VP_STATUS; // Reg.52
- buf[1]= 0x00;
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
-
- bt832_hexdump(i2c_client_s,buf);
-
-
- // Enable Output
- v4l_info(i2c_client_s,"Enable Output\n");
- buf[0]=BT832_VP_CONTROL1; // Reg.40
- buf[1]= 0x27 & (~0x01); // Default | !skip
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- v4l_err(i2c_client_s,"i2c i/o error EO: rc == %d (should be 2)\n",rc);
-
- bt832_hexdump(i2c_client_s,buf);
-
-#if 0
- // Full 30/25 Frame rate
- v4l_err(i2c_client_s,"Full 30/25 Frame rate\n");
- buf[0]=BT832_VP_CONTROL0; // Reg.39
- buf[1]= 0x00;
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- v4l_err(i2c_client_s,"i2c i/o error FFR: rc == %d (should be 2)\n",rc);
-
- bt832_hexdump(i2c_client_s,buf);
-#endif
-
-#if 1
- // for testing (even works when no camera attached)
- v4l_info(i2c_client_s,"*** Generate NTSC M Bars *****\n");
- buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
- buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- v4l_info(i2c_client_s,"i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
-#endif
-
- v4l_info(i2c_client_s,"Camera Present: %s\n",
- (buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
-
- bt832_hexdump(i2c_client_s,buf);
- kfree(buf);
- return 1;
-}
-
-
-
-static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
-{
- struct bt832 *t;
-
- client_template.adapter = adap;
- client_template.addr = addr;
-
- if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))
- return -ENOMEM;
- t->client = client_template;
- i2c_set_clientdata(&t->client, t);
- i2c_attach_client(&t->client);
-
- v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
-
- if(! bt832_init(&t->client)) {
- bt832_detach(&t->client);
- return -1;
- }
-
- return 0;
-}
-
-static int bt832_probe(struct i2c_adapter *adap)
-{
- if (adap->class & I2C_CLASS_TV_ANALOG)
- return i2c_probe(adap, &addr_data, bt832_attach);
- return 0;
-}
-
-static int bt832_detach(struct i2c_client *client)
-{
- struct bt832 *t = i2c_get_clientdata(client);
-
- v4l_info(&t->client,"dettach\n");
- i2c_detach_client(client);
- kfree(t);
- return 0;
-}
-
-static int
-bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
- struct bt832 *t = i2c_get_clientdata(client);
-
- if (debug>1)
- v4l_i2c_print_ioctl(&t->client,cmd);
-
- switch (cmd) {
- case BT832_HEXDUMP: {
- unsigned char *buf;
- buf = kmalloc(65, GFP_KERNEL);
- if (!buf) {
- v4l_err(&t->client,
- "Unable to allocate memory\n");
- break;
- }
- bt832_hexdump(&t->client,buf);
- kfree(buf);
- }
- break;
- case BT832_REATTACH:
- v4l_info(&t->client,"re-attach\n");
- i2c_del_driver(&driver);
- i2c_add_driver(&driver);
- break;
- }
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver driver = {
- .driver = {
- .name = "bt832",
- },
- .id = 0, /* FIXME */
- .attach_adapter = bt832_probe,
- .detach_client = bt832_detach,
- .command = bt832_command,
-};
-static struct i2c_client client_template =
-{
- .name = "bt832",
- .driver = &driver,
-};
-
-
-static int __init bt832_init_module(void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit bt832_cleanup_module(void)
-{
- i2c_del_driver(&driver);
-}
-
-module_init(bt832_init_module);
-module_exit(bt832_cleanup_module);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/linux/drivers/media/video/bt8xx/bt832.h b/linux/drivers/media/video/bt8xx/bt832.h
deleted file mode 100644
index 1ce8fa71f..000000000
--- a/linux/drivers/media/video/bt8xx/bt832.h
+++ /dev/null
@@ -1,305 +0,0 @@
-/* Bt832 CMOS Camera Video Processor (VP)
-
- The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS
- color digital camera directly to video capture devices via an 8-bit,
- 4:2:2 YUV or YCrCb video interface.
-
- i2c addresses: 0x88 or 0x8a
- */
-
-/* The 64 registers: */
-
-// Input Processor
-#define BT832_OFFSET 0
-#define BT832_RCOMP 1
-#define BT832_G1COMP 2
-#define BT832_G2COMP 3
-#define BT832_BCOMP 4
-// Exposures:
-#define BT832_FINEH 5
-#define BT832_FINEL 6
-#define BT832_COARSEH 7
-#define BT832_COARSEL 8
-#define BT832_CAMGAIN 9
-// Main Processor:
-#define BT832_M00 10
-#define BT832_M01 11
-#define BT832_M02 12
-#define BT832_M10 13
-#define BT832_M11 14
-#define BT832_M12 15
-#define BT832_M20 16
-#define BT832_M21 17
-#define BT832_M22 18
-#define BT832_APCOR 19
-#define BT832_GAMCOR 20
-// Level Accumulator Inputs
-#define BT832_VPCONTROL2 21
-#define BT832_ZONECODE0 22
-#define BT832_ZONECODE1 23
-#define BT832_ZONECODE2 24
-#define BT832_ZONECODE3 25
-// Level Accumulator Outputs:
-#define BT832_RACC 26
-#define BT832_GACC 27
-#define BT832_BACC 28
-#define BT832_BLACKACC 29
-#define BT832_EXP_AGC 30
-#define BT832_LACC0 31
-#define BT832_LACC1 32
-#define BT832_LACC2 33
-#define BT832_LACC3 34
-#define BT832_LACC4 35
-#define BT832_LACC5 36
-#define BT832_LACC6 37
-#define BT832_LACC7 38
-// System:
-#define BT832_VP_CONTROL0 39
-#define BT832_VP_CONTROL1 40
-#define BT832_THRESH 41
-#define BT832_VP_TESTCONTROL0 42
-#define BT832_VP_DMCODE 43
-#define BT832_ACB_CONFIG 44
-#define BT832_ACB_GNBASE 45
-#define BT832_ACB_MU 46
-#define BT832_CAM_TEST0 47
-#define BT832_AEC_CONFIG 48
-#define BT832_AEC_TL 49
-#define BT832_AEC_TC 50
-#define BT832_AEC_TH 51
-// Status:
-#define BT832_VP_STATUS 52
-#define BT832_VP_LINECOUNT 53
-#define BT832_CAM_DEVICEL 54 // e.g. 0x19
-#define BT832_CAM_DEVICEH 55 // e.g. 0x40 == 0x194 Mask0, 0x194 = 404 decimal (VVL-404 camera)
-#define BT832_CAM_STATUS 56
- #define BT832_56_CAMERA_PRESENT 0x20
-//Camera Setups:
-#define BT832_CAM_SETUP0 57
-#define BT832_CAM_SETUP1 58
-#define BT832_CAM_SETUP2 59
-#define BT832_CAM_SETUP3 60
-// System:
-#define BT832_DEFCOR 61
-#define BT832_VP_TESTCONTROL1 62
-#define BT832_DEVICE_ID 63
-# define BT832_DEVICE_ID__31 0x31 // Bt832 has ID 0x31
-
-/* STMicroelectronivcs VV5404 camera module
- i2c: 0x20: sensor address
- i2c: 0xa0: eeprom for ccd defect map
- */
-#define VV5404_device_h 0x00 // 0x19
-#define VV5404_device_l 0x01 // 0x40
-#define VV5404_status0 0x02
-#define VV5404_linecountc 0x03 // current line counter
-#define VV5404_linecountl 0x04
-#define VV5404_setup0 0x10
-#define VV5404_setup1 0x11
-#define VV5404_setup2 0x12
-#define VV5404_setup4 0x14
-#define VV5404_setup5 0x15
-#define VV5404_fine_h 0x20 // fine exposure
-#define VV5404_fine_l 0x21
-#define VV5404_coarse_h 0x22 //coarse exposure
-#define VV5404_coarse_l 0x23
-#define VV5404_gain 0x24 // ADC pre-amp gain setting
-#define VV5404_clk_div 0x25
-#define VV5404_cr 0x76 // control register
-#define VV5404_as0 0x77 // ADC setup register
-
-
-// IOCTL
-#define BT832_HEXDUMP _IOR('b',1,int)
-#define BT832_REATTACH _IOR('b',2,int)
-
-/* from BT8x8VXD/capdrv/dialogs.cpp */
-
-/*
-typedef enum { SVI, Logitech, Rockwell } CAMERA;
-
-static COMBOBOX_ENTRY gwCameraOptions[] =
-{
- { SVI, "Silicon Vision 512N" },
- { Logitech, "Logitech VideoMan 1.3" },
- { Rockwell, "Rockwell QuartzSight PCI 1.0" }
-};
-
-// SRAM table values
-//===========================================================================
-typedef enum { TGB_NTSC624, TGB_NTSC780, TGB_NTSC858, TGB_NTSC392 } TimeGenByte;
-
-BYTE SRAMTable[][ 60 ] =
-{
- // TGB_NTSC624
- {
- 0x33, // size of table = 51
- 0x0E, 0xC0, 0x00, 0x00, 0x90, 0x02, 0x03, 0x10, 0x03, 0x06,
- 0x10, 0x04, 0x12, 0x12, 0x05, 0x02, 0x13, 0x04, 0x19, 0x00,
- 0x04, 0x39, 0x00, 0x06, 0x59, 0x08, 0x03, 0x85, 0x08, 0x07,
- 0x03, 0x50, 0x00, 0x91, 0x40, 0x00, 0x11, 0x01, 0x01, 0x4D,
- 0x0D, 0x02, 0x03, 0x11, 0x01, 0x05, 0x37, 0x00, 0x37, 0x21, 0x00
- },
- // TGB_NTSC780
- {
- 0x33, // size of table = 51
- 0x0e, 0xc0, 0x00, 0x00, 0x90, 0xe2, 0x03, 0x10, 0x03, 0x06,
- 0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
- 0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x85, 0x08, 0x97,
- 0x03, 0x50, 0x50, 0xaf, 0x40, 0x30, 0x5f, 0x01, 0xf1, 0x7f,
- 0x0d, 0xf2, 0x03, 0x11, 0xf1, 0x05, 0x37, 0x30, 0x85, 0x21, 0x50
- },
- // TGB_NTSC858
- {
- 0x33, // size of table = 51
- 0x0c, 0xc0, 0x00, 0x00, 0x90, 0xc2, 0x03, 0x10, 0x03, 0x06,
- 0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
- 0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x83, 0x08, 0x97,
- 0x03, 0x50, 0x30, 0xc0, 0x40, 0x30, 0x86, 0x01, 0x01, 0xa6,
- 0x0d, 0x62, 0x03, 0x11, 0x61, 0x05, 0x37, 0x30, 0xac, 0x21, 0x50
- },
- // TGB_NTSC392
- // This table has been modified to be used for Fusion Rev D
- {
- 0x2A, // size of table = 42
- 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
- 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
- 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
- 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
- 0x20, 0x00
- }
-};
-
-//===========================================================================
-// This is the structure of the camera specifications
-//===========================================================================
-typedef struct tag_cameraSpec
-{
- SignalFormat signal; // which digital signal format the camera has
- VideoFormat vidFormat; // video standard
- SyncVideoRef syncRef; // which sync video reference is used
- State syncOutput; // enable sync output for sync video input?
- DecInputClk iClk; // which input clock is used
- TimeGenByte tgb; // which timing generator byte does the camera use
- int HReset; // select 64, 48, 32, or 16 CLKx1 for HReset
- PLLFreq pllFreq; // what synthesized frequency to set PLL to
- VSIZEPARMS vSize; // video size the camera produces
- int lineCount; // expected total number of half-line per frame - 1
- BOOL interlace; // interlace signal?
-} CameraSpec;
-
-//===========================================================================
-// <UPDATE REQUIRED>
-// Camera specifications database. Update this table whenever camera spec
-// has been changed or added/deleted supported camera models
-//===========================================================================
-static CameraSpec dbCameraSpec[ N_CAMERAOPTIONS ] =
-{ // Silicon Vision 512N
- { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC624, 64, KHz19636,
- // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
- { 512, 0x64, 480, 0x13, 240 }, 0, TRUE
- },
- // Logitech VideoMan 1.3
- { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC780, 64, KHz24545,
- // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
- { 640, 0x80, 480, 0x1A, 240 }, 0, TRUE
- },
- // Rockwell QuartzSight
- // Note: Fusion Rev D (rev ID 0x02) and later supports 16 pixels for HReset which is preferable.
- // Use 32 for earlier version of hardware. Clkx1_HDELAY also changed from 0x27 to 0x20.
- { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC392, 16, KHz28636,
- // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
- { 352, 0x20, 576, 0x08, 288 }, 607, FALSE
- }
-};
-*/
-
-/*
-The corresponding APIs required to be invoked are:
-SetConnector( ConCamera, TRUE/FALSE );
-SetSignalFormat( spec.signal );
-SetVideoFormat( spec.vidFormat );
-SetSyncVideoRef( spec.syncRef );
-SetEnableSyncOutput( spec.syncOutput );
-SetTimGenByte( SRAMTable[ spec.tgb ], SRAMTableSize[ spec.tgb ] );
-SetHReset( spec.HReset );
-SetPLL( spec.pllFreq );
-SetDecInputClock( spec.iClk );
-SetVideoInfo( spec.vSize );
-SetTotalLineCount( spec.lineCount );
-SetInterlaceMode( spec.interlace );
-*/
-
-/* from web:
- Video Sampling
-Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
- Pixel Clock Horiz Horiz Vert
- Rate Total Active
-NTSC square pixel 12.27 MHz 780 640 525
-NTSC CCIR-601 13.5 MHz 858 720 525
-NTSC 4FSc 14.32 MHz 910 768 525
-PAL square pixel 14.75 MHz 944 768 625
-PAL CCIR-601 13.5 MHz 864 720 625
-PAL 4FSc 17.72 MHz 1135 948 625
-
-For the CCIR-601 standards, the sampling is based on a static orthogonal sampling grid. The luminance component (Y) is sampled at 13.5 MHz, while the two color difference signals, Cr and Cb are sampled at half that, or 6.75 MHz. The Cr and Cb samples are colocated with alternate Y samples, and they are taken at the same position on each line, such that one sample is coincident with the 50% point of the falling edge of analog sync. The samples are coded to either 8 or 10 bits per component.
-*/
-
-/* from DScaler:*/
-/*
-//===========================================================================
-// CCIR656 Digital Input Support: The tables were taken from DScaler proyect
-//
-// 13 Dec 2000 - Michael Eskin, Conexant Systems - Initial version
-//
-
-//===========================================================================
-// Timing generator SRAM table values for CCIR601 720x480 NTSC
-//===========================================================================
-// For NTSC CCIR656
-BYTE BtCard::SRAMTable_NTSC[] =
-{
- // SRAM Timing Table for NTSC
- 0x0c, 0xc0, 0x00,
- 0x00, 0x90, 0xc2,
- 0x03, 0x10, 0x03,
- 0x06, 0x10, 0x34,
- 0x12, 0x12, 0x65,
- 0x02, 0x13, 0x24,
- 0x19, 0x00, 0x24,
- 0x39, 0x00, 0x96,
- 0x59, 0x08, 0x93,
- 0x83, 0x08, 0x97,
- 0x03, 0x50, 0x30,
- 0xc0, 0x40, 0x30,
- 0x86, 0x01, 0x01,
- 0xa6, 0x0d, 0x62,
- 0x03, 0x11, 0x61,
- 0x05, 0x37, 0x30,
- 0xac, 0x21, 0x50
-};
-
-//===========================================================================
-// Timing generator SRAM table values for CCIR601 720x576 NTSC
-//===========================================================================
-// For PAL CCIR656
-BYTE BtCard::SRAMTable_PAL[] =
-{
- // SRAM Timing Table for PAL
- 0x36, 0x11, 0x01,
- 0x00, 0x90, 0x02,
- 0x05, 0x10, 0x04,
- 0x16, 0x14, 0x05,
- 0x11, 0x00, 0x04,
- 0x12, 0xc0, 0x00,
- 0x31, 0x00, 0x06,
- 0x51, 0x08, 0x03,
- 0x89, 0x08, 0x07,
- 0xc0, 0x44, 0x00,
- 0x81, 0x01, 0x01,
- 0xa9, 0x0d, 0x02,
- 0x02, 0x50, 0x03,
- 0x37, 0x3d, 0x00,
- 0xaf, 0x21, 0x00,
-};
-*/
diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c
index a00228893..aea093419 100644
--- a/linux/drivers/media/video/bt8xx/bttv-cards.c
+++ b/linux/drivers/media/video/bt8xx/bttv-cards.c
@@ -41,14 +41,10 @@
#include "bttvp.h"
#include <media/v4l2-common.h>
#include <media/tvaudio.h>
-#if 0 /* not working yet */
-#include "bt832.h"
-#endif
#include "bttv-audio-hook.h"
/* fwd decl */
static void boot_msp34xx(struct bttv *btv, int pin);
-static void boot_bt832(struct bttv *btv);
static void hauppauge_eeprom(struct bttv *btv);
static void avermedia_eeprom(struct bttv *btv);
static void osprey_eeprom(struct bttv *btv, const u8 ee[256]);
@@ -3762,13 +3758,6 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (bttv_tvcards[btv->c.type].audio_mode_gpio)
btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
- if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) {
- /* detect Bt832 chip for quartzsight digital camera */
- if ((bttv_I2CRead(btv, I2C_ADDR_BT832_ALT1, "Bt832") >=0) ||
- (bttv_I2CRead(btv, I2C_ADDR_BT832_ALT2, "Bt832") >=0))
- boot_bt832(btv);
- }
-
if (!autoload)
return;
@@ -4172,40 +4161,6 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin)
"init [%d]\n", btv->c.nr, pin);
}
-static void __devinit boot_bt832(struct bttv *btv)
-{
-#if 0 /* not working yet */
- int resetbit=0;
-
- switch (btv->c.type) {
- case BTTV_BOARD_PXELVWPLTVPAK:
- resetbit = 0x400000;
- break;
- case BTTV_BOARD_MODTEC_205:
- resetbit = 1<<9;
- break;
- default:
- BUG();
- }
-
- request_module("bt832");
- bttv_call_i2c_clients(btv, BT832_HEXDUMP, NULL);
-
- printk("bttv%d: Reset Bt832 [line=0x%x]\n",btv->c.nr,resetbit);
- gpio_write(0);
- gpio_inout(resetbit, resetbit);
- udelay(5);
- gpio_bits(resetbit, resetbit);
- udelay(5);
- gpio_bits(resetbit, 0);
- udelay(5);
-
- /* bt832 on pixelview changes from i2c 0x8a to 0x88 after
- * being reset as above. So we must follow by this: */
- bttv_call_i2c_clients(btv, BT832_REATTACH, NULL);
-#endif
-}
-
/* ----------------------------------------------------------------------- */
/* Imagenation L-Model PXC200 Framegrabber */
/* This is basically the same procedure as
diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c
index e398de6c1..690e09b91 100644
--- a/linux/drivers/media/video/bt8xx/bttv-driver.c
+++ b/linux/drivers/media/video/bt8xx/bttv-driver.c
@@ -2067,7 +2067,7 @@ static int bttv_log_status(struct file *file, void *f)
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int bttv_g_register(struct file *file, void *f,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
@@ -2075,18 +2075,19 @@ static int bttv_g_register(struct file *file, void *f,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
/* bt848 has a 12-bit register space */
reg->reg &= 0xfff;
reg->val = btread(reg->reg);
+ reg->size = 1;
return 0;
}
static int bttv_s_register(struct file *file, void *f,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
@@ -2094,7 +2095,7 @@ static int bttv_s_register(struct file *file, void *f,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
/* bt848 has a 12-bit register space */
@@ -3236,9 +3237,9 @@ err:
return POLLERR;
}
-static int bttv_open(struct inode *inode, struct file *file)
+static int bttv_open(struct file *file)
{
- int minor = iminor(inode);
+ int minor = video_devdata(file)->minor;
struct bttv *btv = NULL;
struct bttv_fh *fh;
enum v4l2_buf_type type = 0;
@@ -3319,7 +3320,7 @@ static int bttv_open(struct inode *inode, struct file *file)
return 0;
}
-static int bttv_release(struct inode *inode, struct file *file)
+static int bttv_release(struct file *file)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
@@ -3374,14 +3375,12 @@ bttv_mmap(struct file *file, struct vm_area_struct *vma)
return videobuf_mmap_mapper(bttv_queue(fh),vma);
}
-static const struct file_operations bttv_fops =
+static const struct v4l2_file_operations bttv_fops =
{
.owner = THIS_MODULE,
.open = bttv_open,
.release = bttv_release,
.ioctl = video_ioctl2,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
.read = bttv_read,
.mmap = bttv_mmap,
.poll = bttv_poll,
@@ -3450,9 +3449,9 @@ static struct video_device bttv_video_template = {
/* ----------------------------------------------------------------------- */
/* radio interface */
-static int radio_open(struct inode *inode, struct file *file)
+static int radio_open(struct file *file)
{
- int minor = iminor(inode);
+ int minor = video_devdata(file)->minor;
struct bttv *btv = NULL;
struct bttv_fh *fh;
unsigned int i;
@@ -3495,7 +3494,7 @@ static int radio_open(struct inode *inode, struct file *file)
return 0;
}
-static int radio_release(struct inode *inode, struct file *file)
+static int radio_release(struct file *file)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
@@ -3661,15 +3660,13 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
return cmd.result;
}
-static const struct file_operations radio_fops =
+static const struct v4l2_file_operations radio_fops =
{
.owner = THIS_MODULE,
.open = radio_open,
.read = radio_read,
.release = radio_release,
- .compat_ioctl = v4l_compat_ioctl32,
.ioctl = video_ioctl2,
- .llseek = no_llseek,
.poll = radio_poll,
};
diff --git a/linux/drivers/media/video/bt8xx/bttv-i2c.c b/linux/drivers/media/video/bt8xx/bttv-i2c.c
index bcd2cd240..558572589 100644
--- a/linux/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/linux/drivers/media/video/bt8xx/bttv-i2c.c
@@ -260,6 +260,9 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int
static const struct i2c_algorithm bttv_algo = {
.master_xfer = bttv_i2c_xfer,
.functionality = functionality,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
/* ----------------------------------------------------------------------- */
diff --git a/linux/drivers/media/video/bw-qcam.c b/linux/drivers/media/video/bw-qcam.c
index e534eaf39..3702baad6 100644
--- a/linux/drivers/media/video/bw-qcam.c
+++ b/linux/drivers/media/video/bw-qcam.c
@@ -707,7 +707,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
* Video4linux interfacing
*/
-static int qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *dev = video_devdata(file);
struct qcam_device *qcam=(struct qcam_device *)dev;
@@ -864,7 +864,7 @@ static int qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0;
}
-static int qcam_ioctl(struct inode *inode, struct file *file,
+static long qcam_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, qcam_do_ioctl);
@@ -894,7 +894,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
return len;
}
-static int qcam_exclusive_open(struct inode *inode, struct file *file)
+static int qcam_exclusive_open(struct file *file)
{
struct video_device *dev = video_devdata(file);
struct qcam_device *qcam = (struct qcam_device *)dev;
@@ -902,7 +902,7 @@ static int qcam_exclusive_open(struct inode *inode, struct file *file)
return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
}
-static int qcam_exclusive_release(struct inode *inode, struct file *file)
+static int qcam_exclusive_release(struct file *file)
{
struct video_device *dev = video_devdata(file);
struct qcam_device *qcam = (struct qcam_device *)dev;
@@ -911,16 +911,12 @@ static int qcam_exclusive_release(struct inode *inode, struct file *file)
return 0;
}
-static const struct file_operations qcam_fops = {
+static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
.open = qcam_exclusive_open,
.release = qcam_exclusive_release,
.ioctl = qcam_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
.read = qcam_read,
- .llseek = no_llseek,
};
static struct video_device qcam_template=
{
diff --git a/linux/drivers/media/video/c-qcam.c b/linux/drivers/media/video/c-qcam.c
index bdad822a5..abb873fc6 100644
--- a/linux/drivers/media/video/c-qcam.c
+++ b/linux/drivers/media/video/c-qcam.c
@@ -501,7 +501,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
* Video4linux interfacing
*/
-static int qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *dev = video_devdata(file);
struct qcam_device *qcam=(struct qcam_device *)dev;
@@ -666,7 +666,7 @@ static int qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0;
}
-static int qcam_ioctl(struct inode *inode, struct file *file,
+static long qcam_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, qcam_do_ioctl);
@@ -688,7 +688,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
return len;
}
-static int qcam_exclusive_open(struct inode *inode, struct file *file)
+static int qcam_exclusive_open(struct file *file)
{
struct video_device *dev = video_devdata(file);
struct qcam_device *qcam = (struct qcam_device *)dev;
@@ -696,7 +696,7 @@ static int qcam_exclusive_open(struct inode *inode, struct file *file)
return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
}
-static int qcam_exclusive_release(struct inode *inode, struct file *file)
+static int qcam_exclusive_release(struct file *file)
{
struct video_device *dev = video_devdata(file);
struct qcam_device *qcam = (struct qcam_device *)dev;
@@ -706,16 +706,12 @@ static int qcam_exclusive_release(struct inode *inode, struct file *file)
}
/* video device template */
-static const struct file_operations qcam_fops = {
+static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
.open = qcam_exclusive_open,
.release = qcam_exclusive_release,
.ioctl = qcam_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
.read = qcam_read,
- .llseek = no_llseek,
};
static struct video_device qcam_template=
diff --git a/linux/drivers/media/video/cafe_ccic.c b/linux/drivers/media/video/cafe_ccic.c
index 1184b9186..bb8959386 100644
--- a/linux/drivers/media/video/cafe_ccic.c
+++ b/linux/drivers/media/video/cafe_ccic.c
@@ -866,7 +866,7 @@ static int __cafe_cam_reset(struct cafe_camera *cam)
*/
static int cafe_cam_init(struct cafe_camera *cam)
{
- struct v4l2_chip_ident chip = { V4L2_CHIP_MATCH_I2C_ADDR, 0, 0, 0 };
+ struct v4l2_dbg_chip_ident chip;
int ret;
mutex_lock(&cam->s_mutex);
@@ -876,8 +876,9 @@ static int cafe_cam_init(struct cafe_camera *cam)
ret = __cafe_cam_reset(cam);
if (ret)
goto out;
- chip.match_chip = cam->sensor->addr;
- ret = __cafe_cam_cmd(cam, VIDIOC_G_CHIP_IDENT, &chip);
+ chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR;
+ chip.match.addr = cam->sensor->addr;
+ ret = __cafe_cam_cmd(cam, VIDIOC_DBG_G_CHIP_IDENT, &chip);
if (ret)
goto out;
cam->sensor_type = chip.ident;
@@ -1479,11 +1480,11 @@ static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
-static int cafe_v4l_open(struct inode *inode, struct file *filp)
+static int cafe_v4l_open(struct file *filp)
{
struct cafe_camera *cam;
- cam = cafe_find_dev(iminor(inode));
+ cam = cafe_find_dev(video_devdata(filp)->minor);
if (cam == NULL)
return -ENODEV;
filp->private_data = cam;
@@ -1501,7 +1502,7 @@ static int cafe_v4l_open(struct inode *inode, struct file *filp)
}
-static int cafe_v4l_release(struct inode *inode, struct file *filp)
+static int cafe_v4l_release(struct file *filp)
{
struct cafe_camera *cam = filp->private_data;
@@ -1766,7 +1767,7 @@ static void cafe_v4l_dev_release(struct video_device *vd)
* clone it for specific real devices.
*/
-static const struct file_operations cafe_v4l_fops = {
+static const struct v4l2_file_operations cafe_v4l_fops = {
.owner = THIS_MODULE,
.open = cafe_v4l_open,
.release = cafe_v4l_release,
@@ -1774,7 +1775,6 @@ static const struct file_operations cafe_v4l_fops = {
.poll = cafe_v4l_poll,
.mmap = cafe_v4l_mmap,
.ioctl = video_ioctl2,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
diff --git a/linux/drivers/media/video/cpia.c b/linux/drivers/media/video/cpia.c
index 004f36928..9baa70fc9 100644
--- a/linux/drivers/media/video/cpia.c
+++ b/linux/drivers/media/video/cpia.c
@@ -3149,7 +3149,7 @@ static void put_cam(struct cpia_camera_ops* ops)
}
/* ------------------------- V4L interface --------------------- */
-static int cpia_open(struct inode *inode, struct file *file)
+static int cpia_open(struct file *file)
{
struct video_device *dev = video_devdata(file);
struct cam_data *cam = video_get_drvdata(dev);
@@ -3226,7 +3226,7 @@ static int cpia_open(struct inode *inode, struct file *file)
return err;
}
-static int cpia_close(struct inode *inode, struct file *file)
+static int cpia_close(struct file *file)
{
struct video_device *dev = file->private_data;
struct cam_data *cam = video_get_drvdata(dev);
@@ -3334,7 +3334,7 @@ static ssize_t cpia_read(struct file *file, char __user *buf,
return cam->decompressed_frame.count;
}
-static int cpia_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long cpia_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *dev = file->private_data;
struct cam_data *cam = video_get_drvdata(dev);
@@ -3721,7 +3721,7 @@ static int cpia_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return retval;
}
-static int cpia_ioctl(struct inode *inode, struct file *file,
+static long cpia_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, cpia_do_ioctl);
@@ -3781,17 +3781,13 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-static const struct file_operations cpia_fops = {
+static const struct v4l2_file_operations cpia_fops = {
.owner = THIS_MODULE,
.open = cpia_open,
.release = cpia_close,
.read = cpia_read,
.mmap = cpia_mmap,
.ioctl = cpia_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static struct video_device cpia_template = {
diff --git a/linux/drivers/media/video/cpia2/cpia2_v4l.c b/linux/drivers/media/video/cpia2/cpia2_v4l.c
index 3c2d7eac1..9c25894fd 100644
--- a/linux/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/linux/drivers/media/video/cpia2/cpia2_v4l.c
@@ -239,7 +239,7 @@ static struct v4l2_queryctrl controls[] = {
* cpia2_open
*
*****************************************************************************/
-static int cpia2_open(struct inode *inode, struct file *file)
+static int cpia2_open(struct file *file)
{
struct camera_data *cam = video_drvdata(file);
int retval = 0;
@@ -302,7 +302,7 @@ err_return:
* cpia2_close
*
*****************************************************************************/
-static int cpia2_close(struct inode *inode, struct file *file)
+static int cpia2_close(struct file *file)
{
struct video_device *dev = video_devdata(file);
struct camera_data *cam = video_get_drvdata(dev);
@@ -1572,10 +1572,10 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
* cpia2_ioctl
*
*****************************************************************************/
-static int cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct camera_data *cam = video_drvdata(file);
- int retval = 0;
+ long retval = 0;
if (!cam)
return -ENOTTY;
@@ -1841,7 +1841,7 @@ static int cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return retval;
}
-static int cpia2_ioctl(struct inode *inode, struct file *file,
+static long cpia2_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, cpia2_do_ioctl);
@@ -1912,17 +1912,13 @@ static void reset_camera_struct_v4l(struct camera_data *cam)
/***
* The v4l video device structure initialized for this device
***/
-static const struct file_operations fops_template = {
+static const struct v4l2_file_operations fops_template = {
.owner = THIS_MODULE,
.open = cpia2_open,
.release = cpia2_close,
.read = cpia2_v4l_read,
.poll = cpia2_v4l_poll,
.ioctl = cpia2_ioctl,
- .llseek = no_llseek,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
.mmap = cpia2_mmap,
};
diff --git a/linux/drivers/media/video/cs5345.c b/linux/drivers/media/video/cs5345.c
index decbc5f1f..9d19970ce 100644
--- a/linux/drivers/media/video/cs5345.c
+++ b/linux/drivers/media/video/cs5345.c
@@ -23,9 +23,9 @@
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
-#include <media/v4l2-i2c-drv.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
#include "compat.h"
MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
@@ -46,111 +46,142 @@ I2C_CLIENT_INSMOD;
/* ----------------------------------------------------------------------- */
-static inline int cs5345_write(struct i2c_client *client, u8 reg, u8 value)
+static inline int cs5345_write(struct v4l2_subdev *sd, u8 reg, u8 value)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
return i2c_smbus_write_byte_data(client, reg, value);
}
-static inline int cs5345_read(struct i2c_client *client, u8 reg)
+static inline int cs5345_read(struct v4l2_subdev *sd, u8 reg)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
return i2c_smbus_read_byte_data(client, reg);
}
-static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int cs5345_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
{
- struct v4l2_routing *route = arg;
- struct v4l2_control *ctrl = arg;
-
- switch (cmd) {
- case VIDIOC_INT_G_AUDIO_ROUTING:
- route->input = cs5345_read(client, 0x09) & 7;
- route->input |= cs5345_read(client, 0x05) & 0x70;
- route->output = 0;
- break;
-
- case VIDIOC_INT_S_AUDIO_ROUTING:
- if ((route->input & 0xf) > 6) {
- v4l_err(client, "Invalid input %d.\n", route->input);
- return -EINVAL;
- }
- cs5345_write(client, 0x09, route->input & 0xf);
- cs5345_write(client, 0x05, route->input & 0xf0);
- break;
-
- case VIDIOC_G_CTRL:
- if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
- ctrl->value = (cs5345_read(client, 0x04) & 0x08) != 0;
- break;
- }
- if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
- return -EINVAL;
- ctrl->value = cs5345_read(client, 0x07) & 0x3f;
- if (ctrl->value >= 32)
- ctrl->value = ctrl->value - 64;
- break;
-
- case VIDIOC_S_CTRL:
- break;
- if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
- cs5345_write(client, 0x04, ctrl->value ? 0x80 : 0);
- break;
- }
- if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
- return -EINVAL;
- if (ctrl->value > 24 || ctrl->value < -24)
- return -EINVAL;
- cs5345_write(client, 0x07, ((u8)ctrl->value) & 0x3f);
- cs5345_write(client, 0x08, ((u8)ctrl->value) & 0x3f);
- break;
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (!v4l2_chip_match_i2c_client(client,
- reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (cmd == VIDIOC_DBG_G_REGISTER)
- reg->val = cs5345_read(client, reg->reg & 0x1f);
- else
- cs5345_write(client, reg->reg & 0x1f, reg->val & 0xff);
- break;
+ if ((route->input & 0xf) > 6) {
+ v4l2_err(sd, "Invalid input %d.\n", route->input);
+ return -EINVAL;
}
-#endif
+ cs5345_write(sd, 0x09, route->input & 0xf);
+ cs5345_write(sd, 0x05, route->input & 0xf0);
+ return 0;
+}
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client,
- arg, V4L2_IDENT_CS5345, 0);
-
- case VIDIOC_LOG_STATUS:
- {
- u8 v = cs5345_read(client, 0x09) & 7;
- u8 m = cs5345_read(client, 0x04);
- int vol = cs5345_read(client, 0x08) & 0x3f;
-
- v4l_info(client, "Input: %d%s\n", v,
- (m & 0x80) ? " (muted)" : "");
- if (vol >= 32)
- vol = vol - 64;
- v4l_info(client, "Volume: %d dB\n", vol);
- break;
- }
-
- default:
+static int cs5345_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+ ctrl->value = (cs5345_read(sd, 0x04) & 0x08) != 0;
+ return 0;
+ }
+ if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
return -EINVAL;
+ ctrl->value = cs5345_read(sd, 0x07) & 0x3f;
+ if (ctrl->value >= 32)
+ ctrl->value = ctrl->value - 64;
+ return 0;
+}
+
+static int cs5345_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+ cs5345_write(sd, 0x04, ctrl->value ? 0x80 : 0);
+ return 0;
}
+ if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+ return -EINVAL;
+ if (ctrl->value > 24 || ctrl->value < -24)
+ return -EINVAL;
+ cs5345_write(sd, 0x07, ((u8)ctrl->value) & 0x3f);
+ cs5345_write(sd, 0x08, ((u8)ctrl->value) & 0x3f);
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->size = 1;
+ reg->val = cs5345_read(sd, reg->reg & 0x1f);
+ return 0;
+}
+
+static int cs5345_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ cs5345_write(sd, reg->reg & 0x1f, reg->val & 0xff);
return 0;
}
+#endif
+
+static int cs5345_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_CS5345, 0);
+}
+
+static int cs5345_log_status(struct v4l2_subdev *sd)
+{
+ u8 v = cs5345_read(sd, 0x09) & 7;
+ u8 m = cs5345_read(sd, 0x04);
+ int vol = cs5345_read(sd, 0x08) & 0x3f;
+
+ v4l2_info(sd, "Input: %d%s\n", v,
+ (m & 0x80) ? " (muted)" : "");
+ if (vol >= 32)
+ vol = vol - 64;
+ v4l2_info(sd, "Volume: %d dB\n", vol);
+ return 0;
+}
+
+static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops cs5345_core_ops = {
+ .log_status = cs5345_log_status,
+ .g_chip_ident = cs5345_g_chip_ident,
+ .g_ctrl = cs5345_g_ctrl,
+ .s_ctrl = cs5345_s_ctrl,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = cs5345_g_register,
+ .s_register = cs5345_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_audio_ops cs5345_audio_ops = {
+ .s_routing = cs5345_s_routing,
+};
+
+static const struct v4l2_subdev_ops cs5345_ops = {
+ .core = &cs5345_core_ops,
+ .audio = &cs5345_audio_ops,
+};
/* ----------------------------------------------------------------------- */
static int cs5345_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct v4l2_subdev *sd;
+
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
@@ -158,9 +189,25 @@ static int cs5345_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- cs5345_write(client, 0x02, 0x00);
- cs5345_write(client, 0x04, 0x01);
- cs5345_write(client, 0x09, 0x01);
+ sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (sd == NULL)
+ return -ENOMEM;
+ v4l2_i2c_subdev_init(sd, client, &cs5345_ops);
+
+ cs5345_write(sd, 0x02, 0x00);
+ cs5345_write(sd, 0x04, 0x01);
+ cs5345_write(sd, 0x09, 0x01);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cs5345_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(sd);
return 0;
}
@@ -179,6 +226,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.driverid = I2C_DRIVERID_CS5345,
.command = cs5345_command,
.probe = cs5345_probe,
+ .remove = cs5345_remove,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
.id_table = cs5345_id,
#endif
diff --git a/linux/drivers/media/video/cs53l32a.c b/linux/drivers/media/video/cs53l32a.c
index 68f31270c..842a8e4ed 100644
--- a/linux/drivers/media/video/cs53l32a.c
+++ b/linux/drivers/media/video/cs53l32a.c
@@ -27,7 +27,7 @@
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include "compat.h"
@@ -48,84 +48,104 @@ I2C_CLIENT_INSMOD;
/* ----------------------------------------------------------------------- */
-static int cs53l32a_write(struct i2c_client *client, u8 reg, u8 value)
+static int cs53l32a_write(struct v4l2_subdev *sd, u8 reg, u8 value)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
return i2c_smbus_write_byte_data(client, reg, value);
}
-static int cs53l32a_read(struct i2c_client *client, u8 reg)
+static int cs53l32a_read(struct v4l2_subdev *sd, u8 reg)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
return i2c_smbus_read_byte_data(client, reg);
}
-static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int cs53l32a_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
{
- struct v4l2_routing *route = arg;
- struct v4l2_control *ctrl = arg;
-
- switch (cmd) {
- case VIDIOC_INT_G_AUDIO_ROUTING:
- route->input = (cs53l32a_read(client, 0x01) >> 4) & 3;
- route->output = 0;
- break;
-
- case VIDIOC_INT_S_AUDIO_ROUTING:
- /* There are 2 physical inputs, but the second input can be
- placed in two modes, the first mode bypasses the PGA (gain),
- the second goes through the PGA. Hence there are three
- possible inputs to choose from. */
- if (route->input > 2) {
- v4l_err(client, "Invalid input %d.\n", route->input);
- return -EINVAL;
- }
- cs53l32a_write(client, 0x01, 0x01 + (route->input << 4));
- break;
-
- case VIDIOC_G_CTRL:
- if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
- ctrl->value = (cs53l32a_read(client, 0x03) & 0xc0) != 0;
- break;
- }
- if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
- return -EINVAL;
- ctrl->value = (s8)cs53l32a_read(client, 0x04);
- break;
-
- case VIDIOC_S_CTRL:
- if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
- cs53l32a_write(client, 0x03, ctrl->value ? 0xf0 : 0x30);
- break;
- }
- if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
- return -EINVAL;
- if (ctrl->value > 12 || ctrl->value < -96)
- return -EINVAL;
- cs53l32a_write(client, 0x04, (u8) ctrl->value);
- cs53l32a_write(client, 0x05, (u8) ctrl->value);
- break;
-
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client,
- arg, V4L2_IDENT_CS53l32A, 0);
-
- case VIDIOC_LOG_STATUS:
- {
- u8 v = cs53l32a_read(client, 0x01);
- u8 m = cs53l32a_read(client, 0x03);
- s8 vol = cs53l32a_read(client, 0x04);
-
- v4l_info(client, "Input: %d%s\n", (v >> 4) & 3,
- (m & 0xC0) ? " (muted)" : "");
- v4l_info(client, "Volume: %d dB\n", vol);
- break;
- }
-
- default:
+ /* There are 2 physical inputs, but the second input can be
+ placed in two modes, the first mode bypasses the PGA (gain),
+ the second goes through the PGA. Hence there are three
+ possible inputs to choose from. */
+ if (route->input > 2) {
+ v4l2_err(sd, "Invalid input %d.\n", route->input);
return -EINVAL;
}
+ cs53l32a_write(sd, 0x01, 0x01 + (route->input << 4));
+ return 0;
+}
+
+static int cs53l32a_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+ ctrl->value = (cs53l32a_read(sd, 0x03) & 0xc0) != 0;
+ return 0;
+ }
+ if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+ return -EINVAL;
+ ctrl->value = (s8)cs53l32a_read(sd, 0x04);
+ return 0;
+}
+
+static int cs53l32a_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+ cs53l32a_write(sd, 0x03, ctrl->value ? 0xf0 : 0x30);
+ return 0;
+ }
+ if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+ return -EINVAL;
+ if (ctrl->value > 12 || ctrl->value < -96)
+ return -EINVAL;
+ cs53l32a_write(sd, 0x04, (u8) ctrl->value);
+ cs53l32a_write(sd, 0x05, (u8) ctrl->value);
return 0;
}
+static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client,
+ chip, V4L2_IDENT_CS53l32A, 0);
+}
+
+static int cs53l32a_log_status(struct v4l2_subdev *sd)
+{
+ u8 v = cs53l32a_read(sd, 0x01);
+ u8 m = cs53l32a_read(sd, 0x03);
+ s8 vol = cs53l32a_read(sd, 0x04);
+
+ v4l2_info(sd, "Input: %d%s\n", (v >> 4) & 3,
+ (m & 0xC0) ? " (muted)" : "");
+ v4l2_info(sd, "Volume: %d dB\n", vol);
+ return 0;
+}
+
+static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {
+ .log_status = cs53l32a_log_status,
+ .g_chip_ident = cs53l32a_g_chip_ident,
+ .g_ctrl = cs53l32a_g_ctrl,
+ .s_ctrl = cs53l32a_s_ctrl,
+};
+
+static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = {
+ .s_routing = cs53l32a_s_routing,
+};
+
+static const struct v4l2_subdev_ops cs53l32a_ops = {
+ .core = &cs53l32a_core_ops,
+ .audio = &cs53l32a_audio_ops,
+};
+
/* ----------------------------------------------------------------------- */
/* i2c implementation */
@@ -138,6 +158,7 @@ static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
static int cs53l32a_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct v4l2_subdev *sd;
int i;
/* Check if the adapter supports the needed features */
@@ -154,32 +175,46 @@ static int cs53l32a_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
+ sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (sd == NULL)
+ return -ENOMEM;
+ v4l2_i2c_subdev_init(sd, client, &cs53l32a_ops);
+
for (i = 1; i <= 7; i++) {
- u8 v = cs53l32a_read(client, i);
+ u8 v = cs53l32a_read(sd, i);
- v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v);
+ v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
}
/* Set cs53l32a internal register for Adaptec 2010/2410 setup */
- cs53l32a_write(client, 0x01, (u8) 0x21);
- cs53l32a_write(client, 0x02, (u8) 0x29);
- cs53l32a_write(client, 0x03, (u8) 0x30);
- cs53l32a_write(client, 0x04, (u8) 0x00);
- cs53l32a_write(client, 0x05, (u8) 0x00);
- cs53l32a_write(client, 0x06, (u8) 0x00);
- cs53l32a_write(client, 0x07, (u8) 0x00);
+ cs53l32a_write(sd, 0x01, (u8) 0x21);
+ cs53l32a_write(sd, 0x02, (u8) 0x29);
+ cs53l32a_write(sd, 0x03, (u8) 0x30);
+ cs53l32a_write(sd, 0x04, (u8) 0x00);
+ cs53l32a_write(sd, 0x05, (u8) 0x00);
+ cs53l32a_write(sd, 0x06, (u8) 0x00);
+ cs53l32a_write(sd, 0x07, (u8) 0x00);
/* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
for (i = 1; i <= 7; i++) {
- u8 v = cs53l32a_read(client, i);
+ u8 v = cs53l32a_read(sd, i);
- v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v);
+ v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
}
return 0;
}
+static int cs53l32a_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(sd);
+ return 0;
+}
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
static const struct i2c_device_id cs53l32a_id[] = {
{ "cs53l32a", 0 },
@@ -192,6 +227,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "cs53l32a",
.driverid = I2C_DRIVERID_CS53L32A,
.command = cs53l32a_command,
+ .remove = cs53l32a_remove,
.probe = cs53l32a_probe,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
.id_table = cs53l32a_id,
diff --git a/linux/drivers/media/video/cx18/Kconfig b/linux/drivers/media/video/cx18/Kconfig
index ef48565de..8940b5387 100644
--- a/linux/drivers/media/video/cx18/Kconfig
+++ b/linux/drivers/media/video/cx18/Kconfig
@@ -9,7 +9,7 @@ config VIDEO_CX18
select VIDEO_CX2341X
select VIDEO_CS5345
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
---help---
This is a video4linux driver for Conexant cx23418 based
PCI combo video recorder devices.
diff --git a/linux/drivers/media/video/cx18/cx18-av-audio.c b/linux/drivers/media/video/cx18/cx18-av-audio.c
index fd85b9b2d..a2f0ad570 100644
--- a/linux/drivers/media/video/cx18/cx18-av-audio.c
+++ b/linux/drivers/media/video/cx18/cx18-av-audio.c
@@ -31,98 +31,165 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
if (freq != 32000 && freq != 44100 && freq != 48000)
return -EINVAL;
- /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
- cx18_av_write(cx, 0x127, 0x50);
+ /*
+ * The PLL parameters are based on the external crystal frequency that
+ * would ideally be:
+ *
+ * NTSC Color subcarrier freq * 8 =
+ * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
+ *
+ * The accidents of history and rationale that explain from where this
+ * combination of magic numbers originate can be found in:
+ *
+ * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
+ * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
+ *
+ * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
+ * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
+ *
+ * As Mike Bradley has rightly pointed out, it's not the exact crystal
+ * frequency that matters, only that all parts of the driver and
+ * firmware are using the same value (close to the ideal value).
+ *
+ * Since I have a strong suspicion that, if the firmware ever assumes a
+ * crystal value at all, it will assume 28.636360 MHz, the crystal
+ * freq used in calculations in this driver will be:
+ *
+ * xtal_freq = 28.636360 MHz
+ *
+ * an error of less than 0.13 ppm which is way, way better than any off
+ * the shelf crystal will have for accuracy anyway.
+ *
+ * Below I aim to run the PLLs' VCOs near 400 MHz to minimze error.
+ *
+ * Many thanks to Jeff Campbell and Mike Bradley for their extensive
+ * investigation, experimentation, testing, and suggested solutions of
+ * of audio/video sync problems with SVideo and CVBS captures.
+ */
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
switch (freq) {
case 32000:
- /* VID_PLL and AUX_PLL */
- cx18_av_write4(cx, 0x108, 0x1408040f);
+ /*
+ * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+ * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20
+ */
+ cx18_av_write4(cx, 0x108, 0x200d040f);
+
+ /* VID_PLL Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+ cx18_av_write4(cx, 0x10c, 0x002be2fe);
- /* AUX_PLL_FRAC */
- /* 0x8.9504318a * 28,636,363.636 / 0x14 = 32000 * 384 */
- cx18_av_write4(cx, 0x110, 0x012a0863);
+ /* AUX_PLL Fraction = 0x176740c */
+ /* xtal * 0xd.bb3a060/0x20 = 32000 * 384: 393 MHz p-pd*/
+ cx18_av_write4(cx, 0x110, 0x0176740c);
/* src3/4/6_ctl */
- /* 0x1.f77f = (4 * 15734.26) / 32000 */
+ /* 0x1.f77f = (4 * xtal/8*2/455) / 32000 */
cx18_av_write4(cx, 0x900, 0x0801f77f);
cx18_av_write4(cx, 0x904, 0x0801f77f);
cx18_av_write4(cx, 0x90c, 0x0801f77f);
- /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
- cx18_av_write(cx, 0x127, 0x54);
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
+ cx18_av_write(cx, 0x127, 0x60);
/* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */
cx18_av_write4(cx, 0x12c, 0x11202fff);
/*
- * EN_AV_LOCK = 1
+ * EN_AV_LOCK = 0
* VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
* ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
*/
- cx18_av_write4(cx, 0x128, 0xa10d2ef8);
+ cx18_av_write4(cx, 0x128, 0xa00d2ef8);
break;
case 44100:
- /* VID_PLL and AUX_PLL */
- cx18_av_write4(cx, 0x108, 0x1009040f);
+ /*
+ * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+ * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x18
+ */
+ cx18_av_write4(cx, 0x108, 0x180e040f);
+
+ /* VID_PLL Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+ cx18_av_write4(cx, 0x10c, 0x002be2fe);
- /* AUX_PLL_FRAC */
- /* 0x9.7635e7 * 28,636,363.63 / 0x10 = 44100 * 384 */
- cx18_av_write4(cx, 0x110, 0x00ec6bce);
+ /* AUX_PLL Fraction = 0x062a1f2 */
+ /* xtal * 0xe.3150f90/0x18 = 44100 * 384: 406 MHz p-pd*/
+ cx18_av_write4(cx, 0x110, 0x0062a1f2);
/* src3/4/6_ctl */
- /* 0x1.6d59 = (4 * 15734.26) / 44100 */
+ /* 0x1.6d59 = (4 * xtal/8*2/455) / 44100 */
cx18_av_write4(cx, 0x900, 0x08016d59);
cx18_av_write4(cx, 0x904, 0x08016d59);
cx18_av_write4(cx, 0x90c, 0x08016d59);
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x18 */
+ cx18_av_write(cx, 0x127, 0x58);
+
/* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */
cx18_av_write4(cx, 0x12c, 0x112092ff);
/*
- * EN_AV_LOCK = 1
+ * EN_AV_LOCK = 0
* VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
* ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
*/
- cx18_av_write4(cx, 0x128, 0xa11d4bf8);
+ cx18_av_write4(cx, 0x128, 0xa01d4bf8);
break;
case 48000:
- /* VID_PLL and AUX_PLL */
- cx18_av_write4(cx, 0x108, 0x100a040f);
+ /*
+ * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+ * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x16
+ */
+ cx18_av_write4(cx, 0x108, 0x160e040f);
- /* AUX_PLL_FRAC */
- /* 0xa.4c6b6ea * 28,636,363.63 / 0x10 = 48000 * 384 */
- cx18_av_write4(cx, 0x110, 0x0098d6dd);
+ /* VID_PLL Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+ cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+ /* AUX_PLL Fraction = 0x05227ad */
+ /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz p-pd*/
+ cx18_av_write4(cx, 0x110, 0x005227ad);
/* src3/4/6_ctl */
- /* 0x1.4faa = (4 * 15734.26) / 48000 */
+ /* 0x1.4faa = (4 * xtal/8*2/455) / 48000 */
cx18_av_write4(cx, 0x900, 0x08014faa);
cx18_av_write4(cx, 0x904, 0x08014faa);
cx18_av_write4(cx, 0x90c, 0x08014faa);
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+ cx18_av_write(cx, 0x127, 0x56);
+
/* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */
cx18_av_write4(cx, 0x12c, 0x11205fff);
/*
- * EN_AV_LOCK = 1
+ * EN_AV_LOCK = 0
* VID_COUNT = 0x1193f8 = 143999.000 * 8 =
* ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
*/
- cx18_av_write4(cx, 0x128, 0xa11193f8);
+ cx18_av_write4(cx, 0x128, 0xa01193f8);
break;
}
} else {
switch (freq) {
case 32000:
- /* VID_PLL and AUX_PLL */
- cx18_av_write4(cx, 0x108, 0x1e08040f);
+ /*
+ * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+ * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x30
+ */
+ cx18_av_write4(cx, 0x108, 0x300d040f);
+
+ /* VID_PLL Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+ cx18_av_write4(cx, 0x10c, 0x002be2fe);
- /* AUX_PLL_FRAC */
- /* 0x8.9504318 * 28,636,363.63 / 0x1e = 32000 * 256 */
- cx18_av_write4(cx, 0x110, 0x012a0863);
+ /* AUX_PLL Fraction = 0x176740c */
+ /* xtal * 0xd.bb3a060/0x30 = 32000 * 256: 393 MHz p-pd*/
+ cx18_av_write4(cx, 0x110, 0x0176740c);
/* src1_ctl */
/* 0x1.0000 = 32000/32000 */
@@ -134,27 +201,34 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
cx18_av_write4(cx, 0x904, 0x08020000);
cx18_av_write4(cx, 0x90c, 0x08020000);
- /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
- cx18_av_write(cx, 0x127, 0x54);
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x30 */
+ cx18_av_write(cx, 0x127, 0x70);
/* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */
cx18_av_write4(cx, 0x12c, 0x11201fff);
/*
- * EN_AV_LOCK = 1
+ * EN_AV_LOCK = 0
* VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
* ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
*/
- cx18_av_write4(cx, 0x128, 0xa10d2ef8);
+ cx18_av_write4(cx, 0x128, 0xa00d2ef8);
break;
case 44100:
- /* VID_PLL and AUX_PLL */
- cx18_av_write4(cx, 0x108, 0x1809040f);
+ /*
+ * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+ * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x24
+ */
+ cx18_av_write4(cx, 0x108, 0x240e040f);
+
+ /* VID_PLL Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+ cx18_av_write4(cx, 0x10c, 0x002be2fe);
- /* AUX_PLL_FRAC */
- /* 0x9.7635e74 * 28,636,363.63 / 0x18 = 44100 * 256 */
- cx18_av_write4(cx, 0x110, 0x00ec6bce);
+ /* AUX_PLL Fraction = 0x062a1f2 */
+ /* xtal * 0xe.3150f90/0x24 = 44100 * 256: 406 MHz p-pd*/
+ cx18_av_write4(cx, 0x110, 0x0062a1f2);
/* src1_ctl */
/* 0x1.60cd = 44100/32000 */
@@ -166,24 +240,34 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
cx18_av_write4(cx, 0x904, 0x08017385);
cx18_av_write4(cx, 0x90c, 0x08017385);
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x24 */
+ cx18_av_write(cx, 0x127, 0x64);
+
/* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */
cx18_av_write4(cx, 0x12c, 0x112061ff);
/*
- * EN_AV_LOCK = 1
+ * EN_AV_LOCK = 0
* VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
* ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
*/
- cx18_av_write4(cx, 0x128, 0xa11d4bf8);
+ cx18_av_write4(cx, 0x128, 0xa01d4bf8);
break;
case 48000:
- /* VID_PLL and AUX_PLL */
- cx18_av_write4(cx, 0x108, 0x180a040f);
+ /*
+ * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+ * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20
+ */
+ cx18_av_write4(cx, 0x108, 0x200d040f);
- /* AUX_PLL_FRAC */
- /* 0xa.4c6b6ea * 28,636,363.63 / 0x18 = 48000 * 256 */
- cx18_av_write4(cx, 0x110, 0x0098d6dd);
+ /* VID_PLL Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+ cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+ /* AUX_PLL Fraction = 0x176740c */
+ /* xtal * 0xd.bb3a060/0x20 = 48000 * 256: 393 MHz p-pd*/
+ cx18_av_write4(cx, 0x110, 0x0176740c);
/* src1_ctl */
/* 0x1.8000 = 48000/32000 */
@@ -195,15 +279,18 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
cx18_av_write4(cx, 0x904, 0x08015555);
cx18_av_write4(cx, 0x90c, 0x08015555);
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
+ cx18_av_write(cx, 0x127, 0x60);
+
/* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */
cx18_av_write4(cx, 0x12c, 0x11203fff);
/*
- * EN_AV_LOCK = 1
+ * EN_AV_LOCK = 0
* VID_COUNT = 0x1193f8 = 143999.000 * 8 =
* ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
*/
- cx18_av_write4(cx, 0x128, 0xa11193f8);
+ cx18_av_write4(cx, 0x128, 0xa01193f8);
break;
}
}
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c
index 40ea6fde6..0b1c84b4d 100644
--- a/linux/drivers/media/video/cx18/cx18-av-core.c
+++ b/linux/drivers/media/video/cx18/cx18-av-core.c
@@ -271,7 +271,7 @@ void cx18_av_std_setup(struct cx18 *cx)
if (pll_post) {
int fin, fsc, pll;
- pll = (28636364L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
+ pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
pll /= pll_post;
CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
pll / 1000000, pll % 1000000);
diff --git a/linux/drivers/media/video/cx18/cx18-av-vbi.c b/linux/drivers/media/video/cx18/cx18-av-vbi.c
index 02fdf57bb..1527ea4f6 100644
--- a/linux/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/linux/drivers/media/video/cx18/cx18-av-vbi.c
@@ -141,10 +141,11 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
u8 lcr[24];
fmt = arg;
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
+ fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
return -EINVAL;
svbi = &fmt->fmt.sliced;
- if (svbi->service_set == 0) {
+ if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
/* raw VBI */
memset(svbi, 0, sizeof(*svbi));
diff --git a/linux/drivers/media/video/cx18/cx18-cards.c b/linux/drivers/media/video/cx18/cx18-cards.c
index 23bd871b7..10cddba3e 100644
--- a/linux/drivers/media/video/cx18/cx18-cards.c
+++ b/linux/drivers/media/video/cx18/cx18-cards.c
@@ -51,7 +51,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
static const struct cx18_card cx18_card_hvr1600_esmt = {
.type = CX18_CARD_HVR_1600_ESMT,
.name = "Hauppauge HVR-1600",
- .comment = "VBI is not yet supported\n",
+ .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_muxer = CX18_HW_CS5345,
@@ -97,7 +97,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
static const struct cx18_card cx18_card_hvr1600_samsung = {
.type = CX18_CARD_HVR_1600_SAMSUNG,
.name = "Hauppauge HVR-1600 (Preproduction)",
- .comment = "VBI is not yet supported\n",
+ .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_muxer = CX18_HW_CS5345,
@@ -152,7 +152,7 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = {
static const struct cx18_card cx18_card_h900 = {
.type = CX18_CARD_COMPRO_H900,
.name = "Compro VideoMate H900",
- .comment = "VBI is not yet supported\n",
+ .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_all = CX18_HW_TUNER,
@@ -249,7 +249,7 @@ static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
static const struct cx18_card cx18_card_cnxt_raptor_pal = {
.type = CX18_CARD_CNXT_RAPTOR_PAL,
.name = "Conexant Raptor PAL/SECAM",
- .comment = "VBI is not yet supported\n",
+ .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_muxer = CX18_HW_GPIO,
diff --git a/linux/drivers/media/video/cx18/cx18-cards.h b/linux/drivers/media/video/cx18/cx18-cards.h
index a54aae9ed..6fa7bcb42 100644
--- a/linux/drivers/media/video/cx18/cx18-cards.h
+++ b/linux/drivers/media/video/cx18/cx18-cards.h
@@ -48,8 +48,9 @@
/* V4L2 capability aliases */
#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
- V4L2_CAP_AUDIO | V4L2_CAP_READWRITE)
-/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \
+ V4L2_CAP_VBI_CAPTURE)
+/* | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
struct cx18_card_video_input {
u8 video_type; /* video input type */
diff --git a/linux/drivers/media/video/cx18/cx18-controls.c b/linux/drivers/media/video/cx18/cx18-controls.c
index f46c7e5ed..17edf305d 100644
--- a/linux/drivers/media/video/cx18/cx18-controls.c
+++ b/linux/drivers/media/video/cx18/cx18-controls.c
@@ -259,6 +259,7 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
return err;
}
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ struct cx18_api_func_private priv;
struct cx2341x_mpeg_params p = cx->params;
int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
c, VIDIOC_S_EXT_CTRLS);
@@ -278,7 +279,9 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
fmt.fmt.pix.height = cx->params.height;
cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
}
- err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
+ priv.cx = cx;
+ priv.s = &cx->streams[id->type];
+ err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p);
if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
cx->params = p;
diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c
index 1fa9a670b..e447b4ce7 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.c
+++ b/linux/drivers/media/video/cx18/cx18-driver.c
@@ -56,9 +56,6 @@ struct cx18 *cx18_cards[CX18_MAX_CARDS];
/* Protects cx18_cards_active */
DEFINE_SPINLOCK(cx18_cards_lock);
-/* Queue for deferrable IRQ handling work for all cx18 cards in system */
-struct workqueue_struct *cx18_work_queue;
-
/* add your revision and whatnot here */
static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
@@ -86,12 +83,28 @@ static char secam[] = "--";
static char ntsc[] = "-";
/* Buffers */
-static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS;
+static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
+static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS;
static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS;
static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS;
static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS;
+static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE;
+static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE;
+static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE;
+static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE;
+/* VBI bufsize based on standards supported by card tuner for now */
+static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE;
+
+static int enc_ts_bufs = -1;
+static int enc_mpg_bufs = -1;
+static int enc_idx_bufs = -1;
+static int enc_yuv_bufs = -1;
+static int enc_vbi_bufs = -1;
+static int enc_pcm_bufs = -1;
+
+
static int cx18_pci_latency = 1;
static int mmio_ndelay;
@@ -111,12 +124,27 @@ module_param(retry_mmio, int, 0644);
module_param(cx18_pci_latency, int, 0644);
module_param(cx18_first_minor, int, 0644);
-module_param(enc_mpg_buffers, int, 0644);
module_param(enc_ts_buffers, int, 0644);
+module_param(enc_mpg_buffers, int, 0644);
+module_param(enc_idx_buffers, int, 0644);
module_param(enc_yuv_buffers, int, 0644);
module_param(enc_vbi_buffers, int, 0644);
module_param(enc_pcm_buffers, int, 0644);
+module_param(enc_ts_bufsize, int, 0644);
+module_param(enc_mpg_bufsize, int, 0644);
+module_param(enc_idx_bufsize, int, 0644);
+module_param(enc_yuv_bufsize, int, 0644);
+/* VBI bufsize based on standards supported by card tuner for now */
+module_param(enc_pcm_bufsize, int, 0644);
+
+module_param(enc_ts_bufs, int, 0644);
+module_param(enc_mpg_bufs, int, 0644);
+module_param(enc_idx_bufs, int, 0644);
+module_param(enc_yuv_bufs, int, 0644);
+module_param(enc_vbi_bufs, int, 0644);
+module_param(enc_pcm_bufs, int, 0644);
+
MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
"\t\t\tsee tuner.h for values");
MODULE_PARM_DESC(radio,
@@ -157,21 +185,57 @@ MODULE_PARM_DESC(retry_mmio,
MODULE_PARM_DESC(mmio_ndelay,
"(Deprecated) MMIO accesses are now never purposely delayed\n"
"\t\t\tEffectively: 0 ns");
-MODULE_PARM_DESC(enc_mpg_buffers,
- "Encoder MPG Buffers (in MB)\n"
- "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
MODULE_PARM_DESC(enc_ts_buffers,
- "Encoder TS Buffers (in MB)\n"
+ "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n"
"\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS));
+MODULE_PARM_DESC(enc_ts_bufsize,
+ "Size of an encoder TS buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE));
+MODULE_PARM_DESC(enc_ts_bufs,
+ "Number of encoder TS buffers\n"
+ "\t\t\tDefault is computed from other enc_ts_* parameters");
+MODULE_PARM_DESC(enc_mpg_buffers,
+ "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
+MODULE_PARM_DESC(enc_mpg_bufsize,
+ "Size of an encoder MPG buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE));
+MODULE_PARM_DESC(enc_mpg_bufs,
+ "Number of encoder MPG buffers\n"
+ "\t\t\tDefault is computed from other enc_mpg_* parameters");
+MODULE_PARM_DESC(enc_idx_buffers,
+ "Encoder IDX buffer memory (MB). (enc_idx_bufs can override)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_IDX_BUFFERS));
+MODULE_PARM_DESC(enc_idx_bufsize,
+ "Size of an encoder IDX buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_IDX_BUFSIZE));
+MODULE_PARM_DESC(enc_idx_bufs,
+ "Number of encoder IDX buffers\n"
+ "\t\t\tDefault is computed from other enc_idx_* parameters");
MODULE_PARM_DESC(enc_yuv_buffers,
- "Encoder YUV Buffers (in MB)\n"
+ "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n"
"\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
+MODULE_PARM_DESC(enc_yuv_bufsize,
+ "Size of an encoder YUV buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFSIZE));
+MODULE_PARM_DESC(enc_yuv_bufs,
+ "Number of encoder YUV buffers\n"
+ "\t\t\tDefault is computed from other enc_yuv_* parameters");
MODULE_PARM_DESC(enc_vbi_buffers,
- "Encoder VBI Buffers (in MB)\n"
+ "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n"
"\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS));
+MODULE_PARM_DESC(enc_vbi_bufs,
+ "Number of encoder VBI buffers\n"
+ "\t\t\tDefault is computed from enc_vbi_buffers & tuner std");
MODULE_PARM_DESC(enc_pcm_buffers,
- "Encoder PCM buffers (in MB)\n"
+ "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n"
"\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
+MODULE_PARM_DESC(enc_pcm_bufsize,
+ "Size of an encoder PCM buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE));
+MODULE_PARM_DESC(enc_pcm_bufs,
+ "Number of encoder PCM buffers\n"
+ "\t\t\tDefault is computed from other enc_pcm_* parameters");
MODULE_PARM_DESC(cx18_first_minor, "Set kernel number assigned to first card");
@@ -364,11 +428,65 @@ static void cx18_process_options(struct cx18 *cx)
{
int i, j;
- cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers;
cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */
+
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */
+
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = 0; /* computed later */
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */
+
+ /* Except for VBI ensure stream_buffers & stream_buf_size are valid */
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ /* User said to use 0 buffers */
+ if (cx->stream_buffers[i] == 0) {
+ cx->options.megabytes[i] = 0;
+ cx->stream_buf_size[i] = 0;
+ continue;
+ }
+ /* User said to use 0 MB total */
+ if (cx->options.megabytes[i] <= 0) {
+ cx->options.megabytes[i] = 0;
+ cx->stream_buffers[i] = 0;
+ cx->stream_buf_size[i] = 0;
+ continue;
+ }
+ /* VBI is computed later or user said buffer has size 0 */
+ if (cx->stream_buf_size[i] <= 0) {
+ if (i != CX18_ENC_STREAM_TYPE_VBI) {
+ cx->options.megabytes[i] = 0;
+ cx->stream_buffers[i] = 0;
+ cx->stream_buf_size[i] = 0;
+ }
+ continue;
+ }
+ if (cx->stream_buffers[i] < 0) {
+ cx->stream_buffers[i] = cx->options.megabytes[i] * 1024
+ / cx->stream_buf_size[i];
+ } else {
+ /* N.B. This might round down to 0 */
+ cx->options.megabytes[i] =
+ cx->stream_buffers[i] * cx->stream_buf_size[i] / 1024;
+ }
+ cx->stream_buf_size[i] *= 1024; /* convert from kB to bytes */
+ }
+
cx->options.cardtype = cardtype[cx->num];
cx->options.tuner = tuner[cx->num];
cx->options.radio = radio[cx->num];
@@ -446,6 +564,12 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
spin_lock_init(&cx->lock);
+ cx->work_queue = create_singlethread_workqueue(cx->name);
+ if (cx->work_queue == NULL) {
+ CX18_ERR("Unable to create work hander thread\n");
+ return -ENOMEM;
+ }
+
for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) {
cx->epu_work_order[i].cx = cx;
cx->epu_work_order[i].str = cx->epu_debug_str;
@@ -475,15 +599,52 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
init_waitqueue_head(&cx->dma_waitq);
/* VBI */
- cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+ cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
- cx->vbi.raw_size = 1456;
- cx->vbi.raw_decoder_line_size = 1456;
- cx->vbi.raw_decoder_sav_odd_field = 0x20;
- cx->vbi.raw_decoder_sav_even_field = 0x60;
- cx->vbi.sliced_decoder_line_size = 272;
- cx->vbi.sliced_decoder_sav_odd_field = 0xB0;
- cx->vbi.sliced_decoder_sav_even_field = 0xF0;
+
+ /*
+ * The VBI line sizes depend on the pixel clock and the horiz rate
+ *
+ * (1/Fh)*(2*Fp) = Samples/line
+ * = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples
+ *
+ * Sliced VBI is sent as ancillary data during horizontal blanking
+ * Raw VBI is sent as active video samples during vertcal blanking
+ *
+ * We use a BT.656 pxiel clock of 13.5 MHz and a BT.656 active line
+ * length of 720 pixels @ 4:2:2 sampling. Thus...
+ *
+ * For systems that use a 15.734 kHz horizontal rate, such as
+ * NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
+ *
+ * (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line =
+ * 4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples
+ *
+ * For systems that use a 15.625 kHz horizontal rate, such as
+ * PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
+ *
+ * (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
+ * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
+ *
+ */
+
+ /* FIXME: init these based on tuner std & modify when std changes */
+ /* CX18-AV-Core number of VBI samples output per horizontal line */
+ cx->vbi.raw_decoder_line_size = 1444; /* 4 byte SAV + 2 * 720 */
+ cx->vbi.sliced_decoder_line_size = 272; /* 60 Hz: 268+4, 50 Hz: 280+4 */
+
+ /* CX18-AV-Core VBI samples/line possibly rounded up */
+ cx->vbi.raw_size = 1444; /* Real max size is 1444 */
+ cx->vbi.sliced_size = 284; /* Real max size is 284 */
+
+ /*
+ * CX18-AV-Core SAV/EAV RP codes in VIP 1.x mode
+ * Task Field VerticalBlank HorizontalBlank 0 0 0 0
+ */
+ cx->vbi.raw_decoder_sav_odd_field = 0x20; /* V */
+ cx->vbi.raw_decoder_sav_even_field = 0x60; /* FV */
+ cx->vbi.sliced_decoder_sav_odd_field = 0xB0; /* T VH - actually EAV */
+ cx->vbi.sliced_decoder_sav_even_field = 0xF0; /* TFVH - actually EAV */
return 0;
}
@@ -516,6 +677,7 @@ static void __devinit cx18_init_struct2(struct cx18 *cx)
cx->av_state.aud_input = CX18_AV_AUDIO8;
cx->av_state.audclk_freq = 48000;
cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
+ /* FIXME - 8 is NTSC value, investigate */
cx->av_state.vbi_line_offset = 8;
}
@@ -660,12 +822,9 @@ static int __devinit cx18_probe(struct pci_dev *dev,
/* PCI Device Setup */
retval = cx18_setup_pci(cx, dev, pci_id);
- if (retval != 0) {
- if (retval == -EIO)
- goto free_workqueue;
- else if (retval == -ENXIO)
- goto free_mem;
- }
+ if (retval != 0)
+ goto free_workqueue;
+
/* save cx in the pci struct for later use */
pci_set_drvdata(dev, cx);
@@ -724,6 +883,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
goto free_i2c;
}
cx18_init_memory(cx);
+ cx18_init_scb(cx);
/* Register IRQ */
retval = request_irq(cx->dev->irq, cx18_irq_handler,
@@ -773,13 +933,23 @@ static int __devinit cx18_probe(struct pci_dev *dev,
}
cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000;
+ /*
+ * FIXME: setting the buffer size based on the tuner standard is
+ * suboptimal, as the CVBS and SVideo inputs could use a different std
+ * and the buffer could end up being too small in that case.
+ */
vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2;
cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
+ if (cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] < 0)
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] =
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] * 1024 * 1024
+ / vbi_buf_size;
+ else
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] =
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] * vbi_buf_size
+ / (1024 * 1024);
+
if (cx->options.radio > 0)
cx->v4l2_cap |= V4L2_CAP_RADIO;
@@ -835,6 +1005,7 @@ free_map:
free_mem:
release_mem_region(cx->base_addr, CX18_MEM_SIZE);
free_workqueue:
+ destroy_workqueue(cx->work_queue);
err:
if (retval == 0)
retval = -ENODEV;
@@ -917,6 +1088,7 @@ int cx18_init_on_first_open(struct cx18 *cx)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
static void cx18_cancel_epu_work_orders(struct cx18 *cx)
{
int i;
@@ -924,6 +1096,7 @@ static void cx18_cancel_epu_work_orders(struct cx18 *cx)
cancel_work_sync(&cx->epu_work_order[i].work);
}
+#endif
static void cx18_remove(struct pci_dev *pci_dev)
{
struct cx18 *cx = pci_get_drvdata(pci_dev);
@@ -937,11 +1110,22 @@ static void cx18_remove(struct pci_dev *pci_dev)
/* Interrupts */
cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
cx18_halt_firmware(cx);
cx18_cancel_epu_work_orders(cx);
+#else
+
+ flush_workqueue(cx->work_queue);
+
+ cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+ cx18_halt_firmware(cx);
+#endif
+
+ destroy_workqueue(cx->work_queue);
cx18_streams_cleanup(cx, 1);
@@ -984,17 +1168,8 @@ static int module_start(void)
printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n");
}
- cx18_work_queue = create_singlethread_workqueue("cx18");
- if (cx18_work_queue == NULL) {
- printk(KERN_ERR
- "cx18: Unable to create work hander thread\n");
- return -ENOMEM;
- }
-
if (pci_register_driver(&cx18_pci_driver)) {
printk(KERN_ERR "cx18: Error detecting PCI card\n");
- destroy_workqueue(cx18_work_queue);
- cx18_work_queue = NULL;
return -ENODEV;
}
printk(KERN_INFO "cx18: End initialization\n");
@@ -1007,9 +1182,6 @@ static void module_cleanup(void)
pci_unregister_driver(&cx18_pci_driver);
- destroy_workqueue(cx18_work_queue);
- cx18_work_queue = NULL;
-
for (i = 0; i < cx18_cards_active; i++) {
if (cx18_cards[i] == NULL)
continue;
diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h
index ca1f43781..0d2edebc3 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.h
+++ b/linux/drivers/media/video/cx18/cx18-driver.h
@@ -115,6 +115,17 @@
#define CX18_DEFAULT_ENC_VBI_BUFFERS 1
#define CX18_DEFAULT_ENC_PCM_BUFFERS 1
+/* Maximum firmware DMA buffers per stream */
+#define CX18_MAX_FW_MDLS_PER_STREAM 63
+
+/* DMA buffer, default size in kB allocated */
+#define CX18_DEFAULT_ENC_TS_BUFSIZE 32
+#define CX18_DEFAULT_ENC_MPG_BUFSIZE 32
+#define CX18_DEFAULT_ENC_IDX_BUFSIZE 32
+#define CX18_DEFAULT_ENC_YUV_BUFSIZE 128
+/* Default VBI bufsize based on standards supported by card tuner for now */
+#define CX18_DEFAULT_ENC_PCM_BUFSIZE 4
+
/* i2c stuff */
#define I2C_CLIENTS_MAX 16
@@ -244,7 +255,8 @@ struct cx18_scb; /* forward reference */
#define CX18_MAX_MDL_ACKS 2
-#define CX18_MAX_EPU_WORK_ORDERS 70 /* CPU_DE_RELEASE_MDL bursts 63 commands */
+#define CX18_MAX_EPU_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7)
+/* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */
#define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1
#define CX18_F_EWO_MB_STALE_WHILE_PROC 0x2
@@ -289,8 +301,8 @@ struct cx18_stream {
/* Buffer Queues */
struct cx18_queue q_free; /* free buffers */
- struct cx18_queue q_full; /* full buffers */
- struct cx18_queue q_io; /* waiting for I/O */
+ struct cx18_queue q_busy; /* busy buffers - in use by firmware */
+ struct cx18_queue q_full; /* full buffers - data for user apps */
/* DVB / Digital Transport */
struct cx18_dvb dvb;
@@ -408,6 +420,7 @@ struct cx18 {
struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */
struct cx18_options options; /* User options */
+ int stream_buffers[CX18_MAX_STREAMS]; /* # of buffers for each stream */
int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */
struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */
unsigned long i_flags; /* global cx18 flags */
@@ -447,6 +460,7 @@ struct cx18 {
u32 sw2_irq_mask;
u32 hw2_irq_mask;
+ struct workqueue_struct *work_queue;
struct cx18_epu_work_order epu_work_order[CX18_MAX_EPU_WORK_ORDERS];
char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
@@ -478,7 +492,6 @@ extern struct cx18 *cx18_cards[];
extern int cx18_cards_active;
extern int cx18_first_minor;
extern spinlock_t cx18_cards_lock;
-extern struct workqueue_struct *cx18_work_queue;
/*==============Prototypes==================*/
@@ -492,4 +505,10 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv);
/* First-open initialization: load firmware, etc. */
int cx18_init_on_first_open(struct cx18 *cx);
+/* Test if the current VBI mode is raw (1) or sliced (0) */
+static inline int cx18_raw_vbi(const struct cx18 *cx)
+{
+ return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE;
+}
+
#endif /* CX18_DRIVER_H */
diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c
index 034e09a37..bd5e6f3fd 100644
--- a/linux/drivers/media/video/cx18/cx18-dvb.c
+++ b/linux/drivers/media/video/cx18/cx18-dvb.c
@@ -217,6 +217,10 @@ int cx18_dvb_register(struct cx18_stream *stream)
dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
CX18_INFO("DVB Frontend registered\n");
+ CX18_INFO("Registered DVB adapter%d for %s (%d x %d kB)\n",
+ stream->dvb.dvb_adapter.num, stream->name,
+ stream->buffers, stream->buf_size/1024);
+
mutex_init(&dvb->feedlock);
dvb->enabled = 1;
return ret;
diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c
index 45b5f402e..0aaea0e7f 100644
--- a/linux/drivers/media/video/cx18/cx18-fileops.c
+++ b/linux/drivers/media/video/cx18/cx18-fileops.c
@@ -67,12 +67,11 @@ static int cx18_claim_stream(struct cx18_open_id *id, int type)
}
s->id = id->open_id;
- /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI,
- CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
+ /* CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
(provided VBI insertion is on and sliced VBI is selected), for all
other streams we're done */
if (type == CX18_ENC_STREAM_TYPE_MPG &&
- cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) {
+ cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) {
vbi_type = CX18_ENC_STREAM_TYPE_VBI;
} else {
return 0;
@@ -224,8 +223,10 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
!test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) {
/* byteswap and process VBI data */
-/* cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */
- cx18_enqueue(s_vbi, buf, &s_vbi->q_free);
+ cx18_process_vbi_data(cx, buf,
+ s_vbi->dma_pts,
+ s_vbi->type);
+ cx18_stream_put_buf_fw(s_vbi, buf);
}
}
buf = &cx->vbi.sliced_mpeg_buf;
@@ -233,11 +234,6 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
return buf;
}
- /* do we have leftover data? */
- buf = cx18_dequeue(s, &s->q_io);
- if (buf)
- return buf;
-
/* do we have new data? */
buf = cx18_dequeue(s, &s->q_full);
if (buf) {
@@ -301,7 +297,7 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
if (len > ucount)
len = ucount;
if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
- cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) {
+ !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) {
const char *start = buf->buf + buf->readpos;
const char *p = start + 1;
const u8 *q;
@@ -376,8 +372,7 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
/* Each VBI buffer is one frame, the v4l2 API says that for VBI the
frames should arrive one-by-one, so make sure we never output more
than one VBI frame at a time */
- if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
- cx->vbi.sliced_in->service_set)
+ if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx))
single_frame = 1;
for (;;) {
@@ -404,16 +399,10 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
tot_count - tot_written);
if (buf != &cx->vbi.sliced_mpeg_buf) {
- if (buf->readpos == buf->bytesused) {
- cx18_buf_sync_for_device(s, buf);
- cx18_enqueue(s, buf, &s->q_free);
- cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5,
- s->handle,
- (void __iomem *)&cx->scb->cpu_mdl[buf->id] -
- cx->enc_mem,
- 1, buf->id, s->buf_size);
- } else
- cx18_enqueue(s, buf, &s->q_io);
+ if (buf->readpos == buf->bytesused)
+ cx18_stream_put_buf_fw(s, buf);
+ else
+ cx18_push(s, buf, &s->q_full);
} else if (buf->readpos == buf->bytesused) {
int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
@@ -557,7 +546,7 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
CX18_DEBUG_HI_FILE("Encoder poll\n");
poll_wait(filp, &s->waitq, wait);
- if (atomic_read(&s->q_full.buffers) || atomic_read(&s->q_io.buffers))
+ if (atomic_read(&s->q_full.buffers))
return POLLIN | POLLRDNORM;
if (eof)
return POLLHUP;
@@ -601,7 +590,7 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
}
}
-int cx18_v4l2_close(struct inode *inode, struct file *filp)
+int cx18_v4l2_close(struct file *filp)
{
struct cx18_open_id *id = filp->private_data;
struct cx18 *cx = id->cx;
@@ -699,12 +688,12 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
return 0;
}
-int cx18_v4l2_open(struct inode *inode, struct file *filp)
+int cx18_v4l2_open(struct file *filp)
{
int res, x, y = 0;
struct cx18 *cx = NULL;
struct cx18_stream *s = NULL;
- int minor = iminor(inode);
+ int minor = video_devdata(filp)->minor;
/* Find which card this open was on */
spin_lock(&cx18_cards_lock);
diff --git a/linux/drivers/media/video/cx18/cx18-fileops.h b/linux/drivers/media/video/cx18/cx18-fileops.h
index 46da0282f..92e2d5dab 100644
--- a/linux/drivers/media/video/cx18/cx18-fileops.h
+++ b/linux/drivers/media/video/cx18/cx18-fileops.h
@@ -22,12 +22,12 @@
*/
/* Testing/Debugging */
-int cx18_v4l2_open(struct inode *inode, struct file *filp);
+int cx18_v4l2_open(struct file *filp);
ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
loff_t *pos);
ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count,
loff_t *pos);
-int cx18_v4l2_close(struct inode *inode, struct file *filp);
+int cx18_v4l2_close(struct file *filp);
unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait);
int cx18_start_capture(struct cx18_open_id *id);
void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
diff --git a/linux/drivers/media/video/cx18/cx18-firmware.c b/linux/drivers/media/video/cx18/cx18-firmware.c
index 8eac84314..1fa95da15 100644
--- a/linux/drivers/media/video/cx18/cx18-firmware.c
+++ b/linux/drivers/media/video/cx18/cx18-firmware.c
@@ -26,6 +26,7 @@
#include "cx18-irq.h"
#include "cx18-firmware.h"
#include "cx18-cards.h"
+#include "cx18-av-core.h"
#include <linux/firmware.h>
#define CX18_PROC_SOFT_RESET 0xc70010
@@ -224,7 +225,45 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL,
0x00000000, 0x00020002);
- /* The fast clock is at 200/245 MHz */
+ /*
+ * The PLL parameters are based on the external crystal frequency that
+ * would ideally be:
+ *
+ * NTSC Color subcarrier freq * 8 =
+ * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
+ *
+ * The accidents of history and rationale that explain from where this
+ * combination of magic numbers originate can be found in:
+ *
+ * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
+ * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
+ *
+ * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
+ * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
+ *
+ * As Mike Bradley has rightly pointed out, it's not the exact crystal
+ * frequency that matters, only that all parts of the driver and
+ * firmware are using the same value (close to the ideal value).
+ *
+ * Since I have a strong suspicion that, if the firmware ever assumes a
+ * crystal value at all, it will assume 28.636360 MHz, the crystal
+ * freq used in calculations in this driver will be:
+ *
+ * xtal_freq = 28.636360 MHz
+ *
+ * an error of less than 0.13 ppm which is way, way better than any off
+ * the shelf crystal will have for accuracy anyway.
+ *
+ * Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors.
+ *
+ * Many thanks to Jeff Campbell and Mike Bradley for their extensive
+ * investigation, experimentation, testing, and suggested solutions of
+ * of audio/video sync problems with SVideo and CVBS captures.
+ */
+
+ /* the fast clock is at 200/245 MHz */
+ /* 1 * xtal_freq * 0x0d.f7df9b8 / 2 = 200 MHz: 400 MHz pre post-divide*/
+ /* 1 * xtal_freq * 0x11.1c71eb8 / 2 = 245 MHz: 490 MHz pre post-divide*/
cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7,
CX18_FAST_CLOCK_PLL_FRAC);
@@ -234,16 +273,36 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
/* set slow clock to 125/120 MHz */
- cx18_write_reg(cx, lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT);
- cx18_write_reg(cx, lowpwr ? 0xEBAF05 : 0x18618A8,
+ /* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */
+ /* xtal_freq * 0x0c.92493f8 / 3 = 120 MHz: 360 MHz before post-divide */
+ cx18_write_reg(cx, lowpwr ? 0xD : 0xC, CX18_SLOW_CLOCK_PLL_INT);
+ cx18_write_reg(cx, lowpwr ? 0x30C344 : 0x124927F,
CX18_SLOW_CLOCK_PLL_FRAC);
- cx18_write_reg(cx, 4, CX18_SLOW_CLOCK_PLL_POST);
+ cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST);
/* mpeg clock pll 54MHz */
+ /* xtal_freq * 0xf.15f17f0 / 8 = 54 MHz: 432 MHz before post-divide */
cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT);
- cx18_write_reg(cx, 0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC);
+ cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC);
cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);
+ /*
+ * VDCLK Integer = 0x0f, Post Divider = 0x04
+ * AIMCLK Integer = 0x0e, Post Divider = 0x16
+ */
+ cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
+
+ /* VDCLK Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
+ cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
+
+ /* AIMCLK Fraction = 0x05227ad */
+ /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz before post-divide */
+ cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
+
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+ cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+
/* Defaults */
/* APU = SC or SC/2 = 125/62.5 */
/* EPU = SC = 125 */
@@ -332,6 +391,10 @@ void cx18_init_memory(struct cx18 *cx)
int cx18_firmware_init(struct cx18 *cx)
{
+ u32 fw_entry_addr;
+ int sz, retries;
+ u32 api_args[MAX_MB_ARGUMENTS];
+
/* Allow chip to control CLKRUN */
cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK);
@@ -341,65 +404,62 @@ int cx18_firmware_init(struct cx18 *cx)
cx18_msleep_timeout(1, 0);
+ /* If the CPU is still running */
+ if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) {
+ CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__);
+ return -EIO;
+ }
+
cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
- /* Only if the processor is not running */
- if (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) {
- u32 fw_entry_addr = 0;
- int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
- cx->enc_mem, cx, &fw_entry_addr);
-
- if (sz <= 0)
- return sz;
-
- /* Clear bit0 for APU to start from 0 */
- cx18_write_reg(cx, cx18_read_reg(cx, 0xc72030) & ~1, 0xc72030);
-
- cx18_write_enc(cx, 0xE51FF004, 0); /* ldr pc, [pc, #-4] */
- cx18_write_enc(cx, fw_entry_addr, 4);
-
- /* Start APU */
- cx18_write_reg_expect(cx, 0x00010000, CX18_PROC_SOFT_RESET,
- 0x00000000, 0x00010001);
- cx18_msleep_timeout(500, 0);
-
- sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
- cx->enc_mem, cx);
-
- if (sz > 0) {
- int retries = 0;
-
- /* start the CPU */
- cx18_write_reg_expect(cx,
- 0x00080000, CX18_PROC_SOFT_RESET,
- 0x00000000, 0x00080008);
- while (retries++ < 50) { /* Loop for max 500mS */
- if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET)
- & 1) == 0)
- break;
- cx18_msleep_timeout(10, 0);
- }
- cx18_msleep_timeout(200, 0);
- if (retries == 51) {
- CX18_ERR("Could not start the CPU\n");
- return -EIO;
- }
- }
- if (sz <= 0)
- return -EIO;
+ sz = load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx);
+ if (sz <= 0)
+ return sz;
+
+ /* The SCB & IPC area *must* be correct before starting the firmwares */
+ cx18_init_scb(cx);
+
+ fw_entry_addr = 0;
+ sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx,
+ &fw_entry_addr);
+ if (sz <= 0)
+ return sz;
+
+ /* Start the CPU. The CPU will take care of the APU for us. */
+ cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET,
+ 0x00000000, 0x00080008);
+
+ /* Wait up to 500 ms for the APU to come out of reset */
+ for (retries = 0;
+ retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1;
+ retries++)
+ cx18_msleep_timeout(10, 0);
+
+ cx18_msleep_timeout(200, 0);
+
+ if (retries == 50 &&
+ (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) {
+ CX18_ERR("Could not start the CPU\n");
+ return -EIO;
}
/*
- * The CPU firmware apparently sets up to receive an interrupt for it's
- * outgoing IRQ_CPU_TO_EPU_ACK to us (*boggle*). We get an interrupt
- * when it sends us an ack, but by the time we process it, that flag in
- * the SW2 status register has been cleared by the CPU firmware.
- * We'll prevent that not so useful behavior by clearing the CPU's
- * interrupt enables for Ack IRQ's we want to process.
+ * The CPU had once before set up to receive an interrupt for it's
+ * outgoing IRQ_CPU_TO_EPU_ACK to us. If it ever does this, we get an
+ * interrupt when it sends us an ack, but by the time we process it,
+ * that flag in the SW2 status register has been cleared by the CPU
+ * firmware. We'll prevent that not so useful condition from happening
+ * by clearing the CPU's interrupt enables for Ack IRQ's we want to
+ * process.
*/
cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+ /* Try a benign command to see if the CPU is alive and well */
+ sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0);
+ if (sz < 0)
+ return sz;
+
/* initialize GPIO */
cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400);
return 0;
diff --git a/linux/drivers/media/video/cx18/cx18-i2c.c b/linux/drivers/media/video/cx18/cx18-i2c.c
index c0a79ecd4..efae2301a 100644
--- a/linux/drivers/media/video/cx18/cx18-i2c.c
+++ b/linux/drivers/media/video/cx18/cx18-i2c.c
@@ -268,7 +268,7 @@ int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg)
return retval;
}
}
- if (cmd != VIDIOC_G_CHIP_IDENT)
+ if (cmd != VIDIOC_DBG_G_CHIP_IDENT)
CX18_ERR("i2c addr 0x%02x not found for cmd 0x%x!\n",
addr, cmd);
return -ENODEV;
@@ -294,17 +294,6 @@ static int cx18_i2c_id_addr(struct cx18 *cx, u32 id)
return retval;
}
-/* Find the i2c device name matching the DRIVERID */
-static const char *cx18_i2c_id_name(u32 id)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
- if (hw_driverids[i] == id)
- return hw_devicenames[i];
- return "unknown device";
-}
-
/* Find the i2c device name matching the CX18_HW_ flag */
static const char *cx18_i2c_hw_name(u32 hw)
{
@@ -352,21 +341,6 @@ int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg)
return cx18_call_i2c_client(cx, addr, cmd, arg);
}
-/* Calls i2c device based on I2C driver ID. */
-int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg)
-{
- int addr;
-
- addr = cx18_i2c_id_addr(cx, id);
- if (addr < 0) {
- if (cmd != VIDIOC_G_CHIP_IDENT)
- CX18_ERR("i2c ID 0x%08x (%s) not found for cmd 0x%x!\n",
- id, cx18_i2c_id_name(id), cmd);
- return addr;
- }
- return cx18_call_i2c_client(cx, addr, cmd, arg);
-}
-
/* broadcast cmd for all I2C clients and for the gpio subsystem */
void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg)
{
diff --git a/linux/drivers/media/video/cx18/cx18-i2c.h b/linux/drivers/media/video/cx18/cx18-i2c.h
index 113c3f9a2..486973901 100644
--- a/linux/drivers/media/video/cx18/cx18-i2c.h
+++ b/linux/drivers/media/video/cx18/cx18-i2c.h
@@ -23,7 +23,6 @@
int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw);
int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg);
-int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg);
int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg);
void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg);
int cx18_i2c_register(struct cx18 *cx, unsigned idx);
diff --git a/linux/drivers/media/video/cx18/cx18-io.h b/linux/drivers/media/video/cx18/cx18-io.h
index e6716dcb1..2635b3a8c 100644
--- a/linux/drivers/media/video/cx18/cx18-io.h
+++ b/linux/drivers/media/video/cx18/cx18-io.h
@@ -83,10 +83,14 @@ void cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr,
u32 eval, u32 mask)
{
int i;
+ u32 r;
eval &= mask;
for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) {
cx18_writel_noretry(cx, val, addr);
- if (eval == (cx18_readl(cx, addr) & mask))
+ r = cx18_readl(cx, addr);
+ if (r == 0xffffffff && eval != 0xffffffff)
+ continue;
+ if (eval == (r & mask))
break;
}
}
diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c
index 5d9c1146e..84d6381aa 100644
--- a/linux/drivers/media/video/cx18/cx18-ioctl.c
+++ b/linux/drivers/media/video/cx18/cx18-ioctl.c
@@ -284,13 +284,12 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
if (ret)
return ret;
- if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
- cx->vbi.sliced_in->service_set &&
- atomic_read(&cx->ana_capturing) > 0)
+ if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
cx->vbi.sliced_in->service_set = 0;
- cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+ cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
return cx18_g_fmt_vbi_cap(file, fh, fmt);
}
@@ -315,9 +314,9 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
if (check_service_set(vbifmt, cx->is_50hz) == 0)
return -EINVAL;
- if (atomic_read(&cx->ana_capturing) > 0 &&
- cx->vbi.sliced_in->service_set == 0)
+ if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
+ cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
return 0;
@@ -327,30 +326,24 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
}
static int cx18_g_chip_ident(struct file *file, void *fh,
- struct v4l2_chip_ident *chip)
+ struct v4l2_dbg_chip_ident *chip)
{
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
chip->ident = V4L2_IDENT_NONE;
chip->revision = 0;
- if (chip->match_type == V4L2_CHIP_MATCH_HOST) {
- if (v4l2_chip_match_host(chip->match_type, chip->match_chip))
- chip->ident = V4L2_IDENT_CX23418;
+ if (v4l2_chip_match_host(&chip->match)) {
+ chip->ident = V4L2_IDENT_CX23418;
return 0;
}
- if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return cx18_i2c_id(cx, chip->match_chip, VIDIOC_G_CHIP_IDENT,
- chip);
- if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
- return cx18_call_i2c_client(cx, chip->match_chip,
- VIDIOC_G_CHIP_IDENT, chip);
- return -EINVAL;
+ cx18_call_i2c_clients(cx, VIDIOC_DBG_G_CHIP_IDENT, chip);
+ return 0;
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
{
- struct v4l2_register *regs = arg;
+ struct v4l2_dbg_register *regs = arg;
unsigned long flags;
if (!capable(CAP_SYS_ADMIN))
@@ -359,6 +352,7 @@ static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
return -EINVAL;
spin_lock_irqsave(&cx18_cards_lock, flags);
+ regs->size = 4;
if (cmd == VIDIOC_DBG_G_REGISTER)
regs->val = cx18_read_enc(cx, regs->reg);
else
@@ -368,31 +362,25 @@ static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
}
static int cx18_g_register(struct file *file, void *fh,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (v4l2_chip_match_host(&reg->match))
return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
- reg);
- return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
- reg);
+ cx18_call_i2c_clients(cx, VIDIOC_DBG_G_REGISTER, reg);
+ return 0;
}
static int cx18_s_register(struct file *file, void *fh,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (v4l2_chip_match_host(&reg->match))
return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
- reg);
- return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
- reg);
+ cx18_call_i2c_clients(cx, VIDIOC_DBG_S_REGISTER, reg);
+ return 0;
}
#endif
@@ -851,8 +839,7 @@ static int cx18_log_status(struct file *file, void *fh)
continue;
CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
s->name, s->s_flags,
- (s->buffers - atomic_read(&s->q_free.buffers))
- * 100 / s->buffers,
+ atomic_read(&s->q_full.buffers) * 100 / s->buffers,
(s->buffers * s->buf_size) / 1024, s->buffers);
}
CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
@@ -862,7 +849,7 @@ static int cx18_log_status(struct file *file, void *fh)
return 0;
}
-static int cx18_default(struct file *file, void *fh, int cmd, void *arg)
+static long cx18_default(struct file *file, void *fh, int cmd, void *arg)
{
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
@@ -890,19 +877,19 @@ static int cx18_default(struct file *file, void *fh, int cmd, void *arg)
return 0;
}
-int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
struct video_device *vfd = video_devdata(filp);
struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
struct cx18 *cx = id->cx;
- int res;
+ long res;
mutex_lock(&cx->serialize_lock);
if (cx18_debug & CX18_DBGFLG_IOCTL)
vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
- res = video_ioctl2(inode, filp, cmd, arg);
+ res = video_ioctl2(filp, cmd, arg);
vfd->debug = 0;
mutex_unlock(&cx->serialize_lock);
return res;
diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.h b/linux/drivers/media/video/cx18/cx18-ioctl.h
index 08fe24e95..e2ca0d152 100644
--- a/linux/drivers/media/video/cx18/cx18-ioctl.h
+++ b/linux/drivers/media/video/cx18/cx18-ioctl.h
@@ -29,5 +29,5 @@ void cx18_set_funcs(struct video_device *vdev);
int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std);
int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
int cx18_s_input(struct file *file, void *fh, unsigned int inp);
-int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c
index 8415b9683..89a45f51f 100644
--- a/linux/drivers/media/video/cx18/cx18-mailbox.c
+++ b/linux/drivers/media/video/cx18/cx18-mailbox.c
@@ -82,8 +82,9 @@ static const struct cx18_api_info api_info[] = {
API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
- API_ENTRY(CPU, CX18_APU_RESETAI, API_FAST),
API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW),
+ API_ENTRY(APU, CX18_APU_RESETAI, 0),
+ API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32, 0),
API_ENTRY(0, 0, 0),
};
@@ -163,7 +164,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
* it's filled in).
*
* cx18_queue_get buf() will detect the lost buffers
- * and put them back in rotation eventually.
+ * and send them back to q_free for fw rotation eventually.
*/
if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) &&
!(id >= s->mdl_offset &&
@@ -174,33 +175,27 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
break;
}
buf = cx18_queue_get_buf(s, id, mdl_ack->data_used);
+
CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
if (buf == NULL) {
CX18_WARN("Could not find buf %d for stream %s\n",
id, s->name);
+ /* Put as many buffers as possible back into fw use */
+ cx18_stream_load_fw_queue(s);
continue;
}
- cx18_buf_sync_for_cpu(s, buf);
if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n",
buf->bytesused);
-
dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
buf->bytesused);
-
- cx18_buf_sync_for_device(s, buf);
- cx18_enqueue(s, buf, &s->q_free);
-
- if (s->handle != CX18_INVALID_TASK_HANDLE &&
- test_bit(CX18_F_S_STREAMING, &s->s_flags))
- cx18_vapi(cx,
- CX18_CPU_DE_SET_MDL, 5, s->handle,
- (void __iomem *)
- &cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
- 1, buf->id, s->buf_size);
- } else
- set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
+ }
+ /* Put as many buffers as possible back into fw use */
+ cx18_stream_load_fw_queue(s);
+ /* Put back TS buffer, since it was removed from all queues */
+ if (s->type == CX18_ENC_STREAM_TYPE_TS)
+ cx18_stream_put_buf_fw(s, buf);
}
wake_up(&cx->dma_waitq);
if (s->id != -1)
@@ -460,7 +455,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
*/
submit = epu_cmd_irq(cx, order);
if (submit > 0) {
- queue_work(cx18_work_queue, &order->work);
+ queue_work(cx->work_queue, &order->work);
}
}
@@ -618,8 +613,9 @@ static int cx18_set_filter_param(struct cx18_stream *s)
int cx18_api_func(void *priv, u32 cmd, int in, int out,
u32 data[CX2341X_MBOX_MAX_DATA])
{
- struct cx18 *cx = priv;
- struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+ struct cx18_api_func_private *api_priv = priv;
+ struct cx18 *cx = api_priv->cx;
+ struct cx18_stream *s = api_priv->s;
switch (cmd) {
case CX2341X_ENC_SET_OUTPUT_PORT:
diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.h b/linux/drivers/media/video/cx18/cx18-mailbox.h
index 35104458e..a667f1ae4 100644
--- a/linux/drivers/media/video/cx18/cx18-mailbox.h
+++ b/linux/drivers/media/video/cx18/cx18-mailbox.h
@@ -79,6 +79,13 @@ struct cx18_mailbox {
u32 error;
};
+struct cx18_stream;
+
+struct cx18_api_func_private {
+ struct cx18 *cx;
+ struct cx18_stream *s;
+};
+
int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]);
int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd,
int args, ...);
diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c
index 7b09c9a3e..8d9441e88 100644
--- a/linux/drivers/media/video/cx18/cx18-queue.c
+++ b/linux/drivers/media/video/cx18/cx18-queue.c
@@ -42,21 +42,33 @@ void cx18_queue_init(struct cx18_queue *q)
q->bytesused = 0;
}
-void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
- struct cx18_queue *q)
+struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q, int to_front)
{
- /* clear the buffer if it is going to be enqueued to the free queue */
- if (q == &s->q_free) {
+ /* clear the buffer if it is not to be enqueued to the full queue */
+ if (q != &s->q_full) {
buf->bytesused = 0;
buf->readpos = 0;
buf->b_flags = 0;
buf->skipped = 0;
}
+
mutex_lock(&s->qlock);
- list_add_tail(&buf->list, &q->list);
- atomic_inc(&q->buffers);
+
+ /* q_busy is restricted to a max buffer count imposed by firmware */
+ if (q == &s->q_busy &&
+ atomic_read(&q->buffers) >= CX18_MAX_FW_MDLS_PER_STREAM)
+ q = &s->q_free;
+
+ if (to_front)
+ list_add(&buf->list, &q->list); /* LIFO */
+ else
+ list_add_tail(&buf->list, &q->list); /* FIFO */
q->bytesused += buf->bytesused - buf->readpos;
+ atomic_inc(&q->buffers);
+
mutex_unlock(&s->qlock);
+ return q;
}
struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
@@ -65,11 +77,11 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
mutex_lock(&s->qlock);
if (!list_empty(&q->list)) {
- buf = list_entry(q->list.next, struct cx18_buffer, list);
- list_del_init(q->list.next);
- atomic_dec(&q->buffers);
+ buf = list_first_entry(&q->list, struct cx18_buffer, list);
+ list_del_init(&buf->list);
q->bytesused -= buf->bytesused - buf->readpos;
buf->skipped = 0;
+ atomic_dec(&q->buffers);
}
mutex_unlock(&s->qlock);
return buf;
@@ -80,61 +92,51 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
{
struct cx18 *cx = s->cx;
struct cx18_buffer *buf;
+ struct cx18_buffer *tmp;
struct cx18_buffer *ret = NULL;
- struct list_head *p, *t;
- LIST_HEAD(r);
mutex_lock(&s->qlock);
- list_for_each_safe(p, t, &s->q_free.list) {
- buf = list_entry(p, struct cx18_buffer, list);
-
+ list_for_each_entry_safe(buf, tmp, &s->q_busy.list, list) {
if (buf->id != id) {
buf->skipped++;
- if (buf->skipped >= atomic_read(&s->q_free.buffers)-1) {
+ if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) {
/* buffer must have fallen out of rotation */
- atomic_dec(&s->q_free.buffers);
- list_move_tail(&buf->list, &r);
CX18_WARN("Skipped %s, buffer %d, %d "
"times - it must have dropped out of "
"rotation\n", s->name, buf->id,
buf->skipped);
+ /* move it to q_free */
+ list_move_tail(&buf->list, &s->q_free.list);
+ buf->bytesused = buf->readpos = buf->b_flags =
+ buf->skipped = 0;
+ atomic_dec(&s->q_busy.buffers);
+ atomic_inc(&s->q_free.buffers);
}
continue;
}
buf->bytesused = bytesused;
- atomic_dec(&s->q_free.buffers);
+ /* Sync the buffer before we release the qlock */
+ cx18_buf_sync_for_cpu(s, buf);
if (s->type == CX18_ENC_STREAM_TYPE_TS) {
/*
- * TS doesn't use q_full, but for sweeping up lost
- * buffers, we want the TS to requeue the buffer just
- * before sending the MDL back to the firmware, so we
- * pull it off the list here.
+ * TS doesn't use q_full. As we pull the buffer off of
+ * the queue here, the caller will have to put it back.
*/
list_del_init(&buf->list);
} else {
- atomic_inc(&s->q_full.buffers);
- s->q_full.bytesused += buf->bytesused;
+ /* Move buffer from q_busy to q_full */
list_move_tail(&buf->list, &s->q_full.list);
+ set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
+ s->q_full.bytesused += buf->bytesused;
+ atomic_inc(&s->q_full.buffers);
}
+ atomic_dec(&s->q_busy.buffers);
ret = buf;
break;
}
mutex_unlock(&s->qlock);
-
- /* Put lost buffers back into firmware transfer rotation */
- while (!list_empty(&r)) {
- buf = list_entry(r.next, struct cx18_buffer, list);
- list_del_init(r.next);
- cx18_enqueue(s, buf, &s->q_free);
- cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
- (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
- 1, buf->id, s->buf_size);
- CX18_INFO("Returning %s, buffer %d back to transfer rotation\n",
- s->name, buf->id);
- /* and there was much rejoicing... */
- }
return ret;
}
@@ -148,8 +150,8 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
mutex_lock(&s->qlock);
while (!list_empty(&q->list)) {
- buf = list_entry(q->list.next, struct cx18_buffer, list);
- list_move_tail(q->list.next, &s->q_free.list);
+ buf = list_first_entry(&q->list, struct cx18_buffer, list);
+ list_move_tail(&buf->list, &s->q_free.list);
buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0;
atomic_inc(&s->q_free.buffers);
}
@@ -159,7 +161,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
void cx18_flush_queues(struct cx18_stream *s)
{
- cx18_queue_flush(s, &s->q_io);
+ cx18_queue_flush(s, &s->q_busy);
cx18_queue_flush(s, &s->q_full);
}
diff --git a/linux/drivers/media/video/cx18/cx18-queue.h b/linux/drivers/media/video/cx18/cx18-queue.h
index ff50a2b7e..456cec3bc 100644
--- a/linux/drivers/media/video/cx18/cx18-queue.h
+++ b/linux/drivers/media/video/cx18/cx18-queue.h
@@ -43,9 +43,24 @@ static inline void cx18_buf_sync_for_device(struct cx18_stream *s,
void cx18_buf_swap(struct cx18_buffer *buf);
/* cx18_queue utility functions */
+struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q, int to_front);
+
+static inline
+struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q)
+{
+ return _cx18_enqueue(s, buf, q, 0); /* FIFO */
+}
+
+static inline
+struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q)
+{
+ return _cx18_enqueue(s, buf, q, 1); /* LIFO */
+}
+
void cx18_queue_init(struct cx18_queue *q);
-void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
- struct cx18_queue *q);
struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
u32 bytesused);
diff --git a/linux/drivers/media/video/cx18/cx18-scb.c b/linux/drivers/media/video/cx18/cx18-scb.c
index ac18bd932..34b4d03c5 100644
--- a/linux/drivers/media/video/cx18/cx18-scb.c
+++ b/linux/drivers/media/video/cx18/cx18-scb.c
@@ -118,6 +118,5 @@ void cx18_init_scb(struct cx18 *cx)
cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu_state),
&cx->scb->ipc_offset);
- cx18_writel(cx, 1, &cx->scb->hpu_state);
cx18_writel(cx, 1, &cx->scb->epu_state);
}
diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c
index f7a7f38d8..5eb99ea7b 100644
--- a/linux/drivers/media/video/cx18/cx18-streams.c
+++ b/linux/drivers/media/video/cx18/cx18-streams.c
@@ -37,13 +37,12 @@
#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
-static struct file_operations cx18_v4l2_enc_fops = {
+static struct v4l2_file_operations cx18_v4l2_enc_fops = {
.owner = THIS_MODULE,
.read = cx18_v4l2_read,
.open = cx18_v4l2_open,
/* FIXME change to video_ioctl2 if serialization lock can be removed */
.ioctl = cx18_v4l2_ioctl,
- .compat_ioctl = v4l_compat_ioctl32,
.release = cx18_v4l2_close,
.poll = cx18_v4l2_enc_poll,
};
@@ -61,49 +60,41 @@ static struct {
int num_offset;
int dma;
enum v4l2_buf_type buf_type;
- struct file_operations *fops;
} cx18_stream_info[] = {
{ /* CX18_ENC_STREAM_TYPE_MPG */
"encoder MPEG",
VFL_TYPE_GRABBER, 0,
PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
- &cx18_v4l2_enc_fops
},
{ /* CX18_ENC_STREAM_TYPE_TS */
"TS",
VFL_TYPE_GRABBER, -1,
PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
- &cx18_v4l2_enc_fops
},
{ /* CX18_ENC_STREAM_TYPE_YUV */
"encoder YUV",
VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET,
PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
- &cx18_v4l2_enc_fops
},
{ /* CX18_ENC_STREAM_TYPE_VBI */
"encoder VBI",
VFL_TYPE_VBI, 0,
PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VBI_CAPTURE,
- &cx18_v4l2_enc_fops
},
{ /* CX18_ENC_STREAM_TYPE_PCM */
"encoder PCM audio",
VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET,
PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_PRIVATE,
- &cx18_v4l2_enc_fops
},
{ /* CX18_ENC_STREAM_TYPE_IDX */
"encoder IDX",
VFL_TYPE_GRABBER, -1,
PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
- &cx18_v4l2_enc_fops
},
{ /* CX18_ENC_STREAM_TYPE_RAD */
"encoder radio",
VFL_TYPE_RADIO, 0,
PCI_DMA_NONE, V4L2_BUF_TYPE_PRIVATE,
- &cx18_v4l2_enc_fops
},
};
@@ -111,7 +102,6 @@ static void cx18_stream_init(struct cx18 *cx, int type)
{
struct cx18_stream *s = &cx->streams[type];
struct video_device *dev = s->v4l2dev;
- u32 max_size = cx->options.megabytes[type] * 1024 * 1024;
/* we need to keep v4l2dev, so restore it afterwards */
memset(s, 0, sizeof(*s));
@@ -124,21 +114,15 @@ static void cx18_stream_init(struct cx18 *cx, int type)
s->handle = CX18_INVALID_TASK_HANDLE;
s->dma = cx18_stream_info[type].dma;
+ s->buffers = cx->stream_buffers[type];
s->buf_size = cx->stream_buf_size[type];
- if (s->buf_size)
- s->buffers = max_size / s->buf_size;
- if (s->buffers > 63) {
- /* Each stream has a maximum of 63 buffers,
- ensure we do not exceed that. */
- s->buffers = 63;
- s->buf_size = (max_size / s->buffers) & ~0xfff;
- }
+
mutex_init(&s->qlock);
init_waitqueue_head(&s->waitq);
s->id = -1;
cx18_queue_init(&s->q_free);
+ cx18_queue_init(&s->q_busy);
cx18_queue_init(&s->q_full);
- cx18_queue_init(&s->q_io);
}
static int cx18_prep_dev(struct cx18 *cx, int type)
@@ -168,7 +152,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
/* User explicitly selected 0 buffers for these streams, so don't
create them. */
if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
- cx->options.megabytes[type] == 0) {
+ cx->stream_buffers[type] == 0) {
CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name);
return 0;
}
@@ -191,7 +175,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
s->v4l2dev->num = num;
s->v4l2dev->parent = &cx->dev->dev;
- s->v4l2dev->fops = cx18_stream_info[type].fops;
+ s->v4l2dev->fops = &cx18_v4l2_enc_fops;
s->v4l2dev->release = video_device_release;
s->v4l2dev->tvnorms = V4L2_STD_ALL;
cx18_set_funcs(s->v4l2dev);
@@ -268,8 +252,9 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
switch (vfl_type) {
case VFL_TYPE_GRABBER:
- CX18_INFO("Registered device video%d for %s (%d MB)\n",
- num, s->name, cx->options.megabytes[type]);
+ CX18_INFO("Registered device video%d for %s (%d x %d kB)\n",
+ num, s->name, cx->stream_buffers[type],
+ cx->stream_buf_size[type]/1024);
break;
case VFL_TYPE_RADIO:
@@ -278,10 +263,11 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
break;
case VFL_TYPE_VBI:
- if (cx->options.megabytes[type])
- CX18_INFO("Registered device vbi%d for %s (%d MB)\n",
- num,
- s->name, cx->options.megabytes[type]);
+ if (cx->stream_buffers[type])
+ CX18_INFO("Registered device vbi%d for %s "
+ "(%d x %d bytes)\n",
+ num, s->name, cx->stream_buffers[type],
+ cx->stream_buf_size[type]);
else
CX18_INFO("Registered device vbi%d for %s\n",
num, s->name);
@@ -345,7 +331,7 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
static void cx18_vbi_setup(struct cx18_stream *s)
{
struct cx18 *cx = s->cx;
- int raw = cx->vbi.sliced_in->service_set == 0;
+ int raw = cx18_raw_vbi(cx);
u32 data[CX2341X_MBOX_MAX_DATA];
int lines;
@@ -363,8 +349,7 @@ static void cx18_vbi_setup(struct cx18_stream *s)
cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
/* determine number of lines and total number of VBI bytes.
- A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
- The '- 1' byte is probably an unused U or V byte. Or something...
+ A raw line takes 1444 bytes: 4 byte SAV code + 2 * 720
A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
header, 42 data bytes + checksum (to be confirmed) */
if (raw) {
@@ -382,14 +367,15 @@ static void cx18_vbi_setup(struct cx18_stream *s)
/* Lines per field */
data[1] = (lines / 2) | ((lines / 2) << 16);
/* bytes per line */
- data[2] = (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
+ data[2] = (raw ? cx->vbi.raw_decoder_line_size
+ : cx->vbi.sliced_decoder_line_size);
/* Every X number of frames a VBI interrupt arrives
(frames as in 25 or 30 fps) */
data[3] = 1;
/* Setup VBI for the cx25840 digitizer */
if (raw) {
data[4] = 0x20602060;
- data[5] = 0x30703070;
+ data[5] = 0x307090d0;
} else {
data[4] = 0xB0F0B0F0;
data[5] = 0xA0E0A0E0;
@@ -402,11 +388,52 @@ static void cx18_vbi_setup(struct cx18_stream *s)
cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
}
+struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
+ struct cx18_buffer *buf)
+{
+ struct cx18 *cx = s->cx;
+ struct cx18_queue *q;
+
+ /* Don't give it to the firmware, if we're not running a capture */
+ if (s->handle == CX18_INVALID_TASK_HANDLE ||
+ !test_bit(CX18_F_S_STREAMING, &s->s_flags))
+ return cx18_enqueue(s, buf, &s->q_free);
+
+ q = cx18_enqueue(s, buf, &s->q_busy);
+ if (q != &s->q_busy)
+ return q; /* The firmware has the max buffers it can handle */
+
+ cx18_buf_sync_for_device(s, buf);
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
+ (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ 1, buf->id, s->buf_size);
+ return q;
+}
+
+void cx18_stream_load_fw_queue(struct cx18_stream *s)
+{
+ struct cx18_queue *q;
+ struct cx18_buffer *buf;
+
+ if (atomic_read(&s->q_free.buffers) == 0 ||
+ atomic_read(&s->q_busy.buffers) >= CX18_MAX_FW_MDLS_PER_STREAM)
+ return;
+
+ /* Move from q_free to q_busy notifying the firmware, until the limit */
+ do {
+ buf = cx18_dequeue(s, &s->q_free);
+ if (buf == NULL)
+ break;
+ q = cx18_stream_put_buf_fw(s, buf);
+ } while (atomic_read(&s->q_busy.buffers) < CX18_MAX_FW_MDLS_PER_STREAM
+ && q == &s->q_busy);
+}
+
int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
{
u32 data[MAX_MB_ARGUMENTS];
struct cx18 *cx = s->cx;
- struct list_head *p;
+ struct cx18_buffer *buf;
int ts = 0;
int captype = 0;
@@ -435,8 +462,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
captype = CAPTURE_CHANNEL_TYPE_PCM;
break;
case CX18_ENC_STREAM_TYPE_VBI:
- captype = cx->vbi.sliced_in->service_set ?
- CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI;
+ captype = cx18_raw_vbi(cx) ?
+ CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI;
cx->vbi.frame = 0;
cx->vbi.inserted_frame = 0;
memset(cx->vbi.sliced_mpeg_size,
@@ -458,6 +485,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
if (atomic_read(&cx->ana_capturing) == 0 && !ts) {
+ struct cx18_api_func_private priv;
+
/* Stuff from Windows, we don't know what it is */
cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
@@ -477,7 +506,9 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0);
/* Setup API for Stream */
- cx2341x_update(cx, cx18_api_func, NULL, &cx->params);
+ priv.cx = cx;
+ priv.s = s;
+ cx2341x_update(&priv, cx18_api_func, NULL, &cx->params);
}
if (atomic_read(&cx->tot_capturing) == 0) {
@@ -489,16 +520,17 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
(void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
(void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
- list_for_each(p, &s->q_free.list) {
- struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list);
-
+ /* Init all the cpu_mdls for this stream */
+ cx18_flush_queues(s);
+ mutex_lock(&s->qlock);
+ list_for_each_entry(buf, &s->q_free.list, list) {
cx18_writel(cx, buf->dma_handle,
&cx->scb->cpu_mdl[buf->id].paddr);
cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
- cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
- (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
- 1, buf->id, s->buf_size);
}
+ mutex_unlock(&s->qlock);
+ cx18_stream_load_fw_queue(s);
+
/* begin_capture */
if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
CX18_DEBUG_WARN("Error starting capture!\n");
@@ -507,9 +539,15 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1);
else
cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
+ clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+ /* FIXME - CX18_F_S_STREAMOFF as well? */
cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
- /* FIXME - clean-up DSP0_INT mask, i_flags, s_flags, etc. */
+ s->handle = CX18_INVALID_TASK_HANDLE;
+ if (atomic_read(&cx->tot_capturing) == 0) {
+ set_bit(CX18_F_I_EOS, &cx->i_flags);
+ cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
+ }
return -EINVAL;
}
diff --git a/linux/drivers/media/video/cx18/cx18-streams.h b/linux/drivers/media/video/cx18/cx18-streams.h
index 7218b1504..420e0a172 100644
--- a/linux/drivers/media/video/cx18/cx18-streams.h
+++ b/linux/drivers/media/video/cx18/cx18-streams.h
@@ -29,6 +29,9 @@ int cx18_streams_register(struct cx18 *cx);
void cx18_streams_cleanup(struct cx18 *cx, int unregister);
/* Capture related */
+void cx18_stream_load_fw_queue(struct cx18_stream *s);
+struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
+ struct cx18_buffer *buf);
int cx18_start_v4l2_encode_stream(struct cx18_stream *s);
int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end);
diff --git a/linux/drivers/media/video/cx18/cx18-vbi.c b/linux/drivers/media/video/cx18/cx18-vbi.c
index 22e76ee3f..fb595bd54 100644
--- a/linux/drivers/media/video/cx18/cx18-vbi.c
+++ b/linux/drivers/media/video/cx18/cx18-vbi.c
@@ -160,11 +160,14 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
return;
/* Raw VBI data */
- if (cx->vbi.sliced_in->service_set == 0) {
+ if (cx18_raw_vbi(cx)) {
u8 type;
cx18_buf_swap(buf);
+ /* Skip 12 bytes of header that gets stuffed in */
+ size -= 12;
+ memcpy(p, &buf->buf[12], size);
type = p[3];
size = buf->bytesused = compress_raw_buf(cx, p, size);
diff --git a/linux/drivers/media/video/cx18/cx18-version.h b/linux/drivers/media/video/cx18/cx18-version.h
index eb043d599..84c0ff13b 100644
--- a/linux/drivers/media/video/cx18/cx18-version.h
+++ b/linux/drivers/media/video/cx18/cx18-version.h
@@ -25,7 +25,7 @@
#define CX18_DRIVER_NAME "cx18"
#define CX18_DRIVER_VERSION_MAJOR 1
#define CX18_DRIVER_VERSION_MINOR 0
-#define CX18_DRIVER_VERSION_PATCHLEVEL 3
+#define CX18_DRIVER_VERSION_PATCHLEVEL 4
#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
diff --git a/linux/drivers/media/video/cx18/cx23418.h b/linux/drivers/media/video/cx18/cx23418.h
index 668f968d7..601f3a2ab 100644
--- a/linux/drivers/media/video/cx18/cx23418.h
+++ b/linux/drivers/media/video/cx18/cx23418.h
@@ -44,6 +44,7 @@
/* All commands for CPU have the following mask set */
#define CPU_CMD_MASK 0x20000000
+#define CPU_CMD_MASK_DEBUG (CPU_CMD_MASK | 0x00000000)
#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000)
#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000)
#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000)
@@ -71,6 +72,11 @@
0/zero/NULL means "I have nothing to say" */
#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003)
+/* Reads memory/registers (32-bit)
+ IN[0] - Address
+ OUT[1] - Value */
+#define CX18_CPU_DEBUG_PEEK32 (CPU_CMD_MASK_DEBUG | 0x0003)
+
/* Description: This command starts streaming with the set channel type
IN[0] - Task handle. Handle of the task to start
ReturnCode - One of the ERR_CAPTURE_... */
diff --git a/linux/drivers/media/video/cx23885/Kconfig b/linux/drivers/media/video/cx23885/Kconfig
index 8c1b7fa47..00f1e2e88 100644
--- a/linux/drivers/media/video/cx23885/Kconfig
+++ b/linux/drivers/media/video/cx23885/Kconfig
@@ -11,16 +11,16 @@ config VIDEO_CX23885
select VIDEO_CX25840
select VIDEO_CX2341X
select DVB_DIB7000P if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMIZE
select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
- select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
---help---
This is a video4linux driver for Conexant 23885 based
TV cards.
diff --git a/linux/drivers/media/video/cx23885/cx23885-417.c b/linux/drivers/media/video/cx23885/cx23885-417.c
index dfe8ddbce..52f6824ff 100644
--- a/linux/drivers/media/video/cx23885/cx23885-417.c
+++ b/linux/drivers/media/video/cx23885/cx23885-417.c
@@ -1027,12 +1027,13 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev)
printk(KERN_ERR "%s() f/w load failed\n", __func__);
return retval;
}
- dev->cx23417_mailbox = cx23885_find_mailbox(dev);
- if (dev->cx23417_mailbox < 0) {
+ retval = cx23885_find_mailbox(dev);
+ if (retval < 0) {
printk(KERN_ERR "%s() mailbox < 0, error\n",
__func__);
return -1;
}
+ dev->cx23417_mailbox = retval;
retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
if (retval < 0) {
printk(KERN_ERR
@@ -1581,9 +1582,9 @@ static int vidioc_queryctrl(struct file *file, void *priv,
return cx23885_queryctrl(dev, c);
}
-static int mpeg_open(struct inode *inode, struct file *file)
+static int mpeg_open(struct file *file)
{
- int minor = iminor(inode);
+ int minor = video_devdata(file)->minor;
struct cx23885_dev *h, *dev = NULL;
struct list_head *list;
struct cx23885_fh *fh;
@@ -1625,7 +1626,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
return 0;
}
-static int mpeg_release(struct inode *inode, struct file *file)
+static int mpeg_release(struct file *file)
{
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
@@ -1702,15 +1703,13 @@ static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
return videobuf_mmap_mapper(&fh->mpegq, vma);
}
-static struct file_operations mpeg_fops = {
+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,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c
index dc3f79638..db1e8bdab 100644
--- a/linux/drivers/media/video/cx23885/cx23885-cards.c
+++ b/linux/drivers/media/video/cx23885/cx23885-cards.c
@@ -159,6 +159,10 @@ struct cx23885_board cx23885_boards[] = {
.name = "Leadtek Winfast PxDVR3200 H",
.portc = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = {
+ .name = "Compro VideoMate E650F",
+ .portc = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -238,6 +242,10 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x107d,
.subdevice = 0x6681,
.card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H,
+ }, {
+ .subvendor = 0x185b,
+ .subdevice = 0xe800,
+ .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -391,6 +399,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
/* Tuner Reset Command */
bitmask = 0x04;
break;
@@ -531,6 +540,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
cx_set(GP0_IO, 0x000f000f);
break;
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
/* GPIO-2 xc3028 tuner reset */
/* The following GPIO's are on the internal AVCore (cx25840) */
@@ -631,6 +641,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1700:
case CX23885_BOARD_HAUPPAUGE_HVR1400:
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
default:
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
@@ -645,6 +656,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
case CX23885_BOARD_HAUPPAUGE_HVR1700:
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
request_module("cx25840");
break;
}
diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c
index a11fdbfb5..990fd217b 100644
--- a/linux/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c
@@ -503,6 +503,7 @@ static int dvb_register(struct cx23885_tsport *port)
break;
}
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
i2c_bus = &dev->i2c_bus[0];
fe0->dvb.frontend = dvb_attach(zl10353_attach,
diff --git a/linux/drivers/media/video/cx23885/cx23885-i2c.c b/linux/drivers/media/video/cx23885/cx23885-i2c.c
index ced5648d8..2210b47d2 100644
--- a/linux/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/linux/drivers/media/video/cx23885/cx23885-i2c.c
@@ -353,6 +353,9 @@ static u32 cx23885_functionality(struct i2c_adapter *adap)
static struct i2c_algorithm cx23885_i2c_algo_template = {
.master_xfer = i2c_xfer,
.functionality = cx23885_functionality,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
/* ----------------------------------------------------------------------- */
diff --git a/linux/drivers/media/video/cx23885/cx23885-video.c b/linux/drivers/media/video/cx23885/cx23885-video.c
index 0b5d20481..838b3ac5a 100644
--- a/linux/drivers/media/video/cx23885/cx23885-video.c
+++ b/linux/drivers/media/video/cx23885/cx23885-video.c
@@ -774,9 +774,9 @@ static int get_resource(struct cx23885_fh *fh)
}
}
-static int video_open(struct inode *inode, struct file *file)
+static int video_open(struct file *file)
{
- int minor = iminor(inode);
+ int minor = video_devdata(file)->minor;
struct cx23885_dev *h, *dev = NULL;
struct cx23885_fh *fh;
struct list_head *list;
@@ -905,7 +905,7 @@ static unsigned int video_poll(struct file *file,
return 0;
}
-static int video_release(struct inode *inode, struct file *file)
+static int video_release(struct file *file)
{
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
@@ -1415,11 +1415,11 @@ static int vidioc_s_frequency(struct file *file, void *priv,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register(struct file *file, void *fh,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg);
@@ -1428,11 +1428,11 @@ static int vidioc_g_register(struct file *file, void *fh,
}
static int vidioc_s_register(struct file *file, void *fh,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg);
@@ -1630,7 +1630,7 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
/* ----------------------------------------------------------- */
/* exported stuff */
-static const struct file_operations video_fops = {
+static const struct v4l2_file_operations video_fops = {
.owner = THIS_MODULE,
.open = video_open,
.release = video_release,
@@ -1638,8 +1638,6 @@ static const struct file_operations video_fops = {
.poll = video_poll,
.mmap = video_mmap,
.ioctl = video_ioctl2,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -1687,13 +1685,11 @@ static struct video_device cx23885_video_template = {
.current_norm = V4L2_STD_NTSC_M,
};
-static const struct file_operations radio_fops = {
+static const struct v4l2_file_operations radio_fops = {
.owner = THIS_MODULE,
.open = video_open,
.release = video_release,
.ioctl = video_ioctl2,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
};
#if 0
diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h
index 26f755354..ad93e0e88 100644
--- a/linux/drivers/media/video/cx23885/cx23885.h
+++ b/linux/drivers/media/video/cx23885/cx23885.h
@@ -67,6 +67,7 @@
#define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10
#define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11
#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12
+#define CX23885_BOARD_COMPRO_VIDEOMATE_E650F 13
/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
#define CX23885_NORMS (\
diff --git a/linux/drivers/media/video/cx25840/cx25840-audio.c b/linux/drivers/media/video/cx25840/cx25840-audio.c
index 8e134312c..3ee7d7a7d 100644
--- a/linux/drivers/media/video/cx25840/cx25840-audio.c
+++ b/linux/drivers/media/video/cx25840/cx25840-audio.c
@@ -26,7 +26,7 @@
static int set_audclk_freq(struct i2c_client *client, u32 freq)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
if (freq != 32000 && freq != 44100 && freq != 48000)
return -EINVAL;
@@ -194,7 +194,7 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
void cx25840_audio_set_path(struct i2c_client *client)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
/* assert soft reset */
cx25840_and_or(client, 0x810, ~0x1, 0x01);
@@ -236,7 +236,7 @@ void cx25840_audio_set_path(struct i2c_client *client)
static int get_volume(struct i2c_client *client)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
int vol;
if (state->unmute_volume >= 0)
@@ -253,7 +253,7 @@ static int get_volume(struct i2c_client *client)
static void set_volume(struct i2c_client *client, int volume)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
int vol;
if (state->unmute_volume >= 0) {
@@ -341,14 +341,14 @@ static void set_balance(struct i2c_client *client, int balance)
static int get_mute(struct i2c_client *client)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
return state->unmute_volume >= 0;
}
static void set_mute(struct i2c_client *client, int mute)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
if (mute && state->unmute_volume == -1) {
int vol = get_volume(client);
@@ -366,7 +366,7 @@ static void set_mute(struct i2c_client *client, int mute)
int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
struct v4l2_control *ctrl = arg;
int retval;
diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c
index cb4a9c64e..9bac0e67a 100644
--- a/linux/drivers/media/video/cx25840/cx25840-core.c
+++ b/linux/drivers/media/video/cx25840/cx25840-core.c
@@ -198,7 +198,7 @@ void cx25840_work_handler(void *arg)
static void cx25840_initialize(struct i2c_client *client)
{
DEFINE_WAIT(wait);
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
struct workqueue_struct *q;
/* datasheet startup in numbered steps, refer to page 3-77 */
@@ -270,7 +270,7 @@ static void cx25840_initialize(struct i2c_client *client)
static void cx23885_initialize(struct i2c_client *client)
{
DEFINE_WAIT(wait);
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
struct workqueue_struct *q;
/* Internal Reset */
@@ -369,7 +369,7 @@ static void cx23885_initialize(struct i2c_client *client)
void cx25840_std_setup(struct i2c_client *client)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
v4l2_std_id std = state->std;
int hblank, hactive, burst, vblank, vactive, sc;
int vblank656, src_decimation;
@@ -516,7 +516,7 @@ void cx25840_std_setup(struct i2c_client *client)
static void input_change(struct i2c_client *client)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
v4l2_std_id std = state->std;
/* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */
@@ -570,7 +570,7 @@ static void input_change(struct i2c_client *client)
static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
enum cx25840_audio_input aud_input)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
u8 is_composite = (vid_input >= CX25840_COMPOSITE1 &&
vid_input <= CX25840_COMPOSITE8);
u8 reg;
@@ -690,7 +690,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
static int set_v4lstd(struct i2c_client *client)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
u8 fmt = 0; /* zero is autodetect */
u8 pal_m = 0;
@@ -739,9 +739,10 @@ static int set_v4lstd(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
-static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
switch (ctrl->id) {
case CX25840_CID_ENABLE_PVR150_WORKAROUND:
@@ -805,9 +806,10 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
return 0;
}
-static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
switch (ctrl->id) {
case CX25840_CID_ENABLE_PVR150_WORKAROUND:
@@ -842,21 +844,23 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
/* ----------------------------------------------------------------------- */
-static int get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
switch (fmt->type) {
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
return cx25840_vbi(client, VIDIOC_G_FMT, fmt);
default:
return -EINVAL;
}
-
return 0;
}
-static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct v4l2_pix_format *pix;
int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
int is_50Hz = !(state->std & V4L2_STD_525_60);
@@ -933,7 +937,7 @@ static void log_video_status(struct i2c_client *client)
"0xD", "0xE", "0xF"
};
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
u8 gen_stat1 = cx25840_read(client, 0x40d);
u8 gen_stat2 = cx25840_read(client, 0x40e);
@@ -963,7 +967,7 @@ static void log_video_status(struct i2c_client *client)
static void log_audio_status(struct i2c_client *client)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
u8 download_ctl = cx25840_read(client, 0x803);
u8 mod_det_stat0 = cx25840_read(client, 0x804);
u8 mod_det_stat1 = cx25840_read(client, 0x805);
@@ -1116,21 +1120,12 @@ static void log_audio_status(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
-static int cx25840_command(struct i2c_client *client, unsigned int cmd,
- void *arg)
+static int cx25840_init(struct v4l2_subdev *sd, u32 val)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
- struct v4l2_tuner *vt = arg;
- struct v4l2_routing *route = arg;
-
- /* ignore these commands */
- switch (cmd) {
- case TUNER_SET_TYPE_ADDR:
- return 0;
- }
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (!state->is_initialized) {
- v4l_dbg(1, cx25840_debug, client, "cmd %08x triggered fw load\n", cmd);
/* initialize on first use */
state->is_initialized = 1;
if (state->is_cx25836)
@@ -1140,50 +1135,68 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
else
cx25840_initialize(client);
}
+ return 0;
+}
- switch (cmd) {
#ifdef CONFIG_VIDEO_ADV_DEBUG
- /* ioctls to allow direct access to the
- * cx25840 registers for testing */
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
+static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (cmd == VIDIOC_DBG_G_REGISTER)
- reg->val = cx25840_read(client, reg->reg & 0x0fff);
- else
- cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
- break;
- }
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->size = 1;
+ reg->val = cx25840_read(client, reg->reg & 0x0fff);
+ return 0;
+}
+
+static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
+ return 0;
+}
#endif
- case VIDIOC_INT_DECODE_VBI_LINE:
- return cx25840_vbi(client, cmd, arg);
+static int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- return cx25840_audio(client, cmd, arg);
+ return cx25840_vbi(client, VIDIOC_INT_DECODE_VBI_LINE, vbi);
+}
+
+static int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return cx25840_audio(client, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freq);
+}
+
+static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_STREAMON:
- v4l_dbg(1, cx25840_debug, client, "enable output\n");
+ v4l_dbg(1, cx25840_debug, client, "%s output\n",
+ enable ? "enable" : "disable");
+ if (enable) {
if (state->is_cx23885) {
u8 v = (cx25840_read(client, 0x421) | 0x0b);
cx25840_write(client, 0x421, v);
} else {
cx25840_write(client, 0x115,
- state->is_cx25836 ? 0x0c : 0x8c);
+ state->is_cx25836 ? 0x0c : 0x8c);
cx25840_write(client, 0x116,
- state->is_cx25836 ? 0x04 : 0x07);
+ state->is_cx25836 ? 0x04 : 0x07);
}
- break;
-
- case VIDIOC_STREAMOFF:
- v4l_dbg(1, cx25840_debug, client, "disable output\n");
+ } else {
if (state->is_cx23885) {
u8 v = cx25840_read(client, 0x421) & ~(0x0b);
cx25840_write(client, 0x421, v);
@@ -1191,133 +1204,136 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
cx25840_write(client, 0x115, 0x00);
cx25840_write(client, 0x116, 0x00);
}
- break;
+ }
+ return 0;
+}
- case VIDIOC_LOG_STATUS:
- log_video_status(client);
- if (!state->is_cx25836)
- log_audio_status(client);
- break;
+static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ struct cx25840_state *state = to_state(sd);
- case VIDIOC_G_CTRL:
- return get_v4lctrl(client, (struct v4l2_control *)arg);
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ break;
+ }
+ if (state->is_cx25836)
+ return -EINVAL;
- case VIDIOC_S_CTRL:
- return set_v4lctrl(client, (struct v4l2_control *)arg);
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ return v4l2_ctrl_query_fill(qc, 0, 65535,
+ 65535 / 100, state->default_volume);
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
+static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- case V4L2_CID_CONTRAST:
- case V4L2_CID_SATURATION:
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill_std(qc);
- default:
- break;
- }
- if (state->is_cx25836)
- return -EINVAL;
+ if (state->radio == 0 && state->std == std)
+ return 0;
+ state->radio = 0;
+ state->std = std;
+ return set_v4lstd(client);
+}
- switch (qc->id) {
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 65535,
- 65535 / 100, state->default_volume);
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill_std(qc);
- default:
- return -EINVAL;
- }
- return -EINVAL;
- }
+static int cx25840_s_radio(struct v4l2_subdev *sd)
+{
+ struct cx25840_state *state = to_state(sd);
- case VIDIOC_G_STD:
- *(v4l2_std_id *)arg = state->std;
- break;
+ state->radio = 1;
+ return 0;
+}
- case VIDIOC_S_STD:
- if (state->radio == 0 && state->std == *(v4l2_std_id *)arg)
- return 0;
- state->radio = 0;
- state->std = *(v4l2_std_id *)arg;
- return set_v4lstd(client);
+static int cx25840_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case AUDC_SET_RADIO:
- state->radio = 1;
- break;
+ return set_input(client, route->input, state->aud_input);
+}
- case VIDIOC_INT_G_VIDEO_ROUTING:
- route->input = state->vid_input;
- route->output = 0;
- break;
+static int cx25840_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_INT_S_VIDEO_ROUTING:
- return set_input(client, route->input, state->aud_input);
+ if (state->is_cx25836)
+ return -EINVAL;
+ return set_input(client, state->vid_input, route->input);
+}
- case VIDIOC_INT_G_AUDIO_ROUTING:
- if (state->is_cx25836)
- return -EINVAL;
- route->input = state->aud_input;
- route->output = 0;
- break;
+static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_INT_S_AUDIO_ROUTING:
- if (state->is_cx25836)
- return -EINVAL;
- return set_input(client, state->vid_input, route->input);
+ if (!state->is_cx25836)
+ input_change(client);
+ return 0;
+}
- case VIDIOC_S_FREQUENCY:
- if (!state->is_cx25836) {
- input_change(client);
- }
- break;
+static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 vpres = cx25840_read(client, 0x40e) & 0x20;
+ u8 mode;
+ int val = 0;
- case VIDIOC_G_TUNER:
- {
- u8 vpres = cx25840_read(client, 0x40e) & 0x20;
- u8 mode;
- int val = 0;
+ if (state->radio)
+ return 0;
- if (state->radio)
- break;
+ vt->signal = vpres ? 0xffff : 0x0;
+ if (state->is_cx25836)
+ return 0;
- vt->signal = vpres ? 0xffff : 0x0;
- if (state->is_cx25836)
- break;
+ vt->capability |=
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+ V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
- vt->capability |=
- V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
- V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+ mode = cx25840_read(client, 0x804);
- mode = cx25840_read(client, 0x804);
+ /* get rxsubchans and audmode */
+ if ((mode & 0xf) == 1)
+ val |= V4L2_TUNER_SUB_STEREO;
+ else
+ val |= V4L2_TUNER_SUB_MONO;
- /* get rxsubchans and audmode */
- if ((mode & 0xf) == 1)
- val |= V4L2_TUNER_SUB_STEREO;
- else
- val |= V4L2_TUNER_SUB_MONO;
+ if (mode == 2 || mode == 4)
+ val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
- if (mode == 2 || mode == 4)
- val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+ if (mode & 0x10)
+ val |= V4L2_TUNER_SUB_SAP;
- if (mode & 0x10)
- val |= V4L2_TUNER_SUB_SAP;
+ vt->rxsubchans = val;
+ vt->audmode = state->audmode;
+ return 0;
+}
- vt->rxsubchans = val;
- vt->audmode = state->audmode;
- break;
- }
+static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_S_TUNER:
- if (state->radio || state->is_cx25836)
- break;
+ if (state->radio || state->is_cx25836)
+ return 0;
- switch (vt->audmode) {
+ switch (vt->audmode) {
case V4L2_TUNER_MODE_MONO:
/* mono -> mono
stereo -> mono
@@ -1345,41 +1361,100 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
break;
default:
return -EINVAL;
- }
- state->audmode = vt->audmode;
- break;
+ }
+ state->audmode = vt->audmode;
+ return 0;
+}
- case VIDIOC_G_FMT:
- return get_v4lfmt(client, (struct v4l2_format *)arg);
+static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_S_FMT:
- return set_v4lfmt(client, (struct v4l2_format *)arg);
+ if (state->is_cx25836)
+ cx25836_initialize(client);
+ else if (state->is_cx23885)
+ cx23885_initialize(client);
+ else
+ cx25840_initialize(client);
+ return 0;
+}
- case VIDIOC_INT_RESET:
- if (state->is_cx25836)
- cx25836_initialize(client);
- else if (state->is_cx23885)
- cx23885_initialize(client);
- else
- cx25840_initialize(client);
- break;
+static int cx25840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client, arg, state->id, state->rev);
+ return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
+}
- default:
- return -EINVAL;
- }
+static int cx25840_log_status(struct v4l2_subdev *sd)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ log_video_status(client);
+ if (!state->is_cx25836)
+ log_audio_status(client);
return 0;
}
+static int cx25840_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops cx25840_core_ops = {
+ .log_status = cx25840_log_status,
+ .g_chip_ident = cx25840_g_chip_ident,
+ .g_ctrl = cx25840_g_ctrl,
+ .s_ctrl = cx25840_s_ctrl,
+ .queryctrl = cx25840_queryctrl,
+ .reset = cx25840_reset,
+ .init = cx25840_init,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = cx25840_g_register,
+ .s_register = cx25840_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
+ .s_frequency = cx25840_s_frequency,
+ .s_std = cx25840_s_std,
+ .s_radio = cx25840_s_radio,
+ .g_tuner = cx25840_g_tuner,
+ .s_tuner = cx25840_s_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
+ .s_clock_freq = cx25840_s_clock_freq,
+ .s_routing = cx25840_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops cx25840_video_ops = {
+ .s_routing = cx25840_s_video_routing,
+ .g_fmt = cx25840_g_fmt,
+ .s_fmt = cx25840_s_fmt,
+ .decode_vbi_line = cx25840_decode_vbi_line,
+ .s_stream = cx25840_s_stream,
+};
+
+static const struct v4l2_subdev_ops cx25840_ops = {
+ .core = &cx25840_core_ops,
+ .tuner = &cx25840_tuner_ops,
+ .audio = &cx25840_audio_ops,
+ .video = &cx25840_video_ops,
+};
+
/* ----------------------------------------------------------------------- */
static int cx25840_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct cx25840_state *state;
+ struct v4l2_subdev *sd;
u32 id;
u16 device_id;
@@ -1411,10 +1486,11 @@ static int cx25840_probe(struct i2c_client *client,
}
state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
- if (state == NULL) {
+ if (state == NULL)
return -ENOMEM;
- }
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
/* Note: revision '(device_id & 0x0f) == 2' was never built. The
marking skips from 0x1 == 22 to 0x3 == 23. */
v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
@@ -1422,7 +1498,6 @@ static int cx25840_probe(struct i2c_client *client,
(device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f),
client->addr << 1, client->adapter->name);
- i2c_set_clientdata(client, state);
state->c = client;
state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313);
@@ -1449,7 +1524,10 @@ static int cx25840_probe(struct i2c_client *client,
static int cx25840_remove(struct i2c_client *client)
{
- kfree(i2c_get_clientdata(client));
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
return 0;
}
diff --git a/linux/drivers/media/video/cx25840/cx25840-core.h b/linux/drivers/media/video/cx25840/cx25840-core.h
index cd549b119..0a99c19df 100644
--- a/linux/drivers/media/video/cx25840/cx25840-core.h
+++ b/linux/drivers/media/video/cx25840/cx25840-core.h
@@ -23,6 +23,7 @@
#include "compat.h"
#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
#include <linux/i2c.h>
/* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
@@ -35,6 +36,7 @@
struct cx25840_state {
struct i2c_client *c;
+ struct v4l2_subdev sd;
int pvr150_workaround;
int radio;
v4l2_std_id std;
@@ -54,6 +56,11 @@ struct cx25840_state {
struct work_struct fw_work; /* work entry for fw load */
};
+static inline struct cx25840_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct cx25840_state, sd);
+}
+
/* ----------------------------------------------------------------------- */
/* cx25850-core.c */
int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
diff --git a/linux/drivers/media/video/cx25840/cx25840-firmware.c b/linux/drivers/media/video/cx25840/cx25840-firmware.c
index 04a5dbb65..01fbe174e 100644
--- a/linux/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/linux/drivers/media/video/cx25840/cx25840-firmware.c
@@ -92,7 +92,7 @@ static int fw_write(struct i2c_client *client, const u8 *data, int size)
int cx25840_loadfw(struct i2c_client *client)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
const struct firmware *fw = NULL;
u8 buffer[FWSEND];
const u8 *ptr;
diff --git a/linux/drivers/media/video/cx25840/cx25840-vbi.c b/linux/drivers/media/video/cx25840/cx25840-vbi.c
index e45c39625..7790afd5b 100644
--- a/linux/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/linux/drivers/media/video/cx25840/cx25840-vbi.c
@@ -85,7 +85,7 @@ static int decode_vps(u8 * dst, u8 * p)
int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
{
- struct cx25840_state *state = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
struct v4l2_format *fmt;
struct v4l2_sliced_vbi_format *svbi;
diff --git a/linux/drivers/media/video/cx88/Kconfig b/linux/drivers/media/video/cx88/Kconfig
index 0b9e5fac6..b0f837588 100644
--- a/linux/drivers/media/video/cx88/Kconfig
+++ b/linux/drivers/media/video/cx88/Kconfig
@@ -56,12 +56,12 @@ config VIDEO_CX88_DVB
select DVB_NXT200X if !DVB_FE_CUSTOMISE
select DVB_CX24123 if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
select DVB_CX24116 if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_STV0288 if !DVB_FE_CUSTOMISE
select DVB_STB6000 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
---help---
This adds support for DVB/ATSC cards based on the
Conexant 2388x chip.
diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c
index 3dd2f6629..f7171586d 100644
--- a/linux/drivers/media/video/cx88/cx88-alsa.c
+++ b/linux/drivers/media/video/cx88/cx88-alsa.c
@@ -795,7 +795,6 @@ static int __devinit snd_cx88_create(struct snd_card *card,
core = cx88_core_get(pci);
if (NULL == core) {
err = -EINVAL;
- kfree (chip);
return err;
}
@@ -872,7 +871,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
err = snd_cx88_create(card, pci, &chip);
if (err < 0)
- return (err);
+ goto error;
err = snd_cx88_pcm(chip, 0, "CX88 Digital");
if (err < 0)
diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c
index b090c6620..46e009403 100644
--- a/linux/drivers/media/video/cx88/cx88-blackbird.c
+++ b/linux/drivers/media/video/cx88/cx88-blackbird.c
@@ -1068,16 +1068,16 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
/* FIXME: cx88_ioctl_hook not implemented */
-static int mpeg_open(struct inode *inode, struct file *file)
+static int mpeg_open(struct file *file)
{
- int minor = iminor(inode);
+ int minor = video_devdata(file)->minor;
struct cx8802_dev *dev = NULL;
struct cx8802_fh *fh;
struct cx8802_driver *drv = NULL;
int err;
lock_kernel();
- dev = cx8802_get_device(inode);
+ dev = cx8802_get_device(minor);
dprintk( 1, "%s\n", __func__);
@@ -1133,7 +1133,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
return 0;
}
-static int mpeg_release(struct inode *inode, struct file *file)
+static int mpeg_release(struct file *file)
{
struct cx8802_fh *fh = file->private_data;
struct cx8802_dev *dev = fh->dev;
@@ -1151,7 +1151,7 @@ static int mpeg_release(struct inode *inode, struct file *file)
kfree(fh);
/* Make sure we release the hardware */
- dev = cx8802_get_device(inode);
+ dev = cx8802_get_device(video_devdata(file)->minor);
if (dev == NULL)
return -ENODEV;
@@ -1197,7 +1197,7 @@ mpeg_mmap(struct file *file, struct vm_area_struct * vma)
return videobuf_mmap_mapper(&fh->mpegq, vma);
}
-static const struct file_operations mpeg_fops =
+static const struct v4l2_file_operations mpeg_fops =
{
.owner = THIS_MODULE,
.open = mpeg_open,
@@ -1206,7 +1206,6 @@ static const struct file_operations mpeg_fops =
.poll = mpeg_poll,
.mmap = mpeg_mmap,
.ioctl = video_ioctl2,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
@@ -1263,8 +1262,16 @@ static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv)
* We're being given access to re-arrange the GPIOs.
* Take the bus off the cx22702 and put the cx23416 on it.
*/
- cx_clear(MO_GP0_IO, 0x00000080); /* cx22702 in reset */
- cx_set(MO_GP0_IO, 0x00000004); /* Disable the cx22702 */
+ /* Toggle reset on cx22702 leaving i2c active */
+ cx_set(MO_GP0_IO, 0x00000080);
+ udelay(1000);
+ cx_clear(MO_GP0_IO, 0x00000080);
+ udelay(50);
+ cx_set(MO_GP0_IO, 0x00000080);
+ udelay(1000);
+ /* tri-state the cx22702 pins */
+ cx_set(MO_GP0_IO, 0x00000004);
+ udelay(1000);
break;
default:
err = -ENODEV;
diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c
index 5a9fafd25..fc3a080ac 100644
--- a/linux/drivers/media/video/cx88/cx88-dvb.c
+++ b/linux/drivers/media/video/cx88/cx88-dvb.c
@@ -1135,40 +1135,44 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
* on the bus. Take the bus from the cx23416 and enable the
* cx22702 demod
*/
- cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset and enable */
+ /* Toggle reset on cx22702 leaving i2c active */
+ cx_set(MO_GP0_IO, 0x00000080);
+ udelay(1000);
+ cx_clear(MO_GP0_IO, 0x00000080);
+ udelay(50);
+ cx_set(MO_GP0_IO, 0x00000080);
+ udelay(1000);
+ /* enable the cx22702 pins */
cx_clear(MO_GP0_IO, 0x00000004);
udelay(1000);
break;
case CX88_BOARD_HAUPPAUGE_HVR3000:
case CX88_BOARD_HAUPPAUGE_HVR4000:
- if(core->dvbdev->frontends.active_fe_id == 1) {
- /* DVB-S/S2 Enabled */
-
- /* Toggle reset on cx22702 leaving i2c active */
- cx_write(MO_GP0_IO, (core->board.input[0].gpio0 & 0x0000ff00) | 0x00000080);
- udelay(1000);
- cx_clear(MO_GP0_IO, 0x00000080);
- udelay(50);
- cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset */
- cx_set(MO_GP0_IO, 0x00000004); /* tri-state the cx22702 pins */
- udelay(1000);
-
- cx_write(MO_SRST_IO, 1); /* Take the cx24116/cx24123 out of reset */
+ /* Toggle reset on cx22702 leaving i2c active */
+ cx_set(MO_GP0_IO, 0x00000080);
+ udelay(1000);
+ cx_clear(MO_GP0_IO, 0x00000080);
+ udelay(50);
+ cx_set(MO_GP0_IO, 0x00000080);
+ udelay(1000);
+ switch (core->dvbdev->frontends.active_fe_id) {
+ case 1: /* DVB-S/S2 Enabled */
+ /* tri-state the cx22702 pins */
+ cx_set(MO_GP0_IO, 0x00000004);
+ /* Take the cx24116/cx24123 out of reset */
+ cx_write(MO_SRST_IO, 1);
core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */
- } else
- if (core->dvbdev->frontends.active_fe_id == 2) {
- /* DVB-T Enabled */
-
+ break;
+ case 2: /* DVB-T Enabled */
/* Put the cx24116/cx24123 into reset */
cx_write(MO_SRST_IO, 0);
-
- /* cx22702 out of reset and enable it */
- cx_set(MO_GP0_IO, 0x00000080);
+ /* enable the cx22702 pins */
cx_clear(MO_GP0_IO, 0x00000004);
core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */
- udelay(1000);
+ break;
}
+ udelay(1000);
break;
default:
diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c
index 9d407ac26..999d3bd04 100644
--- a/linux/drivers/media/video/cx88/cx88-mpeg.c
+++ b/linux/drivers/media/video/cx88/cx88-mpeg.c
@@ -618,9 +618,8 @@ static int cx8802_resume_common(struct pci_dev *pci_dev)
#if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \
defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE)
-struct cx8802_dev * cx8802_get_device(struct inode *inode)
+struct cx8802_dev *cx8802_get_device(int minor)
{
- int minor = iminor(inode);
struct cx8802_dev *dev;
list_for_each_entry(dev, &cx8802_devlist, devlist)
diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c
index 40136a431..a95bcb0ea 100644
--- a/linux/drivers/media/video/cx88/cx88-video.c
+++ b/linux/drivers/media/video/cx88/cx88-video.c
@@ -983,9 +983,9 @@ static int get_ressource(struct cx8800_fh *fh)
}
}
-static int video_open(struct inode *inode, struct file *file)
+static int video_open(struct file *file)
{
- int minor = iminor(inode);
+ int minor = video_devdata(file)->minor;
struct cx8800_dev *h,*dev = NULL;
struct cx88_core *core;
struct cx8800_fh *fh;
@@ -1130,7 +1130,7 @@ video_poll(struct file *file, struct poll_table_struct *wait)
return 0;
}
-static int video_release(struct inode *inode, struct file *file)
+static int video_release(struct file *file)
{
struct cx8800_fh *fh = file->private_data;
struct cx8800_dev *dev = fh->dev;
@@ -1713,25 +1713,26 @@ static int vidioc_s_frequency (struct file *file, void *priv,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register (struct file *file, void *fh,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
/* cx2388x has a 24-bit register space */
- reg->val = cx_read(reg->reg&0xffffff);
+ reg->val = cx_read(reg->reg & 0xffffff);
+ reg->size = 4;
return 0;
}
static int vidioc_s_register (struct file *file, void *fh,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
- cx_write(reg->reg&0xffffff, reg->val);
+ cx_write(reg->reg & 0xffffff, reg->val);
return 0;
}
#endif
@@ -1963,7 +1964,7 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id)
/* ----------------------------------------------------------- */
/* exported stuff */
-static const struct file_operations video_fops =
+static const struct v4l2_file_operations video_fops =
{
.owner = THIS_MODULE,
.open = video_open,
@@ -1972,8 +1973,6 @@ static const struct file_operations video_fops =
.poll = video_poll,
.mmap = video_mmap,
.ioctl = video_ioctl2,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -2022,14 +2021,12 @@ static struct video_device cx8800_video_template = {
.current_norm = V4L2_STD_NTSC_M,
};
-static const struct file_operations radio_fops =
+static const struct v4l2_file_operations radio_fops =
{
.owner = THIS_MODULE,
.open = video_open,
.release = video_release,
.ioctl = video_ioctl2,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h
index 6f8e575a3..bc26551ca 100644
--- a/linux/drivers/media/video/cx88/cx88.h
+++ b/linux/drivers/media/video/cx88/cx88.h
@@ -664,7 +664,7 @@ int cx88_audio_thread(void *data);
int cx8802_register_driver(struct cx8802_driver *drv);
int cx8802_unregister_driver(struct cx8802_driver *drv);
-struct cx8802_dev * cx8802_get_device(struct inode *inode);
+struct cx8802_dev *cx8802_get_device(int minor);
struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
/* ----------------------------------------------------------- */
diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c
index b86b0870d..34c494d68 100644
--- a/linux/drivers/media/video/em28xx/em28xx-audio.c
+++ b/linux/drivers/media/video/em28xx/em28xx-audio.c
@@ -63,9 +63,9 @@ static int em28xx_isoc_audio_deinit(struct em28xx *dev)
dprintk("Stopping isoc\n");
for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
- usb_kill_urb(dev->adev->urb[i]);
- usb_free_urb(dev->adev->urb[i]);
- dev->adev->urb[i] = NULL;
+ usb_unlink_urb(dev->adev.urb[i]);
+ usb_free_urb(dev->adev.urb[i]);
+ dev->adev.urb[i] = NULL;
}
return 0;
@@ -80,7 +80,9 @@ static void em28xx_audio_isocirq(struct urb *urb)
struct em28xx *dev = urb->context;
int i;
unsigned int oldptr;
+#ifdef NO_PCM_LOCK
unsigned long flags;
+#endif
int period_elapsed = 0;
int status;
unsigned char *cp;
@@ -92,8 +94,8 @@ static void em28xx_audio_isocirq(struct urb *urb)
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
#endif
- if (dev->adev->capture_pcm_substream) {
- substream = dev->adev->capture_pcm_substream;
+ if (dev->adev.capture_pcm_substream) {
+ substream = dev->adev.capture_pcm_substream;
runtime = substream->runtime;
stride = runtime->frame_bits >> 3;
@@ -106,25 +108,10 @@ static void em28xx_audio_isocirq(struct urb *urb)
if (!length)
continue;
- spin_lock_irqsave(&dev->adev->slock, flags);
-
- oldptr = dev->adev->hwptr_done_capture;
- dev->adev->hwptr_done_capture += length;
- if (dev->adev->hwptr_done_capture >=
- runtime->buffer_size)
- dev->adev->hwptr_done_capture -=
- runtime->buffer_size;
-
- dev->adev->capture_transfer_done += length;
- if (dev->adev->capture_transfer_done >=
- runtime->period_size) {
- dev->adev->capture_transfer_done -=
- runtime->period_size;
- period_elapsed = 1;
- }
-
- spin_unlock_irqrestore(&dev->adev->slock, flags);
-
+#ifdef NO_PCM_LOCK
+ spin_lock_irqsave(&dev->adev.slock, flags);
+#endif
+ oldptr = dev->adev.hwptr_done_capture;
if (oldptr + length >= runtime->buffer_size) {
unsigned int cnt =
runtime->buffer_size - oldptr;
@@ -136,13 +123,37 @@ static void em28xx_audio_isocirq(struct urb *urb)
memcpy(runtime->dma_area + oldptr * stride, cp,
length * stride);
}
+
+#ifndef NO_PCM_LOCK
+ snd_pcm_stream_lock(substream);
+#endif
+
+ dev->adev.hwptr_done_capture += length;
+ if (dev->adev.hwptr_done_capture >=
+ runtime->buffer_size)
+ dev->adev.hwptr_done_capture -=
+ runtime->buffer_size;
+
+ dev->adev.capture_transfer_done += length;
+ if (dev->adev.capture_transfer_done >=
+ runtime->period_size) {
+ dev->adev.capture_transfer_done -=
+ runtime->period_size;
+ period_elapsed = 1;
+ }
+
+#ifdef NO_PCM_LOCK
+ spin_unlock_irqrestore(&dev->adev.slock, flags);
+#else
+ snd_pcm_stream_unlock(substream);
+#endif
}
if (period_elapsed)
snd_pcm_period_elapsed(substream);
}
urb->status = 0;
- if (dev->adev->shutdown)
+ if (dev->adev.shutdown)
return;
status = usb_submit_urb(urb, GFP_ATOMIC);
@@ -165,17 +176,17 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
struct urb *urb;
int j, k;
- dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
- if (!dev->adev->transfer_buffer[i])
+ dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
+ if (!dev->adev.transfer_buffer[i])
return -ENOMEM;
- memset(dev->adev->transfer_buffer[i], 0x80, sb_size);
+ memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
if (!urb) {
em28xx_errdev("usb_alloc_urb failed!\n");
for (j = 0; j < i; j++) {
- usb_free_urb(dev->adev->urb[j]);
- kfree(dev->adev->transfer_buffer[j]);
+ usb_free_urb(dev->adev.urb[j]);
+ kfree(dev->adev.transfer_buffer[j]);
}
return -ENOMEM;
}
@@ -184,7 +195,7 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
urb->context = dev;
urb->pipe = usb_rcvisocpipe(dev->udev, 0x83);
urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = dev->adev->transfer_buffer[i];
+ urb->transfer_buffer = dev->adev.transfer_buffer[i];
urb->interval = 1;
urb->complete = em28xx_audio_isocirq;
urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
@@ -196,11 +207,11 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
urb->iso_frame_desc[j].length =
EM28XX_AUDIO_MAX_PACKET_SIZE;
}
- dev->adev->urb[i] = urb;
+ dev->adev.urb[i] = urb;
}
for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
- errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC);
+ errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
if (errCode) {
em28xx_isoc_audio_deinit(dev);
@@ -213,16 +224,16 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
static int em28xx_cmd(struct em28xx *dev, int cmd, int arg)
{
- dprintk("%s transfer\n", (dev->adev->capture_stream == STREAM_ON)?
+ dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ?
"stop" : "start");
switch (cmd) {
case EM28XX_CAPTURE_STREAM_EN:
- if (dev->adev->capture_stream == STREAM_OFF && arg == 1) {
- dev->adev->capture_stream = STREAM_ON;
+ if (dev->adev.capture_stream == STREAM_OFF && arg == 1) {
+ dev->adev.capture_stream = STREAM_ON;
em28xx_init_audio_isoc(dev);
- } else if (dev->adev->capture_stream == STREAM_ON && arg == 0) {
- dev->adev->capture_stream = STREAM_OFF;
+ } else if (dev->adev.capture_stream == STREAM_ON && arg == 0) {
+ dev->adev.capture_stream = STREAM_OFF;
em28xx_isoc_audio_deinit(dev);
} else {
printk(KERN_ERR "An underrun very likely occurred. "
@@ -321,17 +332,17 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
goto err;
runtime->hw = snd_em28xx_hw_capture;
- if (dev->alt == 0 && dev->adev->users == 0) {
+ if (dev->alt == 0 && dev->adev.users == 0) {
int errCode;
dev->alt = 7;
errCode = usb_set_interface(dev->udev, 0, 7);
dprintk("changing alternate number to 7\n");
}
- dev->adev->users++;
+ dev->adev.users++;
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
- dev->adev->capture_pcm_substream = substream;
+ dev->adev.capture_pcm_substream = substream;
runtime->private_data = dev;
return 0;
@@ -347,7 +358,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
#endif
{
struct em28xx *dev = snd_pcm_substream_chip(substream);
- dev->adev->users--;
+ dev->adev.users--;
dprintk("closing device\n");
@@ -356,10 +367,10 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
em28xx_audio_analog_set(dev);
mutex_unlock(&dev->lock);
- if (dev->adev->users == 0 && dev->adev->shutdown == 1) {
- dprintk("audio users: %d\n", dev->adev->users);
+ if (dev->adev.users == 0 && dev->adev.shutdown == 1) {
+ dprintk("audio users: %d\n", dev->adev.users);
dprintk("disabling audio stream!\n");
- dev->adev->shutdown = 0;
+ dev->adev.shutdown = 0;
dprintk("released lock\n");
em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
}
@@ -401,7 +412,7 @@ static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
dprintk("Stop capture, if needed\n");
- if (dev->adev->capture_stream == STREAM_ON)
+ if (dev->adev.capture_stream == STREAM_ON)
em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
return 0;
@@ -432,7 +443,7 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1);
return 0;
case SNDRV_PCM_TRIGGER_STOP:
- dev->adev->shutdown = 1;
+ dev->adev.shutdown = 1;
return 0;
default:
return -EINVAL;
@@ -451,7 +462,7 @@ static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
snd_pcm_uframes_t hwptr_done;
dev = snd_pcm_substream_chip(substream);
- hwptr_done = dev->adev->hwptr_done_capture;
+ hwptr_done = dev->adev.hwptr_done_capture;
return hwptr_done;
}
@@ -487,7 +498,7 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
static int em28xx_audio_init(struct em28xx *dev)
{
- struct em28xx_audio *adev;
+ struct em28xx_audio *adev = &dev->adev;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
snd_pcm_t *pcm;
snd_card_t *card;
@@ -510,16 +521,9 @@ static int em28xx_audio_init(struct em28xx *dev)
printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
"Rechberger\n");
- adev = kzalloc(sizeof(*adev), GFP_KERNEL);
- if (!adev) {
- printk(KERN_ERR "em28xx-audio.c: out of memory\n");
- return -1;
- }
card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0);
- if (card == NULL) {
- kfree(adev);
+ if (card == NULL)
return -ENOMEM;
- }
spin_lock_init(&adev->slock);
err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
@@ -543,7 +547,6 @@ static int em28xx_audio_init(struct em28xx *dev)
}
adev->sndcard = card;
adev->udev = dev->udev;
- dev->adev = adev;
return 0;
}
@@ -560,10 +563,9 @@ static int em28xx_audio_fini(struct em28xx *dev)
return 0;
}
- if (dev->adev) {
- snd_card_free(dev->adev->sndcard);
- kfree(dev->adev);
- dev->adev = NULL;
+ if (dev->adev.sndcard) {
+ snd_card_free(dev->adev.sndcard);
+ dev->adev.sndcard = NULL;
}
return 0;
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index 9177ea54b..c5dd7a96c 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -38,6 +38,8 @@
#include "em28xx.h"
+#define DRIVER_NAME "em28xx"
+
static int tuner = -1;
module_param(tuner, int, 0444);
MODULE_PARM_DESC(tuner, "tuner type");
@@ -46,16 +48,89 @@ static unsigned int disable_ir;
module_param(disable_ir, int, 0444);
MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
+static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
+
+/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
+static unsigned long em28xx_devused;
+
struct em28xx_hash_table {
unsigned long hash;
unsigned int model;
unsigned int tuner;
};
+/*
+ * Reset sequences for analog/digital modes
+ */
+
+/* Reset for the most [analog] boards */
+static struct em28xx_reg_seq default_analog[] = {
+ {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
+};
+
+/* Reset for the most [digital] boards */
+static struct em28xx_reg_seq default_digital[] = {
+ {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
+};
+
+/* Board Hauppauge WinTV HVR 900 analog */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
+ {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10},
+ {0x05, 0xff, 0x10, 10},
+ { -1, -1, -1, -1},
+};
+
+/* Board Hauppauge WinTV HVR 900 digital */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
+ {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10},
+ {EM2880_R04_GPO, 0x04, 0x0f, 10},
+ {EM2880_R04_GPO, 0x0c, 0x0f, 10},
+ { -1, -1, -1, -1},
+};
+
+/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
+static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
+ {EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
+};
+
+/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
+#if 0 /* Still missing the dvb setup */
+static struct em28xx_reg_seq em2880_msi_digivox_ad_digital[] = {
+ {EM28XX_R08_GPIO, 0x6a, ~EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
+};
+#endif
+
+/* Board - EM2870 Kworld 355u
+ Analog - No input analog */
+#if 0 /* Still missing the dvb setup */
+static struct em28xx_reg_seq em2870_kworld_355u_digital[] = {
+ {EM2880_R04_GPO, 0x01, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+#endif
+
+/* Callback for the most boards */
+static struct em28xx_reg_seq default_tuner_gpio[] = {
+ {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
+ {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10},
+ {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
+};
+
+/*
+ * Board definitions
+ */
struct em28xx_board em28xx_boards[] = {
[EM2750_BOARD_UNKNOWN] = {
.name = "Unknown EM2750/EM2751 webcam grabber",
- .vchannels = 1,
+ .xclk = EM28XX_XCLK_FREQUENCY_48MHZ,
+ .tuner_type = TUNER_ABSENT, /* This is a webcam */
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
@@ -65,10 +140,10 @@ struct em28xx_board em28xx_boards[] = {
[EM2800_BOARD_UNKNOWN] = {
.name = "Unknown EM2800 video grabber",
.is_em2800 = 1,
- .vchannels = 2,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .tuner_type = TUNER_ABSENT,
+ .input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
@@ -79,15 +154,15 @@ struct em28xx_board em28xx_boards[] = {
} },
},
[EM2820_BOARD_UNKNOWN] = {
- .name = "Unknown EM2750/28xx video grabber",
- .is_em2800 = 0,
- .tuner_type = TUNER_ABSENT,
+ .name = "Unknown EM2750/28xx video grabber",
+ .tuner_type = TUNER_ABSENT,
},
[EM2750_BOARD_DLCW_130] = {
/* Beijing Huaqi Information Digital Technology Co., Ltd */
.name = "Huaqi DLCW-130",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 1,
+ .xclk = EM28XX_XCLK_FREQUENCY_48MHZ,
+ .tuner_type = TUNER_ABSENT, /* This is a webcam */
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
@@ -96,12 +171,10 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2820_BOARD_KWORLD_PVRTV2800RF] = {
.name = "Kworld PVR TV 2800 RF",
- .is_em2800 = 0,
- .vchannels = 2,
.tuner_type = TUNER_TEMIC_PAL,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
@@ -113,11 +186,10 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2820_BOARD_TERRATEC_CINERGY_250] = {
.name = "Terratec Cinergy 250 USB",
- .vchannels = 3,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_LINE_IN,
@@ -133,11 +205,10 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2820_BOARD_PINNACLE_USB_2] = {
.name = "Pinnacle PCTV USB 2",
- .vchannels = 3,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
@@ -153,15 +224,13 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
.name = "Hauppauge WinTV USB 2",
- .vchannels = 3,
.tuner_type = TUNER_PHILIPS_FM1236_MK3,
.tda9887_conf = TDA9887_PRESENT |
TDA9887_PORT1_ACTIVE|
TDA9887_PORT2_ACTIVE,
.decoder = EM28XX_TVP5150,
.has_msp34xx = 1,
- /*FIXME: S-Video not tested */
- .input = { {
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = MSP_INPUT_DEFAULT,
@@ -175,12 +244,10 @@ struct em28xx_board em28xx_boards[] = {
[EM2820_BOARD_DLINK_USB_TV] = {
.name = "D-Link DUB-T210 TV Tuner",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
- .is_em2800 = 0,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_LINE_IN,
@@ -197,10 +264,9 @@ struct em28xx_board em28xx_boards[] = {
[EM2820_BOARD_HERCULES_SMART_TV_USB2] = {
.name = "Hercules Smart TV USB 2.0",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
+ .decoder = EM28XX_SAA711X,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
@@ -218,12 +284,10 @@ struct em28xx_board em28xx_boards[] = {
[EM2820_BOARD_PINNACLE_USB_2_FM1216ME] = {
.name = "Pinnacle PCTV USB 2 (Philips FM1216ME)",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
- .is_em2800 = 0,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
@@ -240,11 +304,10 @@ struct em28xx_board em28xx_boards[] = {
[EM2820_BOARD_GADMEI_UTV310] = {
.name = "Gadmei UTV310",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_TNF_5335MF,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
@@ -261,44 +324,28 @@ struct em28xx_board em28xx_boards[] = {
[EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE] = {
.name = "Leadtek Winfast USB II Deluxe",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7114,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
- .amux = EM28XX_AMUX_LINE_IN,
- }, {
- .type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
- .amux = EM28XX_AMUX_LINE_IN,
- } },
- },
- [EM2820_BOARD_PINNACLE_DVC_100] = {
- .name = "Pinnacle Dazzle DVC 100",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
- .decoder = EM28XX_SAA7113,
- .input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
- .vmux = SAA7115_SVIDEO3,
+ .vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_VIDEOLOGY_20K14XUSB] = {
- .name = "Videology 20K14XUSB USB2.0",
+ .name = "Videology 20K14XUSB USB2.0",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 1,
- .input = { {
+ .tuner_type = TUNER_ABSENT, /* This is a webcam */
+ .input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
.amux = EM28XX_AMUX_VIDEO,
@@ -307,12 +354,10 @@ struct em28xx_board em28xx_boards[] = {
[EM2821_BOARD_PROLINK_PLAYTV_USB2] = {
.name = "SIIG AVTuner-PVR/Prolink PlayTV USB 2.0",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
- .is_em2800 = 0,
.tuner_type = TUNER_LG_PAL_NEW_TAPC, /* unknown? */
.tda9887_conf = TDA9887_PRESENT, /* unknown? */
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_LINE_IN,
@@ -329,14 +374,12 @@ struct em28xx_board em28xx_boards[] = {
[EM2821_BOARD_SUPERCOMP_USB_2] = {
.name = "Supercomp USB 2.0 TV",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
- .is_em2800 = 0,
.tuner_type = TUNER_PHILIPS_FM1236_MK3,
.tda9887_conf = TDA9887_PRESENT |
TDA9887_PORT1_ACTIVE |
TDA9887_PORT2_ACTIVE,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_LINE_IN,
@@ -351,11 +394,11 @@ struct em28xx_board em28xx_boards[] = {
} },
},
[EM2821_BOARD_USBGEAR_VD204] = {
- .name = "Usbgear VD204v9",
+ .name = "Usbgear VD204v9",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 2,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .tuner_type = TUNER_ABSENT, /* Capture only device */
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
@@ -367,21 +410,20 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2860_BOARD_NETGMBH_CAM] = {
/* Beijing Huaqi Information Digital Technology Co., Ltd */
- .name = "NetGMBH Cam",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 1,
- .input = { {
+ .name = "NetGMBH Cam",
+ .valid = EM28XX_BOARD_NOT_VALIDATED,
+ .tuner_type = TUNER_ABSENT, /* This is a webcam */
+ .input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
.amux = EM28XX_AMUX_VIDEO,
} },
},
[EM2860_BOARD_TYPHOON_DVD_MAKER] = {
- .name = "Typhoon DVD Maker",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 2,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .name = "Typhoon DVD Maker",
+ .decoder = EM28XX_SAA711X,
+ .tuner_type = TUNER_ABSENT, /* Capture only device */
+ .input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
@@ -394,11 +436,10 @@ struct em28xx_board em28xx_boards[] = {
[EM2860_BOARD_GADMEI_UTV330] = {
.name = "Gadmei UTV330",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_TNF_5335MF,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
@@ -415,30 +456,38 @@ struct em28xx_board em28xx_boards[] = {
[EM2860_BOARD_TERRATEC_HYBRID_XS] = {
.name = "Terratec Cinergy A Hybrid XS",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
- .input = { {
+
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900_digital,
+#endif
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
} },
},
[EM2861_BOARD_KWORLD_PVRTV_300U] = {
.name = "KWorld PVRTV 300U",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
- .input = { {
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
@@ -454,8 +503,7 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2861_BOARD_YAKUMO_MOVIE_MIXER] = {
.name = "Yakumo MovieMixer",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 1,
+ .tuner_type = TUNER_ABSENT, /* Capture only device */
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -474,11 +522,10 @@ struct em28xx_board em28xx_boards[] = {
[EM2861_BOARD_PLEXTOR_PX_TV100U] = {
.name = "Plextor ConvertX PX-TV100U",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_TNF_5335MF,
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_TVP5150,
- .input = { {
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
@@ -492,10 +539,18 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
} },
},
+
+ /* Those boards with em2870 are DVB Only*/
+
[EM2870_BOARD_TERRATEC_XS] = {
.name = "Terratec Cinergy T XS",
.valid = EM28XX_BOARD_NOT_VALIDATED,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = default_digital,
+#endif
},
[EM2870_BOARD_TERRATEC_XS_MT2060] = {
.name = "Terratec Cinergy T XS (MT2060)",
@@ -506,172 +561,242 @@ struct em28xx_board em28xx_boards[] = {
.name = "Kworld 350 U DVB-T",
.valid = EM28XX_BOARD_NOT_VALIDATED,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = default_digital,
+#endif
},
[EM2870_BOARD_KWORLD_355U] = {
.name = "Kworld 355 U DVB-T",
.valid = EM28XX_BOARD_NOT_VALIDATED,
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = em2870_kworld_355u_digital,
+#endif
},
[EM2870_BOARD_PINNACLE_PCTV_DVB] = {
.name = "Pinnacle PCTV DVB-T",
.valid = EM28XX_BOARD_NOT_VALIDATED,
.tuner_type = TUNER_ABSENT, /* MT2060 */
+ /* djh - I have serious doubts this is right... */
+ .xclk = EM28XX_XCLK_IR_RC5_MODE |
+ EM28XX_XCLK_FREQUENCY_10MHZ,
},
[EM2870_BOARD_COMPRO_VIDEOMATE] = {
.name = "Compro, VideoMate U3",
.valid = EM28XX_BOARD_NOT_VALIDATED,
.tuner_type = TUNER_ABSENT, /* MT2060 */
},
+
[EM2880_BOARD_TERRATEC_HYBRID_XS_FR] = {
.name = "Terratec Hybrid XS Secam",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.has_msp34xx = 1,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
- .input = { {
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = default_digital,
+#endif
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = default_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = default_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = default_analog,
} },
},
[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
.name = "Hauppauge WinTV HVR 900",
- .vchannels = 3,
.tda9887_conf = TDA9887_PRESENT,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
- .has_dvb = 1,
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900_digital,
.decoder = EM28XX_TVP5150,
- .input = { {
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
} },
},
[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = {
.name = "Hauppauge WinTV HVR 900 (R2)",
- .vchannels = 3,
.tda9887_conf = TDA9887_PRESENT,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
.decoder = EM28XX_TVP5150,
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900_digital,
+#endif
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = hauppauge_wintv_hvr_900_analog,
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = TVP5150_COMPOSITE1,
+ .amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = TVP5150_SVIDEO,
+ .amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
+ } },
+ },
+ [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850] = {
+ .name = "Hauppauge WinTV HVR 850",
+ .tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
+ .mts_firmware = 1,
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900_digital,
+ .ir_codes = ir_codes_hauppauge_new,
+ .decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 3,
+ .amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
} },
},
[EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = {
.name = "Hauppauge WinTV HVR 950",
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
- .has_12mhz_i2s = 1,
.has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900_digital,
.ir_codes = ir_codes_hauppauge_new,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
} },
},
[EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = {
.name = "Pinnacle PCTV HD Pro Stick",
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
- .has_12mhz_i2s = 1,
.has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900_digital,
.ir_codes = ir_codes_pinnacle_pctv_hd,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
} },
},
[EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = {
.name = "AMD ATI TV Wonder HD 600",
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
- .has_12mhz_i2s = 1,
.has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900_digital,
.ir_codes = ir_codes_ati_tv_wonder_hd_600,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
} },
},
[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
- .name = "Terratec Hybrid XS",
- .vchannels = 3,
- .tuner_type = TUNER_XC2028,
- .decoder = EM28XX_TVP5150,
+ .name = "Terratec Hybrid XS",
+ .tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
+ .decoder = EM28XX_TVP5150,
.has_dvb = 1,
+ .dvb_gpio = default_analog,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = default_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = default_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = default_analog,
} },
},
/* maybe there's a reason behind it why Terratec sells the Hybrid XS
@@ -679,33 +804,38 @@ struct em28xx_board em28xx_boards[] = {
maybe we'll need it lateron */
[EM2880_BOARD_TERRATEC_PRODIGY_XS] = {
.name = "Terratec Prodigy XS",
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
- .input = { {
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900_digital,
+#endif
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
} },
},
[EM2820_BOARD_MSI_VOX_USB_2] = {
.name = "MSI VOX USB 2.0",
- .vchannels = 3,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT |
TDA9887_PORT1_ACTIVE |
TDA9887_PORT2_ACTIVE,
.max_range_640_480 = 1,
-
- .decoder = EM28XX_SAA7114,
+ .decoder = EM28XX_SAA711X,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE4,
@@ -723,11 +853,10 @@ struct em28xx_board em28xx_boards[] = {
[EM2800_BOARD_TERRATEC_CINERGY_200] = {
.name = "Terratec Cinergy 200 USB",
.is_em2800 = 1,
- .vchannels = 3,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
@@ -744,9 +873,9 @@ struct em28xx_board em28xx_boards[] = {
[EM2800_BOARD_GRABBEEX_USB2800] = {
.name = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder",
.is_em2800 = 1,
- .vchannels = 2,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .tuner_type = TUNER_ABSENT, /* capture only board */
+ .input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
@@ -759,11 +888,10 @@ struct em28xx_board em28xx_boards[] = {
[EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
.name = "Leadtek Winfast USB II",
.is_em2800 = 1,
- .vchannels = 3,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
@@ -780,11 +908,10 @@ struct em28xx_board em28xx_boards[] = {
[EM2800_BOARD_KWORLD_USB2800] = {
.name = "Kworld USB2800",
.is_em2800 = 1,
- .vchannels = 3,
.tuner_type = TUNER_PHILIPS_FCV1236D,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
@@ -800,10 +927,9 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2820_BOARD_PINNACLE_DVC_90] = {
.name = "Pinnacle Dazzle DVC 90/DVC 100",
- .vchannels = 3,
- .tuner_type = TUNER_ABSENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .tuner_type = TUNER_ABSENT, /* capture only board */
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
@@ -816,11 +942,10 @@ struct em28xx_board em28xx_boards[] = {
[EM2800_BOARD_VGEAR_POCKETTV] = {
.name = "V-Gear PocketTV",
.is_em2800 = 1,
- .vchannels = 3,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
@@ -834,13 +959,34 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
} },
},
+ [EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2] = {
+ .name = "Pixelview PlayTV Box 4 USB 2.0",
+ .tda9887_conf = TDA9887_PRESENT,
+ .tuner_type = TUNER_YMEC_TVF_5533MF,
+ .decoder = EM28XX_SAA711X,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = SAA7115_COMPOSITE2,
+ .amux = EM28XX_AMUX_VIDEO,
+ .aout = EM28XX_AOUT_MONO | /* I2S */
+ EM28XX_AOUT_MASTER, /* Line out pin */
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = SAA7115_COMPOSITE0,
+ .amux = EM28XX_AMUX_LINE_IN,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = SAA7115_SVIDEO3,
+ .amux = EM28XX_AMUX_LINE_IN,
+ } },
+ },
[EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
.name = "Pixelview Prolink PlayTV USB 2.0",
- .vchannels = 3,
+ .has_snapshot_button = 1,
.tda9887_conf = TDA9887_PRESENT,
.tuner_type = TUNER_YMEC_TVF_5533MF,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
@@ -857,13 +1003,12 @@ struct em28xx_board em28xx_boards[] = {
} },
},
[EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = {
- .name = "PointNix Intra-Oral Camera",
+ .name = "PointNix Intra-Oral Camera",
.has_snapshot_button = 1,
- .vchannels = 1,
- .tda9887_conf = TDA9887_PRESENT,
- .tuner_type = TUNER_ABSENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
+ .tda9887_conf = TDA9887_PRESENT,
+ .tuner_type = TUNER_ABSENT,
+ .decoder = EM28XX_SAA711X,
+ .input = { {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
.amux = EM28XX_AMUX_VIDEO,
@@ -872,50 +1017,64 @@ struct em28xx_board em28xx_boards[] = {
[EM2880_BOARD_MSI_DIGIVOX_AD] = {
.name = "MSI DigiVox A/D",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
- .input = { {
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = em2880_msi_digivox_ad_digital,
+#endif
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = em2880_msi_digivox_ad_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = em2880_msi_digivox_ad_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = em2880_msi_digivox_ad_analog,
} },
},
[EM2880_BOARD_MSI_DIGIVOX_AD_II] = {
.name = "MSI DigiVox A/D II",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
- .input = { {
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = em2880_msi_digivox_ad_digital,
+#endif
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = em2880_msi_digivox_ad_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = em2880_msi_digivox_ad_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = em2880_msi_digivox_ad_analog,
} },
},
[EM2880_BOARD_KWORLD_DVB_305U] = {
.name = "KWorld DVB-T 305U",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
- .input = { {
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
@@ -931,93 +1090,118 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2880_BOARD_KWORLD_DVB_310U] = {
.name = "KWorld DVB-T 310U",
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.has_dvb = 1,
+ .dvb_gpio = default_digital,
.mts_firmware = 1,
.decoder = EM28XX_TVP5150,
- .input = { {
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = default_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = default_analog,
}, { /* S-video has not been tested yet */
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = default_analog,
} },
},
[EM2881_BOARD_DNT_DA2_HYBRID] = {
.name = "DNT DA2 Hybrid",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
- .input = { {
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = default_digital,
+#endif
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = default_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = default_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = default_analog,
} },
},
[EM2881_BOARD_PINNACLE_HYBRID_PRO] = {
.name = "Pinnacle Hybrid Pro",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
- .input = { {
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = default_digital,
+#endif
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = default_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = default_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = default_analog,
} },
},
[EM2882_BOARD_PINNACLE_HYBRID_PRO] = {
.name = "Pinnacle Hybrid Pro (2)",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
.decoder = EM28XX_TVP5150,
- .input = { {
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900_digital,
+#endif
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
} },
},
[EM2882_BOARD_KWORLD_VS_DVBT] = {
.name = "Kworld VS-DVB-T 323UR",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
- .input = { {
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
@@ -1034,51 +1218,61 @@ struct em28xx_board em28xx_boards[] = {
[EM2882_BOARD_TERRATEC_HYBRID_XS] = {
.name = "Terratec Hybrid XS (em2882)",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
- .input = { {
+#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900_digital,
+#endif
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
} },
},
[EM2883_BOARD_KWORLD_HYBRID_A316] = {
.name = "Kworld PlusTV HD Hybrid 330",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
- .vchannels = 3,
- .is_em2800 = 0,
.tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
- .input = { {
+ .mts_firmware = 1,
+ .has_dvb = 1,
+ .dvb_gpio = default_digital,
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = default_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
} },
},
[EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = {
.name = "Compro VideoMate ForYou/Stereo",
- .vchannels = 2,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_TVP5150,
- .input = { {
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
@@ -1088,21 +1282,6 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
} },
},
- [EM2874_BOARD_PINNACLE_PCTV_80E] = {
- .name = "Pinnacle PCTV HD Mini",
- .vchannels = 0,
- .tuner_type = TUNER_ABSENT,
- .has_dvb = 1,
- .ir_codes = ir_codes_pinnacle_pctv_hd,
- .decoder = EM28XX_NODECODER,
-#ifdef DJH_DEBUG
- .input = { {
- .type = EM28XX_VMUX_TELEVISION,
- .vmux = TVP5150_COMPOSITE0,
- .amux = EM28XX_AMUX_LINE_IN,
- } },
-#endif
- },
};
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -1117,7 +1296,7 @@ struct usb_device_id em28xx_id_table [] = {
{ USB_DEVICE(0xeb1a, 0x2820),
.driver_info = EM2820_BOARD_UNKNOWN },
{ USB_DEVICE(0xeb1a, 0x2821),
- .driver_info = EM2820_BOARD_PROLINK_PLAYTV_USB2 },
+ .driver_info = EM2820_BOARD_UNKNOWN },
{ USB_DEVICE(0xeb1a, 0x2860),
.driver_info = EM2820_BOARD_UNKNOWN },
{ USB_DEVICE(0xeb1a, 0x2861),
@@ -1184,8 +1363,8 @@ struct usb_device_id em28xx_id_table [] = {
.driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
{ USB_DEVICE(0x2040, 0x651b), /* RP HVR-950 */
.driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
- { USB_DEVICE(0x2040, 0x651f), /* HCW HVR-850 */
- .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+ { USB_DEVICE(0x2040, 0x651f),
+ .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 },
{ USB_DEVICE(0x0438, 0xb002),
.driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 },
{ USB_DEVICE(0x2001, 0xf112),
@@ -1200,8 +1379,6 @@ struct usb_device_id em28xx_id_table [] = {
.driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO },
{ USB_DEVICE(0x2304, 0x0227),
.driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
- { USB_DEVICE(0x2304, 0x023f),
- .driver_info = EM2874_BOARD_PINNACLE_PCTV_80E },
{ USB_DEVICE(0x0413, 0x6023),
.driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII },
{ USB_DEVICE(0x093b, 0xa005),
@@ -1211,89 +1388,12 @@ struct usb_device_id em28xx_id_table [] = {
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
/*
- * Reset sequences for analog/digital modes
- */
-
-/* Reset for the most [analog] boards */
-static struct em28xx_reg_seq default_analog[] = {
- {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10},
- { -1, -1, -1, -1},
-};
-
-/* Reset for the most [digital] boards */
-static struct em28xx_reg_seq default_digital[] = {
- {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10},
- { -1, -1, -1, -1},
-};
-
-/* Board Hauppauge WinTV HVR 900 analog */
-static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
- {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10},
- {0x05, 0xff, 0x10, 10},
- { -1, -1, -1, -1},
-};
-
-/* Board Hauppauge WinTV HVR 900 digital */
-static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
- {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10},
- {EM2880_R04_GPO, 0x04, 0x0f, 10},
- {EM2880_R04_GPO, 0x0c, 0x0f, 10},
- { -1, -1, -1, -1},
-};
-
-/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
-static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
- {EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10},
- { -1, -1, -1, -1},
-};
-
-/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
-static struct em28xx_reg_seq em2880_msi_digivox_ad_digital[] = {
- {EM28XX_R08_GPIO, 0x6a, ~EM_GPIO_4, 10},
- { -1, -1, -1, -1},
-};
-
-/* Board - EM2870 Kworld 355u
- Analog - No input analog */
-static struct em28xx_reg_seq em2870_kworld_355u_digital[] = {
- {EM2880_R04_GPO, 0x01, 0xff, 10},
- { -1, -1, -1, -1},
-};
-
-/* Callback for the most boards */
-static struct em28xx_reg_seq default_callback[] = {
- {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
- {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10},
- {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
- { -1, -1, -1, -1},
-};
-
-/* Callback for EM2882 TERRATEC HYBRID XS */
-static struct em28xx_reg_seq em2882_terratec_hybrid_xs_digital[] = {
- {EM28XX_R08_GPIO, 0x2e, 0xff, 6},
- {EM28XX_R08_GPIO, 0x3e, ~EM_GPIO_4, 6},
- {EM2880_R04_GPO, 0x04, 0xff, 10},
- {EM2880_R04_GPO, 0x0c, 0xff, 10},
- { -1, -1, -1, -1},
-};
-
-/* Pinnacle PCTV HD Mini (80e) GPIOs
- 0-5: not used
- 6: demod reset, active low
- 7: LED on, active high */
-static struct em28xx_reg_seq em2874_pinnacle_80e_digital[] = {
- {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/
- {EM2874_R80_GPIO, 0x80, 0xff, 100},/*Demod reset*/
- {EM2874_R80_GPIO, 0xc0, 0xff, 10},
- { -1, -1, -1, -1},
-};
-
-/*
* EEPROM hash table for devices with generic USB IDs
*/
static struct em28xx_hash_table em28xx_eeprom_hash [] = {
/* P/N: SA 60002070465 Tuner: TVF7533-MF */
{0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
+ {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
{0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
};
@@ -1315,28 +1415,26 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
if (command != XC2028_TUNER_RESET)
return 0;
- if (dev->mode == EM28XX_ANALOG_MODE)
- rc = em28xx_gpio_set(dev, dev->tun_analog_gpio);
- else
- rc = em28xx_gpio_set(dev, dev->tun_digital_gpio);
+ rc = em28xx_gpio_set(dev, dev->board.tuner_gpio);
return rc;
}
EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
-static void em28xx_set_model(struct em28xx *dev)
+static void inline em28xx_set_model(struct em28xx *dev)
{
- dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
- dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
- dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
- dev->decoder = em28xx_boards[dev->model].decoder;
- dev->video_inputs = em28xx_boards[dev->model].vchannels;
- dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
- dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
- dev->has_dvb = em28xx_boards[dev->model].has_dvb;
- dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button;
- dev->ir_codes = em28xx_boards[dev->model].ir_codes;
- dev->valid = em28xx_boards[dev->model].valid;
+ memcpy(&dev->board, &em28xx_boards[dev->model], sizeof(dev->board));
+
+ /* Those are the default values for the majority of boards
+ Use those values if not specified otherwise at boards entry
+ */
+ if (!dev->board.xclk)
+ dev->board.xclk = EM28XX_XCLK_IR_RC5_MODE |
+ EM28XX_XCLK_FREQUENCY_12MHZ;
+
+ if (!dev->board.i2c_speed)
+ dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ;
}
/* Since em28xx_pre_card_setup() requires a proper dev->model,
@@ -1346,6 +1444,11 @@ void em28xx_pre_card_setup(struct em28xx *dev)
{
int rc;
+ em28xx_set_model(dev);
+
+ em28xx_info("Identified as %s (card=%d)\n",
+ dev->board.name, dev->model);
+
/* Set the default GPO/GPIO for legacy devices */
dev->reg_gpo_num = EM2880_R04_GPO;
dev->reg_gpio_num = EM28XX_R08_GPIO;
@@ -1356,7 +1459,8 @@ void em28xx_pre_card_setup(struct em28xx *dev)
rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID);
if (rc > 0) {
dev->chip_id = rc;
- switch (rc) {
+
+ switch (dev->chip_id) {
case CHIP_ID_EM2750:
em28xx_info("chip ID is em2750\n");
break;
@@ -1369,6 +1473,10 @@ void em28xx_pre_card_setup(struct em28xx *dev)
case CHIP_ID_EM2860:
em28xx_info("chip ID is em2860\n");
break;
+ case CHIP_ID_EM2870:
+ em28xx_info("chip ID is em2870\n");
+ dev->wait_after_write = 0;
+ break;
case CHIP_ID_EM2874:
em28xx_info("chip ID is em2874\n");
dev->reg_gpio_num = EM2874_R80_GPIO;
@@ -1379,7 +1487,7 @@ void em28xx_pre_card_setup(struct em28xx *dev)
dev->wait_after_write = 0;
break;
default:
- em28xx_info("em28xx chip ID = %d\n", rc);
+ em28xx_info("em28xx chip ID = %d\n", dev->chip_id);
}
}
@@ -1388,223 +1496,74 @@ void em28xx_pre_card_setup(struct em28xx *dev)
if (rc >= 0)
dev->reg_gpo = rc;
- em28xx_set_model(dev);
+ /* Set the initial XCLK and I2C clock values based on the board
+ definition */
+ em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
+ msleep(50);
/* request some modules */
switch (dev->model) {
- case EM2880_BOARD_TERRATEC_PRODIGY_XS:
- case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
- case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
- case EM2860_BOARD_TERRATEC_HYBRID_XS:
- case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
- case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
- case EM2882_BOARD_PINNACLE_HYBRID_PRO:
- case EM2883_BOARD_KWORLD_HYBRID_A316:
- case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
- msleep(50);
-
- /* Sets GPO/GPIO sequences for this device */
- dev->analog_gpio = hauppauge_wintv_hvr_900_analog;
- dev->digital_gpio = hauppauge_wintv_hvr_900_digital;
- dev->tun_analog_gpio = default_callback;
- dev->tun_digital_gpio = default_callback;
- break;
-
- case EM2882_BOARD_TERRATEC_HYBRID_XS:
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
- msleep(50);
-
- /* should be added ir_codes here */
-
- /* Sets GPO/GPIO sequences for this device */
- dev->analog_gpio = hauppauge_wintv_hvr_900_analog;
- dev->digital_gpio = hauppauge_wintv_hvr_900_digital;
- dev->tun_analog_gpio = default_callback;
- dev->tun_digital_gpio = em2882_terratec_hybrid_xs_digital;
- break;
-
- case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
- case EM2880_BOARD_TERRATEC_HYBRID_XS:
- case EM2870_BOARD_TERRATEC_XS:
- case EM2881_BOARD_PINNACLE_HYBRID_PRO:
- case EM2880_BOARD_KWORLD_DVB_310U:
- case EM2870_BOARD_KWORLD_350U:
- case EM2881_BOARD_DNT_DA2_HYBRID:
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
- msleep(50);
-
- /* NOTE: EM2881_DNT_DA2_HYBRID spend 140 msleep for digital
- and analog commands. If this commands doesn't work,
- add this timer. */
-
- /* Sets GPO/GPIO sequences for this device */
- dev->analog_gpio = default_analog;
- dev->digital_gpio = default_digital;
- dev->tun_analog_gpio = default_callback;
- dev->tun_digital_gpio = default_callback;
- break;
-
- case EM2880_BOARD_MSI_DIGIVOX_AD:
- case EM2880_BOARD_MSI_DIGIVOX_AD_II:
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
- msleep(50);
-
- /* Sets GPO/GPIO sequences for this device */
- dev->analog_gpio = em2880_msi_digivox_ad_analog;
- dev->digital_gpio = em2880_msi_digivox_ad_digital;
- dev->tun_analog_gpio = default_callback;
- dev->tun_digital_gpio = default_callback;
- break;
-
- case EM2750_BOARD_UNKNOWN:
- case EM2750_BOARD_DLCW_130:
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x0a", 1);
- break;
-
case EM2861_BOARD_PLEXTOR_PX_TV100U:
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
/* FIXME guess */
/* Turn on analog audio output */
- em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
break;
-
case EM2861_BOARD_KWORLD_PVRTV_300U:
case EM2880_BOARD_KWORLD_DVB_305U:
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x6d);
msleep(10);
- em28xx_write_regs(dev, 0x08, "\x6d", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x7d);
msleep(10);
- em28xx_write_regs(dev, 0x08, "\x7d", 1);
- msleep(10);
- break;
-
- case EM2870_BOARD_KWORLD_355U:
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
- msleep(50);
-
- /* Sets GPO/GPIO sequences for this device */
- dev->digital_gpio = em2870_kworld_355u_digital;
break;
-
case EM2870_BOARD_COMPRO_VIDEOMATE:
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
/* TODO: someone can do some cleanup here...
not everything's needed */
- em28xx_write_regs(dev, 0x04, "\x00", 1);
+ em28xx_write_reg(dev, EM2880_R04_GPO, 0x00);
msleep(10);
- em28xx_write_regs(dev, 0x04, "\x01", 1);
+ em28xx_write_reg(dev, EM2880_R04_GPO, 0x01);
msleep(10);
- em28xx_write_regs(dev, 0x08, "\xfd", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
mdelay(70);
- em28xx_write_regs(dev, 0x08, "\xfc", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc);
mdelay(70);
- em28xx_write_regs(dev, 0x08, "\xdc", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xdc);
mdelay(70);
- em28xx_write_regs(dev, 0x08, "\xfc", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc);
mdelay(70);
break;
-
case EM2870_BOARD_TERRATEC_XS_MT2060:
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
/* this device needs some gpio writes to get the DVB-T
demod work */
- em28xx_write_regs(dev, 0x08, "\xfe", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
mdelay(70);
- em28xx_write_regs(dev, 0x08, "\xde", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde);
mdelay(70);
- dev->em28xx_write_regs(dev, 0x08, "\xfe", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
mdelay(70);
break;
-
case EM2870_BOARD_PINNACLE_PCTV_DVB:
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
-
/* this device needs some gpio writes to get the
DVB-T demod work */
- em28xx_write_regs(dev, 0x08, "\xfe", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
mdelay(70);
- em28xx_write_regs(dev, 0x08, "\xde", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde);
mdelay(70);
- em28xx_write_regs(dev, 0x08, "\xfe", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
mdelay(70);
- /* switch em2880 rc protocol */
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x22", 1);
- /* should be added ir_codes here */
break;
-
case EM2820_BOARD_GADMEI_UTV310:
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
- /* Turn on analog audio output */
- em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1);
- break;
-
- case EM2860_BOARD_GADMEI_UTV330:
- /* Turn on IR */
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
- /* should be added ir_codes here */
- break;
-
case EM2820_BOARD_MSI_VOX_USB_2:
- em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ);
- /* enables audio for that device */
- em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1);
- break;
-
- case EM2874_BOARD_PINNACLE_PCTV_80E:
- /* Set 400 KHz clock and select secondary i2c bus */
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
- EM28XX_I2C_CLK_WAIT_ENABLE |
- EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_FREQ_400_KHZ);
-
- dev->digital_gpio = em2874_pinnacle_80e_digital;
+ /* enables audio for that devices */
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
break;
}
- em28xx_gpio_set(dev, dev->tun_analog_gpio);
+ em28xx_gpio_set(dev, dev->board.tuner_gpio);
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
/* Unlock device */
- em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+ em28xx_set_mode(dev, EM28XX_SUSPEND);
}
static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
@@ -1630,6 +1589,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
ctl->demod = XC3028_FE_DEFAULT;
ctl->fname = XC3028L_DEFAULT_FIRMWARE;
break;
+ case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
/* FIXME: Better to specify the needed IF */
@@ -1814,6 +1774,7 @@ void em28xx_card_setup(struct em28xx *dev)
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+ case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
{
struct tveeprom tv;
@@ -1829,7 +1790,7 @@ void em28xx_card_setup(struct em28xx *dev)
if (tv.audio_processor == V4L2_IDENT_MSPX4XX) {
dev->i2s_speed = 2048000;
- dev->has_msp34xx = 1;
+ dev->board.has_msp34xx = 1;
}
#ifdef CONFIG_MODULES
if (tv.has_ir)
@@ -1839,7 +1800,7 @@ void em28xx_card_setup(struct em28xx *dev)
}
case EM2820_BOARD_KWORLD_PVRTV2800RF:
/* GPIO enables sound on KWORLD PVR TV 2800RF */
- em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf9);
break;
case EM2820_BOARD_UNKNOWN:
case EM2800_BOARD_UNKNOWN:
@@ -1862,10 +1823,10 @@ void em28xx_card_setup(struct em28xx *dev)
break;
}
- if (dev->has_snapshot_button)
+ if (dev->board.has_snapshot_button)
em28xx_register_snapshot_button(dev);
- if (dev->valid == EM28XX_BOARD_NOT_VALIDATED) {
+ if (dev->board.valid == EM28XX_BOARD_NOT_VALIDATED) {
em28xx_errdev("\n\n");
em28xx_errdev("The support for this board weren't "
"valid yet.\n");
@@ -1880,13 +1841,13 @@ void em28xx_card_setup(struct em28xx *dev)
#ifdef CONFIG_MODULES
/* request some modules */
- if (dev->has_msp34xx)
+ if (dev->board.has_msp34xx)
request_module("msp3400");
- if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
+ if (dev->board.decoder == EM28XX_SAA711X)
request_module("saa7115");
- if (dev->decoder == EM28XX_TVP5150)
+ if (dev->board.decoder == EM28XX_TVP5150)
request_module("tvp5150");
- if (dev->tuner_type != TUNER_ABSENT)
+ if (dev->board.tuner_type != TUNER_ABSENT)
request_module("tuner");
#endif
@@ -1894,3 +1855,433 @@ void em28xx_card_setup(struct em28xx *dev)
em28xx_ir_init(dev);
}
+
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void request_module_async(void *ptr)
+{
+ struct em28xx *dev = (struct em28xx *)ptr;
+#else
+static void request_module_async(struct work_struct *work)
+{
+ struct em28xx *dev = container_of(work,
+ struct em28xx, request_module_wk);
+#endif
+
+ if (dev->has_audio_class)
+ request_module("snd-usb-audio");
+ else if (dev->has_alsa_audio)
+ request_module("em28xx-alsa");
+
+ if (dev->board.has_dvb)
+ request_module("em28xx-dvb");
+}
+
+static void request_modules(struct em28xx *dev)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&dev->request_module_wk, request_module_async,
+ (void *)dev);
+#else
+ INIT_WORK(&dev->request_module_wk, request_module_async);
+#endif
+ schedule_work(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#endif /* CONFIG_MODULES */
+
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void em28xx_release_resources(struct em28xx *dev)
+{
+ if (dev->sbutton_input_dev)
+ em28xx_deregister_snapshot_button(dev);
+
+ if (dev->ir)
+ em28xx_ir_fini(dev);
+
+ /*FIXME: I2C IR should be disconnected */
+
+ em28xx_release_analog_resources(dev);
+
+ em28xx_remove_from_devlist(dev);
+
+ em28xx_i2c_unregister(dev);
+ usb_put_dev(dev->udev);
+
+ /* Mark device as unused */
+ em28xx_devused &= ~(1 << dev->devno);
+};
+
+/*
+ * em28xx_init_dev()
+ * allocates and inits the device structs, registers i2c bus and v4l device
+ */
+int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+ int minor)
+{
+ struct em28xx *dev = *devhandle;
+ int retval = -ENOMEM;
+ int errCode;
+
+ dev->udev = udev;
+ mutex_init(&dev->ctrl_urb_lock);
+ spin_lock_init(&dev->slock);
+ init_waitqueue_head(&dev->open);
+ init_waitqueue_head(&dev->wait_frame);
+ init_waitqueue_head(&dev->wait_stream);
+
+ dev->em28xx_write_regs = em28xx_write_regs;
+ dev->em28xx_read_reg = em28xx_read_reg;
+ dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
+ dev->em28xx_write_regs_req = em28xx_write_regs_req;
+ dev->em28xx_read_reg_req = em28xx_read_reg_req;
+ dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800;
+
+ em28xx_pre_card_setup(dev);
+
+ if (!dev->board.is_em2800) {
+ /* Sets I2C speed to 100 KHz */
+ retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+ if (retval < 0) {
+ em28xx_errdev("%s: em28xx_write_regs_req failed!"
+ " retval [%d]\n",
+ __func__, retval);
+ return retval;
+ }
+ }
+
+ /* register i2c bus */
+ errCode = em28xx_i2c_register(dev);
+ if (errCode < 0) {
+ em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n",
+ __func__, errCode);
+ return errCode;
+ }
+
+ /* Do board specific init and eeprom reading */
+ em28xx_card_setup(dev);
+
+ /* Configure audio */
+ errCode = em28xx_audio_setup(dev);
+ if (errCode < 0) {
+ em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n",
+ __func__, errCode);
+ }
+
+ /* wake i2c devices */
+ em28xx_wake_i2c(dev);
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&dev->vidq.active);
+ INIT_LIST_HEAD(&dev->vidq.queued);
+
+#if 0
+ video_set_drvdata(dev->vbi_dev, dev);
+#endif
+
+ if (dev->board.has_msp34xx) {
+ /* Send a reset to other chips via gpio */
+ errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
+ if (errCode < 0) {
+ em28xx_errdev("%s: em28xx_write_regs_req - "
+ "msp34xx(1) failed! errCode [%d]\n",
+ __func__, errCode);
+ return errCode;
+ }
+ msleep(3);
+
+ errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+ if (errCode < 0) {
+ em28xx_errdev("%s: em28xx_write_regs_req - "
+ "msp34xx(2) failed! errCode [%d]\n",
+ __func__, errCode);
+ return errCode;
+ }
+ msleep(3);
+ }
+
+ em28xx_add_into_devlist(dev);
+
+ retval = em28xx_register_analog_devices(dev);
+ if (retval < 0) {
+ em28xx_release_resources(dev);
+ goto fail_reg_devices;
+ }
+
+ em28xx_init_extension(dev);
+
+ /* Save some power by putting tuner to sleep */
+ em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+
+ return 0;
+
+fail_reg_devices:
+ return retval;
+}
+
+/*
+ * em28xx_usb_probe()
+ * checks for supported devices
+ */
+static int em28xx_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ const struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *udev;
+ struct usb_interface *uif;
+ struct em28xx *dev = NULL;
+ int retval = -ENODEV;
+ int i, nr, ifnum, isoc_pipe;
+ char *speed;
+ char descr[255] = "";
+
+ udev = usb_get_dev(interface_to_usbdev(interface));
+ ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+
+ /* Check to see next free device and mark as used */
+ nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
+ em28xx_devused |= 1<<nr;
+
+ /* Don't register audio interfaces */
+ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+ em28xx_err(DRIVER_NAME " audio device (%04x:%04x): "
+ "interface %i, class %i\n",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct),
+ ifnum,
+ interface->altsetting[0].desc.bInterfaceClass);
+
+ em28xx_devused &= ~(1<<nr);
+ return -ENODEV;
+ }
+
+ endpoint = &interface->cur_altsetting->endpoint[0].desc;
+
+ /* check if the device has the iso in endpoint at the correct place */
+ if (usb_endpoint_xfer_isoc(endpoint)
+ &&
+ (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) {
+ /* It's a newer em2874/em2875 device */
+ isoc_pipe = 0;
+ } else {
+ int check_interface = 1;
+ isoc_pipe = 1;
+ endpoint = &interface->cur_altsetting->endpoint[1].desc;
+ if (usb_endpoint_type(endpoint) !=
+ USB_ENDPOINT_XFER_ISOC)
+ check_interface = 0;
+
+ if (usb_endpoint_dir_out(endpoint))
+ check_interface = 0;
+
+ if (!check_interface) {
+ em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
+ "interface %i, class %i found.\n",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct),
+ ifnum,
+ interface->altsetting[0].desc.bInterfaceClass);
+
+ em28xx_err(DRIVER_NAME " This is an anciliary "
+ "interface not used by the driver\n");
+
+ em28xx_devused &= ~(1<<nr);
+ return -ENODEV;
+ }
+ }
+
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ speed = "1.5";
+ break;
+ case USB_SPEED_UNKNOWN:
+ case USB_SPEED_FULL:
+ speed = "12";
+ break;
+ case USB_SPEED_HIGH:
+ speed = "480";
+ break;
+ default:
+ speed = "unknown";
+ }
+
+ if (udev->manufacturer)
+ strlcpy(descr, udev->manufacturer, sizeof(descr));
+
+ if (udev->product) {
+ if (*descr)
+ strlcat(descr, " ", sizeof(descr));
+ strlcat(descr, udev->product, sizeof(descr));
+ }
+ if (*descr)
+ strlcat(descr, " ", sizeof(descr));
+
+ printk(DRIVER_NAME ": New device %s@ %s Mbps "
+ "(%04x:%04x, interface %d, class %d)\n",
+ descr,
+ speed,
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct),
+ ifnum,
+ interface->altsetting->desc.bInterfaceNumber);
+
+ if (nr >= EM28XX_MAXBOARDS) {
+ printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
+ EM28XX_MAXBOARDS);
+ em28xx_devused &= ~(1<<nr);
+ return -ENOMEM;
+ }
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ em28xx_err(DRIVER_NAME ": out of memory!\n");
+ em28xx_devused &= ~(1<<nr);
+ return -ENOMEM;
+ }
+
+ snprintf(dev->name, 29, "em28xx #%d", nr);
+ dev->devno = nr;
+ dev->model = id->driver_info;
+ dev->alt = -1;
+
+ /* Checks if audio is provided by some interface */
+ for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
+ uif = udev->config->interface[i];
+ if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+ dev->has_audio_class = 1;
+ break;
+ }
+ }
+
+ /* compute alternate max packet sizes */
+ uif = udev->actconfig->interface[0];
+
+ dev->num_alt = uif->num_altsetting;
+ dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
+
+ if (dev->alt_max_pkt_size == NULL) {
+ em28xx_errdev("out of memory!\n");
+ em28xx_devused &= ~(1<<nr);
+ kfree(dev);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < dev->num_alt ; i++) {
+ u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
+ dev->alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ }
+
+ if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
+ dev->model = card[nr];
+
+ /* allocate device struct */
+ mutex_init(&dev->lock);
+ mutex_lock(&dev->lock);
+ retval = em28xx_init_dev(&dev, udev, nr);
+ if (retval) {
+ em28xx_devused &= ~(1<<dev->devno);
+ kfree(dev);
+
+ return retval;
+ }
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+
+ request_modules(dev);
+
+ /* Should be the last thing to do, to avoid newer udev's to
+ open the device before fully initializing it
+ */
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+/*
+ * em28xx_usb_disconnect()
+ * called when the device gets diconencted
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void em28xx_usb_disconnect(struct usb_interface *interface)
+{
+ struct em28xx *dev;
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ if (!dev)
+ return;
+
+ em28xx_info("disconnecting %s\n", dev->vdev->name);
+
+ /* wait until all current v4l2 io is finished then deallocate
+ resources */
+ mutex_lock(&dev->lock);
+
+ wake_up_interruptible_all(&dev->open);
+
+ if (dev->users) {
+ em28xx_warn
+ ("device /dev/video%d is open! Deregistration and memory "
+ "deallocation are deferred on close.\n",
+ dev->vdev->num);
+
+ dev->state |= DEV_MISCONFIGURED;
+ em28xx_uninit_isoc(dev);
+ dev->state |= DEV_DISCONNECTED;
+ wake_up_interruptible(&dev->wait_frame);
+ wake_up_interruptible(&dev->wait_stream);
+ } else {
+ dev->state |= DEV_DISCONNECTED;
+ em28xx_release_resources(dev);
+ }
+
+ em28xx_close_extension(dev);
+
+ mutex_unlock(&dev->lock);
+
+ if (!dev->users) {
+ kfree(dev->alt_max_pkt_size);
+ kfree(dev);
+ }
+}
+
+static struct usb_driver em28xx_usb_driver = {
+ .name = "em28xx",
+ .probe = em28xx_usb_probe,
+ .disconnect = em28xx_usb_disconnect,
+ .id_table = em28xx_id_table,
+};
+
+static int __init em28xx_module_init(void)
+{
+ int result;
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&em28xx_usb_driver);
+ if (result)
+ em28xx_err(DRIVER_NAME
+ " usb_register failed. Error number %d.\n", result);
+
+ printk(KERN_INFO DRIVER_NAME " driver loaded\n");
+
+ return result;
+}
+
+static void __exit em28xx_module_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&em28xx_usb_driver);
+}
+
+module_init(em28xx_module_init);
+module_exit(em28xx_module_exit);
diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c
index eb8515895..1da986118 100644
--- a/linux/drivers/media/video/em28xx/em28xx-core.c
+++ b/linux/drivers/media/video/em28xx/em28xx-core.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/vmalloc.h>
+#include <media/v4l2-common.h>
#include "em28xx.h"
@@ -66,7 +67,8 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
char *buf, int len)
{
- int ret, byte;
+ int ret;
+ int pipe = usb_rcvctrlpipe(dev->udev, 0);
if (dev->state & DEV_DISCONNECTED)
return -ENODEV;
@@ -74,10 +76,18 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
if (len > URB_MAX_CTRL_SIZE)
return -EINVAL;
- em28xx_regdbg("req=%02x, reg=%02x ", req, reg);
+ if (reg_debug) {
+ printk( KERN_DEBUG "(pipe 0x%08x): "
+ "IN: %02x %02x %02x %02x %02x %02x %02x %02x ",
+ pipe,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ req, 0, 0,
+ reg & 0xff, reg >> 8,
+ len & 0xff, len >> 8);
+ }
mutex_lock(&dev->ctrl_urb_lock);
- ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
+ ret = usb_control_msg(dev->udev, pipe, req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x0000, reg, dev->urb_buf, len, HZ);
if (ret < 0) {
@@ -93,7 +103,9 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
mutex_unlock(&dev->ctrl_urb_lock);
if (reg_debug) {
- printk("%02x values: ", ret);
+ int byte;
+
+ printk("<<<");
for (byte = 0; byte < len; byte++)
printk(" %02x", (unsigned char)buf[byte]);
printk("\n");
@@ -108,28 +120,12 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
*/
int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg)
{
- u8 val;
int ret;
+ u8 val;
- if (dev->state & DEV_DISCONNECTED)
- return(-ENODEV);
-
- em28xx_regdbg("req=%02x, reg=%02x:", req, reg);
-
- mutex_lock(&dev->ctrl_urb_lock);
- ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0000, reg, dev->urb_buf, 1, HZ);
- val = dev->urb_buf[0];
- mutex_unlock(&dev->ctrl_urb_lock);
-
- if (ret < 0) {
- printk(" failed!\n");
+ ret = em28xx_read_reg_req_len(dev, req, reg, &val, 1);
+ if (ret < 0)
return ret;
- }
-
- if (reg_debug)
- printk("%02x\n", (unsigned char) val);
return val;
}
@@ -147,6 +143,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
int len)
{
int ret;
+ int pipe = usb_sndctrlpipe(dev->udev, 0);
if (dev->state & DEV_DISCONNECTED)
return -ENODEV;
@@ -154,17 +151,25 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
if ((len < 1) || (len > URB_MAX_CTRL_SIZE))
return -EINVAL;
- em28xx_regdbg("req=%02x reg=%02x:", req, reg);
if (reg_debug) {
- int i;
- for (i = 0; i < len; ++i)
- printk(" %02x", (unsigned char)buf[i]);
+ int byte;
+
+ printk( KERN_DEBUG "(pipe 0x%08x): "
+ "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>",
+ pipe,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ req, 0, 0,
+ reg & 0xff, reg >> 8,
+ len & 0xff, len >> 8);
+
+ for (byte = 0; byte < len; byte++)
+ printk(" %02x", (unsigned char)buf[byte]);
printk("\n");
}
mutex_lock(&dev->ctrl_urb_lock);
memcpy(dev->urb_buf, buf, len);
- ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req,
+ ret = usb_control_msg(dev->udev, pipe, req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x0000, reg, dev->urb_buf, len, HZ);
mutex_unlock(&dev->ctrl_urb_lock);
@@ -255,7 +260,7 @@ static int em28xx_is_ac97_ready(struct em28xx *dev)
* em28xx_read_ac97()
* write a 16 bit value to the specified AC97 address (LSB first!)
*/
-static int em28xx_read_ac97(struct em28xx *dev, u8 reg)
+int em28xx_read_ac97(struct em28xx *dev, u8 reg)
{
int ret;
u8 addr = (reg & 0x7f) | 0x80;
@@ -281,7 +286,7 @@ static int em28xx_read_ac97(struct em28xx *dev, u8 reg)
* em28xx_write_ac97()
* write a 16 bit value to the specified AC97 address (LSB first!)
*/
-static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
{
int ret;
u8 addr = reg & 0x7f;
@@ -349,7 +354,7 @@ static int em28xx_set_audio_source(struct em28xx *dev)
int ret;
u8 input;
- if (dev->is_em2800) {
+ if (dev->board.is_em2800) {
if (dev->ctl_ainput == EM28XX_AMUX_VIDEO)
input = EM2800_AUDIO_SRC_TUNER;
else
@@ -360,7 +365,7 @@ static int em28xx_set_audio_source(struct em28xx *dev)
return ret;
}
- if (dev->has_msp34xx)
+ if (dev->board.has_msp34xx)
input = EM28XX_AUDIO_SRC_TUNER;
else {
switch (dev->ctl_ainput) {
@@ -399,7 +404,7 @@ struct em28xx_vol_table outputs[] = {
int em28xx_audio_analog_set(struct em28xx *dev)
{
int ret, i;
- u8 xclk = 0x07;
+ u8 xclk;
if (!dev->audio_mode.has_audio)
return 0;
@@ -417,13 +422,11 @@ int em28xx_audio_analog_set(struct em28xx *dev)
}
}
- if (dev->has_12mhz_i2s)
- xclk |= 0x20;
-
+ xclk = dev->board.xclk & 0x7f;
if (!dev->mute)
xclk |= 0x80;
- ret = em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, xclk, 0xa7);
+ ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk);
if (ret < 0)
return ret;
msleep(10);
@@ -462,7 +465,7 @@ int em28xx_audio_setup(struct em28xx *dev)
int vid1, vid2, feat, cfg;
u32 vid;
- if (dev->chip_id == CHIP_ID_EM2874) {
+ if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874) {
/* Digital only device - don't load any alsa module */
dev->audio_mode.has_audio = 0;
dev->has_audio_class = 0;
@@ -494,7 +497,8 @@ int em28xx_audio_setup(struct em28xx *dev)
dev->audio_mode.i2s_5rates = 1;
}
- if (!(cfg & EM28XX_CHIPCFG_AC97)) {
+ if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+ /* Skip the code that does AC97 vendor detection */
dev->audio_mode.ac97 = EM28XX_NO_AC97;
goto init_audio;
}
@@ -556,20 +560,20 @@ EXPORT_SYMBOL_GPL(em28xx_audio_setup);
int em28xx_colorlevels_set_default(struct em28xx *dev)
{
- em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1); /* contrast */
- em28xx_write_regs(dev, EM28XX_R21_YOFFSET, "\x00", 1); /* brightness */
- em28xx_write_regs(dev, EM28XX_R22_UVGAIN, "\x10", 1); /* saturation */
- em28xx_write_regs(dev, EM28XX_R23_UOFFSET, "\x00", 1);
- em28xx_write_regs(dev, EM28XX_R24_VOFFSET, "\x00", 1);
- em28xx_write_regs(dev, EM28XX_R25_SHARPNESS, "\x00", 1);
-
- em28xx_write_regs(dev, EM28XX_R14_GAMMA, "\x20", 1);
- em28xx_write_regs(dev, EM28XX_R15_RGAIN, "\x20", 1);
- em28xx_write_regs(dev, EM28XX_R16_GGAIN, "\x20", 1);
- em28xx_write_regs(dev, EM28XX_R17_BGAIN, "\x20", 1);
- em28xx_write_regs(dev, EM28XX_R18_ROFFSET, "\x00", 1);
- em28xx_write_regs(dev, EM28XX_R19_GOFFSET, "\x00", 1);
- return em28xx_write_regs(dev, EM28XX_R1A_BOFFSET, "\x00", 1);
+ em28xx_write_reg(dev, EM28XX_R20_YGAIN, 0x10); /* contrast */
+ em28xx_write_reg(dev, EM28XX_R21_YOFFSET, 0x00); /* brightness */
+ em28xx_write_reg(dev, EM28XX_R22_UVGAIN, 0x10); /* saturation */
+ em28xx_write_reg(dev, EM28XX_R23_UOFFSET, 0x00);
+ em28xx_write_reg(dev, EM28XX_R24_VOFFSET, 0x00);
+ em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, 0x00);
+
+ em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
+ em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
+ em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
+ em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
+ em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
+ em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
+ return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
}
int em28xx_capture_start(struct em28xx *dev, int start)
@@ -602,28 +606,37 @@ int em28xx_capture_start(struct em28xx *dev, int start)
if (!start) {
/* disable video capture */
- rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x27", 1);
+ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
return rc;
}
/* enable video capture */
- rc = em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+ rc = em28xx_write_reg(dev, 0x48, 0x00);
if (dev->mode == EM28XX_ANALOG_MODE)
- rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x67", 1);
+ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
else
- rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x37", 1);
+ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
msleep(6);
return rc;
}
-int em28xx_outfmt_set_yuv422(struct em28xx *dev)
+int em28xx_set_outfmt(struct em28xx *dev)
{
- em28xx_write_regs(dev, EM28XX_R27_OUTFMT, "\x34", 1);
- em28xx_write_regs(dev, EM28XX_R10_VINMODE, "\x10", 1);
- return em28xx_write_regs(dev, EM28XX_R11_VINCTRL, "\x11", 1);
+ int ret;
+
+ ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
+ dev->format->reg | 0x20, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, 0x10);
+ if (ret < 0)
+ return ret;
+
+ return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x11);
}
static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
@@ -660,7 +673,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
{
u8 mode;
/* the em2800 scaler only supports scaling down to 50% */
- if (dev->is_em2800)
+ if (dev->board.is_em2800)
mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
else {
u8 buf[2];
@@ -684,7 +697,7 @@ int em28xx_resolution_set(struct em28xx *dev)
width = norm_maxw(dev);
height = norm_maxh(dev) >> 1;
- em28xx_outfmt_set_yuv422(dev);
+ em28xx_set_outfmt(dev);
em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
@@ -739,12 +752,14 @@ int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
if (!gpio)
return rc;
- dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
- if (dev->mode == EM28XX_ANALOG_MODE)
- dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
- else
- dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x37", 1);
- msleep(6);
+ if (dev->mode != EM28XX_SUSPEND) {
+ em28xx_write_reg(dev, 0x48, 0x00);
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
+ else
+ em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
+ msleep(6);
+ }
/* Send GPIO reset sequences specified at board entry */
while (gpio->sleep >= 0) {
@@ -769,22 +784,25 @@ int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
if (dev->mode == set_mode)
return 0;
- if (set_mode == EM28XX_MODE_UNDEFINED) {
+ if (set_mode == EM28XX_SUSPEND) {
dev->mode = set_mode;
- return 0;
+
+ /* FIXME: add suspend support for ac97 */
+
+ return em28xx_gpio_set(dev, dev->board.suspend_gpio);
}
#if 0
/* Resource is locked */
- if (dev->mode != EM28XX_MODE_UNDEFINED)
+ if (dev->mode != EM28XX_SUSPEND)
return -EINVAL;
#endif
dev->mode = set_mode;
if (dev->mode == EM28XX_DIGITAL_MODE)
- return em28xx_gpio_set(dev, dev->digital_gpio);
+ return em28xx_gpio_set(dev, dev->board.dvb_gpio);
else
- return em28xx_gpio_set(dev, dev->analog_gpio);
+ return em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
}
EXPORT_SYMBOL_GPL(em28xx_set_mode);
@@ -967,3 +985,144 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
return 0;
}
EXPORT_SYMBOL_GPL(em28xx_init_isoc);
+
+/*
+ * em28xx_wake_i2c()
+ * configure i2c attached devices
+ */
+void em28xx_wake_i2c(struct em28xx *dev)
+{
+ struct v4l2_routing route;
+ int zero = 0;
+
+ route.input = INPUT(dev->ctl_input)->vmux;
+ route.output = 0;
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, &zero);
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+ em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
+}
+
+/*
+ * Device control list
+ */
+
+static LIST_HEAD(em28xx_devlist);
+static DEFINE_MUTEX(em28xx_devlist_mutex);
+
+struct em28xx *em28xx_get_device(int minor,
+ enum v4l2_buf_type *fh_type,
+ int *has_radio)
+{
+ struct em28xx *h, *dev = NULL;
+
+ *fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ *has_radio = 0;
+
+ mutex_lock(&em28xx_devlist_mutex);
+ list_for_each_entry(h, &em28xx_devlist, devlist) {
+ if (h->vdev->minor == minor)
+ dev = h;
+ if (h->vbi_dev->minor == minor) {
+ dev = h;
+ *fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ }
+ if (h->radio_dev &&
+ h->radio_dev->minor == minor) {
+ dev = h;
+ *has_radio = 1;
+ }
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+
+ return dev;
+}
+
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void em28xx_remove_from_devlist(struct em28xx *dev)
+{
+ mutex_lock(&em28xx_devlist_mutex);
+ list_del(&dev->devlist);
+ mutex_unlock(&em28xx_devlist_mutex);
+};
+
+void em28xx_add_into_devlist(struct em28xx *dev)
+{
+ mutex_lock(&em28xx_devlist_mutex);
+ list_add_tail(&dev->devlist, &em28xx_devlist);
+ mutex_unlock(&em28xx_devlist_mutex);
+};
+
+/*
+ * Extension interface
+ */
+
+static LIST_HEAD(em28xx_extension_devlist);
+static DEFINE_MUTEX(em28xx_extension_devlist_lock);
+
+int em28xx_register_extension(struct em28xx_ops *ops)
+{
+ struct em28xx *dev = NULL;
+
+ mutex_lock(&em28xx_devlist_mutex);
+ mutex_lock(&em28xx_extension_devlist_lock);
+ list_add_tail(&ops->next, &em28xx_extension_devlist);
+ list_for_each_entry(dev, &em28xx_devlist, devlist) {
+ if (dev)
+ ops->init(dev);
+ }
+ printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
+ mutex_unlock(&em28xx_extension_devlist_lock);
+ mutex_unlock(&em28xx_devlist_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(em28xx_register_extension);
+
+void em28xx_unregister_extension(struct em28xx_ops *ops)
+{
+ struct em28xx *dev = NULL;
+
+ mutex_lock(&em28xx_devlist_mutex);
+ list_for_each_entry(dev, &em28xx_devlist, devlist) {
+ if (dev)
+ ops->fini(dev);
+ }
+
+ mutex_lock(&em28xx_extension_devlist_lock);
+ printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
+ list_del(&ops->next);
+ mutex_unlock(&em28xx_extension_devlist_lock);
+ mutex_unlock(&em28xx_devlist_mutex);
+}
+EXPORT_SYMBOL(em28xx_unregister_extension);
+
+void em28xx_init_extension(struct em28xx *dev)
+{
+ struct em28xx_ops *ops = NULL;
+
+ mutex_lock(&em28xx_extension_devlist_lock);
+ if (!list_empty(&em28xx_extension_devlist)) {
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+ if (ops->init)
+ ops->init(dev);
+ }
+ }
+ mutex_unlock(&em28xx_extension_devlist_lock);
+}
+
+void em28xx_close_extension(struct em28xx *dev)
+{
+ struct em28xx_ops *ops = NULL;
+
+ mutex_lock(&em28xx_extension_devlist_lock);
+ if (!list_empty(&em28xx_extension_devlist)) {
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+ if (ops->fini)
+ ops->fini(dev);
+ }
+ }
+ mutex_unlock(&em28xx_extension_devlist_lock);
+}
diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c
index 714d35c51..8d3ed7dc8 100644
--- a/linux/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c
@@ -162,7 +162,7 @@ static int stop_streaming(struct em28xx_dvb *dvb)
em28xx_uninit_isoc(dev);
- em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+ em28xx_set_mode(dev, EM28XX_SUSPEND);
return 0;
}
@@ -216,7 +216,7 @@ static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
if (acquire)
return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
else
- return em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+ return em28xx_set_mode(dev, EM28XX_SUSPEND);
}
/* ------------------------------------------------------------------ */
@@ -394,7 +394,7 @@ static int dvb_init(struct em28xx *dev)
int result = 0;
struct em28xx_dvb *dvb;
- if (!dev->has_dvb) {
+ if (!dev->board.has_dvb) {
/* This device does not support the extension */
return 0;
}
@@ -410,8 +410,10 @@ static int dvb_init(struct em28xx *dev)
em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
/* init frontend */
switch (dev->model) {
+ case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
+ case EM2883_BOARD_KWORLD_HYBRID_A316:
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
dvb->frontend = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
@@ -467,12 +469,12 @@ static int dvb_init(struct em28xx *dev)
if (result < 0)
goto out_free;
- em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+ em28xx_set_mode(dev, EM28XX_SUSPEND);
printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
return 0;
out_free:
- em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+ em28xx_set_mode(dev, EM28XX_SUSPEND);
kfree(dvb);
dev->dvb = NULL;
return result;
@@ -480,7 +482,7 @@ out_free:
static int dvb_fini(struct em28xx *dev)
{
- if (!dev->has_dvb) {
+ if (!dev->board.has_dvb) {
/* This device does not support the extension */
return 0;
}
diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c
index ec3e3b157..7084728eb 100644
--- a/linux/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c
@@ -250,7 +250,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
(msgs[i].flags & I2C_M_RD) ? "read" : "write",
i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
if (!msgs[i].len) { /* no len: check only for device presence */
- if (dev->is_em2800)
+ if (dev->board.is_em2800)
rc = em2800_i2c_check_for_device(dev, addr);
else
rc = em28xx_i2c_check_for_device(dev, addr);
@@ -261,7 +261,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
} else if (msgs[i].flags & I2C_M_RD) {
/* read bytes */
- if (dev->is_em2800)
+ if (dev->board.is_em2800)
rc = em2800_i2c_recv_bytes(dev, addr,
msgs[i].buf,
msgs[i].len);
@@ -279,7 +279,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
for (byte = 0; byte < msgs[i].len; byte++)
printk(" %02x", msgs[i].buf[byte]);
}
- if (dev->is_em2800)
+ if (dev->board.is_em2800)
rc = em2800_i2c_send_bytes(dev, addr,
msgs[i].buf,
msgs[i].len);
@@ -388,47 +388,49 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
if (em_eeprom->id == 0x9567eb1a)
dev->hash = em28xx_hash_mem(eedata, len, 32);
- printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n",
- em_eeprom->id, dev->hash);
- printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
- em_eeprom->product_ID);
+ printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
+ dev->name, em_eeprom->id, dev->hash);
+
+ printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
switch (em_eeprom->chip_conf >> 4 & 0x3) {
case 0:
- printk(KERN_INFO "No audio on board.\n");
+ printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
break;
case 1:
- printk(KERN_INFO "AC97 audio (5 sample rates)\n");
+ printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
+ dev->name);
break;
case 2:
- printk(KERN_INFO "I2S audio, sample rate=32k\n");
+ printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n", dev->name);
break;
case 3:
- printk(KERN_INFO "I2S audio, 3 sample rates\n");
+ printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n", dev->name);
break;
}
if (em_eeprom->chip_conf & 1 << 3)
- printk(KERN_INFO "USB Remote wakeup capable\n");
+ printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
if (em_eeprom->chip_conf & 1 << 2)
- printk(KERN_INFO "USB Self power capable\n");
+ printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
switch (em_eeprom->chip_conf & 0x3) {
case 0:
- printk(KERN_INFO "500mA max power\n");
+ printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
break;
case 1:
- printk(KERN_INFO "400mA max power\n");
+ printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
break;
case 2:
- printk(KERN_INFO "300mA max power\n");
+ printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
break;
case 3:
- printk(KERN_INFO "200mA max power\n");
+ printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
break;
}
- printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
+ printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
+ dev->name,
em_eeprom->string_idx_table,
em_eeprom->string1,
em_eeprom->string2,
@@ -521,6 +523,9 @@ static int attach_inform(struct i2c_client *client)
static struct i2c_algorithm em28xx_algo = {
.master_xfer = em28xx_i2c_xfer,
.functionality = functionality,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static struct i2c_adapter em28xx_adap_template = {
diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c
index 29900920d..d6ef5c461 100644
--- a/linux/drivers/media/video/em28xx/em28xx-input.c
+++ b/linux/drivers/media/video/em28xx/em28xx-input.c
@@ -345,7 +345,7 @@ int em28xx_ir_init(struct em28xx *dev)
u8 ir_config;
int err = -ENOMEM;
- if (dev->ir_codes == NULL) {
+ if (dev->board.ir_codes == NULL) {
/* No remote control support */
return 0;
}
@@ -384,7 +384,7 @@ int em28xx_ir_init(struct em28xx *dev)
usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
strlcat(ir->phys, "/input0", sizeof(ir->phys));
- ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, dev->ir_codes);
+ ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, dev->board.ir_codes);
input_dev->name = ir->name;
input_dev->phys = ir->phys;
input_dev->id.bustype = BUS_USB;
diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h
index 98e95054e..24e39c568 100644
--- a/linux/drivers/media/video/em28xx/em28xx-reg.h
+++ b/linux/drivers/media/video/em28xx/em28xx-reg.h
@@ -22,8 +22,8 @@
/* em28xx Chip Configuration 0x00 */
#define EM28XX_CHIPCFG_VENDOR_AUDIO 0x80
#define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE 0x40
-#define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x30
-#define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x20
+#define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x30
+#define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x20
#define EM28XX_CHIPCFG_AC97 0x10
#define EM28XX_CHIPCFG_AUDIOMASK 0x30
@@ -51,6 +51,24 @@
#define EM28XX_R0E_AUDIOSRC 0x0e
#define EM28XX_R0F_XCLK 0x0f
+/* em28xx XCLK Register (0x0f) */
+#define EM28XX_XCLK_AUDIO_UNMUTE 0x80 /* otherwise audio muted */
+#define EM28XX_XCLK_I2S_MSB_TIMING 0x40 /* otherwise standard timing */
+#define EM28XX_XCLK_IR_RC5_MODE 0x20 /* otherwise NEC mode */
+#define EM28XX_XCLK_IR_NEC_CHK_PARITY 0x10
+#define EM28XX_XCLK_FREQUENCY_30MHZ 0x00 /* Freq. select (bits [3-0]) */
+#define EM28XX_XCLK_FREQUENCY_15MHZ 0x01
+#define EM28XX_XCLK_FREQUENCY_10MHZ 0x02
+#define EM28XX_XCLK_FREQUENCY_7_5MHZ 0x03
+#define EM28XX_XCLK_FREQUENCY_6MHZ 0x04
+#define EM28XX_XCLK_FREQUENCY_5MHZ 0x05
+#define EM28XX_XCLK_FREQUENCY_4_3MHZ 0x06
+#define EM28XX_XCLK_FREQUENCY_12MHZ 0x07
+#define EM28XX_XCLK_FREQUENCY_20MHZ 0x08
+#define EM28XX_XCLK_FREQUENCY_20MHZ_2 0x09
+#define EM28XX_XCLK_FREQUENCY_48MHZ 0x0a
+#define EM28XX_XCLK_FREQUENCY_24MHZ 0x0b
+
#define EM28XX_R10_VINMODE 0x10
#define EM28XX_R11_VINCTRL 0x11
#define EM28XX_R12_VINENABLE 0x12 /* */
@@ -79,6 +97,19 @@
#define EM28XX_R26_COMPR 0x26
#define EM28XX_R27_OUTFMT 0x27
+/* em28xx Output Format Register (0x27) */
+#define EM28XX_OUTFMT_RGB_8_RGRG 0x00
+#define EM28XX_OUTFMT_RGB_8_GRGR 0x01
+#define EM28XX_OUTFMT_RGB_8_GBGB 0x02
+#define EM28XX_OUTFMT_RGB_8_BGBG 0x03
+#define EM28XX_OUTFMT_RGB_16_656 0x04
+#define EM28XX_OUTFMT_RGB_8_BAYER 0x08 /* Pattern in Reg 0x10[1-0] */
+#define EM28XX_OUTFMT_YUV211 0x10
+#define EM28XX_OUTFMT_YUV422_Y0UY1V 0x14
+#define EM28XX_OUTFMT_YUV422_Y1UY0V 0x15
+#define EM28XX_OUTFMT_YUV411 0x18
+
+
#define EM28XX_R28_XMIN 0x28
#define EM28XX_R29_XMAX 0x29
#define EM28XX_R2A_YMIN 0x2a
@@ -129,10 +160,11 @@
/* FIXME: Need to be populated with the other chip ID's */
enum em28xx_chip_id {
- CHIP_ID_EM2820 = 18,
+ CHIP_ID_EM2820 = 18, /* Also used by em2710 */
CHIP_ID_EM2840 = 20,
CHIP_ID_EM2750 = 33,
CHIP_ID_EM2860 = 34,
+ CHIP_ID_EM2870 = 35,
CHIP_ID_EM2883 = 36,
CHIP_ID_EM2874 = 65,
};
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index 5da519bfa..eb3a87e0a 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -39,6 +39,7 @@
#include "em28xx.h"
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
#include <media/msp3400.h>
#include <media/tuner.h>
@@ -47,9 +48,8 @@
"Mauro Carvalho Chehab <mchehab@infradead.org>, " \
"Sascha Sommer <saschasommer@freenet.de>"
-#define DRIVER_NAME "em28xx"
#define DRIVER_DESC "Empia em28xx based USB video device driver"
-#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 0)
+#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 1)
#define em28xx_videodbg(fmt, arg...) do {\
if (video_debug) \
@@ -72,19 +72,13 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-static LIST_HEAD(em28xx_devlist);
-static DEFINE_MUTEX(em28xx_devlist_mutex);
-
-static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-module_param_array(card, int, NULL, 0444);
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(card, "card type");
MODULE_PARM_DESC(video_nr, "video device numbers");
MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
MODULE_PARM_DESC(radio_nr, "radio device numbers");
@@ -93,8 +87,15 @@ static unsigned int video_debug;
module_param(video_debug, int, 0644);
MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
-/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
-static unsigned long em28xx_devused;
+/* supported video standards */
+static struct em28xx_fmt format[] = {
+ {
+ .name = "16bpp YUY2, 4:2:2, packed",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .reg = EM28XX_OUTFMT_YUV422_Y0UY1V,
+ },
+};
/* supported controls */
/* Common to all boards */
@@ -120,8 +121,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
}
};
-static struct usb_driver em28xx_usb_driver;
-
/* ------------------------------------------------------------------
DMA and thread functions
------------------------------------------------------------------*/
@@ -390,16 +389,18 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
struct em28xx *dev = fh->dev;
struct v4l2_frequency f;
- *size = 16 * fh->dev->width * fh->dev->height >> 3;
+ *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
+
if (0 == *count)
*count = EM28XX_DEF_BUF;
if (*count < EM28XX_MIN_BUF)
*count = EM28XX_MIN_BUF;
- /* Ask tuner to go to analog mode */
+ /* Ask tuner to go to analog or radio mode */
memset(&f, 0, sizeof(f));
f.frequency = dev->ctl_freq;
+ f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
@@ -442,9 +443,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
struct em28xx *dev = fh->dev;
int rc = 0, urb_init = 0;
- /* FIXME: It assumes depth = 16 */
- /* The only currently supported format is 16 bits/pixel */
- buf->vb.size = 16 * dev->width * dev->height >> 3;
+ buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
@@ -512,57 +511,6 @@ static struct videobuf_queue_ops em28xx_video_qops = {
/********************* v4l2 interface **************************************/
-/*
- * em28xx_config()
- * inits registers with sane defaults
- */
-static int em28xx_config(struct em28xx *dev)
-{
- int retval;
-
- /* Sets I2C speed to 100 KHz */
- if (!dev->is_em2800) {
- retval = em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
- if (retval < 0) {
- em28xx_errdev("%s: em28xx_write_regs_req failed! retval [%d]\n",
- __func__, retval);
- return retval;
- }
- }
-
-#if 1
- /* enable vbi capturing */
-
-/* em28xx_write_regs_req(dev, 0x00, 0x0e, "\xC0", 1); audio register */
-/* em28xx_write_regs_req(dev, 0x00, 0x0f, "\x80", 1); clk register */
- em28xx_write_regs_req(dev, 0x00, 0x11, "\x51", 1);
-#endif
-
- dev->mute = 1; /* maybe not the right place... */
- dev->volume = 0x1f;
-
- em28xx_outfmt_set_yuv422(dev);
- em28xx_colorlevels_set_default(dev);
- em28xx_compression_disable(dev);
-
- return 0;
-}
-
-/*
- * em28xx_config_i2c()
- * configure i2c attached devices
- */
-static void em28xx_config_i2c(struct em28xx *dev)
-{
- struct v4l2_routing route;
-
- route.input = INPUT(dev->ctl_input)->vmux;
- route.output = 0;
- em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
- em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
- em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
-}
-
static void video_mux(struct em28xx *dev, int index)
{
struct v4l2_routing route;
@@ -578,7 +526,7 @@ static void video_mux(struct em28xx *dev, int index)
em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
- if (dev->has_msp34xx) {
+ if (dev->board.has_msp34xx) {
if (dev->i2s_speed) {
em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ,
&dev->i2s_speed);
@@ -604,12 +552,10 @@ static int res_get(struct em28xx_fh *fh)
return rc;
if (dev->stream_on)
- return -EINVAL;
+ return -EBUSY;
- mutex_lock(&dev->lock);
dev->stream_on = 1;
fh->stream_on = 1;
- mutex_unlock(&dev->lock);
return rc;
}
@@ -622,10 +568,8 @@ static void res_free(struct em28xx_fh *fh)
{
struct em28xx *dev = fh->dev;
- mutex_lock(&dev->lock);
fh->stream_on = 0;
dev->stream_on = 0;
- mutex_unlock(&dev->lock);
}
/*
@@ -712,8 +656,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- f->fmt.pix.bytesperline = dev->width * 2;
+ f->fmt.pix.pixelformat = dev->format->fourcc;
+ f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
@@ -725,6 +669,17 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
+static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(format); i++)
+ if (format[i].fourcc == fourcc)
+ return &format[i];
+
+ return NULL;
+}
+
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -735,24 +690,30 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
unsigned int maxw = norm_maxw(dev);
unsigned int maxh = norm_maxh(dev);
unsigned int hscale, vscale;
+ struct em28xx_fmt *fmt;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ em28xx_videodbg("Fourcc format (%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
/* width must even because of the YUYV format
height must be even because of interlacing */
height &= 0xfffe;
- width &= 0xfffe;
+ width &= 0xfffe;
- if (height < 32)
+ if (unlikely(height < 32))
height = 32;
- if (height > maxh)
+ if (unlikely(height > maxh))
height = maxh;
- if (width < 48)
+ if (unlikely(width < 48))
width = 48;
- if (width > maxw)
+ if (unlikely(width > maxw))
width = maxw;
- mutex_lock(&dev->lock);
-
- if (dev->is_em2800) {
+ if (dev->board.is_em2800) {
/* the em2800 can only scale down to 50% */
if (height % (maxh / 2))
height = maxh;
@@ -775,13 +736,12 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width = width;
f->fmt.pix.height = height;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- f->fmt.pix.bytesperline = width * 2;
- f->fmt.pix.sizeimage = width * 2 * height;
+ f->fmt.pix.pixelformat = fmt->fourcc;
+ f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- mutex_unlock(&dev->lock);
return 0;
}
@@ -791,14 +751,21 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
int rc;
+ struct em28xx_fmt *fmt;
rc = check_dev(dev);
if (rc < 0)
return rc;
+ mutex_lock(&dev->lock);
+
vidioc_try_fmt_vid_cap(file, priv, f);
- mutex_lock(&dev->lock);
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ rc = -EINVAL;
+ goto out;
+ }
if (videobuf_queue_is_busy(&fh->vb_vidq)) {
em28xx_errdev("%s queue busy\n", __func__);
@@ -815,6 +782,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
/* set new image size */
dev->width = f->fmt.pix.width;
dev->height = f->fmt.pix.height;
+ dev->format = fmt;
get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
em28xx_set_alternate(dev);
@@ -840,15 +808,12 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
mutex_lock(&dev->lock);
dev->norm = *norm;
- mutex_unlock(&dev->lock);
/* Adjusts width/height, if needed */
f.fmt.pix.width = dev->width;
f.fmt.pix.height = dev->height;
vidioc_try_fmt_vid_cap(file, priv, &f);
- mutex_lock(&dev->lock);
-
/* set new image size */
dev->width = f.fmt.pix.width;
dev->height = f.fmt.pix.height;
@@ -983,11 +948,15 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
if (a->index != dev->ctl_ainput)
return -EINVAL;
#else
+ mutex_lock(&dev->lock);
+
dev->ctl_ainput = INPUT(a->index)->amux;
dev->ctl_aoutput = INPUT(a->index)->aout;
if (!dev->ctl_aoutput)
dev->ctl_aoutput = EM28XX_AOUT_MASTER;
+
+ mutex_unlock(&dev->lock);
#endif
return 0;
}
@@ -1009,7 +978,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
qc->id = id;
- if (!dev->has_msp34xx) {
+ if (!dev->board.has_msp34xx) {
for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
if (qc->id && qc->id == em28xx_qctrl[i].id) {
memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
@@ -1037,17 +1006,14 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
rc = check_dev(dev);
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
+ rc = 0;
- if (!dev->has_msp34xx)
- rc = em28xx_get_ctrl(dev, ctrl);
- else
- rc = -EINVAL;
+ mutex_lock(&dev->lock);
- if (rc == -EINVAL) {
+ if (dev->board.has_msp34xx)
em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
- rc = 0;
- }
+ else
+ rc = em28xx_get_ctrl(dev, ctrl);
mutex_unlock(&dev->lock);
return rc;
@@ -1067,7 +1033,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
mutex_lock(&dev->lock);
- if (dev->has_msp34xx)
+ if (dev->board.has_msp34xx)
em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
else {
rc = 1;
@@ -1147,8 +1113,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
+ mutex_lock(&dev->lock);
f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
f->frequency = dev->ctl_freq;
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -1178,6 +1146,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
mutex_unlock(&dev->lock);
+
return 0;
}
@@ -1194,46 +1163,111 @@ static int em28xx_reg_len(int reg)
}
}
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+
+ em28xx_i2c_call_clients(dev, VIDIOC_DBG_G_CHIP_IDENT, chip);
+
+ return 0;
+}
+
+
static int vidioc_g_register(struct file *file, void *priv,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
int ret;
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_AC97:
+ mutex_lock(&dev->lock);
+ ret = em28xx_read_ac97(dev, reg->reg);
+ mutex_unlock(&dev->lock);
+ if (ret < 0)
+ return ret;
+
+ reg->val = ret;
+ reg->size = 1;
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ em28xx_i2c_call_clients(dev, VIDIOC_DBG_G_REGISTER, reg);
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ /* Not supported yet */
return -EINVAL;
+ default:
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+ }
- if (em28xx_reg_len(reg->reg) == 1) {
+ /* Match host */
+ reg->size = em28xx_reg_len(reg->reg);
+ if (reg->size == 1) {
+ mutex_lock(&dev->lock);
ret = em28xx_read_reg(dev, reg->reg);
+ mutex_unlock(&dev->lock);
+
if (ret < 0)
return ret;
reg->val = ret;
} else {
- __le64 val = 0;
+ __le16 val = 0;
+ mutex_lock(&dev->lock);
ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
reg->reg, (char *)&val, 2);
+ mutex_unlock(&dev->lock);
if (ret < 0)
return ret;
- reg->val = le64_to_cpu(val);
+ reg->val = le16_to_cpu(val);
}
return 0;
}
static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- __le64 buf;
+ __le16 buf;
+ int rc;
- buf = cpu_to_le64(reg->val);
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_AC97:
+ mutex_lock(&dev->lock);
+ rc = em28xx_write_ac97(dev, reg->reg, reg->val);
+ mutex_unlock(&dev->lock);
- return em28xx_write_regs(dev, reg->reg, (char *)&buf,
- em28xx_reg_len(reg->reg));
+ return rc;
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ em28xx_i2c_call_clients(dev, VIDIOC_DBG_S_REGISTER, reg);
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ /* Not supported yet */
+ return -EINVAL;
+ default:
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+ }
+
+ /* Match host */
+ buf = cpu_to_le16(reg->val);
+
+ mutex_lock(&dev->lock);
+ rc = em28xx_write_regs(dev, reg->reg, (char *)&buf,
+ em28xx_reg_len(reg->reg));
+ mutex_unlock(&dev->lock);
+
+ return rc;
}
#endif
@@ -1270,10 +1304,15 @@ static int vidioc_streamon(struct file *file, void *priv,
return rc;
- if (unlikely(res_get(fh) < 0))
- return -EBUSY;
+ mutex_lock(&dev->lock);
+ rc = res_get(fh);
- return (videobuf_streamon(&fh->vb_vidq));
+ if (likely(rc >= 0))
+ rc = videobuf_streamon(&fh->vb_vidq);
+
+ mutex_unlock(&dev->lock);
+
+ return rc;
}
static int vidioc_streamoff(struct file *file, void *priv,
@@ -1292,9 +1331,13 @@ static int vidioc_streamoff(struct file *file, void *priv,
if (type != fh->type)
return -EINVAL;
+ mutex_lock(&dev->lock);
+
videobuf_streamoff(&fh->vb_vidq);
res_free(fh);
+ mutex_unlock(&dev->lock);
+
return 0;
}
@@ -1326,15 +1369,13 @@ static int vidioc_querycap(struct file *file, void *priv,
}
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *fmtd)
+ struct v4l2_fmtdesc *f)
{
- if (fmtd->index != 0)
+ if (unlikely(f->index >= ARRAY_SIZE(format)))
return -EINVAL;
- fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(fmtd->description, "Packed YUY2");
- fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
- memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+ strlcpy(f->description, format[f->index].name, sizeof(f->description));
+ f->pixelformat = format[f->index].fourcc;
return 0;
}
@@ -1514,7 +1555,10 @@ static int radio_g_tuner(struct file *file, void *priv,
strcpy(t->name, "Radio");
t->type = V4L2_TUNER_RADIO;
+ mutex_lock(&dev->lock);
em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+ mutex_unlock(&dev->lock);
+
return 0;
}
@@ -1546,7 +1590,9 @@ static int radio_s_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
+ mutex_lock(&dev->lock);
em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -1585,31 +1631,16 @@ static int radio_queryctrl(struct file *file, void *priv,
* em28xx_v4l2_open()
* inits the device and starts isoc transfer
*/
-static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
+static int em28xx_v4l2_open(struct file *filp)
{
- int minor = iminor(inode);
- int errCode = 0, radio = 0;
- struct em28xx *h, *dev = NULL;
+ int minor = video_devdata(filp)->minor;
+ int errCode = 0, radio;
+ struct em28xx *dev;
+ enum v4l2_buf_type fh_type;
struct em28xx_fh *fh;
- enum v4l2_buf_type fh_type = 0;
- mutex_lock(&em28xx_devlist_mutex);
- list_for_each_entry(h, &em28xx_devlist, devlist) {
- if (h->vdev->minor == minor) {
- dev = h;
- fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- }
- if (h->vbi_dev->minor == minor) {
- dev = h;
- fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
- }
- if (h->radio_dev &&
- h->radio_dev->minor == minor) {
- radio = 1;
- dev = h;
- }
- }
- mutex_unlock(&em28xx_devlist_mutex);
+ dev = em28xx_get_device(minor, &fh_type, &radio);
+
if (NULL == dev)
return -ENODEV;
@@ -1651,7 +1682,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
/* Needed, since GPIO might have disabled power of
some i2c device
*/
- em28xx_config_i2c(dev);
+ em28xx_wake_i2c(dev);
#if 0
/* device needs to be initialized before isoc transfer */
@@ -1682,18 +1713,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
* unregisters the v4l2,i2c and usb devices
* called when the device gets disconected or at module unload
*/
-static void em28xx_release_resources(struct em28xx *dev)
+void em28xx_release_analog_resources(struct em28xx *dev)
{
/*FIXME: I2C IR should be disconnected */
- list_del(&dev->devlist);
- if (dev->sbutton_input_dev)
- em28xx_deregister_snapshot_button(dev);
-
- if (dev->ir)
- em28xx_ir_fini(dev);
-
if (dev->radio_dev) {
if (-1 != dev->radio_dev->minor)
video_unregister_device(dev->radio_dev);
@@ -1719,11 +1743,6 @@ static void em28xx_release_resources(struct em28xx *dev)
video_device_release(dev->vdev);
dev->vdev = NULL;
}
- em28xx_i2c_unregister(dev);
- usb_put_dev(dev->udev);
-
- /* Mark device as unused */
- em28xx_devused &= ~(1<<dev->devno);
}
/*
@@ -1731,7 +1750,7 @@ static void em28xx_release_resources(struct em28xx *dev)
* stops streaming and deallocates all resources allocated by the v4l2
* calls and ioctls
*/
-static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
+static int em28xx_v4l2_close(struct file *filp)
{
struct em28xx_fh *fh = filp->private_data;
struct em28xx *dev = fh->dev;
@@ -1740,11 +1759,10 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
em28xx_videodbg("users=%d\n", dev->users);
+ mutex_lock(&dev->lock);
if (res_check(fh))
res_free(fh);
- mutex_lock(&dev->lock);
-
if (dev->users == 1) {
videobuf_stop(&fh->vb_vidq);
videobuf_mmap_free(&fh->vb_vidq);
@@ -1758,9 +1776,12 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
return 0;
}
+ /* Save some power by putting tuner to sleep */
+ em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+
/* do this before setting alternate! */
em28xx_uninit_isoc(dev);
- em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+ em28xx_set_mode(dev, EM28XX_SUSPEND);
/* set alternate 0 */
dev->alt = 0;
@@ -1799,8 +1820,12 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
*/
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (unlikely(res_get(fh)))
- return -EBUSY;
+ mutex_lock(&dev->lock);
+ rc = res_get(fh);
+ mutex_unlock(&dev->lock);
+
+ if (unlikely(rc < 0))
+ return rc;
return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
filp->f_flags & O_NONBLOCK);
@@ -1822,7 +1847,11 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
if (rc < 0)
return rc;
- if (unlikely(res_get(fh) < 0))
+ mutex_lock(&dev->lock);
+ rc = res_get(fh);
+ mutex_unlock(&dev->lock);
+
+ if (unlikely(rc < 0))
return POLLERR;
if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
@@ -1840,13 +1869,17 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
struct em28xx *dev = fh->dev;
int rc;
- if (unlikely(res_get(fh) < 0))
- return -EBUSY;
-
rc = check_dev(dev);
if (rc < 0)
return rc;
+ mutex_lock(&dev->lock);
+ rc = res_get(fh);
+ mutex_unlock(&dev->lock);
+
+ if (unlikely(rc < 0))
+ return rc;
+
rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
@@ -1857,7 +1890,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
return rc;
}
-static const struct file_operations em28xx_v4l_fops = {
+static const struct v4l2_file_operations em28xx_v4l_fops = {
.owner = THIS_MODULE,
.open = em28xx_v4l2_open,
.release = em28xx_v4l2_close,
@@ -1865,8 +1898,6 @@ static const struct file_operations em28xx_v4l_fops = {
.poll = em28xx_v4l2_poll,
.mmap = em28xx_v4l2_mmap,
.ioctl = video_ioctl2,
- .llseek = no_llseek,
- .compat_ioctl = v4l_compat_ioctl32,
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -1908,6 +1939,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
+ .vidioc_g_chip_ident = vidioc_g_chip_ident,
#endif
#ifdef CONFIG_VIDEO_V4L1_COMPAT
.vidiocgmbuf = vidiocgmbuf,
@@ -1925,13 +1957,11 @@ static const struct video_device em28xx_video_template = {
.current_norm = V4L2_STD_PAL,
};
-static const struct file_operations radio_fops = {
+static const struct v4l2_file_operations radio_fops = {
.owner = THIS_MODULE,
.open = em28xx_v4l2_open,
.release = em28xx_v4l2_close,
.ioctl = video_ioctl2,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
@@ -1963,44 +1993,6 @@ static struct video_device em28xx_radio_template = {
/******************************** usb interface ******************************/
-static LIST_HEAD(em28xx_extension_devlist);
-static DEFINE_MUTEX(em28xx_extension_devlist_lock);
-
-int em28xx_register_extension(struct em28xx_ops *ops)
-{
- struct em28xx *dev = NULL;
-
- mutex_lock(&em28xx_devlist_mutex);
- mutex_lock(&em28xx_extension_devlist_lock);
- list_add_tail(&ops->next, &em28xx_extension_devlist);
- list_for_each_entry(dev, &em28xx_devlist, devlist) {
- if (dev)
- ops->init(dev);
- }
- printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
- mutex_unlock(&em28xx_extension_devlist_lock);
- mutex_unlock(&em28xx_devlist_mutex);
- return 0;
-}
-EXPORT_SYMBOL(em28xx_register_extension);
-
-void em28xx_unregister_extension(struct em28xx_ops *ops)
-{
- struct em28xx *dev = NULL;
-
- mutex_lock(&em28xx_devlist_mutex);
- list_for_each_entry(dev, &em28xx_devlist, devlist) {
- if (dev)
- ops->fini(dev);
- }
-
- mutex_lock(&em28xx_extension_devlist_lock);
- printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
- list_del(&ops->next);
- mutex_unlock(&em28xx_extension_devlist_lock);
- mutex_unlock(&em28xx_devlist_mutex);
-}
-EXPORT_SYMBOL(em28xx_unregister_extension);
static struct video_device *em28xx_vdev_init(struct em28xx *dev,
const struct video_device *template,
@@ -2023,10 +2015,45 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
return vfd;
}
-static int register_analog_devices(struct em28xx *dev)
+int em28xx_register_analog_devices(struct em28xx *dev)
{
int ret;
+ printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n",
+ dev->name,
+ (EM28XX_VERSION_CODE >> 16) & 0xff,
+ (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
+
+ /* Analog specific initialization */
+ dev->format = &format[0];
+ video_mux(dev, 0);
+
+#if 1
+ /* enable vbi capturing */
+
+/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
+/* em28xx_write_reg(dev, EM28XX_R0F_XCLK, 0x80); clk register */
+ em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51);
+#endif
+
+ dev->mute = 1; /* maybe not the right place... */
+ dev->volume = 0x1f;
+
+ em28xx_set_outfmt(dev);
+ em28xx_colorlevels_set_default(dev);
+ em28xx_compression_disable(dev);
+
+ /* set default norm */
+ dev->norm = em28xx_video_template.current_norm;
+ dev->width = norm_maxw(dev);
+ dev->height = norm_maxh(dev);
+ dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+ dev->hscale = 0;
+ dev->vscale = 0;
+
+ /* FIXME: This is a very bad hack! Not all devices have TV on input 2 */
+ dev->ctl_input = 2;
+
/* allocate and fill video video_device struct */
dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
if (!dev->vdev) {
@@ -2075,417 +2102,3 @@ static int register_analog_devices(struct em28xx *dev)
return 0;
}
-
-
-/*
- * em28xx_init_dev()
- * allocates and inits the device structs, registers i2c bus and v4l device
- */
-static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
- int minor)
-{
- struct em28xx_ops *ops = NULL;
- struct em28xx *dev = *devhandle;
- int retval = -ENOMEM;
- int errCode;
- unsigned int maxh, maxw;
-
- dev->udev = udev;
- mutex_init(&dev->lock);
- mutex_init(&dev->ctrl_urb_lock);
- spin_lock_init(&dev->slock);
- init_waitqueue_head(&dev->open);
- init_waitqueue_head(&dev->wait_frame);
- init_waitqueue_head(&dev->wait_stream);
-
- dev->em28xx_write_regs = em28xx_write_regs;
- dev->em28xx_read_reg = em28xx_read_reg;
- dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
- dev->em28xx_write_regs_req = em28xx_write_regs_req;
- dev->em28xx_read_reg_req = em28xx_read_reg_req;
- dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
-
- em28xx_pre_card_setup(dev);
-
- errCode = em28xx_config(dev);
- if (errCode) {
- em28xx_errdev("error configuring device\n");
- return -ENOMEM;
- }
-
- /* register i2c bus */
- errCode = em28xx_i2c_register(dev);
- if (errCode < 0) {
- em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n",
- __func__, errCode);
- return errCode;
- }
-
- /* Do board specific init and eeprom reading */
- em28xx_card_setup(dev);
-
- /* Configure audio */
- errCode = em28xx_audio_setup(dev);
- if (errCode < 0) {
- em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n",
- __func__, errCode);
- }
-
- /* configure the device */
- em28xx_config_i2c(dev);
-
- /* set default norm */
- dev->norm = em28xx_video_template.current_norm;
-
- maxw = norm_maxw(dev);
- maxh = norm_maxh(dev);
-
- /* set default image size */
- dev->width = maxw;
- dev->height = maxh;
- dev->interlaced = EM28XX_INTERLACED_DEFAULT;
- dev->hscale = 0;
- dev->vscale = 0;
- dev->ctl_input = 2;
-
- errCode = em28xx_config(dev);
- if (errCode < 0) {
- em28xx_errdev("%s: em28xx_config - errCode [%d]!\n",
- __func__, errCode);
- return errCode;
- }
-
- /* init video dma queues */
- INIT_LIST_HEAD(&dev->vidq.active);
- INIT_LIST_HEAD(&dev->vidq.queued);
-
-#if 0
- video_set_drvdata(dev->vbi_dev, dev);
-#endif
-
- if (dev->has_msp34xx) {
- /* Send a reset to other chips via gpio */
- errCode = em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
- if (errCode < 0) {
- em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(1) failed! errCode [%d]\n",
- __func__, errCode);
- return errCode;
- }
- msleep(3);
-
- errCode = em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
- if (errCode < 0) {
- em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(2) failed! errCode [%d]\n",
- __func__, errCode);
- return errCode;
- }
- msleep(3);
- }
-
- video_mux(dev, 0);
-
- mutex_lock(&em28xx_devlist_mutex);
- list_add_tail(&dev->devlist, &em28xx_devlist);
- retval = register_analog_devices(dev);
- if (retval < 0) {
- em28xx_release_resources(dev);
- mutex_unlock(&em28xx_devlist_mutex);
- goto fail_reg_devices;
- }
-
- mutex_lock(&em28xx_extension_devlist_lock);
- if (!list_empty(&em28xx_extension_devlist)) {
- list_for_each_entry(ops, &em28xx_extension_devlist, next) {
- if (ops->id)
- ops->init(dev);
- }
- }
- mutex_unlock(&em28xx_extension_devlist_lock);
- mutex_unlock(&em28xx_devlist_mutex);
-
- return 0;
-
-fail_unreg:
- em28xx_release_resources(dev);
-fail_reg_devices:
- mutex_unlock(&dev->lock);
- return retval;
-}
-
-#if defined(CONFIG_MODULES) && defined(MODULE)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
-static void request_module_async(void *ptr)
-{
- struct em28xx *dev = (struct em28xx *)ptr;
-#else
-static void request_module_async(struct work_struct *work)
-{
- struct em28xx *dev = container_of(work,
- struct em28xx, request_module_wk);
-#endif
-
- if (dev->has_audio_class)
- request_module("snd-usb-audio");
- else if (dev->has_alsa_audio)
- request_module("em28xx-alsa");
-
- if (dev->has_dvb)
- request_module("em28xx-dvb");
-}
-
-static void request_modules(struct em28xx *dev)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
- INIT_WORK(&dev->request_module_wk, request_module_async,
- (void *)dev);
-#else
- INIT_WORK(&dev->request_module_wk, request_module_async);
-#endif
- schedule_work(&dev->request_module_wk);
-}
-#else
-#define request_modules(dev)
-#endif /* CONFIG_MODULES */
-
-/*
- * em28xx_usb_probe()
- * checks for supported devices
- */
-static int em28xx_usb_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- const struct usb_endpoint_descriptor *endpoint;
- struct usb_device *udev;
- struct usb_interface *uif;
- struct em28xx *dev = NULL;
- int retval = -ENODEV;
- int i, nr, ifnum, isoc_pipe;
-
- udev = usb_get_dev(interface_to_usbdev(interface));
- ifnum = interface->altsetting[0].desc.bInterfaceNumber;
-
- /* Check to see next free device and mark as used */
- nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
- em28xx_devused |= 1<<nr;
-
- /* Don't register audio interfaces */
- if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
- em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n",
- udev->descriptor.idVendor,
- udev->descriptor.idProduct,
- ifnum,
- interface->altsetting[0].desc.bInterfaceClass);
-
- em28xx_devused &= ~(1<<nr);
- return -ENODEV;
- }
-
- endpoint = &interface->cur_altsetting->endpoint[0].desc;
-
- /* check if the device has the iso in endpoint at the correct place */
- if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
- USB_ENDPOINT_XFER_ISOC &&
- (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940))
- {
- /* It's a newer em2874/em2875 device */
- isoc_pipe = 0;
- } else {
- int check_interface = 1;
- isoc_pipe = 1;
- endpoint = &interface->cur_altsetting->endpoint[1].desc;
- if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
- USB_ENDPOINT_XFER_ISOC)
- check_interface = 0;
-
- if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
- check_interface = 0;
-
- if (!check_interface) {
- em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
- "interface %i, class %i found.\n",
- udev->descriptor.idVendor,
- udev->descriptor.idProduct,
- ifnum,
- interface->altsetting[0].desc.bInterfaceClass);
-
- em28xx_err(DRIVER_NAME " This is an anciliary "
- "interface not used by the driver\n");
-
- em28xx_devused &= ~(1<<nr);
- return -ENODEV;
- }
-
- }
-
- em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
- udev->descriptor.idVendor,
- udev->descriptor.idProduct,
- ifnum,
- interface->altsetting[0].desc.bInterfaceClass);
-
- if (nr >= EM28XX_MAXBOARDS) {
- printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
- EM28XX_MAXBOARDS);
- em28xx_devused &= ~(1<<nr);
- return -ENOMEM;
- }
-
- /* allocate memory for our device state and initialize it */
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
- em28xx_err(DRIVER_NAME ": out of memory!\n");
- em28xx_devused &= ~(1<<nr);
- return -ENOMEM;
- }
-
- snprintf(dev->name, 29, "em28xx #%d", nr);
- dev->devno = nr;
- dev->model = id->driver_info;
- dev->alt = -1;
-
- /* Checks if audio is provided by some interface */
- for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
- uif = udev->config->interface[i];
- if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
- dev->has_audio_class = 1;
- break;
- }
- }
-
- /* compute alternate max packet sizes */
- uif = udev->actconfig->interface[0];
-
- dev->num_alt = uif->num_altsetting;
- em28xx_info("Alternate settings: %i\n", dev->num_alt);
-/* dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)* */
- dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
-
- if (dev->alt_max_pkt_size == NULL) {
- em28xx_errdev("out of memory!\n");
- em28xx_devused &= ~(1<<nr);
- kfree(dev);
- return -ENOMEM;
- }
-
- for (i = 0; i < dev->num_alt ; i++) {
- u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.
- wMaxPacketSize);
- dev->alt_max_pkt_size[i] =
- (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- em28xx_info("Alternate setting %i, max size= %i\n", i,
- dev->alt_max_pkt_size[i]);
- }
-
- if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
- dev->model = card[nr];
-
- /* allocate device struct */
- retval = em28xx_init_dev(&dev, udev, nr);
- if (retval) {
- em28xx_devused &= ~(1<<dev->devno);
- kfree(dev);
-
- return retval;
- }
-
- em28xx_info("Found %s\n", em28xx_boards[dev->model].name);
-
- /* save our data pointer in this interface device */
- usb_set_intfdata(interface, dev);
-
- request_modules(dev);
-
- return 0;
-}
-
-/*
- * em28xx_usb_disconnect()
- * called when the device gets diconencted
- * video device will be unregistered on v4l2_close in case it is still open
- */
-static void em28xx_usb_disconnect(struct usb_interface *interface)
-{
- struct em28xx *dev;
- struct em28xx_ops *ops = NULL;
-
- dev = usb_get_intfdata(interface);
- usb_set_intfdata(interface, NULL);
-
- if (!dev)
- return;
-
- em28xx_info("disconnecting %s\n", dev->vdev->name);
-
- /* wait until all current v4l2 io is finished then deallocate
- resources */
- mutex_lock(&dev->lock);
-
- wake_up_interruptible_all(&dev->open);
-
- if (dev->users) {
- em28xx_warn
- ("device /dev/video%d is open! Deregistration and memory "
- "deallocation are deferred on close.\n",
- dev->vdev->num);
-
- dev->state |= DEV_MISCONFIGURED;
- em28xx_uninit_isoc(dev);
- dev->state |= DEV_DISCONNECTED;
- wake_up_interruptible(&dev->wait_frame);
- wake_up_interruptible(&dev->wait_stream);
- } else {
- dev->state |= DEV_DISCONNECTED;
- em28xx_release_resources(dev);
- }
- mutex_unlock(&dev->lock);
-
- mutex_lock(&em28xx_extension_devlist_lock);
- if (!list_empty(&em28xx_extension_devlist)) {
- list_for_each_entry(ops, &em28xx_extension_devlist, next) {
- ops->fini(dev);
- }
- }
- mutex_unlock(&em28xx_extension_devlist_lock);
-
- if (!dev->users) {
- kfree(dev->alt_max_pkt_size);
- kfree(dev);
- }
-}
-
-static struct usb_driver em28xx_usb_driver = {
- .name = "em28xx",
- .probe = em28xx_usb_probe,
- .disconnect = em28xx_usb_disconnect,
- .id_table = em28xx_id_table,
-};
-
-static int __init em28xx_module_init(void)
-{
- int result;
-
- printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n",
- (EM28XX_VERSION_CODE >> 16) & 0xff,
- (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
- printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n",
- SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100);
-#endif
-
- /* register this driver with the USB subsystem */
- result = usb_register(&em28xx_usb_driver);
- if (result)
- em28xx_err(DRIVER_NAME
- " usb_register failed. Error number %d.\n", result);
-
- return result;
-}
-
-static void __exit em28xx_module_exit(void)
-{
- /* deregister this driver with the USB subsystem */
- usb_deregister(&em28xx_usb_driver);
-}
-
-module_init(em28xx_module_init);
-module_exit(em28xx_module_exit);
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index 151668c60..06fe92efc 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -68,7 +68,6 @@
#define EM2820_BOARD_HERCULES_SMART_TV_USB2 26
#define EM2820_BOARD_PINNACLE_USB_2_FM1216ME 27
#define EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE 28
-#define EM2820_BOARD_PINNACLE_DVC_100 29
#define EM2820_BOARD_VIDEOLOGY_20K14XUSB 30
#define EM2821_BOARD_USBGEAR_VD204 31
#define EM2821_BOARD_SUPERCOMP_USB_2 32
@@ -98,7 +97,8 @@
#define EM2882_BOARD_PINNACLE_HYBRID_PRO 56
#define EM2883_BOARD_KWORLD_HYBRID_A316 57
#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58
-#define EM2874_BOARD_PINNACLE_PCTV_80E 59
+#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60
+#define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -161,7 +161,7 @@
#define EM2800_I2C_WRITE_TIMEOUT 20
enum em28xx_mode {
- EM28XX_MODE_UNDEFINED,
+ EM28XX_SUSPEND,
EM28XX_ANALOG_MODE,
EM28XX_DIGITAL_MODE,
};
@@ -209,9 +209,12 @@ struct em28xx_usb_isoc_ctl {
};
+/* Struct to enumberate video formats */
struct em28xx_fmt {
char *name;
u32 fourcc; /* v4l2 format id */
+ int depth;
+ int reg;
};
/* buffer for one video frame */
@@ -305,11 +308,18 @@ enum em28xx_aout {
EM28XX_AOUT_SURR = 1 << 4,
};
+struct em28xx_reg_seq {
+ int reg;
+ unsigned char val, mask;
+ int sleep;
+};
+
struct em28xx_input {
enum enum28xx_itype type;
unsigned int vmux;
enum em28xx_amux amux;
enum em28xx_aout aout;
+ struct em28xx_reg_seq *gpio;
};
#define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
@@ -317,14 +327,7 @@ struct em28xx_input {
enum em28xx_decoder {
EM28XX_NODECODER,
EM28XX_TVP5150,
- EM28XX_SAA7113,
- EM28XX_SAA7114
-};
-
-struct em28xx_reg_seq {
- int reg;
- unsigned char val, mask;
- int sleep;
+ EM28XX_SAA711X,
};
struct em28xx_board {
@@ -336,15 +339,21 @@ struct em28xx_board {
/* i2c flags */
unsigned int tda9887_conf;
+ /* GPIO sequences */
+ struct em28xx_reg_seq *dvb_gpio;
+ struct em28xx_reg_seq *suspend_gpio;
+ struct em28xx_reg_seq *tuner_gpio;
+
unsigned int is_em2800:1;
unsigned int has_msp34xx:1;
unsigned int mts_firmware:1;
- unsigned int has_12mhz_i2s:1;
unsigned int max_range_640_480:1;
unsigned int has_dvb:1;
unsigned int has_snapshot_button:1;
unsigned int valid:1;
+ unsigned char xclk, i2c_speed;
+
enum em28xx_decoder decoder;
struct em28xx_input input[MAX_EM28XX_INPUT];
@@ -425,35 +434,24 @@ struct em28xx {
int model; /* index in the device_data struct */
int devno; /* marks the number of this device */
enum em28xx_chip_id chip_id;
- unsigned int is_em2800:1;
- unsigned int has_msp34xx:1;
- unsigned int has_tda9887:1;
+
+ struct em28xx_board board;
+
unsigned int stream_on:1; /* Locks streams */
unsigned int has_audio_class:1;
unsigned int has_alsa_audio:1;
- unsigned int has_12mhz_i2s:1;
- unsigned int max_range_640_480:1;
- unsigned int has_dvb:1;
- unsigned int has_snapshot_button:1;
- unsigned int valid:1; /* report for validated boards */
+
+ struct em28xx_fmt *format;
struct em28xx_IR *ir;
/* Some older em28xx chips needs a waiting time after writing */
unsigned int wait_after_write;
- /* GPIO sequences for analog and digital mode */
- struct em28xx_reg_seq *analog_gpio, *digital_gpio;
-
- /* GPIO sequences for tuner callbacks */
- struct em28xx_reg_seq *tun_analog_gpio, *tun_digital_gpio;
-
- int video_inputs; /* number of video inputs */
struct list_head devlist;
u32 i2s_speed; /* I2S speed for audio digital stream */
- enum em28xx_decoder decoder;
struct em28xx_audio_mode audio_mode;
int tuner_type; /* type of the tuner */
@@ -484,7 +482,7 @@ struct em28xx {
unsigned long i2c_hash; /* i2c devicelist hash -
for boards with generic ID */
- struct em28xx_audio *adev;
+ struct em28xx_audio adev;
/* states */
enum em28xx_dev_state state;
@@ -536,9 +534,6 @@ struct em28xx {
/* Caches GPO and GPIO registers */
unsigned char reg_gpo, reg_gpio;
- /* Infrared remote control support */
- IR_KEYTAB_TYPE *ir_codes;
-
/* Snapshot button */
char snapshot_button_path[30]; /* path of the input dev */
struct input_dev *sbutton_input_dev;
@@ -581,12 +576,15 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val);
+int em28xx_read_ac97(struct em28xx *dev, u8 reg);
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
+
int em28xx_audio_analog_set(struct em28xx *dev);
int em28xx_audio_setup(struct em28xx *dev);
int em28xx_colorlevels_set_default(struct em28xx *dev);
int em28xx_capture_start(struct em28xx *dev, int start);
-int em28xx_outfmt_set_yuv422(struct em28xx *dev);
+int em28xx_set_outfmt(struct em28xx *dev);
int em28xx_resolution_set(struct em28xx *dev);
int em28xx_set_alternate(struct em28xx *dev);
int em28xx_init_isoc(struct em28xx *dev, int max_packets,
@@ -595,10 +593,20 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
void em28xx_uninit_isoc(struct em28xx *dev);
int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
-
-/* Provided by em28xx-video.c */
+void em28xx_wake_i2c(struct em28xx *dev);
+void em28xx_remove_from_devlist(struct em28xx *dev);
+void em28xx_add_into_devlist(struct em28xx *dev);
+struct em28xx *em28xx_get_device(int minor,
+ enum v4l2_buf_type *fh_type,
+ int *has_radio);
int em28xx_register_extension(struct em28xx_ops *dev);
void em28xx_unregister_extension(struct em28xx_ops *dev);
+void em28xx_init_extension(struct em28xx *dev);
+void em28xx_close_extension(struct em28xx *dev);
+
+/* Provided by em28xx-video.c */
+int em28xx_register_analog_devices(struct em28xx *dev);
+void em28xx_release_analog_resources(struct em28xx *dev);
/* Provided by em28xx-cards.c */
extern int em2800_variant_detect(struct usb_device *udev, int model);
@@ -609,6 +617,7 @@ extern struct usb_device_id em28xx_id_table[];
extern const unsigned int em28xx_bcount;
void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
+void em28xx_release_resources(struct em28xx *dev);
/* Provided by em28xx-input.c */
int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
@@ -640,7 +649,7 @@ int em28xx_ir_fini(struct em28xx *dev);
static inline int em28xx_compression_disable(struct em28xx *dev)
{
/* side effect of disabling scaler and mixer */
- return em28xx_write_regs(dev, EM28XX_R26_COMPR, "\x00", 1);
+ return em28xx_write_reg(dev, EM28XX_R26_COMPR, 0x00);
}
static inline int em28xx_contrast_get(struct em28xx *dev)
@@ -712,7 +721,7 @@ static inline int em28xx_gamma_set(struct em28xx *dev, s32 val)
/*FIXME: maxw should be dependent of alt mode */
static inline unsigned int norm_maxw(struct em28xx *dev)
{
- if (dev->max_range_640_480)
+ if (dev->board.max_range_640_480)
return 640;
else
return 720;
@@ -720,7 +729,7 @@ static inline unsigned int norm_maxw(struct em28xx *dev)
static inline unsigned int norm_maxh(struct em28xx *dev)
{
- if (dev->max_range_640_480)
+ if (dev->board.max_range_640_480)
return 480;
else
return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
diff --git a/linux/drivers/media/video/et61x251/et61x251_core.c b/linux/drivers/media/video/et61x251/et61x251_core.c
index 52e0f2710..bf88a1387 100644
--- a/linux/drivers/media/video/et61x251/et61x251_core.c
+++ b/linux/drivers/media/video/et61x251/et61x251_core.c
@@ -1210,7 +1210,7 @@ static void et61x251_release_resources(struct kref *kref)
}
-static int et61x251_open(struct inode* inode, struct file* filp)
+static int et61x251_open(struct file *filp)
{
struct et61x251_device* cam;
int err = 0;
@@ -1295,7 +1295,7 @@ out:
}
-static int et61x251_release(struct inode* inode, struct file* filp)
+static int et61x251_release(struct file *filp)
{
struct et61x251_device* cam;
@@ -2396,8 +2396,8 @@ et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg)
}
-static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
- unsigned int cmd, void __user * arg)
+static long et61x251_ioctl_v4l2(struct file *filp,
+ unsigned int cmd, void __user *arg)
{
struct et61x251_device *cam = video_drvdata(filp);
@@ -2491,11 +2491,11 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
}
-static int et61x251_ioctl(struct inode* inode, struct file* filp,
+static long et61x251_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct et61x251_device *cam = video_drvdata(filp);
- int err = 0;
+ long err = 0;
if (mutex_lock_interruptible(&cam->fileop_mutex))
return -ERESTARTSYS;
@@ -2515,7 +2515,7 @@ static int et61x251_ioctl(struct inode* inode, struct file* filp,
V4LDBG(3, "et61x251", cmd);
- err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
+ err = et61x251_ioctl_v4l2(filp, cmd, (void __user *)arg);
mutex_unlock(&cam->fileop_mutex);
@@ -2523,18 +2523,14 @@ static int et61x251_ioctl(struct inode* inode, struct file* filp,
}
-static const struct file_operations et61x251_fops = {
+static const struct v4l2_file_operations et61x251_fops = {
.owner = THIS_MODULE,
.open = et61x251_open,
.release = et61x251_release,
.ioctl = et61x251_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
.read = et61x251_read,
.poll = et61x251_poll,
.mmap = et61x251_mmap,
- .llseek = no_llseek,
};
/*****************************************************************************/
diff --git a/linux/drivers/media/video/gspca/Kconfig b/linux/drivers/media/video/gspca/Kconfig
index 770fb699d..ee6a691df 100644
--- a/linux/drivers/media/video/gspca/Kconfig
+++ b/linux/drivers/media/video/gspca/Kconfig
@@ -18,6 +18,7 @@ menuconfig USB_GSPCA
if USB_GSPCA && VIDEO_V4L2
source "drivers/media/video/gspca/m5602/Kconfig"
+source "drivers/media/video/gspca/stv06xx/Kconfig"
config USB_GSPCA_CONEX
tristate "Conexant Camera Driver"
diff --git a/linux/drivers/media/video/gspca/Makefile b/linux/drivers/media/video/gspca/Makefile
index 6c8046e23..bd8d9ee40 100644
--- a/linux/drivers/media/video/gspca/Makefile
+++ b/linux/drivers/media/video/gspca/Makefile
@@ -47,4 +47,4 @@ gspca_vc032x-objs := vc032x.o
gspca_zc3xx-objs := zc3xx.o
obj-$(CONFIG_USB_M5602) += m5602/
-
+obj-$(CONFIG_USB_STV06XX) += stv06xx/
diff --git a/linux/drivers/media/video/gspca/conex.c b/linux/drivers/media/video/gspca/conex.c
index de28354ea..1753f5bb3 100644
--- a/linux/drivers/media/video/gspca/conex.c
+++ b/linux/drivers/media/video/gspca/conex.c
@@ -93,7 +93,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 176,
.sizeimage = 176 * 144 * 3 / 8 + 590,
diff --git a/linux/drivers/media/video/gspca/etoms.c b/linux/drivers/media/video/gspca/etoms.c
index 28869ef26..84b56c303 100644
--- a/linux/drivers/media/video/gspca/etoms.c
+++ b/linux/drivers/media/video/gspca/etoms.c
@@ -112,7 +112,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240,
@@ -125,7 +125,7 @@ static struct v4l2_pix_format vga_mode[] = {
.priv = 0}, */
};
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
{176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 176,
.sizeimage = 176 * 144,
diff --git a/linux/drivers/media/video/gspca/finepix.c b/linux/drivers/media/video/gspca/finepix.c
index 03cb94466..afc8b2dd3 100644
--- a/linux/drivers/media/video/gspca/finepix.c
+++ b/linux/drivers/media/video/gspca/finepix.c
@@ -72,7 +72,7 @@ struct usb_fpix {
}
/* These cameras only support 320x200. */
-static struct v4l2_pix_format fpix_mode[1] = {
+static const struct v4l2_pix_format fpix_mode[1] = {
{ 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c
index d725663fc..479b4feea 100644
--- a/linux/drivers/media/video/gspca/gspca.c
+++ b/linux/drivers/media/video/gspca/gspca.c
@@ -649,8 +649,11 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
"usb_submit_urb [%d] err %d", n, ret);
gspca_dev->streaming = 0;
destroy_urbs(gspca_dev);
- if (ret == -ENOSPC)
+ if (ret == -ENOSPC) {
+ msleep(20); /* wait for kill
+ * complete */
break; /* try the previous alt */
+ }
goto out;
}
}
@@ -668,7 +671,7 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
if (ret < 0)
- PDEBUG(D_ERR|D_STREAM, "set interface 0 err %d", ret);
+ PDEBUG(D_ERR|D_STREAM, "set alt 0 err %d", ret);
return ret;
}
@@ -782,8 +785,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct gspca_dev *gspca_dev = priv;
int mode;
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
mode = gspca_dev->curr_mode;
memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode],
sizeof fmt->fmt.pix);
@@ -795,8 +796,6 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
{
int w, h, mode, mode2;
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
w = fmt->fmt.pix.width;
h = fmt->fmt.pix.height;
@@ -886,7 +885,7 @@ static void gspca_release(struct video_device *vfd)
kfree(gspca_dev);
}
-static int dev_open(struct inode *inode, struct file *file)
+static int dev_open(struct file *file)
{
struct gspca_dev *gspca_dev;
int ret;
@@ -933,7 +932,7 @@ out:
return ret;
}
-static int dev_close(struct inode *inode, struct file *file)
+static int dev_close(struct file *file)
{
struct gspca_dev *gspca_dev = file->private_data;
@@ -1078,6 +1077,35 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
return -EINVAL;
}
+/*fixme: have an audio flag in gspca_dev?*/
+static int vidioc_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+{
+ if (audio->index != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+{
+ memset(audio, 0, sizeof *audio);
+ strcpy(audio->name, "Microphone");
+ return 0;
+}
+
+static int vidioc_enumaudio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+{
+ if (audio->index != 0)
+ return -EINVAL;
+
+ strcpy(audio->name, "Microphone");
+ audio->capability = 0;
+ audio->mode = 0;
+ return 0;
+}
+
static int vidioc_querymenu(struct file *file, void *priv,
struct v4l2_querymenu *qmenu)
{
@@ -1121,8 +1149,6 @@ static int vidioc_reqbufs(struct file *file, void *priv,
struct gspca_dev *gspca_dev = priv;
int i, ret = 0;
- if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
switch (rb->memory) {
case GSPCA_MEMORY_READ: /* (internal call) */
case V4L2_MEMORY_MMAP:
@@ -1187,8 +1213,7 @@ static int vidioc_querybuf(struct file *file, void *priv,
struct gspca_dev *gspca_dev = priv;
struct gspca_frame *frame;
- if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
- || v4l2_buf->index < 0
+ if (v4l2_buf->index < 0
|| v4l2_buf->index >= gspca_dev->nframes)
return -EINVAL;
@@ -1211,7 +1236,8 @@ static int vidioc_streamon(struct file *file, void *priv,
ret = -ENODEV;
goto out;
}
- if (gspca_dev->nframes == 0) {
+ if (gspca_dev->nframes == 0
+ || !(gspca_dev->frame[0].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)) {
ret = -EINVAL;
goto out;
}
@@ -1288,10 +1314,10 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
struct gspca_dev *gspca_dev = priv;
int ret;
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
if (!gspca_dev->sd_desc->set_jcomp)
return -EINVAL;
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
mutex_unlock(&gspca_dev->usb_lock);
return ret;
@@ -1305,6 +1331,17 @@ static int vidioc_g_parm(struct file *filp, void *priv,
memset(parm, 0, sizeof *parm);
parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
parm->parm.capture.readbuffers = gspca_dev->nbufread;
+
+ if (gspca_dev->sd_desc->get_streamparm) {
+ int ret;
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ ret = gspca_dev->sd_desc->get_streamparm(gspca_dev, parm);
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+ }
+
return 0;
}
@@ -1319,6 +1356,17 @@ static int vidioc_s_parm(struct file *filp, void *priv,
parm->parm.capture.readbuffers = gspca_dev->nbufread;
else
gspca_dev->nbufread = n;
+
+ if (gspca_dev->sd_desc->set_streamparm) {
+ int ret;
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ ret = gspca_dev->sd_desc->set_streamparm(gspca_dev, parm);
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+ }
+
return 0;
}
@@ -1507,8 +1555,6 @@ static int vidioc_dqbuf(struct file *file, void *priv,
int i, ret;
PDEBUG(D_FRAM, "dqbuf");
- if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
if (v4l2_buf->memory != gspca_dev->memory)
return -EINVAL;
@@ -1563,8 +1609,6 @@ static int vidioc_qbuf(struct file *file, void *priv,
int i, index, ret;
PDEBUG(D_FRAM, "qbuf %d", v4l2_buf->index);
- if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
@@ -1768,17 +1812,13 @@ out:
return ret;
}
-static struct file_operations dev_fops = {
+static struct v4l2_file_operations dev_fops = {
.owner = THIS_MODULE,
.open = dev_open,
.release = dev_close,
.read = dev_read,
.mmap = dev_mmap,
- .ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
+ .unlocked_ioctl = video_ioctl2,
.poll = dev_poll,
};
@@ -1794,6 +1834,9 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
.vidioc_queryctrl = vidioc_queryctrl,
.vidioc_g_ctrl = vidioc_g_ctrl,
.vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_enumaudio = vidioc_enumaudio,
.vidioc_querymenu = vidioc_querymenu,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h
index 15db13296..c90af9cb1 100644
--- a/linux/drivers/media/video/gspca/gspca.h
+++ b/linux/drivers/media/video/gspca/gspca.h
@@ -56,7 +56,7 @@ extern int gspca_debug;
/* device information - set at probe time */
struct cam {
int bulk_size; /* buffer size when image transfer by bulk */
- struct v4l2_pix_format *cam_mode; /* size nmodes */
+ const struct v4l2_pix_format *cam_mode; /* size nmodes */
char nmodes;
__u8 bulk_nurbs; /* number of URBs in bulk mode
* - cannot be > MAX_NURBS
@@ -74,6 +74,8 @@ typedef void (*cam_v_op) (struct gspca_dev *);
typedef int (*cam_cf_op) (struct gspca_dev *, const struct usb_device_id *);
typedef int (*cam_jpg_op) (struct gspca_dev *,
struct v4l2_jpegcompression *);
+typedef int (*cam_streamparm_op) (struct gspca_dev *,
+ struct v4l2_streamparm *);
typedef int (*cam_qmnu_op) (struct gspca_dev *,
struct v4l2_querymenu *);
typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
@@ -106,6 +108,8 @@ struct sd_desc {
cam_jpg_op get_jcomp;
cam_jpg_op set_jcomp;
cam_qmnu_op querymenu;
+ cam_streamparm_op get_streamparm;
+ cam_streamparm_op set_streamparm;
};
/* packet types when moving from iso buf to frame buf */
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_bridge.h b/linux/drivers/media/video/gspca/m5602/m5602_bridge.h
index c1c7ce524..a3f3b7a0c 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_bridge.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_bridge.h
@@ -109,7 +109,6 @@ static const unsigned char sensor_urb_skeleton[] = {
0x13, M5602_XB_I2C_CTRL, 0x81, 0x11
};
-/* m5602 device descriptor, currently it just wraps the m5602_camera struct */
struct sd {
struct gspca_dev gspca_dev;
@@ -134,4 +133,10 @@ int m5602_read_bridge(
int m5602_write_bridge(
struct sd *sd, u8 address, u8 i2c_data);
+int m5602_write_sensor(struct sd *sd, const u8 address,
+ u8 *i2c_data, const u8 len);
+
+int m5602_read_sensor(struct sd *sd, const u8 address,
+ u8 *i2c_data, const u8 len);
+
#endif
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_core.c b/linux/drivers/media/video/gspca/m5602/m5602_core.c
index fd6ce384b..ed906fe31 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_core.c
@@ -24,7 +24,7 @@
/* Kernel module parameters */
int force_sensor;
-int dump_bridge;
+static int dump_bridge;
int dump_sensor;
static const __devinitdata struct usb_device_id m5602_table[] = {
@@ -80,6 +80,97 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
return (err < 0) ? err : 0;
}
+int m5602_read_sensor(struct sd *sd, const u8 address,
+ u8 *i2c_data, const u8 len)
+{
+ int err, i;
+
+ if (!len || len > sd->sensor->i2c_regW)
+ return -EINVAL;
+
+ do {
+ err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+ } while ((*i2c_data & I2C_BUSY) && !err);
+ if (err < 0)
+ goto out;
+
+ err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
+ sd->sensor->i2c_slave_id);
+ if (err < 0)
+ goto out;
+
+ err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
+ if (err < 0)
+ goto out;
+
+ if (sd->sensor->i2c_regW == 1) {
+ err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, len);
+ if (err < 0)
+ goto out;
+
+ err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
+ if (err < 0)
+ goto out;
+ } else {
+ err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
+ if (err < 0)
+ goto out;
+ }
+
+ for (i = 0; (i < len) && !err; i++) {
+ err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
+
+ PDEBUG(D_CONF, "Reading sensor register "
+ "0x%x containing 0x%x ", address, *i2c_data);
+ }
+out:
+ return err;
+}
+
+int m5602_write_sensor(struct sd *sd, const u8 address,
+ u8 *i2c_data, const u8 len)
+{
+ int err, i;
+ u8 *p;
+ struct usb_device *udev = sd->gspca_dev.dev;
+ __u8 *buf = sd->gspca_dev.usb_buf;
+
+ /* No sensor with a data width larger than 16 bits has yet been seen */
+ if (len > sd->sensor->i2c_regW || !len)
+ return -EINVAL;
+
+ memcpy(buf, sensor_urb_skeleton,
+ sizeof(sensor_urb_skeleton));
+
+ buf[11] = sd->sensor->i2c_slave_id;
+ buf[15] = address;
+
+ /* Special case larger sensor writes */
+ p = buf + 16;
+
+ /* Copy a four byte write sequence for each byte to be written to */
+ for (i = 0; i < len; i++) {
+ memcpy(p, sensor_urb_skeleton + 16, 4);
+ p[3] = i2c_data[i];
+ p += 4;
+ PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
+ address, i2c_data[i]);
+ }
+
+ /* Copy the tailer */
+ memcpy(p, sensor_urb_skeleton + 20, 4);
+
+ /* Set the total length */
+ p[3] = 0x10 + len;
+
+ err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 0x04, 0x40, 0x19,
+ 0x0000, buf,
+ 20 + len * 4, M5602_URB_MSG_TIMEOUT);
+
+ return (err < 0) ? err : 0;
+}
+
/* Dump all the registers of the m5602 bridge,
unfortunately this breaks the camera until it's power cycled */
static void m5602_dump_bridge(struct sd *sd)
@@ -150,11 +241,15 @@ static int m5602_start_transfer(struct gspca_dev *gspca_dev)
/* Send start command to the camera */
const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01};
+
+ if (sd->sensor->start)
+ sd->sensor->start(sd);
+
memcpy(buf, buffer, sizeof(buffer));
err = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0x04, 0x40, 0x19, 0x0000, buf,
- 4, M5602_URB_MSG_TIMEOUT);
+ sizeof(buffer), M5602_URB_MSG_TIMEOUT);
PDEBUG(D_STREAM, "Transfer started");
return (err < 0) ? err : 0;
@@ -284,6 +379,7 @@ static int __init mod_m5602_init(void)
PDEBUG(D_PROBE, "registered");
return 0;
}
+
static void __exit mod_m5602_exit(void)
{
usb_deregister(&sd_driver);
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c
index fb700c2d0..c0e71c331 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c
@@ -18,6 +18,8 @@
#include "m5602_mt9m111.h"
+static void mt9m111_dump_registers(struct sd *sd);
+
int mt9m111_probe(struct sd *sd)
{
u8 data[2] = {0x00, 0x00};
@@ -44,12 +46,12 @@ int mt9m111_probe(struct sd *sd)
} else {
data[0] = preinit_mt9m111[i][2];
data[1] = preinit_mt9m111[i][3];
- mt9m111_write_sensor(sd,
+ m5602_write_sensor(sd,
preinit_mt9m111[i][1], data, 2);
}
}
- if (mt9m111_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2))
+ if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2))
return -ENODEV;
if ((data[0] == 0x14) && (data[1] == 0x3a)) {
@@ -72,7 +74,7 @@ int mt9m111_init(struct sd *sd)
int i, err = 0;
/* Init the sensor */
- for (i = 0; i < ARRAY_SIZE(init_mt9m111); i++) {
+ for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
u8 data[2];
if (init_mt9m111[i][0] == BRIDGE) {
@@ -82,7 +84,7 @@ int mt9m111_init(struct sd *sd)
} else {
data[0] = init_mt9m111[i][2];
data[1] = init_mt9m111[i][3];
- err = mt9m111_write_sensor(sd,
+ err = m5602_write_sensor(sd,
init_mt9m111[i][1], data, 2);
}
}
@@ -104,12 +106,12 @@ int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
- err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+ err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2);
*val = data[0] & MT9M111_RMB_MIRROR_ROWS;
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -121,19 +123,19 @@ int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
/* Set the correct page map */
- err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
+ err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0)
goto out;
- err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+ err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
if (err < 0)
goto out;
data[0] = (data[0] & 0xfe) | val;
- err = mt9m111_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+ err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -142,12 +144,12 @@ int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
- err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+ err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2);
*val = data[0] & MT9M111_RMB_MIRROR_COLS;
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -159,19 +161,19 @@ int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
/* Set the correct page map */
- err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
+ err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0)
goto out;
- err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+ err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
if (err < 0)
goto out;
data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02);
- err = mt9m111_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+ err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -180,7 +182,7 @@ int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
- err = mt9m111_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2);
+ err = m5602_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2);
tmp = ((data[1] << 8) | data[0]);
*val = ((tmp & (1 << 10)) * 2) |
@@ -190,7 +192,7 @@ int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
PDEBUG(D_V4L2, "Read gain %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -200,7 +202,7 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
/* Set the correct page map */
- err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
+ err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0)
goto out;
@@ -225,90 +227,13 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
data[1], data[0]);
- err = mt9m111_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
+ err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
data, 2);
out:
- return (err < 0) ? err : 0;
-}
-
-int mt9m111_read_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len) {
- int err, i;
-
- do {
- err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
- } while ((*i2c_data & I2C_BUSY) && !err);
- if (err < 0)
- goto out;
-
- err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
- sd->sensor->i2c_slave_id);
- if (err < 0)
- goto out;
-
- err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
- if (err < 0)
- goto out;
-
- err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x1a);
- if (err < 0)
- goto out;
-
- for (i = 0; i < len && !err; i++) {
- err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
-
- PDEBUG(D_CONF, "Reading sensor register "
- "0x%x contains 0x%x ", address, *i2c_data);
- }
-out:
- return (err < 0) ? err : 0;
-}
-
-int mt9m111_write_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len)
-{
- int err, i;
- u8 *p;
- struct usb_device *udev = sd->gspca_dev.dev;
- __u8 *buf = sd->gspca_dev.usb_buf;
-
- /* No sensor with a data width larger
- than 16 bits has yet been seen, nor with 0 :p*/
- if (len > 2 || !len)
- return -EINVAL;
-
- memcpy(buf, sensor_urb_skeleton,
- sizeof(sensor_urb_skeleton));
-
- buf[11] = sd->sensor->i2c_slave_id;
- buf[15] = address;
-
- p = buf + 16;
-
- /* Copy a four byte write sequence for each byte to be written to */
- for (i = 0; i < len; i++) {
- memcpy(p, sensor_urb_skeleton + 16, 4);
- p[3] = i2c_data[i];
- p += 4;
- PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
- address, i2c_data[i]);
- }
-
- /* Copy the tailer */
- memcpy(p, sensor_urb_skeleton + 20, 4);
-
- /* Set the total length */
- p[3] = 0x10 + len;
-
- err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- 0x04, 0x40, 0x19,
- 0x0000, buf,
- 20 + len * 4, M5602_URB_MSG_TIMEOUT);
-
- return (err < 0) ? err : 0;
+ return err;
}
-void mt9m111_dump_registers(struct sd *sd)
+static void mt9m111_dump_registers(struct sd *sd)
{
u8 address, value[2] = {0x00, 0x00};
@@ -316,27 +241,27 @@ void mt9m111_dump_registers(struct sd *sd)
info("Dumping the mt9m111 sensor core registers");
value[1] = MT9M111_SENSOR_CORE;
- mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
+ m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
for (address = 0; address < 0xff; address++) {
- mt9m111_read_sensor(sd, address, value, 2);
+ m5602_read_sensor(sd, address, value, 2);
info("register 0x%x contains 0x%x%x",
address, value[0], value[1]);
}
info("Dumping the mt9m111 color pipeline registers");
value[1] = MT9M111_COLORPIPE;
- mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
+ m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
for (address = 0; address < 0xff; address++) {
- mt9m111_read_sensor(sd, address, value, 2);
+ m5602_read_sensor(sd, address, value, 2);
info("register 0x%x contains 0x%x%x",
address, value[0], value[1]);
}
info("Dumping the mt9m111 camera control registers");
value[1] = MT9M111_CAMERA_CONTROL;
- mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
+ m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
for (address = 0; address < 0xff; address++) {
- mt9m111_read_sensor(sd, address, value, 2);
+ m5602_read_sensor(sd, address, value, 2);
info("register 0x%x contains 0x%x%x",
address, value[0], value[1]);
}
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h
index 315209d5a..e795ab7a3 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h
@@ -87,14 +87,6 @@ int mt9m111_probe(struct sd *sd);
int mt9m111_init(struct sd *sd);
int mt9m111_power_down(struct sd *sd);
-int mt9m111_read_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len);
-
-int mt9m111_write_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len);
-
-void mt9m111_dump_registers(struct sd *sd);
-
int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
@@ -106,14 +98,12 @@ static struct m5602_sensor mt9m111 = {
.name = "MT9M111",
.i2c_slave_id = 0xba,
+ .i2c_regW = 2,
.probe = mt9m111_probe,
.init = mt9m111_init,
.power_down = mt9m111_power_down,
- .read_sensor = mt9m111_read_sensor,
- .write_sensor = mt9m111_write_sensor,
-
.nctrls = 3,
.ctrls = {
{
@@ -1003,7 +993,7 @@ static const unsigned char init_mt9m111[][4] =
{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, /* 639*/
{BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c
index 07ef2b3db..dde5075ed 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c
@@ -47,86 +47,30 @@ static
}
},
{
+ .ident = "ASUS A6Ja",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
+ }
+ },
+ {
.ident = "ASUS A6Kt",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
}
},
+ {
+ .ident = "Alienware Aurora m9700",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "alienware"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700")
+ }
+ },
{ }
};
-int ov9650_read_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len)
-{
- int err, i;
-
- /* The ov9650 registers have a max depth of one byte */
- if (len > 1 || !len)
- return -EINVAL;
-
- do {
- err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
- } while ((*i2c_data & I2C_BUSY) && !err);
-
- m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
- ov9650.i2c_slave_id);
- m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
- m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x10 + len);
- m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
-
- for (i = 0; i < len; i++) {
- err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
-
- PDEBUG(D_CONF, "Reading sensor register "
- "0x%x containing 0x%x ", address, *i2c_data);
- }
- return (err < 0) ? err : 0;
-}
-
-int ov9650_write_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len)
-{
- int err, i;
- u8 *p;
- struct usb_device *udev = sd->gspca_dev.dev;
- __u8 *buf = sd->gspca_dev.usb_buf;
-
- /* The ov9650 only supports one byte writes */
- if (len > 1 || !len)
- return -EINVAL;
-
- memcpy(buf, sensor_urb_skeleton,
- sizeof(sensor_urb_skeleton));
-
- buf[11] = sd->sensor->i2c_slave_id;
- buf[15] = address;
-
- /* Special case larger sensor writes */
- p = buf + 16;
-
- /* Copy a four byte write sequence for each byte to be written to */
- for (i = 0; i < len; i++) {
- memcpy(p, sensor_urb_skeleton + 16, 4);
- p[3] = i2c_data[i];
- p += 4;
- PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
- address, i2c_data[i]);
- }
-
- /* Copy the tailer */
- memcpy(p, sensor_urb_skeleton + 20, 4);
-
- /* Set the total length */
- p[3] = 0x10 + len;
-
- err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- 0x04, 0x40, 0x19,
- 0x0000, buf,
- 20 + len * 4, M5602_URB_MSG_TIMEOUT);
-
- return (err < 0) ? err : 0;
-}
+static void ov9650_dump_registers(struct sd *sd);
int ov9650_probe(struct sd *sd)
{
@@ -148,16 +92,16 @@ int ov9650_probe(struct sd *sd)
for (i = 0; i < ARRAY_SIZE(preinit_ov9650); i++) {
u8 data = preinit_ov9650[i][2];
if (preinit_ov9650[i][0] == SENSOR)
- ov9650_write_sensor(sd,
+ m5602_write_sensor(sd,
preinit_ov9650[i][1], &data, 1);
else
m5602_write_bridge(sd, preinit_ov9650[i][1], data);
}
- if (ov9650_read_sensor(sd, OV9650_PID, &prod_id, 1))
+ if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1))
return -ENODEV;
- if (ov9650_read_sensor(sd, OV9650_VER, &ver_id, 1))
+ if (m5602_read_sensor(sd, OV9650_VER, &ver_id, 1))
return -ENODEV;
if ((prod_id == 0x96) && (ver_id == 0x52)) {
@@ -186,34 +130,90 @@ int ov9650_init(struct sd *sd)
for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) {
data = init_ov9650[i][2];
if (init_ov9650[i][0] == SENSOR)
- err = ov9650_write_sensor(sd, init_ov9650[i][1],
+ err = m5602_write_sensor(sd, init_ov9650[i][1],
&data, 1);
else
err = m5602_write_bridge(sd, init_ov9650[i][1], data);
}
- if (!err && dmi_check_system(ov9650_flip_dmi_table)) {
+ if (dmi_check_system(ov9650_flip_dmi_table) && !err) {
info("vflip quirk active");
data = 0x30;
- err = ov9650_write_sensor(sd, OV9650_MVFP, &data, 1);
+ err = m5602_write_sensor(sd, OV9650_MVFP, &data, 1);
}
+ return err;
+}
- return (err < 0) ? err : 0;
+int ov9650_start(struct sd *sd)
+{
+ int i, err = 0;
+ struct cam *cam = &sd->gspca_dev.cam;
+
+ for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) {
+ u8 data = res_init_ov9650[i][1];
+ err = m5602_write_bridge(sd, res_init_ov9650[i][0], data);
+ }
+ if (err < 0)
+ return err;
+
+ switch (cam->cam_mode[sd->gspca_dev.curr_mode].width)
+ {
+ case 640:
+ PDEBUG(D_V4L2, "Configuring camera for VGA mode");
+
+ for (i = 0; i < ARRAY_SIZE(VGA_ov9650) && !err; i++) {
+ u8 data = VGA_ov9650[i][2];
+ if (VGA_ov9650[i][0] == SENSOR)
+ err = m5602_write_sensor(sd,
+ VGA_ov9650[i][1], &data, 1);
+ else
+ err = m5602_write_bridge(sd, VGA_ov9650[i][1], data);
+ }
+ break;
+
+ case 352:
+ PDEBUG(D_V4L2, "Configuring camera for CIF mode");
+
+ for (i = 0; i < ARRAY_SIZE(CIF_ov9650) && !err; i++) {
+ u8 data = CIF_ov9650[i][2];
+ if (CIF_ov9650[i][0] == SENSOR)
+ err = m5602_write_sensor(sd,
+ CIF_ov9650[i][1], &data, 1);
+ else
+ err = m5602_write_bridge(sd, CIF_ov9650[i][1], data);
+ }
+ break;
+
+ case 320:
+ PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
+
+ for (i = 0; i < ARRAY_SIZE(QVGA_ov9650) && !err; i++) {
+ u8 data = QVGA_ov9650[i][2];
+ if (QVGA_ov9650[i][0] == SENSOR)
+ err = m5602_write_sensor(sd,
+ QVGA_ov9650[i][1], &data, 1);
+ else
+ err = m5602_write_bridge(sd, QVGA_ov9650[i][1], data);
+ }
+ break;
+ }
+ return err;
}
int ov9650_power_down(struct sd *sd)
{
- int i;
- for (i = 0; i < ARRAY_SIZE(power_down_ov9650); i++) {
+ int i, err = 0;
+ for (i = 0; i < ARRAY_SIZE(power_down_ov9650) && !err; i++) {
u8 data = power_down_ov9650[i][2];
if (power_down_ov9650[i][0] == SENSOR)
- ov9650_write_sensor(sd,
+ err = m5602_write_sensor(sd,
power_down_ov9650[i][1], &data, 1);
else
- m5602_write_bridge(sd, power_down_ov9650[i][1], data);
+ err = m5602_write_bridge(sd, power_down_ov9650[i][1],
+ data);
}
- return 0;
+ return err;
}
int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
@@ -222,24 +222,24 @@ int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
int err;
- err = ov9650_read_sensor(sd, OV9650_COM1, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_COM1, &i2c_data, 1);
if (err < 0)
goto out;
*val = i2c_data & 0x03;
- err = ov9650_read_sensor(sd, OV9650_AECH, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_AECH, &i2c_data, 1);
if (err < 0)
goto out;
*val |= (i2c_data << 2);
- err = ov9650_read_sensor(sd, OV9650_AECHM, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_AECHM, &i2c_data, 1);
if (err < 0)
goto out;
*val |= (i2c_data & 0x3f) << 10;
PDEBUG(D_V4L2, "Read exposure %d", *val);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
@@ -253,24 +253,24 @@ int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
/* The 6 MSBs */
i2c_data = (val >> 10) & 0x3f;
- err = ov9650_write_sensor(sd, OV9650_AECHM,
+ err = m5602_write_sensor(sd, OV9650_AECHM,
&i2c_data, 1);
if (err < 0)
goto out;
/* The 8 middle bits */
i2c_data = (val >> 2) & 0xff;
- err = ov9650_write_sensor(sd, OV9650_AECH,
+ err = m5602_write_sensor(sd, OV9650_AECH,
&i2c_data, 1);
if (err < 0)
goto out;
/* The 2 LSBs */
i2c_data = val & 0x03;
- err = ov9650_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
+ err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -279,13 +279,13 @@ int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
*val = (i2c_data & 0x03) << 8;
- err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
*val |= i2c_data;
PDEBUG(D_V4L2, "Read gain %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -297,16 +297,16 @@ int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
/* The 2 MSB */
/* Read the OV9650_VREF register first to avoid
corrupting the VREF high and low bits */
- ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
/* Mask away all uninteresting bits */
i2c_data = ((val & 0x0300) >> 2) |
(i2c_data & 0x3F);
- err = ov9650_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
/* The 8 LSBs */
i2c_data = val & 0xff;
- err = ov9650_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
- return (err < 0) ? err : 0;
+ err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+ return err;
}
int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -315,12 +315,12 @@ int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- err = ov9650_read_sensor(sd, OV9650_RED, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_RED, &i2c_data, 1);
*val = i2c_data;
PDEBUG(D_V4L2, "Read red gain %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -333,9 +333,9 @@ int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
val & 0xff);
i2c_data = val & 0xff;
- err = ov9650_write_sensor(sd, OV9650_RED, &i2c_data, 1);
+ err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -344,12 +344,12 @@ int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- err = ov9650_read_sensor(sd, OV9650_BLUE, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_BLUE, &i2c_data, 1);
*val = i2c_data;
PDEBUG(D_V4L2, "Read blue gain %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -362,9 +362,9 @@ int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
val & 0xff);
i2c_data = val & 0xff;
- err = ov9650_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
+ err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -373,14 +373,14 @@ int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
if (dmi_check_system(ov9650_flip_dmi_table))
*val = ((i2c_data & OV9650_HFLIP) >> 5) ? 0 : 1;
else
*val = (i2c_data & OV9650_HFLIP) >> 5;
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -390,20 +390,20 @@ int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
- err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
if (err < 0)
goto out;
if (dmi_check_system(ov9650_flip_dmi_table))
i2c_data = ((i2c_data & 0xdf) |
- (((val ? 0 : 1) & 0x01) << 5));
+ (((val ? 0 : 1) & 0x01) << 5));
else
i2c_data = ((i2c_data & 0xdf) |
- ((val & 0x01) << 5));
+ ((val & 0x01) << 5));
- err = ov9650_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+ err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -412,14 +412,14 @@ int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
if (dmi_check_system(ov9650_flip_dmi_table))
*val = ((i2c_data & 0x10) >> 4) ? 0 : 1;
else
*val = (i2c_data & 0x10) >> 4;
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -429,7 +429,7 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
- err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
if (err < 0)
goto out;
@@ -440,9 +440,9 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
i2c_data = ((i2c_data & 0xef) |
((val & 0x01) << 4));
- err = ov9650_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+ err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
@@ -451,16 +451,16 @@ int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- err = ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
if (err < 0)
goto out;
*val = (i2c_data & 0x03) << 8;
- err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
*val |= i2c_data;
PDEBUG(D_V4L2, "Read gain %d", *val);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -473,22 +473,22 @@ int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
/* Read the OV9650_VREF register first to avoid
corrupting the VREF high and low bits */
- err = ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
if (err < 0)
goto out;
/* Mask away all uninteresting bits */
i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F);
- err = ov9650_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
if (err < 0)
goto out;
/* The 8 LSBs */
i2c_data = val & 0xff;
- err = ov9650_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+ err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -497,11 +497,11 @@ int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
*val = (i2c_data & OV9650_AWB_EN) >> 1;
PDEBUG(D_V4L2, "Read auto white balance %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -511,14 +511,14 @@ int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
PDEBUG(D_V4L2, "Set auto white balance to %d", val);
- err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
goto out;
i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
- err = ov9650_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
+ err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -527,11 +527,11 @@ int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
*val = (i2c_data & OV9650_AGC_EN) >> 2;
PDEBUG(D_V4L2, "Read auto gain control %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -541,23 +541,23 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
PDEBUG(D_V4L2, "Set auto gain control to %d", val);
- err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
goto out;
i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
- err = ov9650_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
+ err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
out:
- return (err < 0) ? err : 0;
+ return err;
}
-void ov9650_dump_registers(struct sd *sd)
+static void ov9650_dump_registers(struct sd *sd)
{
int address;
info("Dumping the ov9650 register state");
for (address = 0; address < 0xa9; address++) {
u8 value;
- ov9650_read_sensor(sd, address, &value, 1);
+ m5602_read_sensor(sd, address, &value, 1);
info("register 0x%x contains 0x%x",
address, value);
}
@@ -569,9 +569,9 @@ void ov9650_dump_registers(struct sd *sd)
u8 old_value, ctrl_value;
u8 test_value[2] = {0xff, 0xff};
- ov9650_read_sensor(sd, address, &old_value, 1);
- ov9650_write_sensor(sd, address, test_value, 1);
- ov9650_read_sensor(sd, address, &ctrl_value, 1);
+ m5602_read_sensor(sd, address, &old_value, 1);
+ m5602_write_sensor(sd, address, test_value, 1);
+ m5602_read_sensor(sd, address, &ctrl_value, 1);
if (ctrl_value == test_value[0])
info("register 0x%x is writeable", address);
@@ -579,6 +579,6 @@ void ov9650_dump_registers(struct sd *sd)
info("register 0x%x is read only", address);
/* Restore original value */
- ov9650_write_sensor(sd, address, &old_value, 1);
+ m5602_write_sensor(sd, address, &old_value, 1);
}
}
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h
index e0efdb930..f4b33b8e8 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h
@@ -20,7 +20,6 @@
#define M5602_OV9650_H_
#include <linux/dmi.h>
-
#include "m5602_sensor.h"
/*****************************************************************************/
@@ -36,6 +35,7 @@
#define OV9650_PID 0x0a
#define OV9650_VER 0x0b
#define OV9650_COM3 0x0c
+#define OV9650_COM4 0x0d
#define OV9650_COM5 0x0e
#define OV9650_COM6 0x0f
#define OV9650_AECH 0x10
@@ -94,6 +94,8 @@
#define OV9650_REGISTER_RESET (1 << 7)
#define OV9650_VGA_SELECT (1 << 6)
+#define OV9650_CIF_SELECT (1 << 5)
+#define OV9650_QVGA_SELECT (1 << 4)
#define OV9650_RGB_SELECT (1 << 2)
#define OV9650_RAW_RGB_SELECT (1 << 0)
@@ -108,6 +110,8 @@
#define OV9650_SYSTEM_CLK_SEL (1 << 7)
#define OV9650_SLAM_MODE (1 << 4)
+#define OV9650_QVGA_VARIOPIXEL (1 << 7)
+
#define OV9650_VFLIP (1 << 4)
#define OV9650_HFLIP (1 << 5)
@@ -124,15 +128,9 @@ extern int dump_sensor;
int ov9650_probe(struct sd *sd);
int ov9650_init(struct sd *sd);
+int ov9650_start(struct sd *sd);
int ov9650_power_down(struct sd *sd);
-int ov9650_read_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len);
-int ov9650_write_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len);
-
-void ov9650_dump_registers(struct sd *sd);
-
int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
@@ -155,11 +153,11 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
static struct m5602_sensor ov9650 = {
.name = "OV9650",
.i2c_slave_id = 0x60,
+ .i2c_regW = 1,
.probe = ov9650_probe,
.init = ov9650_init,
+ .start = ov9650_start,
.power_down = ov9650_power_down,
- .read_sensor = ov9650_read_sensor,
- .write_sensor = ov9650_write_sensor,
.nctrls = 8,
.ctrls = {
@@ -264,18 +262,38 @@ static struct m5602_sensor ov9650 = {
}
},
- .nmodes = 1,
+ .nmodes = 3,
.modes = {
{
- M5602_DEFAULT_FRAME_WIDTH,
- M5602_DEFAULT_FRAME_HEIGHT,
+ 320,
+ 240,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 320 * 240,
+ .bytesperline = 320,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ }, {
+ 352,
+ 288,
V4L2_PIX_FMT_SBGGR8,
V4L2_FIELD_NONE,
.sizeimage =
- M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
- .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
+ 352 * 288,
+ .bytesperline = 352,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1
+ .priv = 0
+ }, {
+ 640,
+ 480,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 640 * 480,
+ .bytesperline = 640,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
}
}
};
@@ -324,6 +342,7 @@ static const unsigned char init_ov9650[][3] =
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
{BRIDGE, M5602_XB_GPIO_DAT, 0x00},
{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a},
+
/* Reset chip */
{SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
/* Enable double clock */
@@ -331,8 +350,6 @@ static const unsigned char init_ov9650[][3] =
/* Do something out of spec with the power */
{SENSOR, OV9650_OFON, 0x40},
- /* Set QQVGA */
- {SENSOR, OV9650_COM1, 0x20},
/* Set fast AGC/AEC algorithm with unlimited step size */
{SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC |
OV9650_AEC_UNLIM_STEP_SIZE |
@@ -343,7 +360,7 @@ static const unsigned char init_ov9650[][3] =
{SENSOR, OV9650_ACOM38, 0x81},
/* Turn off color matrix coefficient double option */
{SENSOR, OV9650_COM16, 0x00},
- /* Enable color matrix for RGB/YUV, Delay Y channel,
+ /* Enable color matrix for RGB/YUV, Delay Y channel,
set output Y/UV delay to 1 */
{SENSOR, OV9650_COM13, 0x19},
/* Enable digital BLC, Set output mode to U Y V Y */
@@ -352,7 +369,7 @@ static const unsigned char init_ov9650[][3] =
{SENSOR, OV9650_COM24, 0x00},
/* Enable HREF and some out of spec things */
{SENSOR, OV9650_COM12, 0x73},
- /* Set all DBLC offset signs to positive and
+ /* Set all DBLC offset signs to positive and
do some out of spec stuff */
{SENSOR, OV9650_DBLC1, 0xdf},
{SENSOR, OV9650_COM21, 0x06},
@@ -364,7 +381,7 @@ static const unsigned char init_ov9650[][3] =
{SENSOR, OV9650_RSVD96, 0x04},
/* Enable full range output */
{SENSOR, OV9650_COM15, 0x0},
- /* Enable HREF at optical black, enable ADBLC bias,
+ /* Enable HREF at optical black, enable ADBLC bias,
enable ADBLC, reset timings at format change */
{SENSOR, OV9650_COM6, 0x4b},
/* Subtract 32 from the B channel bias */
@@ -385,7 +402,7 @@ static const unsigned char init_ov9650[][3] =
{SENSOR, OV9650_AEB, 0x5c},
/* Set the high and low limit nibbles to 3 */
{SENSOR, OV9650_VPT, 0xc3},
- /* Set the Automatic Gain Ceiling (AGC) to 128x,
+ /* Set the Automatic Gain Ceiling (AGC) to 128x,
drop VSYNC at frame drop,
limit exposure timing,
drop frame when the AEC step is larger than the exposure gap */
@@ -394,9 +411,9 @@ static const unsigned char init_ov9650[][3] =
and set PWDN to SLVS (slave mode vertical sync) */
{SENSOR, OV9650_COM10, 0x42},
/* Set horizontal column start high to default value */
- {SENSOR, OV9650_HSTART, 0x1a},
+ {SENSOR, OV9650_HSTART, 0x1a}, /* 210 */
/* Set horizontal column end */
- {SENSOR, OV9650_HSTOP, 0xbf},
+ {SENSOR, OV9650_HSTOP, 0xbf}, /* 1534 */
/* Complementing register to the two writes above */
{SENSOR, OV9650_HREF, 0xb2},
/* Set vertical row start high bits */
@@ -405,10 +422,6 @@ static const unsigned char init_ov9650[][3] =
{SENSOR, OV9650_VSTOP, 0x7e},
/* Set complementing vertical frame control */
{SENSOR, OV9650_VREF, 0x10},
- /* Set raw RGB output format with VGA resolution */
- {SENSOR, OV9650_COM7, OV9650_VGA_SELECT |
- OV9650_RGB_SELECT |
- OV9650_RAW_RGB_SELECT},
{SENSOR, OV9650_ADC, 0x04},
{SENSOR, OV9650_HV, 0x40},
/* Enable denoise, and white-pixel erase */
@@ -417,31 +430,15 @@ static const unsigned char init_ov9650[][3] =
/* Set the high bits of the exposure value */
{SENSOR, OV9650_AECH, ((EXPOSURE_DEFAULT & 0xff00) >> 8)},
+ /* Enable VARIOPIXEL */
+ {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL},
+ {SENSOR, OV9650_COM4, OV9650_QVGA_VARIOPIXEL},
+
/* Set the low bits of the exposure value */
{SENSOR, OV9650_COM1, (EXPOSURE_DEFAULT & 0xff)},
{SENSOR, OV9650_GAIN, GAIN_DEFAULT},
{SENSOR, OV9650_BLUE, BLUE_GAIN_DEFAULT},
{SENSOR, OV9650_RED, RED_GAIN_DEFAULT},
-
- {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL},
- {SENSOR, OV9650_COM5, OV9650_SYSTEM_CLK_SEL},
-
- {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82},
- {BRIDGE, M5602_XB_LINE_OF_FRAME_L, 0x00},
- {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
- {BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x01},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- /* Moves the view window in a vertical orientation */
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x09},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x5e},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0xde}
};
static const unsigned char power_down_ov9650[][3] =
@@ -461,7 +458,76 @@ static const unsigned char power_down_ov9650[][3] =
{BRIDGE, M5602_XB_GPIO_EN_L, 0x06},
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+};
+
+static const unsigned char res_init_ov9650[][2] =
+{
+ {M5602_XB_LINE_OF_FRAME_H, 0x82},
+ {M5602_XB_LINE_OF_FRAME_L, 0x00},
+ {M5602_XB_PIX_OF_LINE_H, 0x82},
+ {M5602_XB_PIX_OF_LINE_L, 0x00},
+ {M5602_XB_SIG_INI, 0x01}
+};
+
+static const unsigned char VGA_ov9650[][3] =
+{
+ /* Moves the view window in a vertical orientation */
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x09},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0}, /* 480 */
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x62}, /* 98 */
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, /* 640 + 98 */
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0xe2},
+
+ {SENSOR, OV9650_COM7, OV9650_VGA_SELECT |
+ OV9650_RGB_SELECT |
+ OV9650_RAW_RGB_SELECT},
+};
+
+static const unsigned char CIF_ov9650[][3] =
+{
+ /* Moves the view window in a vertical orientation */
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x09},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x20}, /* 288 */
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x62}, /* 98 */
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x01}, /* 352 + 98 */
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0xc2},
+
+ {SENSOR, OV9650_COM7, OV9650_CIF_SELECT |
+ OV9650_RGB_SELECT |
+ OV9650_RAW_RGB_SELECT},
+};
+
+static const unsigned char QVGA_ov9650[][3] =
+{
+ /* Moves the view window in a vertical orientation */
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x08},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0xf0}, /* 240 */
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x31}, /* 50 */
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x01}, /* 320 + 50 */
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x71},
+
+ {SENSOR, OV9650_COM7, OV9650_QVGA_SELECT |
+ OV9650_RGB_SELECT |
+ OV9650_RAW_RGB_SELECT},
};
#endif
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_po1030.c b/linux/drivers/media/video/gspca/m5602/m5602_po1030.c
index d17ac5256..2e7fb9167 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_po1030.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_po1030.c
@@ -18,6 +18,8 @@
#include "m5602_po1030.h"
+static void po1030_dump_registers(struct sd *sd);
+
int po1030_probe(struct sd *sd)
{
u8 prod_id = 0, ver_id = 0, i;
@@ -38,16 +40,16 @@ int po1030_probe(struct sd *sd)
for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) {
u8 data = preinit_po1030[i][2];
if (preinit_po1030[i][0] == SENSOR)
- po1030_write_sensor(sd,
+ m5602_write_sensor(sd,
preinit_po1030[i][1], &data, 1);
else
m5602_write_bridge(sd, preinit_po1030[i][1], data);
}
- if (po1030_read_sensor(sd, 0x3, &prod_id, 1))
+ if (m5602_read_sensor(sd, 0x3, &prod_id, 1))
return -ENODEV;
- if (po1030_read_sensor(sd, 0x4, &ver_id, 1))
+ if (m5602_read_sensor(sd, 0x4, &ver_id, 1))
return -ENODEV;
if ((prod_id == 0x02) && (ver_id == 0xef)) {
@@ -64,78 +66,12 @@ sensor_found:
return 0;
}
-int po1030_read_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len)
-{
- int err, i;
-
- do {
- err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
- } while ((*i2c_data & I2C_BUSY) && !err);
-
- m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
- sd->sensor->i2c_slave_id);
- m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
- m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x10 + len);
- m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
-
- for (i = 0; i < len; i++) {
- err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
-
- PDEBUG(D_CONF, "Reading sensor register "
- "0x%x containing 0x%x ", address, *i2c_data);
- }
- return (err < 0) ? err : 0;
-}
-
-int po1030_write_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len)
-{
- int err, i;
- u8 *p;
- struct usb_device *udev = sd->gspca_dev.dev;
- __u8 *buf = sd->gspca_dev.usb_buf;
-
- /* The po1030 only supports one byte writes */
- if (len > 1 || !len)
- return -EINVAL;
-
- memcpy(buf, sensor_urb_skeleton, sizeof(sensor_urb_skeleton));
-
- buf[11] = sd->sensor->i2c_slave_id;
- buf[15] = address;
-
- p = buf + 16;
-
- /* Copy a four byte write sequence for each byte to be written to */
- for (i = 0; i < len; i++) {
- memcpy(p, sensor_urb_skeleton + 16, 4);
- p[3] = i2c_data[i];
- p += 4;
- PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
- address, i2c_data[i]);
- }
-
- /* Copy the footer */
- memcpy(p, sensor_urb_skeleton + 20, 4);
-
- /* Set the total length */
- p[3] = 0x10 + len;
-
- err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- 0x04, 0x40, 0x19,
- 0x0000, buf,
- 20 + len * 4, M5602_URB_MSG_TIMEOUT);
-
- return (err < 0) ? err : 0;
-}
-
int po1030_init(struct sd *sd)
{
int i, err = 0;
/* Init the sensor */
- for (i = 0; i < ARRAY_SIZE(init_po1030); i++) {
+ for (i = 0; i < ARRAY_SIZE(init_po1030) && !err; i++) {
u8 data[2] = {0x00, 0x00};
switch (init_po1030[i][0]) {
@@ -147,16 +83,10 @@ int po1030_init(struct sd *sd)
case SENSOR:
data[0] = init_po1030[i][2];
- err = po1030_write_sensor(sd,
+ err = m5602_write_sensor(sd,
init_po1030[i][1], data, 1);
break;
- case SENSOR_LONG:
- data[0] = init_po1030[i][2];
- data[1] = init_po1030[i][3];
- err = po1030_write_sensor(sd,
- init_po1030[i][1], data, 2);
- break;
default:
info("Invalid stream command, exiting init");
return -EINVAL;
@@ -166,7 +96,7 @@ int po1030_init(struct sd *sd)
if (dump_sensor)
po1030_dump_registers(sd);
- return (err < 0) ? err : 0;
+ return err;
}
int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
@@ -175,19 +105,19 @@ int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
int err;
- err = po1030_read_sensor(sd, PO1030_REG_INTEGLINES_H,
+ err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_H,
&i2c_data, 1);
if (err < 0)
goto out;
*val = (i2c_data << 8);
- err = po1030_read_sensor(sd, PO1030_REG_INTEGLINES_M,
+ err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_M,
&i2c_data, 1);
*val |= i2c_data;
PDEBUG(D_V4L2, "Exposure read as %d", *val);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
@@ -202,7 +132,7 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x",
i2c_data);
- err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_H,
+ err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_H,
&i2c_data, 1);
if (err < 0)
goto out;
@@ -210,11 +140,11 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
i2c_data = (val & 0xff);
PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
i2c_data);
- err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_M,
+ err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_M,
&i2c_data, 1);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -223,12 +153,12 @@ int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
int err;
- err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN,
+ err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN,
&i2c_data, 1);
*val = i2c_data;
PDEBUG(D_V4L2, "Read global gain %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -237,14 +167,14 @@ int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
int err;
- err = po1030_read_sensor(sd, PO1030_REG_CONTROL2,
+ err = m5602_read_sensor(sd, PO1030_REG_CONTROL2,
&i2c_data, 1);
*val = (i2c_data >> 7) & 0x01 ;
PDEBUG(D_V4L2, "Read hflip %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -254,13 +184,17 @@ int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
int err;
PDEBUG(D_V4L2, "Set hflip %d", val);
+ err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1);
+ if (err < 0)
+ goto out;
- i2c_data = (val & 0x01) << 7;
+ i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7);
- err = po1030_write_sensor(sd, PO1030_REG_CONTROL2,
- &i2c_data, 1);
+ err = m5602_write_sensor(sd, PO1030_REG_CONTROL2,
+ &i2c_data, 1);
- return (err < 0) ? err : 0;
+out:
+ return err;
}
int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -269,14 +203,14 @@ int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
int err;
- err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN,
+ err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN,
&i2c_data, 1);
*val = (i2c_data >> 6) & 0x01;
PDEBUG(D_V4L2, "Read vflip %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -286,13 +220,17 @@ int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
int err;
PDEBUG(D_V4L2, "Set vflip %d", val);
+ err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1);
+ if (err < 0)
+ goto out;
- i2c_data = (val & 0x01) << 6;
+ i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6);
- err = po1030_write_sensor(sd, PO1030_REG_CONTROL2,
- &i2c_data, 1);
+ err = m5602_write_sensor(sd, PO1030_REG_CONTROL2,
+ &i2c_data, 1);
- return (err < 0) ? err : 0;
+out:
+ return err;
}
int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -303,9 +241,9 @@ int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
i2c_data = val & 0xff;
PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
- err = po1030_write_sensor(sd, PO1030_REG_GLOBALGAIN,
+ err = m5602_write_sensor(sd, PO1030_REG_GLOBALGAIN,
&i2c_data, 1);
- return (err < 0) ? err : 0;
+ return err;
}
int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -314,11 +252,11 @@ int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
int err;
- err = po1030_read_sensor(sd, PO1030_REG_RED_GAIN,
+ err = m5602_read_sensor(sd, PO1030_REG_RED_GAIN,
&i2c_data, 1);
*val = i2c_data;
PDEBUG(D_V4L2, "Read red gain %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -329,9 +267,9 @@ int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
i2c_data = val & 0xff;
PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
- err = po1030_write_sensor(sd, PO1030_REG_RED_GAIN,
+ err = m5602_write_sensor(sd, PO1030_REG_RED_GAIN,
&i2c_data, 1);
- return (err < 0) ? err : 0;
+ return err;
}
int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -340,12 +278,12 @@ int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
u8 i2c_data;
int err;
- err = po1030_read_sensor(sd, PO1030_REG_BLUE_GAIN,
+ err = m5602_read_sensor(sd, PO1030_REG_BLUE_GAIN,
&i2c_data, 1);
*val = i2c_data;
PDEBUG(D_V4L2, "Read blue gain %d", *val);
- return (err < 0) ? err : 0;
+ return err;
}
int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -355,10 +293,10 @@ int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
int err;
i2c_data = val & 0xff;
PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
- err = po1030_write_sensor(sd, PO1030_REG_BLUE_GAIN,
+ err = m5602_write_sensor(sd, PO1030_REG_BLUE_GAIN,
&i2c_data, 1);
- return (err < 0) ? err : 0;
+ return err;
}
int po1030_power_down(struct sd *sd)
@@ -366,14 +304,14 @@ int po1030_power_down(struct sd *sd)
return 0;
}
-void po1030_dump_registers(struct sd *sd)
+static void po1030_dump_registers(struct sd *sd)
{
int address;
u8 value = 0;
info("Dumping the po1030 sensor core registers");
for (address = 0; address < 0x7f; address++) {
- po1030_read_sensor(sd, address, &value, 1);
+ m5602_read_sensor(sd, address, &value, 1);
info("register 0x%x contains 0x%x",
address, value);
}
@@ -385,9 +323,9 @@ void po1030_dump_registers(struct sd *sd)
u8 old_value, ctrl_value;
u8 test_value[2] = {0xff, 0xff};
- po1030_read_sensor(sd, address, &old_value, 1);
- po1030_write_sensor(sd, address, test_value, 1);
- po1030_read_sensor(sd, address, &ctrl_value, 1);
+ m5602_read_sensor(sd, address, &old_value, 1);
+ m5602_write_sensor(sd, address, test_value, 1);
+ m5602_read_sensor(sd, address, &ctrl_value, 1);
if (ctrl_value == test_value[0])
info("register 0x%x is writeable", address);
@@ -395,6 +333,6 @@ void po1030_dump_registers(struct sd *sd)
info("register 0x%x is read only", address);
/* Restore original value */
- po1030_write_sensor(sd, address, &old_value, 1);
+ m5602_write_sensor(sd, address, &old_value, 1);
}
}
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_po1030.h b/linux/drivers/media/video/gspca/m5602/m5602_po1030.h
index a0b75ff61..def39d5bc 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_po1030.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_po1030.h
@@ -10,7 +10,7 @@
* v4l2 interface modeled after the V4L2 driver
* for SN9C10x PC Camera Controllers
*
- * Register defines taken from Pascal Stangs Proxycon Armlib
+ * Register defines taken from Pascal Stangs Procyon Armlib
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -128,13 +128,6 @@ int po1030_probe(struct sd *sd);
int po1030_init(struct sd *sd);
int po1030_power_down(struct sd *sd);
-void po1030_dump_registers(struct sd *sd);
-
-int po1030_read_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len);
-int po1030_write_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len);
-
int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
@@ -152,6 +145,7 @@ static struct m5602_sensor po1030 = {
.name = "PO1030",
.i2c_slave_id = 0xdc,
+ .i2c_regW = 1,
.probe = po1030_probe,
.init = po1030_init,
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
index 1f72e7eae..2bd7d4d99 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -52,6 +52,7 @@ static
{ }
};
+static void s5k4aa_dump_registers(struct sd *sd);
int s5k4aa_probe(struct sd *sd)
{
@@ -84,7 +85,7 @@ int s5k4aa_probe(struct sd *sd)
case SENSOR:
data[0] = preinit_s5k4aa[i][2];
- err = s5k4aa_write_sensor(sd,
+ err = m5602_write_sensor(sd,
preinit_s5k4aa[i][1],
data, 1);
break;
@@ -92,7 +93,7 @@ int s5k4aa_probe(struct sd *sd)
case SENSOR_LONG:
data[0] = preinit_s5k4aa[i][2];
data[1] = preinit_s5k4aa[i][3];
- err = s5k4aa_write_sensor(sd,
+ err = m5602_write_sensor(sd,
preinit_s5k4aa[i][1],
data, 2);
break;
@@ -103,13 +104,14 @@ int s5k4aa_probe(struct sd *sd)
}
/* Test some registers, but we don't know their exact meaning yet */
- if (s5k4aa_read_sensor(sd, 0x00, prod_id, sizeof(prod_id)))
+ if (m5602_read_sensor(sd, 0x00, prod_id, sizeof(prod_id)))
return -ENODEV;
if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
return -ENODEV;
else
info("Detected a s5k4aa sensor");
+
sensor_found:
sd->gspca_dev.cam.cam_mode = s5k4aa.modes;
sd->gspca_dev.cam.nmodes = s5k4aa.nmodes;
@@ -119,90 +121,6 @@ sensor_found:
return 0;
}
-int s5k4aa_read_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len)
-{
- int err, i;
-
- do {
- err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
- } while ((*i2c_data & I2C_BUSY) && !err);
- if (err < 0)
- goto out;
-
- err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
- sd->sensor->i2c_slave_id);
- if (err < 0)
- goto out;
-
- err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
- if (err < 0)
- goto out;
-
- err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
- if (err < 0)
- goto out;
-
- do {
- err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
- } while ((*i2c_data & I2C_BUSY) && !err);
- if (err < 0)
- goto out;
-
- for (i = 0; (i < len) & !err; i++) {
- err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
-
- PDEBUG(D_CONF, "Reading sensor register "
- "0x%x containing 0x%x ", address, *i2c_data);
- }
-out:
- return (err < 0) ? err : 0;
-}
-
-int s5k4aa_write_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len)
-{
- int err, i;
- u8 *p;
- struct usb_device *udev = sd->gspca_dev.dev;
- __u8 *buf = sd->gspca_dev.usb_buf;
-
- /* No sensor with a data width larger than 16 bits has yet been seen */
- if (len > 2 || !len)
- return -EINVAL;
-
- memcpy(buf, sensor_urb_skeleton,
- sizeof(sensor_urb_skeleton));
-
- buf[11] = sd->sensor->i2c_slave_id;
- buf[15] = address;
-
- /* Special case larger sensor writes */
- p = buf + 16;
-
- /* Copy a four byte write sequence for each byte to be written to */
- for (i = 0; i < len; i++) {
- memcpy(p, sensor_urb_skeleton + 16, 4);
- p[3] = i2c_data[i];
- p += 4;
- PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
- address, i2c_data[i]);
- }
-
- /* Copy the tailer */
- memcpy(p, sensor_urb_skeleton + 20, 4);
-
- /* Set the total length */
- p[3] = 0x10 + len;
-
- err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- 0x04, 0x40, 0x19,
- 0x0000, buf,
- 20 + len * 4, M5602_URB_MSG_TIMEOUT);
-
- return (err < 0) ? err : 0;
-}
-
int s5k4aa_init(struct sd *sd)
{
int i, err = 0;
@@ -219,14 +137,14 @@ int s5k4aa_init(struct sd *sd)
case SENSOR:
data[0] = init_s5k4aa[i][2];
- err = s5k4aa_write_sensor(sd,
+ err = m5602_write_sensor(sd,
init_s5k4aa[i][1], data, 1);
break;
case SENSOR_LONG:
data[0] = init_s5k4aa[i][2];
data[1] = init_s5k4aa[i][3];
- err = s5k4aa_write_sensor(sd,
+ err = m5602_write_sensor(sd,
init_s5k4aa[i][1], data, 2);
break;
default:
@@ -241,21 +159,21 @@ int s5k4aa_init(struct sd *sd)
if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) {
u8 data = 0x02;
info("vertical flip quirk active");
- s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
- s5k4aa_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+ m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+ m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
data |= S5K4AA_RM_V_FLIP;
data &= ~S5K4AA_RM_H_FLIP;
- s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+ m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
/* Decrement COLSTART to preserve color order (BGGR) */
- s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+ m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
data--;
- s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+ m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
/* Increment ROWSTART to preserve color order (BGGR) */
- s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+ m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
data++;
- s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+ m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
}
return (err < 0) ? err : 0;
@@ -272,20 +190,20 @@ int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
goto out;
- err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
if (err < 0)
goto out;
*val = data << 8;
- err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
*val |= data;
PDEBUG(D_V4L2, "Read exposure %d", *val);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
@@ -295,17 +213,17 @@ int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
int err;
PDEBUG(D_V4L2, "Set exposure to %d", val);
- err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
goto out;
data = (val >> 8) & 0xff;
- err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
if (err < 0)
goto out;
data = val & 0xff;
- err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -314,16 +232,16 @@ int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
goto out;
- err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
*val = (data & S5K4AA_RM_V_FLIP) >> 7;
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -333,35 +251,35 @@ int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
int err;
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
- err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
goto out;
- err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
goto out;
data = ((data & ~S5K4AA_RM_V_FLIP)
| ((val & 0x01) << 7));
- err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
goto out;
if (val) {
- err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
if (err < 0)
goto out;
data++;
- err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
} else {
- err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
if (err < 0)
goto out;
data--;
- err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
}
out:
- return (err < 0) ? err : 0;
+ return err;
}
int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -370,15 +288,15 @@ int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
goto out;
- err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
*val = (data & S5K4AA_RM_H_FLIP) >> 6;
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -389,35 +307,35 @@ int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
PDEBUG(D_V4L2, "Set horizontal flip to %d",
val);
- err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
goto out;
- err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
goto out;
data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
- err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
goto out;
if (val) {
- err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
if (err < 0)
goto out;
data++;
- err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
if (err < 0)
goto out;
} else {
- err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
if (err < 0)
goto out;
data--;
- err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
}
out:
- return (err < 0) ? err : 0;
+ return err;
}
int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -426,16 +344,16 @@ int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
goto out;
- err = s5k4aa_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
*val = data;
PDEBUG(D_V4L2, "Read gain %d", *val);
out:
- return (err < 0) ? err : 0;
+ return err;
}
int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -445,28 +363,28 @@ int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
int err;
PDEBUG(D_V4L2, "Set gain to %d", val);
- err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
goto out;
data = val & 0xff;
- err = s5k4aa_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
out:
- return (err < 0) ? err : 0;
+ return err;
}
-void s5k4aa_dump_registers(struct sd *sd)
+static void s5k4aa_dump_registers(struct sd *sd)
{
int address;
u8 page, old_page;
- s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
+ m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
for (page = 0; page < 16; page++) {
- s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
+ m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
info("Dumping the s5k4aa register state for page 0x%x", page);
for (address = 0; address <= 0xff; address++) {
u8 value = 0;
- s5k4aa_read_sensor(sd, address, &value, 1);
+ m5602_read_sensor(sd, address, &value, 1);
info("register 0x%x contains 0x%x",
address, value);
}
@@ -474,15 +392,15 @@ void s5k4aa_dump_registers(struct sd *sd)
info("s5k4aa register state dump complete");
for (page = 0; page < 16; page++) {
- s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
+ m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
info("Probing for which registers that are "
"read/write for page 0x%x", page);
for (address = 0; address <= 0xff; address++) {
u8 old_value, ctrl_value, test_value = 0xff;
- s5k4aa_read_sensor(sd, address, &old_value, 1);
- s5k4aa_write_sensor(sd, address, &test_value, 1);
- s5k4aa_read_sensor(sd, address, &ctrl_value, 1);
+ m5602_read_sensor(sd, address, &old_value, 1);
+ m5602_write_sensor(sd, address, &test_value, 1);
+ m5602_read_sensor(sd, address, &ctrl_value, 1);
if (ctrl_value == test_value)
info("register 0x%x is writeable", address);
@@ -490,9 +408,9 @@ void s5k4aa_dump_registers(struct sd *sd)
info("register 0x%x is read only", address);
/* Restore original value */
- s5k4aa_write_sensor(sd, address, &old_value, 1);
+ m5602_write_sensor(sd, address, &old_value, 1);
}
}
info("Read/write register probing complete");
- s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
+ m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
}
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
index 151c6f530..1f88b0d04 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
@@ -41,11 +41,10 @@
#define S5K4AA_WINDOW_HEIGHT_LO 0x09
#define S5K4AA_WINDOW_WIDTH_HI 0x0a
#define S5K4AA_WINDOW_WIDTH_LO 0x0b
-#define S5K4AA_GLOBAL_GAIN__ 0x0f /* Only a guess ATM !!! */
-#define S5K4AA_H_BLANK_HI__ 0x1d /* Only a guess ATM !!! sync lost
- if too low, reduces frame rate
- if too high */
-#define S5K4AA_H_BLANK_LO__ 0x1e /* Only a guess ATM !!! */
+#define S5K4AA_GLOBAL_GAIN__ 0x0f
+/* sync lost, if too low, reduces frame rate if too high */
+#define S5K4AA_H_BLANK_HI__ 0x1d
+#define S5K4AA_H_BLANK_LO__ 0x1e
#define S5K4AA_EXPOSURE_HI 0x17
#define S5K4AA_EXPOSURE_LO 0x18
#define S5K4AA_GAIN_1 0x1f /* (digital?) gain : 5 bits */
@@ -68,13 +67,6 @@ int s5k4aa_probe(struct sd *sd);
int s5k4aa_init(struct sd *sd);
int s5k4aa_power_down(struct sd *sd);
-void s5k4aa_dump_registers(struct sd *sd);
-
-int s5k4aa_read_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len);
-int s5k4aa_write_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len);
-
int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
@@ -89,9 +81,8 @@ static struct m5602_sensor s5k4aa = {
.probe = s5k4aa_probe,
.init = s5k4aa_init,
.power_down = s5k4aa_power_down,
- .read_sensor = s5k4aa_read_sensor,
- .write_sensor = s5k4aa_write_sensor,
.i2c_slave_id = 0x5a,
+ .i2c_regW = 2,
.nctrls = 4,
.ctrls = {
{
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c
index 8988a728e..af3f2dc2c 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -18,6 +18,8 @@
#include "m5602_s5k83a.h"
+static void s5k83a_dump_registers(struct sd *sd);
+
int s5k83a_probe(struct sd *sd)
{
u8 prod_id = 0, ver_id = 0;
@@ -39,7 +41,7 @@ int s5k83a_probe(struct sd *sd)
for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};
if (preinit_s5k83a[i][0] == SENSOR)
- err = s5k83a_write_sensor(sd, preinit_s5k83a[i][1],
+ err = m5602_write_sensor(sd, preinit_s5k83a[i][1],
data, 2);
else
err = m5602_write_bridge(sd, preinit_s5k83a[i][1],
@@ -49,10 +51,10 @@ int s5k83a_probe(struct sd *sd)
/* We don't know what register (if any) that contain the product id
* Just pick the first addresses that seem to produce the same results
* on multiple machines */
- if (s5k83a_read_sensor(sd, 0x00, &prod_id, 1))
+ if (m5602_read_sensor(sd, 0x00, &prod_id, 1))
return -ENODEV;
- if (s5k83a_read_sensor(sd, 0x01, &ver_id, 1))
+ if (m5602_read_sensor(sd, 0x01, &ver_id, 1))
return -ENODEV;
if ((prod_id == 0xff) || (ver_id == 0xff))
@@ -68,91 +70,6 @@ sensor_found:
return 0;
}
-int s5k83a_read_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len)
-{
- int err, i;
-
- do {
- err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
- } while ((*i2c_data & I2C_BUSY) && !err);
- if (err < 0)
- goto out;
-
- err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
- sd->sensor->i2c_slave_id);
- if (err < 0)
- goto out;
-
- err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
- if (err < 0)
- goto out;
-
- err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
- if (err < 0)
- goto out;
-
- do {
- err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
- } while ((*i2c_data & I2C_BUSY) && !err);
-
- if (err < 0)
- goto out;
- for (i = 0; i < len && !len; i++) {
- err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
-
- PDEBUG(D_CONF, "Reading sensor register "
- "0x%x containing 0x%x ", address, *i2c_data);
- }
-
-out:
- return (err < 0) ? err : 0;
-}
-
-int s5k83a_write_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len)
-{
- int err, i;
- u8 *p;
- struct usb_device *udev = sd->gspca_dev.dev;
- __u8 *buf = sd->gspca_dev.usb_buf;
-
- /* No sensor with a data width larger than 16 bits has yet been seen */
- if (len > 2 || !len)
- return -EINVAL;
-
- memcpy(buf, sensor_urb_skeleton,
- sizeof(sensor_urb_skeleton));
-
- buf[11] = sd->sensor->i2c_slave_id;
- buf[15] = address;
-
- /* Special case larger sensor writes */
- p = buf + 16;
-
- /* Copy a four byte write sequence for each byte to be written to */
- for (i = 0; i < len; i++) {
- memcpy(p, sensor_urb_skeleton + 16, 4);
- p[3] = i2c_data[i];
- p += 4;
- PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
- address, i2c_data[i]);
- }
-
- /* Copy the tailer */
- memcpy(p, sensor_urb_skeleton + 20, 4);
-
- /* Set the total length */
- p[3] = 0x10 + len;
-
- err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- 0x04, 0x40, 0x19,
- 0x0000, buf,
- 20 + len * 4, M5602_URB_MSG_TIMEOUT);
-
- return (err < 0) ? err : 0;
-}
-
int s5k83a_init(struct sd *sd)
{
int i, err = 0;
@@ -169,14 +86,14 @@ int s5k83a_init(struct sd *sd)
case SENSOR:
data[0] = init_s5k83a[i][2];
- err = s5k83a_write_sensor(sd,
+ err = m5602_write_sensor(sd,
init_s5k83a[i][1], data, 1);
break;
case SENSOR_LONG:
data[0] = init_s5k83a[i][2];
data[1] = init_s5k83a[i][3];
- err = s5k83a_write_sensor(sd,
+ err = m5602_write_sensor(sd,
init_s5k83a[i][1], data, 2);
break;
default:
@@ -200,14 +117,14 @@ void s5k83a_dump_registers(struct sd *sd)
{
int address;
u8 page, old_page;
- s5k83a_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+ m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
for (page = 0; page < 16; page++) {
- s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
+ m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
info("Dumping the s5k83a register state for page 0x%x", page);
for (address = 0; address <= 0xff; address++) {
u8 val = 0;
- s5k83a_read_sensor(sd, address, &val, 1);
+ m5602_read_sensor(sd, address, &val, 1);
info("register 0x%x contains 0x%x",
address, val);
}
@@ -215,15 +132,15 @@ void s5k83a_dump_registers(struct sd *sd)
info("s5k83a register state dump complete");
for (page = 0; page < 16; page++) {
- s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
+ m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
info("Probing for which registers that are read/write "
"for page 0x%x", page);
for (address = 0; address <= 0xff; address++) {
u8 old_val, ctrl_val, test_val = 0xff;
- s5k83a_read_sensor(sd, address, &old_val, 1);
- s5k83a_write_sensor(sd, address, &test_val, 1);
- s5k83a_read_sensor(sd, address, &ctrl_val, 1);
+ m5602_read_sensor(sd, address, &old_val, 1);
+ m5602_write_sensor(sd, address, &test_val, 1);
+ m5602_read_sensor(sd, address, &ctrl_val, 1);
if (ctrl_val == test_val)
info("register 0x%x is writeable", address);
@@ -231,11 +148,11 @@ void s5k83a_dump_registers(struct sd *sd)
info("register 0x%x is read only", address);
/* Restore original val */
- s5k83a_write_sensor(sd, address, &old_val, 1);
+ m5602_write_sensor(sd, address, &old_val, 1);
}
}
info("Read/write register probing complete");
- s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+ m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
}
int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
@@ -244,11 +161,15 @@ int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
- err = s5k83a_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+ err = m5602_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+ if (err < 0)
+ goto out;
+
data[1] = data[1] << 1;
*val = data[1];
- return (err < 0) ? err : 0;
+out:
+ return err;
}
int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -259,23 +180,24 @@ int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
data[0] = 0x00;
data[1] = 0x20;
- err = s5k83a_write_sensor(sd, 0x14, data, 2);
+ err = m5602_write_sensor(sd, 0x14, data, 2);
if (err < 0)
- return err;
+ goto out;
data[0] = 0x01;
data[1] = 0x00;
- err = s5k83a_write_sensor(sd, 0x0d, data, 2);
+ err = m5602_write_sensor(sd, 0x0d, data, 2);
if (err < 0)
- return err;
+ goto out;
/* FIXME: This is not sane, we need to figure out the composition
of these registers */
data[0] = val >> 3; /* brightness, high 5 bits */
data[1] = val >> 1; /* brightness, high 7 bits */
- err = s5k83a_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+ err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
- return (err < 0) ? err : 0;
+out:
+ return err;
}
int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val)
@@ -284,10 +206,14 @@ int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val)
u8 data;
struct sd *sd = (struct sd *) gspca_dev;
- err = s5k83a_read_sensor(sd, S5K83A_WHITENESS, &data, 1);
+ err = m5602_read_sensor(sd, S5K83A_WHITENESS, &data, 1);
+ if (err < 0)
+ goto out;
*val = data;
- return (err < 0) ? err : 0;
+
+out:
+ return err;
}
int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val)
@@ -297,9 +223,9 @@ int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
data[0] = val;
- err = s5k83a_write_sensor(sd, S5K83A_WHITENESS, data, 1);
+ err = m5602_write_sensor(sd, S5K83A_WHITENESS, data, 1);
- return (err < 0) ? err : 0;
+ return err;
}
int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -308,7 +234,9 @@ int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
- err = s5k83a_read_sensor(sd, S5K83A_GAIN, data, 2);
+ err = m5602_read_sensor(sd, S5K83A_GAIN, data, 2);
+ if (err < 0)
+ goto out;
data[1] = data[1] & 0x3f;
if (data[1] > S5K83A_MAXIMUM_GAIN)
@@ -316,7 +244,8 @@ int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
*val = data[1];
- return (err < 0) ? err : 0;
+out:
+ return err;
}
int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -327,9 +256,8 @@ int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
data[0] = 0;
data[1] = val;
- err = s5k83a_write_sensor(sd, S5K83A_GAIN, data, 2);
-
- return (err < 0) ? err : 0;
+ err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
+ return err;
}
int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -339,14 +267,15 @@ int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
struct sd *sd = (struct sd *) gspca_dev;
data[0] = 0x05;
- err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+ err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
if (err < 0)
- return err;
+ goto out;
- err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+ err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
*val = (data[0] | 0x40) ? 1 : 0;
- return (err < 0) ? err : 0;
+out:
+ return err;
}
int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -356,25 +285,26 @@ int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
data[0] = 0x05;
- err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+ err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
if (err < 0)
- return err;
+ goto out;
- err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+ err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
if (err < 0)
- return err;
+ goto out;
/* set or zero six bit, seven is hflip */
data[0] = (val) ? (data[0] & 0x80) | 0x40 | S5K83A_FLIP_MASK
: (data[0] & 0x80) | S5K83A_FLIP_MASK;
- err = s5k83a_write_sensor(sd, S5K83A_FLIP, data, 1);
+ err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
if (err < 0)
- return err;
+ goto out;
data[0] = (val) ? 0x0b : 0x0a;
- err = s5k83a_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
+ err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
- return (err < 0) ? err : 0;
+out:
+ return err;
}
int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -384,14 +314,15 @@ int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
struct sd *sd = (struct sd *) gspca_dev;
data[0] = 0x05;
- err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+ err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
if (err < 0)
- return err;
+ goto out;
- err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+ err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
*val = (data[0] | 0x80) ? 1 : 0;
- return (err < 0) ? err : 0;
+out:
+ return err;
}
int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -401,23 +332,23 @@ int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
data[0] = 0x05;
- err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+ err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
if (err < 0)
- return err;
+ goto out;
- err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+ err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
if (err < 0)
- return err;
+ goto out;
/* set or zero seven bit, six is vflip */
data[0] = (val) ? (data[0] & 0x40) | 0x80 | S5K83A_FLIP_MASK
: (data[0] & 0x40) | S5K83A_FLIP_MASK;
- err = s5k83a_write_sensor(sd, S5K83A_FLIP, data, 1);
+ err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
if (err < 0)
- return err;
+ goto out;
data[0] = (val) ? 0x0a : 0x0b;
- err = s5k83a_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
-
- return (err < 0) ? err : 0;
+ err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
+out:
+ return err;
}
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h
index ee3ee9cfc..05ccb5b57 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h
@@ -22,15 +22,15 @@
#include "m5602_sensor.h"
#define S5K83A_FLIP 0x01
-#define S5K83A_HFLIP_TUNE 0x03
-#define S5K83A_VFLIP_TUNE 0x05
-#define S5K83A_WHITENESS 0x0a
+#define S5K83A_HFLIP_TUNE 0x03
+#define S5K83A_VFLIP_TUNE 0x05
+#define S5K83A_WHITENESS 0x0a
#define S5K83A_GAIN 0x18
-#define S5K83A_BRIGHTNESS 0x1b
-#define S5K83A_PAGE_MAP 0xec
+#define S5K83A_BRIGHTNESS 0x1b
+#define S5K83A_PAGE_MAP 0xec
-#define S5K83A_DEFAULT_BRIGHTNESS 0x71
-#define S5K83A_DEFAULT_WHITENESS 0x7e
+#define S5K83A_DEFAULT_BRIGHTNESS 0x71
+#define S5K83A_DEFAULT_WHITENESS 0x7e
#define S5K83A_DEFAULT_GAIN 0x00
#define S5K83A_MAXIMUM_GAIN 0x3c
#define S5K83A_FLIP_MASK 0x10
@@ -46,13 +46,6 @@ int s5k83a_probe(struct sd *sd);
int s5k83a_init(struct sd *sd);
int s5k83a_power_down(struct sd *sd);
-void s5k83a_dump_registers(struct sd *sd);
-
-int s5k83a_read_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len);
-int s5k83a_write_sensor(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len);
-
int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val);
@@ -64,15 +57,13 @@ int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-
static struct m5602_sensor s5k83a = {
.name = "S5K83A",
.probe = s5k83a_probe,
.init = s5k83a_init,
.power_down = s5k83a_power_down,
- .read_sensor = s5k83a_read_sensor,
- .write_sensor = s5k83a_write_sensor,
.i2c_slave_id = 0x5a,
+ .i2c_regW = 2,
.nctrls = 5,
.ctrls = {
{
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_sensor.h b/linux/drivers/media/video/gspca/m5602/m5602_sensor.h
index 60c9a48e0..261623f0d 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_sensor.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_sensor.h
@@ -49,23 +49,21 @@ struct m5602_sensor {
/* What i2c address the sensor is connected to */
u8 i2c_slave_id;
+ /* Width of each i2c register (in bytes) */
+ u8 i2c_regW;
+
/* Probes if the sensor is connected */
int (*probe)(struct sd *sd);
/* Performs a initialization sequence */
int (*init)(struct sd *sd);
+ /* Executed when the camera starts to send data */
+ int (*start)(struct sd *sd);
+
/* Performs a power down sequence */
int (*power_down)(struct sd *sd);
- /* Reads a sensor register */
- int (*read_sensor)(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len);
-
- /* Writes to a sensor register */
- int (*write_sensor)(struct sd *sd, const u8 address,
- u8 *i2c_data, const u8 len);
-
int nctrls;
struct ctrl ctrls[M5602_MAX_CTRLS];
diff --git a/linux/drivers/media/video/gspca/mars.c b/linux/drivers/media/video/gspca/mars.c
index 492cdd3b5..3d2090e67 100644
--- a/linux/drivers/media/video/gspca/mars.c
+++ b/linux/drivers/media/video/gspca/mars.c
@@ -39,7 +39,7 @@ struct sd {
static struct ctrl sd_ctrls[] = {
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 589,
diff --git a/linux/drivers/media/video/gspca/ov519.c b/linux/drivers/media/video/gspca/ov519.c
index b18d98191..5e31a9145 100644
--- a/linux/drivers/media/video/gspca/ov519.c
+++ b/linux/drivers/media/video/gspca/ov519.c
@@ -3,7 +3,18 @@
*
* Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
*
- * (This module is adapted from the ov51x-jpeg package)
+ * This module is adapted from the ov51x-jpeg package, which itself
+ * was adapted from the ov511 driver.
+ *
+ * Original copyright for the ov511 driver is:
+ *
+ * Copyright (c) 1999-2004 Mark W. McClelland
+ * Support for OV519, OV8610 Copyright (c) 2003 Joerg Heckenbach
+ *
+ * ov51x-jpeg original copyright is:
+ *
+ * Copyright (c) 2004-2007 Romain Beauxis <toots@rastageeks.org>
+ * Support for OV7670 sensors was contributed by Sam Skipsey <aoanla@yahoo.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -153,7 +164,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -165,7 +176,7 @@ static struct v4l2_pix_format vga_mode[] = {
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 0},
};
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 176,
.sizeimage = 176 * 144 * 3 / 8 + 590,
diff --git a/linux/drivers/media/video/gspca/ov534.c b/linux/drivers/media/video/gspca/ov534.c
index a574be09b..3bf15e401 100644
--- a/linux/drivers/media/video/gspca/ov534.c
+++ b/linux/drivers/media/video/gspca/ov534.c
@@ -1,6 +1,7 @@
/*
* ov534/ov772x gspca driver
* Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it>
+ * Copyright (C) 2008 Jim Paris <jim@jtan.com>
*
* Based on a prototype written by Mark Ferrell <majortrips@gmail.com>
* USB protocol reverse engineered by Jim Paris <jim@jtan.com>
@@ -42,20 +43,19 @@ MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver");
MODULE_LICENSE("GPL");
-/* global parameters */
-static int frame_rate;
-
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- __u8 frame_rate;
+ __u32 last_fid;
+ __u32 last_pts;
+ int frame_rate;
};
/* V4L2 controls supported by the driver */
static struct ctrl sd_ctrls[] = {
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
.bytesperline = 640 * 2,
.sizeimage = 640 * 480 * 2,
@@ -63,80 +63,68 @@ static struct v4l2_pix_format vga_mode[] = {
.priv = 0},
};
-static void ov534_reg_write(struct usb_device *udev, u16 reg, u16 val)
+static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
{
- u16 data = val;
+ struct usb_device *udev = gspca_dev->dev;
int ret;
- PDEBUG(D_USBO, "reg=0x%04x, val=0%04x", reg, val);
+ PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val);
+ gspca_dev->usb_buf[0] = val;
ret = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
0x1,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0, reg, &data, 1, CTRL_TIMEOUT);
+ 0x0, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
if (ret < 0)
PDEBUG(D_ERR, "write failed");
}
-static u16 ov534_reg_read(struct usb_device *udev, u16 reg)
+static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
{
- u16 data;
+ struct usb_device *udev = gspca_dev->dev;
int ret;
ret = usb_control_msg(udev,
usb_rcvctrlpipe(udev, 0),
0x1,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0, reg, &data, 1, CTRL_TIMEOUT);
- PDEBUG(D_USBI, "reg=0x%04x, data=0x%04x", reg, data);
+ 0x0, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
+ PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]);
if (ret < 0)
PDEBUG(D_ERR, "read failed");
- return data;
-}
-
-static void ov534_reg_verify_write(struct usb_device *udev, u16 reg, u16 val)
-{
- u16 data;
-
- ov534_reg_write(udev, reg, val);
- data = ov534_reg_read(udev, reg);
- if (data != val) {
- PDEBUG(D_ERR | D_USBO,
- "unexpected result from read: 0x%04x != 0x%04x", val,
- data);
- }
+ return gspca_dev->usb_buf[0];
}
/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.
* (direction and output)? */
-static void ov534_set_led(struct usb_device *udev, int status)
+static void ov534_set_led(struct gspca_dev *gspca_dev, int status)
{
- u16 data;
+ u8 data;
PDEBUG(D_CONF, "led status: %d", status);
- data = ov534_reg_read(udev, 0x21);
+ data = ov534_reg_read(gspca_dev, 0x21);
data |= 0x80;
- ov534_reg_write(udev, 0x21, data);
+ ov534_reg_write(gspca_dev, 0x21, data);
- data = ov534_reg_read(udev, 0x23);
+ data = ov534_reg_read(gspca_dev, 0x23);
if (status)
data |= 0x80;
else
data &= ~(0x80);
- ov534_reg_write(udev, 0x23, data);
+ ov534_reg_write(gspca_dev, 0x23, data);
}
-static int sccb_check_status(struct usb_device *udev)
+static int sccb_check_status(struct gspca_dev *gspca_dev)
{
- u16 data;
+ u8 data;
int i;
for (i = 0; i < 5; i++) {
- data = ov534_reg_read(udev, OV534_REG_STATUS);
+ data = ov534_reg_read(gspca_dev, OV534_REG_STATUS);
- switch (data & 0xFF) {
+ switch (data) {
case 0x00:
return 1;
case 0x04:
@@ -144,195 +132,243 @@ static int sccb_check_status(struct usb_device *udev)
case 0x03:
break;
default:
- PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5\n",
+ PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5",
data, i + 1);
}
}
return 0;
}
-static void sccb_reg_write(struct usb_device *udev, u16 reg, u16 val)
+static void sccb_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
{
- PDEBUG(D_USBO, "reg: 0x%04x, val: 0x%04x", reg, val);
- ov534_reg_write(udev, OV534_REG_SUBADDR, reg);
- ov534_reg_write(udev, OV534_REG_WRITE, val);
- ov534_reg_write(udev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
+ PDEBUG(D_USBO, "reg: 0x%04x, val: 0x%02x", reg, val);
+ ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
+ ov534_reg_write(gspca_dev, OV534_REG_WRITE, val);
+ ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
- if (!sccb_check_status(udev))
+ if (!sccb_check_status(gspca_dev))
PDEBUG(D_ERR, "sccb_reg_write failed");
}
+#ifdef GSPCA_DEBUG
+static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
+{
+ ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
+ ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
+ if (!sccb_check_status(gspca_dev))
+ PDEBUG(D_ERR, "sccb_reg_read failed 1");
+
+ ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
+ if (!sccb_check_status(gspca_dev))
+ PDEBUG(D_ERR, "sccb_reg_read failed 2");
+
+ return ov534_reg_read(gspca_dev, OV534_REG_READ);
+}
+#endif
+
+static const __u8 ov534_reg_initdata[][2] = {
+ { 0xe7, 0x3a },
+
+ { OV534_REG_ADDRESS, 0x42 }, /* select OV772x sensor */
+
+ { 0xc2, 0x0c },
+ { 0x88, 0xf8 },
+ { 0xc3, 0x69 },
+ { 0x89, 0xff },
+ { 0x76, 0x03 },
+ { 0x92, 0x01 },
+ { 0x93, 0x18 },
+ { 0x94, 0x10 },
+ { 0x95, 0x10 },
+ { 0xe2, 0x00 },
+ { 0xe7, 0x3e },
+
+ { 0x96, 0x00 },
+
+ { 0x97, 0x20 },
+ { 0x97, 0x20 },
+ { 0x97, 0x20 },
+ { 0x97, 0x0a },
+ { 0x97, 0x3f },
+ { 0x97, 0x4a },
+ { 0x97, 0x20 },
+ { 0x97, 0x15 },
+ { 0x97, 0x0b },
+
+ { 0x8e, 0x40 },
+ { 0x1f, 0x81 },
+ { 0x34, 0x05 },
+ { 0xe3, 0x04 },
+ { 0x88, 0x00 },
+ { 0x89, 0x00 },
+ { 0x76, 0x00 },
+ { 0xe7, 0x2e },
+ { 0x31, 0xf9 },
+ { 0x25, 0x42 },
+ { 0x21, 0xf0 },
+
+ { 0x1c, 0x00 },
+ { 0x1d, 0x40 },
+ { 0x1d, 0x02 }, /* payload size 0x0200 * 4 = 2048 bytes */
+ { 0x1d, 0x00 }, /* payload size */
+ { 0x1d, 0x02 }, /* frame size 0x025800 * 4 = 614400 */
+ { 0x1d, 0x58 }, /* frame size */
+ { 0x1d, 0x00 }, /* frame size */
+
+ { 0x1c, 0x0a },
+ { 0x1d, 0x08 }, /* turn on UVC header */
+ { 0x1d, 0x0e }, /* .. */
+
+ { 0x8d, 0x1c },
+ { 0x8e, 0x80 },
+ { 0xe5, 0x04 },
+
+ { 0xc0, 0x50 },
+ { 0xc1, 0x3c },
+ { 0xc2, 0x0c },
+};
+
+static const __u8 ov772x_reg_initdata[][2] = {
+ { 0x12, 0x80 },
+ { 0x11, 0x01 },
+
+ { 0x3d, 0x03 },
+ { 0x17, 0x26 },
+ { 0x18, 0xa0 },
+ { 0x19, 0x07 },
+ { 0x1a, 0xf0 },
+ { 0x32, 0x00 },
+ { 0x29, 0xa0 },
+ { 0x2c, 0xf0 },
+ { 0x65, 0x20 },
+ { 0x11, 0x01 },
+ { 0x42, 0x7f },
+ { 0x63, 0xe0 },
+ { 0x64, 0xff },
+ { 0x66, 0x00 },
+ { 0x13, 0xf0 },
+ { 0x0d, 0x41 },
+ { 0x0f, 0xc5 },
+ { 0x14, 0x11 },
+
+ { 0x22, 0x7f },
+ { 0x23, 0x03 },
+ { 0x24, 0x40 },
+ { 0x25, 0x30 },
+ { 0x26, 0xa1 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x00 },
+ { 0x6b, 0xaa },
+ { 0x13, 0xff },
+
+ { 0x90, 0x05 },
+ { 0x91, 0x01 },
+ { 0x92, 0x03 },
+ { 0x93, 0x00 },
+ { 0x94, 0x60 },
+ { 0x95, 0x3c },
+ { 0x96, 0x24 },
+ { 0x97, 0x1e },
+ { 0x98, 0x62 },
+ { 0x99, 0x80 },
+ { 0x9a, 0x1e },
+ { 0x9b, 0x08 },
+ { 0x9c, 0x20 },
+ { 0x9e, 0x81 },
+
+ { 0xa6, 0x04 },
+ { 0x7e, 0x0c },
+ { 0x7f, 0x16 },
+ { 0x80, 0x2a },
+ { 0x81, 0x4e },
+ { 0x82, 0x61 },
+ { 0x83, 0x6f },
+ { 0x84, 0x7b },
+ { 0x85, 0x86 },
+ { 0x86, 0x8e },
+ { 0x87, 0x97 },
+ { 0x88, 0xa4 },
+ { 0x89, 0xaf },
+ { 0x8a, 0xc5 },
+ { 0x8b, 0xd7 },
+ { 0x8c, 0xe8 },
+ { 0x8d, 0x20 },
+
+ { 0x0c, 0x90 },
+
+ { 0x2b, 0x00 },
+ { 0x22, 0x7f },
+ { 0x23, 0x03 },
+ { 0x11, 0x01 },
+ { 0x0c, 0xd0 },
+ { 0x64, 0xff },
+ { 0x0d, 0x41 },
+
+ { 0x14, 0x41 },
+ { 0x0e, 0xcd },
+ { 0xac, 0xbf },
+ { 0x8e, 0x00 },
+ { 0x0c, 0xd0 }
+};
+
+/* set framerate */
+static void ov534_set_frame_rate(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int fr = sd->frame_rate;
+
+ switch (fr) {
+ case 50:
+ sccb_reg_write(gspca_dev, 0x11, 0x01);
+ sccb_reg_write(gspca_dev, 0x0d, 0x41);
+ ov534_reg_write(gspca_dev, 0xe5, 0x02);
+ break;
+ case 40:
+ sccb_reg_write(gspca_dev, 0x11, 0x02);
+ sccb_reg_write(gspca_dev, 0x0d, 0xc1);
+ ov534_reg_write(gspca_dev, 0xe5, 0x04);
+ break;
+/* case 30: */
+ default:
+ fr = 30;
+ sccb_reg_write(gspca_dev, 0x11, 0x04);
+ sccb_reg_write(gspca_dev, 0x0d, 0x81);
+ ov534_reg_write(gspca_dev, 0xe5, 0x02);
+ break;
+ case 15:
+ sccb_reg_write(gspca_dev, 0x11, 0x03);
+ sccb_reg_write(gspca_dev, 0x0d, 0x41);
+ ov534_reg_write(gspca_dev, 0xe5, 0x04);
+ break;
+ }
+
+ sd->frame_rate = fr;
+ PDEBUG(D_PROBE, "frame_rate: %d", fr);
+}
+
/* setup method */
-static void ov534_setup(struct usb_device *udev)
+static void ov534_setup(struct gspca_dev *gspca_dev)
{
- ov534_reg_verify_write(udev, 0xe7, 0x3a);
-
- ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60);
- ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60);
- ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60);
- ov534_reg_write(udev, OV534_REG_ADDRESS, 0x42);
-
- ov534_reg_verify_write(udev, 0xc2, 0x0c);
- ov534_reg_verify_write(udev, 0x88, 0xf8);
- ov534_reg_verify_write(udev, 0xc3, 0x69);
- ov534_reg_verify_write(udev, 0x89, 0xff);
- ov534_reg_verify_write(udev, 0x76, 0x03);
- ov534_reg_verify_write(udev, 0x92, 0x01);
- ov534_reg_verify_write(udev, 0x93, 0x18);
- ov534_reg_verify_write(udev, 0x94, 0x10);
- ov534_reg_verify_write(udev, 0x95, 0x10);
- ov534_reg_verify_write(udev, 0xe2, 0x00);
- ov534_reg_verify_write(udev, 0xe7, 0x3e);
-
- ov534_reg_write(udev, 0x1c, 0x0a);
- ov534_reg_write(udev, 0x1d, 0x22);
- ov534_reg_write(udev, 0x1d, 0x06);
-
- ov534_reg_verify_write(udev, 0x96, 0x00);
-
- ov534_reg_write(udev, 0x97, 0x20);
- ov534_reg_write(udev, 0x97, 0x20);
- ov534_reg_write(udev, 0x97, 0x20);
- ov534_reg_write(udev, 0x97, 0x0a);
- ov534_reg_write(udev, 0x97, 0x3f);
- ov534_reg_write(udev, 0x97, 0x4a);
- ov534_reg_write(udev, 0x97, 0x20);
- ov534_reg_write(udev, 0x97, 0x15);
- ov534_reg_write(udev, 0x97, 0x0b);
-
- ov534_reg_verify_write(udev, 0x8e, 0x40);
- ov534_reg_verify_write(udev, 0x1f, 0x81);
- ov534_reg_verify_write(udev, 0x34, 0x05);
- ov534_reg_verify_write(udev, 0xe3, 0x04);
- ov534_reg_verify_write(udev, 0x88, 0x00);
- ov534_reg_verify_write(udev, 0x89, 0x00);
- ov534_reg_verify_write(udev, 0x76, 0x00);
- ov534_reg_verify_write(udev, 0xe7, 0x2e);
- ov534_reg_verify_write(udev, 0x31, 0xf9);
- ov534_reg_verify_write(udev, 0x25, 0x42);
- ov534_reg_verify_write(udev, 0x21, 0xf0);
-
- ov534_reg_write(udev, 0x1c, 0x00);
- ov534_reg_write(udev, 0x1d, 0x40);
- ov534_reg_write(udev, 0x1d, 0x02);
- ov534_reg_write(udev, 0x1d, 0x00);
- ov534_reg_write(udev, 0x1d, 0x02);
- ov534_reg_write(udev, 0x1d, 0x57);
- ov534_reg_write(udev, 0x1d, 0xff);
-
- ov534_reg_verify_write(udev, 0x8d, 0x1c);
- ov534_reg_verify_write(udev, 0x8e, 0x80);
- ov534_reg_verify_write(udev, 0xe5, 0x04);
-
- ov534_set_led(udev, 1);
-
- sccb_reg_write(udev, 0x12, 0x80);
- sccb_reg_write(udev, 0x11, 0x01);
- sccb_reg_write(udev, 0x11, 0x01);
- sccb_reg_write(udev, 0x11, 0x01);
- sccb_reg_write(udev, 0x11, 0x01);
- sccb_reg_write(udev, 0x11, 0x01);
- sccb_reg_write(udev, 0x11, 0x01);
- sccb_reg_write(udev, 0x11, 0x01);
- sccb_reg_write(udev, 0x11, 0x01);
- sccb_reg_write(udev, 0x11, 0x01);
- sccb_reg_write(udev, 0x11, 0x01);
- sccb_reg_write(udev, 0x11, 0x01);
-
- ov534_set_led(udev, 0);
-
- sccb_reg_write(udev, 0x3d, 0x03);
- sccb_reg_write(udev, 0x17, 0x26);
- sccb_reg_write(udev, 0x18, 0xa0);
- sccb_reg_write(udev, 0x19, 0x07);
- sccb_reg_write(udev, 0x1a, 0xf0);
- sccb_reg_write(udev, 0x32, 0x00);
- sccb_reg_write(udev, 0x29, 0xa0);
- sccb_reg_write(udev, 0x2c, 0xf0);
- sccb_reg_write(udev, 0x65, 0x20);
- sccb_reg_write(udev, 0x11, 0x01);
- sccb_reg_write(udev, 0x42, 0x7f);
- sccb_reg_write(udev, 0x63, 0xe0);
- sccb_reg_write(udev, 0x64, 0xff);
- sccb_reg_write(udev, 0x66, 0x00);
- sccb_reg_write(udev, 0x13, 0xf0);
- sccb_reg_write(udev, 0x0d, 0x41);
- sccb_reg_write(udev, 0x0f, 0xc5);
- sccb_reg_write(udev, 0x14, 0x11);
-
- ov534_set_led(udev, 1);
-
- sccb_reg_write(udev, 0x22, 0x7f);
- sccb_reg_write(udev, 0x23, 0x03);
- sccb_reg_write(udev, 0x24, 0x40);
- sccb_reg_write(udev, 0x25, 0x30);
- sccb_reg_write(udev, 0x26, 0xa1);
- sccb_reg_write(udev, 0x2a, 0x00);
- sccb_reg_write(udev, 0x2b, 0x00);
- sccb_reg_write(udev, 0x6b, 0xaa);
- sccb_reg_write(udev, 0x13, 0xff);
-
- ov534_set_led(udev, 0);
-
- sccb_reg_write(udev, 0x90, 0x05);
- sccb_reg_write(udev, 0x91, 0x01);
- sccb_reg_write(udev, 0x92, 0x03);
- sccb_reg_write(udev, 0x93, 0x00);
- sccb_reg_write(udev, 0x94, 0x60);
- sccb_reg_write(udev, 0x95, 0x3c);
- sccb_reg_write(udev, 0x96, 0x24);
- sccb_reg_write(udev, 0x97, 0x1e);
- sccb_reg_write(udev, 0x98, 0x62);
- sccb_reg_write(udev, 0x99, 0x80);
- sccb_reg_write(udev, 0x9a, 0x1e);
- sccb_reg_write(udev, 0x9b, 0x08);
- sccb_reg_write(udev, 0x9c, 0x20);
- sccb_reg_write(udev, 0x9e, 0x81);
-
- ov534_set_led(udev, 1);
-
- sccb_reg_write(udev, 0xa6, 0x04);
- sccb_reg_write(udev, 0x7e, 0x0c);
- sccb_reg_write(udev, 0x7f, 0x16);
- sccb_reg_write(udev, 0x80, 0x2a);
- sccb_reg_write(udev, 0x81, 0x4e);
- sccb_reg_write(udev, 0x82, 0x61);
- sccb_reg_write(udev, 0x83, 0x6f);
- sccb_reg_write(udev, 0x84, 0x7b);
- sccb_reg_write(udev, 0x85, 0x86);
- sccb_reg_write(udev, 0x86, 0x8e);
- sccb_reg_write(udev, 0x87, 0x97);
- sccb_reg_write(udev, 0x88, 0xa4);
- sccb_reg_write(udev, 0x89, 0xaf);
- sccb_reg_write(udev, 0x8a, 0xc5);
- sccb_reg_write(udev, 0x8b, 0xd7);
- sccb_reg_write(udev, 0x8c, 0xe8);
- sccb_reg_write(udev, 0x8d, 0x20);
-
- sccb_reg_write(udev, 0x0c, 0x90);
-
- ov534_reg_verify_write(udev, 0xc0, 0x50);
- ov534_reg_verify_write(udev, 0xc1, 0x3c);
- ov534_reg_verify_write(udev, 0xc2, 0x0c);
-
- ov534_set_led(udev, 1);
-
- sccb_reg_write(udev, 0x2b, 0x00);
- sccb_reg_write(udev, 0x22, 0x7f);
- sccb_reg_write(udev, 0x23, 0x03);
- sccb_reg_write(udev, 0x11, 0x01);
- sccb_reg_write(udev, 0x0c, 0xd0);
- sccb_reg_write(udev, 0x64, 0xff);
- sccb_reg_write(udev, 0x0d, 0x41);
-
- sccb_reg_write(udev, 0x14, 0x41);
- sccb_reg_write(udev, 0x0e, 0xcd);
- sccb_reg_write(udev, 0xac, 0xbf);
- sccb_reg_write(udev, 0x8e, 0x00);
- sccb_reg_write(udev, 0x0c, 0xd0);
-
- ov534_reg_write(udev, 0xe0, 0x09);
- ov534_set_led(udev, 0);
+ int i;
+
+ /* Initialize bridge chip */
+ for (i = 0; i < ARRAY_SIZE(ov534_reg_initdata); i++)
+ ov534_reg_write(gspca_dev, ov534_reg_initdata[i][0],
+ ov534_reg_initdata[i][1]);
+
+ PDEBUG(D_PROBE, "sensor is ov%02x%02x",
+ sccb_reg_read(gspca_dev, 0x0a),
+ sccb_reg_read(gspca_dev, 0x0b));
+
+ ov534_set_led(gspca_dev, 1);
+
+ /* Initialize sensor */
+ for (i = 0; i < ARRAY_SIZE(ov772x_reg_initdata); i++)
+ sccb_reg_write(gspca_dev, ov772x_reg_initdata[i][0],
+ ov772x_reg_initdata[i][1]);
+
+ ov534_reg_write(gspca_dev, 0xe0, 0x09);
+ ov534_set_led(gspca_dev, 0);
}
/* this function is called at probe time */
@@ -347,70 +383,26 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
- cam->bulk_size = vga_mode[0].sizeimage;
+ cam->bulk_size = 16384;
cam->bulk_nurbs = 2;
- PDEBUG(D_PROBE, "bulk_size = %d", cam->bulk_size);
-
return 0;
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
- struct sd *sd = (struct sd *)gspca_dev;
- ov534_setup(gspca_dev->dev);
-
- if (frame_rate > 0)
- sd->frame_rate = frame_rate;
-
- PDEBUG(D_PROBE, "frame_rate = %d", sd->frame_rate);
-
- switch (sd->frame_rate) {
- case 50:
- sccb_reg_write(gspca_dev->dev, 0x11, 0x01);
- sccb_check_status(gspca_dev->dev);
- sccb_reg_write(gspca_dev->dev, 0x0d, 0x41);
- sccb_check_status(gspca_dev->dev);
- ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x02);
- break;
- case 40:
- sccb_reg_write(gspca_dev->dev, 0x11, 0x02);
- sccb_check_status(gspca_dev->dev);
- sccb_reg_write(gspca_dev->dev, 0x0d, 0xc1);
- sccb_check_status(gspca_dev->dev);
- ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x04);
- break;
- case 30:
- default:
- sccb_reg_write(gspca_dev->dev, 0x11, 0x04);
- sccb_check_status(gspca_dev->dev);
- sccb_reg_write(gspca_dev->dev, 0x0d, 0x81);
- sccb_check_status(gspca_dev->dev);
- ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x02);
- break;
- case 15:
- sccb_reg_write(gspca_dev->dev, 0x11, 0x03);
- sccb_check_status(gspca_dev->dev);
- sccb_reg_write(gspca_dev->dev, 0x0d, 0x41);
- sccb_check_status(gspca_dev->dev);
- ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x04);
- break;
- };
+ ov534_setup(gspca_dev);
+ ov534_set_frame_rate(gspca_dev);
return 0;
}
static int sd_start(struct gspca_dev *gspca_dev)
{
- PDEBUG(D_PROBE, "width = %d, height = %d",
- gspca_dev->width, gspca_dev->height);
-
- gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height * 2;
-
/* start streaming data */
- ov534_set_led(gspca_dev->dev, 1);
- ov534_reg_write(gspca_dev->dev, 0xe0, 0x00);
+ ov534_set_led(gspca_dev, 1);
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
return 0;
}
@@ -418,29 +410,134 @@ static int sd_start(struct gspca_dev *gspca_dev)
static void sd_stopN(struct gspca_dev *gspca_dev)
{
/* stop streaming data */
- ov534_reg_write(gspca_dev->dev, 0xe0, 0x09);
- ov534_set_led(gspca_dev->dev, 0);
+ ov534_reg_write(gspca_dev, 0xe0, 0x09);
+ ov534_set_led(gspca_dev, 0);
}
+/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
+#define UVC_STREAM_EOH (1 << 7)
+#define UVC_STREAM_ERR (1 << 6)
+#define UVC_STREAM_STI (1 << 5)
+#define UVC_STREAM_RES (1 << 4)
+#define UVC_STREAM_SCR (1 << 3)
+#define UVC_STREAM_PTS (1 << 2)
+#define UVC_STREAM_EOF (1 << 1)
+#define UVC_STREAM_FID (1 << 0)
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
__u8 *data, int len)
{
- /*
- * The current camera setup doesn't stream the last pixel, so we set it
- * to a dummy value
- */
- __u8 last_pixel[4] = { 0, 0, 0, 0 };
- int framesize = gspca_dev->cam.bulk_size;
-
- if (len == framesize - 4) {
- frame =
- gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
- frame =
- gspca_frame_add(gspca_dev, LAST_PACKET, frame, last_pixel,
- 4);
- } else
- PDEBUG(D_PACK, "packet len = %d, framesize = %d", len,
- framesize);
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u32 this_pts;
+ int this_fid;
+ int remaining_len = len;
+ __u8 *next_data = data;
+
+scan_next:
+ if (remaining_len <= 0)
+ return;
+
+ data = next_data;
+ len = min(remaining_len, 2048);
+ remaining_len -= len;
+ next_data += len;
+
+ /* Payloads are prefixed with a UVC-style header. We
+ consider a frame to start when the FID toggles, or the PTS
+ changes. A frame ends when EOF is set, and we've received
+ the correct number of bytes. */
+
+ /* Verify UVC header. Header length is always 12 */
+ if (data[0] != 12 || len < 12) {
+ PDEBUG(D_PACK, "bad header");
+ goto discard;
+ }
+
+ /* Check errors */
+ if (data[1] & UVC_STREAM_ERR) {
+ PDEBUG(D_PACK, "payload error");
+ goto discard;
+ }
+
+ /* Extract PTS and FID */
+ if (!(data[1] & UVC_STREAM_PTS)) {
+ PDEBUG(D_PACK, "PTS not present");
+ goto discard;
+ }
+ this_pts = (data[5] << 24) | (data[4] << 16) | (data[3] << 8) | data[2];
+ this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0;
+
+ /* If PTS or FID has changed, start a new frame. */
+ if (this_pts != sd->last_pts || this_fid != sd->last_fid) {
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
+ sd->last_pts = this_pts;
+ sd->last_fid = this_fid;
+ }
+
+ /* Add the data from this payload */
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data + 12, len - 12);
+
+ /* If this packet is marked as EOF, end the frame */
+ if (data[1] & UVC_STREAM_EOF) {
+ sd->last_pts = 0;
+
+ if ((frame->data_end - frame->data) !=
+ (gspca_dev->width * gspca_dev->height * 2)) {
+ PDEBUG(D_PACK, "short frame");
+ goto discard;
+ }
+
+ gspca_frame_add(gspca_dev, LAST_PACKET, frame, NULL, 0);
+ }
+
+ /* Done this payload */
+ goto scan_next;
+
+discard:
+ /* Discard data until a new frame starts. */
+ gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0);
+ goto scan_next;
+}
+
+/* get stream parameters (framerate) */
+static int sd_get_streamparm(struct gspca_dev *gspca_dev,
+ struct v4l2_streamparm *parm)
+{
+ struct v4l2_captureparm *cp = &parm->parm.capture;
+ struct v4l2_fract *tpf = &cp->timeperframe;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ cp->capability |= V4L2_CAP_TIMEPERFRAME;
+ tpf->numerator = 1;
+ tpf->denominator = sd->frame_rate;
+
+ return 0;
+}
+
+/* set stream parameters (framerate) */
+static int sd_set_streamparm(struct gspca_dev *gspca_dev,
+ struct v4l2_streamparm *parm)
+{
+ struct v4l2_captureparm *cp = &parm->parm.capture;
+ struct v4l2_fract *tpf = &cp->timeperframe;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* Set requested framerate */
+ sd->frame_rate = tpf->denominator / tpf->numerator;
+ ov534_set_frame_rate(gspca_dev);
+
+ /* Return the actual framerate */
+ tpf->numerator = 1;
+ tpf->denominator = sd->frame_rate;
+
+ return 0;
}
/* sub-driver description */
@@ -453,6 +550,8 @@ static const struct sd_desc sd_desc = {
.start = sd_start,
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
+ .get_streamparm = sd_get_streamparm,
+ .set_streamparm = sd_set_streamparm,
};
/* -- module initialisation -- */
@@ -500,6 +599,3 @@ static void __exit sd_mod_exit(void)
module_init(sd_mod_init);
module_exit(sd_mod_exit);
-
-module_param(frame_rate, int, 0644);
-MODULE_PARM_DESC(frame_rate, "Frame rate (15, 30, 40, 50)");
diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c
index 39473e6b9..c90ac852b 100644
--- a/linux/drivers/media/video/gspca/pac207.c
+++ b/linux/drivers/media/video/gspca/pac207.c
@@ -1,7 +1,7 @@
/*
* Pixart PAC207BCA library
*
- * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+ * Copyright (C) 2008 Hans de Goede <hdgoede@redhat.com>
* Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
* Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
*
@@ -27,7 +27,7 @@
#include "gspca.h"
-MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
MODULE_DESCRIPTION("Pixart PAC207");
MODULE_LICENSE("GPL");
@@ -149,7 +149,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
{176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
.bytesperline = 176,
.sizeimage = (176 + 2) * 144,
@@ -529,6 +529,7 @@ static const struct sd_desc sd_desc = {
static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x4028)},
{USB_DEVICE(0x093a, 0x2460)},
+ {USB_DEVICE(0x093a, 0x2461)},
{USB_DEVICE(0x093a, 0x2463)},
{USB_DEVICE(0x093a, 0x2464)},
{USB_DEVICE(0x093a, 0x2468)},
diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c
index f443df77e..83ab0df0e 100644
--- a/linux/drivers/media/video/gspca/pac7311.c
+++ b/linux/drivers/media/video/gspca/pac7311.c
@@ -226,7 +226,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120 * 3 / 8 + 590,
@@ -1078,10 +1078,13 @@ static __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
{USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
{USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x2620), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
+ {USB_DEVICE(0x093a, 0x2622), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},
+ {USB_DEVICE(0x093a, 0x262c), .driver_info = SENSOR_PAC7302},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/linux/drivers/media/video/gspca/sonixb.c b/linux/drivers/media/video/gspca/sonixb.c
index 5ca8ab780..75b44b362 100644
--- a/linux/drivers/media/video/gspca/sonixb.c
+++ b/linux/drivers/media/video/gspca/sonixb.c
@@ -227,7 +227,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120,
@@ -249,7 +249,7 @@ static struct v4l2_pix_format vga_mode[] = {
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0},
};
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
{160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120,
diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c
index 182b84f1c..217db0d88 100644
--- a/linux/drivers/media/video/gspca/sonixj.c
+++ b/linux/drivers/media/video/gspca/sonixj.c
@@ -37,24 +37,26 @@ struct sd {
atomic_t avg_lum;
unsigned int exposure;
- unsigned short brightness;
- unsigned char contrast;
- unsigned char colors;
- unsigned char autogain;
+ __u16 brightness;
+ __u8 contrast;
+ __u8 colors;
+ __u8 autogain;
+ __u8 blue;
+ __u8 red;
__u8 vflip; /* ov7630 only */
__u8 infrared; /* mi0360 only */
- signed char ag_cnt;
+ __s8 ag_cnt;
#define AG_CNT_START 13
- char qindex;
- unsigned char bridge;
+ __u8 qindex;
+ __u8 bridge;
#define BRIDGE_SN9C102P 0
#define BRIDGE_SN9C105 1
#define BRIDGE_SN9C110 2
#define BRIDGE_SN9C120 3
#define BRIDGE_SN9C325 4
- char sensor; /* Type of image sensor chip */
+ __u8 sensor; /* Type of image sensor chip */
#define SENSOR_HV7131R 0
#define SENSOR_MI0360 1
#define SENSOR_MO4000 2
@@ -62,7 +64,7 @@ struct sd {
#define SENSOR_OV7630 4
#define SENSOR_OV7648 5
#define SENSOR_OV7660 6
- unsigned char i2c_base;
+ __u8 i2c_base;
};
/* V4L2 controls supported by the driver */
@@ -72,6 +74,10 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
@@ -89,7 +95,7 @@ static struct ctrl sd_ctrls[] = {
#define BRIGHTNESS_MAX 0xffff
.maximum = BRIGHTNESS_MAX,
.step = 1,
-#define BRIGHTNESS_DEF 0x7fff
+#define BRIGHTNESS_DEF 0x8000
.default_value = BRIGHTNESS_DEF,
},
.set = sd_setbrightness,
@@ -116,7 +122,7 @@ static struct ctrl sd_ctrls[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Color",
.minimum = 0,
- .maximum = 64,
+ .maximum = 40,
.step = 1,
#define COLOR_DEF 32
.default_value = COLOR_DEF,
@@ -124,7 +130,35 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setcolors,
.get = sd_getcolors,
},
-#define AUTOGAIN_IDX 3
+ {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+ .minimum = 24,
+ .maximum = 40,
+ .step = 1,
+#define BLUE_BALANCE_DEF 32
+ .default_value = BLUE_BALANCE_DEF,
+ },
+ .set = sd_setblue_balance,
+ .get = sd_getblue_balance,
+ },
+ {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+ .minimum = 24,
+ .maximum = 40,
+ .step = 1,
+#define RED_BALANCE_DEF 32
+ .default_value = RED_BALANCE_DEF,
+ },
+ .set = sd_setred_balance,
+ .get = sd_getred_balance,
+ },
+#define AUTOGAIN_IDX 5
{
{
.id = V4L2_CID_AUTOGAIN,
@@ -140,7 +174,7 @@ static struct ctrl sd_ctrls[] = {
.get = sd_getautogain,
},
/* ov7630 only */
-#define VFLIP_IDX 4
+#define VFLIP_IDX 6
{
{
.id = V4L2_CID_VFLIP,
@@ -156,7 +190,7 @@ static struct ctrl sd_ctrls[] = {
.get = sd_getvflip,
},
/* mi0360 only */
-#define INFRARED_IDX 5
+#define INFRARED_IDX 7
{
{
.id = V4L2_CID_INFRARED,
@@ -173,7 +207,25 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+/* table of the disabled controls */
+static __u32 ctrl_dis[] = {
+ (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+ /* SENSOR_HV7131R 0 */
+ (1 << VFLIP_IDX),
+ /* SENSOR_MI0360 1 */
+ (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+ /* SENSOR_MO4000 2 */
+ (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+ /* SENSOR_OM6802 3 */
+ (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX),
+ /* SENSOR_OV7630 4 */
+ (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+ /* SENSOR_OV7648 5 */
+ (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+ /* SENSOR_OV7660 6 */
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120 * 4 / 8 + 590,
@@ -767,8 +819,6 @@ static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg)
static int probesensor(struct gspca_dev *gspca_dev)
{
- struct sd *sd = (struct sd *) gspca_dev;
-
i2c_w1(gspca_dev, 0x02, 0); /* sensor wakeup */
msleep(10);
reg_w1(gspca_dev, 0x02, 0x66); /* Gpio on */
@@ -780,8 +830,7 @@ static int probesensor(struct gspca_dev *gspca_dev)
&& gspca_dev->usb_buf[3] == 0x00
&& gspca_dev->usb_buf[4] == 0x00) {
PDEBUG(D_PROBE, "Find Sensor sn9c102P HV7131R");
- sd->sensor = SENSOR_HV7131R;
- return SENSOR_HV7131R;
+ return 0;
}
PDEBUG(D_PROBE, "Find Sensor 0x%02x 0x%02x 0x%02x",
gspca_dev->usb_buf[0], gspca_dev->usb_buf[1],
@@ -989,22 +1038,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
+ sd->blue = BLUE_BALANCE_DEF;
+ sd->red = RED_BALANCE_DEF;
sd->autogain = AUTOGAIN_DEF;
sd->ag_cnt = -1;
sd->vflip = VFLIP_DEF;
sd->infrared = INFRARED_DEF;
- switch (sd->sensor) {
- case SENSOR_OV7630:
- case SENSOR_OV7648:
- case SENSOR_OV7660:
- gspca_dev->ctrl_dis = (1 << AUTOGAIN_IDX);
- break;
- }
- if (sd->sensor != SENSOR_OV7630)
- gspca_dev->ctrl_dis |= (1 << VFLIP_IDX);
- if (sd->sensor != SENSOR_MI0360)
- gspca_dev->ctrl_dis |= (1 << INFRARED_IDX);
+ gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
return 0;
}
@@ -1012,7 +1053,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
-/* const __u8 *sn9c1xx; */
__u8 regGpio[] = { 0x29, 0x74 };
__u8 regF1;
@@ -1051,12 +1091,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0xf1, 0x01);
-#if 1 /*jfm: from win trace*/
return 0;
-#else
- sn9c1xx = sn_tb[(int) sd->sensor];
- return configure_gpio(gspca_dev, sn9c1xx);
-#endif
}
static unsigned int setexposure(struct gspca_dev *gspca_dev,
@@ -1136,32 +1171,13 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
return expo;
}
-/* this function is used for sensors o76xx only */
-static void setbrightcont(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int val;
- __u8 reg84_full[0x15];
-
- memcpy(reg84_full, reg84, sizeof reg84_full);
- val = sd->contrast * 0x30 / CONTRAST_MAX + 0x10; /* 10..40 */
- reg84_full[0] = (val + 1) / 2; /* red */
- reg84_full[2] = val; /* green */
- reg84_full[4] = (val + 1) / 5; /* blue */
- val = (sd->brightness - BRIGHTNESS_DEF) * 0x10
- / BRIGHTNESS_MAX;
- reg84_full[0x12] = val & 0x1f; /* 5:0 signed value */
- reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full);
-}
-
-/* sensor != ov76xx */
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
unsigned int expo;
__u8 k2;
- k2 = sd->brightness >> 10;
+ k2 = ((int) sd->brightness - 0x8000) >> 10;
switch (sd->sensor) {
case SENSOR_HV7131R:
expo = sd->brightness << 4;
@@ -1183,38 +1199,49 @@ static void setbrightness(struct gspca_dev *gspca_dev)
break;
}
- reg_w1(gspca_dev, 0x96, k2);
+ reg_w1(gspca_dev, 0x96, k2); /* color matrix Y offset */
}
-/* sensor != ov76xx */
static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u8 k2;
- __u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 };
-
- k2 = sd->contrast;
- contrast[2] = k2;
- contrast[0] = (k2 + 1) >> 1;
- contrast[4] = (k2 + 1) / 5;
- reg_w(gspca_dev, 0x84, contrast, 6);
+ __u8 contrast[6];
+
+ k2 = sd->contrast * 0x30 / (CONTRAST_MAX + 1) + 0x10; /* 10..40 */
+ contrast[0] = (k2 + 1) / 2; /* red */
+ contrast[1] = 0;
+ contrast[2] = k2; /* green */
+ contrast[3] = 0;
+ contrast[4] = (k2 + 1) / 5; /* blue */
+ contrast[5] = 0;
+ reg_w(gspca_dev, 0x84, contrast, sizeof contrast);
}
static void setcolors(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 blue, red;
-
- if (sd->colors >= 32) {
- red = 32 + (sd->colors - 32) / 2;
- blue = 64 - sd->colors;
- } else {
- red = sd->colors;
- blue = 32 + (32 - sd->colors) / 2;
+ int i, v;
+ __u8 reg8a[12]; /* U & V gains */
+ static __s16 uv[6] = { /* same as reg84 in signed decimal */
+ -24, -38, 64, /* UR UG UB */
+ 62, -51, -9 /* VR VG VB */
+ };
+ for (i = 0; i < 6; i++) {
+ v = uv[i] * sd->colors / COLOR_DEF;
+ reg8a[i * 2] = v;
+ reg8a[i * 2 + 1] = (v >> 8) & 0x0f;
}
- reg_w1(gspca_dev, 0x05, red);
+ reg_w(gspca_dev, 0x8a, reg8a, sizeof reg8a);
+}
+
+static void setredblue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w1(gspca_dev, 0x05, sd->red);
/* reg_w1(gspca_dev, 0x07, 32); */
- reg_w1(gspca_dev, 0x06, blue);
+ reg_w1(gspca_dev, 0x06, sd->blue);
}
static void setautogain(struct gspca_dev *gspca_dev)
@@ -1300,9 +1327,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
reg_w1(gspca_dev, 0x17, reg17);
/* set reg1 was here */
- reg_w1(gspca_dev, 0x05, sn9c1xx[5]);
- reg_w1(gspca_dev, 0x07, sn9c1xx[7]);
- reg_w1(gspca_dev, 0x06, sn9c1xx[6]);
+ reg_w1(gspca_dev, 0x05, sn9c1xx[5]); /* red */
+ reg_w1(gspca_dev, 0x07, sn9c1xx[7]); /* green */
+ reg_w1(gspca_dev, 0x06, sn9c1xx[6]); /* blue */
reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]);
reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def);
for (i = 0; i < 8; i++)
@@ -1361,27 +1388,19 @@ static int sd_start(struct gspca_dev *gspca_dev)
ov7648_InitSensor(gspca_dev);
reg17 = 0x21;
/* reg1 = 0x42; * 42 - 46? */
-/* if (mode)
- ; * 320x2...
- else
- ; * 640x... */
break;
default:
/* case SENSOR_OV7660: */
ov7660_InitSensor(gspca_dev);
- if (mode) {
-/* reg17 = 0x21; * 320 */
-/* reg1 = 0x44; */
-/* reg1 = 0x46; (done) */
- } else { /* 640 */
- if (sd->bridge == BRIDGE_SN9C120) {
+ if (sd->bridge == BRIDGE_SN9C120) {
+ if (mode) { /* 320x240 - 160x120 */
reg17 = 0xa2;
reg1 = 0x44; /* 48 Mhz, video trf eneble */
- } else {
- reg17 = 0x22;
- reg1 = 0x06; /* 24 Mhz, video trf eneble
- * inverse power down */
}
+ } else {
+ reg17 = 0x22;
+ reg1 = 0x06; /* 24 Mhz, video trf eneble
+ * inverse power down */
}
break;
}
@@ -1413,20 +1432,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
case SENSOR_MI0360:
setinfrared(sd);
- /* fall thru */
- case SENSOR_HV7131R:
- case SENSOR_MO4000:
- case SENSOR_OM6802:
- setbrightness(gspca_dev);
- setcontrast(gspca_dev);
break;
case SENSOR_OV7630:
setvflip(sd);
- /* fall thru */
- default: /* OV76xx */
- setbrightcont(gspca_dev);
break;
}
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
setautogain(gspca_dev);
return 0;
}
@@ -1510,7 +1522,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
expotimes = 0;
sd->exposure = setexposure(gspca_dev,
(unsigned int) expotimes);
- setcolors(gspca_dev);
+ setredblue(gspca_dev);
break;
}
}
@@ -1564,19 +1576,8 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
sd->brightness = val;
- if (gspca_dev->streaming) {
- switch (sd->sensor) {
- case SENSOR_HV7131R:
- case SENSOR_MI0360:
- case SENSOR_MO4000:
- case SENSOR_OM6802:
- setbrightness(gspca_dev);
- break;
- default: /* OV76xx */
- setbrightcont(gspca_dev);
- break;
- }
- }
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
return 0;
}
@@ -1593,19 +1594,8 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
sd->contrast = val;
- if (gspca_dev->streaming) {
- switch (sd->sensor) {
- case SENSOR_HV7131R:
- case SENSOR_MI0360:
- case SENSOR_MO4000:
- case SENSOR_OM6802:
- setcontrast(gspca_dev);
- break;
- default: /* OV76xx */
- setbrightcont(gspca_dev);
- break;
- }
- }
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
return 0;
}
@@ -1635,6 +1625,42 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->blue = val;
+ if (gspca_dev->streaming)
+ setredblue(gspca_dev);
+ return 0;
+}
+
+static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->blue;
+ return 0;
+}
+
+static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->red = val;
+ if (gspca_dev->streaming)
+ setredblue(gspca_dev);
+ return 0;
+}
+
+static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->red;
+ return 0;
+}
+
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1719,6 +1745,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
#endif
{USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)},
{USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)},
+ {USB_DEVICE(0x06f8, 0x3004), BSI(SN9C105, OV7660, 0x21)},
{USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)},
/* bw600.inf:
{USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */
diff --git a/linux/drivers/media/video/gspca/spca500.c b/linux/drivers/media/video/gspca/spca500.c
index 2e1c5e50e..6b4865280 100644
--- a/linux/drivers/media/video/gspca/spca500.c
+++ b/linux/drivers/media/video/gspca/spca500.c
@@ -111,7 +111,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -124,7 +124,7 @@ static struct v4l2_pix_format vga_mode[] = {
.priv = 0},
};
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 176,
.sizeimage = 176 * 144 * 3 / 8 + 590,
diff --git a/linux/drivers/media/video/gspca/spca501.c b/linux/drivers/media/video/gspca/spca501.c
index 17dab9859..609459321 100644
--- a/linux/drivers/media/video/gspca/spca501.c
+++ b/linux/drivers/media/video/gspca/spca501.c
@@ -132,7 +132,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120 * 3 / 2,
diff --git a/linux/drivers/media/video/gspca/spca505.c b/linux/drivers/media/video/gspca/spca505.c
index c52598e94..854ed1ff5 100644
--- a/linux/drivers/media/video/gspca/spca505.c
+++ b/linux/drivers/media/video/gspca/spca505.c
@@ -59,7 +59,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120 * 3 / 2,
diff --git a/linux/drivers/media/video/gspca/spca506.c b/linux/drivers/media/video/gspca/spca506.c
index 645ee9d44..96e2512e0 100644
--- a/linux/drivers/media/video/gspca/spca506.c
+++ b/linux/drivers/media/video/gspca/spca506.c
@@ -110,7 +110,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120 * 3 / 2,
diff --git a/linux/drivers/media/video/gspca/spca508.c b/linux/drivers/media/video/gspca/spca508.c
index c9360cdb8..698d4ed95 100644
--- a/linux/drivers/media/video/gspca/spca508.c
+++ b/linux/drivers/media/video/gspca/spca508.c
@@ -62,7 +62,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
{160, 120, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120 * 3 / 2,
diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c
index 4c0046cc7..499511fa0 100644
--- a/linux/drivers/media/video/gspca/spca561.c
+++ b/linux/drivers/media/video/gspca/spca561.c
@@ -32,22 +32,22 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- __u16 contrast; /* rev72a only */
-#define CONTRAST_MIN 0x0000
-#define CONTRAST_DEF 0x2000
-#define CONTRAST_MAX 0x3fff
-
__u16 exposure; /* rev12a only */
#define EXPOSURE_MIN 1
#define EXPOSURE_DEF 200
#define EXPOSURE_MAX (4095 - 900) /* see set_exposure */
+ __u8 contrast; /* rev72a only */
+#define CONTRAST_MIN 0x00
+#define CONTRAST_DEF 0x20
+#define CONTRAST_MAX 0x3f
+
__u8 brightness; /* rev72a only */
#define BRIGHTNESS_MIN 0
-#define BRIGHTNESS_DEF 32
-#define BRIGHTNESS_MAX 63
+#define BRIGHTNESS_DEF 0x20
+#define BRIGHTNESS_MAX 0x3f
- __u8 white; /* rev12a only */
+ __u8 white;
#define WHITE_MIN 1
#define WHITE_DEF 0x40
#define WHITE_MAX 0x7f
@@ -73,7 +73,7 @@ struct sd {
#define AG_CNT_START 13
};
-static struct v4l2_pix_format sif_012a_mode[] = {
+static const struct v4l2_pix_format sif_012a_mode[] = {
{160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120,
@@ -96,7 +96,7 @@ static struct v4l2_pix_format sif_012a_mode[] = {
.priv = 0},
};
-static struct v4l2_pix_format sif_072a_mode[] = {
+static const struct v4l2_pix_format sif_072a_mode[] = {
{160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120,
@@ -146,98 +146,7 @@ static struct v4l2_pix_format sif_072a_mode[] = {
#define SPCA561_SNAPBIT 0x20
#define SPCA561_SNAPCTRL 0x40
-static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
-{
- int ret;
-
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- 0, /* request */
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value, index, NULL, 0, 500);
- PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
- if (ret < 0)
- PDEBUG(D_ERR, "reg write: error %d", ret);
-}
-
-static void write_vector(struct gspca_dev *gspca_dev,
- const __u16 data[][2])
-{
- struct usb_device *dev = gspca_dev->dev;
- int i;
-
- i = 0;
- while (data[i][1] != 0) {
- reg_w_val(dev, data[i][1], data[i][0]);
- i++;
- }
-}
-
-/* read 'len' bytes to gspca_dev->usb_buf */
-static void reg_r(struct gspca_dev *gspca_dev,
- __u16 index, __u16 length)
-{
- usb_control_msg(gspca_dev->dev,
- usb_rcvctrlpipe(gspca_dev->dev, 0),
- 0, /* request */
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, /* value */
- index, gspca_dev->usb_buf, length, 500);
-}
-
-static void reg_w_buf(struct gspca_dev *gspca_dev,
- __u16 index, const __u8 *buffer, __u16 len)
-{
- memcpy(gspca_dev->usb_buf, buffer, len);
- usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- 0, /* request */
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, /* value */
- index, gspca_dev->usb_buf, len, 500);
-}
-
-static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
-{
- int retry = 60;
- __u8 DataLow;
- __u8 DataHight;
-
- DataLow = valeur;
- DataHight = valeur >> 8;
- reg_w_val(gspca_dev->dev, 0x8801, reg);
- reg_w_val(gspca_dev->dev, 0x8805, DataLow);
- reg_w_val(gspca_dev->dev, 0x8800, DataHight);
- while (retry--) {
- reg_r(gspca_dev, 0x8803, 1);
- if (!gspca_dev->usb_buf[0])
- break;
- }
-}
-
-static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
-{
- int retry = 60;
- __u8 value;
- __u8 vallsb;
-
- reg_w_val(gspca_dev->dev, 0x8804, 0x92);
- reg_w_val(gspca_dev->dev, 0x8801, reg);
- reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01));
- do {
- reg_r(gspca_dev, 0x8803, 1);
- if (!gspca_dev->usb_buf[0])
- break;
- } while (--retry);
- if (retry == 0)
- return -1;
- reg_r(gspca_dev, 0x8800, 1);
- value = gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8805, 1);
- vallsb = gspca_dev->usb_buf[0];
- return ((int) value << 8) | vallsb;
-}
-
-static const __u16 spca561_init_data[][2] = {
+static const __u16 rev72a_init_data1[][2] = {
{0x0000, 0x8114}, /* Software GPIO output data */
{0x0001, 0x8114}, /* Software GPIO output data */
{0x0000, 0x8112}, /* Some kind of reset */
@@ -247,44 +156,26 @@ static const __u16 spca561_init_data[][2] = {
{0x0001, 0x8118}, /* Conf sensor */
{0x0092, 0x8804}, /* I know nothing about these */
{0x0010, 0x8802}, /* 0x88xx registers, so I won't */
- /***************/
{0x000d, 0x8805}, /* sensor default setting */
- {0x0001, 0x8801}, /* 1 <- 0x0d */
- {0x0000, 0x8800},
- {0x0018, 0x8805},
- {0x0002, 0x8801}, /* 2 <- 0x18 */
- {0x0000, 0x8800},
- {0x0065, 0x8805},
- {0x0004, 0x8801}, /* 4 <- 0x01 0x65 */
- {0x0001, 0x8800},
- {0x0021, 0x8805},
- {0x0005, 0x8801}, /* 5 <- 0x21 */
- {0x0000, 0x8800},
- {0x00aa, 0x8805},
- {0x0007, 0x8801}, /* 7 <- 0xaa */
- {0x0000, 0x8800},
- {0x0004, 0x8805},
- {0x0020, 0x8801}, /* 0x20 <- 0x15 0x04 */
- {0x0015, 0x8800},
- {0x0002, 0x8805},
- {0x0039, 0x8801}, /* 0x39 <- 0x02 */
- {0x0000, 0x8800},
- {0x0010, 0x8805},
- {0x0035, 0x8801}, /* 0x35 <- 0x10 */
- {0x0000, 0x8800},
- {0x0049, 0x8805},
- {0x0009, 0x8801}, /* 0x09 <- 0x10 0x49 */
- {0x0010, 0x8800},
- {0x000b, 0x8805},
- {0x0028, 0x8801}, /* 0x28 <- 0x0b */
- {0x0000, 0x8800},
- {0x000f, 0x8805},
- {0x003b, 0x8801}, /* 0x3b <- 0x0f */
- {0x0000, 0x8800},
- {0x0000, 0x8805},
- {0x003c, 0x8801}, /* 0x3c <- 0x00 */
- {0x0000, 0x8800},
- /***************/
+ {}
+};
+static const __u16 rev72a_init_sensor1[][2] = {
+ /* ms-win values */
+ {0x0001, 0x0018}, /* 0x01 <- 0x0d */
+ {0x0002, 0x0065}, /* 0x02 <- 0x18 */
+ {0x0004, 0x0121}, /* 0x04 <- 0x0165 */
+ {0x0005, 0x00aa}, /* 0x05 <- 0x21 */
+ {0x0007, 0x0004}, /* 0x07 <- 0xaa */
+ {0x0020, 0x1502}, /* 0x20 <- 0x1504 */
+ {0x0039, 0x0010}, /* 0x39 <- 0x02 */
+ {0x0035, 0x0049}, /* 0x35 <- 0x10 */
+ {0x0009, 0x100b}, /* 0x09 <- 0x1049 */
+ {0x0028, 0x000f}, /* 0x28 <- 0x0b */
+ {0x003b, 0x003c}, /* 0x3b <- 0x0f */
+ {0x003c, 0x0000}, /* 0x3c <- 0x00 */
+ {}
+};
+static const __u16 rev72a_init_data2[][2] = {
{0x0018, 0x8601}, /* Pixel/line selection for color separation */
{0x0000, 0x8602}, /* Optical black level for user setting */
{0x0060, 0x8604}, /* Optical black horizontal offset */
@@ -309,10 +200,18 @@ static const __u16 spca561_init_data[][2] = {
{0x0004, 0x8612}, /* Gr offset for white balance */
{0x0007, 0x8613}, /* B offset for white balance */
{0x0000, 0x8614}, /* Gb offset for white balance */
+#if 1
+/* from ms-win */
+ {0x0035, 0x8651}, /* R gain for white balance */
+ {0x0040, 0x8652}, /* Gr gain for white balance */
+ {0x005f, 0x8653}, /* B gain for white balance */
+ {0x0040, 0x8654}, /* Gb gain for white balance */
+#else
{0x008c, 0x8651}, /* R gain for white balance */
{0x008c, 0x8652}, /* Gr gain for white balance */
{0x00b5, 0x8653}, /* B gain for white balance */
{0x008c, 0x8654}, /* Gb gain for white balance */
+#endif
{0x0002, 0x8502}, /* Maximum average bit rate stuff */
{0x0011, 0x8802},
@@ -324,29 +223,22 @@ static const __u16 spca561_init_data[][2] = {
{0x0002, 0x865b}, /* Horizontal offset for valid pixels */
{0x0003, 0x865c}, /* Vertical offset for valid lines */
- /***************//* sensor active */
- {0x0003, 0x8801}, /* 0x03 <- 0x01 0x21 //289 */
- {0x0021, 0x8805},
- {0x0001, 0x8800},
- {0x0004, 0x8801}, /* 0x04 <- 0x01 0x65 //357 */
- {0x0065, 0x8805},
- {0x0001, 0x8800},
- {0x0005, 0x8801}, /* 0x05 <- 0x2f */
- {0x002f, 0x8805},
- {0x0000, 0x8800},
- {0x0006, 0x8801}, /* 0x06 <- 0 */
- {0x0000, 0x8805},
- {0x0000, 0x8800},
- {0x000a, 0x8801}, /* 0x0a <- 2 */
- {0x0002, 0x8805},
- {0x0000, 0x8800},
- {0x0009, 0x8801}, /* 0x09 <- 0x1061 */
- {0x0061, 0x8805},
- {0x0010, 0x8800},
- {0x0035, 0x8801}, /* 0x35 <-0x14 */
- {0x0014, 0x8805},
- {0x0000, 0x8800},
+ {}
+};
+static const __u16 rev72a_init_sensor2[][2] = {
+ /* ms-win values */
+ {0x0003, 0x0121}, /* 0x03 <- 0x01 0x21 //289 */
+ {0x0004, 0x0165}, /* 0x04 <- 0x01 0x65 //357 */
+ {0x0005, 0x002f}, /* 0x05 <- 0x2f */
+ {0x0006, 0x0000}, /* 0x06 <- 0 */
+ {0x000a, 0x0002}, /* 0x0a <- 2 */
+ {0x0009, 0x1061}, /* 0x09 <- 0x1061 */
+ {0x0035, 0x0014}, /* 0x35 <- 0x14 */
+ {}
+};
+static const __u16 rev72a_init_data3[][2] = {
{0x0030, 0x8112}, /* ISO and drop packet enable */
+/*fixme: should stop here*/
{0x0000, 0x8112}, /* Some kind of reset ???? */
{0x0009, 0x8118}, /* Enable sensor and set standby */
{0x0000, 0x8114}, /* Software GPIO output data */
@@ -434,21 +326,6 @@ static const __u16 spca561_init_data[][2] = {
{}
};
-#if 0
-static void sensor_reset(struct gspca_dev *gspca_dev)
-{
- reg_w_val(gspca_dev->dev, 0x8631, 0xc8);
- reg_w_val(gspca_dev->dev, 0x8634, 0xc8);
- reg_w_val(gspca_dev->dev, 0x8112, 0x00);
- reg_w_val(gspca_dev->dev, 0x8114, 0x00);
- reg_w_val(gspca_dev->dev, 0x8118, 0x21);
- reg_w_val(gspca_dev->dev, 0x8804, 0x92); /* i2c init */
- reg_w_val(gspca_dev->dev, 0x8802, 0x14);
- i2c_write(gspca_dev, 0x0001, 0x0d);
- i2c_write(gspca_dev, 0x0000, 0x0d);
-}
-#endif
-
/******************** QC Express etch2 stuff ********************/
static const __u16 Pb100_1map8300[][2] = {
/* reg, value */
@@ -529,22 +406,112 @@ static const __u16 spca561_161rev12A_data2[][2] = {
{}
};
-static void sensor_mapwrite(struct gspca_dev *gspca_dev,
- const __u16 sensormap[][2])
+static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
+{
+ int ret;
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg write: error %d", ret);
+}
+
+static void write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][2])
{
- int i = 0;
- __u8 usbval[2];
+ struct usb_device *dev = gspca_dev->dev;
+ int i;
- while (sensormap[i][0]) {
- usbval[0] = sensormap[i][1];
- usbval[1] = sensormap[i][1] >> 8;
- reg_w_buf(gspca_dev, sensormap[i][0], usbval, 2);
+ i = 0;
+ while (data[i][1] != 0) {
+ reg_w_val(dev, data[i][1], data[i][0]);
i++;
}
}
+
+/* read 'len' bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+ __u16 index, __u16 length)
+{
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, length, 500);
+}
+
+/* write 'len' bytes from gspca_dev->usb_buf */
+static void reg_w_buf(struct gspca_dev *gspca_dev,
+ __u16 index, __u16 len)
+{
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, len, 500);
+}
+
+static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg)
+{
+ int retry = 60;
+
+ reg_w_val(gspca_dev->dev, 0x8801, reg);
+ reg_w_val(gspca_dev->dev, 0x8805, value);
+ reg_w_val(gspca_dev->dev, 0x8800, value >> 8);
+ do {
+ reg_r(gspca_dev, 0x8803, 1);
+ if (!gspca_dev->usb_buf[0])
+ return;
+ } while (--retry);
+}
+
+static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
+{
+ int retry = 60;
+ __u8 value;
+
+ reg_w_val(gspca_dev->dev, 0x8804, 0x92);
+ reg_w_val(gspca_dev->dev, 0x8801, reg);
+ reg_w_val(gspca_dev->dev, 0x8802, mode | 0x01);
+ do {
+ reg_r(gspca_dev, 0x8803, 1);
+ if (!gspca_dev->usb_buf[0]) {
+ reg_r(gspca_dev, 0x8800, 1);
+ value = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8805, 1);
+ return ((int) value << 8) | gspca_dev->usb_buf[0];
+ }
+ } while (--retry);
+ return -1;
+}
+
+static void sensor_mapwrite(struct gspca_dev *gspca_dev,
+ const __u16 (*sensormap)[2])
+{
+ while ((*sensormap)[0]) {
+ gspca_dev->usb_buf[0] = (*sensormap)[1];
+ gspca_dev->usb_buf[1] = (*sensormap)[1] >> 8;
+ reg_w_buf(gspca_dev, (*sensormap)[0], 2);
+ sensormap++;
+ }
+}
+
+static void write_sensor_72a(struct gspca_dev *gspca_dev,
+ const __u16 (*sensor)[2])
+{
+ while ((*sensor)[0]) {
+ i2c_write(gspca_dev, (*sensor)[1], (*sensor)[0]);
+ sensor++;
+ }
+}
+
static void init_161rev12A(struct gspca_dev *gspca_dev)
{
-/* sensor_reset(gspca_dev); (not in win) */
write_vector(gspca_dev, spca561_161rev12A_data1);
sensor_mapwrite(gspca_dev, Pb100_1map8300);
/*fixme: should be in sd_start*/
@@ -612,49 +579,68 @@ static int sd_init_12a(struct gspca_dev *gspca_dev)
static int sd_init_72a(struct gspca_dev *gspca_dev)
{
PDEBUG(D_STREAM, "Chip revision: 072a");
- write_vector(gspca_dev, spca561_init_data);
+ write_vector(gspca_dev, rev72a_init_data1);
+ write_sensor_72a(gspca_dev, rev72a_init_sensor1);
+ write_vector(gspca_dev, rev72a_init_data2);
+ write_sensor_72a(gspca_dev, rev72a_init_sensor2);
+ write_vector(gspca_dev, rev72a_init_data3);
return 0;
}
-static void setcontrast(struct gspca_dev *gspca_dev)
+/* rev 72a only */
+static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
- __u8 lowb;
+ __u8 value;
- switch (sd->chip_revision) {
- case Rev072A:
- lowb = sd->contrast >> 8;
- reg_w_val(dev, 0x8651, lowb);
- reg_w_val(dev, 0x8652, lowb);
- reg_w_val(dev, 0x8653, lowb);
- reg_w_val(dev, 0x8654, lowb);
- break;
- default: {
-/* case Rev012A: { */
- static const __u8 Reg8391[] =
- { 0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00 };
+ value = sd->brightness;
- reg_w_buf(gspca_dev, 0x8391, Reg8391, 8);
- reg_w_buf(gspca_dev, 0x8390, Reg8391, 8);
- break;
- }
- }
+ /* offsets for white balance */
+ reg_w_val(dev, 0x8611, value); /* R */
+ reg_w_val(dev, 0x8612, value); /* Gr */
+ reg_w_val(dev, 0x8613, value); /* B */
+ reg_w_val(dev, 0x8614, value); /* Gb */
}
-/* rev12a only */
static void setwhite(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u16 white;
- __u8 reg8614, reg8616;
+ __u8 blue, red;
+ __u16 reg;
- white = sd->white;
/* try to emulate MS-win as possible */
- reg8616 = 0x90 - white * 5 / 8;
- reg_w_val(gspca_dev->dev, 0x8616, reg8616);
- reg8614 = 0x20 + white * 3 / 8;
- reg_w_val(gspca_dev->dev, 0x8614, reg8614);
+ white = sd->white;
+ red = 0x20 + white * 3 / 8;
+ blue = 0x90 - white * 5 / 8;
+ if (sd->chip_revision == Rev012A) {
+ reg = 0x8614;
+ } else {
+ reg = 0x8651;
+ red += sd->contrast - 0x20;
+ blue += sd->contrast - 0x20;
+ }
+ reg_w_val(gspca_dev->dev, reg, red);
+ reg_w_val(gspca_dev->dev, reg + 2, blue);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 value;
+
+ if (sd->chip_revision != Rev072A)
+ return;
+ value = sd->contrast + 0x20;
+
+ /* gains for white balance */
+ setwhite(gspca_dev);
+/* reg_w_val(dev, 0x8651, value); * R - done by setwhite */
+ reg_w_val(dev, 0x8652, value); /* Gr */
+/* reg_w_val(dev, 0x8653, value); * B - done by setwhite */
+ reg_w_val(dev, 0x8654, value); /* Gb */
}
/* rev 12a only */
@@ -663,7 +649,6 @@ static void setexposure(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int expo;
int clock_divider;
- __u8 data[2];
/* Register 0x8309 controls exposure for the spca561,
the basic exposure setting goes from 1-2047, where 1 is completely
@@ -687,20 +672,19 @@ static void setexposure(struct gspca_dev *gspca_dev)
clock_divider = 3;
}
expo |= clock_divider << 11;
- data[0] = expo;
- data[1] = expo >> 8;
- reg_w_buf(gspca_dev, 0x8309, data, 2);
+ gspca_dev->usb_buf[0] = expo;
+ gspca_dev->usb_buf[1] = expo >> 8;
+ reg_w_buf(gspca_dev, 0x8309, 2);
}
/* rev 12a only */
static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 data[2];
- data[0] = sd->gain;
- data[1] = 0;
- reg_w_buf(gspca_dev, 0x8335, data, 2);
+ gspca_dev->usb_buf[0] = sd->gain;
+ gspca_dev->usb_buf[1] = 0;
+ reg_w_buf(gspca_dev, 0x8335, 2);
}
static void setautogain(struct gspca_dev *gspca_dev)
@@ -716,9 +700,9 @@ static void setautogain(struct gspca_dev *gspca_dev)
static int sd_start_12a(struct gspca_dev *gspca_dev)
{
struct usb_device *dev = gspca_dev->dev;
- int Clck = 0x8a; /* lower 0x8X values lead to fps > 30 */
- __u8 Reg8307[] = { 0xaa, 0x00 };
int mode;
+ static const __u8 Reg8391[8] =
+ {0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00};
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
if (mode <= 1) {
@@ -730,14 +714,21 @@ static int sd_start_12a(struct gspca_dev *gspca_dev)
* is sufficient to push raw frames at ~20fps */
reg_w_val(dev, 0x8500, mode);
} /* -- qq@kuku.eu.org */
- reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
- reg_w_val(gspca_dev->dev, 0x8700, Clck);
+
+ gspca_dev->usb_buf[0] = 0xaa;
+ gspca_dev->usb_buf[1] = 0x00;
+ reg_w_buf(gspca_dev, 0x8307, 2);
+ /* clock - lower 0x8X values lead to fps > 30 */
+ reg_w_val(gspca_dev->dev, 0x8700, 0x8a);
/* 0x8f 0x85 0x27 clock */
reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
reg_w_val(gspca_dev->dev, 0x850b, 0x03);
- setcontrast(gspca_dev);
+ memcpy(gspca_dev->usb_buf, Reg8391, 8);
+ reg_w_buf(gspca_dev, 0x8391, 8);
+ reg_w_buf(gspca_dev, 0x8390, 8);
setwhite(gspca_dev);
setautogain(gspca_dev);
+/* setgain(gspca_dev); */
setexposure(gspca_dev);
return 0;
}
@@ -764,6 +755,9 @@ static int sd_start_72a(struct gspca_dev *gspca_dev)
reg_w_val(dev, 0x8500, mode); /* mode */
reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
reg_w_val(dev, 0x8112, 0x10 | 0x20);
+ setcontrast(gspca_dev);
+/* setbrightness(gspca_dev); * fixme: bad values */
+ setwhite(gspca_dev);
setautogain(gspca_dev);
return 0;
}
@@ -805,7 +799,6 @@ static void do_autogain(struct gspca_dev *gspca_dev)
__u8 luma_mean = 110;
__u8 luma_delta = 20;
__u8 spring = 4;
- __u8 reg8339[2];
if (sd->ag_cnt < 0)
return;
@@ -848,13 +841,13 @@ static void do_autogain(struct gspca_dev *gspca_dev)
if (gainG > 0x3f)
gainG = 0x3f;
- else if (gainG < 4)
+ else if (gainG < 3)
gainG = 3;
i2c_write(gspca_dev, gainG, 0x35);
- if (expotimes >= 0x0256)
+ if (expotimes > 0x0256)
expotimes = 0x0256;
- else if (expotimes < 4)
+ else if (expotimes < 3)
expotimes = 3;
i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
}
@@ -862,13 +855,13 @@ static void do_autogain(struct gspca_dev *gspca_dev)
case Rev012A:
reg_r(gspca_dev, 0x8330, 2);
if (gspca_dev->usb_buf[1] > 0x08) {
- reg8339[0] = ++sd->expo12a;
- reg8339[1] = 0;
- reg_w_buf(gspca_dev, 0x8339, reg8339, 2);
+ gspca_dev->usb_buf[0] = ++sd->expo12a;
+ gspca_dev->usb_buf[1] = 0;
+ reg_w_buf(gspca_dev, 0x8339, 2);
} else if (gspca_dev->usb_buf[1] < 0x02) {
- reg8339[0] = --sd->expo12a;
- reg8339[1] = 0;
- reg_w_buf(gspca_dev, 0x8339, reg8339, 2);
+ gspca_dev->usb_buf[0] = --sd->expo12a;
+ gspca_dev->usb_buf[1] = 0;
+ reg_w_buf(gspca_dev, 0x8339, 2);
}
break;
}
@@ -881,8 +874,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
- switch (data[0]) {
- case 0: /* start of frame */
+ switch (data[0]) { /* sequence number */
+ case 0: /* start of frame */
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
data, 0);
data += SPCA561_OFFSET_DATA;
@@ -904,8 +897,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
frame, data, len);
}
return;
- case 0xff: /* drop */
-/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ case 0xff: /* drop (empty mpackets) */
return;
}
data++;
@@ -914,55 +906,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
}
/* rev 72a only */
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- __u8 value;
-
- value = sd->brightness;
- reg_w_val(gspca_dev->dev, 0x8611, value);
- reg_w_val(gspca_dev->dev, 0x8612, value);
- reg_w_val(gspca_dev->dev, 0x8613, value);
- reg_w_val(gspca_dev->dev, 0x8614, value);
-}
-
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- __u16 tot;
-
- tot = 0;
- reg_r(gspca_dev, 0x8611, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8612, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8613, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8614, 1);
- tot += gspca_dev->usb_buf[0];
- sd->brightness = tot >> 2;
-}
-
-/* rev72a only */
-static void getcontrast(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- __u16 tot;
-
- tot = 0;
- reg_r(gspca_dev, 0x8651, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8652, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8653, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8654, 1);
- tot += gspca_dev->usb_buf[0];
- sd->contrast = tot << 6;
- PDEBUG(D_CONF, "get contrast %d", sd->contrast);
-}
-
-/* rev 72a only */
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -977,7 +920,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- getbrightness(gspca_dev);
*val = sd->brightness;
return 0;
}
@@ -997,7 +939,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- getcontrast(gspca_dev);
*val = sd->contrast;
return 0;
}
@@ -1020,7 +961,6 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
-/* rev12a only */
static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1135,6 +1075,19 @@ static struct ctrl sd_ctrls_12a[] = {
static struct ctrl sd_ctrls_72a[] = {
{
+ {
+ .id = V4L2_CID_DO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "White Balance",
+ .minimum = WHITE_MIN,
+ .maximum = WHITE_MAX,
+ .step = 1,
+ .default_value = WHITE_DEF,
+ },
+ .set = sd_setwhite,
+ .get = sd_getwhite,
+ },
+ {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
diff --git a/linux/drivers/media/video/gspca/stk014.c b/linux/drivers/media/video/gspca/stk014.c
index d9d64911f..60de9af87 100644
--- a/linux/drivers/media/video/gspca/stk014.c
+++ b/linux/drivers/media/video/gspca/stk014.c
@@ -109,7 +109,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -424,10 +424,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* beginning of the frame */
#define STKHDRSZ 12
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- data + STKHDRSZ, len - STKHDRSZ);
-#undef STKHDRSZ
- return;
+ data += STKHDRSZ;
+ len -= STKHDRSZ;
}
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
diff --git a/linux/drivers/media/video/gspca/stv06xx/Kconfig b/linux/drivers/media/video/gspca/stv06xx/Kconfig
new file mode 100644
index 000000000..634ad38d9
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/Kconfig
@@ -0,0 +1,9 @@
+config USB_STV06XX
+ tristate "STV06XX USB Camera Driver"
+ depends on USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on
+ the ST STV06XX chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_stv06xx.
diff --git a/linux/drivers/media/video/gspca/stv06xx/Makefile b/linux/drivers/media/video/gspca/stv06xx/Makefile
new file mode 100644
index 000000000..feeaa94ab
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/Makefile
@@ -0,0 +1,9 @@
+obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o
+
+gspca_stv06xx-objs := stv06xx.o \
+ stv06xx_vv6410.o \
+ stv06xx_hdcs.o \
+ stv06xx_pb0100.o
+
+EXTRA_CFLAGS += -Idrivers/media/video/gspca
+
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx.c
new file mode 100644
index 000000000..13a021e3c
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * P/N 861037: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express
+ * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000 ASIC
+ * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web
+ */
+
+#include "stv06xx_sensor.h"
+
+MODULE_AUTHOR("Erik Andrén");
+MODULE_DESCRIPTION("STV06XX USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+static int dump_bridge;
+static int dump_sensor;
+
+int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data)
+{
+ int err;
+ struct usb_device *udev = sd->gspca_dev.dev;
+ __u8 *buf = sd->gspca_dev.usb_buf;
+ u8 len = (i2c_data > 0xff) ? 2 : 1;
+
+ buf[0] = i2c_data & 0xff;
+ buf[1] = (i2c_data >> 8) & 0xff;
+
+ err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 0x04, 0x40, address, 0, buf, len,
+ STV06XX_URB_MSG_TIMEOUT);
+
+
+ PDEBUG(D_CONF, "Written 0x%x to address 0x%x, status: %d",
+ i2c_data, address, err);
+
+ return (err < 0) ? err : 0;
+}
+
+int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data)
+{
+ int err;
+ struct usb_device *udev = sd->gspca_dev.dev;
+ __u8 *buf = sd->gspca_dev.usb_buf;
+
+ err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ 0x04, 0xc0, address, 0, buf, 1,
+ STV06XX_URB_MSG_TIMEOUT);
+
+ *i2c_data = buf[0];
+
+ PDEBUG(D_CONF, "Read 0x%x from address 0x%x, status %d",
+ *i2c_data, address, err);
+
+ return (err < 0) ? err : 0;
+}
+
+/* Wraps the normal write sensor bytes / words functions for writing a
+ single value */
+int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value)
+{
+ if (sd->sensor->i2c_len == 2) {
+ u16 data[2] = { address, value };
+ return stv06xx_write_sensor_words(sd, data, 1);
+ } else {
+ u8 data[2] = { address, value };
+ return stv06xx_write_sensor_bytes(sd, data, 1);
+ }
+}
+
+static int stv06xx_write_sensor_finish(struct sd *sd)
+{
+ int err = 0;
+
+ if (IS_850(sd)) {
+ struct usb_device *udev = sd->gspca_dev.dev;
+ __u8 *buf = sd->gspca_dev.usb_buf;
+
+ /* Quickam Web needs an extra packet */
+ buf[0] = 0;
+ err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 0x04, 0x40, 0x1704, 0, buf, 1,
+ STV06XX_URB_MSG_TIMEOUT);
+ }
+
+ return (err < 0) ? err : 0;
+}
+
+int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len)
+{
+ int err, i, j;
+ struct usb_device *udev = sd->gspca_dev.dev;
+ __u8 *buf = sd->gspca_dev.usb_buf;
+
+ PDEBUG(D_USBO, "I2C: Command buffer contains %d entries", len);
+ for (i = 0; i < len;) {
+ /* Build the command buffer */
+ memset(buf, 0, I2C_BUFFER_LENGTH);
+ for (j = 0; j < I2C_MAX_BYTES && i < len; j++, i++) {
+ buf[j] = data[2*i];
+ buf[0x10 + j] = data[2*i+1];
+ PDEBUG(D_USBO, "I2C: Writing 0x%02x to reg 0x%02x",
+ data[2*i+1], data[2*i]);
+ }
+ buf[0x20] = sd->sensor->i2c_addr;
+ buf[0x21] = j - 1; /* Number of commands to send - 1 */
+ buf[0x22] = I2C_WRITE_CMD;
+ err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 0x04, 0x40, 0x0400, 0, buf,
+ I2C_BUFFER_LENGTH,
+ STV06XX_URB_MSG_TIMEOUT);
+ if (err < 0)
+ return err;
+ }
+ return stv06xx_write_sensor_finish(sd);
+}
+
+int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len)
+{
+ int err, i, j;
+ struct usb_device *udev = sd->gspca_dev.dev;
+ __u8 *buf = sd->gspca_dev.usb_buf;
+
+ PDEBUG(D_USBO, "I2C: Command buffer contains %d entries", len);
+
+ for (i = 0; i < len;) {
+ /* Build the command buffer */
+ memset(buf, 0, I2C_BUFFER_LENGTH);
+ for (j = 0; j < I2C_MAX_WORDS && i < len; j++, i++) {
+ buf[j] = data[2*i];
+ buf[0x10 + j * 2] = data[2*i+1];
+ buf[0x10 + j * 2 + 1] = data[2*i+1] >> 8;
+ PDEBUG(D_USBO, "I2C: Writing 0x%04x to reg 0x%02x",
+ data[2*i+1], data[2*i]);
+ }
+ buf[0x20] = sd->sensor->i2c_addr;
+ buf[0x21] = j - 1; /* Number of commands to send - 1 */
+ buf[0x22] = I2C_WRITE_CMD;
+ err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 0x04, 0x40, 0x0400, 0, buf,
+ I2C_BUFFER_LENGTH,
+ STV06XX_URB_MSG_TIMEOUT);
+ if (err < 0)
+ return err;
+ }
+ return stv06xx_write_sensor_finish(sd);
+}
+
+int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value)
+{
+ int err;
+ struct usb_device *udev = sd->gspca_dev.dev;
+ __u8 *buf = sd->gspca_dev.usb_buf;
+
+ err = stv06xx_write_bridge(sd, STV_I2C_FLUSH, sd->sensor->i2c_flush);
+ if (err < 0)
+ return err;
+
+ /* Clear mem */
+ memset(buf, 0, I2C_BUFFER_LENGTH);
+
+ buf[0] = address;
+ buf[0x20] = sd->sensor->i2c_addr;
+ buf[0x21] = 0;
+
+ /* Read I2C register */
+ buf[0x22] = I2C_READ_CMD;
+
+ err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH,
+ STV06XX_URB_MSG_TIMEOUT);
+ if (err < 0) {
+ PDEBUG(D_ERR, "I2C Read: error writing address: %d", err);
+ return err;
+ }
+
+ err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ 0x04, 0xc0, 0x1410, 0, buf, sd->sensor->i2c_len,
+ STV06XX_URB_MSG_TIMEOUT);
+ if (sd->sensor->i2c_len == 2)
+ *value = buf[0] | (buf[1] << 8);
+ else
+ *value = buf[0];
+
+ PDEBUG(D_USBO, "I2C: Read 0x%x from address 0x%x, status: %d",
+ *value, address, err);
+
+ return (err < 0) ? err : 0;
+}
+
+/* Dumps all bridge registers */
+static void stv06xx_dump_bridge(struct sd *sd)
+{
+ int i;
+ u8 data, buf;
+
+ info("Dumping all stv06xx bridge registers");
+ for (i = 0x1400; i < 0x160f; i++) {
+ stv06xx_read_bridge(sd, i, &data);
+
+ info("Read 0x%x from address 0x%x", data, i);
+ }
+
+ for (i = 0x1400; i < 0x160f; i++) {
+ stv06xx_read_bridge(sd, i, &data);
+ buf = data;
+
+ stv06xx_write_bridge(sd, i, 0xff);
+ stv06xx_read_bridge(sd, i, &data);
+ if (data == 0xff)
+ info("Register 0x%x is read/write", i);
+ else if (data != buf)
+ info("Register 0x%x is read/write,"
+ "but only partially", i);
+ else
+ info("Register 0x%x is read-only", i);
+
+ stv06xx_write_bridge(sd, i, buf);
+ }
+}
+
+/* this function is called at probe and resume time */
+static int stv06xx_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int err;
+
+ PDEBUG(D_PROBE, "Initializing camera");
+
+ /* Let the usb init settle for a bit
+ before performing the initialization */
+ msleep(250);
+
+ err = sd->sensor->init(sd);
+
+ if (dump_sensor)
+ sd->sensor->dump(sd);
+
+ return (err < 0) ? err : 0;
+}
+
+/* Start the camera */
+static int stv06xx_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int err;
+
+ /* Prepare the sensor for start */
+ err = sd->sensor->start(sd);
+ if (err < 0)
+ goto out;
+
+ /* Start isochronous streaming */
+ err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 1);
+
+out:
+ if (err < 0)
+ PDEBUG(D_STREAM, "Starting stream failed");
+ else
+ PDEBUG(D_STREAM, "Started streaming");
+
+ return (err < 0) ? err : 0;
+}
+
+static void stv06xx_stopN(struct gspca_dev *gspca_dev)
+{
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* stop ISO-streaming */
+ err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 0);
+ if (err < 0)
+ goto out;
+
+ err = sd->sensor->stop(sd);
+ if (err < 0)
+ goto out;
+
+out:
+ if (err < 0)
+ PDEBUG(D_STREAM, "Failed to stop stream");
+ else
+ PDEBUG(D_STREAM, "Stopped streaming");
+}
+
+/*
+ * Analyse an USB packet of the data stream and store it appropriately.
+ * Each packet contains an integral number of chunks. Each chunk has
+ * 2-bytes identification, followed by 2-bytes that describe the chunk
+ * length. Known/guessed chunk identifications are:
+ * 8001/8005/C001/C005 - Begin new frame
+ * 8002/8006/C002/C006 - End frame
+ * 0200/4200 - Contains actual image data, bayer or compressed
+ * 0005 - 11 bytes of unknown data
+ * 0100 - 2 bytes of unknown data
+ * The 0005 and 0100 chunks seem to appear only in compressed stream.
+ */
+static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ PDEBUG(D_PACK, "Packet of length %d arrived", len);
+
+ /* A packet may contain several frames
+ loop until the whole packet is reached */
+ while (len) {
+ int id, chunk_len;
+
+ if (len < 4) {
+ PDEBUG(D_PACK, "Packet is smaller than 4 bytes");
+ return;
+ }
+
+ /* Capture the id */
+ id = (data[0] << 8) | data[1];
+
+ /* Capture the chunk length */
+ chunk_len = (data[2] << 8) | data[3];
+ PDEBUG(D_PACK, "Chunk id: %x, length: %d", id, chunk_len);
+
+ data += 4;
+ len -= 4;
+
+ if (len < chunk_len) {
+ PDEBUG(D_ERR, "URB packet length is smaller"
+ " than the specified chunk length");
+ return;
+ }
+
+ switch (id) {
+ case 0x0200:
+ case 0x4200:
+ PDEBUG(D_PACK, "Frame data packet detected");
+
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data, chunk_len);
+ break;
+
+ case 0x8001:
+ case 0x8005:
+ case 0xc001:
+ case 0xc005:
+ PDEBUG(D_PACK, "Starting new frame");
+
+ /* Create a new frame, chunk length should be zero */
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ frame, data, 0);
+
+ if (chunk_len)
+ PDEBUG(D_ERR, "Chunk length is "
+ "non-zero on a SOF");
+ break;
+
+ case 0x8002:
+ case 0x8006:
+ case 0xc002:
+ PDEBUG(D_PACK, "End of frame detected");
+
+ /* Complete the last frame (if any) */
+ gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0);
+
+ if (chunk_len)
+ PDEBUG(D_ERR, "Chunk length is "
+ "non-zero on a EOF");
+ break;
+
+ case 0x0005:
+ PDEBUG(D_PACK, "Chunk 0x005 detected");
+ /* Unknown chunk with 11 bytes of data,
+ occurs just before end of each frame
+ in compressed mode */
+ break;
+
+ case 0x0100:
+ PDEBUG(D_PACK, "Chunk 0x0100 detected");
+ /* Unknown chunk with 2 bytes of data,
+ occurs 2-3 times per USB interrupt */
+ break;
+ default:
+ PDEBUG(D_PACK, "Unknown chunk %d detected", id);
+ /* Unknown chunk */
+ }
+ data += chunk_len;
+ len -= chunk_len;
+ }
+}
+
+static int stv06xx_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id);
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .config = stv06xx_config,
+ .init = stv06xx_init,
+ .start = stv06xx_start,
+ .stopN = stv06xx_stopN,
+ .pkt_scan = stv06xx_pkt_scan
+};
+
+/* This function is called at probe time */
+static int stv06xx_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+
+ PDEBUG(D_PROBE, "Configuring camera");
+
+ cam = &gspca_dev->cam;
+ cam->epaddr = STV_ISOC_ENDPOINT_ADDR;
+ sd->desc = sd_desc;
+ gspca_dev->sd_desc = &sd->desc;
+
+ if (dump_bridge)
+ stv06xx_dump_bridge(sd);
+
+ sd->sensor = &stv06xx_sensor_vv6410;
+ if (!sd->sensor->probe(sd))
+ return 0;
+
+ sd->sensor = &stv06xx_sensor_hdcs1x00;
+ if (!sd->sensor->probe(sd))
+ return 0;
+
+ sd->sensor = &stv06xx_sensor_hdcs1020;
+ if (!sd->sensor->probe(sd))
+ return 0;
+
+ sd->sensor = &stv06xx_sensor_pb0100;
+ if (!sd->sensor->probe(sd))
+ return 0;
+
+ sd->sensor = NULL;
+ return -ENODEV;
+}
+
+
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x046d, 0x0840)}, /* QuickCam Express */
+ {USB_DEVICE(0x046d, 0x0850)}, /* LEGO cam / QuickCam Web */
+ {USB_DEVICE(0x046d, 0x0870)}, /* Dexxa WebCam USB */
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ PDEBUG(D_PROBE, "Probing for a stv06xx device");
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static void sd_disconnect(struct usb_interface *intf)
+{
+ struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+ struct sd *sd = (struct sd *) gspca_dev;
+ PDEBUG(D_PROBE, "Disconnecting the stv06xx device");
+
+ if (sd->sensor->disconnect)
+ sd->sensor->disconnect(sd);
+ gspca_disconnect(intf);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = sd_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param(dump_bridge, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup");
+
+module_param(dump_sensor, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dump_sensor, "Dumps all sensor registers at startup");
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx.h
new file mode 100644
index 000000000..1207e7d17
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * P/N 861037: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express
+ * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000 ASIC
+ * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web
+ */
+
+#ifndef STV06XX_H_
+#define STV06XX_H_
+
+#include "gspca.h"
+
+#define MODULE_NAME "STV06xx"
+
+#define STV_ISOC_ENDPOINT_ADDR 0x81
+
+#ifndef V4L2_PIX_FMT_SGRBG8
+#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G')
+#endif
+
+#define STV_REG23 0x0423
+
+/* Control registers of the STV0600 ASIC */
+#define STV_I2C_PARTNER 0x1420
+#define STV_I2C_VAL_REG_VAL_PAIRS_MIN1 0x1421
+#define STV_I2C_READ_WRITE_TOGGLE 0x1422
+#define STV_I2C_FLUSH 0x1423
+#define STV_I2C_SUCC_READ_REG_VALS 0x1424
+
+#define STV_ISO_ENABLE 0x1440
+#define STV_SCAN_RATE 0x1443
+#define STV_LED_CTRL 0x1445
+#define STV_STV0600_EMULATION 0x1446
+#define STV_REG00 0x1500
+#define STV_REG01 0x1501
+#define STV_REG02 0x1502
+#define STV_REG03 0x1503
+#define STV_REG04 0x1504
+
+#define STV_ISO_SIZE_L 0x15c1
+#define STV_ISO_SIZE_H 0x15c2
+
+/* Refers to the CIF 352x288 and QCIF 176x144 */
+/* 1: 288 lines, 2: 144 lines */
+#define STV_Y_CTRL 0x15c3
+
+/* 0xa: 352 columns, 0x6: 176 columns */
+#define STV_X_CTRL 0x1680
+
+#define STV06XX_URB_MSG_TIMEOUT 5000
+
+#define I2C_MAX_BYTES 16
+#define I2C_MAX_WORDS 8
+
+#define I2C_BUFFER_LENGTH 0x23
+#define I2C_READ_CMD 3
+#define I2C_WRITE_CMD 1
+
+#define LED_ON 1
+#define LED_OFF 0
+
+/* STV06xx device descriptor */
+struct sd {
+ struct gspca_dev gspca_dev;
+
+ /* A pointer to the currently connected sensor */
+ const struct stv06xx_sensor *sensor;
+
+ /* A pointer to the sd_desc struct */
+ struct sd_desc desc;
+
+ /* Sensor private data */
+ void *sensor_priv;
+};
+
+int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data);
+int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data);
+
+int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len);
+int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len);
+
+int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value);
+int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value);
+
+#endif
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
new file mode 100644
index 000000000..14335a9e4
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ * Copyright (c) 2008 Chia-I Wu
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * P/N 861037: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express
+ * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000 ASIC
+ * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web
+ */
+
+#include "stv06xx_hdcs.h"
+
+enum hdcs_power_state {
+ HDCS_STATE_SLEEP,
+ HDCS_STATE_IDLE,
+ HDCS_STATE_RUN
+};
+
+/* no lock? */
+struct hdcs {
+ enum hdcs_power_state state;
+ int w, h;
+
+ /* visible area of the sensor array */
+ struct {
+ int left, top;
+ int width, height;
+ int border;
+ } array;
+
+ struct {
+ /* Column timing overhead */
+ u8 cto;
+ /* Column processing overhead */
+ u8 cpo;
+ /* Row sample period constant */
+ u16 rs;
+ /* Exposure reset duration */
+ u16 er;
+ } exp;
+
+ int psmp;
+};
+
+static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
+{
+ u8 regs[I2C_MAX_BYTES * 2];
+ int i;
+
+ if (unlikely((len <= 0) || (len >= I2C_MAX_BYTES) ||
+ (reg + len > 0xff)))
+ return -EINVAL;
+
+ for (i = 0; i < len; i++, reg++) {
+ regs[2*i] = reg;
+ regs[2*i+1] = vals[i];
+ }
+
+ return stv06xx_write_sensor_bytes(sd, regs, len);
+}
+
+static int hdcs_set_state(struct sd *sd, enum hdcs_power_state state)
+{
+ struct hdcs *hdcs = sd->sensor_priv;
+ u8 val;
+ int ret;
+
+ if (hdcs->state == state)
+ return 0;
+
+ /* we need to go idle before running or sleeping */
+ if (hdcs->state != HDCS_STATE_IDLE) {
+ ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0);
+ if (ret)
+ return ret;
+ }
+
+ hdcs->state = HDCS_STATE_IDLE;
+
+ if (state == HDCS_STATE_IDLE)
+ return 0;
+
+ switch (state) {
+ case HDCS_STATE_SLEEP:
+ val = HDCS_SLEEP_MODE;
+ break;
+
+ case HDCS_STATE_RUN:
+ val = HDCS_RUN_ENABLE;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val);
+ if (ret < 0)
+ hdcs->state = state;
+
+ return ret;
+}
+
+static int hdcs_reset(struct sd *sd)
+{
+ struct hdcs *hdcs = sd->sensor_priv;
+ int err;
+
+ err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 1);
+ if (err < 0)
+ return err;
+
+ err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0);
+ if (err < 0)
+ hdcs->state = HDCS_STATE_IDLE;
+
+ return err;
+}
+
+static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct hdcs *hdcs = sd->sensor_priv;
+
+ /* Column time period */
+ int ct;
+ /* Column processing period */
+ int cp;
+ /* Row processing period */
+ int rp;
+ int cycles;
+ int err;
+ int rowexp;
+ u16 data[2];
+
+ err = stv06xx_read_sensor(sd, HDCS_ROWEXPL, &data[0]);
+ if (err < 0)
+ return err;
+
+ err = stv06xx_read_sensor(sd, HDCS_ROWEXPH, &data[1]);
+ if (err < 0)
+ return err;
+
+ rowexp = (data[1] << 8) | data[0];
+
+ ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
+ cp = hdcs->exp.cto + (hdcs->w * ct / 2);
+ rp = hdcs->exp.rs + cp;
+
+ cycles = rp * rowexp;
+ *val = cycles / HDCS_CLK_FREQ_MHZ;
+ PDEBUG(D_V4L2, "Read exposure %d", *val);
+ return 0;
+}
+
+static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct hdcs *hdcs = sd->sensor_priv;
+ int rowexp, srowexp;
+ int max_srowexp;
+ /* Column time period */
+ int ct;
+ /* Column processing period */
+ int cp;
+ /* Row processing period */
+ int rp;
+ /* Minimum number of column timing periods
+ within the column processing period */
+ int mnct;
+ int cycles, err;
+ u8 exp[4];
+
+ cycles = val * HDCS_CLK_FREQ_MHZ;
+
+ ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
+ cp = hdcs->exp.cto + (hdcs->w * ct / 2);
+
+ /* the cycles one row takes */
+ rp = hdcs->exp.rs + cp;
+
+ rowexp = cycles / rp;
+
+ /* the remaining cycles */
+ cycles -= rowexp * rp;
+
+ /* calculate sub-row exposure */
+ if (IS_1020(sd)) {
+ /* see HDCS-1020 datasheet 3.5.6.4, p. 63 */
+ srowexp = hdcs->w - (cycles + hdcs->exp.er + 13) / ct;
+
+ mnct = (hdcs->exp.er + 12 + ct - 1) / ct;
+ max_srowexp = hdcs->w - mnct;
+ } else {
+ /* see HDCS-1000 datasheet 3.4.5.5, p. 61 */
+ srowexp = cp - hdcs->exp.er - 6 - cycles;
+
+ mnct = (hdcs->exp.er + 5 + ct - 1) / ct;
+ max_srowexp = cp - mnct * ct - 1;
+ }
+
+ if (srowexp < 0)
+ srowexp = 0;
+ else if (srowexp > max_srowexp)
+ srowexp = max_srowexp;
+
+ if (IS_1020(sd)) {
+ exp[0] = rowexp & 0xff;
+ exp[1] = rowexp >> 8;
+ exp[2] = (srowexp >> 2) & 0xff;
+ /* this clears exposure error flag */
+ exp[3] = 0x1;
+ err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4);
+ } else {
+ exp[0] = rowexp & 0xff;
+ exp[1] = rowexp >> 8;
+ exp[2] = srowexp & 0xff;
+ exp[3] = srowexp >> 8;
+ err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4);
+ if (err < 0)
+ return err;
+
+ /* clear exposure error flag */
+ err = stv06xx_write_sensor(sd,
+ HDCS_STATUS, BIT(4));
+ }
+ PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d",
+ val, rowexp, srowexp);
+ return err;
+}
+
+static int hdcs_set_gains(struct sd *sd, u8 r, u8 g, u8 b)
+{
+ u8 gains[4];
+
+ /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */
+ if (r > 127)
+ r = 0x80 | (r / 2);
+ if (g > 127)
+ g = 0x80 | (g / 2);
+ if (b > 127)
+ b = 0x80 | (b / 2);
+
+ gains[0] = g;
+ gains[1] = r;
+ gains[2] = b;
+ gains[3] = g;
+
+ return hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4);
+}
+
+static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int err;
+ u16 data;
+
+ err = stv06xx_read_sensor(sd, HDCS_ERECPGA, &data);
+
+ /* Bit 7 doubles the gain */
+ if (data & 0x80)
+ *val = (data & 0x7f) * 2;
+ else
+ *val = data;
+
+ PDEBUG(D_V4L2, "Read gain %d", *val);
+ return err;
+}
+
+static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ PDEBUG(D_V4L2, "Writing gain %d", val);
+ return hdcs_set_gains((struct sd *) gspca_dev,
+ val & 0xff, val & 0xff, val & 0xff);
+}
+
+static int hdcs_set_size(struct sd *sd,
+ unsigned int width, unsigned int height)
+{
+ struct hdcs *hdcs = sd->sensor_priv;
+ u8 win[4];
+ unsigned int x, y;
+ int err;
+
+ /* must be multiple of 4 */
+ width = (width + 3) & ~0x3;
+ height = (height + 3) & ~0x3;
+
+ if (width > hdcs->array.width)
+ width = hdcs->array.width;
+
+ if (IS_1020(sd)) {
+ /* the borders are also invalid */
+ if (height + 2 * hdcs->array.border + HDCS_1020_BOTTOM_Y_SKIP
+ > hdcs->array.height)
+ height = hdcs->array.height - 2 * hdcs->array.border -
+ HDCS_1020_BOTTOM_Y_SKIP;
+
+ y = (hdcs->array.height - HDCS_1020_BOTTOM_Y_SKIP - height) / 2
+ + hdcs->array.top;
+ } else {
+ if (height > hdcs->array.height)
+ height = hdcs->array.height;
+
+ y = hdcs->array.top + (hdcs->array.height - height) / 2;
+ }
+
+ x = hdcs->array.left + (hdcs->array.width - width) / 2;
+
+ win[0] = y / 4;
+ win[1] = x / 4;
+ win[2] = (y + height) / 4 - 1;
+ win[3] = (x + width) / 4 - 1;
+
+ err = hdcs_reg_write_seq(sd, HDCS_FWROW, win, 4);
+ if (err < 0)
+ return err;
+
+ /* Update the current width and height */
+ hdcs->w = width;
+ hdcs->h = height;
+ return err;
+}
+
+static int hdcs_probe_1x00(struct sd *sd)
+{
+ struct hdcs *hdcs;
+ u16 sensor;
+ int ret;
+
+ ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor);
+ if (ret < 0 || sensor != 0x08)
+ return -ENODEV;
+
+ info("HDCS-1000/1100 sensor detected");
+
+ sd->gspca_dev.cam.cam_mode = stv06xx_sensor_hdcs1x00.modes;
+ sd->gspca_dev.cam.nmodes = stv06xx_sensor_hdcs1x00.nmodes;
+ sd->desc.ctrls = stv06xx_sensor_hdcs1x00.ctrls;
+ sd->desc.nctrls = stv06xx_sensor_hdcs1x00.nctrls;
+
+ hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
+ if (!hdcs)
+ return -ENOMEM;
+
+ hdcs->array.left = 8;
+ hdcs->array.top = 8;
+ hdcs->array.width = HDCS_1X00_DEF_WIDTH;
+ hdcs->array.height = HDCS_1X00_DEF_HEIGHT;
+ hdcs->array.border = 4;
+
+ hdcs->exp.cto = 4;
+ hdcs->exp.cpo = 2;
+ hdcs->exp.rs = 186;
+ hdcs->exp.er = 100;
+
+ /*
+ * Frame rate on HDCS-1000 0x46D:0x840 depends on PSMP:
+ * 4 = doesn't work at all
+ * 5 = 7.8 fps,
+ * 6 = 6.9 fps,
+ * 8 = 6.3 fps,
+ * 10 = 5.5 fps,
+ * 15 = 4.4 fps,
+ * 31 = 2.8 fps
+ *
+ * Frame rate on HDCS-1000 0x46D:0x870 depends on PSMP:
+ * 15 = doesn't work at all
+ * 18 = doesn't work at all
+ * 19 = 7.3 fps
+ * 20 = 7.4 fps
+ * 21 = 7.4 fps
+ * 22 = 7.4 fps
+ * 24 = 6.3 fps
+ * 30 = 5.4 fps
+ */
+ hdcs->psmp = IS_870(sd) ? 20 : 5;
+
+ sd->sensor_priv = hdcs;
+
+ return 0;
+}
+
+static int hdcs_probe_1020(struct sd *sd)
+{
+ struct hdcs *hdcs;
+ u16 sensor;
+ int ret;
+
+ ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor);
+ if (ret < 0 || sensor != 0x10)
+ return -ENODEV;
+
+ info("HDCS-1020 sensor detected");
+
+ sd->gspca_dev.cam.cam_mode = stv06xx_sensor_hdcs1020.modes;
+ sd->gspca_dev.cam.nmodes = stv06xx_sensor_hdcs1020.nmodes;
+ sd->desc.ctrls = stv06xx_sensor_hdcs1020.ctrls;
+ sd->desc.nctrls = stv06xx_sensor_hdcs1020.nctrls;
+
+ hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
+ if (!hdcs)
+ return -ENOMEM;
+
+ /*
+ * From Andrey's test image: looks like HDCS-1020 upper-left
+ * visible pixel is at 24,8 (y maybe even smaller?) and lower-right
+ * visible pixel at 375,299 (x maybe even larger?)
+ */
+ hdcs->array.left = 24;
+ hdcs->array.top = 4;
+ hdcs->array.width = HDCS_1020_DEF_WIDTH;
+ hdcs->array.height = 304;
+ hdcs->array.border = 4;
+
+ hdcs->psmp = 6;
+
+ hdcs->exp.cto = 3;
+ hdcs->exp.cpo = 3;
+ hdcs->exp.rs = 155;
+ hdcs->exp.er = 96;
+
+ sd->sensor_priv = hdcs;
+
+ return 0;
+}
+
+static int hdcs_start(struct sd *sd)
+{
+ PDEBUG(D_STREAM, "Starting stream");
+
+ return hdcs_set_state(sd, HDCS_STATE_RUN);
+}
+
+static int hdcs_stop(struct sd *sd)
+{
+ PDEBUG(D_STREAM, "Halting stream");
+
+ return hdcs_set_state(sd, HDCS_STATE_SLEEP);
+}
+
+static void hdcs_disconnect(struct sd *sd)
+{
+ PDEBUG(D_PROBE, "Disconnecting the sensor");
+ kfree(sd->sensor_priv);
+}
+
+static int hdcs_init(struct sd *sd)
+{
+ struct hdcs *hdcs = sd->sensor_priv;
+ int i, err = 0;
+
+ /* Set the STV0602AA in STV0600 emulation mode */
+ if (IS_870(sd))
+ stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1);
+
+ /* Execute the bridge init */
+ for (i = 0; i < ARRAY_SIZE(stv_bridge_init) && !err; i++) {
+ err = stv06xx_write_bridge(sd, stv_bridge_init[i][0],
+ stv_bridge_init[i][1]);
+ }
+ if (err < 0)
+ return err;
+
+ /* sensor soft reset */
+ hdcs_reset(sd);
+
+ /* Execute the sensor init */
+ for (i = 0; i < ARRAY_SIZE(stv_sensor_init) && !err; i++) {
+ err = stv06xx_write_sensor(sd, stv_sensor_init[i][0],
+ stv_sensor_init[i][1]);
+ }
+ if (err < 0)
+ return err;
+
+ /* Enable continous frame capture, bit 2: stop when frame complete */
+ err = stv06xx_write_sensor(sd, HDCS_REG_CONFIG(sd), BIT(3));
+ if (err < 0)
+ return err;
+
+ /* Set PGA sample duration
+ (was 0x7E for IS_870, but caused slow framerate with HDCS-1020) */
+ if (IS_1020(sd))
+ err = stv06xx_write_sensor(sd, HDCS_TCTRL,
+ (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp);
+ else
+ err = stv06xx_write_sensor(sd, HDCS_TCTRL,
+ (HDCS_ADC_START_SIG_DUR << 5) | hdcs->psmp);
+ if (err < 0)
+ return err;
+
+ err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN, HDCS_DEFAULT_GAIN,
+ HDCS_DEFAULT_GAIN);
+ if (err < 0)
+ return err;
+
+ err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE);
+ if (err < 0)
+ return err;
+
+ err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
+ return err;
+}
+
+static int hdcs_dump(struct sd *sd)
+{
+ u16 reg, val;
+
+ info("Dumping sensor registers:");
+
+ for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) {
+ stv06xx_read_sensor(sd, reg, &val);
+ info("reg 0x%02x = 0x%02x", reg, val);
+ }
+ return 0;
+}
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
new file mode 100644
index 000000000..9c7279a4c
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ * Copyright (c) 2008 Chia-I Wu
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * P/N 861037: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express
+ * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000 ASIC
+ * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web
+ */
+
+#ifndef STV06XX_HDCS_H_
+#define STV06XX_HDCS_H_
+
+#include "stv06xx_sensor.h"
+
+#define HDCS_REG_CONFIG(sd) (IS_1020(sd) ? HDCS20_CONFIG : HDCS00_CONFIG)
+#define HDCS_REG_CONTROL(sd) (IS_1020(sd) ? HDCS20_CONTROL : HDCS00_CONTROL)
+
+#define HDCS_1X00_DEF_WIDTH 360
+#define HDCS_1X00_DEF_HEIGHT 296
+
+#define HDCS_1020_DEF_WIDTH 352
+#define HDCS_1020_DEF_HEIGHT 292
+
+#define HDCS_1020_BOTTOM_Y_SKIP 4
+
+#define HDCS_CLK_FREQ_MHZ 25
+
+#define HDCS_ADC_START_SIG_DUR 3
+
+/* LSB bit of I2C or register address signifies write (0) or read (1) */
+/* I2C Registers common for both HDCS-1000/1100 and HDCS-1020 */
+/* Identifications Register */
+#define HDCS_IDENT (0x00 << 1)
+/* Status Register */
+#define HDCS_STATUS (0x01 << 1)
+/* Interrupt Mask Register */
+#define HDCS_IMASK (0x02 << 1)
+/* Pad Control Register */
+#define HDCS_PCTRL (0x03 << 1)
+/* Pad Drive Control Register */
+#define HDCS_PDRV (0x04 << 1)
+/* Interface Control Register */
+#define HDCS_ICTRL (0x05 << 1)
+/* Interface Timing Register */
+#define HDCS_ITMG (0x06 << 1)
+/* Baud Fraction Register */
+#define HDCS_BFRAC (0x07 << 1)
+/* Baud Rate Register */
+#define HDCS_BRATE (0x08 << 1)
+/* ADC Control Register */
+#define HDCS_ADCCTRL (0x09 << 1)
+/* First Window Row Register */
+#define HDCS_FWROW (0x0a << 1)
+/* First Window Column Register */
+#define HDCS_FWCOL (0x0b << 1)
+/* Last Window Row Register */
+#define HDCS_LWROW (0x0c << 1)
+/* Last Window Column Register */
+#define HDCS_LWCOL (0x0d << 1)
+/* Timing Control Register */
+#define HDCS_TCTRL (0x0e << 1)
+/* PGA Gain Register: Even Row, Even Column */
+#define HDCS_ERECPGA (0x0f << 1)
+/* PGA Gain Register: Even Row, Odd Column */
+#define HDCS_EROCPGA (0x10 << 1)
+/* PGA Gain Register: Odd Row, Even Column */
+#define HDCS_ORECPGA (0x11 << 1)
+/* PGA Gain Register: Odd Row, Odd Column */
+#define HDCS_OROCPGA (0x12 << 1)
+/* Row Exposure Low Register */
+#define HDCS_ROWEXPL (0x13 << 1)
+/* Row Exposure High Register */
+#define HDCS_ROWEXPH (0x14 << 1)
+
+/* I2C Registers only for HDCS-1000/1100 */
+/* Sub-Row Exposure Low Register */
+#define HDCS00_SROWEXPL (0x15 << 1)
+/* Sub-Row Exposure High Register */
+#define HDCS00_SROWEXPH (0x16 << 1)
+/* Configuration Register */
+#define HDCS00_CONFIG (0x17 << 1)
+/* Control Register */
+#define HDCS00_CONTROL (0x18 << 1)
+
+/* I2C Registers only for HDCS-1020 */
+/* Sub-Row Exposure Register */
+#define HDCS20_SROWEXP (0x15 << 1)
+/* Error Control Register */
+#define HDCS20_ERROR (0x16 << 1)
+/* Interface Timing 2 Register */
+#define HDCS20_ITMG2 (0x17 << 1)
+/* Interface Control 2 Register */
+#define HDCS20_ICTRL2 (0x18 << 1)
+/* Horizontal Blank Register */
+#define HDCS20_HBLANK (0x19 << 1)
+/* Vertical Blank Register */
+#define HDCS20_VBLANK (0x1a << 1)
+/* Configuration Register */
+#define HDCS20_CONFIG (0x1b << 1)
+/* Control Register */
+#define HDCS20_CONTROL (0x1c << 1)
+
+#define HDCS_RUN_ENABLE (1 << 2)
+#define HDCS_SLEEP_MODE (1 << 1)
+
+#define HDCS_DEFAULT_EXPOSURE 5000
+#define HDCS_DEFAULT_GAIN 128
+
+static int hdcs_probe_1x00(struct sd *sd);
+static int hdcs_probe_1020(struct sd *sd);
+static int hdcs_start(struct sd *sd);
+static int hdcs_init(struct sd *sd);
+static int hdcs_stop(struct sd *sd);
+static int hdcs_dump(struct sd *sd);
+static void hdcs_disconnect(struct sd *sd);
+
+static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+
+const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = {
+ .name = "HP HDCS-1000/1100",
+ .i2c_flush = 0,
+ .i2c_addr = (0x55 << 1),
+ .i2c_len = 1,
+
+ .init = hdcs_init,
+ .probe = hdcs_probe_1x00,
+ .start = hdcs_start,
+ .stop = hdcs_stop,
+ .disconnect = hdcs_disconnect,
+ .dump = hdcs_dump,
+
+ .nctrls = 2,
+ .ctrls = {
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x00,
+ .maximum = 0xffff,
+ .step = 0x1,
+ .default_value = HDCS_DEFAULT_EXPOSURE,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = hdcs_set_exposure,
+ .get = hdcs_get_exposure
+ },
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = HDCS_DEFAULT_GAIN,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = hdcs_set_gain,
+ .get = hdcs_get_gain
+ }
+ },
+
+ .nmodes = 1,
+ .modes = {
+ {
+ HDCS_1X00_DEF_WIDTH,
+ HDCS_1X00_DEF_HEIGHT,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT,
+ .bytesperline = HDCS_1X00_DEF_WIDTH,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1
+ }
+ }
+};
+
+const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = {
+ .name = "HDCS-1020",
+ .i2c_flush = 0,
+ .i2c_addr = (0x55 << 1),
+ .i2c_len = 1,
+
+ .nctrls = 0,
+ .ctrls = {},
+
+ .init = hdcs_init,
+ .probe = hdcs_probe_1020,
+ .start = hdcs_start,
+ .stop = hdcs_stop,
+ .dump = hdcs_dump,
+
+ .nmodes = 1,
+ .modes = {
+ {
+ HDCS_1020_DEF_WIDTH,
+ HDCS_1020_DEF_HEIGHT,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT,
+ .bytesperline = HDCS_1020_DEF_WIDTH,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1
+ }
+ }
+};
+
+static const u16 stv_bridge_init[][2] = {
+ {STV_ISO_ENABLE, 0},
+ {STV_REG23, 0},
+ {STV_REG00, 0x1d},
+ {STV_REG01, 0xb5},
+ {STV_REG02, 0xa8},
+ {STV_REG03, 0x95},
+ {STV_REG04, 0x07},
+
+ {STV_SCAN_RATE, 0x20},
+ {STV_ISO_SIZE_L, 847},
+ {STV_Y_CTRL, 0x01},
+ {STV_X_CTRL, 0x0a}
+};
+
+static const u8 stv_sensor_init[][2] = {
+ /* Clear status (writing 1 will clear the corresponding status bit) */
+ {HDCS_STATUS, BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1)},
+ /* Disable all interrupts */
+ {HDCS_IMASK, 0x00},
+ {HDCS_PCTRL, BIT(6) | BIT(5) | BIT(1) | BIT(0)},
+ {HDCS_PDRV, 0x00},
+ {HDCS_ICTRL, BIT(5)},
+ {HDCS_ITMG, BIT(4) | BIT(1)},
+ /* ADC output resolution to 10 bits */
+ {HDCS_ADCCTRL, 10}
+};
+
+#endif
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
new file mode 100644
index 000000000..d0a0f8596
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * P/N 861037: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express
+ * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000 ASIC
+ * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web
+ */
+
+/*
+ * The spec file for the PB-0100 suggests the following for best quality
+ * images after the sensor has been reset :
+ *
+ * PB_ADCGAINL = R60 = 0x03 (3 dec) : sets low reference of ADC
+ to produce good black level
+ * PB_PREADCTRL = R32 = 0x1400 (5120 dec) : Enables global gain changes
+ through R53
+ * PB_ADCMINGAIN = R52 = 0x10 (16 dec) : Sets the minimum gain for
+ auto-exposure
+ * PB_ADCGLOBALGAIN = R53 = 0x10 (16 dec) : Sets the global gain
+ * PB_EXPGAIN = R14 = 0x11 (17 dec) : Sets the auto-exposure value
+ * PB_UPDATEINT = R23 = 0x02 (2 dec) : Sets the speed on
+ auto-exposure routine
+ * PB_CFILLIN = R5 = 0x0E (14 dec) : Sets the frame rate
+ */
+
+#include "stv06xx_pb0100.h"
+
+static int pb0100_probe(struct sd *sd)
+{
+ u16 sensor;
+ int i, err;
+ s32 *sensor_settings;
+
+ err = stv06xx_read_sensor(sd, PB_IDENT, &sensor);
+
+ if (err < 0)
+ return -ENODEV;
+
+ if ((sensor >> 8) == 0x64) {
+ sensor_settings = kmalloc(
+ stv06xx_sensor_pb0100.nctrls * sizeof(s32),
+ GFP_KERNEL);
+ if (!sensor_settings)
+ return -ENOMEM;
+
+ info("Photobit pb0100 sensor detected");
+
+ sd->gspca_dev.cam.cam_mode = stv06xx_sensor_pb0100.modes;
+ sd->gspca_dev.cam.nmodes = stv06xx_sensor_pb0100.nmodes;
+ sd->desc.ctrls = stv06xx_sensor_pb0100.ctrls;
+ sd->desc.nctrls = stv06xx_sensor_pb0100.nctrls;
+ for (i = 0; i < stv06xx_sensor_pb0100.nctrls; i++)
+ sensor_settings[i] = stv06xx_sensor_pb0100.
+ ctrls[i].qctrl.default_value;
+ sd->sensor_priv = sensor_settings;
+
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int pb0100_start(struct sd *sd)
+{
+ int err;
+ struct cam *cam = &sd->gspca_dev.cam;
+ s32 *sensor_settings = sd->sensor_priv;
+ u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
+
+ /* Setup sensor window */
+ if (mode & PB0100_CROP_TO_VGA) {
+ stv06xx_write_sensor(sd, PB_RSTART, 30);
+ stv06xx_write_sensor(sd, PB_CSTART, 20);
+ stv06xx_write_sensor(sd, PB_RWSIZE, 240 - 1);
+ stv06xx_write_sensor(sd, PB_CWSIZE, 320 - 1);
+ } else {
+ stv06xx_write_sensor(sd, PB_RSTART, 8);
+ stv06xx_write_sensor(sd, PB_CSTART, 4);
+ stv06xx_write_sensor(sd, PB_RWSIZE, 288 - 1);
+ stv06xx_write_sensor(sd, PB_CWSIZE, 352 - 1);
+ }
+
+ if (mode & PB0100_SUBSAMPLE) {
+ stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); /* Wrong, FIXME */
+ stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
+
+ stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
+ } else {
+ stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
+ stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
+ /* larger -> slower */
+ stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
+ }
+
+ /* set_gain also sets red and blue balance */
+ pb0100_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+ pb0100_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]);
+ pb0100_set_autogain_target(&sd->gspca_dev,
+ sensor_settings[AUTOGAIN_TARGET_IDX]);
+ pb0100_set_autogain(&sd->gspca_dev, sensor_settings[AUTOGAIN_IDX]);
+
+ err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1));
+ PDEBUG(D_STREAM, "Started stream, status: %d", err);
+
+ return (err < 0) ? err : 0;
+}
+
+static int pb0100_stop(struct sd *sd)
+{
+ int err;
+
+ err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1);
+
+ if (err < 0)
+ goto out;
+
+ /* Set bit 1 to zero */
+ err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
+
+ PDEBUG(D_STREAM, "Halting stream");
+out:
+ return (err < 0) ? err : 0;
+}
+
+/* FIXME: Sort the init commands out and put them into tables,
+ this is only for getting the camera to work */
+/* FIXME: No error handling for now,
+ add this once the init has been converted to proper tables */
+static int pb0100_init(struct sd *sd)
+{
+ stv06xx_write_bridge(sd, STV_REG00, 1);
+ stv06xx_write_bridge(sd, STV_SCAN_RATE, 0);
+
+ /* Reset sensor */
+ stv06xx_write_sensor(sd, PB_RESET, 1);
+ stv06xx_write_sensor(sd, PB_RESET, 0);
+
+ /* Disable chip */
+ stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
+
+ /* Gain stuff...*/
+ stv06xx_write_sensor(sd, PB_PREADCTRL, BIT(12)|BIT(10)|BIT(6));
+ stv06xx_write_sensor(sd, PB_ADCGLOBALGAIN, 12);
+
+ /* Set up auto-exposure */
+ /* ADC VREF_HI new setting for a transition
+ from the Expose1 to the Expose2 setting */
+ stv06xx_write_sensor(sd, PB_R28, 12);
+ /* gain max for autoexposure */
+ stv06xx_write_sensor(sd, PB_ADCMAXGAIN, 180);
+ /* gain min for autoexposure */
+ stv06xx_write_sensor(sd, PB_ADCMINGAIN, 12);
+ /* Maximum frame integration time (programmed into R8)
+ allowed for auto-exposure routine */
+ stv06xx_write_sensor(sd, PB_R54, 3);
+ /* Minimum frame integration time (programmed into R8)
+ allowed for auto-exposure routine */
+ stv06xx_write_sensor(sd, PB_R55, 0);
+ stv06xx_write_sensor(sd, PB_UPDATEINT, 1);
+ /* R15 Expose0 (maximum that auto-exposure may use) */
+ stv06xx_write_sensor(sd, PB_R15, 800);
+ /* R17 Expose2 (minimum that auto-exposure may use) */
+ stv06xx_write_sensor(sd, PB_R17, 10);
+
+ stv06xx_write_sensor(sd, PB_EXPGAIN, 0);
+
+ /* 0x14 */
+ stv06xx_write_sensor(sd, PB_VOFFSET, 0);
+ /* 0x0D */
+ stv06xx_write_sensor(sd, PB_ADCGAINH, 11);
+ /* Set black level (important!) */
+ stv06xx_write_sensor(sd, PB_ADCGAINL, 0);
+
+ /* ??? */
+ stv06xx_write_bridge(sd, STV_REG00, 0x11);
+ stv06xx_write_bridge(sd, STV_REG03, 0x45);
+ stv06xx_write_bridge(sd, STV_REG04, 0x07);
+
+ /* ISO-Size (0x27b: 635... why? - HDCS uses 847) */
+ stv06xx_write_bridge(sd, STV_ISO_SIZE_L, 847);
+
+ /* Scan/timing for the sensor */
+ stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
+ stv06xx_write_sensor(sd, PB_CFILLIN, 14);
+ stv06xx_write_sensor(sd, PB_VBL, 0);
+ stv06xx_write_sensor(sd, PB_FINTTIME, 0);
+ stv06xx_write_sensor(sd, PB_RINTTIME, 123);
+
+ stv06xx_write_bridge(sd, STV_REG01, 0xc2);
+ stv06xx_write_bridge(sd, STV_REG02, 0xb0);
+ return 0;
+}
+
+static int pb0100_dump(struct sd *sd)
+{
+ return 0;
+}
+
+static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[GAIN_IDX];
+
+ return 0;
+}
+
+static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ if (sensor_settings[AUTOGAIN_IDX])
+ return -EBUSY;
+
+ sensor_settings[GAIN_IDX] = val;
+ err = stv06xx_write_sensor(sd, PB_G1GAIN, val);
+ if (!err)
+ err = stv06xx_write_sensor(sd, PB_G2GAIN, val);
+ PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err);
+
+ if (!err)
+ err = pb0100_set_red_balance(gspca_dev,
+ sensor_settings[RED_BALANCE_IDX]);
+ if (!err)
+ err = pb0100_set_blue_balance(gspca_dev,
+ sensor_settings[BLUE_BALANCE_IDX]);
+
+ return err;
+}
+
+static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[RED_BALANCE_IDX];
+
+ return 0;
+}
+
+static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ if (sensor_settings[AUTOGAIN_IDX])
+ return -EBUSY;
+
+ sensor_settings[RED_BALANCE_IDX] = val;
+ val += sensor_settings[GAIN_IDX];
+ if (val < 0)
+ val = 0;
+ else if (val > 255)
+ val = 255;
+
+ err = stv06xx_write_sensor(sd, PB_RGAIN, val);
+ PDEBUG(D_V4L2, "Set red gain to %d, status: %d", val, err);
+
+ return err;
+}
+
+static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[BLUE_BALANCE_IDX];
+
+ return 0;
+}
+
+static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ if (sensor_settings[AUTOGAIN_IDX])
+ return -EBUSY;
+
+ sensor_settings[BLUE_BALANCE_IDX] = val;
+ val += sensor_settings[GAIN_IDX];
+ if (val < 0)
+ val = 0;
+ else if (val > 255)
+ val = 255;
+
+ err = stv06xx_write_sensor(sd, PB_BGAIN, val);
+ PDEBUG(D_V4L2, "Set blue gain to %d, status: %d", val, err);
+
+ return err;
+}
+
+static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[EXPOSURE_IDX];
+
+ return 0;
+}
+
+static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ if (sensor_settings[AUTOGAIN_IDX])
+ return -EBUSY;
+
+ sensor_settings[EXPOSURE_IDX] = val;
+ err = stv06xx_write_sensor(sd, PB_RINTTIME, val);
+ PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err);
+
+ return err;
+}
+
+static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[AUTOGAIN_IDX];
+
+ return 0;
+}
+
+static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ sensor_settings[AUTOGAIN_IDX] = val;
+ if (sensor_settings[AUTOGAIN_IDX]) {
+ if (sensor_settings[NATURAL_IDX])
+ val = BIT(6)|BIT(4)|BIT(0);
+ else
+ val = BIT(4)|BIT(0);
+ } else
+ val = 0;
+
+ err = stv06xx_write_sensor(sd, PB_EXPGAIN, val);
+ PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d",
+ sensor_settings[AUTOGAIN_IDX], sensor_settings[NATURAL_IDX],
+ err);
+
+ return err;
+}
+
+static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[AUTOGAIN_TARGET_IDX];
+
+ return 0;
+}
+
+static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err, totalpixels, brightpixels, darkpixels;
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ sensor_settings[AUTOGAIN_TARGET_IDX] = val;
+
+ /* Number of pixels counted by the sensor when subsampling the pixels.
+ * Slightly larger than the real value to avoid oscillation */
+ totalpixels = gspca_dev->width * gspca_dev->height;
+ totalpixels = totalpixels/(8*8) + totalpixels/(64*64);
+
+ brightpixels = (totalpixels * val) >> 8;
+ darkpixels = totalpixels - brightpixels;
+ err = stv06xx_write_sensor(sd, PB_R21, brightpixels);
+ if (!err)
+ err = stv06xx_write_sensor(sd, PB_R22, darkpixels);
+
+ PDEBUG(D_V4L2, "Set autogain target to %d, status: %d", val, err);
+
+ return err;
+}
+
+static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[NATURAL_IDX];
+
+ return 0;
+}
+
+static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ sensor_settings[NATURAL_IDX] = val;
+
+ return pb0100_set_autogain(gspca_dev, sensor_settings[AUTOGAIN_IDX]);
+}
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
new file mode 100644
index 000000000..4b47270aa
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * P/N 861037: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express
+ * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000 ASIC
+ * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web
+ */
+
+#ifndef STV06XX_PB0100_H_
+#define STV06XX_PB0100_H_
+
+#include "stv06xx_sensor.h"
+
+/* mode priv field flags */
+#define PB0100_CROP_TO_VGA 0x01
+#define PB0100_SUBSAMPLE 0x02
+
+/* I2C Registers */
+#define PB_IDENT 0x00 /* Chip Version */
+#define PB_RSTART 0x01 /* Row Window Start */
+#define PB_CSTART 0x02 /* Column Window Start */
+#define PB_RWSIZE 0x03 /* Row Window Size */
+#define PB_CWSIZE 0x04 /* Column Window Size */
+#define PB_CFILLIN 0x05 /* Column Fill-In */
+#define PB_VBL 0x06 /* Vertical Blank Count */
+#define PB_CONTROL 0x07 /* Control Mode */
+#define PB_FINTTIME 0x08 /* Integration Time/Frame Unit Count */
+#define PB_RINTTIME 0x09 /* Integration Time/Row Unit Count */
+#define PB_ROWSPEED 0x0a /* Row Speed Control */
+#define PB_ABORTFRAME 0x0b /* Abort Frame */
+#define PB_R12 0x0c /* Reserved */
+#define PB_RESET 0x0d /* Reset */
+#define PB_EXPGAIN 0x0e /* Exposure Gain Command */
+#define PB_R15 0x0f /* Expose0 */
+#define PB_R16 0x10 /* Expose1 */
+#define PB_R17 0x11 /* Expose2 */
+#define PB_R18 0x12 /* Low0_DAC */
+#define PB_R19 0x13 /* Low1_DAC */
+#define PB_R20 0x14 /* Low2_DAC */
+#define PB_R21 0x15 /* Threshold11 */
+#define PB_R22 0x16 /* Threshold0x */
+#define PB_UPDATEINT 0x17 /* Update Interval */
+#define PB_R24 0x18 /* High_DAC */
+#define PB_R25 0x19 /* Trans0H */
+#define PB_R26 0x1a /* Trans1L */
+#define PB_R27 0x1b /* Trans1H */
+#define PB_R28 0x1c /* Trans2L */
+#define PB_R29 0x1d /* Reserved */
+#define PB_R30 0x1e /* Reserved */
+#define PB_R31 0x1f /* Wait to Read */
+#define PB_PREADCTRL 0x20 /* Pixel Read Control Mode */
+#define PB_R33 0x21 /* IREF_VLN */
+#define PB_R34 0x22 /* IREF_VLP */
+#define PB_R35 0x23 /* IREF_VLN_INTEG */
+#define PB_R36 0x24 /* IREF_MASTER */
+#define PB_R37 0x25 /* IDACP */
+#define PB_R38 0x26 /* IDACN */
+#define PB_R39 0x27 /* DAC_Control_Reg */
+#define PB_R40 0x28 /* VCL */
+#define PB_R41 0x29 /* IREF_VLN_ADCIN */
+#define PB_R42 0x2a /* Reserved */
+#define PB_G1GAIN 0x2b /* Green 1 Gain */
+#define PB_BGAIN 0x2c /* Blue Gain */
+#define PB_RGAIN 0x2d /* Red Gain */
+#define PB_G2GAIN 0x2e /* Green 2 Gain */
+#define PB_R47 0x2f /* Dark Row Address */
+#define PB_R48 0x30 /* Dark Row Options */
+#define PB_R49 0x31 /* Reserved */
+#define PB_R50 0x32 /* Image Test Data */
+#define PB_ADCMAXGAIN 0x33 /* Maximum Gain */
+#define PB_ADCMINGAIN 0x34 /* Minimum Gain */
+#define PB_ADCGLOBALGAIN 0x35 /* Global Gain */
+#define PB_R54 0x36 /* Maximum Frame */
+#define PB_R55 0x37 /* Minimum Frame */
+#define PB_R56 0x38 /* Reserved */
+#define PB_VOFFSET 0x39 /* VOFFSET */
+#define PB_R58 0x3a /* Snap-Shot Sequence Trigger */
+#define PB_ADCGAINH 0x3b /* VREF_HI */
+#define PB_ADCGAINL 0x3c /* VREF_LO */
+#define PB_R61 0x3d /* Reserved */
+#define PB_R62 0x3e /* Reserved */
+#define PB_R63 0x3f /* Reserved */
+#define PB_R64 0x40 /* Red/Blue Gain */
+#define PB_R65 0x41 /* Green 2/Green 1 Gain */
+#define PB_R66 0x42 /* VREF_HI/LO */
+#define PB_R67 0x43 /* Integration Time/Row Unit Count */
+#define PB_R240 0xf0 /* ADC Test */
+#define PB_R241 0xf1 /* Chip Enable */
+#define PB_R242 0xf2 /* Reserved */
+
+static int pb0100_probe(struct sd *sd);
+static int pb0100_start(struct sd *sd);
+static int pb0100_init(struct sd *sd);
+static int pb0100_stop(struct sd *sd);
+static int pb0100_dump(struct sd *sd);
+
+/* V4L2 controls supported by the driver */
+static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val);
+static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val);
+static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val);
+
+const struct stv06xx_sensor stv06xx_sensor_pb0100 = {
+ .name = "PB-0100",
+ .i2c_flush = 1,
+ .i2c_addr = 0xba,
+ .i2c_len = 2,
+
+ .nctrls = 7,
+ .ctrls = {
+#define GAIN_IDX 0
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 128
+ },
+ .set = pb0100_set_gain,
+ .get = pb0100_get_gain
+ },
+#define RED_BALANCE_IDX 1
+ {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+ .minimum = -255,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = pb0100_set_red_balance,
+ .get = pb0100_get_red_balance
+ },
+#define BLUE_BALANCE_IDX 2
+ {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+ .minimum = -255,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = pb0100_set_blue_balance,
+ .get = pb0100_get_blue_balance
+ },
+#define EXPOSURE_IDX 3
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 0,
+ .maximum = 511,
+ .step = 1,
+ .default_value = 12
+ },
+ .set = pb0100_set_exposure,
+ .get = pb0100_get_exposure
+ },
+#define AUTOGAIN_IDX 4
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic Gain and Exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
+ },
+ .set = pb0100_set_autogain,
+ .get = pb0100_get_autogain
+ },
+#define AUTOGAIN_TARGET_IDX 5
+ {
+ {
+ .id = V4L2_CTRL_CLASS_USER + 0x1000,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Automatic Gain Target",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 128
+ },
+ .set = pb0100_set_autogain_target,
+ .get = pb0100_get_autogain_target
+ },
+#define NATURAL_IDX 6
+ {
+ {
+ .id = V4L2_CTRL_CLASS_USER + 0x1001,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Natural Light Source",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
+ },
+ .set = pb0100_set_natural,
+ .get = pb0100_get_natural
+ },
+ },
+
+ .init = pb0100_init,
+ .probe = pb0100_probe,
+ .start = pb0100_start,
+ .stop = pb0100_stop,
+ .dump = pb0100_dump,
+
+ .nmodes = 2,
+ .modes = {
+/* low res / subsample modes disabled as they are only half res horizontal,
+ halving the vertical resolution does not seem to work */
+#if 0
+ {
+ 160,
+ 120,
+ V4L2_PIX_FMT_SGRBG8,
+ V4L2_FIELD_NONE,
+ .sizeimage = 160 * 120 * 2,
+ .bytesperline = 160,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = PB0100_CROP_TO_VGA | PB0100_SUBSAMPLE
+ },
+ {
+ 176,
+ 144,
+ V4L2_PIX_FMT_SGRBG8,
+ V4L2_FIELD_NONE,
+ .sizeimage = 176 * 144 * 2,
+ .bytesperline = 176,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = PB0100_SUBSAMPLE
+ },
+#endif
+ {
+ 320,
+ 240,
+ V4L2_PIX_FMT_SGRBG8,
+ V4L2_FIELD_NONE,
+ .sizeimage = 320 * 240,
+ .bytesperline = 320,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = PB0100_CROP_TO_VGA
+ },
+ {
+ 352,
+ 288,
+ V4L2_PIX_FMT_SGRBG8,
+ V4L2_FIELD_NONE,
+ .sizeimage = 352 * 288,
+ .bytesperline = 352,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ },
+ }
+};
+
+#endif
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
new file mode 100644
index 000000000..c726dacef
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * P/N 861037: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express
+ * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000 ASIC
+ * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web
+ */
+
+#ifndef STV06XX_SENSOR_H_
+#define STV06XX_SENSOR_H_
+
+#include "stv06xx.h"
+
+#define IS_850(sd) ((sd)->gspca_dev.dev->descriptor.idProduct == 0x850)
+#define IS_870(sd) ((sd)->gspca_dev.dev->descriptor.idProduct == 0x870)
+#define IS_1020(sd) ((sd)->sensor == &stv06xx_sensor_hdcs1020)
+
+extern const struct stv06xx_sensor stv06xx_sensor_vv6410;
+extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00;
+extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020;
+extern const struct stv06xx_sensor stv06xx_sensor_pb0100;
+
+#define STV06XX_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
+
+struct stv06xx_sensor {
+ /* Defines the name of a sensor */
+ char name[32];
+
+ /* Sensor i2c address */
+ u8 i2c_addr;
+
+ /* Flush value*/
+ u8 i2c_flush;
+
+ /* length of an i2c word */
+ u8 i2c_len;
+
+ /* Probes if the sensor is connected */
+ int (*probe)(struct sd *sd);
+
+ /* Performs a initialization sequence */
+ int (*init)(struct sd *sd);
+
+ /* Executed at device disconnect */
+ void (*disconnect)(struct sd *sd);
+
+ /* Reads a sensor register */
+ int (*read_sensor)(struct sd *sd, const u8 address,
+ u8 *i2c_data, const u8 len);
+
+ /* Writes to a sensor register */
+ int (*write_sensor)(struct sd *sd, const u8 address,
+ u8 *i2c_data, const u8 len);
+
+ /* Instructs the sensor to start streaming */
+ int (*start)(struct sd *sd);
+
+ /* Instructs the sensor to stop streaming */
+ int (*stop)(struct sd *sd);
+
+ /* Instructs the sensor to dump all its contents */
+ int (*dump)(struct sd *sd);
+
+ int nctrls;
+ struct ctrl ctrls[STV06XX_MAX_CTRLS];
+
+ char nmodes;
+ struct v4l2_pix_format modes[];
+};
+
+#endif
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
new file mode 100644
index 000000000..1ca91f2a6
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * P/N 861037: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express
+ * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000 ASIC
+ * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web
+ */
+
+#include "stv06xx_vv6410.h"
+
+static int vv6410_probe(struct sd *sd)
+{
+ u16 data;
+ int err;
+
+ err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data);
+
+ if (err < 0)
+ return -ENODEV;
+
+ if (data == 0x19) {
+ info("vv6410 sensor detected");
+
+ sd->gspca_dev.cam.cam_mode = stv06xx_sensor_vv6410.modes;
+ sd->gspca_dev.cam.nmodes = stv06xx_sensor_vv6410.nmodes;
+ sd->desc.ctrls = stv06xx_sensor_vv6410.ctrls;
+ sd->desc.nctrls = stv06xx_sensor_vv6410.nctrls;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int vv6410_init(struct sd *sd)
+{
+ int err = 0, i;
+
+ for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) {
+ /* if NULL then len contains single value */
+ if (stv_bridge_init[i].data == NULL) {
+ err = stv06xx_write_bridge(sd,
+ stv_bridge_init[i].start,
+ stv_bridge_init[i].len);
+ } else {
+ int j;
+ for (j = 0; j < stv_bridge_init[i].len; j++)
+ err = stv06xx_write_bridge(sd,
+ stv_bridge_init[i].start + j,
+ stv_bridge_init[i].data[j]);
+ }
+ }
+
+ if (err < 0)
+ return err;
+
+ err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init,
+ ARRAY_SIZE(vv6410_sensor_init));
+
+ return (err < 0) ? err : 0;
+}
+
+static int vv6410_start(struct sd *sd)
+{
+ int err;
+ struct cam *cam = &sd->gspca_dev.cam;
+ u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
+
+ if (priv & VV6410_CROP_TO_QVGA) {
+ PDEBUG(D_CONF, "Cropping to QVGA");
+ stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1);
+ stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1);
+ } else {
+ stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1);
+ stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1);
+ }
+
+ if (priv & VV6410_SUBSAMPLE) {
+ PDEBUG(D_CONF, "Enabling subsampling");
+ stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02);
+ stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
+
+ stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
+ } else {
+ stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
+ stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
+
+ stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
+ }
+
+ /* Turn on LED */
+ err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON);
+ if (err < 0)
+ return err;
+
+ err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0);
+ if (err < 0)
+ return err;
+
+ PDEBUG(D_STREAM, "Starting stream");
+
+ return 0;
+}
+
+static int vv6410_stop(struct sd *sd)
+{
+ int err;
+
+ /* Turn off LED */
+ err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF);
+ if (err < 0)
+ return err;
+
+ err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE);
+ if (err < 0)
+ return err;
+
+ PDEBUG(D_STREAM, "Halting stream");
+
+ return (err < 0) ? err : 0;
+}
+
+static int vv6410_dump(struct sd *sd)
+{
+ u8 i;
+ int err = 0;
+
+ info("Dumping all vv6410 sensor registers");
+ for (i = 0; i < 0xff && !err; i++) {
+ u16 data;
+ err = stv06xx_read_sensor(sd, i, &data);
+ info("Register 0x%x contained 0x%x", i, data);
+ }
+ return (err < 0) ? err : 0;
+}
+
+static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ int err;
+ u16 i2c_data;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
+
+ *val = (i2c_data & VV6410_HFLIP) ? 1 : 0;
+
+ PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
+
+ return (err < 0) ? err : 0;
+}
+
+static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ u16 i2c_data;
+ struct sd *sd = (struct sd *) gspca_dev;
+ err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
+ if (err < 0)
+ return err;
+
+ if (val)
+ i2c_data |= VV6410_HFLIP;
+ else
+ i2c_data &= ~VV6410_HFLIP;
+
+ PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
+ err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
+
+ return (err < 0) ? err : 0;
+}
+
+static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ int err;
+ u16 i2c_data;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
+
+ *val = (i2c_data & VV6410_VFLIP) ? 1 : 0;
+
+ PDEBUG(D_V4L2, "Read vertical flip %d", *val);
+
+ return (err < 0) ? err : 0;
+}
+
+static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ u16 i2c_data;
+ struct sd *sd = (struct sd *) gspca_dev;
+ err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
+ if (err < 0)
+ return err;
+
+ if (val)
+ i2c_data |= VV6410_VFLIP;
+ else
+ i2c_data &= ~VV6410_VFLIP;
+
+ PDEBUG(D_V4L2, "Set vertical flip to %d", val);
+ err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
+
+ return (err < 0) ? err : 0;
+}
+
+static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ int err;
+ u16 i2c_data;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ err = stv06xx_read_sensor(sd, VV6410_ANALOGGAIN, &i2c_data);
+
+ *val = i2c_data & 0xf;
+
+ PDEBUG(D_V4L2, "Read analog gain %d", *val);
+
+ return (err < 0) ? err : 0;
+}
+
+static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ PDEBUG(D_V4L2, "Set analog gain to %d", val);
+ err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf));
+
+ return (err < 0) ? err : 0;
+}
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
new file mode 100644
index 000000000..3ff8c4ea3
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * P/N 861037: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express
+ * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000 ASIC
+ * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web
+ */
+
+#ifndef STV06XX_VV6410_H_
+#define STV06XX_VV6410_H_
+
+#include "stv06xx_sensor.h"
+
+#define VV6410_COLS 416
+#define VV6410_ROWS 320
+
+/* Status registers */
+/* Chip identification number including revision indicator */
+#define VV6410_DEVICEH 0x00
+#define VV6410_DEVICEL 0x01
+
+/* User can determine whether timed I2C data
+ has been consumed by interrogating flag states */
+#define VV6410_STATUS0 0x02
+
+/* Current line counter value */
+#define VV6410_LINECOUNTH 0x03
+#define VV6410_LINECOUNTL 0x04
+
+/* End x coordinate of image size */
+#define VV6410_XENDH 0x05
+#define VV6410_XENDL 0x06
+
+/* End y coordinate of image size */
+#define VV6410_YENDH 0x07
+#define VV6410_YENDL 0x08
+
+/* This is the average pixel value returned from the
+ dark line offset cancellation algorithm */
+#define VV6410_DARKAVGH 0x09
+#define VV6410_DARKAVGL 0x0a
+
+/* This is the average pixel value returned from the
+ black line offset cancellation algorithm */
+#define VV6410_BLACKAVGH 0x0b
+#define VV6410_BLACKAVGL 0x0c
+
+/* Flags to indicate whether the x or y image coordinates have been clipped */
+#define VV6410_STATUS1 0x0d
+
+/* Setup registers */
+
+/* Low-power/sleep modes & video timing */
+#define VV6410_SETUP0 0x10
+
+/* Various parameters */
+#define VV6410_SETUP1 0x11
+
+/* Contains pixel counter reset value used by external sync */
+#define VV6410_SYNCVALUE 0x12
+
+/* Frame grabbing modes (FST, LST and QCK) */
+#define VV6410_FGMODES 0x14
+
+/* FST and QCK mapping modes. */
+#define VV6410_PINMAPPING 0x15
+
+/* Data resolution */
+#define VV6410_DATAFORMAT 0x16
+
+/* Output coding formats */
+#define VV6410_OPFORMAT 0x17
+
+/* Various mode select bits */
+#define VV6410_MODESELECT 0x18
+
+/* Exposure registers */
+/* Fine exposure. */
+#define VV6410_FINEH 0x20
+#define VV6410_FINEL 0x21
+
+/* Coarse exposure */
+#define VV6410_COARSEH 0x22
+#define VV6410_COARSEL 0x23
+
+/* Analog gain setting */
+#define VV6410_ANALOGGAIN 0x24
+
+/* Clock division */
+#define VV6410_CLKDIV 0x25
+
+/* Dark line offset cancellation value */
+#define VV6410_DARKOFFSETH 0x2c
+#define VV6410_DARKOFFSETL 0x2d
+
+/* Dark line offset cancellation enable */
+#define VV6410_DARKOFFSETSETUP 0x2e
+
+/* Video timing registers */
+/* Line Length (Pixel Clocks) */
+#define VV6410_LINELENGTHH 0x52
+#define VV6410_LINELENGTHL 0x53
+
+/* X-co-ordinate of top left corner of region of interest (x-offset) */
+#define VV6410_XOFFSETH 0x57
+#define VV6410_XOFFSETL 0x58
+
+/* Y-coordinate of top left corner of region of interest (y-offset) */
+#define VV6410_YOFFSETH 0x59
+#define VV6410_YOFFSETL 0x5a
+
+/* Field length (Lines) */
+#define VV6410_FIELDLENGTHH 0x61
+#define VV6410_FIELDLENGTHL 0x62
+
+/* System registers */
+/* Black offset cancellation default value */
+#define VV6410_BLACKOFFSETH 0x70
+#define VV6410_BLACKOFFSETL 0x71
+
+/* Black offset cancellation setup */
+#define VV6410_BLACKOFFSETSETUP 0x72
+
+/* Analog Control Register 0 */
+#define VV6410_CR0 0x75
+
+/* Analog Control Register 1 */
+#define VV6410_CR1 0x76
+
+/* ADC Setup Register */
+#define VV6410_AS0 0x77
+
+/* Analog Test Register */
+#define VV6410_AT0 0x78
+
+/* Audio Amplifier Setup Register */
+#define VV6410_AT1 0x79
+
+#define VV6410_HFLIP (1 << 3)
+#define VV6410_VFLIP (1 << 4)
+
+#define VV6410_LOW_POWER_MODE (1 << 0)
+#define VV6410_SOFT_RESET (1 << 2)
+#define VV6410_PAL_25_FPS (0 << 3)
+
+#define VV6410_CLK_DIV_2 (1 << 1)
+
+#define VV6410_FINE_EXPOSURE 320
+#define VV6410_COARSE_EXPOSURE 192
+#define VV6410_DEFAULT_GAIN 5
+
+#define VV6410_SUBSAMPLE 0x01
+#define VV6410_CROP_TO_QVGA 0x02
+
+static int vv6410_probe(struct sd *sd);
+static int vv6410_start(struct sd *sd);
+static int vv6410_init(struct sd *sd);
+static int vv6410_stop(struct sd *sd);
+static int vv6410_dump(struct sd *sd);
+
+/* V4L2 controls supported by the driver */
+static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val);
+
+const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
+ .name = "ST VV6410",
+ .i2c_flush = 5,
+ .i2c_addr = 0x20,
+ .i2c_len = 1,
+ .init = vv6410_init,
+ .probe = vv6410_probe,
+ .start = vv6410_start,
+ .stop = vv6410_stop,
+ .dump = vv6410_dump,
+
+ .nctrls = 3,
+ .ctrls = {
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = vv6410_set_hflip,
+ .get = vv6410_get_hflip
+ }, {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = vv6410_set_vflip,
+ .get = vv6410_get_vflip
+ }, {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "analog gain",
+ .minimum = 0,
+ .maximum = 15,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = vv6410_set_analog_gain,
+ .get = vv6410_get_analog_gain
+ }
+ },
+
+ .nmodes = 1,
+ .modes = {
+ {
+ 356,
+ 292,
+ V4L2_PIX_FMT_SGRBG8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 356 * 292,
+ .bytesperline = 356,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ }
+ }
+};
+
+/* If NULL, only single value to write, stored in len */
+struct stv_init {
+ const u8 *data;
+ u16 start;
+ u8 len;
+};
+
+static const u8 x1500[] = { /* 0x1500 - 0x150f */
+ 0x0b, 0xa7, 0xb7, 0x00, 0x00
+};
+
+static const u8 x1536[] = { /* 0x1536 - 0x153b */
+ 0x02, 0x00, 0x60, 0x01, 0x20, 0x01
+};
+
+static const u8 x15c1[] = { /* 0x15c1 - 0x15c2 */
+ 0xff, 0x03 /* Output word 0x03ff = 1023 (ISO size) */
+};
+
+static const struct stv_init stv_bridge_init[] = {
+ /* This reg is written twice. Some kind of reset? */
+ {NULL, 0x1620, 0x80},
+ {NULL, 0x1620, 0x00},
+ {NULL, 0x1423, 0x04},
+ {x1500, 0x1500, ARRAY_SIZE(x1500)},
+ {x1536, 0x1536, ARRAY_SIZE(x1536)},
+ {x15c1, 0x15c1, ARRAY_SIZE(x15c1)}
+};
+
+static const u8 vv6410_sensor_init[][2] = {
+ /* Setup registers */
+ {VV6410_SETUP0, VV6410_SOFT_RESET},
+ {VV6410_SETUP0, VV6410_LOW_POWER_MODE},
+ /* Use shuffled read-out mode */
+ {VV6410_SETUP1, BIT(6)},
+ /* All modes to 1 */
+ {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)},
+ {VV6410_PINMAPPING, 0x00},
+ /* Pre-clock generator divide off */
+ {VV6410_DATAFORMAT, BIT(7) | BIT(0)},
+
+ /* Exposure registers */
+ {VV6410_FINEH, VV6410_FINE_EXPOSURE >> 8},
+ {VV6410_FINEL, VV6410_FINE_EXPOSURE & 0xff},
+ {VV6410_COARSEH, VV6410_COARSE_EXPOSURE >> 8},
+ {VV6410_COARSEL, VV6410_COARSE_EXPOSURE & 0xff},
+ {VV6410_ANALOGGAIN, 0xf0 | VV6410_DEFAULT_GAIN},
+ {VV6410_CLKDIV, VV6410_CLK_DIV_2},
+
+ /* System registers */
+ /* Enable voltage doubler */
+ {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)},
+ {VV6410_AT0, 0x00},
+ /* Power up audio, differential */
+ {VV6410_AT1, BIT(4)|BIT(0)},
+};
+
+#endif
diff --git a/linux/drivers/media/video/gspca/sunplus.c b/linux/drivers/media/video/gspca/sunplus.c
index 3a972ff1c..3692062d0 100644
--- a/linux/drivers/media/video/gspca/sunplus.c
+++ b/linux/drivers/media/video/gspca/sunplus.c
@@ -123,7 +123,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -136,7 +136,7 @@ static struct v4l2_pix_format vga_mode[] = {
.priv = 1},
};
-static struct v4l2_pix_format custom_mode[] = {
+static const struct v4l2_pix_format custom_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -149,7 +149,7 @@ static struct v4l2_pix_format custom_mode[] = {
.priv = 1},
};
-static struct v4l2_pix_format vga_mode2[] = {
+static const struct v4l2_pix_format vga_mode2[] = {
{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 176,
.sizeimage = 176 * 144 * 3 / 8 + 590,
diff --git a/linux/drivers/media/video/gspca/t613.c b/linux/drivers/media/video/gspca/t613.c
index d2d6ad9d1..2d032aa0e 100644
--- a/linux/drivers/media/video/gspca/t613.c
+++ b/linux/drivers/media/video/gspca/t613.c
@@ -233,7 +233,7 @@ static char *effects_control[] = {
"Negative",
};
-static struct v4l2_pix_format vga_mode_t16[] = {
+static const struct v4l2_pix_format vga_mode_t16[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120 * 4 / 8 + 590,
@@ -499,7 +499,7 @@ static void om6802_sensor_init(struct gspca_dev *gspca_dev)
reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
msleep(5);
i = 4;
- while (--i < 0) {
+ while (--i > 0) {
byte = reg_r(gspca_dev, 0x0060);
if (!(byte & 0x01))
break;
diff --git a/linux/drivers/media/video/gspca/tv8532.c b/linux/drivers/media/video/gspca/tv8532.c
index 4e18f90ba..7d11a0d3e 100644
--- a/linux/drivers/media/video/gspca/tv8532.c
+++ b/linux/drivers/media/video/gspca/tv8532.c
@@ -73,7 +73,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
{176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 176,
.sizeimage = 176 * 144,
diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c
index f6fae60ae..82dc818f4 100644
--- a/linux/drivers/media/video/gspca/vc032x.c
+++ b/linux/drivers/media/video/gspca/vc032x.c
@@ -32,44 +32,68 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- unsigned char autogain;
- unsigned char lightfreq;
+ __u8 hflip;
+ __u8 vflip;
+ __u8 lightfreq;
+ __u8 sharpness;
- char qindex;
char bridge;
#define BRIDGE_VC0321 0
#define BRIDGE_VC0323 1
char sensor;
#define SENSOR_HV7131R 0
-#define SENSOR_MI1320 1
-#define SENSOR_MI1310_SOC 2
-#define SENSOR_OV7660 3
-#define SENSOR_OV7670 4
-#define SENSOR_PO3130NC 5
+#define SENSOR_MI0360 1
+#define SENSOR_MI1320 2
+#define SENSOR_MI1310_SOC 3
+#define SENSOR_OV7660 4
+#define SENSOR_OV7670 5
+#define SENSOR_PO1200 6
+#define SENSOR_PO3130NC 7
};
/* V4L2 controls supported by the driver */
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
+/* next 2 controls work with ov7660 and ov7670 only */
+#define HFLIP_IDX 0
{
{
- .id = V4L2_CID_AUTOGAIN,
+ .id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Gain",
+ .name = "Mirror",
.minimum = 0,
.maximum = 1,
.step = 1,
-#define AUTOGAIN_DEF 1
- .default_value = AUTOGAIN_DEF,
+#define HFLIP_DEF 0
+ .default_value = HFLIP_DEF,
},
- .set = sd_setautogain,
- .get = sd_getautogain,
+ .set = sd_sethflip,
+ .get = sd_gethflip,
},
-#define LIGHTFREQ_IDX 1
+#define VFLIP_IDX 1
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vflip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define VFLIP_DEF 0
+ .default_value = VFLIP_DEF,
+ },
+ .set = sd_setvflip,
+ .get = sd_getvflip,
+ },
+#define LIGHTFREQ_IDX 2
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -84,9 +108,25 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setfreq,
.get = sd_getfreq,
},
+/* po1200 only */
+#define SHARPNESS_IDX 3
+ {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sharpness",
+ .minimum = 0,
+ .maximum = 2,
+ .step = 1,
+#define SHARPNESS_DEF 1
+ .default_value = SHARPNESS_DEF,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
};
-static struct v4l2_pix_format vc0321_mode[] = {
+static const struct v4l2_pix_format vc0321_mode[] = {
{320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 2,
@@ -98,7 +138,7 @@ static struct v4l2_pix_format vc0321_mode[] = {
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0},
};
-static struct v4l2_pix_format vc0323_mode[] = {
+static const struct v4l2_pix_format vc0323_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -111,15 +151,252 @@ static struct v4l2_pix_format vc0323_mode[] = {
.priv = 0},
};
-#if 0
-static const __u8 mi1310soc_gamma[17] = {
- 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
- 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+static const struct v4l2_pix_format svga_mode[] = {
+ {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 800,
+ .sizeimage = 800 * 600 * 1 / 4 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
};
-static const __u8 mi1310soc_matrix[9] = {
- 0x56, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x58
+
+/* OV7660/7670 registers */
+#define OV7660_REG_MVFP 0x1e
+#define OV7660_MVFP_MIRROR 0x20
+#define OV7660_MVFP_VFLIP 0x10
+
+static const __u8 mi0360_matrix[9] = {
+ 0x50, 0xf8, 0xf8, 0xf5, 0x50, 0xfb, 0xff, 0xf1, 0x50
};
-#endif
+
+static const __u8 mi0360_initVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xb8, 0x00, 0x13, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc},
+ {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc},
+ {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc},
+ {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc},
+ {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x50, 0xcc},
+ {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc},
+ {0xb8, 0x37, 0x00, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc},
+ {0xb8, 0x08, 0xe0, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc},
+ {0xb8, 0x14, 0x18, 0xcc},
+ {0xb8, 0xb2, 0x0a, 0xcc},
+ {0xb8, 0xb4, 0x0a, 0xcc},
+ {0xb8, 0xb5, 0x0a, 0xcc},
+ {0xb8, 0xfe, 0x00, 0xcc},
+ {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc},
+ {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc},
+ {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc},
+ {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc},
+ {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc},
+ {0x31, 0x00, 0x00, 0xbb},
+ {0x09, 0x01, 0xc7, 0xbb},
+ {0x34, 0x01, 0x00, 0xbb},
+ {0x2b, 0x00, 0x28, 0xbb},
+ {0x2c, 0x00, 0x30, 0xbb},
+ {0x2d, 0x00, 0x30, 0xbb},
+ {0x2e, 0x00, 0x28, 0xbb},
+ {0x62, 0x04, 0x11, 0xbb},
+ {0x03, 0x01, 0xe0, 0xbb},
+ {0x2c, 0x00, 0x2c, 0xbb},
+ {0x20, 0xd0, 0x00, 0xbb},
+ {0x01, 0x00, 0x08, 0xbb},
+ {0x06, 0x00, 0x10, 0xbb},
+ {0x05, 0x00, 0x20, 0xbb},
+ {0x20, 0x00, 0x00, 0xbb},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x02, 0xcc},
+ {0xb6, 0x02, 0x80, 0xcc},
+ {0xb6, 0x05, 0x01, 0xcc},
+ {0xb6, 0x04, 0xe0, 0xcc},
+ {0xb6, 0x12, 0x78, 0xcc},
+ {0xb6, 0x18, 0x02, 0xcc},
+ {0xb6, 0x17, 0x58, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x10, 0xcc},
+ {0xb9, 0x12, 0x00, 0xcc},
+ {0xb9, 0x13, 0x0a, 0xcc},
+ {0xb9, 0x14, 0x0a, 0xcc},
+ {0xb9, 0x15, 0x0a, 0xcc},
+ {0xb9, 0x16, 0x0a, 0xcc},
+ {0xb9, 0x18, 0x00, 0xcc},
+ {0xb9, 0x19, 0x0f, 0xcc},
+ {0xb9, 0x1a, 0x0f, 0xcc},
+ {0xb9, 0x1b, 0x0f, 0xcc},
+ {0xb9, 0x1c, 0x0f, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb8, 0x0c, 0x20, 0xcc},
+ {0xb8, 0x0d, 0x70, 0xcc},
+ {0xb6, 0x13, 0x13, 0xcc},
+ {0x35, 0x00, 0x60, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+static const __u8 mi0360_initQVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc},
+ {0xbc, 0x00, 0xd1, 0xcc},
+ {0xb8, 0x00, 0x13, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc},
+ {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc},
+ {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc},
+ {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc},
+ {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x50, 0xcc},
+ {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc},
+ {0xb8, 0x37, 0x00, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc},
+ {0xb8, 0x08, 0xe0, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc},
+ {0xb8, 0x14, 0x18, 0xcc},
+ {0xb8, 0xb2, 0x0a, 0xcc},
+ {0xb8, 0xb4, 0x0a, 0xcc},
+ {0xb8, 0xb5, 0x0a, 0xcc},
+ {0xb8, 0xfe, 0x00, 0xcc},
+ {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc},
+ {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc},
+ {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc},
+ {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc},
+ {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc},
+ {0x31, 0x00, 0x00, 0xbb},
+ {0x09, 0x01, 0xc7, 0xbb},
+ {0x34, 0x01, 0x00, 0xbb},
+ {0x2b, 0x00, 0x28, 0xbb},
+ {0x2c, 0x00, 0x30, 0xbb},
+ {0x2d, 0x00, 0x30, 0xbb},
+ {0x2e, 0x00, 0x28, 0xbb},
+ {0x62, 0x04, 0x11, 0xbb},
+ {0x03, 0x01, 0xe0, 0xbb},
+ {0x2c, 0x00, 0x2c, 0xbb},
+ {0x20, 0xd0, 0x00, 0xbb},
+ {0x01, 0x00, 0x08, 0xbb},
+ {0x06, 0x00, 0x10, 0xbb},
+ {0x05, 0x00, 0x20, 0xbb},
+ {0x20, 0x00, 0x00, 0xbb},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x01, 0xcc},
+ {0xb6, 0x02, 0x40, 0xcc},
+ {0xb6, 0x05, 0x00, 0xcc},
+ {0xb6, 0x04, 0xf0, 0xcc},
+ {0xb6, 0x12, 0x78, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc},
+ {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x10, 0xcc},
+ {0xb9, 0x12, 0x00, 0xcc},
+ {0xb9, 0x13, 0x0a, 0xcc},
+ {0xb9, 0x14, 0x0a, 0xcc},
+ {0xb9, 0x15, 0x0a, 0xcc},
+ {0xb9, 0x16, 0x0a, 0xcc},
+ {0xb9, 0x18, 0x00, 0xcc},
+ {0xb9, 0x19, 0x0f, 0xcc},
+ {0xb9, 0x1a, 0x0f, 0xcc},
+ {0xb9, 0x1b, 0x0f, 0xcc},
+ {0xb9, 0x1c, 0x0f, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x13, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc},
+ {0xb8, 0x0c, 0x20, 0xcc},
+ {0xb8, 0x0d, 0x70, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+ {0x35, 0x00, 0xef, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+
static const __u8 mi1310_socinitVGA_JPG[][4] = {
{0xb0, 0x03, 0x19, 0xcc},
{0xb0, 0x04, 0x02, 0xcc},
@@ -832,7 +1109,7 @@ static const __u8 ov7660_initVGA_data[][4] = {
{0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa},
{0x00, 0x12, 0x80, 0xaa},
{0x00, 0x12, 0x05, 0xaa},
- {0x00, 0x1e, 0x01, 0xaa},
+ {0x00, 0x1e, 0x01, 0xaa}, /* MVFP */
{0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
{0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
{0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa},
@@ -886,7 +1163,7 @@ static const __u8 ov7660_initQVGA_data[][4] = {
{0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x8f, 0x50, 0xcc},
{0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa},
{0x00, 0x12, 0x80, 0xaa}, {0x00, 0x12, 0x05, 0xaa},
- {0x00, 0x1e, 0x01, 0xaa},
+ {0x00, 0x1e, 0x01, 0xaa}, /* MVFP */
{0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
{0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
{0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa},
@@ -992,7 +1269,8 @@ static const __u8 ov7670_initVGA_JPG[][4] = {
{0x00, 0xa9, 0x90, 0xaa}, {0x00, 0xaa, 0x14, 0xaa},
{0x00, 0x13, 0xe5, 0xaa}, {0x00, 0x0e, 0x61, 0xaa},
{0x00, 0x0f, 0x4b, 0xaa}, {0x00, 0x16, 0x02, 0xaa},
- {0x00, 0x1e, 0x07, 0xaa}, {0x00, 0x21, 0x02, 0xaa},
+ {0x00, 0x1e, 0x07, 0xaa}, /* MVFP */
+ {0x00, 0x21, 0x02, 0xaa},
{0x00, 0x22, 0x91, 0xaa}, {0x00, 0x29, 0x07, 0xaa},
{0x00, 0x33, 0x0b, 0xaa}, {0x00, 0x35, 0x0b, 0xaa},
{0x00, 0x37, 0x1d, 0xaa}, {0x00, 0x38, 0x71, 0xaa},
@@ -1057,7 +1335,8 @@ static const __u8 ov7670_initVGA_JPG[][4] = {
{0x00, 0x71, 0x35, 0xaa}, {0x00, 0x72, 0x11, 0xaa},
{0x00, 0x73, 0xf0, 0xaa}, {0x00, 0xa2, 0x02, 0xaa},
{0x00, 0xb1, 0x00, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa},
- {0x00, 0x1e, 0x37, 0xaa}, {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x1e, 0x37, 0xaa}, /* MVFP */
+ {0x00, 0xaa, 0x14, 0xaa},
{0x00, 0x24, 0x80, 0xaa}, {0x00, 0x25, 0x74, 0xaa},
{0x00, 0x26, 0xd3, 0xaa}, {0x00, 0x0d, 0x00, 0xaa},
{0x00, 0x14, 0x18, 0xaa}, {0x00, 0x9d, 0x99, 0xaa},
@@ -1119,7 +1398,8 @@ static const __u8 ov7670_initQVGA_JPG[][4] = {
{0x00, 0xa9, 0x90, 0xaa}, {0x00, 0xaa, 0x14, 0xaa},
{0x00, 0x13, 0xe5, 0xaa}, {0x00, 0x0e, 0x61, 0xaa},
{0x00, 0x0f, 0x4b, 0xaa}, {0x00, 0x16, 0x02, 0xaa},
- {0x00, 0x1e, 0x07, 0xaa}, {0x00, 0x21, 0x02, 0xaa},
+ {0x00, 0x1e, 0x07, 0xaa}, /* MVFP */
+ {0x00, 0x21, 0x02, 0xaa},
{0x00, 0x22, 0x91, 0xaa}, {0x00, 0x29, 0x07, 0xaa},
{0x00, 0x33, 0x0b, 0xaa}, {0x00, 0x35, 0x0b, 0xaa},
{0x00, 0x37, 0x1d, 0xaa}, {0x00, 0x38, 0x71, 0xaa},
@@ -1184,7 +1464,8 @@ static const __u8 ov7670_initQVGA_JPG[][4] = {
{0x00, 0x71, 0x35, 0xaa}, {0x00, 0x72, 0x11, 0xaa},
{0x00, 0x73, 0xf0, 0xaa}, {0x00, 0xa2, 0x02, 0xaa},
{0x00, 0xb1, 0x00, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa},
- {0x00, 0x1e, 0x37, 0xaa}, {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x1e, 0x37, 0xaa}, /* MVFP */
+ {0x00, 0xaa, 0x14, 0xaa},
{0x00, 0x24, 0x80, 0xaa}, {0x00, 0x25, 0x74, 0xaa},
{0x00, 0x26, 0xd3, 0xaa}, {0x00, 0x0d, 0x00, 0xaa},
{0x00, 0x14, 0x18, 0xaa}, {0x00, 0x9d, 0x99, 0xaa},
@@ -1212,177 +1493,301 @@ static const __u8 ov7670_initQVGA_JPG[][4] = {
{0x00, 0x77, 0x05, 0xaa },
{},
};
+
+/* PO1200 - values from usbvm326.inf and ms-win trace */
+static const __u8 po1200_gamma[17] = {
+#if 1
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+#else
+/*ms-win trace*/
+ 0x01, 0x0b, 0x1e, 0x38, 0x51, 0x6b, 0x83, 0x9a, 0xaf,
+ 0xc1, 0xd0, 0xdd, 0xe8, 0xf2, 0xf9, 0xff, 0xff
+#endif
+};
+static const __u8 po1200_matrix[9] = {
+ 0x60, 0xf9, 0xe5, 0xe7, 0x50, 0x05, 0xf3, 0xe6, 0x5e
+};
+static const __u8 po1200_initVGA_data[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc}, /* reset? */
#if 0
-static const __u8 ov7670_initQVGA_JPG[][4] = {
- {0xb3, 0x00, 0x00, 0xcc},
- {0xb0, 0x16, 0x0d, 0xcc},
- {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x16, 0x00, 0xcc},
- {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x19, 0xcc},
- {0x00, 0x00, 0x50, 0xdd}, {0xb3, 0x49, 0x11, 0xcc},
- {0xb3, 0x49, 0x00, 0xcc}, {0xb0, 0x16, 0x00, 0xcc},
-
- {0xb3, 0x01, 0x05, 0xcc}, {0x00, 0x00, 0x50, 0xdd},
- {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc},
- {0x00, 0x00, 0x50, 0xdd}, {0xb3, 0x00, 0x66, 0xcc},
- {0xb3, 0x00, 0x67, 0xcc}, {0xb3, 0x35, 0xa1, 0xcc},
- {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x02, 0x02, 0xcc},
- {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc},
- {0xbc, 0x00, 0xd1, 0xcc}, /* set QVGA */
- {0xbc, 0x01, 0x01, 0xcc},/* */
- {0x00, 0x12, 0x80, 0xaa},/* OV sensor reset */
- {0x00, 0x00, 0x50, 0xdd},/* wait sometimes */
- {0, 0x12, 0x00, 0xaa},
- {0, 0x11, 0x40, 0xaa}, {0, 0x6b, 0x0a, 0xaa},
- {0, 0x3a, 0x04, 0xaa}, {0, 0x40, 0xc0, 0xaa},
- {0, 0x8c, 0x00, 0xaa}, {0, 0x7a, 0x29, 0xaa},
- {0, 0x7b, 0x0e, 0xaa}, {0, 0x7c, 0x1a, 0xaa},
- {0, 0x7d, 0x31, 0xaa}, {0, 0x7e, 0x53, 0xaa},
- {0, 0x7f, 0x60, 0xaa}, {0, 0x80, 0x6b, 0xaa},
- {0, 0x81, 0x73, 0xaa}, {0, 0x82, 0x7b, 0xaa},
- {0, 0x83, 0x82, 0xaa}, {0, 0x84, 0x89, 0xaa},
- {0, 0x85, 0x96, 0xaa}, {0, 0x86, 0xa1, 0xaa},
- {0, 0x87, 0xb7, 0xaa}, {0, 0x88, 0xcc, 0xaa},
- {0, 0x89, 0xe1, 0xaa}, {0, 0x13, 0xe0, 0xaa},
- {0, 0x00, 0x00, 0xaa}, {0, 0x10, 0x00, 0xaa},
- {0, 0x0d, 0x40, 0xaa}, {0, 0x14, 0x28, 0xaa},
- {0, 0xa5, 0x05, 0xaa}, {0, 0xab, 0x07, 0xaa},
- {0, 0x24, 0x95, 0xaa}, {0, 0x25, 0x33, 0xaa},
- {0, 0x26, 0xe3, 0xaa}, {0, 0x9f, 0x88, 0xaa},
- {0, 0xa0, 0x78, 0xaa}, {0, 0x55, 0x90, 0xaa},
- {0, 0xa1, 0x03, 0xaa}, {0, 0xa6, 0xe0, 0xaa},
- {0, 0xa7, 0xd8, 0xaa}, {0, 0xa8, 0xf0, 0xaa},
- {0, 0xa9, 0x90, 0xaa}, {0, 0xaa, 0x14, 0xaa},
- {0, 0x13, 0xe5, 0xaa}, {0, 0x0e, 0x61, 0xaa},
- {0, 0x0f, 0x4b, 0xaa}, {0, 0x16, 0x02, 0xaa},
- {0, 0x1e, 0x07, 0xaa}, {0, 0x21, 0x02, 0xaa},
- {0, 0x22, 0x91, 0xaa}, {0, 0x29, 0x07, 0xaa},
- {0, 0x33, 0x0b, 0xaa}, {0, 0x35, 0x0b, 0xaa},
- {0, 0x37, 0x1d, 0xaa}, {0, 0x38, 0x71, 0xaa},
- {0, 0x39, 0x2a, 0xaa}, {0, 0x3c, 0x78, 0xaa},
- {0, 0x4d, 0x40, 0xaa}, {0, 0x4e, 0x20, 0xaa},
- {0, 0x74, 0x19, 0xaa}, {0, 0x8d, 0x4f, 0xaa},
- {0, 0x8e, 0x00, 0xaa}, {0, 0x8f, 0x00, 0xaa},
- {0, 0x90, 0x00, 0xaa}, {0, 0x91, 0x00, 0xaa},
- {0, 0x96, 0x00, 0xaa}, {0, 0x9a, 0x80, 0xaa},
- {0, 0xb0, 0x84, 0xaa}, {0, 0xb1, 0x0c, 0xaa},
- {0, 0xb2, 0x0e, 0xaa}, {0, 0xb3, 0x82, 0xaa},
- {0, 0xb8, 0x0a, 0xaa}, {0, 0x43, 0x14, 0xaa},
- {0, 0x44, 0xf0, 0xaa}, {0, 0x45, 0x45, 0xaa},
- {0, 0x46, 0x63, 0xaa}, {0, 0x47, 0x2d, 0xaa},
- {0, 0x48, 0x46, 0xaa}, {0, 0x59, 0x88, 0xaa},
- {0, 0x5a, 0xa0, 0xaa}, {0, 0x5b, 0xc6, 0xaa},
- {0, 0x5c, 0x7d, 0xaa}, {0, 0x5d, 0x5f, 0xaa},
- {0, 0x5e, 0x19, 0xaa}, {0, 0x6c, 0x0a, 0xaa},
- {0, 0x6d, 0x55, 0xaa}, {0, 0x6e, 0x11, 0xaa},
- {0, 0x6f, 0x9e, 0xaa}, {0, 0x69, 0x00, 0xaa},
- {0, 0x6a, 0x40, 0xaa}, {0, 0x01, 0x40, 0xaa},
- {0, 0x02, 0x40, 0xaa}, {0, 0x13, 0xe7, 0xaa},
- {0, 0x5f, 0xf0, 0xaa}, {0, 0x60, 0xf0, 0xaa},
- {0, 0x61, 0xf0, 0xaa}, {0, 0x27, 0xa0, 0xaa},
- {0, 0x28, 0x80, 0xaa}, {0, 0x2c, 0x90, 0xaa},
- {0, 0x4f, 0x66, 0xaa}, {0, 0x50, 0x66, 0xaa},
- {0, 0x51, 0x00, 0xaa}, {0, 0x52, 0x22, 0xaa},
- {0, 0x53, 0x5e, 0xaa}, {0, 0x54, 0x80, 0xaa},
- {0, 0x58, 0x9e, 0xaa}, {0, 0x41, 0x08, 0xaa},
- {0, 0x3f, 0x00, 0xaa}, {0, 0x75, 0x85, 0xaa},
- {0, 0x76, 0xe1, 0xaa}, {0, 0x4c, 0x00, 0xaa},
- {0, 0x77, 0x0a, 0xaa}, {0, 0x3d, 0x88, 0xaa},
- {0, 0x4b, 0x09, 0xaa}, {0, 0xc9, 0x60, 0xaa},
- {0, 0x41, 0x38, 0xaa}, {0, 0x62, 0x30, 0xaa},
- {0, 0x63, 0x30, 0xaa}, {0, 0x64, 0x08, 0xaa},
- {0, 0x94, 0x07, 0xaa}, {0, 0x95, 0x0b, 0xaa},
- {0, 0x65, 0x00, 0xaa}, {0, 0x66, 0x05, 0xaa},
- {0, 0x56, 0x50, 0xaa}, {0, 0x34, 0x11, 0xaa},
- {0, 0xa4, 0x88, 0xaa}, {0, 0x96, 0x00, 0xaa},
- {0, 0x97, 0x30, 0xaa}, {0, 0x98, 0x20, 0xaa},
- {0, 0x99, 0x30, 0xaa}, {0, 0x9a, 0x84, 0xaa},
- {0, 0x9b, 0x29, 0xaa}, {0, 0x9c, 0x03, 0xaa},
- {0, 0x78, 0x04, 0xaa}, {0, 0x79, 0x01, 0xaa},
- {0, 0xc8, 0xf0, 0xaa}, {0, 0x79, 0x0f, 0xaa},
- {0, 0xc8, 0x00, 0xaa}, {0, 0x79, 0x10, 0xaa},
- {0, 0xc8, 0x7e, 0xaa}, {0, 0x79, 0x0a, 0xaa},
- {0, 0xc8, 0x80, 0xaa}, {0, 0x79, 0x0b, 0xaa},
- {0, 0xc8, 0x01, 0xaa}, {0, 0x79, 0x0c, 0xaa},
- {0, 0xc8, 0x0f, 0xaa}, {0, 0x79, 0x0d, 0xaa},
- {0, 0xc8, 0x20, 0xaa}, {0, 0x79, 0x09, 0xaa},
- {0, 0xc8, 0x80, 0xaa}, {0, 0x79, 0x02, 0xaa},
- {0, 0xc8, 0xc0, 0xaa}, {0, 0x79, 0x03, 0xaa},
- {0, 0xc8, 0x40, 0xaa}, {0, 0x79, 0x05, 0xaa},
- {0, 0xc8, 0x30, 0xaa}, {0, 0x79, 0x26, 0xaa},
- {0, 0x11, 0x40, 0xaa}, {0, 0x3a, 0x04, 0xaa},
- {0, 0x12, 0x00, 0xaa}, {0, 0x40, 0xc0, 0xaa},
- {0, 0x8c, 0x00, 0xaa}, {0, 0x17, 0x14, 0xaa},
- {0, 0x18, 0x02, 0xaa}, {0, 0x32, 0x92, 0xaa},
- {0, 0x19, 0x02, 0xaa}, {0, 0x1a, 0x7a, 0xaa},
- {0, 0x03, 0x0a, 0xaa}, {0, 0x0c, 0x00, 0xaa},
- {0, 0x3e, 0x00, 0xaa}, {0, 0x70, 0x3a, 0xaa},
- {0, 0x71, 0x35, 0xaa}, {0, 0x72, 0x11, 0xaa},
- {0, 0x73, 0xf0, 0xaa}, {0, 0xa2, 0x02, 0xaa},
- {0, 0xb1, 0x00, 0xaa}, {0, 0xb1, 0x0c, 0xaa},
- {0, 0x1e, 0x37, 0xaa}, {0, 0xaa, 0x14, 0xaa},
- {0, 0x24, 0x80, 0xaa}, {0, 0x25, 0x74, 0xaa},
- {0, 0x26, 0xd3, 0xaa}, {0, 0x0d, 0x00, 0xaa},
- {0, 0x14, 0x18, 0xaa}, {0, 0x9d, 0x99, 0xaa},
- {0, 0x9e, 0x7f, 0xaa}, {0, 0x64, 0x08, 0xaa},
- {0, 0x94, 0x07, 0xaa}, {0, 0x95, 0x06, 0xaa},
- {0, 0x66, 0x05, 0xaa}, {0, 0x41, 0x08, 0xaa},
- {0, 0x3f, 0x00, 0xaa}, {0, 0x75, 0x07, 0xaa},
- {0, 0x76, 0xe1, 0xaa}, {0, 0x4c, 0x00, 0xaa},
- {0, 0x77, 0x00, 0xaa}, {0, 0x3d, 0xc2, 0xaa},
- {0, 0x4b, 0x09, 0xaa}, {0, 0xc9, 0x60, 0xaa},
- {0, 0x41, 0x38, 0xaa},
- {0xb6, 0x00, 0x00, 0xcc}, {0xb6, 0x03, 0x01, 0xcc},
- {0xb6, 0x02, 0x40, 0xcc},
- {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc},
- {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x21, 0xcc},
- {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc},
- {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0x00, 0x00, 0x64, 0xdd},
+ {0xb3, 0x49, 0x11, 0xcc},
+ {0x00, 0x00, 0x33, 0xdd},
+/*read b349*/
+#endif
+ {0xb0, 0x03, 0x19, 0xcc},
+/* {0x00, 0x00, 0x33, 0xdd}, */
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0xb0, 0x02, 0x02, 0xcc},
+ {0xb3, 0x5d, 0x00, 0xcc},
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x02, 0xb2, 0xcc},
+ {0xb3, 0x03, 0x18, 0xcc},
+ {0xb3, 0x04, 0x15, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x02, 0xcc},
+ {0xb3, 0x23, 0x58, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x03, 0xcc},
+ {0xb3, 0x17, 0x1f, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb0, 0x54, 0x13, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xdc, 0xcc},
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x12, 0x05, 0xaa},
+ {0x00, 0x13, 0x02, 0xaa},
+ {0x00, 0x1e, 0xc6, 0xaa}, /* h/v flip */
+ {0x00, 0x21, 0x00, 0xaa},
+ {0x00, 0x25, 0x02, 0xaa},
+ {0x00, 0x3c, 0x4f, 0xaa},
+ {0x00, 0x3f, 0xe0, 0xaa},
+ {0x00, 0x42, 0xff, 0xaa},
+ {0x00, 0x45, 0x34, 0xaa},
+ {0x00, 0x55, 0xfe, 0xaa},
+ {0x00, 0x59, 0xd3, 0xaa},
+ {0x00, 0x5e, 0x04, 0xaa},
+ {0x00, 0x61, 0xb8, 0xaa}, /* sharpness */
+ {0x00, 0x62, 0x02, 0xaa},
+ {0x00, 0xa7, 0x31, 0xaa},
+ {0x00, 0xa9, 0x66, 0xaa},
+ {0x00, 0xb0, 0x00, 0xaa},
+ {0x00, 0xb1, 0x00, 0xaa},
+ {0x00, 0xb3, 0x11, 0xaa},
+ {0x00, 0xb6, 0x26, 0xaa},
+ {0x00, 0xb7, 0x20, 0xaa},
+ {0x00, 0xba, 0x04, 0xaa},
+ {0x00, 0x88, 0x42, 0xaa},
+ {0x00, 0x89, 0x9a, 0xaa},
+ {0x00, 0x8a, 0x88, 0xaa},
+ {0x00, 0x8b, 0x8e, 0xaa},
+ {0x00, 0x8c, 0x3e, 0xaa},
+ {0x00, 0x8d, 0x90, 0xaa},
+ {0x00, 0x8e, 0x87, 0xaa},
+ {0x00, 0x8f, 0x96, 0xaa},
+ {0x00, 0x90, 0x3d, 0xaa},
+ {0x00, 0x64, 0x00, 0xaa},
+ {0x00, 0x65, 0x10, 0xaa},
+ {0x00, 0x66, 0x20, 0xaa},
+ {0x00, 0x67, 0x2b, 0xaa},
+ {0x00, 0x68, 0x36, 0xaa},
+ {0x00, 0x69, 0x49, 0xaa},
+ {0x00, 0x6a, 0x5a, 0xaa},
+ {0x00, 0x6b, 0x7f, 0xaa},
+ {0x00, 0x6c, 0x9b, 0xaa},
+ {0x00, 0x6d, 0xba, 0xaa},
+ {0x00, 0x6e, 0xd4, 0xaa},
+ {0x00, 0x6f, 0xea, 0xaa},
+ {0x00, 0x70, 0x00, 0xaa},
+ {0x00, 0x71, 0x10, 0xaa},
+ {0x00, 0x72, 0x20, 0xaa},
+ {0x00, 0x73, 0x2b, 0xaa},
+ {0x00, 0x74, 0x36, 0xaa},
+ {0x00, 0x75, 0x49, 0xaa},
+ {0x00, 0x76, 0x5a, 0xaa},
+ {0x00, 0x77, 0x7f, 0xaa},
+ {0x00, 0x78, 0x9b, 0xaa},
+ {0x00, 0x79, 0xba, 0xaa},
+ {0x00, 0x7a, 0xd4, 0xaa},
+ {0x00, 0x7b, 0xea, 0xaa},
+ {0x00, 0x7c, 0x00, 0xaa},
+ {0x00, 0x7d, 0x10, 0xaa},
+ {0x00, 0x7e, 0x20, 0xaa},
+ {0x00, 0x7f, 0x2b, 0xaa},
+ {0x00, 0x80, 0x36, 0xaa},
+ {0x00, 0x81, 0x49, 0xaa},
+ {0x00, 0x82, 0x5a, 0xaa},
+ {0x00, 0x83, 0x7f, 0xaa},
+ {0x00, 0x84, 0x9b, 0xaa},
+ {0x00, 0x85, 0xba, 0xaa},
+ {0x00, 0x86, 0xd4, 0xaa},
+ {0x00, 0x87, 0xea, 0xaa},
+ {0x00, 0x57, 0x2a, 0xaa},
+ {0x00, 0x03, 0x01, 0xaa},
+ {0x00, 0x04, 0x10, 0xaa},
+ {0x00, 0x05, 0x10, 0xaa},
+ {0x00, 0x06, 0x10, 0xaa},
+ {0x00, 0x07, 0x10, 0xaa},
+ {0x00, 0x08, 0x13, 0xaa},
+ {0x00, 0x0a, 0x00, 0xaa},
+ {0x00, 0x0b, 0x10, 0xaa},
+ {0x00, 0x0c, 0x20, 0xaa},
+ {0x00, 0x0d, 0x18, 0xaa},
+ {0x00, 0x22, 0x01, 0xaa},
+ {0x00, 0x23, 0x60, 0xaa},
+ {0x00, 0x25, 0x08, 0xaa},
+ {0x00, 0x26, 0x82, 0xaa},
+ {0x00, 0x2e, 0x0f, 0xaa},
+ {0x00, 0x2f, 0x1e, 0xaa},
+ {0x00, 0x30, 0x2d, 0xaa},
+ {0x00, 0x31, 0x3c, 0xaa},
+ {0x00, 0x32, 0x4b, 0xaa},
+ {0x00, 0x33, 0x5a, 0xaa},
+ {0x00, 0x34, 0x69, 0xaa},
+ {0x00, 0x35, 0x78, 0xaa},
+ {0x00, 0x36, 0x87, 0xaa},
+ {0x00, 0x37, 0x96, 0xaa},
+ {0x00, 0x38, 0xa5, 0xaa},
+ {0x00, 0x39, 0xb4, 0xaa},
+ {0x00, 0x3a, 0xc3, 0xaa},
+ {0x00, 0x3b, 0xd2, 0xaa},
+ {0x00, 0x3c, 0xe1, 0xaa},
+ {0x00, 0x3e, 0xff, 0xaa},
+ {0x00, 0x3f, 0xff, 0xaa},
+ {0x00, 0x40, 0xff, 0xaa},
+ {0x00, 0x41, 0xff, 0xaa},
+ {0x00, 0x42, 0xff, 0xaa},
+ {0x00, 0x43, 0xff, 0xaa},
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x20, 0xc4, 0xaa},
+ {0x00, 0x13, 0x03, 0xaa},
+ {0x00, 0x3c, 0x50, 0xaa},
+ {0x00, 0x61, 0x6a, 0xaa}, /* sharpness? */
+ {0x00, 0x51, 0x5b, 0xaa},
+ {0x00, 0x52, 0x91, 0xaa},
+ {0x00, 0x53, 0x4c, 0xaa},
+ {0x00, 0x54, 0x50, 0xaa},
+ {0x00, 0x56, 0x02, 0xaa},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x03, 0xcc},
+ {0xb6, 0x02, 0x20, 0xcc},
+ {0xb6, 0x05, 0x02, 0xcc},
+ {0xb6, 0x04, 0x58, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x21, 0xcc},
+ {0xb6, 0x18, 0x03, 0xcc},
+ {0xb6, 0x17, 0xa9, 0xcc},
+ {0xb6, 0x16, 0x80, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
{0xb6, 0x23, 0x0b, 0xcc},
- {0xbf, 0xc0, 0x39, 0xcc},/* set jpeg */
- {0xbf, 0xc1, 0x04, 0xcc},/* */
- {0xbf, 0xcc, 0x00, 0xcc},/* */
- {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc},
- {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc},
- {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc},
- {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc},
- {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x45, 0xcc},
- {0, 0x77, 0x05, 0xaa}, {0xb6, 0x12, 0xf8, 0xcc},
- {0xb6, 0x13, 0x20, 0xcc},
- {0, 0x24, 0x6c, 0xaa},
- {0, 0x25, 0x5c, 0xaa}, {0, 0x56, 0x50, 0xaa},
- {0, 0x4f, 0xa8, 0xaa}, {0, 0x50, 0xa5, 0xaa},
- {0, 0x51, 0x02, 0xaa}, {0, 0x52, 0x22, 0xaa},
- {0, 0x53, 0x86, 0xaa}, {0, 0x54, 0xaa, 0xaa},
- {0, 0x7a, 0x19, 0xaa}, {0, 0x7b, 0x0c, 0xaa},
- {0, 0x7c, 0x18, 0xaa}, {0, 0x7d, 0x2f, 0xaa},
- {0, 0x7e, 0x54, 0xaa}, {0, 0x7f, 0x64, 0xaa},
- {0, 0x80, 0x71, 0xaa}, {0, 0x81, 0x7d, 0xaa},
- {0, 0x82, 0x88, 0xaa}, {0, 0x83, 0x91, 0xaa},
- {0, 0x84, 0x98, 0xaa}, {0, 0x85, 0xa7, 0xaa},
- {0, 0x86, 0xb4, 0xaa}, {0, 0x87, 0xcb, 0xaa},
- {0, 0x88, 0xde, 0xaa}, {0, 0x89, 0xed, 0xaa},
- {0, 0x75, 0x86, 0xaa}, {0, 0x92, 0x00, 0xaa},
- {0, 0x3b, 0, 0xbb},
- {0, 0x3b, 0x00, 0xaa},
- {0, 0x13, 0, 0xbb}, {0, 0x13, 0xe7, 0xaa},
- {0, 0x2d, 0x00, 0xaa}, {0, 0x2e, 0x00, 0xaa},
- {0, 0x04, 0x00, 0xaa}, {0, 0x10, 0x00, 0xaa},
- {0, 0x3b, 0, 0xbb}, {0, 0x3b, 0x80, 0xaa},
- {0, 0x13, 0, 0xbb},
- {0, 0x13, 0xe7, 0xaa},
- {0, 0x1e, 0x27, 0xaa},
- {0, 0x1e, 0x27, 0xaa},
- {0, 0x3b, 0xc8, 0xaa},
- {}
-};
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x00, 0xcc},
+ {0xb8, 0x06, 0x20, 0xcc},
+ {0xb8, 0x07, 0x03, 0xcc},
+ {0xb8, 0x08, 0x58, 0xcc},
+ {0xb8, 0x09, 0x02, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0xd9, 0x0f, 0xaa},
+ {0x00, 0xda, 0xaa, 0xaa},
+ {0x00, 0xd9, 0x10, 0xaa},
+ {0x00, 0xda, 0xaa, 0xaa},
+ {0x00, 0xd9, 0x11, 0xaa},
+ {0x00, 0xda, 0x00, 0xaa},
+ {0x00, 0xd9, 0x12, 0xaa},
+ {0x00, 0xda, 0xff, 0xaa},
+ {0x00, 0xd9, 0x13, 0xaa},
+ {0x00, 0xda, 0xff, 0xaa},
+ {0x00, 0xe8, 0x11, 0xaa},
+ {0x00, 0xe9, 0x12, 0xaa},
+ {0x00, 0xea, 0x5c, 0xaa},
+ {0x00, 0xeb, 0xff, 0xaa},
+ {0x00, 0xd8, 0x80, 0xaa},
+ {0x00, 0xe6, 0x02, 0xaa},
+ {0x00, 0xd6, 0x40, 0xaa},
+ {0x00, 0xe3, 0x05, 0xaa},
+ {0x00, 0xe0, 0x40, 0xaa},
+ {0x00, 0xde, 0x03, 0xaa},
+ {0x00, 0xdf, 0x03, 0xaa},
+ {0x00, 0xdb, 0x02, 0xaa},
+ {0x00, 0xdc, 0x00, 0xaa},
+ {0x00, 0xdd, 0x03, 0xaa},
+ {0x00, 0xe1, 0x08, 0xaa},
+ {0x00, 0xe2, 0x01, 0xaa},
+ {0x00, 0xd6, 0x40, 0xaa},
+ {0x00, 0xe4, 0x40, 0xaa},
+#if 1
+ {0x00, 0xa8, 0x8f, 0xaa},
+#else
+/*modified later*/
+ {0x00, 0xa8, 0x9f, 0xaa},
+#endif
+ {0x00, 0xb4, 0x16, 0xaa},
+ {0xb0, 0x02, 0x06, 0xcc},
+ {0xb0, 0x18, 0x06, 0xcc},
+ {0xb0, 0x19, 0x06, 0xcc},
+ {0xb3, 0x5d, 0x18, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0x00, 0xb4, 0x0e, 0xaa},
+ {0x00, 0xb5, 0x49, 0xaa},
+ {0x00, 0xb6, 0x1c, 0xaa},
+ {0x00, 0xb7, 0x96, 0xaa},
+/* end of usbvm326.inf - start of ms-win trace */
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x3d, 0xcc},
+/*read b306*/
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x1a, 0x09, 0xaa},
+ {0x00, 0x1b, 0x8a, 0xaa},
+/*read b827*/
+ {0xb8, 0x27, 0x00, 0xcc},
+ {0xb8, 0x26, 0x60, 0xcc},
+ {0xb8, 0x26, 0x60, 0xcc},
+/*gamma - to do?*/
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0xae, 0x84, 0xaa},
+/*gamma again*/
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x96, 0xa0, 0xaa},
+/*matrix*/
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x91, 0x35, 0xaa},
+ {0x00, 0x92, 0x22, 0xaa},
+/*gamma*/
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x95, 0x85, 0xaa},
+/*matrix*/
+#if 0
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x61, 0xb8, 0xaa}, /* sharpness */
+#endif
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x4d, 0x20, 0xaa},
+ {0xb8, 0x22, 0x40, 0xcc},
+ {0xb8, 0x23, 0x40, 0xcc},
+ {0xb8, 0x24, 0x40, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc},
+ {0x00, 0x00, 0x64, 0xdd},
+ {0x00, 0x03, 0x01, 0xaa},
+/*read 46*/
+ {0x00, 0x46, 0x3c, 0xaa},
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x16, 0x40, 0xaa},
+ {0x00, 0x17, 0x40, 0xaa},
+ {0x00, 0x18, 0x40, 0xaa},
+ {0x00, 0x19, 0x41, 0xaa},
+ {0x00, 0x03, 0x01, 0xaa},
+ {0x00, 0x46, 0x3c, 0xaa},
+ {0x00, 0x00, 0x18, 0xdd},
+/*read bfff*/
+#if 0
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x1e, 0x46, 0xaa}, /* h/v flip */
+ {0x00, 0xa8, 0x8f, 0xaa},
#endif
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0xb4, 0x1c, 0xaa},
+ {0x00, 0xb5, 0x92, 0xaa},
+ {0x00, 0xb6, 0x39, 0xaa},
+ {0x00, 0xb7, 0x24, 0xaa},
+/*write 89 0400 1415*/
+};
struct sensor_info {
int sensorId;
@@ -1402,6 +1807,9 @@ static const struct sensor_info sensor_info_data[] = {
{SENSOR_MI1320, 0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01},
{SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
{SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+/* (tested in vc032x_probe_sensor) */
+/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
+ {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
};
/* read 'len' bytes in gspca_dev->usb_buf */
@@ -1458,18 +1866,18 @@ static void read_sensor_register(struct gspca_dev *gspca_dev,
msleep(1);
}
reg_r(gspca_dev, 0xa1, 0xb33e, 1);
- hdata = gspca_dev->usb_buf[0];
+ ldata = gspca_dev->usb_buf[0];
reg_r(gspca_dev, 0xa1, 0xb33d, 1);
mdata = gspca_dev->usb_buf[0];
reg_r(gspca_dev, 0xa1, 0xb33c, 1);
- ldata = gspca_dev->usb_buf[0];
- PDEBUG(D_PROBE, "Read Sensor h (0x%02X) m (0x%02X) l (0x%02X)",
+ hdata = gspca_dev->usb_buf[0];
+ PDEBUG(D_PROBE, "Read Sensor %02x%02x %02x",
hdata, mdata, ldata);
reg_r(gspca_dev, 0xa1, 0xb334, 1);
if (gspca_dev->usb_buf[0] == 0x02)
- *value = (ldata << 8) + mdata;
+ *value = (hdata << 8) + mdata;
else
- *value = ldata;
+ *value = hdata;
}
static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
@@ -1480,7 +1888,7 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
const struct sensor_info *ptsensor_info;
reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
- PDEBUG(D_PROBE, "check sensor header %d", gspca_dev->usb_buf[0]);
+ PDEBUG(D_PROBE, "check sensor header %02x", gspca_dev->usb_buf[0]);
for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) {
ptsensor_info = &sensor_info_data[i];
reg_w(dev, 0xa0, 0x02, 0xb334);
@@ -1489,16 +1897,15 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
reg_w(dev, 0xa0, 0x01, 0xb308);
reg_w(dev, 0xa0, 0x0c, 0xb309);
reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
-/* PDEBUG(D_PROBE,
- "check sensor VC032X -> %d Add -> ox%02X!",
- i, ptsensor_info->I2cAdd); */
reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
read_sensor_register(gspca_dev, ptsensor_info->IdAdd, &value);
- if (value == ptsensor_info->VpId) {
-/* PDEBUG(D_PROBE, "find sensor VC032X -> ox%04X!",
- ptsensor_info->VpId); */
+ if (value == ptsensor_info->VpId)
return ptsensor_info->sensorId;
- }
+
+ /* special case for MI0360 */
+ if (ptsensor_info->sensorId == SENSOR_MI1310_SOC
+ && value == 0x8243)
+ return SENSOR_MI0360;
}
return -1;
}
@@ -1600,13 +2007,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->epaddr = 0x02;
sd->bridge = id->driver_info;
- if (sd->bridge == BRIDGE_VC0321) {
- cam->cam_mode = vc0321_mode;
- cam->nmodes = ARRAY_SIZE(vc0321_mode);
- } else {
- cam->cam_mode = vc0323_mode;
- cam->nmodes = ARRAY_SIZE(vc0323_mode);
- }
vc0321_reset(gspca_dev);
sensor = vc032x_probe_sensor(gspca_dev);
@@ -1616,35 +2016,66 @@ static int sd_config(struct gspca_dev *gspca_dev,
return -EINVAL;
case SENSOR_HV7131R:
PDEBUG(D_PROBE, "Find Sensor HV7131R");
- sd->sensor = SENSOR_HV7131R;
+ break;
+ case SENSOR_MI0360:
+ PDEBUG(D_PROBE, "Find Sensor MI0360");
+ sd->bridge = BRIDGE_VC0323;
break;
case SENSOR_MI1310_SOC:
PDEBUG(D_PROBE, "Find Sensor MI1310_SOC");
- sd->sensor = SENSOR_MI1310_SOC;
break;
case SENSOR_MI1320:
PDEBUG(D_PROBE, "Find Sensor MI1320");
- sd->sensor = SENSOR_MI1320;
break;
case SENSOR_OV7660:
PDEBUG(D_PROBE, "Find Sensor OV7660");
- sd->sensor = SENSOR_OV7660;
break;
case SENSOR_OV7670:
PDEBUG(D_PROBE, "Find Sensor OV7670");
- sd->sensor = SENSOR_OV7670;
+ break;
+ case SENSOR_PO1200:
+ PDEBUG(D_PROBE, "Find Sensor PO1200");
break;
case SENSOR_PO3130NC:
PDEBUG(D_PROBE, "Find Sensor PO3130NC");
- sd->sensor = SENSOR_PO3130NC;
break;
}
+ sd->sensor = sensor;
- sd->qindex = 7;
- sd->autogain = AUTOGAIN_DEF;
+ if (sd->bridge == BRIDGE_VC0321) {
+ cam->cam_mode = vc0321_mode;
+ cam->nmodes = ARRAY_SIZE(vc0321_mode);
+ } else {
+ if (sensor != SENSOR_PO1200) {
+ cam->cam_mode = vc0323_mode;
+ cam->nmodes = ARRAY_SIZE(vc0323_mode);
+ } else {
+ cam->cam_mode = svga_mode;
+ cam->nmodes = ARRAY_SIZE(svga_mode);
+ }
+ }
+
+ sd->hflip = HFLIP_DEF;
+ sd->vflip = VFLIP_DEF;
+ if (sd->sensor == SENSOR_OV7670) {
+ sd->hflip = 1;
+ sd->vflip = 1;
+ }
sd->lightfreq = FREQ_DEF;
if (sd->sensor != SENSOR_OV7670)
gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
+ switch (sd->sensor) {
+ case SENSOR_OV7660:
+ case SENSOR_OV7670:
+ case SENSOR_PO1200:
+ break;
+ default:
+ gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
+ | (1 << VFLIP_IDX);
+ break;
+ }
+
+ sd->sharpness = SHARPNESS_DEF;
if (sd->bridge == BRIDGE_VC0321) {
reg_r(gspca_dev, 0x8a, 0, 3);
@@ -1662,29 +2093,33 @@ static int sd_init(struct gspca_dev *gspca_dev)
return 0;
}
-static void setquality(struct gspca_dev *gspca_dev)
-{
-#if 0
- struct sd *sd = (struct sd *) gspca_dev;
- __u8 quality = 0;
-
- quality = sd->qindex & 0xff;
- reg_w(gspca_dev->dev, 0xa0, quality, 0x0008);
-#endif
-}
-
-static void setautogain(struct gspca_dev *gspca_dev)
+/* for OV7660 and OV7670 only */
+static void sethvflip(struct gspca_dev *gspca_dev)
{
-#if 0
struct sd *sd = (struct sd *) gspca_dev;
- __u8 autoval;
+ __u8 data;
- if (sd->autogain)
- autoval = 0x42;
- else
- autoval = 0x02;
- reg_w(gspca_dev->dev, 0xa0, autoval, 0x0180);
-#endif
+ switch (sd->sensor) {
+ case SENSOR_OV7660:
+ data = 1;
+ break;
+ case SENSOR_OV7670:
+ data = 7;
+ break;
+ case SENSOR_PO1200:
+ data = 0;
+ i2c_write(gspca_dev, 0x03, &data, 1);
+ data = 0x80 * sd->hflip
+ | 0x40 * sd->vflip
+ | 0x06;
+ i2c_write(gspca_dev, 0x1e, &data, 1);
+ return;
+ default:
+ return;
+ }
+ data |= OV7660_MVFP_MIRROR * sd->hflip
+ | OV7660_MVFP_VFLIP * sd->vflip;
+ i2c_write(gspca_dev, OV7660_REG_MVFP, &data, 1);
}
static void setlightfreq(struct gspca_dev *gspca_dev)
@@ -1698,6 +2133,20 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]);
}
+/* po1200 only */
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 data;
+
+ if (sd->sensor != SENSOR_PO1200)
+ return;
+ data = 0;
+ i2c_write(gspca_dev, 0x03, &data, 1);
+ data = 0xb5 + sd->sharpness * 3;
+ i2c_write(gspca_dev, 0x61, &data, 1);
+}
+
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1748,6 +2197,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
usb_exchange(gspca_dev, ov7670_initVGA_JPG);
}
break;
+ case SENSOR_MI0360:
+ GammaT = mi1320_gamma;
+ MatrixT = mi0360_matrix;
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, mi0360_initQVGA_JPG);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, mi0360_initVGA_JPG);
+ }
+ break;
case SENSOR_MI1310_SOC:
if (mode) {
/* 320x240 */
@@ -1780,6 +2240,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
usb_exchange(gspca_dev, po3130_rundata);
break;
+ case SENSOR_PO1200:
+ GammaT = po1200_gamma;
+ MatrixT = po1200_matrix;
+ usb_exchange(gspca_dev, po1200_initVGA_data);
+ break;
default:
PDEBUG(D_PROBE, "Damned !! no sensor found Bye");
return -EMEDIUMTYPE;
@@ -1812,11 +2277,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev->dev, 0xa0, 0x23, 0xb800); * ISP CTRL_BAS
*/
/* set the led on 0x0892 0x0896 */
- reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
- msleep(100);
- setquality(gspca_dev);
- setautogain(gspca_dev);
- setlightfreq(gspca_dev);
+ if (sd->sensor != SENSOR_PO1200) {
+ reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+ msleep(100);
+ sethvflip(gspca_dev);
+ setlightfreq(gspca_dev);
+ } else {
+ setsharpness(gspca_dev);
+ sethvflip(gspca_dev);
+ reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
+ }
}
return 0;
}
@@ -1862,24 +2332,48 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data, len);
return;
}
+
+ /* The vc0321 sends some additional data after sending the complete
+ * frame, we ignore this. */
+ if (sd->bridge == BRIDGE_VC0321
+ && len > frame->v4l2_buf.length - (frame->data_end - frame->data))
+ len = frame->v4l2_buf.length - (frame->data_end - frame->data);
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->autogain = val;
+ sd->hflip = val;
if (gspca_dev->streaming)
- setautogain(gspca_dev);
+ sethvflip(gspca_dev);
return 0;
}
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->autogain;
+ *val = sd->hflip;
+ return 0;
+}
+
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->vflip = val;
+ if (gspca_dev->streaming)
+ sethvflip(gspca_dev);
+ return 0;
+}
+
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->vflip;
return 0;
}
@@ -1901,6 +2395,24 @@ static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->sharpness = val;
+ if (gspca_dev->streaming)
+ setsharpness(gspca_dev);
+ return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->sharpness;
+ return 0;
+}
+
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
@@ -1940,11 +2452,13 @@ static const struct sd_desc sd_desc = {
static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x046d, 0x0892), .driver_info = BRIDGE_VC0321},
{USB_DEVICE(0x046d, 0x0896), .driver_info = BRIDGE_VC0321},
+ {USB_DEVICE(0x046d, 0x0897), .driver_info = BRIDGE_VC0321},
{USB_DEVICE(0x0ac8, 0x0321), .driver_info = BRIDGE_VC0321},
{USB_DEVICE(0x0ac8, 0x0323), .driver_info = BRIDGE_VC0323},
{USB_DEVICE(0x0ac8, 0x0328), .driver_info = BRIDGE_VC0321},
{USB_DEVICE(0x0ac8, 0xc001), .driver_info = BRIDGE_VC0321},
{USB_DEVICE(0x0ac8, 0xc002), .driver_info = BRIDGE_VC0321},
+ {USB_DEVICE(0x15b8, 0x6002), .driver_info = BRIDGE_VC0323},
{USB_DEVICE(0x17ef, 0x4802), .driver_info = BRIDGE_VC0323},
{}
};
diff --git a/linux/drivers/media/video/gspca/zc3xx-reg.h b/linux/drivers/media/video/gspca/zc3xx-reg.h
index f52e09c2c..bfb559c3b 100644
--- a/linux/drivers/media/video/gspca/zc3xx-reg.h
+++ b/linux/drivers/media/video/gspca/zc3xx-reg.h
@@ -244,14 +244,6 @@
#define ZC3XX_R1CA_SHARPNESS04 0x01ca
#define ZC3XX_R1CB_SHARPNESS05 0x01cb
-/* Synchronization */
-#define ZC3XX_R190_SYNC00LOW 0x0190
-#define ZC3XX_R191_SYNC00MID 0x0191
-#define ZC3XX_R192_SYNC00HIGH 0x0192
-#define ZC3XX_R195_SYNC01LOW 0x0195
-#define ZC3XX_R196_SYNC01MID 0x0196
-#define ZC3XX_R197_SYNC01HIGH 0x0197
-
/* Dead pixels */
#define ZC3XX_R250_DEADPIXELSMODE 0x0250
diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c
index adbca6a9d..79d2a776d 100644
--- a/linux/drivers/media/video/gspca/zc3xx.c
+++ b/linux/drivers/media/video/gspca/zc3xx.c
@@ -51,16 +51,16 @@ struct sd {
#define SENSOR_CS2102 0
#define SENSOR_CS2102K 1
#define SENSOR_GC0305 2
-#define SENSOR_HDCS2020 3
-#define SENSOR_HDCS2020b 4
-#define SENSOR_HV7131B 5
-#define SENSOR_HV7131C 6
-#define SENSOR_ICM105A 7
-#define SENSOR_MC501CB 8
-#define SENSOR_OV7620 9
-/*#define SENSOR_OV7648 9 - same values */
-#define SENSOR_OV7630C 10
-#define SENSOR_PAS106 11
+#define SENSOR_HDCS2020b 3
+#define SENSOR_HV7131B 4
+#define SENSOR_HV7131C 5
+#define SENSOR_ICM105A 6
+#define SENSOR_MC501CB 7
+#define SENSOR_OV7620 8
+/*#define SENSOR_OV7648 8 - same values */
+#define SENSOR_OV7630C 9
+#define SENSOR_PAS106 10
+#define SENSOR_PAS202B 11
#define SENSOR_PB0330 12
#define SENSOR_PO2030 13
#define SENSOR_TAS5130CK 14
@@ -173,7 +173,7 @@ static struct ctrl sd_ctrls[] = {
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -186,7 +186,7 @@ static struct v4l2_pix_format vga_mode[] = {
.priv = 0},
};
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 176,
.sizeimage = 176 * 144 * 3 / 8 + 590,
@@ -1653,295 +1653,6 @@ static const struct usb_action gc0305_NoFliker[] = {
{}
};
-/* play poker with registers at your own risk !! */
-static const struct usb_action hdcs2020xx_Initial[] = {
- {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
- {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT},
- {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
- {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
- {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
- {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
- {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW},
- /* D0 ?? E0 did not start */
- {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
- {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
- {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
- {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},
- {0xa0, 0x08, ZC3XX_R098_WINYSTARTLOW},
- {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW},
- {0xa0, 0x08, ZC3XX_R11A_FIRSTYLOW},
- {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW},
- {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
- {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW},
- {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
- {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
- {0xaa, 0x02, 0x0002},
- {0xaa, 0x07, 0x0006},
- {0xaa, 0x08, 0x0002},
- {0xaa, 0x09, 0x0006},
- {0xaa, 0x0a, 0x0001},
- {0xaa, 0x0b, 0x0001},
- {0xaa, 0x0c, 0x0008},
- {0xaa, 0x0d, 0x0000},
- {0xaa, 0x10, 0x0000},
- {0xaa, 0x12, 0x0005},
- {0xaa, 0x13, 0x0063},
- {0xaa, 0x15, 0x0070},
- {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
- {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
- {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
- {0xa0, 0x00, 0x01ad},
- {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
- {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
- {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
- {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
- {0xa0, 0x70, ZC3XX_R18D_YTARGET},
- {0xa1, 0x01, 0x0002},
- {0xa1, 0x01, 0x0008},
- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
- {0xa0, 0x04, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
- {0xa1, 0x01, 0x01c8},
- {0xa1, 0x01, 0x01c9},
- {0xa1, 0x01, 0x01ca},
- {0xa0, 0x07, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
- {0xa0, 0x11, ZC3XX_R120_GAMMA00}, /* gamma ~4 */
- {0xa0, 0x37, ZC3XX_R121_GAMMA01},
- {0xa0, 0x58, ZC3XX_R122_GAMMA02},
- {0xa0, 0x79, ZC3XX_R123_GAMMA03},
- {0xa0, 0x91, ZC3XX_R124_GAMMA04},
- {0xa0, 0xa6, ZC3XX_R125_GAMMA05},
- {0xa0, 0xb8, ZC3XX_R126_GAMMA06},
- {0xa0, 0xc7, ZC3XX_R127_GAMMA07},
- {0xa0, 0xd3, ZC3XX_R128_GAMMA08},
- {0xa0, 0xde, ZC3XX_R129_GAMMA09},
- {0xa0, 0xe6, ZC3XX_R12A_GAMMA0A},
- {0xa0, 0xed, ZC3XX_R12B_GAMMA0B},
- {0xa0, 0xf3, ZC3XX_R12C_GAMMA0C},
- {0xa0, 0xf8, ZC3XX_R12D_GAMMA0D},
- {0xa0, 0xfb, ZC3XX_R12E_GAMMA0E},
- {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
- {0xa0, 0x26, ZC3XX_R130_GAMMA10},
- {0xa0, 0x23, ZC3XX_R131_GAMMA11},
- {0xa0, 0x20, ZC3XX_R132_GAMMA12},
- {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
- {0xa0, 0x16, ZC3XX_R134_GAMMA14},
- {0xa0, 0x13, ZC3XX_R135_GAMMA15},
- {0xa0, 0x10, ZC3XX_R136_GAMMA16},
- {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
- {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
- {0xa0, 0x09, ZC3XX_R139_GAMMA19},
- {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
- {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
- {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
- {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
- {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
- {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
-
- {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */
- {0xa0, 0xf5, ZC3XX_R10B_RGB01},
- {0xa0, 0xff, ZC3XX_R10C_RGB02},
- {0xa0, 0xf9, ZC3XX_R10D_RGB10},
- {0xa0, 0x51, ZC3XX_R10E_RGB11},
- {0xa0, 0xf5, ZC3XX_R10F_RGB12},
- {0xa0, 0xfb, ZC3XX_R110_RGB20},
- {0xa0, 0xed, ZC3XX_R111_RGB21},
- {0xa0, 0x5f, ZC3XX_R112_RGB22},
-
- {0xa1, 0x01, 0x0180},
- {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
- {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
- {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
- {0xaa, 0x20, 0x0004},
- {0xaa, 0x21, 0x003d},
- {0xaa, 0x03, 0x0041},
- {0xaa, 0x04, 0x0010},
- {0xaa, 0x05, 0x003d},
- {0xaa, 0x0e, 0x0001},
- {0xaa, 0x0f, 0x0000},
- {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
- {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
- {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
- {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
- {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW},
- {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
- {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
- {0xa0, 0x9b, ZC3XX_R197_ANTIFLICKERLOW},
- {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
- {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
- {0xa0, 0x41, ZC3XX_R01D_HSYNC_0},
- {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1},
- {0xa0, 0xad, ZC3XX_R01F_HSYNC_2},
- {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
- {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},
- {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},
- {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa1, 0x01, 0x0195},
- {0xa1, 0x01, 0x0196},
- {0xa1, 0x01, 0x0197},
- {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW},
- {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
- {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
- {0xa0, 0x1d, ZC3XX_R116_RGAIN},
- {0xa0, 0x40, ZC3XX_R117_GGAIN},
- {0xa0, 0x85, ZC3XX_R118_BGAIN},
- {0xa1, 0x01, 0x0116},
- {0xa1, 0x01, 0x0118},
- {0xa1, 0x01, 0x0180},
- {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x1d, ZC3XX_R116_RGAIN},
- {0xa0, 0x40, ZC3XX_R117_GGAIN},
- {0xa0, 0x85, ZC3XX_R118_BGAIN},
- {0xa1, 0x01, 0x0116},
- {0xa1, 0x01, 0x0118},
-/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
- {0xa0, 0x00, 0x0007},
- {}
-};
-
-static const struct usb_action hdcs2020xx_InitialScale[] = {
- {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
- {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT},
- {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
- {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
- {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
- {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
- {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
- {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
- {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
- {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
- {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},
- {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
- {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW},
- {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
- {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW},
- {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
- {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},
- {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
- {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},
- {0xaa, 0x02, 0x0002},
- {0xaa, 0x07, 0x0006},
- {0xaa, 0x08, 0x0002},
- {0xaa, 0x09, 0x0006},
- {0xaa, 0x0a, 0x0001},
- {0xaa, 0x0b, 0x0001},
- {0xaa, 0x0c, 0x0008},
- {0xaa, 0x0d, 0x0000},
- {0xaa, 0x10, 0x0000},
- {0xaa, 0x12, 0x0005},
- {0xaa, 0x13, 0x0063},
- {0xaa, 0x15, 0x0070},
- {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
- {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
- {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
- {0xa0, 0x00, 0x01ad},
- {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
- {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
- {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
- {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
- {0xa0, 0x70, ZC3XX_R18D_YTARGET},
- {0xa1, 0x01, 0x0002},
- {0xa1, 0x01, 0x0008},
- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
- {0xa0, 0x04, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
- {0xa1, 0x01, 0x01c8},
- {0xa1, 0x01, 0x01c9},
- {0xa1, 0x01, 0x01ca},
- {0xa0, 0x07, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
- {0xa0, 0x11, ZC3XX_R120_GAMMA00}, /* gamma ~4*/
- {0xa0, 0x37, ZC3XX_R121_GAMMA01},
- {0xa0, 0x58, ZC3XX_R122_GAMMA02},
- {0xa0, 0x79, ZC3XX_R123_GAMMA03},
- {0xa0, 0x91, ZC3XX_R124_GAMMA04},
- {0xa0, 0xa6, ZC3XX_R125_GAMMA05},
- {0xa0, 0xb8, ZC3XX_R126_GAMMA06},
- {0xa0, 0xc7, ZC3XX_R127_GAMMA07},
- {0xa0, 0xd3, ZC3XX_R128_GAMMA08},
- {0xa0, 0xde, ZC3XX_R129_GAMMA09},
- {0xa0, 0xe6, ZC3XX_R12A_GAMMA0A},
- {0xa0, 0xed, ZC3XX_R12B_GAMMA0B},
- {0xa0, 0xf3, ZC3XX_R12C_GAMMA0C},
- {0xa0, 0xf8, ZC3XX_R12D_GAMMA0D},
- {0xa0, 0xfb, ZC3XX_R12E_GAMMA0E},
- {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
- {0xa0, 0x26, ZC3XX_R130_GAMMA10},
- {0xa0, 0x23, ZC3XX_R131_GAMMA11},
- {0xa0, 0x20, ZC3XX_R132_GAMMA12},
- {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
- {0xa0, 0x16, ZC3XX_R134_GAMMA14},
- {0xa0, 0x13, ZC3XX_R135_GAMMA15},
- {0xa0, 0x10, ZC3XX_R136_GAMMA16},
- {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
- {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
- {0xa0, 0x09, ZC3XX_R139_GAMMA19},
- {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
- {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
- {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
- {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
- {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
- {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
- {0xa0, 0x60, ZC3XX_R10A_RGB00}, /* matrix */
- {0xa0, 0xff, ZC3XX_R10B_RGB01},
- {0xa0, 0xff, ZC3XX_R10C_RGB02},
- {0xa0, 0xff, ZC3XX_R10D_RGB10},
- {0xa0, 0x60, ZC3XX_R10E_RGB11},
- {0xa0, 0xff, ZC3XX_R10F_RGB12},
- {0xa0, 0xff, ZC3XX_R110_RGB20},
- {0xa0, 0xff, ZC3XX_R111_RGB21},
- {0xa0, 0x60, ZC3XX_R112_RGB22},
-
- {0xa1, 0x01, 0x0180},
- {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
- {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
- {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
- {0xaa, 0x20, 0x0002},
- {0xaa, 0x21, 0x001b},
- {0xaa, 0x03, 0x0044},
- {0xaa, 0x04, 0x0008},
- {0xaa, 0x05, 0x001b},
- {0xaa, 0x0e, 0x0001},
- {0xaa, 0x0f, 0x0000},
- {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
- {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
- {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
- {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
- {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW},
- {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
- {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
- {0xa0, 0x4d, ZC3XX_R197_ANTIFLICKERLOW},
- {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
- {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
- {0xa0, 0x44, ZC3XX_R01D_HSYNC_0},
- {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1},
- {0xa0, 0xad, ZC3XX_R01F_HSYNC_2},
- {0xa0, 0xeb, ZC3XX_R020_HSYNC_3},
- {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},
- {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},
- {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa1, 0x01, 0x0195},
- {0xa1, 0x01, 0x0196},
- {0xa1, 0x01, 0x0197},
- {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW},
- {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
- {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
- {0xa0, 0x1d, ZC3XX_R116_RGAIN},
- {0xa0, 0x40, ZC3XX_R117_GGAIN},
- {0xa0, 0x99, ZC3XX_R118_BGAIN},
- {0xa1, 0x01, 0x0116},
- {0xa1, 0x01, 0x0118},
- {0xa1, 0x01, 0x0180},
- {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x1d, ZC3XX_R116_RGAIN},
- {0xa0, 0x40, ZC3XX_R117_GGAIN},
- {0xa0, 0x99, ZC3XX_R118_BGAIN},
-/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
- {0xa0, 0x00, 0x0007},
-/* {0xa0, 0x18, 0x00fe}, */
- {}
-};
static const struct usb_action hdcs2020xb_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
@@ -2368,12 +2079,12 @@ static const struct usb_action hv7131b_50HZ[] = { /* 640x480*/
{0xaa, 0x21, 0x0050}, /* 00,21,50,aa */
{0xaa, 0x22, 0x001b}, /* 00,22,1b,aa */
{0xaa, 0x23, 0x00fc}, /* 00,23,fc,aa */
- {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */
- {0xa0, 0x9b, ZC3XX_R191_SYNC00MID}, /* 01,91,9b,cc */
- {0xa0, 0x80, ZC3XX_R192_SYNC00HIGH}, /* 01,92,80,cc */
- {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */
- {0xa0, 0xea, ZC3XX_R196_SYNC01MID}, /* 01,96,ea,cc */
- {0xa0, 0x60, ZC3XX_R197_SYNC01HIGH}, /* 01,97,60,cc */
+ {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */
+ {0xa0, 0x9b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,9b,cc */
+ {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0xea, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,ea,cc */
+ {0xa0, 0x60, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,60,cc */
{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */
{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */
{0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */
@@ -2393,12 +2104,12 @@ static const struct usb_action hv7131b_50HZScale[] = { /* 320x240 */
{0xaa, 0x21, 0x0050}, /* 00,21,50,aa */
{0xaa, 0x22, 0x0012}, /* 00,22,12,aa */
{0xaa, 0x23, 0x0080}, /* 00,23,80,aa */
- {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */
- {0xa0, 0x9b, ZC3XX_R191_SYNC00MID}, /* 01,91,9b,cc */
- {0xa0, 0x80, ZC3XX_R192_SYNC00HIGH}, /* 01,92,80,cc */
- {0xa0, 0x01, ZC3XX_R195_SYNC01LOW}, /* 01,95,01,cc */
- {0xa0, 0xd4, ZC3XX_R196_SYNC01MID}, /* 01,96,d4,cc */
- {0xa0, 0xc0, ZC3XX_R197_SYNC01HIGH}, /* 01,97,c0,cc */
+ {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */
+ {0xa0, 0x9b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,9b,cc */
+ {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */
+ {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,01,cc */
+ {0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,d4,cc */
+ {0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,c0,cc */
{0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, /* 01,8c,07,cc */
{0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,0f,cc */
{0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */
@@ -2418,12 +2129,12 @@ static const struct usb_action hv7131b_60HZ[] = { /* 640x480*/
{0xaa, 0x21, 0x0040}, /* 00,21,40,aa */
{0xaa, 0x22, 0x0013}, /* 00,22,13,aa */
{0xaa, 0x23, 0x004c}, /* 00,23,4c,aa */
- {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */
- {0xa0, 0x4d, ZC3XX_R191_SYNC00MID}, /* 01,91,4d,cc */
- {0xa0, 0x60, ZC3XX_R192_SYNC00HIGH}, /* 01,92,60,cc */
- {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */
- {0xa0, 0xc3, ZC3XX_R196_SYNC01MID}, /* 01,96,c3,cc */
- {0xa0, 0x50, ZC3XX_R197_SYNC01HIGH}, /* 01,97,50,cc */
+ {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */
+ {0xa0, 0x4d, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,4d,cc */
+ {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,60,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,c3,cc */
+ {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,50,cc */
{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */
{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */
{0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */
@@ -2443,12 +2154,12 @@ static const struct usb_action hv7131b_60HZScale[] = { /* 320x240 */
{0xaa, 0x21, 0x00a0}, /* 00,21,a0,aa */
{0xaa, 0x22, 0x0016}, /* 00,22,16,aa */
{0xaa, 0x23, 0x0040}, /* 00,23,40,aa */
- {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */
- {0xa0, 0x4d, ZC3XX_R191_SYNC00MID}, /* 01,91,4d,cc */
- {0xa0, 0x60, ZC3XX_R192_SYNC00HIGH}, /* 01,92,60,cc */
- {0xa0, 0x01, ZC3XX_R195_SYNC01LOW}, /* 01,95,01,cc */
- {0xa0, 0x86, ZC3XX_R196_SYNC01MID}, /* 01,96,86,cc */
- {0xa0, 0xa0, ZC3XX_R197_SYNC01HIGH}, /* 01,97,a0,cc */
+ {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */
+ {0xa0, 0x4d, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,4d,cc */
+ {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,60,cc */
+ {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,01,cc */
+ {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,86,cc */
+ {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,a0,cc */
{0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, /* 01,8c,07,cc */
{0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,0f,cc */
{0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */
@@ -2468,12 +2179,12 @@ static const struct usb_action hv7131b_NoFliker[] = { /* 640x480*/
{0xaa, 0x21, 0x0010}, /* 00,21,10,aa */
{0xaa, 0x22, 0x0000}, /* 00,22,00,aa */
{0xaa, 0x23, 0x0003}, /* 00,23,03,aa */
- {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */
- {0xa0, 0xf8, ZC3XX_R191_SYNC00MID}, /* 01,91,f8,cc */
- {0xa0, 0x00, ZC3XX_R192_SYNC00HIGH}, /* 01,92,00,cc */
- {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */
- {0xa0, 0x02, ZC3XX_R196_SYNC01MID}, /* 01,96,02,cc */
- {0xa0, 0x00, ZC3XX_R197_SYNC01HIGH}, /* 01,97,00,cc */
+ {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */
+ {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,f8,cc */
+ {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,00,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,02,cc */
+ {0xa0, 0x00, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,00,cc */
{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
@@ -2493,12 +2204,12 @@ static const struct usb_action hv7131b_NoFlikerScale[] = { /* 320x240 */
{0xaa, 0x21, 0x00a0}, /* 00,21,a0,aa */
{0xaa, 0x22, 0x0016}, /* 00,22,16,aa */
{0xaa, 0x23, 0x0040}, /* 00,23,40,aa */
- {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */
- {0xa0, 0xf8, ZC3XX_R191_SYNC00MID}, /* 01,91,f8,cc */
- {0xa0, 0x00, ZC3XX_R192_SYNC00HIGH}, /* 01,92,00,cc */
- {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */
- {0xa0, 0x02, ZC3XX_R196_SYNC01MID}, /* 01,96,02,cc */
- {0xa0, 0x00, ZC3XX_R197_SYNC01HIGH}, /* 01,97,00,cc */
+ {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */
+ {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,f8,cc */
+ {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,00,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,02,cc */
+ {0xa0, 0x00, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,00,cc */
{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
@@ -4424,6 +4135,270 @@ static const struct usb_action pas106b_NoFliker[] = {
{}
};
+/* from usbvm31b.inf */
+static const struct usb_action pas202b_Initial[] = { /* 640x480 */
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+ {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */
+ {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0e,cc */
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+ {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+ {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,03,cc */
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+ {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,03,cc */
+ {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */
+ {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc */
+ {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */
+ {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */
+ {0xaa, 0x02, 0x0002}, /* 00,02,04,aa --> 02 */
+ {0xaa, 0x07, 0x0006}, /* 00,07,06,aa */
+ {0xaa, 0x08, 0x0002}, /* 00,08,02,aa */
+ {0xaa, 0x09, 0x0006}, /* 00,09,06,aa */
+ {0xaa, 0x0a, 0x0001}, /* 00,0a,01,aa */
+ {0xaa, 0x0b, 0x0001}, /* 00,0b,01,aa */
+ {0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */
+ {0xaa, 0x0d, 0x0000}, /* 00,0d,00,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x12, 0x0005}, /* 00,12,05,aa */
+ {0xaa, 0x13, 0x0063}, /* 00,13,63,aa */
+ {0xaa, 0x15, 0x0070}, /* 00,15,70,aa */
+ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+ {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+ {0xa0, 0x70, ZC3XX_R18D_YTARGET}, /* 01,8d,70,cc */
+ {}
+};
+static const struct usb_action pas202b_InitialScale[] = { /* 320x240 */
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+ {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */
+ {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0e,cc */
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+ {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+ {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */
+ {0xa0, 0x08, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,08,cc */
+ {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,02,cc */
+ {0xa0, 0x08, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,08,cc */
+ {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,02,cc */
+ {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */
+ {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d8,cc */
+ {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */
+ {0xaa, 0x02, 0x0002}, /* 00,02,02,aa */
+ {0xaa, 0x07, 0x0006}, /* 00,07,06,aa */
+ {0xaa, 0x08, 0x0002}, /* 00,08,02,aa */
+ {0xaa, 0x09, 0x0006}, /* 00,09,06,aa */
+ {0xaa, 0x0a, 0x0001}, /* 00,0a,01,aa */
+ {0xaa, 0x0b, 0x0001}, /* 00,0b,01,aa */
+ {0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */
+ {0xaa, 0x0d, 0x0000}, /* 00,0d,00,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x12, 0x0005}, /* 00,12,05,aa */
+ {0xaa, 0x13, 0x0063}, /* 00,13,63,aa */
+ {0xaa, 0x15, 0x0070}, /* 00,15,70,aa */
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */
+ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+ {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+ {0xa0, 0x70, ZC3XX_R18D_YTARGET}, /* 01,8d,70,cc */
+ {}
+};
+static const struct usb_action pas202b_50HZ[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */
+ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */
+ {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */
+ {0xaa, 0x21, 0x0068}, /* 00,21,68,aa */
+ {0xaa, 0x03, 0x0044}, /* 00,03,44,aa */
+ {0xaa, 0x04, 0x0009}, /* 00,04,09,aa */
+ {0xaa, 0x05, 0x0028}, /* 00,05,28,aa */
+ {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */
+ {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,14,cc */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+ {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,d2,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x4d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,4d,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x44, ZC3XX_R01D_HSYNC_0}, /* 00,1d,44,cc */
+ {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */
+ {0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ad,cc */
+ {0xa0, 0xeb, ZC3XX_R020_HSYNC_3}, /* 00,20,eb,cc */
+ {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */
+ {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */
+ {}
+};
+static const struct usb_action pas202b_50HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */
+ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */
+ {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */
+ {0xaa, 0x21, 0x006c}, /* 00,21,6c,aa */
+ {0xaa, 0x03, 0x0041}, /* 00,03,41,aa */
+ {0xaa, 0x04, 0x0009}, /* 00,04,09,aa */
+ {0xaa, 0x05, 0x002c}, /* 00,05,2c,aa */
+ {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */
+ {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,14,cc */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x0f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0f,cc */
+ {0xa0, 0xbe, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,be,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x9b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,9b,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x41, ZC3XX_R01D_HSYNC_0}, /* 00,1d,41,cc */
+ {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */
+ {0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ad,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */
+ {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */
+ {}
+};
+static const struct usb_action pas202b_60HZ[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */
+ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */
+ {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */
+ {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+ {0xaa, 0x03, 0x0045}, /* 00,03,45,aa */
+ {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */
+ {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */
+ {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */
+ {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,14,cc */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+ {0xa0, 0xc0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,c0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x40, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,40,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x45, ZC3XX_R01D_HSYNC_0}, /* 00,1d,45,cc */
+ {0xa0, 0x8e, ZC3XX_R01E_HSYNC_1}, /* 00,1e,8e,cc */
+ {0xa0, 0xc1, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c1,cc */
+ {0xa0, 0xf5, ZC3XX_R020_HSYNC_3}, /* 00,20,f5,cc */
+ {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */
+ {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */
+ {}
+};
+static const struct usb_action pas202b_60HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */
+ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */
+ {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */
+ {0xaa, 0x21, 0x0004}, /* 00,21,04,aa */
+ {0xaa, 0x03, 0x0042}, /* 00,03,42,aa */
+ {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */
+ {0xaa, 0x05, 0x0004}, /* 00,05,04,aa */
+ {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */
+ {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,14,cc */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x0f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0f,cc */
+ {0xa0, 0x9f, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,9f,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,81,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x42, ZC3XX_R01D_HSYNC_0}, /* 00,1d,42,cc */
+ {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */
+ {0xa0, 0xaf, ZC3XX_R01F_HSYNC_2}, /* 00,1f,af,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */
+ {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */
+ {}
+};
+static const struct usb_action pas202b_NoFliker[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */
+ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */
+ {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */
+ {0xaa, 0x21, 0x0020}, /* 00,21,20,aa */
+ {0xaa, 0x03, 0x0040}, /* 00,03,40,aa */
+ {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */
+ {0xaa, 0x05, 0x0020}, /* 00,05,20,aa */
+ {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */
+ {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+ {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x02, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,02,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0x40, ZC3XX_R01D_HSYNC_0}, /* 00,1d,40,cc */
+ {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, /* 00,1e,60,cc */
+ {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */
+ {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */
+ {}
+};
+static const struct usb_action pas202b_NoFlikerScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */
+ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */
+ {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */
+ {0xaa, 0x21, 0x0010}, /* 00,21,10,aa */
+ {0xaa, 0x03, 0x0040}, /* 00,03,40,aa */
+ {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */
+ {0xaa, 0x05, 0x0010}, /* 00,05,10,aa */
+ {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */
+ {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+ {0xa0, 0x0f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0f,cc */
+ {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+ {0xa0, 0x02, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,02,cc */
+ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0x40, ZC3XX_R01D_HSYNC_0}, /* 00,1d,40,cc */
+ {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, /* 00,1e,60,cc */
+ {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+ {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */
+ {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */
+ {}
+};
+
static const struct usb_action pb03303x_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
@@ -5760,7 +5735,7 @@ static const struct usb_action tas5130cxx_Initial[] = {
{}
};
static const struct usb_action tas5130cxx_InitialScale[] = {
- {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+/*?? {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x40, ZC3XX_R002_CLOCKSELECT},
@@ -6084,7 +6059,7 @@ static const struct usb_action tas5130c_vf0250_InitialScale[] = {
{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */
{0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */
{0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
- {0xaa, 0x01, 0x0000},
+/*?? {0xaa, 0x01, 0x0000}, */
{0xaa, 0x01, 0x0000},
{0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */
{0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */
@@ -6100,8 +6075,8 @@ static const struct usb_action tas5130c_vf0250_InitialScale[] = {
{0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */
{0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */
{0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */
- {0xa0, 0x00, 0x0039},
- {0xa1, 0x01, 0x0037},
+/*?? {0xa0, 0x00, 0x0039},
+ {0xa1, 0x01, 0x0037}, */
{0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */
{0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa (e6 -> e8) */
{0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */
@@ -6338,7 +6313,7 @@ static __u8 i2c_write(struct gspca_dev *gspca_dev,
reg_w_i(gspca_dev->dev, valL, 0x93);
reg_w_i(gspca_dev->dev, valH, 0x94);
reg_w_i(gspca_dev->dev, 0x01, 0x90); /* <- write command */
- msleep(5);
+ msleep(15);
retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */
PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)",
reg, valH, valL, retbyte);
@@ -6381,31 +6356,35 @@ static void setmatrix(struct gspca_dev *gspca_dev)
{0x50, 0xf8, 0xf8, 0xf8, 0x50, 0xf8, 0xf8, 0xf8, 0x50};
static const __u8 ov7620_matrix[9] =
{0x58, 0xf4, 0xf4, 0xf4, 0x58, 0xf4, 0xf4, 0xf4, 0x58};
+ static const __u8 pas202b_matrix[9] =
+ {0x4c, 0xf5, 0xff, 0xf9, 0x51, 0xf5, 0xfb, 0xed, 0x5f};
static const __u8 po2030_matrix[9] =
{0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60};
static const __u8 vf0250_matrix[9] =
{0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b};
+ static const __u8 *matrix_tb[SENSOR_MAX] = {
+ NULL, /* SENSOR_CS2102 0 */
+ NULL, /* SENSOR_CS2102K 1 */
+ gc0305_matrix, /* SENSOR_GC0305 2 */
+ NULL, /* SENSOR_HDCS2020b 3 */
+ NULL, /* SENSOR_HV7131B 4 */
+ NULL, /* SENSOR_HV7131C 5 */
+ NULL, /* SENSOR_ICM105A 6 */
+ NULL, /* SENSOR_MC501CB 7 */
+ ov7620_matrix, /* SENSOR_OV7620 8 */
+ NULL, /* SENSOR_OV7630C 9 */
+ NULL, /* SENSOR_PAS106 10 */
+ pas202b_matrix, /* SENSOR_PAS202B 11 */
+ NULL, /* SENSOR_PB0330 12 */
+ po2030_matrix, /* SENSOR_PO2030 13 */
+ NULL, /* SENSOR_TAS5130CK 14 */
+ NULL, /* SENSOR_TAS5130CXX 15 */
+ vf0250_matrix, /* SENSOR_TAS5130C_VF0250 16 */
+ };
- switch (sd->sensor) {
- case SENSOR_GC0305:
- case SENSOR_HV7131B:
- matrix = gc0305_matrix;
- break;
- case SENSOR_MC501CB:
- return; /* no matrix? */
- case SENSOR_OV7620:
-/* case SENSOR_OV7648: */
- matrix = ov7620_matrix;
- break;
- case SENSOR_PO2030:
- matrix = po2030_matrix;
- break;
- case SENSOR_TAS5130C_VF0250:
- matrix = vf0250_matrix;
- break;
- default: /* matrix already loaded */
- return;
- }
+ matrix = matrix_tb[sd->sensor];
+ if (matrix == NULL)
+ return; /* matrix already loaded */
for (i = 0; i < ARRAY_SIZE(ov7620_matrix); i++)
reg_w(gspca_dev->dev, matrix[i], 0x010a + i);
}
@@ -6621,42 +6600,42 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
{gc0305_NoFliker, gc0305_NoFliker,
gc0305_50HZ, gc0305_50HZ,
gc0305_60HZ, gc0305_60HZ},
-/* SENSOR_HDCS2020 3 */
- {NULL, NULL,
- NULL, NULL,
- NULL, NULL},
-/* SENSOR_HDCS2020b 4 */
+/* SENSOR_HDCS2020b 3 */
{hdcs2020b_NoFliker, hdcs2020b_NoFliker,
hdcs2020b_50HZ, hdcs2020b_50HZ,
hdcs2020b_60HZ, hdcs2020b_60HZ},
-/* SENSOR_HV7131B 5 */
+/* SENSOR_HV7131B 4 */
{hv7131b_NoFlikerScale, hv7131b_NoFliker,
hv7131b_50HZScale, hv7131b_50HZ,
hv7131b_60HZScale, hv7131b_60HZ},
-/* SENSOR_HV7131C 6 */
+/* SENSOR_HV7131C 5 */
{NULL, NULL,
NULL, NULL,
NULL, NULL},
-/* SENSOR_ICM105A 7 */
+/* SENSOR_ICM105A 6 */
{icm105a_NoFliker, icm105a_NoFlikerScale,
icm105a_50HZ, icm105a_50HZScale,
icm105a_60HZ, icm105a_60HZScale},
-/* SENSOR_MC501CB 8 */
+/* SENSOR_MC501CB 7 */
{MC501CB_NoFliker, MC501CB_NoFlikerScale,
MC501CB_50HZ, MC501CB_50HZScale,
MC501CB_60HZ, MC501CB_60HZScale},
-/* SENSOR_OV7620 9 */
+/* SENSOR_OV7620 8 */
{OV7620_NoFliker, OV7620_NoFliker,
OV7620_50HZ, OV7620_50HZ,
OV7620_60HZ, OV7620_60HZ},
-/* SENSOR_OV7630C 10 */
+/* SENSOR_OV7630C 9 */
{NULL, NULL,
NULL, NULL,
NULL, NULL},
-/* SENSOR_PAS106 11 */
+/* SENSOR_PAS106 10 */
{pas106b_NoFliker, pas106b_NoFliker,
pas106b_50HZ, pas106b_50HZ,
pas106b_60HZ, pas106b_60HZ},
+/* SENSOR_PAS202B 11 */
+ {pas202b_NoFlikerScale, pas202b_NoFliker,
+ pas202b_50HZScale, pas202b_50HZ,
+ pas202b_60HZScale, pas202b_60HZ},
/* SENSOR_PB0330 12 */
{pb0330_NoFliker, pb0330_NoFlikerScale,
pb0330_50HZ, pb0330_50HZScale,
@@ -7038,15 +7017,15 @@ static int sd_config(struct gspca_dev *gspca_dev,
5, /* SENSOR_CS2102 0 */
5, /* SENSOR_CS2102K 1 */
4, /* SENSOR_GC0305 2 */
- 4, /* SENSOR_HDCS2020 3 */
- 4, /* SENSOR_HDCS2020b 4 */
- 4, /* SENSOR_HV7131B 5 */
- 4, /* SENSOR_HV7131C 6 */
- 4, /* SENSOR_ICM105A 7 */
- 4, /* SENSOR_MC501CB 8 */
- 3, /* SENSOR_OV7620 9 */
- 4, /* SENSOR_OV7630C 10 */
- 4, /* SENSOR_PAS106 11 */
+ 4, /* SENSOR_HDCS2020b 3 */
+ 4, /* SENSOR_HV7131B 4 */
+ 4, /* SENSOR_HV7131C 5 */
+ 4, /* SENSOR_ICM105A 6 */
+ 4, /* SENSOR_MC501CB 7 */
+ 3, /* SENSOR_OV7620 8 */
+ 4, /* SENSOR_OV7630C 9 */
+ 4, /* SENSOR_PAS106 10 */
+ 4, /* SENSOR_PAS202B 11 */
4, /* SENSOR_PB0330 12 */
4, /* SENSOR_PO2030 13 */
4, /* SENSOR_TAS5130CK 14 */
@@ -7102,8 +7081,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->sensor = SENSOR_ICM105A;
break;
case 0x0e:
- PDEBUG(D_PROBE, "Find Sensor HDCS2020");
- sd->sensor = SENSOR_HDCS2020;
+ PDEBUG(D_PROBE, "Find Sensor PAS202B");
+ sd->sensor = SENSOR_PAS202B;
sd->sharpness = 1;
break;
case 0x0f:
@@ -7196,7 +7175,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
case SENSOR_PO2030:
gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX);
break;
- case SENSOR_HDCS2020:
case SENSOR_HV7131B:
case SENSOR_HV7131C:
case SENSOR_OV7630C:
@@ -7226,15 +7204,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
{cs2102_InitialScale, cs2102_Initial}, /* 0 */
{cs2102K_InitialScale, cs2102K_Initial}, /* 1 */
{gc0305_Initial, gc0305_InitialScale}, /* 2 */
- {hdcs2020xx_InitialScale, hdcs2020xx_Initial}, /* 3 */
- {hdcs2020xb_InitialScale, hdcs2020xb_Initial}, /* 4 */
- {hv7131bxx_InitialScale, hv7131bxx_Initial}, /* 5 */
- {hv7131cxx_InitialScale, hv7131cxx_Initial}, /* 6 */
- {icm105axx_InitialScale, icm105axx_Initial}, /* 7 */
- {MC501CB_InitialScale, MC501CB_Initial}, /* 9 */
- {OV7620_mode0, OV7620_mode1}, /* 9 */
- {ov7630c_InitialScale, ov7630c_Initial}, /* 10 */
- {pas106b_InitialScale, pas106b_Initial}, /* 11 */
+ {hdcs2020xb_InitialScale, hdcs2020xb_Initial}, /* 3 */
+ {hv7131bxx_InitialScale, hv7131bxx_Initial}, /* 4 */
+ {hv7131cxx_InitialScale, hv7131cxx_Initial}, /* 5 */
+ {icm105axx_InitialScale, icm105axx_Initial}, /* 6 */
+ {MC501CB_InitialScale, MC501CB_Initial}, /* 7 */
+ {OV7620_mode0, OV7620_mode1}, /* 8 */
+ {ov7630c_InitialScale, ov7630c_Initial}, /* 9 */
+ {pas106b_InitialScale, pas106b_Initial}, /* 10 */
+ {pas202b_Initial, pas202b_InitialScale}, /* 11 */
{pb0330xx_InitialScale, pb0330xx_Initial}, /* 12 */
/* or {pb03303x_InitialScale, pb03303x_Initial}, */
{PO2030_mode0, PO2030_mode1}, /* 13 */
@@ -7291,6 +7269,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_r(gspca_dev, 0x0008);
reg_w(dev, 0x00, 0x0008);
break;
+ case SENSOR_PAS202B:
+#if 0/*fixme*/
+ reg_r(gspca_dev, ZC3XX_R002_CLOCKSELECT);
+ /* fall thru */
+#endif
case SENSOR_GC0305:
reg_r(gspca_dev, 0x0008);
/* fall thru */
@@ -7304,7 +7287,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
case SENSOR_CS2102: /* gamma set in xxx_Initial */
case SENSOR_CS2102K:
- case SENSOR_HDCS2020:
case SENSOR_HDCS2020b:
case SENSOR_PB0330: /* pb with chip_revision - see above */
case SENSOR_OV7630C:
@@ -7317,6 +7299,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
setmatrix(gspca_dev); /* one more time? */
switch (sd->sensor) {
case SENSOR_OV7620:
+ case SENSOR_PAS202B:
reg_r(gspca_dev, 0x0180); /* from win */
reg_w(dev, 0x00, 0x0180);
break;
@@ -7328,37 +7311,29 @@ static int sd_start(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
case SENSOR_GC0305:
- case SENSOR_OV7620:
reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
reg_w(dev, 0x15, 0x01ae);
- sd->autogain = 0;
- break;
+ /* fall thru */
+ case SENSOR_PAS202B:
case SENSOR_PO2030:
- reg_w(dev, 0x40, 0x0117); /* (from win traces) */
+/* reg_w(dev, 0x40, ZC3XX_R117_GGAIN); * (from win traces) */
reg_r(gspca_dev, 0x0180);
break;
- }
-
- setautogain(gspca_dev);
- switch (sd->sensor) {
- case SENSOR_GC0305:
-/* setlightfreq(gspca_dev); ?? (end: 80 -> [18d]) */
- reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
- reg_w(dev, 0x15, 0x01ae);
- reg_w(dev, 0x40, 0x0180);
- reg_w(dev, 0x40, 0x0117);
- reg_r(gspca_dev, 0x0180);
- sd->autogain = 1;
- setautogain(gspca_dev);
- break;
case SENSOR_OV7620:
+ reg_w(dev, 0x09, 0x01ad);
+ reg_w(dev, 0x15, 0x01ae);
i2c_read(gspca_dev, 0x13); /*fixme: returns 0xa3 */
i2c_write(gspca_dev, 0x13, 0xa3, 0x00);
/*fixme: returned value to send? */
- reg_w(dev, 0x40, 0x0117); /* (from win traces) */
+ reg_w(dev, 0x40, 0x0117);
reg_r(gspca_dev, 0x0180);
- setautogain(gspca_dev);
- msleep(500);
+ break;
+ }
+
+ setautogain(gspca_dev);
+ switch (sd->sensor) {
+ case SENSOR_PAS202B:
+ reg_w(dev, 0x00, 0x0007); /* (from win traces) */
break;
case SENSOR_PO2030:
msleep(500);
@@ -7368,6 +7343,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(dev, 0x02, 0x0008);
break;
}
+ if (sd->sensor == SENSOR_PAS202B)
+ reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
return 0;
}
@@ -7565,6 +7542,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x0458, 0x700c)},
{USB_DEVICE(0x0458, 0x700f)},
{USB_DEVICE(0x0461, 0x0a00)},
+ {USB_DEVICE(0x046d, 0x089d), .driver_info = SENSOR_MC501CB},
{USB_DEVICE(0x046d, 0x08a0)},
{USB_DEVICE(0x046d, 0x08a1)},
{USB_DEVICE(0x046d, 0x08a2)},
diff --git a/linux/drivers/media/video/hexium_gemini.c b/linux/drivers/media/video/hexium_gemini.c
index 185a862c0..043a3080b 100644
--- a/linux/drivers/media/video/hexium_gemini.c
+++ b/linux/drivers/media/video/hexium_gemini.c
@@ -307,7 +307,7 @@ static int hexium_detach(struct saa7146_dev *dev)
return 0;
}
-static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct saa7146_dev *dev = fh->dev;
struct hexium *hexium = (struct hexium *) dev->ext_priv;
diff --git a/linux/drivers/media/video/hexium_orion.c b/linux/drivers/media/video/hexium_orion.c
index 53db5fabc..847518f78 100644
--- a/linux/drivers/media/video/hexium_orion.c
+++ b/linux/drivers/media/video/hexium_orion.c
@@ -371,7 +371,7 @@ static int hexium_detach(struct saa7146_dev *dev)
return 0;
}
-static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct saa7146_dev *dev = fh->dev;
struct hexium *hexium = (struct hexium *) dev->ext_priv;
diff --git a/linux/drivers/media/video/ivtv/ivtv-controls.c b/linux/drivers/media/video/ivtv/ivtv-controls.c
index 48e103be7..62aa06f5d 100644
--- a/linux/drivers/media/video/ivtv/ivtv-controls.c
+++ b/linux/drivers/media/video/ivtv/ivtv-controls.c
@@ -63,7 +63,7 @@ int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
case V4L2_CID_HUE:
case V4L2_CID_SATURATION:
case V4L2_CID_CONTRAST:
- if (itv->video_dec_func(itv, VIDIOC_QUERYCTRL, qctrl))
+ if (v4l2_subdev_call(itv->sd_video, core, queryctrl, qctrl))
qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
return 0;
@@ -73,7 +73,7 @@ int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_LOUDNESS:
- if (ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl))
+ if (v4l2_subdev_call(itv->sd_audio, core, queryctrl, qctrl))
qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
return 0;
@@ -122,7 +122,7 @@ static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
case V4L2_CID_HUE:
case V4L2_CID_SATURATION:
case V4L2_CID_CONTRAST:
- return itv->video_dec_func(itv, VIDIOC_S_CTRL, vctrl);
+ return v4l2_subdev_call(itv->sd_video, core, s_ctrl, vctrl);
case V4L2_CID_AUDIO_VOLUME:
case V4L2_CID_AUDIO_MUTE:
@@ -130,7 +130,7 @@ static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_LOUDNESS:
- return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
+ return v4l2_subdev_call(itv->sd_audio, core, s_ctrl, vctrl);
default:
IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
@@ -147,7 +147,7 @@ static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
case V4L2_CID_HUE:
case V4L2_CID_SATURATION:
case V4L2_CID_CONTRAST:
- return itv->video_dec_func(itv, VIDIOC_G_CTRL, vctrl);
+ return v4l2_subdev_call(itv->sd_video, core, g_ctrl, vctrl);
case V4L2_CID_AUDIO_VOLUME:
case V4L2_CID_AUDIO_MUTE:
@@ -155,7 +155,7 @@ static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_LOUDNESS:
- return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
+ return v4l2_subdev_call(itv->sd_audio, core, g_ctrl, vctrl);
default:
IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
return -EINVAL;
@@ -268,7 +268,7 @@ int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1);
fmt.fmt.pix.height = itv->params.height;
- itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt);
+ v4l2_subdev_call(itv->sd_video, video, s_fmt, &fmt);
}
err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p);
if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt)
@@ -279,7 +279,7 @@ int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
/* The audio clock of the digitizer must match the codec sample
rate otherwise you get some very strange effects. */
if (idx < sizeof(freqs))
- ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]);
+ ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]);
return err;
}
return -EINVAL;
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c
index db866d912..b712c29e7 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.c
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.c
@@ -60,9 +60,6 @@
#include <media/v4l2-chip-ident.h>
#include "tuner-xc2028.h"
-/* var to keep track of the number of array elements in use */
-int ivtv_cards_active;
-
/* If you have already X v4l cards, then set this to X. This way
the device numbers stay matched. Example: you have a WinTV card
without radio and a PVR-350 with. Normally this would give a
@@ -70,12 +67,6 @@ int ivtv_cards_active;
setting this to 1 you ensure that radio0 is now also radio1. */
int ivtv_first_minor;
-/* Master variable for all ivtv info */
-struct ivtv *ivtv_cards[IVTV_MAX_CARDS];
-
-/* Protects ivtv_cards_active */
-DEFINE_SPINLOCK(ivtv_cards_lock);
-
/* add your revision and whatnot here */
static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15,
@@ -87,6 +78,9 @@ static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl);
+/* ivtv instance counter */
+static atomic_t ivtv_instance = ATOMIC_INIT(0);
+
/* Parameter declarations */
static int cardtype[IVTV_MAX_CARDS];
static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
@@ -599,9 +593,9 @@ static void ivtv_process_options(struct ivtv *itv)
itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024;
itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024;
itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers;
- itv->options.cardtype = cardtype[itv->num];
- itv->options.tuner = tuner[itv->num];
- itv->options.radio = radio[itv->num];
+ itv->options.cardtype = cardtype[itv->instance];
+ itv->options.tuner = tuner[itv->instance];
+ itv->options.radio = radio[itv->instance];
itv->options.newi2c = newi2c;
if (tunertype < -1 || tunertype > 1) {
IVTV_WARN("Invalid tunertype argument, will autodetect instead\n");
@@ -688,7 +682,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
spin_lock_init(&itv->lock);
spin_lock_init(&itv->dma_reg_lock);
- itv->irq_work_queues = create_singlethread_workqueue(itv->name);
+ itv->irq_work_queues = create_singlethread_workqueue(itv->device.name);
if (itv->irq_work_queues == NULL) {
IVTV_ERR("Could not create ivtv workqueue\n");
return -1;
@@ -774,12 +768,6 @@ static void __devinit ivtv_init_struct2(struct ivtv *itv)
i = 0;
itv->active_input = i;
itv->audio_input = itv->card->video_inputs[i].audio_index;
- if (itv->card->hw_all & IVTV_HW_CX25840)
- itv->video_dec_func = ivtv_cx25840;
- else if (itv->card->hw_all & IVTV_HW_SAA717X)
- itv->video_dec_func = ivtv_saa717x;
- else
- itv->video_dec_func = ivtv_saa7115;
}
static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
@@ -792,21 +780,21 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
IVTV_DEBUG_INFO("Enabling pci device\n");
if (pci_enable_device(dev)) {
- IVTV_ERR("Can't enable device %d!\n", itv->num);
+ IVTV_ERR("Can't enable device!\n");
return -EIO;
}
if (pci_set_dma_mask(dev, 0xffffffff)) {
- IVTV_ERR("No suitable DMA available on card %d.\n", itv->num);
+ IVTV_ERR("No suitable DMA available.\n");
return -EIO;
}
if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) {
- IVTV_ERR("Cannot request encoder memory region on card %d.\n", itv->num);
+ IVTV_ERR("Cannot request encoder memory region.\n");
return -EIO;
}
if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET,
IVTV_REG_SIZE, "ivtv registers")) {
- IVTV_ERR("Cannot request register memory region on card %d.\n", itv->num);
+ IVTV_ERR("Cannot request register memory region.\n");
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
return -EIO;
}
@@ -814,7 +802,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
if (itv->has_cx23415 &&
!request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET,
IVTV_DECODER_SIZE, "ivtv decoder")) {
- IVTV_ERR("Cannot request decoder memory region on card %d.\n", itv->num);
+ IVTV_ERR("Cannot request decoder memory region.\n");
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
return -EIO;
@@ -857,69 +845,11 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
return 0;
}
-#ifdef MODULE
-static u32 ivtv_request_module(struct ivtv *itv, u32 hw,
- const char *name, u32 id)
-{
- if ((hw & id) == 0)
- return hw;
- if (request_module(name) != 0) {
- IVTV_ERR("Failed to load module %s\n", name);
- return hw & ~id;
- }
- IVTV_DEBUG_INFO("Loaded module %s\n", name);
- return hw;
-}
-#endif
-
static void ivtv_load_and_init_modules(struct ivtv *itv)
{
u32 hw = itv->card->hw_all;
unsigned i;
-#ifdef MODULE
- /* load modules */
-#ifdef CONFIG_MEDIA_TUNER_MODULE
- hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER);
-#endif
-#ifdef CONFIG_VIDEO_CX25840_MODULE
- hw = ivtv_request_module(itv, hw, "cx25840", IVTV_HW_CX25840);
-#endif
-#ifdef CONFIG_VIDEO_SAA711X_MODULE
- hw = ivtv_request_module(itv, hw, "saa7115", IVTV_HW_SAA711X);
-#endif
-#ifdef CONFIG_VIDEO_SAA7127_MODULE
- hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127);
-#endif
-#ifdef CONFIG_VIDEO_SAA717X_MODULE
- hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X);
-#endif
-#ifdef CONFIG_VIDEO_UPD64031A_MODULE
- hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A);
-#endif
-#ifdef CONFIG_VIDEO_UPD64083_MODULE
- hw = ivtv_request_module(itv, hw, "upd64083", IVTV_HW_UPD6408X);
-#endif
-#ifdef CONFIG_VIDEO_MSP3400_MODULE
- hw = ivtv_request_module(itv, hw, "msp3400", IVTV_HW_MSP34XX);
-#endif
-#ifdef CONFIG_VIDEO_VP27SMPX_MODULE
- hw = ivtv_request_module(itv, hw, "vp27smpx", IVTV_HW_VP27SMPX);
-#endif
-#ifdef CONFIG_VIDEO_WM8775_MODULE
- hw = ivtv_request_module(itv, hw, "wm8775", IVTV_HW_WM8775);
-#endif
-#ifdef CONFIG_VIDEO_WM8739_MODULE
- hw = ivtv_request_module(itv, hw, "wm8739", IVTV_HW_WM8739);
-#endif
-#ifdef CONFIG_VIDEO_CS53L32A_MODULE
- hw = ivtv_request_module(itv, hw, "cs53l32a", IVTV_HW_CS53L32A);
-#endif
-#ifdef CONFIG_VIDEO_M52790_MODULE
- hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790);
-#endif
-#endif
-
/* check which i2c devices are actually found */
for (i = 0; i < 32; i++) {
u32 device = 1 << i;
@@ -931,11 +861,21 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
itv->hw_flags |= device;
continue;
}
- ivtv_i2c_register(itv, i);
- if (ivtv_i2c_hw_addr(itv, device) > 0)
+ if (ivtv_i2c_register(itv, i) == 0)
itv->hw_flags |= device;
}
+ if (itv->card->hw_all & IVTV_HW_CX25840)
+ itv->sd_video = ivtv_find_hw(itv, IVTV_HW_CX25840);
+ else if (itv->card->hw_all & IVTV_HW_SAA717X)
+ itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA717X);
+ else if (itv->card->hw_all & IVTV_HW_SAA7114)
+ itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA7114);
+ else
+ itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA7115);
+ itv->sd_audio = ivtv_find_hw(itv, itv->card->hw_audio_ctrl);
+ itv->sd_muxer = ivtv_find_hw(itv, itv->card->hw_muxer);
+
hw = itv->hw_flags;
if (itv->card->type == IVTV_CARD_CX23416GYC) {
@@ -953,7 +893,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
/* The crystal frequency of GVMVPRX is 24.576MHz */
crystal_freq.freq = SAA7115_FREQ_24_576_MHZ;
crystal_freq.flags = SAA7115_FREQ_FL_UCGC;
- itv->video_dec_func(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+ v4l2_subdev_call(itv->sd_video, video, s_crystal_freq, &crystal_freq);
}
if (hw & IVTV_HW_CX25840) {
@@ -966,18 +906,19 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
}
if (hw & IVTV_HW_SAA711X) {
- struct v4l2_chip_ident v = { V4L2_CHIP_MATCH_I2C_DRIVER, I2C_DRIVERID_SAA711X };
+ struct v4l2_dbg_chip_ident v;
/* determine the exact saa711x model */
itv->hw_flags &= ~IVTV_HW_SAA711X;
- ivtv_saa7115(itv, VIDIOC_G_CHIP_IDENT, &v);
+ v.match.type = V4L2_CHIP_MATCH_I2C_DRIVER;
+ strlcpy(v.match.name, "saa7115", sizeof(v.match.name));
+ ivtv_call_hw(itv, IVTV_HW_SAA711X, core, g_chip_ident, &v);
if (v.ident == V4L2_IDENT_SAA7114) {
itv->hw_flags |= IVTV_HW_SAA7114;
/* VBI is not yet supported by the saa7114 driver. */
itv->v4l2_cap &= ~(V4L2_CAP_SLICED_VBI_CAPTURE|V4L2_CAP_VBI_CAPTURE);
- }
- else {
+ } else {
itv->hw_flags |= IVTV_HW_SAA7115;
}
itv->vbi.raw_decoder_line_size = 1443;
@@ -1005,28 +946,20 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
int vbi_buf_size;
struct ivtv *itv;
- spin_lock(&ivtv_cards_lock);
-
- /* Make sure we've got a place for this card */
- if (ivtv_cards_active == IVTV_MAX_CARDS) {
- printk(KERN_ERR "ivtv: Maximum number of cards detected (%d)\n",
- ivtv_cards_active);
- spin_unlock(&ivtv_cards_lock);
- return -ENOMEM;
- }
-
itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC);
- if (itv == NULL) {
- spin_unlock(&ivtv_cards_lock);
+ if (itv == NULL)
return -ENOMEM;
- }
- ivtv_cards[ivtv_cards_active] = itv;
itv->dev = dev;
- itv->num = ivtv_cards_active++;
- snprintf(itv->name, sizeof(itv->name), "ivtv%d", itv->num);
- IVTV_INFO("Initializing card #%d\n", itv->num);
+ itv->instance = atomic_inc_return(&ivtv_instance) - 1;
- spin_unlock(&ivtv_cards_lock);
+ retval = v4l2_device_register(&dev->dev, &itv->device);
+ if (retval)
+ return retval;
+ /* "ivtv + PCI ID" is a bit of a mouthful, so use
+ "ivtv + instance" instead. */
+ snprintf(itv->device.name, sizeof(itv->device.name),
+ "ivtv%d", itv->instance);
+ IVTV_INFO("Initializing card %d\n", itv->instance);
ivtv_process_options(itv);
if (itv->options.cardtype == -1) {
@@ -1047,8 +980,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
else if (retval == -ENXIO)
goto free_mem;
}
- /* save itv in the pci struct for later use */
- pci_set_drvdata(dev, itv);
/* map io memory */
IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
@@ -1090,7 +1021,9 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
goto free_io;
}
- ivtv_gpio_init(itv);
+ retval = ivtv_gpio_init(itv);
+ if (retval)
+ goto free_io;
/* active i2c */
IVTV_DEBUG_INFO("activating i2c...\n");
@@ -1099,8 +1032,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
goto free_io;
}
- IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
-
if (itv->card->hw_all & IVTV_HW_TVEEPROM) {
/* Based on the model number the cardtype may be changed.
The PCI IDs are not always reliable. */
@@ -1195,7 +1126,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
setup.tuner_callback = (setup.type == TUNER_XC2028) ?
ivtv_reset_tuner_gpio : NULL;
- ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup);
+ ivtv_call_all(itv, tuner, s_type_addr, &setup);
if (setup.type == TUNER_XC2028) {
static struct xc2028_ctrl ctrl = {
.fname = XC2028_DEFAULT_FIRMWARE,
@@ -1205,7 +1136,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
.tuner = itv->options.tuner,
.priv = &ctrl,
};
- ivtv_call_i2c_clients(itv, TUNER_SET_CONFIG, &cfg);
+ ivtv_call_all(itv, tuner, s_config, &cfg);
}
}
@@ -1214,11 +1145,11 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
itv->tuner_std = itv->std;
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
- ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std);
+ ivtv_call_all(itv, video, s_std_output, itv->std);
/* Turn off the output signal. The mpeg decoder is not yet
active so without this you would get a green image until the
mpeg decoder becomes active. */
- ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
}
/* clear interrupt mask, effectively disabling interrupts */
@@ -1226,7 +1157,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
/* Register IRQ */
retval = request_irq(itv->dev->irq, ivtv_irq_handler,
- IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv);
+ IRQF_SHARED | IRQF_DISABLED, itv->device.name, (void *)itv);
if (retval) {
IVTV_ERR("Failed to register irq %d\n", retval);
goto free_i2c;
@@ -1242,7 +1173,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
IVTV_ERR("Error %d registering devices\n", retval);
goto free_streams;
}
- IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
+ IVTV_INFO("Initialized card: %s\n", itv->card_name);
return 0;
free_streams:
@@ -1265,10 +1196,8 @@ err:
retval = -ENODEV;
IVTV_ERR("Error %d on initialization\n", retval);
- spin_lock(&ivtv_cards_lock);
- kfree(ivtv_cards[ivtv_cards_active]);
- ivtv_cards[ivtv_cards_active] = NULL;
- spin_unlock(&ivtv_cards_lock);
+ v4l2_device_unregister(&itv->device);
+ kfree(itv);
return retval;
}
@@ -1308,10 +1237,11 @@ int ivtv_init_on_first_open(struct ivtv *itv)
if (itv->card->hw_all & IVTV_HW_CX25840) {
struct v4l2_control ctrl;
+ v4l2_subdev_call(itv->sd_video, core, init, 0);
/* CX25840_CID_ENABLE_PVR150_WORKAROUND */
ctrl.id = V4L2_CID_PRIVATE_BASE;
ctrl.value = itv->pvr150_workaround;
- itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl);
+ v4l2_subdev_call(itv->sd_video, core, s_ctrl, &ctrl);
}
vf.tuner = 0;
@@ -1341,7 +1271,7 @@ int ivtv_init_on_first_open(struct ivtv *itv)
/* Turn on the TV-out: ivtv_init_mpeg_decoder() initializes
the mpeg decoder so now the saa7127 receives a proper
signal. */
- ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
ivtv_init_mpeg_decoder(itv);
}
ivtv_s_std(NULL, &fh, &itv->tuner_std);
@@ -1366,9 +1296,11 @@ int ivtv_init_on_first_open(struct ivtv *itv)
static void ivtv_remove(struct pci_dev *pci_dev)
{
- struct ivtv *itv = pci_get_drvdata(pci_dev);
+ struct v4l2_device *dev = dev_get_drvdata(&pci_dev->dev);
+ struct ivtv *itv = to_ivtv(dev);
+ int i;
- IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num);
+ IVTV_DEBUG_INFO("Removing card\n");
if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) {
/* Stop all captures */
@@ -1381,7 +1313,7 @@ static void ivtv_remove(struct pci_dev *pci_dev)
/* Turn off the TV-out */
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
- ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
if (atomic_read(&itv->decoding) > 0) {
int type;
@@ -1406,6 +1338,8 @@ static void ivtv_remove(struct pci_dev *pci_dev)
ivtv_streams_cleanup(itv, 1);
ivtv_udma_free(itv);
+ v4l2_device_unregister(&itv->device);
+
exit_ivtv_i2c(itv);
free_irq(itv->dev->irq, (void *)itv);
@@ -1417,8 +1351,11 @@ static void ivtv_remove(struct pci_dev *pci_dev)
release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
pci_disable_device(itv->dev);
+ for (i = 0; i < IVTV_VBI_FRAMES; i++)
+ kfree(itv->vbi.sliced_mpeg_data[i]);
- IVTV_INFO("Removed %s, card #%d\n", itv->card_name, itv->num);
+ printk(KERN_INFO "ivtv: Removed %s\n", itv->card_name);
+ kfree(itv);
}
/* define a pci_driver for card detection */
@@ -1431,54 +1368,36 @@ static struct pci_driver ivtv_pci_driver = {
static int module_start(void)
{
- printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION);
-
- memset(ivtv_cards, 0, sizeof(ivtv_cards));
+ printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION);
/* Validate parameters */
if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
- printk(KERN_ERR "ivtv: Exiting, ivtv_first_minor must be between 0 and %d\n",
+ printk(KERN_ERR "ivtv: Exiting, ivtv_first_minor must be between 0 and %d\n",
IVTV_MAX_CARDS - 1);
return -1;
}
if (ivtv_debug < 0 || ivtv_debug > 2047) {
ivtv_debug = 0;
- printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n");
+ printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n");
}
if (pci_register_driver(&ivtv_pci_driver)) {
- printk(KERN_ERR "ivtv: Error detecting PCI card\n");
+ printk(KERN_ERR "ivtv: Error detecting PCI card\n");
return -ENODEV;
}
- printk(KERN_INFO "ivtv: End initialization\n");
+ printk(KERN_INFO "ivtv: End initialization\n");
return 0;
}
static void module_cleanup(void)
{
- int i, j;
-
pci_unregister_driver(&ivtv_pci_driver);
-
- spin_lock(&ivtv_cards_lock);
- for (i = 0; i < ivtv_cards_active; i++) {
- if (ivtv_cards[i] == NULL)
- continue;
- for (j = 0; j < IVTV_VBI_FRAMES; j++) {
- kfree(ivtv_cards[i]->vbi.sliced_mpeg_data[j]);
- }
- kfree(ivtv_cards[i]);
- }
- spin_unlock(&ivtv_cards_lock);
}
/* Note: These symbols are exported because they are used by the ivtvfb
framebuffer module and an infrared module for the IR-blaster. */
EXPORT_SYMBOL(ivtv_set_irq_mask);
-EXPORT_SYMBOL(ivtv_cards_active);
-EXPORT_SYMBOL(ivtv_cards);
-EXPORT_SYMBOL(ivtv_cards_lock);
EXPORT_SYMBOL(ivtv_api);
EXPORT_SYMBOL(ivtv_vapi);
EXPORT_SYMBOL(ivtv_vapi_result);
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h
index 9128df0f3..51f6e54ba 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.h
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.h
@@ -62,6 +62,7 @@
#include <linux/dvb/audio.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
#include <media/tuner.h>
#include <media/cx2341x.h>
@@ -114,9 +115,6 @@
#define IVTV_REG_VPU (0x9058)
#define IVTV_REG_APU (0xA064)
-/* i2c stuff */
-#define I2C_CLIENTS_MAX 16
-
/* debugging */
extern int ivtv_debug;
@@ -133,12 +131,10 @@ extern int ivtv_debug;
/* Flag to turn on high volume debugging */
#define IVTV_DBGFLG_HIGHVOL (1 << 10)
-/* NOTE: extra space before comma in 'itv->num , ## args' is required for
- gcc-2.95, otherwise it won't compile. */
#define IVTV_DEBUG(x, type, fmt, args...) \
do { \
if ((x) & ivtv_debug) \
- printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
+ v4l2_info(&itv->device, " " type ": " fmt , ##args); \
} while (0)
#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warn", fmt , ## args)
#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args)
@@ -153,8 +149,8 @@ extern int ivtv_debug;
#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
do { \
- if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
- printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
+ if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
+ v4l2_info(&itv->device, " " type ": " fmt , ##args); \
} while (0)
#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warn", fmt , ## args)
#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info", fmt , ## args)
@@ -168,9 +164,9 @@ extern int ivtv_debug;
#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
/* Standard kernel messages */
-#define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args)
-#define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args)
-#define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args)
+#define IVTV_ERR(fmt, args...) v4l2_err(&itv->device, fmt , ## args)
+#define IVTV_WARN(fmt, args...) v4l2_warn(&itv->device, fmt , ## args)
+#define IVTV_INFO(fmt, args...) v4l2_info(&itv->device, fmt , ## args)
/* output modes (cx23415 only) */
#define OUT_NONE 0
@@ -597,8 +593,6 @@ struct ivtv_card;
/* Struct to hold info about ivtv cards */
struct ivtv {
/* General fixed card data */
- int num; /* board number, -1 during init! */
- char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */
struct pci_dev *dev; /* PCI device */
const struct ivtv_card *card; /* card information */
const char *card_name; /* full name of the card */
@@ -610,14 +604,18 @@ struct ivtv {
u32 v4l2_cap; /* V4L2 capabilities of card */
u32 hw_flags; /* hardware description of the board */
v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */
- /* controlling video decoder function */
- int (*video_dec_func)(struct ivtv *, unsigned int, void *);
+ struct v4l2_subdev *sd_video; /* controlling video decoder subdev */
+ struct v4l2_subdev *sd_audio; /* controlling audio subdev */
+ struct v4l2_subdev *sd_muxer; /* controlling audio muxer subdev */
u32 base_addr; /* PCI resource base address */
volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */
volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */
volatile void __iomem *reg_mem; /* pointer to mapped registers */
struct ivtv_options options; /* user options */
+ struct v4l2_device device;
+ struct v4l2_subdev sd_gpio; /* GPIO sub-device */
+ u16 instance;
/* High-level state info */
unsigned long i_flags; /* global ivtv flags */
@@ -677,7 +675,6 @@ struct ivtv {
struct i2c_adapter i2c_adap;
struct i2c_algo_bit_data i2c_algo;
struct i2c_client i2c_client;
- struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];/* pointers to all I2C clients */
int i2c_state; /* i2c bit state */
struct mutex i2c_bus_lock; /* lock i2c bus */
@@ -723,11 +720,13 @@ struct ivtv {
struct osd_info *osd_info; /* ivtvfb private OSD info */
};
+static inline struct ivtv *to_ivtv(struct v4l2_device *dev)
+{
+ return container_of(dev, struct ivtv, device);
+}
+
/* Globals */
-extern struct ivtv *ivtv_cards[];
-extern int ivtv_cards_active;
extern int ivtv_first_minor;
-extern spinlock_t ivtv_cards_lock;
/*==============Prototypes==================*/
@@ -787,4 +786,19 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
#define write_dec_sync(val, addr) \
do { write_dec(val, addr); read_dec(addr); } while (0)
+/* Call the specified callback for all subdevs matching hw (if 0, then
+ match them all). Ignore any errors. */
+#define ivtv_call_hw(itv, hw, o, f, args...) \
+ __v4l2_device_call_subdevs(&(itv)->device, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+
+#define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args)
+
+/* Call the specified callback for all subdevs matching hw (if 0, then
+ match them all). If the callback returns an error other than 0 or
+ -ENOIOCTLCMD, then return with that error code. */
+#define ivtv_call_hw_err(itv, hw, o, f, args...) \
+ __v4l2_device_call_subdevs_until_err(&(itv)->device, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+
+#define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args)
+
#endif
diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c
index 1c404e454..d594bc29f 100644
--- a/linux/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c
@@ -155,7 +155,7 @@ static void ivtv_dualwatch(struct ivtv *itv)
new_stereo_mode = itv->params.audio_properties & stereo_mask;
memset(&vt, 0, sizeof(vt));
- ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, &vt);
+ ivtv_call_all(itv, tuner, g_tuner, &vt);
if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
new_stereo_mode = dual;
@@ -831,7 +831,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
ivtv_release_stream(s);
}
-int ivtv_v4l2_close(struct inode *inode, struct file *filp)
+int ivtv_v4l2_close(struct file *filp)
{
struct ivtv_open_id *id = filp->private_data;
struct ivtv *itv = id->itv;
@@ -857,7 +857,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
/* Mark that the radio is no longer in use */
clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
/* Switch tuner to TV */
- ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
+ ivtv_call_all(itv, tuner, s_std, itv->std);
/* Select correct audio input (i.e. TV tuner or Line in) */
ivtv_audio_set_io(itv);
if (itv->hw_flags & IVTV_HW_SAA711X)
@@ -865,7 +865,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
struct v4l2_crystal_freq crystal_freq;
crystal_freq.freq = SAA7115_FREQ_32_11_MHZ;
crystal_freq.flags = 0;
- ivtv_saa7115(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+ ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq, &crystal_freq);
}
if (atomic_read(&itv->capturing) > 0) {
/* Undo video mute */
@@ -952,15 +952,14 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
/* We have the radio */
ivtv_mute(itv);
/* Switch tuner to radio */
- ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL);
+ ivtv_call_all(itv, tuner, s_radio);
/* Select the correct audio input (i.e. radio tuner) */
ivtv_audio_set_io(itv);
- if (itv->hw_flags & IVTV_HW_SAA711X)
- {
+ if (itv->hw_flags & IVTV_HW_SAA711X) {
struct v4l2_crystal_freq crystal_freq;
crystal_freq.freq = SAA7115_FREQ_32_11_MHZ;
crystal_freq.flags = SAA7115_FREQ_FL_APLL;
- ivtv_saa7115(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+ ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq, &crystal_freq);
}
/* Done! Unmute and continue. */
ivtv_unmute(itv);
@@ -979,39 +978,20 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
return 0;
}
-int ivtv_v4l2_open(struct inode *inode, struct file *filp)
+int ivtv_v4l2_open(struct file *filp)
{
- int res, x, y = 0;
+ int res;
struct ivtv *itv = NULL;
struct ivtv_stream *s = NULL;
- int minor = iminor(inode);
-
- /* Find which card this open was on */
- spin_lock(&ivtv_cards_lock);
- for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
- if (ivtv_cards[x] == NULL)
- continue;
- /* find out which stream this open was on */
- for (y = 0; y < IVTV_MAX_STREAMS; y++) {
- s = &ivtv_cards[x]->streams[y];
- if (s->v4l2dev && s->v4l2dev->minor == minor) {
- itv = ivtv_cards[x];
- break;
- }
- }
- }
- spin_unlock(&ivtv_cards_lock);
+ struct video_device *vdev = video_devdata(filp);
- if (itv == NULL) {
- /* Couldn't find a device registered
- on that minor, shouldn't happen! */
- printk(KERN_WARNING "No ivtv device found on minor %d\n", minor);
- return -ENXIO;
- }
+ s = video_get_drvdata(vdev);
+ itv = s->itv;
mutex_lock(&itv->serialize_lock);
if (ivtv_init_on_first_open(itv)) {
- IVTV_ERR("Failed to initialize on minor %d\n", minor);
+ IVTV_ERR("Failed to initialize on minor %d\n",
+ s->v4l2dev->minor);
mutex_unlock(&itv->serialize_lock);
return -ENXIO;
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.h b/linux/drivers/media/video/ivtv/ivtv-fileops.h
index df81e7901..049a29239 100644
--- a/linux/drivers/media/video/ivtv/ivtv-fileops.h
+++ b/linux/drivers/media/video/ivtv/ivtv-fileops.h
@@ -22,12 +22,12 @@
#define IVTV_FILEOPS_H
/* Testing/Debugging */
-int ivtv_v4l2_open(struct inode *inode, struct file *filp);
+int ivtv_v4l2_open(struct file *filp);
ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count,
loff_t * pos);
ssize_t ivtv_v4l2_write(struct file *filp, const char __user *buf, size_t count,
loff_t * pos);
-int ivtv_v4l2_close(struct inode *inode, struct file *filp);
+int ivtv_v4l2_close(struct file *filp);
unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait);
unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table * wait);
int ivtv_start_capture(struct ivtv_open_id *id);
diff --git a/linux/drivers/media/video/ivtv/ivtv-gpio.c b/linux/drivers/media/video/ivtv/ivtv-gpio.c
index 74a44844c..dc2850e87 100644
--- a/linux/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/linux/drivers/media/video/ivtv/ivtv-gpio.c
@@ -144,22 +144,9 @@ int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value)
return 0;
}
-void ivtv_gpio_init(struct ivtv *itv)
+static inline struct ivtv *sd_to_ivtv(struct v4l2_subdev *sd)
{
- u16 pin = 0;
-
- if (itv->card->xceive_pin)
- pin = 1 << itv->card->xceive_pin;
-
- if ((itv->card->gpio_init.direction | pin) == 0)
- return;
-
- IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
- read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT));
-
- /* init output data then direction */
- write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT);
- write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR);
+ return container_of(sd, struct ivtv, sd_gpio);
}
static struct v4l2_queryctrl gpio_ctrl_mute = {
@@ -173,134 +160,231 @@ static struct v4l2_queryctrl gpio_ctrl_mute = {
.flags = 0,
};
-int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg)
+static int subdev_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
{
- struct v4l2_tuner *tuner = arg;
- struct v4l2_control *ctrl = arg;
- struct v4l2_routing *route = arg;
+ struct ivtv *itv = sd_to_ivtv(sd);
u16 mask, data;
- switch (command) {
- case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- mask = itv->card->gpio_audio_freq.mask;
- switch (*(u32 *)arg) {
- case 32000:
- data = itv->card->gpio_audio_freq.f32000;
- break;
- case 44100:
- data = itv->card->gpio_audio_freq.f44100;
- break;
- case 48000:
- default:
- data = itv->card->gpio_audio_freq.f48000;
- break;
- }
+ mask = itv->card->gpio_audio_freq.mask;
+ switch (freq) {
+ case 32000:
+ data = itv->card->gpio_audio_freq.f32000;
+ break;
+ case 44100:
+ data = itv->card->gpio_audio_freq.f44100;
+ break;
+ case 48000:
+ default:
+ data = itv->card->gpio_audio_freq.f48000;
break;
+ }
+ if (mask)
+ write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+ return 0;
+}
- case VIDIOC_G_TUNER:
- mask = itv->card->gpio_audio_detect.mask;
- if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask))
- tuner->rxsubchans = V4L2_TUNER_MODE_STEREO |
- V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
- else
- tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
- return 0;
+static int subdev_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct ivtv *itv = sd_to_ivtv(sd);
+ u16 mask;
+
+ mask = itv->card->gpio_audio_detect.mask;
+ if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask))
+ vt->rxsubchans = V4L2_TUNER_MODE_STEREO |
+ V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+ else
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+ return 0;
+}
- case VIDIOC_S_TUNER:
- mask = itv->card->gpio_audio_mode.mask;
- switch (tuner->audmode) {
- case V4L2_TUNER_MODE_LANG1:
- data = itv->card->gpio_audio_mode.lang1;
- break;
- case V4L2_TUNER_MODE_LANG2:
- data = itv->card->gpio_audio_mode.lang2;
- break;
- case V4L2_TUNER_MODE_MONO:
- data = itv->card->gpio_audio_mode.mono;
- break;
- case V4L2_TUNER_MODE_STEREO:
- case V4L2_TUNER_MODE_LANG1_LANG2:
- default:
- data = itv->card->gpio_audio_mode.stereo;
- break;
- }
- break;
+static int subdev_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct ivtv *itv = sd_to_ivtv(sd);
+ u16 mask, data;
- case AUDC_SET_RADIO:
- mask = itv->card->gpio_audio_input.mask;
- data = itv->card->gpio_audio_input.radio;
+ mask = itv->card->gpio_audio_mode.mask;
+ switch (vt->audmode) {
+ case V4L2_TUNER_MODE_LANG1:
+ data = itv->card->gpio_audio_mode.lang1;
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ data = itv->card->gpio_audio_mode.lang2;
+ break;
+ case V4L2_TUNER_MODE_MONO:
+ data = itv->card->gpio_audio_mode.mono;
break;
+ case V4L2_TUNER_MODE_STEREO:
+ case V4L2_TUNER_MODE_LANG1_LANG2:
+ default:
+ data = itv->card->gpio_audio_mode.stereo;
+ break;
+ }
+ if (mask)
+ write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+ return 0;
+}
+
+static int subdev_s_radio(struct v4l2_subdev *sd)
+{
+ struct ivtv *itv = sd_to_ivtv(sd);
+ u16 mask, data;
+
+ mask = itv->card->gpio_audio_input.mask;
+ data = itv->card->gpio_audio_input.radio;
+ if (mask)
+ write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+ return 0;
+}
- case VIDIOC_S_STD:
- mask = itv->card->gpio_audio_input.mask;
+static int subdev_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct ivtv *itv = sd_to_ivtv(sd);
+ u16 mask, data;
+
+ mask = itv->card->gpio_audio_input.mask;
+ data = itv->card->gpio_audio_input.tuner;
+ if (mask)
+ write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+ return 0;
+}
+
+static int subdev_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+ struct ivtv *itv = sd_to_ivtv(sd);
+ u16 mask, data;
+
+ if (route->input > 2)
+ return -EINVAL;
+ mask = itv->card->gpio_audio_input.mask;
+ switch (route->input) {
+ case 0:
data = itv->card->gpio_audio_input.tuner;
break;
-
- case VIDIOC_INT_S_AUDIO_ROUTING:
- if (route->input > 2)
- return -EINVAL;
- mask = itv->card->gpio_audio_input.mask;
- switch (route->input) {
- case 0:
- data = itv->card->gpio_audio_input.tuner;
- break;
- case 1:
- data = itv->card->gpio_audio_input.linein;
- break;
- case 2:
- default:
- data = itv->card->gpio_audio_input.radio;
- break;
- }
+ case 1:
+ data = itv->card->gpio_audio_input.linein;
+ break;
+ case 2:
+ default:
+ data = itv->card->gpio_audio_input.radio;
break;
+ }
+ if (mask)
+ write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+ return 0;
+}
- case VIDIOC_G_CTRL:
- if (ctrl->id != V4L2_CID_AUDIO_MUTE)
- return -EINVAL;
- mask = itv->card->gpio_audio_mute.mask;
- data = itv->card->gpio_audio_mute.mute;
- ctrl->value = (read_reg(IVTV_REG_GPIO_OUT) & mask) == data;
- return 0;
+static int subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct ivtv *itv = sd_to_ivtv(sd);
+ u16 mask, data;
- case VIDIOC_S_CTRL:
- if (ctrl->id != V4L2_CID_AUDIO_MUTE)
- return -EINVAL;
- mask = itv->card->gpio_audio_mute.mask;
- data = ctrl->value ? itv->card->gpio_audio_mute.mute : 0;
- break;
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ mask = itv->card->gpio_audio_mute.mask;
+ data = itv->card->gpio_audio_mute.mute;
+ ctrl->value = (read_reg(IVTV_REG_GPIO_OUT) & mask) == data;
+ return 0;
+}
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
+static int subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct ivtv *itv = sd_to_ivtv(sd);
+ u16 mask, data;
- if (qc->id != V4L2_CID_AUDIO_MUTE)
- return -EINVAL;
- *qc = gpio_ctrl_mute;
- return 0;
- }
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ mask = itv->card->gpio_audio_mute.mask;
+ data = ctrl->value ? itv->card->gpio_audio_mute.mute : 0;
+ if (mask)
+ write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+ return 0;
+}
+
+static int subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ if (qc->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ *qc = gpio_ctrl_mute;
+ return 0;
+}
+
+static int subdev_log_status(struct v4l2_subdev *sd)
+{
+ struct ivtv *itv = sd_to_ivtv(sd);
- case VIDIOC_LOG_STATUS:
- IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n",
+ IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n",
read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT),
read_reg(IVTV_REG_GPIO_IN));
- return 0;
+ return 0;
+}
- case VIDIOC_INT_S_VIDEO_ROUTING:
- if (route->input > 2) /* 0:Tuner 1:Composite 2:S-Video */
- return -EINVAL;
- mask = itv->card->gpio_video_input.mask;
- if (route->input == 0)
- data = itv->card->gpio_video_input.tuner;
- else if (route->input == 1)
- data = itv->card->gpio_video_input.composite;
- else
- data = itv->card->gpio_video_input.svideo;
- break;
+static int subdev_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+ struct ivtv *itv = sd_to_ivtv(sd);
+ u16 mask, data;
- default:
+ if (route->input > 2) /* 0:Tuner 1:Composite 2:S-Video */
return -EINVAL;
- }
+ mask = itv->card->gpio_video_input.mask;
+ if (route->input == 0)
+ data = itv->card->gpio_video_input.tuner;
+ else if (route->input == 1)
+ data = itv->card->gpio_video_input.composite;
+ else
+ data = itv->card->gpio_video_input.svideo;
if (mask)
write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
return 0;
}
+
+static const struct v4l2_subdev_core_ops subdev_core_ops = {
+ .log_status = subdev_log_status,
+ .g_ctrl = subdev_g_ctrl,
+ .s_ctrl = subdev_s_ctrl,
+ .queryctrl = subdev_queryctrl,
+};
+
+static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = {
+ .s_std = subdev_s_std,
+ .s_radio = subdev_s_radio,
+ .g_tuner = subdev_g_tuner,
+ .s_tuner = subdev_s_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops subdev_audio_ops = {
+ .s_clock_freq = subdev_s_clock_freq,
+ .s_routing = subdev_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops subdev_video_ops = {
+ .s_routing = subdev_s_video_routing,
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &subdev_core_ops,
+ .tuner = &subdev_tuner_ops,
+ .audio = &subdev_audio_ops,
+ .video = &subdev_video_ops,
+};
+
+int ivtv_gpio_init(struct ivtv *itv)
+{
+ u16 pin = 0;
+
+ if (itv->card->xceive_pin)
+ pin = 1 << itv->card->xceive_pin;
+
+ if ((itv->card->gpio_init.direction | pin) == 0)
+ return 0;
+
+ IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
+ read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT));
+
+ /* init output data then direction */
+ write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT);
+ write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR);
+ v4l2_subdev_init(&itv->sd_gpio, &subdev_ops);
+ snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->device.name);
+ itv->sd_gpio.grp_id = IVTV_HW_GPIO;
+ return v4l2_device_register_subdev(&itv->device, &itv->sd_gpio);
+}
diff --git a/linux/drivers/media/video/ivtv/ivtv-gpio.h b/linux/drivers/media/video/ivtv/ivtv-gpio.h
index 48b629161..0b5d19c8e 100644
--- a/linux/drivers/media/video/ivtv/ivtv-gpio.h
+++ b/linux/drivers/media/video/ivtv/ivtv-gpio.h
@@ -22,9 +22,8 @@
#define IVTV_GPIO_H
/* GPIO stuff */
-void ivtv_gpio_init(struct ivtv *itv);
+int ivtv_gpio_init(struct ivtv *itv);
void ivtv_reset_ir_gpio(struct ivtv *itv);
int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value);
-int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg);
#endif
diff --git a/linux/drivers/media/video/ivtv/ivtv-i2c.c b/linux/drivers/media/video/ivtv/ivtv-i2c.c
index c251ddb2f..41452e111 100644
--- a/linux/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/linux/drivers/media/video/ivtv/ivtv-i2c.c
@@ -90,26 +90,6 @@
#define IVTV_M52790_I2C_ADDR 0x48
/* This array should match the IVTV_HW_ defines */
-static const u8 hw_driverids[] = {
- I2C_DRIVERID_CX25840,
- I2C_DRIVERID_SAA711X,
- I2C_DRIVERID_SAA7127,
- I2C_DRIVERID_MSP3400,
- I2C_DRIVERID_TUNER,
- I2C_DRIVERID_WM8775,
- I2C_DRIVERID_CS53L32A,
- I2C_DRIVERID_TVEEPROM,
- I2C_DRIVERID_SAA711X,
- I2C_DRIVERID_UPD64031A,
- I2C_DRIVERID_UPD64083,
- I2C_DRIVERID_SAA717X,
- I2C_DRIVERID_WM8739,
- I2C_DRIVERID_VP27SMPX,
- I2C_DRIVERID_M52790,
- 0 /* IVTV_HW_GPIO dummy driver ID */
-};
-
-/* This array should match the IVTV_HW_ defines */
static const u8 hw_addrs[] = {
IVTV_CX25840_I2C_ADDR,
IVTV_SAA7115_I2C_ADDR,
@@ -130,6 +110,26 @@ static const u8 hw_addrs[] = {
};
/* This array should match the IVTV_HW_ defines */
+static const char *hw_modules[] = {
+ "cx25840",
+ "saa7115",
+ "saa7127",
+ "msp3400",
+ "tuner",
+ "wm8775",
+ "cs53l32a",
+ NULL,
+ "saa7115",
+ "upd64031a",
+ "upd64083",
+ "saa717x",
+ "wm8739",
+ "vp27smpx",
+ "m52790",
+ NULL
+};
+
+/* This array should match the IVTV_HW_ defines */
static const char * const hw_devicenames[] = {
"cx25840",
"saa7115",
@@ -155,104 +155,58 @@ static const char * const hw_devicenames[] = {
int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
- struct i2c_board_info info;
- struct i2c_client *c;
- u8 id;
- int i;
+ struct v4l2_subdev *sd;
+ struct i2c_adapter *adap = &itv->i2c_adap;
+ const char *mod = hw_modules[idx];
+ const char *type = hw_devicenames[idx];
+ u32 hw = 1 << idx;
- IVTV_DEBUG_I2C("i2c client register\n");
- if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
+ if (idx >= ARRAY_SIZE(hw_addrs))
return -1;
- id = hw_driverids[idx];
- memset(&info, 0, sizeof(info));
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
- strlcpy(info.driver_name, hw_devicenames[idx],
- sizeof(info.driver_name));
-#else
- strlcpy(info.type, hw_devicenames[idx], sizeof(info.type));
-#endif
- info.addr = hw_addrs[idx];
- for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {}
-
- if (i == I2C_CLIENTS_MAX) {
- IVTV_ERR("insufficient room for new I2C client!\n");
- return -ENOMEM;
+ if (hw == IVTV_HW_TUNER) {
+ /* special tuner handling */
+ sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
+ itv->card_i2c->radio);
+ if (sd)
+ sd->grp_id = 1 << idx;
+ sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
+ itv->card_i2c->demod);
+ if (sd)
+ sd->grp_id = 1 << idx;
+ sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
+ itv->card_i2c->tv);
+ if (sd)
+ sd->grp_id = 1 << idx;
+ return sd ? 0 : -1;
}
+ if (!hw_addrs[idx])
+ return -1;
+ if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) {
+ unsigned short addrs[2] = { hw_addrs[idx], I2C_CLIENT_END };
- if (id != I2C_DRIVERID_TUNER) {
- if (id == I2C_DRIVERID_UPD64031A ||
- id == I2C_DRIVERID_UPD64083) {
- unsigned short addrs[2] = { info.addr, I2C_CLIENT_END };
-
- c = i2c_new_probed_device(&itv->i2c_adap, &info, addrs);
- } else
- c = i2c_new_device(&itv->i2c_adap, &info);
- if (c && c->driver == NULL)
- i2c_unregister_device(c);
- else if (c)
- itv->i2c_clients[i] = c;
- return itv->i2c_clients[i] ? 0 : -ENODEV;
- }
-
- /* special tuner handling */
- c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->radio);
- if (c && c->driver == NULL)
- i2c_unregister_device(c);
- else if (c)
- itv->i2c_clients[i++] = c;
- c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->demod);
- if (c && c->driver == NULL)
- i2c_unregister_device(c);
- else if (c)
- itv->i2c_clients[i++] = c;
- c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->tv);
- if (c && c->driver == NULL)
- i2c_unregister_device(c);
- else if (c)
- itv->i2c_clients[i++] = c;
- return 0;
-#else
- return 0;
-#endif
-}
-
-static int attach_inform(struct i2c_client *client)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
- struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter);
- int i;
-
- IVTV_DEBUG_I2C("i2c client attach\n");
- for (i = 0; i < I2C_CLIENTS_MAX; i++) {
- if (itv->i2c_clients[i] == NULL) {
- itv->i2c_clients[i] = client;
- break;
- }
- }
- if (i == I2C_CLIENTS_MAX) {
- IVTV_ERR("Insufficient room for new I2C client\n");
+ sd = v4l2_i2c_new_probed_subdev(adap, mod, type, addrs);
+ } else {
+ sd = v4l2_i2c_new_subdev(adap, mod, type, hw_addrs[idx]);
}
-#endif
- return 0;
+ if (sd)
+ sd->grp_id = 1 << idx;
+ return sd ? 0 : -1;
}
-static int detach_inform(struct i2c_client *client)
+struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw)
{
- int i;
- struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter);
+ struct v4l2_subdev *result = NULL;
+ struct v4l2_subdev *sd;
- IVTV_DEBUG_I2C("i2c client detach\n");
- for (i = 0; i < I2C_CLIENTS_MAX; i++) {
- if (itv->i2c_clients[i] == client) {
- itv->i2c_clients[i] = NULL;
+ spin_lock(&itv->device.lock);
+ v4l2_device_for_each_subdev(sd, &itv->device) {
+ if (sd->grp_id == hw) {
+ result = sd;
break;
}
}
- IVTV_DEBUG_I2C("i2c detach [client=%s,%s]\n",
- client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed");
-
- return 0;
+ spin_unlock(&itv->device.lock);
+ return result;
}
/* Set the serial clock line to the desired state */
@@ -522,7 +476,8 @@ static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data,
intervening stop condition */
static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
{
- struct ivtv *itv = i2c_get_adapdata(i2c_adap);
+ struct v4l2_device *drv = i2c_get_adapdata(i2c_adap);
+ struct ivtv *itv = to_ivtv(drv);
int retval;
int i;
@@ -550,6 +505,9 @@ static u32 ivtv_functionality(struct i2c_adapter *adap)
static struct i2c_algorithm ivtv_algo = {
.master_xfer = ivtv_xfer,
.functionality = ivtv_functionality,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
/* template for our-bit banger */
@@ -558,8 +516,6 @@ static struct i2c_adapter ivtv_i2c_adap_hw_template = {
.id = I2C_HW_B_CX2341X,
.algo = &ivtv_algo,
.algo_data = NULL, /* filled from template */
- .client_register = attach_inform,
- .client_unregister = detach_inform,
.owner = THIS_MODULE,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
.class = I2C_CLASS_TV_ANALOG,
@@ -614,8 +570,6 @@ static struct i2c_adapter ivtv_i2c_adap_template = {
.id = I2C_HW_B_CX2341X,
.algo = NULL, /* set by i2c-algo-bit */
.algo_data = NULL, /* filled from template */
- .client_register = attach_inform,
- .client_unregister = detach_inform,
.owner = THIS_MODULE,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
.class = I2C_CLASS_TV_ANALOG,
@@ -635,160 +589,6 @@ static struct i2c_client ivtv_i2c_client_template = {
.name = "ivtv internal",
};
-int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg)
-{
- struct i2c_client *client;
- int retval;
- int i;
-
- IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
- for (i = 0; i < I2C_CLIENTS_MAX; i++) {
- client = itv->i2c_clients[i];
- if (client == NULL || client->driver == NULL ||
- client->driver->command == NULL)
- continue;
- if (addr == client->addr) {
- retval = client->driver->command(client, cmd, arg);
- return retval;
- }
- }
- if (cmd != VIDIOC_G_CHIP_IDENT)
- IVTV_ERR("i2c addr 0x%02x not found for command 0x%x\n", addr, cmd);
- return -ENODEV;
-}
-
-/* Find the i2c device based on the driver ID and return
- its i2c address or -ENODEV if no matching device was found. */
-static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id)
-{
- struct i2c_client *client;
- int retval = -ENODEV;
- int i;
-
- for (i = 0; i < I2C_CLIENTS_MAX; i++) {
- client = itv->i2c_clients[i];
- if (client == NULL || client->driver == NULL)
- continue;
- if (id == client->driver->id) {
- retval = client->addr;
- break;
- }
- }
- return retval;
-}
-
-/* Find the i2c device name matching the DRIVERID */
-static const char *ivtv_i2c_id_name(u32 id)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
- if (hw_driverids[i] == id)
- return hw_devicenames[i];
- return "unknown device";
-}
-
-/* Find the i2c device name matching the IVTV_HW_ flag */
-static const char *ivtv_i2c_hw_name(u32 hw)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
- if (1 << i == hw)
- return hw_devicenames[i];
- return "unknown device";
-}
-
-/* Find the i2c device matching the IVTV_HW_ flag and return
- its i2c address or -ENODEV if no matching device was found. */
-int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
- if (1 << i == hw)
- return ivtv_i2c_id_addr(itv, hw_driverids[i]);
- return -ENODEV;
-}
-
-/* Calls i2c device based on IVTV_HW_ flag. If hw == 0, then do nothing.
- If hw == IVTV_HW_GPIO then call the gpio handler. */
-int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg)
-{
- int addr;
-
- if (hw == IVTV_HW_GPIO)
- return ivtv_gpio(itv, cmd, arg);
- if (hw == 0)
- return 0;
-
- addr = ivtv_i2c_hw_addr(itv, hw);
- if (addr < 0) {
- IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x\n",
- hw, ivtv_i2c_hw_name(hw), cmd);
- return addr;
- }
- return ivtv_call_i2c_client(itv, addr, cmd, arg);
-}
-
-/* Calls i2c device based on I2C driver ID. */
-int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg)
-{
- int addr;
-
- addr = ivtv_i2c_id_addr(itv, id);
- if (addr < 0) {
- if (cmd != VIDIOC_G_CHIP_IDENT)
- IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x\n",
- id, ivtv_i2c_id_name(id), cmd);
- return addr;
- }
- return ivtv_call_i2c_client(itv, addr, cmd, arg);
-}
-
-int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg)
-{
- return ivtv_call_i2c_client(itv, IVTV_CX25840_I2C_ADDR, cmd, arg);
-}
-
-int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg)
-{
- return ivtv_call_i2c_client(itv, IVTV_SAA7115_I2C_ADDR, cmd, arg);
-}
-
-int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg)
-{
- return ivtv_call_i2c_client(itv, IVTV_SAA7127_I2C_ADDR, cmd, arg);
-}
-EXPORT_SYMBOL(ivtv_saa7127);
-
-int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg)
-{
- return ivtv_call_i2c_client(itv, IVTV_SAA717x_I2C_ADDR, cmd, arg);
-}
-
-int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg)
-{
- return ivtv_call_i2c_client(itv, IVTV_UPD64031A_I2C_ADDR, cmd, arg);
-}
-
-int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg)
-{
- return ivtv_call_i2c_client(itv, IVTV_UPD64083_I2C_ADDR, cmd, arg);
-}
-
-/* broadcast cmd for all I2C clients and for the gpio subsystem */
-void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg)
-{
- if (itv->i2c_adap.algo == NULL) {
- IVTV_ERR("Adapter is not set");
- return;
- }
- i2c_clients_command(&itv->i2c_adap, cmd, arg);
- if (itv->hw_flags & IVTV_HW_GPIO)
- ivtv_gpio(itv, cmd, arg);
-}
-
/* init + register i2c algo-bit adapter */
int init_ivtv_i2c(struct ivtv *itv)
{
@@ -797,10 +597,9 @@ int init_ivtv_i2c(struct ivtv *itv)
/* Sanity checks for the I2C hardware arrays. They must be the
* same size and GPIO must be the last entry.
*/
- if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
- ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
- IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
- hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
+ if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
+ ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_modules) ||
+ IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1))) {
IVTV_ERR("Mismatched I2C hardware arrays\n");
return -ENODEV;
}
@@ -817,8 +616,8 @@ int init_ivtv_i2c(struct ivtv *itv)
itv->i2c_adap.algo_data = &itv->i2c_algo;
sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d",
- itv->num);
- i2c_set_adapdata(&itv->i2c_adap, itv);
+ itv->instance);
+ i2c_set_adapdata(&itv->i2c_adap, &itv->device);
memcpy(&itv->i2c_client, &ivtv_i2c_client_template,
sizeof(struct i2c_client));
diff --git a/linux/drivers/media/video/ivtv/ivtv-i2c.h b/linux/drivers/media/video/ivtv/ivtv-i2c.h
index 022978cf5..396928a06 100644
--- a/linux/drivers/media/video/ivtv/ivtv-i2c.h
+++ b/linux/drivers/media/video/ivtv/ivtv-i2c.h
@@ -21,19 +21,8 @@
#ifndef IVTV_I2C_H
#define IVTV_I2C_H
-int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg);
-
-int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw);
-int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg);
-int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg);
-int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg);
-void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg);
int ivtv_i2c_register(struct ivtv *itv, unsigned idx);
+struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw);
/* init + register i2c algo-bit adapter */
int init_ivtv_i2c(struct ivtv *itv);
diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c
index 4bae38d21..f6b3ef6e6 100644
--- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -393,7 +393,7 @@ static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo
return 0;
}
- itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
+ v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
vbifmt->service_set = ivtv_get_service_set(vbifmt);
return 0;
}
@@ -581,7 +581,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
p->height = h;
if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
fmt->fmt.pix.width /= 2;
- itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+ v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
return ivtv_g_fmt_vid_cap(file, fh, fmt);
}
@@ -593,7 +593,7 @@ static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f
return -EBUSY;
itv->vbi.sliced_in->service_set = 0;
itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
- itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+ v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
return ivtv_g_fmt_vbi_cap(file, fh, fmt);
}
@@ -611,7 +611,7 @@ static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo
if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
return -EBUSY;
itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
- itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+ v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
return 0;
}
@@ -674,29 +674,28 @@ static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_f
return ret;
}
-static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_chip_ident *chip)
+static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
chip->ident = V4L2_IDENT_NONE;
chip->revision = 0;
- if (chip->match_type == V4L2_CHIP_MATCH_HOST) {
- if (v4l2_chip_match_host(chip->match_type, chip->match_chip))
+ if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
+ if (v4l2_chip_match_host(&chip->match))
chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
return 0;
}
- if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return ivtv_i2c_id(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip);
- if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
- return ivtv_call_i2c_client(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip);
- return -EINVAL;
+ if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+ chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+ /* TODO: is this correct? */
+ return ivtv_call_all_err(itv, core, g_chip_ident, chip);
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
{
- struct v4l2_register *regs = arg;
- unsigned long flags;
+ struct v4l2_dbg_register *regs = arg;
volatile u8 __iomem *reg_start;
if (!capable(CAP_SYS_ADMIN))
@@ -711,35 +710,36 @@ static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
else
return -EINVAL;
- spin_lock_irqsave(&ivtv_cards_lock, flags);
+ regs->size = 4;
if (cmd == VIDIOC_DBG_G_REGISTER)
regs->val = readl(regs->reg + reg_start);
else
writel(regs->val, regs->reg + reg_start);
- spin_unlock_irqrestore(&ivtv_cards_lock, flags);
return 0;
}
-static int ivtv_g_register(struct file *file, void *fh, struct v4l2_register *reg)
+static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (v4l2_chip_match_host(&reg->match))
return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg);
- return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg);
+ /* TODO: subdev errors should not be ignored, this should become a
+ subdev helper function. */
+ ivtv_call_all(itv, core, g_register, reg);
+ return 0;
}
-static int ivtv_s_register(struct file *file, void *fh, struct v4l2_register *reg)
+static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (v4l2_chip_match_host(&reg->match))
return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg);
- return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg);
+ /* TODO: subdev errors should not be ignored, this should become a
+ subdev helper function. */
+ ivtv_call_all(itv, core, s_register, reg);
+ return 0;
}
#endif
@@ -884,12 +884,6 @@ static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
streamtype = id->type;
- if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
- printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
- /* Should be replaced */
- /* v4l_printk_ioctl(VIDIOC_S_CROP); */
- }
-
if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
@@ -1050,7 +1044,7 @@ static int ivtv_s_output(struct file *file, void *fh, unsigned int outp)
itv->active_output = outp;
route.input = SAA7127_INPUT_TYPE_NORMAL;
route.output = itv->card->video_outputs[outp].video_output;
- ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing, &route);
return 0;
}
@@ -1062,7 +1056,7 @@ static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *
if (vf->tuner != 0)
return -EINVAL;
- ivtv_call_i2c_clients(itv, VIDIOC_G_FREQUENCY, vf);
+ ivtv_call_all(itv, tuner, g_frequency, vf);
return 0;
}
@@ -1075,7 +1069,7 @@ int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
ivtv_mute(itv);
IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
- ivtv_call_i2c_clients(itv, VIDIOC_S_FREQUENCY, vf);
+ ivtv_call_all(itv, tuner, s_frequency, vf);
ivtv_unmute(itv);
return 0;
}
@@ -1123,14 +1117,14 @@ int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
/* Tuner */
- ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
+ ivtv_call_all(itv, tuner, s_std, itv->std);
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
/* set display standard */
itv->std_out = *std;
itv->is_out_60hz = itv->is_60hz;
itv->is_out_50hz = itv->is_50hz;
- ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out);
+ ivtv_call_all(itv, video, s_std_output, itv->std_out);
ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
itv->main_rect.left = itv->main_rect.top = 0;
itv->main_rect.width = 720;
@@ -1154,7 +1148,7 @@ static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
if (vt->index != 0)
return -EINVAL;
- ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt);
+ ivtv_call_all(itv, tuner, s_tuner, vt);
return 0;
}
@@ -1166,7 +1160,7 @@ static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
if (vt->index != 0)
return -EINVAL;
- ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
+ ivtv_call_all(itv, tuner, g_tuner, vt);
if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
@@ -1444,14 +1438,15 @@ static int ivtv_log_status(struct file *file, void *fh)
struct v4l2_audio audin;
int i;
- IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num);
+ IVTV_INFO("================= START STATUS CARD #%d =================\n",
+ itv->instance);
IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
if (itv->hw_flags & IVTV_HW_TVEEPROM) {
struct tveeprom tv;
ivtv_read_eeprom(itv, &tv);
}
- ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
+ ivtv_call_all(itv, core, log_status);
ivtv_get_input(itv, itv->active_input, &vidin);
ivtv_get_audio_input(itv, itv->audio_input, &audin);
IVTV_INFO("Video Input: %s\n", vidin.name);
@@ -1518,7 +1513,7 @@ static int ivtv_log_status(struct file *file, void *fh)
}
IVTV_INFO("Tuner: %s\n",
test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
- cx2341x_log_status(&itv->params, itv->name);
+ cx2341x_log_status(&itv->params, itv->device.name);
IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
for (i = 0; i < IVTV_MAX_STREAMS; i++) {
struct ivtv_stream *s = &itv->streams[i];
@@ -1530,8 +1525,11 @@ static int ivtv_log_status(struct file *file, void *fh)
(s->buffers * s->buf_size) / 1024, s->buffers);
}
- IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
- IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num);
+ IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n",
+ (long long)itv->mpg_data_received,
+ (long long)itv->vbi_data_inserted);
+ IVTV_INFO("================== END STATUS CARD #%d ==================\n",
+ itv->instance);
return 0;
}
@@ -1728,7 +1726,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
return 0;
}
-static int ivtv_default(struct file *file, void *fh, int cmd, void *arg)
+static long ivtv_default(struct file *file, void *fh, int cmd, void *arg)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
@@ -1736,7 +1734,7 @@ static int ivtv_default(struct file *file, void *fh, int cmd, void *arg)
case VIDIOC_INT_S_AUDIO_ROUTING: {
struct v4l2_routing *route = arg;
- ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
+ ivtv_call_hw(itv, itv->card->hw_audio, audio, s_routing, route);
break;
}
@@ -1746,7 +1744,7 @@ static int ivtv_default(struct file *file, void *fh, int cmd, void *arg)
if ((val == 0 && itv->options.newi2c) || (val & 0x01))
ivtv_reset_ir_gpio(itv);
if (val & 0x02)
- itv->video_dec_func(itv, cmd, NULL);
+ v4l2_subdev_call(itv->sd_video, core, reset, 0);
break;
}
@@ -1830,7 +1828,7 @@ static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp,
if (ivtv_debug & IVTV_DBGFLG_IOCTL)
vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
- ret = __video_ioctl2(filp, cmd, arg);
+ ret = video_ioctl2(filp, cmd, arg);
vfd->debug = 0;
return ret;
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-routing.c b/linux/drivers/media/video/ivtv/ivtv-routing.c
index 05564919b..3fd302294 100644
--- a/linux/drivers/media/video/ivtv/ivtv-routing.c
+++ b/linux/drivers/media/video/ivtv/ivtv-routing.c
@@ -47,13 +47,13 @@ void ivtv_audio_set_io(struct ivtv *itv)
route.output = 0;
if (itv->card->hw_muxer & IVTV_HW_M52790)
route.output = M52790_OUT_STEREO;
- ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ v4l2_subdev_call(itv->sd_muxer, audio, s_routing, &route);
route.input = in->audio_input;
route.output = 0;
if (itv->card->hw_audio & IVTV_HW_MSP34XX)
route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
- ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ ivtv_call_hw(itv, itv->card->hw_audio, audio, s_routing, &route);
}
/* Selects the video input and output according to the current
@@ -66,7 +66,7 @@ void ivtv_video_set_io(struct ivtv *itv)
route.input = itv->card->video_inputs[inp].video_input;
route.output = 0;
- itv->video_dec_func(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+ v4l2_subdev_call(itv->sd_video, video, s_routing, &route);
type = itv->card->video_inputs[inp].video_type;
@@ -79,7 +79,7 @@ void ivtv_video_set_io(struct ivtv *itv)
}
if (itv->card->hw_video & IVTV_HW_GPIO)
- ivtv_gpio(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+ ivtv_call_hw(itv, IVTV_HW_GPIO, video, s_routing, &route);
if (itv->card->hw_video & IVTV_HW_UPD64031A) {
if (type == IVTV_CARD_INPUT_VID_TUNER ||
@@ -92,7 +92,7 @@ void ivtv_video_set_io(struct ivtv *itv)
}
route.input |= itv->card->gr_config;
- ivtv_upd64031a(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+ ivtv_call_hw(itv, IVTV_HW_UPD64031A, video, s_routing, &route);
}
if (itv->card->hw_video & IVTV_HW_UPD6408X) {
@@ -110,6 +110,6 @@ void ivtv_video_set_io(struct ivtv *itv)
route.input |= UPD64083_EXT_Y_ADC;
}
}
- ivtv_upd64083(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+ ivtv_call_hw(itv, IVTV_HW_UPD6408X, video, s_routing, &route);
}
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c
index 9b7aa79eb..854a950af 100644
--- a/linux/drivers/media/video/ivtv/ivtv-streams.c
+++ b/linux/drivers/media/video/ivtv/ivtv-streams.c
@@ -43,24 +43,22 @@
#include "ivtv-cards.h"
#include "ivtv-streams.h"
-static const struct file_operations ivtv_v4l2_enc_fops = {
+static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
.owner = THIS_MODULE,
.read = ivtv_v4l2_read,
.write = ivtv_v4l2_write,
.open = ivtv_v4l2_open,
.unlocked_ioctl = ivtv_v4l2_ioctl,
- .compat_ioctl = v4l_compat_ioctl32,
.release = ivtv_v4l2_close,
.poll = ivtv_v4l2_enc_poll,
};
-static const struct file_operations ivtv_v4l2_dec_fops = {
+static const struct v4l2_file_operations ivtv_v4l2_dec_fops = {
.owner = THIS_MODULE,
.read = ivtv_v4l2_read,
.write = ivtv_v4l2_write,
.open = ivtv_v4l2_open,
.unlocked_ioctl = ivtv_v4l2_ioctl,
- .compat_ioctl = v4l_compat_ioctl32,
.release = ivtv_v4l2_close,
.poll = ivtv_v4l2_dec_poll,
};
@@ -78,7 +76,7 @@ static struct {
int num_offset;
int dma, pio;
enum v4l2_buf_type buf_type;
- const struct file_operations *fops;
+ const struct v4l2_file_operations *fops;
} ivtv_stream_info[] = {
{ /* IVTV_ENC_STREAM_TYPE_MPG */
"encoder MPG",
@@ -172,7 +170,7 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
{
struct ivtv_stream *s = &itv->streams[type];
int num_offset = ivtv_stream_info[type].num_offset;
- int num = itv->num + ivtv_first_minor + num_offset;
+ int num = itv->instance + ivtv_first_minor + num_offset;
/* These four fields are always initialized. If v4l2dev == NULL, then
this stream is not in use. In that case no other fields but these
@@ -205,11 +203,11 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
return -ENOMEM;
}
- snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s",
- itv->num, s->name);
+ snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "%s %s",
+ itv->device.name, s->name);
s->v4l2dev->num = num;
- s->v4l2dev->parent = &itv->dev->dev;
+ s->v4l2dev->v4l2_dev = &itv->device;
s->v4l2dev->fops = ivtv_stream_info[type].fops;
s->v4l2dev->release = video_device_release;
s->v4l2dev->tvnorms = V4L2_STD_ALL;
@@ -260,6 +258,7 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
if (s_mpg->v4l2dev)
num = s_mpg->v4l2dev->num + ivtv_stream_info[type].num_offset;
}
+ video_set_drvdata(s->v4l2dev, s);
/* Register device. First try the desired minor, then any free one. */
if (video_register_device(s->v4l2dev, vfl_type, num)) {
@@ -343,7 +342,7 @@ static void ivtv_vbi_setup(struct ivtv *itv)
ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);
/* setup VBI registers */
- itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
+ v4l2_subdev_call(itv->sd_video, video, s_fmt, &itv->vbi.in);
/* determine number of lines and total number of VBI bytes.
A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
@@ -577,10 +576,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
clear_bit(IVTV_F_I_EOS, &itv->i_flags);
/* Initialize Digitizer for Capture */
- itv->video_dec_func(itv, VIDIOC_STREAMOFF, NULL);
+ v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
ivtv_msleep_timeout(300, 1);
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
- itv->video_dec_func(itv, VIDIOC_STREAMON, NULL);
+ v4l2_subdev_call(itv->sd_video, video, s_stream, 1);
}
/* begin_capture */
diff --git a/linux/drivers/media/video/ivtv/ivtv-vbi.c b/linux/drivers/media/video/ivtv/ivtv-vbi.c
index 4a37a7d2e..5c5d1c462 100644
--- a/linux/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/linux/drivers/media/video/ivtv/ivtv-vbi.c
@@ -21,6 +21,7 @@
#include "ivtv-i2c.h"
#include "ivtv-ioctl.h"
#include "ivtv-queue.h"
+#include "ivtv-cards.h"
#include "ivtv-vbi.h"
static void ivtv_set_vps(struct ivtv *itv, int enabled)
@@ -37,7 +38,7 @@ static void ivtv_set_vps(struct ivtv *itv, int enabled)
data.data[9] = itv->vbi.vps_payload.data[2];
data.data[10] = itv->vbi.vps_payload.data[3];
data.data[11] = itv->vbi.vps_payload.data[4];
- ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
}
static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
@@ -51,12 +52,12 @@ static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
data.line = (mode & 1) ? 21 : 0;
data.data[0] = cc->odd[0];
data.data[1] = cc->odd[1];
- ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
data.field = 1;
data.line = (mode & 2) ? 21 : 0;
data.data[0] = cc->even[0];
data.data[1] = cc->even[1];
- ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
}
static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
@@ -79,7 +80,7 @@ static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
data.line = enabled ? 23 : 0;
data.data[0] = mode & 0xff;
data.data[1] = (mode >> 8) & 0xff;
- ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
}
static int odd_parity(u8 c)
@@ -313,7 +314,7 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8
continue;
}
vbi.p = p + 4;
- itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
+ v4l2_subdev_call(itv->sd_video, video, decode_vbi_line, &vbi);
if (vbi.type && !(lines & (1 << vbi.line))) {
lines |= 1 << vbi.line;
itv->vbi.sliced_data[line].id = vbi.type;
@@ -437,7 +438,7 @@ void ivtv_vbi_work_handler(struct ivtv *itv)
data.id = V4L2_SLICED_WSS_625;
data.field = 0;
- if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
+ if (v4l2_subdev_call(itv->sd_video, video, g_vbi_data, &data) == 0) {
ivtv_set_wss(itv, 1, data.data[0] & 0xf);
vi->wss_missing_cnt = 0;
} else if (vi->wss_missing_cnt == 4) {
@@ -451,13 +452,13 @@ void ivtv_vbi_work_handler(struct ivtv *itv)
data.id = V4L2_SLICED_CAPTION_525;
data.field = 0;
- if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
+ if (v4l2_subdev_call(itv->sd_video, video, g_vbi_data, &data) == 0) {
mode |= 1;
cc.odd[0] = data.data[0];
cc.odd[1] = data.data[1];
}
data.field = 1;
- if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
+ if (v4l2_subdev_call(itv->sd_video, video, g_vbi_data, &data) == 0) {
mode |= 2;
cc.even[0] = data.data[0];
cc.even[1] = data.data[1];
diff --git a/linux/drivers/media/video/ivtv/ivtvfb.c b/linux/drivers/media/video/ivtv/ivtvfb.c
index 5e3613d86..26b91d2c8 100644
--- a/linux/drivers/media/video/ivtv/ivtvfb.c
+++ b/linux/drivers/media/video/ivtv/ivtvfb.c
@@ -48,6 +48,7 @@
#endif
#include "ivtv-driver.h"
+#include "ivtv-cards.h"
#include "ivtv-i2c.h"
#include "ivtv-udma.h"
#include "ivtv-mailbox.h"
@@ -121,15 +122,15 @@ MODULE_LICENSE("GPL");
#define IVTVFB_DEBUG(x, type, fmt, args...) \
do { \
if ((x) & ivtvfb_debug) \
- printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \
+ printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->instance , ## args); \
} while (0)
#define IVTVFB_DEBUG_WARN(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
#define IVTVFB_DEBUG_INFO(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
/* Standard kernel messages */
-#define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->num , ## args)
-#define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->num , ## args)
-#define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args)
+#define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->instance , ## args)
+#define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->instance , ## args)
+#define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->instance , ## args)
/* --------------------------------------------------------------------- */
@@ -904,16 +905,16 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info)
switch (blank_mode) {
case FB_BLANK_UNBLANK:
ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
- ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
break;
case FB_BLANK_NORMAL:
case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_VSYNC_SUSPEND:
ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
- ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
break;
case FB_BLANK_POWERDOWN:
- ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
break;
}
@@ -1197,10 +1198,45 @@ static int ivtvfb_init_card(struct ivtv *itv)
}
+static int __init ivtvfb_callback_init(struct device *dev, void *p)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+ struct ivtv *itv = container_of(v4l2_dev, struct ivtv, device);
+
+ if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ if (ivtvfb_init_card(itv) == 0) {
+ IVTVFB_INFO("Framebuffer registered on %s\n",
+ itv->device.name);
+ (*(int *)p)++;
+ }
+ }
+ return 0;
+}
+
+static int ivtvfb_callback_cleanup(struct device *dev, void *p)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+ struct ivtv *itv = container_of(v4l2_dev, struct ivtv, device);
+
+ if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
+ IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
+ itv->instance);
+ return 0;
+ }
+ IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
+ ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
+ ivtvfb_release_buffers(itv);
+ itv->osd_video_pbase = 0;
+ }
+ return 0;
+}
+
static int __init ivtvfb_init(void)
{
- struct ivtv *itv;
- int i, registered = 0;
+ struct device_driver *drv;
+ int registered = 0;
+ int err;
if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
@@ -1208,20 +1244,11 @@ static int __init ivtvfb_init(void)
return -EINVAL;
}
- /* Locate & initialise all cards supporting an OSD. */
- for (i = 0; i < ivtv_cards_active; i++) {
- if (ivtvfb_card_id != -1 && i != ivtvfb_card_id)
- continue;
- itv = ivtv_cards[i];
- if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
- if (ivtvfb_init_card(itv) == 0) {
- IVTVFB_INFO("Framebuffer registered on ivtv card id %d\n", i);
- registered++;
- }
- }
- }
+ drv = driver_find("ivtv", &pci_bus_type);
+ err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
+ put_driver(drv);
if (!registered) {
- printk(KERN_ERR "ivtvfb: no cards found");
+ printk(KERN_ERR "ivtvfb: no cards found\n");
return -ENODEV;
}
return 0;
@@ -1229,24 +1256,14 @@ static int __init ivtvfb_init(void)
static void ivtvfb_cleanup(void)
{
- struct ivtv *itv;
- int i;
+ struct device_driver *drv;
+ int err;
printk(KERN_INFO "ivtvfb: Unloading framebuffer module\n");
- for (i = 0; i < ivtv_cards_active; i++) {
- itv = ivtv_cards[i];
- if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
- if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
- IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n", i);
- return;
- }
- IVTVFB_DEBUG_INFO("Unregister framebuffer %d\n", i);
- ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
- ivtvfb_release_buffers(itv);
- itv->osd_video_pbase = 0;
- }
- }
+ drv = driver_find("ivtv", &pci_bus_type);
+ err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
+ put_driver(drv);
}
module_init(ivtvfb_init);
diff --git a/linux/drivers/media/video/m52790.c b/linux/drivers/media/video/m52790.c
index f39da4a36..af179cf4b 100644
--- a/linux/drivers/media/video/m52790.c
+++ b/linux/drivers/media/video/m52790.c
@@ -28,7 +28,7 @@
#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/m52790.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
#include "compat.h"
@@ -44,89 +44,129 @@ I2C_CLIENT_INSMOD;
#endif
struct m52790_state {
+ struct v4l2_subdev sd;
u16 input;
u16 output;
};
+static inline struct m52790_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct m52790_state, sd);
+}
+
/* ----------------------------------------------------------------------- */
-static int m52790_write(struct i2c_client *client)
+static int m52790_write(struct v4l2_subdev *sd)
{
- struct m52790_state *state = i2c_get_clientdata(client);
+ struct m52790_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
u8 sw1 = (state->input | state->output) & 0xff;
u8 sw2 = (state->input | state->output) >> 8;
return i2c_smbus_write_byte_data(client, sw1, sw2);
}
-static int m52790_command(struct i2c_client *client, unsigned int cmd,
- void *arg)
+/* Note: audio and video are linked and cannot be switched separately.
+ So audio and video routing commands are identical for this chip.
+ In theory the video amplifier and audio modes could be handled
+ separately for the output, but that seems to be overkill right now.
+ The same holds for implementing an audio mute control, this is now
+ part of the audio output routing. The normal case is that another
+ chip takes care of the actual muting so making it part of the
+ output routing seems to be the right thing to do for now. */
+static int m52790_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
{
- struct m52790_state *state = i2c_get_clientdata(client);
- struct v4l2_routing *route = arg;
-
- /* Note: audio and video are linked and cannot be switched separately.
- So audio and video routing commands are identical for this chip.
- In theory the video amplifier and audio modes could be handled
- separately for the output, but that seems to be overkill right now.
- The same holds for implementing an audio mute control, this is now
- part of the audio output routing. The normal case is that another
- chip takes care of the actual muting so making it part of the
- output routing seems to be the right thing to do for now. */
- switch (cmd) {
- case VIDIOC_INT_G_AUDIO_ROUTING:
- case VIDIOC_INT_G_VIDEO_ROUTING:
- route->input = state->input;
- route->output = state->output;
- break;
-
- case VIDIOC_INT_S_AUDIO_ROUTING:
- case VIDIOC_INT_S_VIDEO_ROUTING:
- state->input = route->input;
- state->output = route->output;
- m52790_write(client);
- break;
+ struct m52790_state *state = to_state(sd);
+
+ state->input = route->input;
+ state->output = route->output;
+ m52790_write(sd);
+ return 0;
+}
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (!v4l2_chip_match_i2c_client(client,
- reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (reg->reg != 0)
- return -EINVAL;
- if (cmd == VIDIOC_DBG_G_REGISTER)
- reg->val = state->input | state->output;
- else {
- state->input = reg->val & 0x0303;
- state->output = reg->val & ~0x0303;
- m52790_write(client);
- }
- break;
- }
-#endif
+static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct m52790_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client, arg,
- V4L2_IDENT_M52790, 0);
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (reg->reg != 0)
+ return -EINVAL;
+ reg->size = 1;
+ reg->val = state->input | state->output;
+ return 0;
+}
- case VIDIOC_LOG_STATUS:
- v4l_info(client, "Switch 1: %02x\n",
- (state->input | state->output) & 0xff);
- v4l_info(client, "Switch 2: %02x\n",
- (state->input | state->output) >> 8);
- break;
+static int m52790_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct m52790_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- default:
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
return -EINVAL;
- }
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (reg->reg != 0)
+ return -EINVAL;
+ state->input = reg->val & 0x0303;
+ state->output = reg->val & ~0x0303;
+ m52790_write(sd);
return 0;
}
+#endif
+
+static int m52790_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_M52790, 0);
+}
+
+static int m52790_log_status(struct v4l2_subdev *sd)
+{
+ struct m52790_state *state = to_state(sd);
+
+ v4l2_info(sd, "Switch 1: %02x\n",
+ (state->input | state->output) & 0xff);
+ v4l2_info(sd, "Switch 2: %02x\n",
+ (state->input | state->output) >> 8);
+ return 0;
+}
+
+static int m52790_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops m52790_core_ops = {
+ .log_status = m52790_log_status,
+ .g_chip_ident = m52790_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = m52790_g_register,
+ .s_register = m52790_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_audio_ops m52790_audio_ops = {
+ .s_routing = m52790_s_routing,
+};
+
+static const struct v4l2_subdev_video_ops m52790_video_ops = {
+ .s_routing = m52790_s_routing,
+};
+
+static const struct v4l2_subdev_ops m52790_ops = {
+ .core = &m52790_core_ops,
+ .audio = &m52790_audio_ops,
+ .video = &m52790_video_ops,
+};
/* ----------------------------------------------------------------------- */
@@ -136,6 +176,7 @@ static int m52790_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct m52790_state *state;
+ struct v4l2_subdev *sd;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -152,16 +193,20 @@ static int m52790_probe(struct i2c_client *client,
if (state == NULL)
return -ENOMEM;
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &m52790_ops);
state->input = M52790_IN_TUNER;
state->output = M52790_OUT_STEREO;
- i2c_set_clientdata(client, state);
- m52790_write(client);
+ m52790_write(sd);
return 0;
}
static int m52790_remove(struct i2c_client *client)
{
- kfree(i2c_get_clientdata(client));
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
return 0;
}
diff --git a/linux/drivers/media/video/meye.c b/linux/drivers/media/video/meye.c
index 535443887..323aa378b 100644
--- a/linux/drivers/media/video/meye.c
+++ b/linux/drivers/media/video/meye.c
@@ -846,7 +846,7 @@ again:
/* video4linux integration */
/****************************************************************************/
-static int meye_open(struct inode *inode, struct file *file)
+static int meye_open(struct file *file)
{
int i;
@@ -868,7 +868,7 @@ static int meye_open(struct inode *inode, struct file *file)
return 0;
}
-static int meye_release(struct inode *inode, struct file *file)
+static int meye_release(struct file *file)
{
mchip_hic_stop();
mchip_dma_free();
@@ -1582,7 +1582,7 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
return 0;
}
-static int vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
{
switch (cmd) {
case MEYEIOC_G_PARAMS:
@@ -1689,17 +1689,13 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-static const struct file_operations meye_fops = {
+static const struct v4l2_file_operations meye_fops = {
.owner = THIS_MODULE,
.open = meye_open,
.release = meye_release,
.mmap = meye_mmap,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
.poll = meye_poll,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops meye_ioctl_ops = {
diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c
index c6c0a584c..053f168bf 100644
--- a/linux/drivers/media/video/msp3400-driver.c
+++ b/linux/drivers/media/video/msp3400-driver.c
@@ -51,18 +51,18 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-i2c-drv-legacy.h>
-#include <media/tvaudio.h>
-#include <media/msp3400.h>
#include <linux/kthread.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
#include <linux/suspend.h>
#else
#include <linux/freezer.h>
#endif
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/msp3400.h>
+#include <media/tvaudio.h>
#include "compat.h"
#include "msp3400-driver.h"
@@ -270,7 +270,7 @@ static char *scart_names[] = {
void msp_set_scart(struct i2c_client *client, int in, int out)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
state->in_scart = in;
@@ -294,7 +294,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out)
void msp_set_audio(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
int bal = 0, bass, treble, loudness;
int val = 0;
int reallymuted = state->muted | state->scan_in_progress;
@@ -341,7 +341,7 @@ void msp_set_audio(struct i2c_client *client)
static void msp_wake_thread(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
if (NULL == state->kthread)
return;
@@ -395,9 +395,9 @@ static int msp_mode_v4l1_to_v4l2(int mode)
}
#endif
-static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int msp_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
@@ -438,9 +438,10 @@ static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
return 0;
}
-static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
@@ -486,40 +487,16 @@ static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
return 0;
}
-static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
+static long msp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
- struct msp_state *state = i2c_get_clientdata(client);
-
- if (msp_debug >= 2)
- v4l_i2c_print_ioctl(client, cmd);
+ struct msp_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
switch (cmd) {
- case AUDC_SET_RADIO:
- if (state->radio)
- return 0;
- state->radio = 1;
- v4l_dbg(1, msp_debug, client, "switching to radio mode\n");
- state->watch_stereo = 0;
- switch (state->opmode) {
- case OPMODE_MANUAL:
- /* set msp3400 to FM radio mode */
- msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
- msp3400c_set_carrier(client, MSP_CARRIER(10.7),
- MSP_CARRIER(10.7));
- msp_set_audio(client);
- break;
- case OPMODE_AUTODETECT:
- case OPMODE_AUTOSELECT:
- /* the thread will do for us */
- msp_wake_thread(client);
- break;
- }
- break;
-
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */
-#ifdef CONFIG_VIDEO_ALLOW_V4L1
case VIDIOCGAUDIO:
{
struct video_audio *va = arg;
@@ -593,105 +570,137 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
msp_wake_thread(client);
break;
}
-#endif
- case VIDIOC_S_FREQUENCY:
- {
- /* new channel -- kick audio carrier scan */
- msp_wake_thread(client);
- break;
+ default:
+ return -ENOIOCTLCMD;
}
+ return 0;
+}
+#endif
- /* --- v4l2 ioctls --- */
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
- int update = state->radio || state->v4l2_std != *id;
+/* --- v4l2 ioctls --- */
+static int msp_s_radio(struct v4l2_subdev *sd)
+{
+ struct msp_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- state->v4l2_std = *id;
- state->radio = 0;
- if (update)
- msp_wake_thread(client);
+ if (state->radio)
return 0;
+ state->radio = 1;
+ v4l_dbg(1, msp_debug, client, "switching to radio mode\n");
+ state->watch_stereo = 0;
+ switch (state->opmode) {
+ case OPMODE_MANUAL:
+ /* set msp3400 to FM radio mode */
+ msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
+ msp3400c_set_carrier(client, MSP_CARRIER(10.7),
+ MSP_CARRIER(10.7));
+ msp_set_audio(client);
+ break;
+ case OPMODE_AUTODETECT:
+ case OPMODE_AUTOSELECT:
+ /* the thread will do for us */
+ msp_wake_thread(client);
+ break;
}
+ return 0;
+}
- case VIDIOC_INT_G_AUDIO_ROUTING:
- {
- struct v4l2_routing *rt = arg;
+static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- *rt = state->routing;
- break;
- }
+ /* new channel -- kick audio carrier scan */
+ msp_wake_thread(client);
+ return 0;
+}
- case VIDIOC_INT_S_AUDIO_ROUTING:
- {
- struct v4l2_routing *rt = arg;
- int tuner = (rt->input >> 3) & 1;
- int sc_in = rt->input & 0x7;
- int sc1_out = rt->output & 0xf;
- int sc2_out = (rt->output >> 4) & 0xf;
- u16 val, reg;
- int i;
- int extern_input = 1;
-
- if (state->routing.input == rt->input &&
- state->routing.output == rt->output)
- break;
- state->routing = *rt;
- /* check if the tuner input is used */
- for (i = 0; i < 5; i++) {
- if (((rt->input >> (4 + i * 4)) & 0xf) == 0)
- extern_input = 0;
- }
- state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT;
- state->rxsubchans = V4L2_TUNER_SUB_STEREO;
- msp_set_scart(client, sc_in, 0);
- msp_set_scart(client, sc1_out, 1);
- msp_set_scart(client, sc2_out, 2);
- msp_set_audmode(client);
- reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb;
- val = msp_read_dem(client, reg);
- msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
- /* wake thread when a new input is chosen */
+static int msp_s_std(struct v4l2_subdev *sd, v4l2_std_id id)
+{
+ struct msp_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int update = state->radio || state->v4l2_std != id;
+
+ state->v4l2_std = id;
+ state->radio = 0;
+ if (update)
msp_wake_thread(client);
- break;
+ return 0;
+}
+
+static int msp_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *rt)
+{
+ struct msp_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int tuner = (rt->input >> 3) & 1;
+ int sc_in = rt->input & 0x7;
+ int sc1_out = rt->output & 0xf;
+ int sc2_out = (rt->output >> 4) & 0xf;
+ u16 val, reg;
+ int i;
+ int extern_input = 1;
+
+ if (state->routing.input == rt->input &&
+ state->routing.output == rt->output)
+ return 0;
+ state->routing = *rt;
+ /* check if the tuner input is used */
+ for (i = 0; i < 5; i++) {
+ if (((rt->input >> (4 + i * 4)) & 0xf) == 0)
+ extern_input = 0;
}
+ state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT;
+ state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ msp_set_scart(client, sc_in, 0);
+ msp_set_scart(client, sc1_out, 1);
+ msp_set_scart(client, sc2_out, 2);
+ msp_set_audmode(client);
+ reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb;
+ val = msp_read_dem(client, reg);
+ msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
+ /* wake thread when a new input is chosen */
+ msp_wake_thread(client);
+ return 0;
+}
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *vt = arg;
+static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct msp_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (state->radio)
- break;
- if (state->opmode == OPMODE_AUTOSELECT)
- msp_detect_stereo(client);
- vt->audmode = state->audmode;
- vt->rxsubchans = state->rxsubchans;
- vt->capability |= V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
- break;
- }
+ if (state->radio)
+ return 0;
+ if (state->opmode == OPMODE_AUTOSELECT)
+ msp_detect_stereo(client);
+ vt->audmode = state->audmode;
+ vt->rxsubchans = state->rxsubchans;
+ vt->capability |= V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+ return 0;
+}
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+static int msp_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct msp_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (state->radio) /* TODO: add mono/stereo support for radio */
- break;
- if (state->audmode == vt->audmode)
- break;
- state->audmode = vt->audmode;
- /* only set audmode */
- msp_set_audmode(client);
- break;
- }
+ if (state->radio) /* TODO: add mono/stereo support for radio */
+ return 0;
+ if (state->audmode == vt->audmode)
+ return 0;
+ state->audmode = vt->audmode;
+ /* only set audmode */
+ msp_set_audmode(client);
+ return 0;
+}
- case VIDIOC_INT_I2S_CLOCK_FREQ:
- {
- u32 *a = (u32 *)arg;
+static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+ struct msp_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", *a);
+ v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", freq);
- switch (*a) {
+ switch (freq) {
case 1024000:
state->i2s_mode = 0;
break;
@@ -700,24 +709,24 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
default:
return -EINVAL;
- }
- break;
}
+ return 0;
+}
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
+static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ struct msp_state *state = to_state(sd);
- switch (qc->id) {
+ switch (qc->id) {
case V4L2_CID_AUDIO_VOLUME:
case V4L2_CID_AUDIO_MUTE:
return v4l2_ctrl_query_fill_std(qc);
default:
break;
- }
- if (!state->has_sound_processing)
- return -EINVAL;
- switch (qc->id) {
+ }
+ if (!state->has_sound_processing)
+ return -EINVAL;
+ switch (qc->id) {
case V4L2_CID_AUDIO_LOUDNESS:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
@@ -725,32 +734,38 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
return v4l2_ctrl_query_fill_std(qc);
default:
return -EINVAL;
- }
}
+ return 0;
+}
- case VIDIOC_G_CTRL:
- return msp_get_ctrl(client, arg);
-
- case VIDIOC_S_CTRL:
- return msp_set_ctrl(client, arg);
+static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct msp_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_LOG_STATUS:
- {
- const char *p;
+ return v4l2_chip_ident_i2c_client(client, chip, state->ident,
+ (state->rev1 << 16) | state->rev2);
+}
- if (state->opmode == OPMODE_AUTOSELECT)
- msp_detect_stereo(client);
- v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n",
- client->name, state->rev1, state->rev2);
- v4l_info(client, "Audio: volume %d%s\n",
- state->volume, state->muted ? " (muted)" : "");
- if (state->has_sound_processing) {
- v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n",
- state->balance, state->bass,
- state->treble,
- state->loudness ? "on" : "off");
- }
- switch (state->mode) {
+static int msp_log_status(struct v4l2_subdev *sd)
+{
+ struct msp_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ const char *p;
+
+ if (state->opmode == OPMODE_AUTOSELECT)
+ msp_detect_stereo(client);
+ v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n",
+ client->name, state->rev1, state->rev2);
+ v4l_info(client, "Audio: volume %d%s\n",
+ state->volume, state->muted ? " (muted)" : "");
+ if (state->has_sound_processing) {
+ v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n",
+ state->balance, state->bass,
+ state->treble,
+ state->loudness ? "on" : "off");
+ }
+ switch (state->mode) {
case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;
case MSP_MODE_FM_RADIO: p = "FM Radio"; break;
case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break;
@@ -761,36 +776,25 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
case MSP_MODE_BTSC: p = "BTSC"; break;
case MSP_MODE_EXTERN: p = "External input"; break;
default: p = "unknown"; break;
- }
- if (state->mode == MSP_MODE_EXTERN) {
- v4l_info(client, "Mode: %s\n", p);
- } else if (state->opmode == OPMODE_MANUAL) {
- v4l_info(client, "Mode: %s (%s%s)\n", p,
+ }
+ if (state->mode == MSP_MODE_EXTERN) {
+ v4l_info(client, "Mode: %s\n", p);
+ } else if (state->opmode == OPMODE_MANUAL) {
+ v4l_info(client, "Mode: %s (%s%s)\n", p,
(state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
(state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
- } else {
- if (state->opmode == OPMODE_AUTODETECT)
- v4l_info(client, "Mode: %s\n", p);
- v4l_info(client, "Standard: %s (%s%s)\n",
+ } else {
+ if (state->opmode == OPMODE_AUTODETECT)
+ v4l_info(client, "Mode: %s\n", p);
+ v4l_info(client, "Standard: %s (%s%s)\n",
msp_standard_std_name(state->std),
(state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
(state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
- }
- v4l_info(client, "Audmode: 0x%04x\n", state->audmode);
- v4l_info(client, "Routing: 0x%08x (input) 0x%08x (output)\n",
- state->routing.input, state->routing.output);
- v4l_info(client, "ACB: 0x%04x\n", state->acb);
- break;
- }
-
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client, arg, state->ident,
- (state->rev1 << 16) | state->rev2);
-
- default:
- /* unknown */
- return -EINVAL;
}
+ v4l_info(client, "Audmode: 0x%04x\n", state->audmode);
+ v4l_info(client, "Routing: 0x%08x (input) 0x%08x (output)\n",
+ state->routing.input, state->routing.output);
+ v4l_info(client, "ACB: 0x%04x\n", state->acb);
return 0;
}
@@ -808,11 +812,49 @@ static int msp_resume(struct i2c_client *client)
return 0;
}
+static int msp_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops msp_core_ops = {
+ .log_status = msp_log_status,
+ .g_chip_ident = msp_g_chip_ident,
+ .g_ctrl = msp_g_ctrl,
+ .s_ctrl = msp_s_ctrl,
+ .queryctrl = msp_queryctrl,
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
+ .ioctl = msp_ioctl,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops msp_tuner_ops = {
+ .s_frequency = msp_s_frequency,
+ .g_tuner = msp_g_tuner,
+ .s_tuner = msp_s_tuner,
+ .s_radio = msp_s_radio,
+ .s_std = msp_s_std,
+};
+
+static const struct v4l2_subdev_audio_ops msp_audio_ops = {
+ .s_routing = msp_s_routing,
+ .s_i2s_clock_freq = msp_s_i2s_clock_freq,
+};
+
+static const struct v4l2_subdev_ops msp_ops = {
+ .core = &msp_core_ops,
+ .tuner = &msp_tuner_ops,
+ .audio = &msp_audio_ops,
+};
+
/* ----------------------------------------------------------------------- */
static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct msp_state *state;
+ struct v4l2_subdev *sd;
int (*thread_func)(void *data) = NULL;
int msp_hard;
int msp_family;
@@ -836,7 +878,8 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (!state)
return -ENOMEM;
- i2c_set_clientdata(client, state);
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &msp_ops);
state->v4l2_std = V4L2_STD_NTSC;
state->audmode = V4L2_TUNER_MODE_STEREO;
@@ -990,8 +1033,9 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
static int msp_remove(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
+ v4l2_device_unregister_subdev(&state->sd);
/* shutdown control thread */
if (state->kthread) {
state->restart = 1;
diff --git a/linux/drivers/media/video/msp3400-driver.h b/linux/drivers/media/video/msp3400-driver.h
index ab69a290e..3fe1c1b10 100644
--- a/linux/drivers/media/video/msp3400-driver.h
+++ b/linux/drivers/media/video/msp3400-driver.h
@@ -5,6 +5,7 @@
#define MSP3400_DRIVER_H
#include <media/msp3400.h>
+#include <media/v4l2-device.h>
/* ---------------------------------------------------------------------- */
@@ -49,6 +50,7 @@ extern int msp_dolby;
extern int msp_stereo_thresh;
struct msp_state {
+ struct v4l2_subdev sd;
int rev1, rev2;
int ident;
u8 has_nicam;
@@ -96,6 +98,11 @@ struct msp_state {
unsigned int watch_stereo:1;
};
+static inline struct msp_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct msp_state, sd);
+}
+
/* msp3400-driver.c */
int msp_write_dem(struct i2c_client *client, int addr, int val);
int msp_write_dsp(struct i2c_client *client, int addr, int val);
diff --git a/linux/drivers/media/video/msp3400-kthreads.c b/linux/drivers/media/video/msp3400-kthreads.c
index 29c0d5cf6..ccba71d9f 100644
--- a/linux/drivers/media/video/msp3400-kthreads.c
+++ b/linux/drivers/media/video/msp3400-kthreads.c
@@ -162,7 +162,7 @@ const char *msp_standard_std_name(int std)
static void msp_set_source(struct i2c_client *client, u16 src)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
if (msp_dolby) {
msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
@@ -189,7 +189,7 @@ void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2)
void msp3400c_set_mode(struct i2c_client *client, int mode)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode];
int tuner = (state->routing.input >> 3) & 1;
int i;
@@ -230,7 +230,7 @@ static void msp3400c_set_audmode(struct i2c_client *client)
static char *strmode[] = {
"mono", "stereo", "lang2", "lang1", "lang1+lang2"
};
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
char *modestr = (state->audmode >= 0 && state->audmode < 5) ?
strmode[state->audmode] : "unknown";
int src = 0; /* channel source: FM/AM, nicam or SCART */
@@ -359,7 +359,7 @@ static void msp3400c_set_audmode(struct i2c_client *client)
static void msp3400c_print_mode(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
if (state->main == state->second)
v4l_dbg(1, msp_debug, client,
@@ -388,7 +388,7 @@ static void msp3400c_print_mode(struct i2c_client *client)
static int msp3400c_detect_stereo(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
int val;
int rxsubchans = state->rxsubchans;
int newnicam = state->nicam_on;
@@ -466,7 +466,7 @@ static int msp3400c_detect_stereo(struct i2c_client *client)
/* stereo/multilang monitoring */
static void watch_stereo(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
if (msp_detect_stereo(client))
msp_set_audmode(client);
@@ -478,7 +478,7 @@ static void watch_stereo(struct i2c_client *client)
int msp3400c_thread(void *data)
{
struct i2c_client *client = data;
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
struct msp3400c_carrier_detect *cd;
int count, max1, max2, val1, val2, val, i;
@@ -662,7 +662,7 @@ no_second:
int msp3410d_thread(void *data)
{
struct i2c_client *client = data;
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
int val, i, std, count;
v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n");
@@ -828,7 +828,7 @@ restart:
static int msp34xxg_modus(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
if (state->radio) {
v4l_dbg(1, msp_debug, client, "selected radio modus\n");
@@ -855,7 +855,7 @@ static int msp34xxg_modus(struct i2c_client *client)
static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
int source, matrix;
switch (state->audmode) {
@@ -898,7 +898,7 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
static void msp34xxg_set_sources(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
u32 in = state->routing.input;
msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf);
@@ -914,7 +914,7 @@ static void msp34xxg_set_sources(struct i2c_client *client)
/* (re-)initialize the msp34xxg */
static void msp34xxg_reset(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
int tuner = (state->routing.input >> 3) & 1;
int modus;
@@ -957,7 +957,7 @@ static void msp34xxg_reset(struct i2c_client *client)
int msp34xxg_thread(void *data)
{
struct i2c_client *client = data;
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
int val, i;
v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n");
@@ -1052,7 +1052,7 @@ unmute:
static int msp34xxg_detect_stereo(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
int status = msp_read_dem(client, 0x0200);
int is_bilingual = status & 0x100;
int is_stereo = status & 0x40;
@@ -1081,7 +1081,7 @@ static int msp34xxg_detect_stereo(struct i2c_client *client)
static void msp34xxg_set_audmode(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
if (state->std == 0x20) {
if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) &&
@@ -1098,7 +1098,7 @@ static void msp34xxg_set_audmode(struct i2c_client *client)
void msp_set_audmode(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
switch (state->opmode) {
case OPMODE_MANUAL:
@@ -1113,7 +1113,7 @@ void msp_set_audmode(struct i2c_client *client)
int msp_detect_stereo(struct i2c_client *client)
{
- struct msp_state *state = i2c_get_clientdata(client);
+ struct msp_state *state = to_state(i2c_get_clientdata(client));
switch (state->opmode) {
case OPMODE_MANUAL:
diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c
index 228183c54..3d8e6ed8d 100644
--- a/linux/drivers/media/video/mt9m001.c
+++ b/linux/drivers/media/video/mt9m001.c
@@ -272,21 +272,20 @@ static int mt9m001_set_bus_param(struct soc_camera_device *icd,
static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- unsigned int width_flag = SOCAM_DATAWIDTH_10;
+ struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+ /* MT9M001 has all capture_format parameters fixed */
+ unsigned long flags = SOCAM_DATAWIDTH_10 | SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+ SOCAM_MASTER;
if (bus_switch_possible(mt9m001))
- width_flag |= SOCAM_DATAWIDTH_8;
+ flags |= SOCAM_DATAWIDTH_8;
- /* MT9M001 has all capture_format parameters fixed */
- return SOCAM_PCLK_SAMPLE_RISING |
- SOCAM_HSYNC_ACTIVE_HIGH |
- SOCAM_VSYNC_ACTIVE_HIGH |
- SOCAM_MASTER |
- width_flag;
+ return soc_camera_apply_sensor_flags(icl, flags);
}
-static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9m001_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
int ret;
@@ -298,7 +297,7 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank);
/* The caller provides a supported format, as verified per
- * call to icd->try_fmt_cap() */
+ * call to icd->try_fmt() */
if (!ret)
ret = reg_write(icd, MT9M001_COLUMN_START, rect->left);
if (!ret)
@@ -325,31 +324,33 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
return ret;
}
-static int mt9m001_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m001_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
- if (f->fmt.pix.height < 32 + icd->y_skip_top)
- f->fmt.pix.height = 32 + icd->y_skip_top;
- if (f->fmt.pix.height > 1024 + icd->y_skip_top)
- f->fmt.pix.height = 1024 + icd->y_skip_top;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > 1280)
- f->fmt.pix.width = 1280;
- f->fmt.pix.width &= ~0x01; /* has to be even, unsure why was ~3 */
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ if (pix->height < 32 + icd->y_skip_top)
+ pix->height = 32 + icd->y_skip_top;
+ if (pix->height > 1024 + icd->y_skip_top)
+ pix->height = 1024 + icd->y_skip_top;
+ if (pix->width < 48)
+ pix->width = 48;
+ if (pix->width > 1280)
+ pix->width = 1280;
+ pix->width &= ~0x01; /* has to be even, unsure why was ~3 */
return 0;
}
static int mt9m001_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_chip_ident *id)
+ struct v4l2_dbg_chip_ident *id)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+ if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
- if (id->match_chip != mt9m001->client->addr)
+ if (id->match.addr != mt9m001->client->addr)
return -ENODEV;
id->ident = mt9m001->model;
@@ -360,16 +361,17 @@ static int mt9m001_get_chip_id(struct soc_camera_device *icd,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mt9m001_get_register(struct soc_camera_device *icd,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
- if (reg->match_chip != mt9m001->client->addr)
+ if (reg->match.addr != mt9m001->client->addr)
return -ENODEV;
+ reg->size = 2;
reg->val = reg_read(icd, reg->reg);
if (reg->val > 0xffff)
@@ -379,14 +381,14 @@ static int mt9m001_get_register(struct soc_camera_device *icd,
}
static int mt9m001_set_register(struct soc_camera_device *icd,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
- if (reg->match_chip != mt9m001->client->addr)
+ if (reg->match.addr != mt9m001->client->addr)
return -ENODEV;
if (reg_write(icd, reg->reg, reg->val) < 0)
@@ -447,8 +449,8 @@ static struct soc_camera_ops mt9m001_ops = {
.release = mt9m001_release,
.start_capture = mt9m001_start_capture,
.stop_capture = mt9m001_stop_capture,
- .set_fmt_cap = mt9m001_set_fmt_cap,
- .try_fmt_cap = mt9m001_try_fmt_cap,
+ .set_fmt = mt9m001_set_fmt,
+ .try_fmt = mt9m001_try_fmt,
.set_bus_param = mt9m001_set_bus_param,
.query_bus_param = mt9m001_query_bus_param,
.controls = mt9m001_controls,
@@ -578,6 +580,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
static int mt9m001_video_probe(struct soc_camera_device *icd)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
s32 data;
int ret;
@@ -588,7 +591,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
return -ENODEV;
/* Enable the chip */
- data = reg_write(&mt9m001->icd, MT9M001_CHIP_ENABLE, 1);
+ data = reg_write(icd, MT9M001_CHIP_ENABLE, 1);
dev_dbg(&icd->dev, "write: %d\n", data);
/* Read out the chip version register */
@@ -600,7 +603,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
case 0x8421:
mt9m001->model = V4L2_IDENT_MT9M001C12ST;
icd->formats = mt9m001_colour_formats;
- if (mt9m001->client->dev.platform_data)
+ if (gpio_is_valid(icl->gpio))
icd->num_formats = ARRAY_SIZE(mt9m001_colour_formats);
else
icd->num_formats = 1;
@@ -608,7 +611,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
case 0x8431:
mt9m001->model = V4L2_IDENT_MT9M001C12STM;
icd->formats = mt9m001_monochrome_formats;
- if (mt9m001->client->dev.platform_data)
+ if (gpio_is_valid(icl->gpio))
icd->num_formats = ARRAY_SIZE(mt9m001_monochrome_formats);
else
icd->num_formats = 1;
@@ -640,8 +643,8 @@ static void mt9m001_video_remove(struct soc_camera_device *icd)
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
- mt9m001->icd.dev.parent, mt9m001->icd.vdev);
- soc_camera_video_stop(&mt9m001->icd);
+ icd->dev.parent, icd->vdev);
+ soc_camera_video_stop(icd);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c
index ceff40edc..cdf3f38e2 100644
--- a/linux/drivers/media/video/mt9m111.c
+++ b/linux/drivers/media/video/mt9m111.c
@@ -1,5 +1,5 @@
/*
- * Driver for MT9M111 CMOS Image Sensor from Micron
+ * Driver for MT9M111/MT9M112 CMOS Image Sensor from Micron
*
* Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
*
@@ -19,7 +19,7 @@
#include <media/soc_camera.h>
/*
- * mt9m111 i2c address is 0x5d or 0x48 (depending on SAddr pin)
+ * mt9m111 and mt9m112 i2c address is 0x5d or 0x48 (depending on SAddr pin)
* The platform has to define i2c_board_info and call i2c_register_board_info()
*/
@@ -90,7 +90,7 @@
#define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b
#define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14)
-
+#define MT9M111_OPMODE_AUTOWHITEBAL_EN (1 << 1)
#define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14)
#define MT9M111_OUTFMT_BYPASS_IFP (1 << 10)
@@ -128,9 +128,14 @@
.colorspace = _colorspace }
#define RGB_FMT(_name, _depth, _fourcc) \
COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_SRGB)
+#define JPG_FMT(_name, _depth, _fourcc) \
+ COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_JPEG)
static const struct soc_camera_data_format mt9m111_colour_formats[] = {
- COL_FMT("YCrYCb 8 bit", 8, V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_JPEG),
+ JPG_FMT("CbYCrY 16 bit", 16, V4L2_PIX_FMT_UYVY),
+ JPG_FMT("CrYCbY 16 bit", 16, V4L2_PIX_FMT_VYUY),
+ JPG_FMT("YCbYCr 16 bit", 16, V4L2_PIX_FMT_YUYV),
+ JPG_FMT("YCrYCb 16 bit", 16, V4L2_PIX_FMT_YVYU),
RGB_FMT("RGB 565", 16, V4L2_PIX_FMT_RGB565),
RGB_FMT("RGB 555", 16, V4L2_PIX_FMT_RGB555),
RGB_FMT("Bayer (sRGB) 10 bit", 10, V4L2_PIX_FMT_SBGGR16),
@@ -145,7 +150,7 @@ enum mt9m111_context {
struct mt9m111 {
struct i2c_client *client;
struct soc_camera_device icd;
- int model; /* V4L2_IDENT_MT9M111* codes from v4l2-chip-ident.h */
+ int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */
enum mt9m111_context context;
unsigned int left, top, width, height;
u32 pixfmt;
@@ -158,6 +163,7 @@ struct mt9m111 {
unsigned int swap_rgb_red_blue:1;
unsigned int swap_yuv_y_chromas:1;
unsigned int swap_yuv_cb_cr:1;
+ unsigned int autowhitebalance:1;
};
static int reg_page_map_set(struct i2c_client *client, const u16 reg)
@@ -410,9 +416,13 @@ static int mt9m111_stop_capture(struct soc_camera_device *icd)
static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
{
- return SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+ unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
SOCAM_DATAWIDTH_8;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
}
static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
@@ -438,7 +448,24 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
case V4L2_PIX_FMT_RGB565:
ret = mt9m111_setfmt_rgb565(icd);
break;
+ case V4L2_PIX_FMT_UYVY:
+ mt9m111->swap_yuv_y_chromas = 0;
+ mt9m111->swap_yuv_cb_cr = 0;
+ ret = mt9m111_setfmt_yuv(icd);
+ break;
+ case V4L2_PIX_FMT_VYUY:
+ mt9m111->swap_yuv_y_chromas = 0;
+ mt9m111->swap_yuv_cb_cr = 1;
+ ret = mt9m111_setfmt_yuv(icd);
+ break;
case V4L2_PIX_FMT_YUYV:
+ mt9m111->swap_yuv_y_chromas = 1;
+ mt9m111->swap_yuv_cb_cr = 0;
+ ret = mt9m111_setfmt_yuv(icd);
+ break;
+ case V4L2_PIX_FMT_YVYU:
+ mt9m111->swap_yuv_y_chromas = 1;
+ mt9m111->swap_yuv_cb_cr = 1;
ret = mt9m111_setfmt_yuv(icd);
break;
default:
@@ -452,8 +479,8 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
return ret;
}
-static int mt9m111_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9m111_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
int ret;
@@ -473,26 +500,28 @@ static int mt9m111_set_fmt_cap(struct soc_camera_device *icd,
return ret;
}
-static int mt9m111_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m111_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
- if (f->fmt.pix.height > MT9M111_MAX_HEIGHT)
- f->fmt.pix.height = MT9M111_MAX_HEIGHT;
- if (f->fmt.pix.width > MT9M111_MAX_WIDTH)
- f->fmt.pix.width = MT9M111_MAX_WIDTH;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ if (pix->height > MT9M111_MAX_HEIGHT)
+ pix->height = MT9M111_MAX_HEIGHT;
+ if (pix->width > MT9M111_MAX_WIDTH)
+ pix->width = MT9M111_MAX_WIDTH;
return 0;
}
static int mt9m111_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_chip_ident *id)
+ struct v4l2_dbg_chip_ident *id)
{
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
- if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+ if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
- if (id->match_chip != mt9m111->client->addr)
+ if (id->match.addr != mt9m111->client->addr)
return -ENODEV;
id->ident = mt9m111->model;
@@ -503,18 +532,19 @@ static int mt9m111_get_chip_id(struct soc_camera_device *icd,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mt9m111_get_register(struct soc_camera_device *icd,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
int val;
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
- if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
return -EINVAL;
- if (reg->match_chip != mt9m111->client->addr)
+ if (reg->match.addr != mt9m111->client->addr)
return -ENODEV;
val = mt9m111_reg_read(icd, reg->reg);
+ reg->size = 2;
reg->val = (u64)val;
if (reg->val > 0xffff)
@@ -524,14 +554,14 @@ static int mt9m111_get_register(struct soc_camera_device *icd,
}
static int mt9m111_set_register(struct soc_camera_device *icd,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
- if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
return -EINVAL;
- if (reg->match_chip != mt9m111->client->addr)
+ if (reg->match.addr != mt9m111->client->addr)
return -ENODEV;
if (mt9m111_reg_write(icd, reg->reg, reg->val) < 0)
@@ -597,8 +627,8 @@ static struct soc_camera_ops mt9m111_ops = {
.release = mt9m111_release,
.start_capture = mt9m111_start_capture,
.stop_capture = mt9m111_stop_capture,
- .set_fmt_cap = mt9m111_set_fmt_cap,
- .try_fmt_cap = mt9m111_try_fmt_cap,
+ .set_fmt = mt9m111_set_fmt,
+ .try_fmt = mt9m111_try_fmt,
.query_bus_param = mt9m111_query_bus_param,
.set_bus_param = mt9m111_set_bus_param,
.controls = mt9m111_controls,
@@ -634,18 +664,15 @@ static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
static int mt9m111_get_global_gain(struct soc_camera_device *icd)
{
- unsigned int data, gain;
+ int data;
data = reg_read(GLOBAL_GAIN);
if (data >= 0)
- gain = ((data & (1 << 10)) * 2)
- | ((data & (1 << 9)) * 2)
- | (data & 0x2f);
- else
- gain = data;
-
- return gain;
+ return (data & 0x2f) * (1 << ((data >> 10) & 1)) *
+ (1 << ((data >> 9) & 1));
+ return data;
}
+
static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
{
u16 val;
@@ -679,6 +706,23 @@ static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
return ret;
}
+
+static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int ret;
+
+ if (on)
+ ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
+ else
+ ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
+
+ if (!ret)
+ mt9m111->autowhitebalance = on;
+
+ return ret;
+}
+
static int mt9m111_get_control(struct soc_camera_device *icd,
struct v4l2_control *ctrl)
{
@@ -715,6 +759,9 @@ static int mt9m111_get_control(struct soc_camera_device *icd,
case V4L2_CID_EXPOSURE_AUTO:
ctrl->value = mt9m111->autoexposure;
break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ctrl->value = mt9m111->autowhitebalance;
+ break;
}
return 0;
}
@@ -748,6 +795,9 @@ static int mt9m111_set_control(struct soc_camera_device *icd,
case V4L2_CID_EXPOSURE_AUTO:
ret = mt9m111_set_autoexposure(icd, ctrl->value);
break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = mt9m111_set_autowhitebalance(icd, ctrl->value);
+ break;
default:
ret = -EINVAL;
}
@@ -766,6 +816,7 @@ static int mt9m111_restore_state(struct soc_camera_device *icd)
mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
mt9m111_set_global_gain(icd, icd->gain);
mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
+ mt9m111_set_autowhitebalance(icd, mt9m111->autowhitebalance);
return 0;
}
@@ -798,7 +849,7 @@ static int mt9m111_init(struct soc_camera_device *icd)
if (!ret)
ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
if (ret)
- dev_err(&icd->dev, "mt9m111 init failed: %d\n", ret);
+ dev_err(&icd->dev, "mt9m11x init failed: %d\n", ret);
return ret;
}
@@ -808,7 +859,7 @@ static int mt9m111_release(struct soc_camera_device *icd)
ret = mt9m111_disable(icd);
if (ret < 0)
- dev_err(&icd->dev, "mt9m111 release failed: %d\n", ret);
+ dev_err(&icd->dev, "mt9m11x release failed: %d\n", ret);
return ret;
}
@@ -841,25 +892,30 @@ static int mt9m111_video_probe(struct soc_camera_device *icd)
data = reg_read(CHIP_VERSION);
switch (data) {
- case 0x143a:
+ case 0x143a: /* MT9M111 */
mt9m111->model = V4L2_IDENT_MT9M111;
- icd->formats = mt9m111_colour_formats;
- icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats);
+ break;
+ case 0x148c: /* MT9M112 */
+ mt9m111->model = V4L2_IDENT_MT9M112;
break;
default:
ret = -ENODEV;
dev_err(&icd->dev,
- "No MT9M111 chip detected, register read %x\n", data);
+ "No MT9M11x chip detected, register read %x\n", data);
goto ei2c;
}
- dev_info(&icd->dev, "Detected a MT9M111 chip ID 0x143a\n");
+ icd->formats = mt9m111_colour_formats;
+ icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats);
+
+ dev_info(&icd->dev, "Detected a MT9M11x chip ID %x\n", data);
ret = soc_camera_video_start(icd);
if (ret)
goto eisis;
mt9m111->autoexposure = 1;
+ mt9m111->autowhitebalance = 1;
mt9m111->swap_rgb_even_odd = 1;
mt9m111->swap_rgb_red_blue = 1;
@@ -893,7 +949,7 @@ static int mt9m111_probe(struct i2c_client *client,
int ret;
if (!icl) {
- dev_err(&client->dev, "MT9M111 driver needs platform data\n");
+ dev_err(&client->dev, "MT9M11x driver needs platform data\n");
return -EINVAL;
}
@@ -976,6 +1032,6 @@ static void __exit mt9m111_mod_exit(void)
module_init(mt9m111_mod_init);
module_exit(mt9m111_mod_exit);
-MODULE_DESCRIPTION("Micron MT9M111 Camera driver");
+MODULE_DESCRIPTION("Micron MT9M111/MT9M112 Camera driver");
MODULE_AUTHOR("Robert Jarzmik");
MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/mt9t031.c b/linux/drivers/media/video/mt9t031.c
new file mode 100644
index 000000000..dd5bd9dd0
--- /dev/null
+++ b/linux/drivers/media/video/mt9t031.c
@@ -0,0 +1,744 @@
+/*
+ * Driver for MT9T031 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski, DENX Software Engineering <lg@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+
+/* mt9t031 i2c address 0x5d
+ * The platform has to define i2c_board_info
+ * and call i2c_register_board_info() */
+
+/* mt9t031 selected register addresses */
+#define MT9T031_CHIP_VERSION 0x00
+#define MT9T031_ROW_START 0x01
+#define MT9T031_COLUMN_START 0x02
+#define MT9T031_WINDOW_HEIGHT 0x03
+#define MT9T031_WINDOW_WIDTH 0x04
+#define MT9T031_HORIZONTAL_BLANKING 0x05
+#define MT9T031_VERTICAL_BLANKING 0x06
+#define MT9T031_OUTPUT_CONTROL 0x07
+#define MT9T031_SHUTTER_WIDTH_UPPER 0x08
+#define MT9T031_SHUTTER_WIDTH 0x09
+#define MT9T031_PIXEL_CLOCK_CONTROL 0x0a
+#define MT9T031_FRAME_RESTART 0x0b
+#define MT9T031_SHUTTER_DELAY 0x0c
+#define MT9T031_RESET 0x0d
+#define MT9T031_READ_MODE_1 0x1e
+#define MT9T031_READ_MODE_2 0x20
+#define MT9T031_READ_MODE_3 0x21
+#define MT9T031_ROW_ADDRESS_MODE 0x22
+#define MT9T031_COLUMN_ADDRESS_MODE 0x23
+#define MT9T031_GLOBAL_GAIN 0x35
+#define MT9T031_CHIP_ENABLE 0xF8
+
+#define MT9T031_MAX_HEIGHT 1536
+#define MT9T031_MAX_WIDTH 2048
+#define MT9T031_MIN_HEIGHT 2
+#define MT9T031_MIN_WIDTH 2
+#define MT9T031_HORIZONTAL_BLANK 142
+#define MT9T031_VERTICAL_BLANK 25
+#define MT9T031_COLUMN_SKIP 32
+#define MT9T031_ROW_SKIP 20
+
+#define MT9T031_BUS_PARAM (SOCAM_PCLK_SAMPLE_RISING | \
+ SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH | \
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \
+ SOCAM_MASTER | SOCAM_DATAWIDTH_10)
+
+static const struct soc_camera_data_format mt9t031_colour_formats[] = {
+ {
+ .name = "Bayer (sRGB) 10 bit",
+ .depth = 10,
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }
+};
+
+struct mt9t031 {
+ struct i2c_client *client;
+ struct soc_camera_device icd;
+ int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
+ unsigned char autoexposure;
+ u16 xskip;
+ u16 yskip;
+};
+
+static int reg_read(struct soc_camera_device *icd, const u8 reg)
+{
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct i2c_client *client = mt9t031->client;
+ s32 data = i2c_smbus_read_word_data(client, reg);
+ return data < 0 ? data : swab16(data);
+}
+
+static int reg_write(struct soc_camera_device *icd, const u8 reg,
+ const u16 data)
+{
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ return i2c_smbus_write_word_data(mt9t031->client, reg, swab16(data));
+}
+
+static int reg_set(struct soc_camera_device *icd, const u8 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_read(icd, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(icd, reg, ret | data);
+}
+
+static int reg_clear(struct soc_camera_device *icd, const u8 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_read(icd, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(icd, reg, ret & ~data);
+}
+
+static int set_shutter(struct soc_camera_device *icd, const u32 data)
+{
+ int ret;
+
+ ret = reg_write(icd, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16);
+
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_SHUTTER_WIDTH, data & 0xffff);
+
+ return ret;
+}
+
+static int get_shutter(struct soc_camera_device *icd, u32 *data)
+{
+ int ret;
+
+ ret = reg_read(icd, MT9T031_SHUTTER_WIDTH_UPPER);
+ *data = ret << 16;
+
+ if (ret >= 0)
+ ret = reg_read(icd, MT9T031_SHUTTER_WIDTH);
+ *data |= ret & 0xffff;
+
+ return ret < 0 ? ret : 0;
+}
+
+static int mt9t031_init(struct soc_camera_device *icd)
+{
+ int ret;
+
+ /* Disable chip output, synchronous option update */
+ dev_dbg(icd->vdev->parent, "%s\n", __func__);
+
+ ret = reg_write(icd, MT9T031_RESET, 1);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_RESET, 0);
+ if (ret >= 0)
+ ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3);
+
+ return ret >= 0 ? 0 : -EIO;
+}
+
+static int mt9t031_release(struct soc_camera_device *icd)
+{
+ /* Disable the chip */
+ reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3);
+ return 0;
+}
+
+static int mt9t031_start_capture(struct soc_camera_device *icd)
+{
+ /* Switch to master "normal" mode */
+ if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 3) < 0)
+ return -EIO;
+ return 0;
+}
+
+static int mt9t031_stop_capture(struct soc_camera_device *icd)
+{
+ /* Stop sensor readout */
+ if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3) < 0)
+ return -EIO;
+ return 0;
+}
+
+static int mt9t031_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ /* The caller should have queried our parameters, check anyway */
+ if (flags & ~MT9T031_BUS_PARAM)
+ return -EINVAL;
+
+ if (flags & SOCAM_PCLK_SAMPLE_FALLING)
+ reg_set(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+ else
+ reg_clear(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+
+ return 0;
+}
+
+static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
+{
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct soc_camera_link *icl = mt9t031->client->dev.platform_data;
+
+ return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM);
+}
+
+static int mt9t031_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
+{
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ int ret;
+ const u16 hblank = MT9T031_HORIZONTAL_BLANK,
+ vblank = MT9T031_VERTICAL_BLANK;
+ u16 xbin, xskip = mt9t031->xskip, ybin, yskip = mt9t031->yskip,
+ width = rect->width * xskip, height = rect->height * yskip;
+
+ if (pixfmt) {
+ /* S_FMT - use binning and skipping for scaling, recalculate */
+ /* Is this more optimal than just a division? */
+ for (xskip = 8; xskip > 1; xskip--)
+ if (rect->width * xskip <= icd->width_max)
+ break;
+
+ for (yskip = 8; yskip > 1; yskip--)
+ if (rect->height * yskip <= icd->height_max)
+ break;
+
+ width = rect->width * xskip;
+ height = rect->height * yskip;
+
+ dev_dbg(&icd->dev, "xskip %u, width %u, yskip %u, height %u\n",
+ xskip, width, yskip, height);
+ }
+
+ xbin = min(xskip, (u16)3);
+ ybin = min(yskip, (u16)3);
+
+ /* Make sure we don't exceed frame limits */
+ if (rect->left + width > icd->width_max)
+ rect->left = (icd->width_max - width) / 2;
+
+ if (rect->top + height > icd->height_max)
+ rect->top = (icd->height_max - height) / 2;
+
+ /* Could just do roundup(rect->left, [xy]bin); but this is cheaper */
+ switch (xbin) {
+ case 2:
+ rect->left = (rect->left + 1) & ~1;
+ break;
+ case 3:
+ rect->left = roundup(rect->left, 3);
+ }
+
+ switch (ybin) {
+ case 2:
+ rect->top = (rect->top + 1) & ~1;
+ break;
+ case 3:
+ rect->top = roundup(rect->top, 3);
+ }
+
+ /* Blanking and start values - default... */
+ ret = reg_write(icd, MT9T031_HORIZONTAL_BLANKING, hblank);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_VERTICAL_BLANKING, vblank);
+
+ if (pixfmt) {
+ /* Binning, skipping */
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_COLUMN_ADDRESS_MODE,
+ ((xbin - 1) << 4) | (xskip - 1));
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_ROW_ADDRESS_MODE,
+ ((ybin - 1) << 4) | (yskip - 1));
+ }
+ dev_dbg(&icd->dev, "new left %u, top %u\n", rect->left, rect->top);
+
+ /* The caller provides a supported format, as guaranteed by
+ * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_COLUMN_START, rect->left);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_ROW_START, rect->top);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_WINDOW_WIDTH, width - 1);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_WINDOW_HEIGHT,
+ height + icd->y_skip_top - 1);
+ if (ret >= 0 && mt9t031->autoexposure) {
+ ret = set_shutter(icd, height + icd->y_skip_top + vblank);
+ if (ret >= 0) {
+ const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
+ const struct v4l2_queryctrl *qctrl =
+ soc_camera_find_qctrl(icd->ops,
+ V4L2_CID_EXPOSURE);
+ icd->exposure = (shutter_max / 2 + (height +
+ icd->y_skip_top + vblank - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
+ shutter_max + qctrl->minimum;
+ }
+ }
+
+ if (!ret && pixfmt) {
+ mt9t031->xskip = xskip;
+ mt9t031->yskip = yskip;
+ }
+
+ return ret < 0 ? ret : 0;
+}
+
+static int mt9t031_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ if (pix->height < icd->height_min)
+ pix->height = icd->height_min;
+ if (pix->height > icd->height_max)
+ pix->height = icd->height_max;
+ if (pix->width < icd->width_min)
+ pix->width = icd->width_min;
+ if (pix->width > icd->width_max)
+ pix->width = icd->width_max;
+
+ pix->width &= ~0x01; /* has to be even */
+ pix->height &= ~0x01; /* has to be even */
+
+ return 0;
+}
+
+static int mt9t031_get_chip_id(struct soc_camera_device *icd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+
+ if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ if (id->match.addr != mt9t031->client->addr)
+ return -ENODEV;
+
+ id->ident = mt9t031->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9t031_get_register(struct soc_camera_device *icd,
+ struct v4l2_dbg_register *reg)
+{
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match.addr != mt9t031->client->addr)
+ return -ENODEV;
+
+ reg->val = reg_read(icd, reg->reg);
+
+ if (reg->val > 0xffff)
+ return -EIO;
+
+ return 0;
+}
+
+static int mt9t031_set_register(struct soc_camera_device *icd,
+ struct v4l2_dbg_register *reg)
+{
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match.addr != mt9t031->client->addr)
+ return -ENODEV;
+
+ if (reg_write(icd, reg->reg, reg->val) < 0)
+ return -EIO;
+
+ return 0;
+}
+#endif
+
+static const struct v4l2_queryctrl mt9t031_controls[] = {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Vertically",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ }, {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 64,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 1,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 255,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic Exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ }
+};
+
+static int mt9t031_video_probe(struct soc_camera_device *);
+static void mt9t031_video_remove(struct soc_camera_device *);
+static int mt9t031_get_control(struct soc_camera_device *, struct v4l2_control *);
+static int mt9t031_set_control(struct soc_camera_device *, struct v4l2_control *);
+
+static struct soc_camera_ops mt9t031_ops = {
+ .owner = THIS_MODULE,
+ .probe = mt9t031_video_probe,
+ .remove = mt9t031_video_remove,
+ .init = mt9t031_init,
+ .release = mt9t031_release,
+ .start_capture = mt9t031_start_capture,
+ .stop_capture = mt9t031_stop_capture,
+ .set_fmt = mt9t031_set_fmt,
+ .try_fmt = mt9t031_try_fmt,
+ .set_bus_param = mt9t031_set_bus_param,
+ .query_bus_param = mt9t031_query_bus_param,
+ .controls = mt9t031_controls,
+ .num_controls = ARRAY_SIZE(mt9t031_controls),
+ .get_control = mt9t031_get_control,
+ .set_control = mt9t031_set_control,
+ .get_chip_id = mt9t031_get_chip_id,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .get_register = mt9t031_get_register,
+ .set_register = mt9t031_set_register,
+#endif
+};
+
+static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+{
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ int data;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ data = reg_read(icd, MT9T031_READ_MODE_2);
+ if (data < 0)
+ return -EIO;
+ ctrl->value = !!(data & 0x8000);
+ break;
+ case V4L2_CID_HFLIP:
+ data = reg_read(icd, MT9T031_READ_MODE_2);
+ if (data < 0)
+ return -EIO;
+ ctrl->value = !!(data & 0x4000);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ctrl->value = mt9t031->autoexposure;
+ break;
+ }
+ return 0;
+}
+
+static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+{
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ const struct v4l2_queryctrl *qctrl;
+ int data;
+
+ qctrl = soc_camera_find_qctrl(&mt9t031_ops, ctrl->id);
+
+ if (!qctrl)
+ return -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ if (ctrl->value)
+ data = reg_set(icd, MT9T031_READ_MODE_2, 0x8000);
+ else
+ data = reg_clear(icd, MT9T031_READ_MODE_2, 0x8000);
+ if (data < 0)
+ return -EIO;
+ break;
+ case V4L2_CID_HFLIP:
+ if (ctrl->value)
+ data = reg_set(icd, MT9T031_READ_MODE_2, 0x4000);
+ else
+ data = reg_clear(icd, MT9T031_READ_MODE_2, 0x4000);
+ if (data < 0)
+ return -EIO;
+ break;
+ case V4L2_CID_GAIN:
+ if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+ return -EINVAL;
+ /* See Datasheet Table 7, Gain settings. */
+ if (ctrl->value <= qctrl->default_value) {
+ /* Pack it into 0..1 step 0.125, register values 0..8 */
+ unsigned long range = qctrl->default_value - qctrl->minimum;
+ data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
+
+ dev_dbg(&icd->dev, "Setting gain %d\n", data);
+ data = reg_write(icd, MT9T031_GLOBAL_GAIN, data);
+ if (data < 0)
+ return -EIO;
+ } else {
+ /* Pack it into 1.125..15 variable step, register values 9..67 */
+ /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
+ unsigned long range = qctrl->maximum - qctrl->default_value - 1;
+ unsigned long gain = ((ctrl->value - qctrl->default_value - 1) *
+ 111 + range / 2) / range + 9;
+
+ if (gain <= 32)
+ data = gain;
+ else if (gain <= 64)
+ data = ((gain - 32) * 16 + 16) / 32 + 80;
+ else
+ data = ((gain - 64) * 7 + 28) / 56 + 96;
+
+ dev_dbg(&icd->dev, "Setting gain from %d to %d\n",
+ reg_read(icd, MT9T031_GLOBAL_GAIN), data);
+ data = reg_write(icd, MT9T031_GLOBAL_GAIN, data);
+ if (data < 0)
+ return -EIO;
+ }
+
+ /* Success */
+ icd->gain = ctrl->value;
+ break;
+ case V4L2_CID_EXPOSURE:
+ /* mt9t031 has maximum == default */
+ if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+ return -EINVAL;
+ else {
+ const unsigned long range = qctrl->maximum - qctrl->minimum;
+ const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 +
+ range / 2) / range + 1;
+ u32 old;
+
+ get_shutter(icd, &old);
+ dev_dbg(&icd->dev, "Setting shutter width from %u to %u\n",
+ old, shutter);
+ if (set_shutter(icd, shutter) < 0)
+ return -EIO;
+ icd->exposure = ctrl->value;
+ mt9t031->autoexposure = 0;
+ }
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ if (ctrl->value) {
+ const u16 vblank = MT9T031_VERTICAL_BLANK;
+ const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
+ if (set_shutter(icd, icd->height +
+ icd->y_skip_top + vblank) < 0)
+ return -EIO;
+ qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
+ icd->exposure = (shutter_max / 2 + (icd->height +
+ icd->y_skip_top + vblank - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
+ shutter_max + qctrl->minimum;
+ mt9t031->autoexposure = 1;
+ } else
+ mt9t031->autoexposure = 0;
+ break;
+ }
+ return 0;
+}
+
+/* Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one */
+static int mt9t031_video_probe(struct soc_camera_device *icd)
+{
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ s32 data;
+ int ret;
+
+ /* We must have a parent by now. And it cannot be a wrong one.
+ * So this entire test is completely redundant. */
+ if (!icd->dev.parent ||
+ to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+ return -ENODEV;
+
+ /* Enable the chip */
+ data = reg_write(icd, MT9T031_CHIP_ENABLE, 1);
+ dev_dbg(&icd->dev, "write: %d\n", data);
+
+ /* Read out the chip version register */
+ data = reg_read(icd, MT9T031_CHIP_VERSION);
+
+ switch (data) {
+ case 0x1621:
+ mt9t031->model = V4L2_IDENT_MT9T031;
+ icd->formats = mt9t031_colour_formats;
+ icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats);
+ break;
+ default:
+ ret = -ENODEV;
+ dev_err(&icd->dev,
+ "No MT9T031 chip detected, register read %x\n", data);
+ goto ei2c;
+ }
+
+ dev_info(&icd->dev, "Detected a MT9T031 chip ID %x\n", data);
+
+ /* Now that we know the model, we can start video */
+ ret = soc_camera_video_start(icd);
+ if (ret)
+ goto evstart;
+
+ return 0;
+
+evstart:
+ei2c:
+ return ret;
+}
+
+static void mt9t031_video_remove(struct soc_camera_device *icd)
+{
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+
+ dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9t031->client->addr,
+ icd->dev.parent, icd->vdev);
+ soc_camera_video_stop(icd);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+static int mt9t031_probe(struct i2c_client *client)
+#else
+static int mt9t031_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+#endif
+{
+ struct mt9t031 *mt9t031;
+ struct soc_camera_device *icd;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl = client->dev.platform_data;
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "MT9T031 driver needs platform data\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ mt9t031 = kzalloc(sizeof(struct mt9t031), GFP_KERNEL);
+ if (!mt9t031)
+ return -ENOMEM;
+
+ mt9t031->client = client;
+ i2c_set_clientdata(client, mt9t031);
+
+ /* Second stage probe - when a capture adapter is there */
+ icd = &mt9t031->icd;
+ icd->ops = &mt9t031_ops;
+ icd->control = &client->dev;
+ icd->x_min = MT9T031_COLUMN_SKIP;
+ icd->y_min = MT9T031_ROW_SKIP;
+ icd->x_current = icd->x_min;
+ icd->y_current = icd->y_min;
+ icd->width_min = MT9T031_MIN_WIDTH;
+ icd->width_max = MT9T031_MAX_WIDTH;
+ icd->height_min = MT9T031_MIN_HEIGHT;
+ icd->height_max = MT9T031_MAX_HEIGHT;
+ icd->y_skip_top = 0;
+ icd->iface = icl->bus_id;
+ /* Simulated autoexposure. If enabled, we calculate shutter width
+ * ourselves in the driver based on vertical blanking and frame width */
+ mt9t031->autoexposure = 1;
+
+ mt9t031->xskip = 1;
+ mt9t031->yskip = 1;
+
+ ret = soc_camera_device_register(icd);
+ if (ret)
+ goto eisdr;
+
+ return 0;
+
+eisdr:
+ i2c_set_clientdata(client, NULL);
+ kfree(mt9t031);
+ return ret;
+}
+
+static int mt9t031_remove(struct i2c_client *client)
+{
+ struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
+
+ soc_camera_device_unregister(&mt9t031->icd);
+ i2c_set_clientdata(client, NULL);
+ kfree(mt9t031);
+
+ return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id mt9t031_id[] = {
+ { "mt9t031", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9t031_id);
+
+#endif
+static struct i2c_driver mt9t031_i2c_driver = {
+ .driver = {
+ .name = "mt9t031",
+ },
+ .probe = mt9t031_probe,
+ .remove = mt9t031_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = mt9t031_id,
+#endif
+};
+
+static int __init mt9t031_mod_init(void)
+{
+ return i2c_add_driver(&mt9t031_i2c_driver);
+}
+
+static void __exit mt9t031_mod_exit(void)
+{
+ i2c_del_driver(&mt9t031_i2c_driver);
+}
+
+module_init(mt9t031_mod_init);
+module_exit(mt9t031_mod_exit);
+
+MODULE_DESCRIPTION("Micron MT9T031 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c
index bea695a2c..9601884ca 100644
--- a/linux/drivers/media/video/mt9v022.c
+++ b/linux/drivers/media/video/mt9v022.c
@@ -273,6 +273,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
int ret;
u16 pixclk = 0;
@@ -296,6 +297,8 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
}
+ flags = soc_camera_apply_sensor_flags(icl, flags);
+
if (flags & SOCAM_PCLK_SAMPLE_RISING)
pixclk |= 0x10;
@@ -337,14 +340,14 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
width_flag;
}
-static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9v022_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
int ret;
/* The caller provides a supported format, as verified per call to
- * icd->try_fmt_cap(), datawidth is from our supported format list */
+ * icd->try_fmt(), datawidth is from our supported format list */
switch (pixfmt) {
case V4L2_PIX_FMT_GREY:
case V4L2_PIX_FMT_Y16:
@@ -400,31 +403,33 @@ static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
return 0;
}
-static int mt9v022_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9v022_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
- if (f->fmt.pix.height < 32 + icd->y_skip_top)
- f->fmt.pix.height = 32 + icd->y_skip_top;
- if (f->fmt.pix.height > 480 + icd->y_skip_top)
- f->fmt.pix.height = 480 + icd->y_skip_top;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > 752)
- f->fmt.pix.width = 752;
- f->fmt.pix.width &= ~0x03; /* ? */
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ if (pix->height < 32 + icd->y_skip_top)
+ pix->height = 32 + icd->y_skip_top;
+ if (pix->height > 480 + icd->y_skip_top)
+ pix->height = 480 + icd->y_skip_top;
+ if (pix->width < 48)
+ pix->width = 48;
+ if (pix->width > 752)
+ pix->width = 752;
+ pix->width &= ~0x03; /* ? */
return 0;
}
static int mt9v022_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_chip_ident *id)
+ struct v4l2_dbg_chip_ident *id)
{
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+ if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
- if (id->match_chip != mt9v022->client->addr)
+ if (id->match.addr != mt9v022->client->addr)
return -ENODEV;
id->ident = mt9v022->model;
@@ -435,16 +440,17 @@ static int mt9v022_get_chip_id(struct soc_camera_device *icd,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mt9v022_get_register(struct soc_camera_device *icd,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
- if (reg->match_chip != mt9v022->client->addr)
+ if (reg->match.addr != mt9v022->client->addr)
return -ENODEV;
+ reg->size = 2;
reg->val = reg_read(icd, reg->reg);
if (reg->val > 0xffff)
@@ -454,14 +460,14 @@ static int mt9v022_get_register(struct soc_camera_device *icd,
}
static int mt9v022_set_register(struct soc_camera_device *icd,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
- if (reg->match_chip != mt9v022->client->addr)
+ if (reg->match.addr != mt9v022->client->addr)
return -ENODEV;
if (reg_write(icd, reg->reg, reg->val) < 0)
@@ -538,8 +544,8 @@ static struct soc_camera_ops mt9v022_ops = {
.release = mt9v022_release,
.start_capture = mt9v022_start_capture,
.stop_capture = mt9v022_stop_capture,
- .set_fmt_cap = mt9v022_set_fmt_cap,
- .try_fmt_cap = mt9v022_try_fmt_cap,
+ .set_fmt = mt9v022_set_fmt,
+ .try_fmt = mt9v022_try_fmt,
.set_bus_param = mt9v022_set_bus_param,
.query_bus_param = mt9v022_query_bus_param,
.controls = mt9v022_controls,
@@ -690,6 +696,7 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
static int mt9v022_video_probe(struct soc_camera_device *icd)
{
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
s32 data;
int ret;
@@ -725,7 +732,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
icd->formats = mt9v022_colour_formats;
- if (mt9v022->client->dev.platform_data)
+ if (gpio_is_valid(icl->gpio))
icd->num_formats = ARRAY_SIZE(mt9v022_colour_formats);
else
icd->num_formats = 1;
@@ -733,7 +740,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11);
mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
icd->formats = mt9v022_monochrome_formats;
- if (mt9v022->client->dev.platform_data)
+ if (gpio_is_valid(icl->gpio))
icd->num_formats = ARRAY_SIZE(mt9v022_monochrome_formats);
else
icd->num_formats = 1;
@@ -760,8 +767,8 @@ static void mt9v022_video_remove(struct soc_camera_device *icd)
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
- mt9v022->icd.dev.parent, mt9v022->icd.vdev);
- soc_camera_video_stop(&mt9v022->icd);
+ icd->dev.parent, icd->vdev);
+ soc_camera_video_stop(icd);
}
static int mt9v022_probe(struct i2c_client *client,
diff --git a/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c
index 8252ad94c..974d9bcbd 100644
--- a/linux/drivers/media/video/mxb.c
+++ b/linux/drivers/media/video/mxb.c
@@ -490,7 +490,7 @@ static int mxb_detach(struct saa7146_dev *dev)
return 0;
}
-static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct saa7146_dev *dev = fh->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
diff --git a/linux/drivers/media/video/omap24xxcam-dma.c b/linux/drivers/media/video/omap24xxcam-dma.c
new file mode 100644
index 000000000..1d54b86c9
--- /dev/null
+++ b/linux/drivers/media/video/omap24xxcam-dma.c
@@ -0,0 +1,601 @@
+/*
+ * drivers/media/video/omap24xxcam-dma.c
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.com> and
+ * David Cohen <david.cohen@indt.org.br>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/scatterlist.h>
+
+#include "omap24xxcam.h"
+
+/*
+ *
+ * DMA hardware.
+ *
+ */
+
+/* Ack all interrupt on CSR and IRQSTATUS_L0 */
+static void omap24xxcam_dmahw_ack_all(unsigned long base)
+{
+ u32 csr;
+ int i;
+
+ for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) {
+ csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i));
+ /* ack interrupt in CSR */
+ omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr);
+ }
+ omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf);
+}
+
+/* Ack dmach on CSR and IRQSTATUS_L0 */
+static u32 omap24xxcam_dmahw_ack_ch(unsigned long base, int dmach)
+{
+ u32 csr;
+
+ csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach));
+ /* ack interrupt in CSR */
+ omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr);
+ /* ack interrupt in IRQSTATUS */
+ omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach));
+
+ return csr;
+}
+
+static int omap24xxcam_dmahw_running(unsigned long base, int dmach)
+{
+ return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE;
+}
+
+static void omap24xxcam_dmahw_transfer_setup(unsigned long base, int dmach,
+ dma_addr_t start, u32 len)
+{
+ omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
+ CAMDMA_CCR_SEL_SRC_DST_SYNC
+ | CAMDMA_CCR_BS
+ | CAMDMA_CCR_DST_AMODE_POST_INC
+ | CAMDMA_CCR_SRC_AMODE_POST_INC
+ | CAMDMA_CCR_FS
+ | CAMDMA_CCR_WR_ACTIVE
+ | CAMDMA_CCR_RD_ACTIVE
+ | CAMDMA_CCR_SYNCHRO_CAMERA);
+ omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CEN(dmach), len);
+ omap24xxcam_reg_out(base, CAMDMA_CFN(dmach), 1);
+ omap24xxcam_reg_out(base, CAMDMA_CSDP(dmach),
+ CAMDMA_CSDP_WRITE_MODE_POSTED
+ | CAMDMA_CSDP_DST_BURST_EN_32
+ | CAMDMA_CSDP_DST_PACKED
+ | CAMDMA_CSDP_SRC_BURST_EN_32
+ | CAMDMA_CSDP_SRC_PACKED
+ | CAMDMA_CSDP_DATA_TYPE_8BITS);
+ omap24xxcam_reg_out(base, CAMDMA_CSSA(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CDSA(dmach), start);
+ omap24xxcam_reg_out(base, CAMDMA_CSEI(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CSFI(dmach), DMA_THRESHOLD);
+ omap24xxcam_reg_out(base, CAMDMA_CDEI(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CDFI(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CSR(dmach),
+ CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR
+ | CAMDMA_CSR_BLOCK
+ | CAMDMA_CSR_DROP);
+ omap24xxcam_reg_out(base, CAMDMA_CICR(dmach),
+ CAMDMA_CICR_MISALIGNED_ERR_IE
+ | CAMDMA_CICR_SECURE_ERR_IE
+ | CAMDMA_CICR_TRANS_ERR_IE
+ | CAMDMA_CICR_BLOCK_IE
+ | CAMDMA_CICR_DROP_IE);
+}
+
+static void omap24xxcam_dmahw_transfer_start(unsigned long base, int dmach)
+{
+ omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
+ CAMDMA_CCR_SEL_SRC_DST_SYNC
+ | CAMDMA_CCR_BS
+ | CAMDMA_CCR_DST_AMODE_POST_INC
+ | CAMDMA_CCR_SRC_AMODE_POST_INC
+ | CAMDMA_CCR_ENABLE
+ | CAMDMA_CCR_FS
+ | CAMDMA_CCR_SYNCHRO_CAMERA);
+}
+
+static void omap24xxcam_dmahw_transfer_chain(unsigned long base, int dmach,
+ int free_dmach)
+{
+ int prev_dmach, ch;
+
+ if (dmach == 0)
+ prev_dmach = NUM_CAMDMA_CHANNELS - 1;
+ else
+ prev_dmach = dmach - 1;
+ omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach),
+ CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach);
+ /* Did we chain the DMA transfer before the previous one
+ * finished?
+ */
+ ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS;
+ while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch))
+ & CAMDMA_CCR_ENABLE)) {
+ if (ch == dmach) {
+ /* The previous transfer has ended and this one
+ * hasn't started, so we must not have chained
+ * to the previous one in time. We'll have to
+ * start it now.
+ */
+ omap24xxcam_dmahw_transfer_start(base, dmach);
+ break;
+ } else
+ ch = (ch + 1) % NUM_CAMDMA_CHANNELS;
+ }
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. The DMA
+ * controller may not be idle after this routine completes, because
+ * the completion routines might start new transfers.
+ */
+static void omap24xxcam_dmahw_abort_ch(unsigned long base, int dmach)
+{
+ /* mask all interrupts from this channel */
+ omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0);
+ /* unlink this channel */
+ omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0,
+ CAMDMA_CLNK_CTRL_ENABLE_LNK);
+ /* disable this channel */
+ omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE);
+}
+
+static void omap24xxcam_dmahw_init(unsigned long base)
+{
+ omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG,
+ CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY
+ | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE
+ | CAMDMA_OCP_SYSCONFIG_AUTOIDLE);
+
+ omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10,
+ CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH);
+
+ omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf);
+}
+
+/*
+ *
+ * Individual DMA channel handling.
+ *
+ */
+
+/* Start a DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully started, or non-zero if all
+ * DMA channels are already in use or starting is currently inhibited.
+ */
+static int omap24xxcam_dma_start(struct omap24xxcam_dma *dma, dma_addr_t start,
+ u32 len, dma_callback_t callback, void *arg)
+{
+ unsigned long flags;
+ int dmach;
+
+ spin_lock_irqsave(&dma->lock, flags);
+
+ if (!dma->free_dmach || atomic_read(&dma->dma_stop)) {
+ spin_unlock_irqrestore(&dma->lock, flags);
+ return -EBUSY;
+ }
+
+ dmach = dma->next_dmach;
+
+ dma->ch_state[dmach].callback = callback;
+ dma->ch_state[dmach].arg = arg;
+
+ omap24xxcam_dmahw_transfer_setup(dma->base, dmach, start, len);
+
+ /* We're ready to start the DMA transfer. */
+
+ if (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
+ /* A transfer is already in progress, so try to chain to it. */
+ omap24xxcam_dmahw_transfer_chain(dma->base, dmach,
+ dma->free_dmach);
+ } else {
+ /* No transfer is in progress, so we'll just start this one
+ * now.
+ */
+ omap24xxcam_dmahw_transfer_start(dma->base, dmach);
+ }
+
+ dma->next_dmach = (dma->next_dmach + 1) % NUM_CAMDMA_CHANNELS;
+ dma->free_dmach--;
+
+ spin_unlock_irqrestore(&dma->lock, flags);
+
+ return 0;
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. The DMA
+ * controller may not be idle after this routine completes, because
+ * the completion routines might start new transfers.
+ */
+static void omap24xxcam_dma_abort(struct omap24xxcam_dma *dma, u32 csr)
+{
+ unsigned long flags;
+ int dmach, i, free_dmach;
+ dma_callback_t callback;
+ void *arg;
+
+ spin_lock_irqsave(&dma->lock, flags);
+
+ /* stop any DMA transfers in progress */
+ dmach = (dma->next_dmach + dma->free_dmach) % NUM_CAMDMA_CHANNELS;
+ for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) {
+ omap24xxcam_dmahw_abort_ch(dma->base, dmach);
+ dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS;
+ }
+
+ /* We have to be careful here because the callback routine
+ * might start a new DMA transfer, and we only want to abort
+ * transfers that were started before this routine was called.
+ */
+ free_dmach = dma->free_dmach;
+ while ((dma->free_dmach < NUM_CAMDMA_CHANNELS) &&
+ (free_dmach < NUM_CAMDMA_CHANNELS)) {
+ dmach = (dma->next_dmach + dma->free_dmach)
+ % NUM_CAMDMA_CHANNELS;
+ callback = dma->ch_state[dmach].callback;
+ arg = dma->ch_state[dmach].arg;
+ dma->free_dmach++;
+ free_dmach++;
+ if (callback) {
+ /* leave interrupts disabled during callback */
+ spin_unlock(&dma->lock);
+ (*callback) (dma, csr, arg);
+ spin_lock(&dma->lock);
+ }
+ }
+
+ spin_unlock_irqrestore(&dma->lock, flags);
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. If the completion
+ * routines attempt to start a new DMA transfer it will fail, so the
+ * DMA controller will be idle after this routine completes.
+ */
+static void omap24xxcam_dma_stop(struct omap24xxcam_dma *dma, u32 csr)
+{
+ atomic_inc(&dma->dma_stop);
+ omap24xxcam_dma_abort(dma, csr);
+ atomic_dec(&dma->dma_stop);
+}
+
+/* Camera DMA interrupt service routine. */
+void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma)
+{
+ int dmach;
+ dma_callback_t callback;
+ void *arg;
+ u32 csr;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ spin_lock(&dma->lock);
+
+ if (dma->free_dmach == NUM_CAMDMA_CHANNELS) {
+ /* A camera DMA interrupt occurred while all channels
+ * are idle, so we'll acknowledge the interrupt in the
+ * IRQSTATUS register and exit.
+ */
+ omap24xxcam_dmahw_ack_all(dma->base);
+ spin_unlock(&dma->lock);
+ return;
+ }
+
+ while (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
+ dmach = (dma->next_dmach + dma->free_dmach)
+ % NUM_CAMDMA_CHANNELS;
+ if (omap24xxcam_dmahw_running(dma->base, dmach)) {
+ /* This buffer hasn't finished yet, so we're done. */
+ break;
+ }
+ csr = omap24xxcam_dmahw_ack_ch(dma->base, dmach);
+ if (csr & csr_error) {
+ /* A DMA error occurred, so stop all DMA
+ * transfers in progress.
+ */
+ spin_unlock(&dma->lock);
+ omap24xxcam_dma_stop(dma, csr);
+ return;
+ } else {
+ callback = dma->ch_state[dmach].callback;
+ arg = dma->ch_state[dmach].arg;
+ dma->free_dmach++;
+ if (callback) {
+ spin_unlock(&dma->lock);
+ (*callback) (dma, csr, arg);
+ spin_lock(&dma->lock);
+ }
+ }
+ }
+
+ spin_unlock(&dma->lock);
+
+ omap24xxcam_sgdma_process(
+ container_of(dma, struct omap24xxcam_sgdma, dma));
+}
+
+void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dma->lock, flags);
+
+ omap24xxcam_dmahw_init(dma->base);
+
+ spin_unlock_irqrestore(&dma->lock, flags);
+}
+
+static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma,
+ unsigned long base)
+{
+ int ch;
+
+ /* group all channels on DMA IRQ0 and unmask irq */
+ spin_lock_init(&dma->lock);
+ dma->base = base;
+ dma->free_dmach = NUM_CAMDMA_CHANNELS;
+ dma->next_dmach = 0;
+ for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) {
+ dma->ch_state[ch].callback = NULL;
+ dma->ch_state[ch].arg = NULL;
+ }
+}
+
+/*
+ *
+ * Scatter-gather DMA.
+ *
+ * High-level DMA construct for transferring whole picture frames to
+ * memory that is discontinuous.
+ *
+ */
+
+/* DMA completion routine for the scatter-gather DMA fragments. */
+static void omap24xxcam_sgdma_callback(struct omap24xxcam_dma *dma, u32 csr,
+ void *arg)
+{
+ struct omap24xxcam_sgdma *sgdma =
+ container_of(dma, struct omap24xxcam_sgdma, dma);
+ int sgslot = (int)arg;
+ struct sgdma_state *sg_state;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ spin_lock(&sgdma->lock);
+
+ /* We got an interrupt, we can remove the timer */
+ del_timer(&sgdma->reset_timer);
+
+ sg_state = sgdma->sg_state + sgslot;
+ if (!sg_state->queued_sglist) {
+ spin_unlock(&sgdma->lock);
+ printk(KERN_ERR "%s: sgdma completed when none queued!\n",
+ __func__);
+ return;
+ }
+
+ sg_state->csr |= csr;
+ if (!--sg_state->queued_sglist) {
+ /* Queue for this sglist is empty, so check to see if we're
+ * done.
+ */
+ if ((sg_state->next_sglist == sg_state->sglen)
+ || (sg_state->csr & csr_error)) {
+ sgdma_callback_t callback = sg_state->callback;
+ void *arg = sg_state->arg;
+ u32 sg_csr = sg_state->csr;
+ /* All done with this sglist */
+ sgdma->free_sgdma++;
+ if (callback) {
+ spin_unlock(&sgdma->lock);
+ (*callback) (sgdma, sg_csr, arg);
+ return;
+ }
+ }
+ }
+
+ spin_unlock(&sgdma->lock);
+}
+
+/* Start queued scatter-gather DMA transfers. */
+void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma)
+{
+ unsigned long flags;
+ int queued_sgdma, sgslot;
+ struct sgdma_state *sg_state;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ spin_lock_irqsave(&sgdma->lock, flags);
+
+ queued_sgdma = NUM_SG_DMA - sgdma->free_sgdma;
+ sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
+ while (queued_sgdma > 0) {
+ sg_state = sgdma->sg_state + sgslot;
+ while ((sg_state->next_sglist < sg_state->sglen) &&
+ !(sg_state->csr & csr_error)) {
+ const struct scatterlist *sglist;
+ unsigned int len;
+
+ sglist = sg_state->sglist + sg_state->next_sglist;
+ /* try to start the next DMA transfer */
+ if (sg_state->next_sglist + 1 == sg_state->sglen) {
+ /*
+ * On the last sg, we handle the case where
+ * cam->img.pix.sizeimage % PAGE_ALIGN != 0
+ */
+ len = sg_state->len - sg_state->bytes_read;
+ } else {
+ len = sg_dma_len(sglist);
+ }
+
+ if (omap24xxcam_dma_start(&sgdma->dma,
+ sg_dma_address(sglist),
+ len,
+ omap24xxcam_sgdma_callback,
+ (void *)sgslot)) {
+ /* DMA start failed */
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+ return;
+ } else {
+ unsigned long expires;
+ /* DMA start was successful */
+ sg_state->next_sglist++;
+ sg_state->bytes_read += len;
+ sg_state->queued_sglist++;
+
+ /* We start the reset timer */
+ expires = jiffies + HZ;
+ mod_timer(&sgdma->reset_timer, expires);
+ }
+ }
+ queued_sgdma--;
+ sgslot = (sgslot + 1) % NUM_SG_DMA;
+ }
+
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+}
+
+/*
+ * Queue a scatter-gather DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully queued, or non-zero
+ * if all of the scatter-gather slots are already in use.
+ */
+int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
+ const struct scatterlist *sglist, int sglen,
+ int len, sgdma_callback_t callback, void *arg)
+{
+ unsigned long flags;
+ struct sgdma_state *sg_state;
+
+ if ((sglen < 0) || ((sglen > 0) & !sglist))
+ return -EINVAL;
+
+ spin_lock_irqsave(&sgdma->lock, flags);
+
+ if (!sgdma->free_sgdma) {
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+ return -EBUSY;
+ }
+
+ sg_state = sgdma->sg_state + sgdma->next_sgdma;
+
+ sg_state->sglist = sglist;
+ sg_state->sglen = sglen;
+ sg_state->next_sglist = 0;
+ sg_state->bytes_read = 0;
+ sg_state->len = len;
+ sg_state->queued_sglist = 0;
+ sg_state->csr = 0;
+ sg_state->callback = callback;
+ sg_state->arg = arg;
+
+ sgdma->next_sgdma = (sgdma->next_sgdma + 1) % NUM_SG_DMA;
+ sgdma->free_sgdma--;
+
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+
+ omap24xxcam_sgdma_process(sgdma);
+
+ return 0;
+}
+
+/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress.
+ * Any queued scatter-gather DMA transactions that have not yet been started
+ * will remain queued. The DMA controller will be idle after this routine
+ * completes. When the scatter-gather queue is restarted, the next
+ * scatter-gather DMA transfer will begin at the start of a new transaction.
+ */
+void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma)
+{
+ unsigned long flags;
+ int sgslot;
+ struct sgdma_state *sg_state;
+ u32 csr = CAMDMA_CSR_TRANS_ERR;
+
+ /* stop any DMA transfers in progress */
+ omap24xxcam_dma_stop(&sgdma->dma, csr);
+
+ spin_lock_irqsave(&sgdma->lock, flags);
+
+ if (sgdma->free_sgdma < NUM_SG_DMA) {
+ sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
+ sg_state = sgdma->sg_state + sgslot;
+ if (sg_state->next_sglist != 0) {
+ /* This DMA transfer was in progress, so abort it. */
+ sgdma_callback_t callback = sg_state->callback;
+ void *arg = sg_state->arg;
+ sgdma->free_sgdma++;
+ if (callback) {
+ /* leave interrupts masked */
+ spin_unlock(&sgdma->lock);
+ (*callback) (sgdma, csr, arg);
+ spin_lock(&sgdma->lock);
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+}
+
+void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
+ unsigned long base,
+ void (*reset_callback)(unsigned long data),
+ unsigned long reset_callback_data)
+{
+ int sg;
+
+ spin_lock_init(&sgdma->lock);
+ sgdma->free_sgdma = NUM_SG_DMA;
+ sgdma->next_sgdma = 0;
+ for (sg = 0; sg < NUM_SG_DMA; sg++) {
+ sgdma->sg_state[sg].sglen = 0;
+ sgdma->sg_state[sg].next_sglist = 0;
+ sgdma->sg_state[sg].bytes_read = 0;
+ sgdma->sg_state[sg].queued_sglist = 0;
+ sgdma->sg_state[sg].csr = 0;
+ sgdma->sg_state[sg].callback = NULL;
+ sgdma->sg_state[sg].arg = NULL;
+ }
+
+ omap24xxcam_dma_init(&sgdma->dma, base);
+ setup_timer(&sgdma->reset_timer, reset_callback, reset_callback_data);
+}
diff --git a/linux/drivers/media/video/omap24xxcam.c b/linux/drivers/media/video/omap24xxcam.c
new file mode 100644
index 000000000..73eb656ac
--- /dev/null
+++ b/linux/drivers/media/video/omap24xxcam.c
@@ -0,0 +1,1907 @@
+/*
+ * drivers/media/video/omap24xxcam.c
+ *
+ * OMAP 2 camera block driver.
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007-2008 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/pci.h> /* needed for videobufs */
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+#include "omap24xxcam.h"
+
+#define OMAP24XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
+
+#define RESET_TIMEOUT_NS 10000
+
+static void omap24xxcam_reset(struct omap24xxcam_device *cam);
+static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam);
+static void omap24xxcam_device_unregister(struct v4l2_int_device *s);
+static int omap24xxcam_remove(struct platform_device *pdev);
+
+/* module parameters */
+static int video_nr = -1; /* video device minor (-1 ==> auto assign) */
+/*
+ * Maximum amount of memory to use for capture buffers.
+ * Default is 4800KB, enough to double-buffer SXGA.
+ */
+static int capture_mem = 1280 * 960 * 2 * 2;
+
+static struct v4l2_int_device omap24xxcam;
+
+/*
+ *
+ * Clocks.
+ *
+ */
+
+static void omap24xxcam_clock_put(struct omap24xxcam_device *cam)
+{
+ if (cam->ick != NULL && !IS_ERR(cam->ick))
+ clk_put(cam->ick);
+ if (cam->fck != NULL && !IS_ERR(cam->fck))
+ clk_put(cam->fck);
+
+ cam->ick = cam->fck = NULL;
+}
+
+static int omap24xxcam_clock_get(struct omap24xxcam_device *cam)
+{
+ int rval = 0;
+
+ cam->fck = clk_get(cam->dev, "cam_fck");
+ if (IS_ERR(cam->fck)) {
+ dev_err(cam->dev, "can't get cam_fck");
+ rval = PTR_ERR(cam->fck);
+ omap24xxcam_clock_put(cam);
+ return rval;
+ }
+
+ cam->ick = clk_get(cam->dev, "cam_ick");
+ if (IS_ERR(cam->ick)) {
+ dev_err(cam->dev, "can't get cam_ick");
+ rval = PTR_ERR(cam->ick);
+ omap24xxcam_clock_put(cam);
+ }
+
+ return rval;
+}
+
+static void omap24xxcam_clock_on(struct omap24xxcam_device *cam)
+{
+ clk_enable(cam->fck);
+ clk_enable(cam->ick);
+}
+
+static void omap24xxcam_clock_off(struct omap24xxcam_device *cam)
+{
+ clk_disable(cam->fck);
+ clk_disable(cam->ick);
+}
+
+/*
+ *
+ * Camera core
+ *
+ */
+
+/*
+ * Set xclk.
+ *
+ * To disable xclk, use value zero.
+ */
+static void omap24xxcam_core_xclk_set(const struct omap24xxcam_device *cam,
+ u32 xclk)
+{
+ if (xclk) {
+ u32 divisor = CAM_MCLK / xclk;
+
+ if (divisor == 1)
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+ CC_CTRL_XCLK,
+ CC_CTRL_XCLK_DIV_BYPASS);
+ else
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+ CC_CTRL_XCLK, divisor);
+ } else
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+ CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW);
+}
+
+static void omap24xxcam_core_hwinit(const struct omap24xxcam_device *cam)
+{
+ /*
+ * Setting the camera core AUTOIDLE bit causes problems with frame
+ * synchronization, so we will clear the AUTOIDLE bit instead.
+ */
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_SYSCONFIG,
+ CC_SYSCONFIG_AUTOIDLE);
+
+ /* program the camera interface DMA packet size */
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_DMA,
+ CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1));
+
+ /* enable camera core error interrupts */
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQENABLE,
+ CC_IRQENABLE_FW_ERR_IRQ
+ | CC_IRQENABLE_FSC_ERR_IRQ
+ | CC_IRQENABLE_SSC_ERR_IRQ
+ | CC_IRQENABLE_FIFO_OF_IRQ);
+}
+
+/*
+ * Enable the camera core.
+ *
+ * Data transfer to the camera DMA starts from next starting frame.
+ */
+static void omap24xxcam_core_enable(const struct omap24xxcam_device *cam)
+{
+
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
+ cam->cc_ctrl);
+}
+
+/*
+ * Disable camera core.
+ *
+ * The data transfer will be stopped immediately (CC_CTRL_CC_RST). The
+ * core internal state machines will be reset. Use
+ * CC_CTRL_CC_FRAME_TRIG instead if you want to transfer the current
+ * frame completely.
+ */
+static void omap24xxcam_core_disable(const struct omap24xxcam_device *cam)
+{
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
+ CC_CTRL_CC_RST);
+}
+
+/* Interrupt service routine for camera core interrupts. */
+static void omap24xxcam_core_isr(struct omap24xxcam_device *cam)
+{
+ u32 cc_irqstatus;
+ const u32 cc_irqstatus_err =
+ CC_IRQSTATUS_FW_ERR_IRQ
+ | CC_IRQSTATUS_FSC_ERR_IRQ
+ | CC_IRQSTATUS_SSC_ERR_IRQ
+ | CC_IRQSTATUS_FIFO_UF_IRQ
+ | CC_IRQSTATUS_FIFO_OF_IRQ;
+
+ cc_irqstatus = omap24xxcam_reg_in(cam->mmio_base + CC_REG_OFFSET,
+ CC_IRQSTATUS);
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQSTATUS,
+ cc_irqstatus);
+
+ if (cc_irqstatus & cc_irqstatus_err
+ && !atomic_read(&cam->in_reset)) {
+ dev_dbg(cam->dev, "resetting camera, cc_irqstatus 0x%x\n",
+ cc_irqstatus);
+ omap24xxcam_reset(cam);
+ }
+}
+
+/*
+ *
+ * videobuf_buffer handling.
+ *
+ * Memory for mmapped videobuf_buffers is not allocated
+ * conventionally, but by several kmalloc allocations and then
+ * creating the scatterlist on our own. User-space buffers are handled
+ * normally.
+ *
+ */
+
+/*
+ * Free the memory-mapped buffer memory allocated for a
+ * videobuf_buffer and the associated scatterlist.
+ */
+static void omap24xxcam_vbq_free_mmap_buffer(struct videobuf_buffer *vb)
+{
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+ size_t alloc_size;
+ struct page *page;
+ int i;
+
+ if (dma->sglist == NULL)
+ return;
+
+ i = dma->sglen;
+ while (i) {
+ i--;
+ alloc_size = sg_dma_len(&dma->sglist[i]);
+ page = sg_page(&dma->sglist[i]);
+ do {
+ ClearPageReserved(page++);
+ } while (alloc_size -= PAGE_SIZE);
+ __free_pages(sg_page(&dma->sglist[i]),
+ get_order(sg_dma_len(&dma->sglist[i])));
+ }
+
+ kfree(dma->sglist);
+ dma->sglist = NULL;
+}
+
+/* Release all memory related to the videobuf_queue. */
+static void omap24xxcam_vbq_free_mmap_buffers(struct videobuf_queue *vbq)
+{
+ int i;
+
+ mutex_lock(&vbq->vb_lock);
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == vbq->bufs[i])
+ continue;
+ if (V4L2_MEMORY_MMAP != vbq->bufs[i]->memory)
+ continue;
+ vbq->ops->buf_release(vbq, vbq->bufs[i]);
+ omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
+ kfree(vbq->bufs[i]);
+ vbq->bufs[i] = NULL;
+ }
+
+ mutex_unlock(&vbq->vb_lock);
+
+ videobuf_mmap_free(vbq);
+}
+
+/*
+ * Allocate physically as contiguous as possible buffer for video
+ * frame and allocate and build DMA scatter-gather list for it.
+ */
+static int omap24xxcam_vbq_alloc_mmap_buffer(struct videobuf_buffer *vb)
+{
+ unsigned int order;
+ size_t alloc_size, size = vb->bsize; /* vb->bsize is page aligned */
+ struct page *page;
+ int max_pages, err = 0, i = 0;
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ /*
+ * allocate maximum size scatter-gather list. Note this is
+ * overhead. We may not use as many entries as we allocate
+ */
+ max_pages = vb->bsize >> PAGE_SHIFT;
+ dma->sglist = kcalloc(max_pages, sizeof(*dma->sglist), GFP_KERNEL);
+ if (dma->sglist == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ while (size) {
+ order = get_order(size);
+ /*
+ * do not over-allocate even if we would get larger
+ * contiguous chunk that way
+ */
+ if ((PAGE_SIZE << order) > size)
+ order--;
+
+ /* try to allocate as many contiguous pages as possible */
+ page = alloc_pages(GFP_KERNEL | GFP_DMA, order);
+ /* if allocation fails, try to allocate smaller amount */
+ while (page == NULL) {
+ order--;
+ page = alloc_pages(GFP_KERNEL | GFP_DMA, order);
+ if (page == NULL && !order) {
+ err = -ENOMEM;
+ goto out;
+ }
+ }
+ size -= (PAGE_SIZE << order);
+
+ /* append allocated chunk of pages into scatter-gather list */
+ sg_set_page(&dma->sglist[i], page, PAGE_SIZE << order, 0);
+ dma->sglen++;
+ i++;
+
+ alloc_size = (PAGE_SIZE << order);
+
+ /* clear pages before giving them to user space */
+ memset(page_address(page), 0, alloc_size);
+
+ /* mark allocated pages reserved */
+ do {
+ SetPageReserved(page++);
+ } while (alloc_size -= PAGE_SIZE);
+ }
+ /*
+ * REVISIT: not fully correct to assign nr_pages == sglen but
+ * video-buf is passing nr_pages for e.g. unmap_sg calls
+ */
+ dma->nr_pages = dma->sglen;
+ dma->direction = PCI_DMA_FROMDEVICE;
+
+ return 0;
+
+out:
+ omap24xxcam_vbq_free_mmap_buffer(vb);
+ return err;
+}
+
+static int omap24xxcam_vbq_alloc_mmap_buffers(struct videobuf_queue *vbq,
+ unsigned int count)
+{
+ int i, err = 0;
+ struct omap24xxcam_fh *fh =
+ container_of(vbq, struct omap24xxcam_fh, vbq);
+
+ mutex_lock(&vbq->vb_lock);
+
+ for (i = 0; i < count; i++) {
+ err = omap24xxcam_vbq_alloc_mmap_buffer(vbq->bufs[i]);
+ if (err)
+ goto out;
+ dev_dbg(fh->cam->dev, "sglen is %d for buffer %d\n",
+ videobuf_to_dma(vbq->bufs[i])->sglen, i);
+ }
+
+ mutex_unlock(&vbq->vb_lock);
+
+ return 0;
+out:
+ while (i) {
+ i--;
+ omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
+ }
+
+ mutex_unlock(&vbq->vb_lock);
+
+ return err;
+}
+
+/*
+ * This routine is called from interrupt context when a scatter-gather DMA
+ * transfer of a videobuf_buffer completes.
+ */
+static void omap24xxcam_vbq_complete(struct omap24xxcam_sgdma *sgdma,
+ u32 csr, void *arg)
+{
+ struct omap24xxcam_device *cam =
+ container_of(sgdma, struct omap24xxcam_device, sgdma);
+ struct omap24xxcam_fh *fh = cam->streaming->private_data;
+ struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+ if (--cam->sgdma_in_queue == 0)
+ omap24xxcam_core_disable(cam);
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+
+ do_gettimeofday(&vb->ts);
+ vb->field_count = atomic_add_return(2, &fh->field_count);
+ if (csr & csr_error) {
+ vb->state = VIDEOBUF_ERROR;
+ if (!atomic_read(&fh->cam->in_reset)) {
+ dev_dbg(cam->dev, "resetting camera, csr 0x%x\n", csr);
+ omap24xxcam_reset(cam);
+ }
+ } else
+ vb->state = VIDEOBUF_DONE;
+ wake_up(&vb->done);
+}
+
+static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb)
+{
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ /* wait for buffer, especially to get out of the sgdma queue */
+ videobuf_waiton(vb, 0, 0);
+ if (vb->memory == V4L2_MEMORY_MMAP) {
+ dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen,
+ dma->direction);
+ dma->direction = DMA_NONE;
+ } else {
+ videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
+ videobuf_dma_free(videobuf_to_dma(vb));
+ }
+
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+/*
+ * Limit the number of available kernel image capture buffers based on the
+ * number requested, the currently selected image size, and the maximum
+ * amount of memory permitted for kernel capture buffers.
+ */
+static int omap24xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
+ unsigned int *size)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+
+ if (*cnt <= 0)
+ *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+ if (*cnt > VIDEO_MAX_FRAME)
+ *cnt = VIDEO_MAX_FRAME;
+
+ *size = fh->pix.sizeimage;
+
+ /* accessing fh->cam->capture_mem is ok, it's constant */
+ while (*size * *cnt > fh->cam->capture_mem)
+ (*cnt)--;
+
+ return 0;
+}
+
+static int omap24xxcam_dma_iolock(struct videobuf_queue *vbq,
+ struct videobuf_dmabuf *dma)
+{
+ int err = 0;
+
+ dma->direction = PCI_DMA_FROMDEVICE;
+ if (!dma_map_sg(vbq->dev, dma->sglist, dma->sglen, dma->direction)) {
+ kfree(dma->sglist);
+ dma->sglist = NULL;
+ dma->sglen = 0;
+ err = -EIO;
+ }
+
+ return err;
+}
+
+static int omap24xxcam_vbq_prepare(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ int err = 0;
+
+ /*
+ * Accessing pix here is okay since it's constant while
+ * streaming is on (and we only get called then).
+ */
+ if (vb->baddr) {
+ /* This is a userspace buffer. */
+ if (fh->pix.sizeimage > vb->bsize) {
+ /* The buffer isn't big enough. */
+ err = -EINVAL;
+ } else
+ vb->size = fh->pix.sizeimage;
+ } else {
+ if (vb->state != VIDEOBUF_NEEDS_INIT) {
+ /*
+ * We have a kernel bounce buffer that has
+ * already been allocated.
+ */
+ if (fh->pix.sizeimage > vb->size) {
+ /*
+ * The image size has been changed to
+ * a larger size since this buffer was
+ * allocated, so we need to free and
+ * reallocate it.
+ */
+ omap24xxcam_vbq_release(vbq, vb);
+ vb->size = fh->pix.sizeimage;
+ }
+ } else {
+ /* We need to allocate a new kernel bounce buffer. */
+ vb->size = fh->pix.sizeimage;
+ }
+ }
+
+ if (err)
+ return err;
+
+ vb->width = fh->pix.width;
+ vb->height = fh->pix.height;
+ vb->field = field;
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ if (vb->memory == V4L2_MEMORY_MMAP)
+ /*
+ * we have built the scatter-gather list by ourself so
+ * do the scatter-gather mapping as well
+ */
+ err = omap24xxcam_dma_iolock(vbq, videobuf_to_dma(vb));
+ else
+ err = videobuf_iolock(vbq, vb, NULL);
+ }
+
+ if (!err)
+ vb->state = VIDEOBUF_PREPARED;
+ else
+ omap24xxcam_vbq_release(vbq, vb);
+
+ return err;
+}
+
+static void omap24xxcam_vbq_queue(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ enum videobuf_state state = vb->state;
+ unsigned long flags;
+ int err;
+
+ /*
+ * FIXME: We're marking the buffer active since we have no
+ * pretty way of marking it active exactly when the
+ * scatter-gather transfer starts.
+ */
+ vb->state = VIDEOBUF_ACTIVE;
+
+ err = omap24xxcam_sgdma_queue(&fh->cam->sgdma,
+ videobuf_to_dma(vb)->sglist,
+ videobuf_to_dma(vb)->sglen, vb->size,
+ omap24xxcam_vbq_complete, vb);
+
+ if (!err) {
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+ if (++cam->sgdma_in_queue == 1
+ && !atomic_read(&cam->in_reset))
+ omap24xxcam_core_enable(cam);
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+ } else {
+ /*
+ * Oops. We're not supposed to get any errors here.
+ * The only way we could get an error is if we ran out
+ * of scatter-gather DMA slots, but we are supposed to
+ * have at least as many scatter-gather DMA slots as
+ * video buffers so that can't happen.
+ */
+ dev_err(cam->dev, "failed to queue a video buffer for dma!\n");
+ dev_err(cam->dev, "likely a bug in the driver!\n");
+ vb->state = state;
+ }
+}
+
+static struct videobuf_queue_ops omap24xxcam_vbq_ops = {
+ .buf_setup = omap24xxcam_vbq_setup,
+ .buf_prepare = omap24xxcam_vbq_prepare,
+ .buf_queue = omap24xxcam_vbq_queue,
+ .buf_release = omap24xxcam_vbq_release,
+};
+
+/*
+ *
+ * OMAP main camera system
+ *
+ */
+
+/*
+ * Reset camera block to power-on state.
+ */
+static void omap24xxcam_poweron_reset(struct omap24xxcam_device *cam)
+{
+ int max_loop = RESET_TIMEOUT_NS;
+
+ /* Reset whole camera subsystem */
+ omap24xxcam_reg_out(cam->mmio_base,
+ CAM_SYSCONFIG,
+ CAM_SYSCONFIG_SOFTRESET);
+
+ /* Wait till it's finished */
+ while (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
+ & CAM_SYSSTATUS_RESETDONE)
+ && --max_loop) {
+ ndelay(1);
+ }
+
+ if (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
+ & CAM_SYSSTATUS_RESETDONE))
+ dev_err(cam->dev, "camera soft reset timeout\n");
+}
+
+/*
+ * (Re)initialise the camera block.
+ */
+static void omap24xxcam_hwinit(struct omap24xxcam_device *cam)
+{
+ omap24xxcam_poweron_reset(cam);
+
+ /* set the camera subsystem autoidle bit */
+ omap24xxcam_reg_out(cam->mmio_base, CAM_SYSCONFIG,
+ CAM_SYSCONFIG_AUTOIDLE);
+
+ /* set the camera MMU autoidle bit */
+ omap24xxcam_reg_out(cam->mmio_base,
+ CAMMMU_REG_OFFSET + CAMMMU_SYSCONFIG,
+ CAMMMU_SYSCONFIG_AUTOIDLE);
+
+ omap24xxcam_core_hwinit(cam);
+
+ omap24xxcam_dma_hwinit(&cam->sgdma.dma);
+}
+
+/*
+ * Callback for dma transfer stalling.
+ */
+static void omap24xxcam_stalled_dma_reset(unsigned long data)
+{
+ struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data;
+
+ if (!atomic_read(&cam->in_reset)) {
+ dev_dbg(cam->dev, "dma stalled, resetting camera\n");
+ omap24xxcam_reset(cam);
+ }
+}
+
+/*
+ * Stop capture. Mark we're doing a reset, stop DMA transfers and
+ * core. (No new scatter-gather transfers will be queued whilst
+ * in_reset is non-zero.)
+ *
+ * If omap24xxcam_capture_stop is called from several places at
+ * once, only the first call will have an effect. Similarly, the last
+ * call omap24xxcam_streaming_cont will have effect.
+ *
+ * Serialisation is ensured by using cam->core_enable_disable_lock.
+ */
+static void omap24xxcam_capture_stop(struct omap24xxcam_device *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+
+ if (atomic_inc_return(&cam->in_reset) != 1) {
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+ return;
+ }
+
+ omap24xxcam_core_disable(cam);
+
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+
+ omap24xxcam_sgdma_sync(&cam->sgdma);
+}
+
+/*
+ * Reset and continue streaming.
+ *
+ * Note: Resetting the camera FIFO via the CC_RST bit in the CC_CTRL
+ * register is supposed to be sufficient to recover from a camera
+ * interface error, but it doesn't seem to be enough. If we only do
+ * that then subsequent image captures are out of sync by either one
+ * or two times DMA_THRESHOLD bytes. Resetting and re-initializing the
+ * entire camera subsystem prevents the problem with frame
+ * synchronization.
+ */
+static void omap24xxcam_capture_cont(struct omap24xxcam_device *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+
+ if (atomic_read(&cam->in_reset) != 1)
+ goto out;
+
+ omap24xxcam_hwinit(cam);
+
+ omap24xxcam_sensor_if_enable(cam);
+
+ omap24xxcam_sgdma_process(&cam->sgdma);
+
+ if (cam->sgdma_in_queue)
+ omap24xxcam_core_enable(cam);
+
+out:
+ atomic_dec(&cam->in_reset);
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+}
+
+static ssize_t
+omap24xxcam_streaming_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct omap24xxcam_device *cam = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", cam->streaming ? "active" : "inactive");
+}
+static DEVICE_ATTR(streaming, S_IRUGO, omap24xxcam_streaming_show, NULL);
+
+/*
+ * Stop capture and restart it. I.e. reset the camera during use.
+ */
+static void omap24xxcam_reset(struct omap24xxcam_device *cam)
+{
+ omap24xxcam_capture_stop(cam);
+ omap24xxcam_capture_cont(cam);
+}
+
+/*
+ * The main interrupt handler.
+ */
+static irqreturn_t omap24xxcam_isr(int irq, void *arg)
+{
+ struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg;
+ u32 irqstatus;
+ unsigned int irqhandled = 0;
+
+ irqstatus = omap24xxcam_reg_in(cam->mmio_base, CAM_IRQSTATUS);
+
+ if (irqstatus &
+ (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1
+ | CAM_IRQSTATUS_DMA_IRQ0)) {
+ omap24xxcam_dma_isr(&cam->sgdma.dma);
+ irqhandled = 1;
+ }
+ if (irqstatus & CAM_IRQSTATUS_CC_IRQ) {
+ omap24xxcam_core_isr(cam);
+ irqhandled = 1;
+ }
+ if (irqstatus & CAM_IRQSTATUS_MMU_IRQ)
+ dev_err(cam->dev, "unhandled camera MMU interrupt!\n");
+
+ return IRQ_RETVAL(irqhandled);
+}
+
+/*
+ *
+ * Sensor handling.
+ *
+ */
+
+/*
+ * Enable the external sensor interface. Try to negotiate interface
+ * parameters with the sensor and start using the new ones. The calls
+ * to sensor_if_enable and sensor_if_disable need not to be balanced.
+ */
+static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam)
+{
+ int rval;
+ struct v4l2_ifparm p;
+
+ rval = vidioc_int_g_ifparm(cam->sdev, &p);
+ if (rval) {
+ dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval);
+ return rval;
+ }
+
+ cam->if_type = p.if_type;
+
+ cam->cc_ctrl = CC_CTRL_CC_EN;
+
+ switch (p.if_type) {
+ case V4L2_IF_TYPE_BT656:
+ if (p.u.bt656.frame_start_on_rising_vs)
+ cam->cc_ctrl |= CC_CTRL_NOBT_SYNCHRO;
+ if (p.u.bt656.bt_sync_correct)
+ cam->cc_ctrl |= CC_CTRL_BT_CORRECT;
+ if (p.u.bt656.swap)
+ cam->cc_ctrl |= CC_CTRL_PAR_ORDERCAM;
+ if (p.u.bt656.latch_clk_inv)
+ cam->cc_ctrl |= CC_CTRL_PAR_CLK_POL;
+ if (p.u.bt656.nobt_hs_inv)
+ cam->cc_ctrl |= CC_CTRL_NOBT_HS_POL;
+ if (p.u.bt656.nobt_vs_inv)
+ cam->cc_ctrl |= CC_CTRL_NOBT_VS_POL;
+
+ switch (p.u.bt656.mode) {
+ case V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT8;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT10;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT12;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_BT_8BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT8;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_BT_10BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT10;
+ break;
+ default:
+ dev_err(cam->dev,
+ "bt656 interface mode %d not supported\n",
+ p.u.bt656.mode);
+ return -EINVAL;
+ }
+ /*
+ * The clock rate that the sensor wants has changed.
+ * We have to adjust the xclk from OMAP 2 side to
+ * match the sensor's wish as closely as possible.
+ */
+ if (p.u.bt656.clock_curr != cam->if_u.bt656.xclk) {
+ u32 xclk = p.u.bt656.clock_curr;
+ u32 divisor;
+
+ if (xclk == 0)
+ return -EINVAL;
+
+ if (xclk > CAM_MCLK)
+ xclk = CAM_MCLK;
+
+ divisor = CAM_MCLK / xclk;
+ if (divisor * xclk < CAM_MCLK)
+ divisor++;
+ if (CAM_MCLK / divisor < p.u.bt656.clock_min
+ && divisor > 1)
+ divisor--;
+ if (divisor > 30)
+ divisor = 30;
+
+ xclk = CAM_MCLK / divisor;
+
+ if (xclk < p.u.bt656.clock_min
+ || xclk > p.u.bt656.clock_max)
+ return -EINVAL;
+
+ cam->if_u.bt656.xclk = xclk;
+ }
+ omap24xxcam_core_xclk_set(cam, cam->if_u.bt656.xclk);
+ break;
+ default:
+ /* FIXME: how about other interfaces? */
+ dev_err(cam->dev, "interface type %d not supported\n",
+ p.if_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void omap24xxcam_sensor_if_disable(const struct omap24xxcam_device *cam)
+{
+ switch (cam->if_type) {
+ case V4L2_IF_TYPE_BT656:
+ omap24xxcam_core_xclk_set(cam, 0);
+ break;
+ }
+}
+
+/*
+ * Initialise the sensor hardware.
+ */
+static int omap24xxcam_sensor_init(struct omap24xxcam_device *cam)
+{
+ int err = 0;
+ struct v4l2_int_device *sdev = cam->sdev;
+
+ omap24xxcam_clock_on(cam);
+ err = omap24xxcam_sensor_if_enable(cam);
+ if (err) {
+ dev_err(cam->dev, "sensor interface could not be enabled at "
+ "initialisation, %d\n", err);
+ cam->sdev = NULL;
+ goto out;
+ }
+
+ /* power up sensor during sensor initialization */
+ vidioc_int_s_power(sdev, 1);
+
+ err = vidioc_int_dev_init(sdev);
+ if (err) {
+ dev_err(cam->dev, "cannot initialize sensor, error %d\n", err);
+ /* Sensor init failed --- it's nonexistent to us! */
+ cam->sdev = NULL;
+ goto out;
+ }
+
+ dev_info(cam->dev, "sensor is %s\n", sdev->name);
+
+out:
+ omap24xxcam_sensor_if_disable(cam);
+ omap24xxcam_clock_off(cam);
+
+ vidioc_int_s_power(sdev, 0);
+
+ return err;
+}
+
+static void omap24xxcam_sensor_exit(struct omap24xxcam_device *cam)
+{
+ if (cam->sdev)
+ vidioc_int_dev_exit(cam->sdev);
+}
+
+static void omap24xxcam_sensor_disable(struct omap24xxcam_device *cam)
+{
+ omap24xxcam_sensor_if_disable(cam);
+ omap24xxcam_clock_off(cam);
+ vidioc_int_s_power(cam->sdev, 0);
+}
+
+/*
+ * Power-up and configure camera sensor. It's ready for capturing now.
+ */
+static int omap24xxcam_sensor_enable(struct omap24xxcam_device *cam)
+{
+ int rval;
+
+ omap24xxcam_clock_on(cam);
+
+ omap24xxcam_sensor_if_enable(cam);
+
+ rval = vidioc_int_s_power(cam->sdev, 1);
+ if (rval)
+ goto out;
+
+ rval = vidioc_int_init(cam->sdev);
+ if (rval)
+ goto out;
+
+ return 0;
+
+out:
+ omap24xxcam_sensor_disable(cam);
+
+ return rval;
+}
+
+static void omap24xxcam_sensor_reset_work(struct work_struct *work)
+{
+ struct omap24xxcam_device *cam =
+ container_of(work, struct omap24xxcam_device,
+ sensor_reset_work);
+
+ if (atomic_read(&cam->reset_disable))
+ return;
+
+ omap24xxcam_capture_stop(cam);
+
+ if (vidioc_int_reset(cam->sdev) == 0) {
+ vidioc_int_init(cam->sdev);
+ } else {
+ /* Can't reset it by vidioc_int_reset. */
+ omap24xxcam_sensor_disable(cam);
+ omap24xxcam_sensor_enable(cam);
+ }
+
+ omap24xxcam_capture_cont(cam);
+}
+
+/*
+ *
+ * IOCTL interface.
+ *
+ */
+
+static int vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+
+ strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
+ cap->version = OMAP24XXCAM_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ rval = vidioc_int_enum_fmt_cap(cam->sdev, f);
+
+ return rval;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_fmt_cap(cam->sdev, f);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ rval = vidioc_int_s_fmt_cap(cam->sdev, f);
+
+out:
+ mutex_unlock(&cam->mutex);
+
+ if (!rval) {
+ mutex_lock(&ofh->vbq.vb_lock);
+ ofh->pix = f->fmt.pix;
+ mutex_unlock(&ofh->vbq.vb_lock);
+ }
+
+ memset(f, 0, sizeof(*f));
+ vidioc_g_fmt_vid_cap(file, fh, f);
+
+ return rval;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_try_fmt_cap(cam->sdev, f);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ mutex_unlock(&cam->mutex);
+ return -EBUSY;
+ }
+
+ omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
+ mutex_unlock(&cam->mutex);
+
+ rval = videobuf_reqbufs(&ofh->vbq, b);
+
+ /*
+ * Either videobuf_reqbufs failed or the buffers are not
+ * memory-mapped (which would need special attention).
+ */
+ if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
+ goto out;
+
+ rval = omap24xxcam_vbq_alloc_mmap_buffers(&ofh->vbq, rval);
+ if (rval)
+ omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
+
+out:
+ return rval;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+
+ return videobuf_querybuf(&ofh->vbq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+
+ return videobuf_qbuf(&ofh->vbq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ struct videobuf_buffer *vb;
+ int rval;
+
+videobuf_dqbuf_again:
+ rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+ if (rval)
+ goto out;
+
+ vb = ofh->vbq.bufs[b->index];
+
+ mutex_lock(&cam->mutex);
+ /* _needs_reset returns -EIO if reset is required. */
+ rval = vidioc_int_g_needs_reset(cam->sdev, (void *)vb->baddr);
+ mutex_unlock(&cam->mutex);
+ if (rval == -EIO)
+ schedule_work(&cam->sensor_reset_work);
+ else
+ rval = 0;
+
+out:
+ /*
+ * This is a hack. We don't want to show -EIO to the user
+ * space. Requeue the buffer and try again if we're not doing
+ * this in non-blocking mode.
+ */
+ if (rval == -EIO) {
+ videobuf_qbuf(&ofh->vbq, b);
+ if (!(file->f_flags & O_NONBLOCK))
+ goto videobuf_dqbuf_again;
+ /*
+ * We don't have a videobuf_buffer now --- maybe next
+ * time...
+ */
+ rval = -EAGAIN;
+ }
+
+ return rval;
+}
+
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ rval = omap24xxcam_sensor_if_enable(cam);
+ if (rval) {
+ dev_dbg(cam->dev, "vidioc_int_g_ifparm failed\n");
+ goto out;
+ }
+
+ rval = videobuf_streamon(&ofh->vbq);
+ if (!rval) {
+ cam->streaming = file;
+ sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+ }
+
+out:
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ struct videobuf_queue *q = &ofh->vbq;
+ int rval;
+
+ atomic_inc(&cam->reset_disable);
+
+ flush_scheduled_work();
+
+ rval = videobuf_streamoff(q);
+ if (!rval) {
+ mutex_lock(&cam->mutex);
+ cam->streaming = NULL;
+ mutex_unlock(&cam->mutex);
+ sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+ }
+
+ atomic_dec(&cam->reset_disable);
+
+ return rval;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh,
+ struct v4l2_input *inp)
+{
+ if (inp->index > 0)
+ return -EINVAL;
+
+ strlcpy(inp->name, "camera", sizeof(inp->name));
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ *i = 0;
+
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ rval = vidioc_int_queryctrl(cam->sdev, a);
+
+ return rval;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_ctrl(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_s_ctrl(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a) {
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_parm(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ struct v4l2_streamparm old_streamparm;
+ int rval;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ old_streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rval = vidioc_int_g_parm(cam->sdev, &old_streamparm);
+ if (rval)
+ goto out;
+
+ rval = vidioc_int_s_parm(cam->sdev, a);
+ if (rval)
+ goto out;
+
+ rval = omap24xxcam_sensor_if_enable(cam);
+ /*
+ * Revert to old streaming parameters if enabling sensor
+ * interface with the new ones failed.
+ */
+ if (rval)
+ vidioc_int_s_parm(cam->sdev, &old_streamparm);
+
+out:
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+/*
+ *
+ * File operations.
+ *
+ */
+
+static unsigned int omap24xxcam_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ struct videobuf_buffer *vb;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming != file) {
+ mutex_unlock(&cam->mutex);
+ return POLLERR;
+ }
+ mutex_unlock(&cam->mutex);
+
+ mutex_lock(&fh->vbq.vb_lock);
+ if (list_empty(&fh->vbq.stream)) {
+ mutex_unlock(&fh->vbq.vb_lock);
+ return POLLERR;
+ }
+ vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
+ mutex_unlock(&fh->vbq.vb_lock);
+
+ poll_wait(file, &vb->done, wait);
+
+ if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static int omap24xxcam_mmap_buffers(struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ struct videobuf_queue *vbq = &fh->vbq;
+ unsigned int first, last, size, i, j;
+ int err = 0;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ mutex_unlock(&cam->mutex);
+ return -EBUSY;
+ }
+ mutex_unlock(&cam->mutex);
+ mutex_lock(&vbq->vb_lock);
+
+ /* look for first buffer to map */
+ for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+ if (NULL == vbq->bufs[first])
+ continue;
+ if (V4L2_MEMORY_MMAP != vbq->bufs[first]->memory)
+ continue;
+ if (vbq->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+ break;
+ }
+
+ /* look for last buffer to map */
+ for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
+ if (NULL == vbq->bufs[last])
+ continue;
+ if (V4L2_MEMORY_MMAP != vbq->bufs[last]->memory)
+ continue;
+ size += vbq->bufs[last]->bsize;
+ if (size == (vma->vm_end - vma->vm_start))
+ break;
+ }
+
+ size = 0;
+ for (i = first; i <= last; i++) {
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vbq->bufs[i]);
+
+ for (j = 0; j < dma->sglen; j++) {
+ err = remap_pfn_range(
+ vma, vma->vm_start + size,
+ page_to_pfn(sg_page(&dma->sglist[j])),
+ sg_dma_len(&dma->sglist[j]), vma->vm_page_prot);
+ if (err)
+ goto out;
+ size += sg_dma_len(&dma->sglist[j]);
+ }
+ }
+
+out:
+ mutex_unlock(&vbq->vb_lock);
+
+ return err;
+}
+
+static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ int rval;
+
+ /* let the video-buf mapper check arguments and set-up structures */
+ rval = videobuf_mmap_mapper(&fh->vbq, vma);
+ if (rval)
+ return rval;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ /* do mapping to our allocated buffers */
+ rval = omap24xxcam_mmap_buffers(file, vma);
+ /*
+ * In case of error, free vma->vm_private_data allocated by
+ * videobuf_mmap_mapper.
+ */
+ if (rval)
+ kfree(vma->vm_private_data);
+
+ return rval;
+}
+
+static int omap24xxcam_open(struct file *file)
+{
+ int minor = video_devdata(file)->minor;
+ struct omap24xxcam_device *cam = omap24xxcam.priv;
+ struct omap24xxcam_fh *fh;
+ struct v4l2_format format;
+
+ if (!cam || !cam->vfd || (cam->vfd->minor != minor))
+ return -ENODEV;
+
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (fh == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&cam->mutex);
+ if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) {
+ mutex_unlock(&cam->mutex);
+ goto out_try_module_get;
+ }
+
+ if (atomic_inc_return(&cam->users) == 1) {
+ omap24xxcam_hwinit(cam);
+ if (omap24xxcam_sensor_enable(cam)) {
+ mutex_unlock(&cam->mutex);
+ goto out_omap24xxcam_sensor_enable;
+ }
+ }
+ mutex_unlock(&cam->mutex);
+
+ fh->cam = cam;
+ mutex_lock(&cam->mutex);
+ vidioc_int_g_fmt_cap(cam->sdev, &format);
+ mutex_unlock(&cam->mutex);
+ /* FIXME: how about fh->pix when there are more users? */
+ fh->pix = format.fmt.pix;
+
+ file->private_data = fh;
+
+ spin_lock_init(&fh->vbq_lock);
+
+ videobuf_queue_sg_init(&fh->vbq, &omap24xxcam_vbq_ops, NULL,
+ &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), fh);
+
+ return 0;
+
+out_omap24xxcam_sensor_enable:
+ omap24xxcam_poweron_reset(cam);
+ module_put(cam->sdev->module);
+
+out_try_module_get:
+ kfree(fh);
+
+ return -ENODEV;
+}
+
+static int omap24xxcam_release(struct file *file)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+
+ atomic_inc(&cam->reset_disable);
+
+ flush_scheduled_work();
+
+ /* stop streaming capture */
+ videobuf_streamoff(&fh->vbq);
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming == file) {
+ cam->streaming = NULL;
+ mutex_unlock(&cam->mutex);
+ sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+ } else {
+ mutex_unlock(&cam->mutex);
+ }
+
+ atomic_dec(&cam->reset_disable);
+
+ omap24xxcam_vbq_free_mmap_buffers(&fh->vbq);
+
+ /*
+ * Make sure the reset work we might have scheduled is not
+ * pending! It may be run *only* if we have users. (And it may
+ * not be scheduled anymore since streaming is already
+ * disabled.)
+ */
+ flush_scheduled_work();
+
+ mutex_lock(&cam->mutex);
+ if (atomic_dec_return(&cam->users) == 0) {
+ omap24xxcam_sensor_disable(cam);
+ omap24xxcam_poweron_reset(cam);
+ }
+ mutex_unlock(&cam->mutex);
+
+ file->private_data = NULL;
+
+ module_put(cam->sdev->module);
+ kfree(fh);
+
+ return 0;
+}
+
+static struct v4l2_file_operations omap24xxcam_fops = {
+ .ioctl = video_ioctl2,
+ .poll = omap24xxcam_poll,
+ .mmap = omap24xxcam_mmap,
+ .open = omap24xxcam_open,
+ .release = omap24xxcam_release,
+};
+
+/*
+ *
+ * Power management.
+ *
+ */
+
+#ifdef CONFIG_PM
+static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ if (atomic_read(&cam->users) == 0)
+ return 0;
+
+ if (!atomic_read(&cam->reset_disable))
+ omap24xxcam_capture_stop(cam);
+
+ omap24xxcam_sensor_disable(cam);
+ omap24xxcam_poweron_reset(cam);
+
+ return 0;
+}
+
+static int omap24xxcam_resume(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ if (atomic_read(&cam->users) == 0)
+ return 0;
+
+ omap24xxcam_hwinit(cam);
+ omap24xxcam_sensor_enable(cam);
+
+ if (!atomic_read(&cam->reset_disable))
+ omap24xxcam_capture_cont(cam);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct v4l2_ioctl_ops omap24xxcam_ioctl_fops = {
+ .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_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_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_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_s_parm = vidioc_s_parm,
+};
+
+/*
+ *
+ * Camera device (i.e. /dev/video).
+ *
+ */
+
+static int omap24xxcam_device_register(struct v4l2_int_device *s)
+{
+ struct omap24xxcam_device *cam = s->u.slave->master->priv;
+ struct video_device *vfd;
+ int rval;
+
+ /* We already have a slave. */
+ if (cam->sdev)
+ return -EBUSY;
+
+ cam->sdev = s;
+
+ if (device_create_file(cam->dev, &dev_attr_streaming) != 0) {
+ dev_err(cam->dev, "could not register sysfs entry\n");
+ rval = -EBUSY;
+ goto err;
+ }
+
+ /* initialize the video_device struct */
+ vfd = cam->vfd = video_device_alloc();
+ if (!vfd) {
+ dev_err(cam->dev, "could not allocate video device struct\n");
+ rval = -ENOMEM;
+ goto err;
+ }
+ vfd->release = video_device_release;
+
+ vfd->parent = cam->dev;
+
+ strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+ vfd->vfl_type = VID_TYPE_CAPTURE | VID_TYPE_CHROMAKEY;
+ vfd->fops = &omap24xxcam_fops;
+ vfd->minor = -1;
+ vfd->ioctl_ops = &omap24xxcam_ioctl_fops;
+
+ omap24xxcam_hwinit(cam);
+
+ rval = omap24xxcam_sensor_init(cam);
+ if (rval)
+ goto err;
+
+ if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+ dev_err(cam->dev, "could not register V4L device\n");
+ vfd->minor = -1;
+ rval = -EBUSY;
+ goto err;
+ }
+
+ omap24xxcam_poweron_reset(cam);
+
+ dev_info(cam->dev, "registered device video%d\n", vfd->minor);
+
+ return 0;
+
+err:
+ omap24xxcam_device_unregister(s);
+
+ return rval;
+}
+
+static void omap24xxcam_device_unregister(struct v4l2_int_device *s)
+{
+ struct omap24xxcam_device *cam = s->u.slave->master->priv;
+
+ omap24xxcam_sensor_exit(cam);
+
+ if (cam->vfd) {
+ if (cam->vfd->minor == -1) {
+ /*
+ * The device was never registered, so release the
+ * video_device struct directly.
+ */
+ video_device_release(cam->vfd);
+ } else {
+ /*
+ * The unregister function will release the
+ * video_device struct as well as
+ * unregistering it.
+ */
+ video_unregister_device(cam->vfd);
+ }
+ cam->vfd = NULL;
+ }
+
+ device_remove_file(cam->dev, &dev_attr_streaming);
+
+ cam->sdev = NULL;
+}
+
+static struct v4l2_int_master omap24xxcam_master = {
+ .attach = omap24xxcam_device_register,
+ .detach = omap24xxcam_device_unregister,
+};
+
+static struct v4l2_int_device omap24xxcam = {
+ .module = THIS_MODULE,
+ .name = CAM_NAME,
+ .type = v4l2_int_type_master,
+ .u = {
+ .master = &omap24xxcam_master
+ },
+};
+
+/*
+ *
+ * Driver initialisation and deinitialisation.
+ *
+ */
+
+static int __init omap24xxcam_probe(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam;
+ struct resource *mem;
+ int irq;
+
+ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+ if (!cam) {
+ dev_err(&pdev->dev, "could not allocate memory\n");
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, cam);
+
+ cam->dev = &pdev->dev;
+
+ /*
+ * Impose a lower limit on the amount of memory allocated for
+ * capture. We require at least enough memory to double-buffer
+ * QVGA (300KB).
+ */
+ if (capture_mem < 320 * 240 * 2 * 2)
+ capture_mem = 320 * 240 * 2 * 2;
+ cam->capture_mem = capture_mem;
+
+ /* request the mem region for the camera registers */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(cam->dev, "no mem resource?\n");
+ goto err;
+ }
+ if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ pdev->name)) {
+ dev_err(cam->dev,
+ "cannot reserve camera register I/O region\n");
+ goto err;
+ }
+ cam->mmio_base_phys = mem->start;
+ cam->mmio_size = (mem->end - mem->start) + 1;
+
+ /* map the region */
+ cam->mmio_base = (unsigned long)
+ ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
+ if (!cam->mmio_base) {
+ dev_err(cam->dev, "cannot map camera register I/O region\n");
+ goto err;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(cam->dev, "no irq for camera?\n");
+ goto err;
+ }
+
+ /* install the interrupt service routine */
+ if (request_irq(irq, omap24xxcam_isr, 0, CAM_NAME, cam)) {
+ dev_err(cam->dev,
+ "could not install interrupt service routine\n");
+ goto err;
+ }
+ cam->irq = irq;
+
+ if (omap24xxcam_clock_get(cam))
+ goto err;
+
+ INIT_WORK(&cam->sensor_reset_work, omap24xxcam_sensor_reset_work);
+
+ mutex_init(&cam->mutex);
+ spin_lock_init(&cam->core_enable_disable_lock);
+
+ omap24xxcam_sgdma_init(&cam->sgdma,
+ cam->mmio_base + CAMDMA_REG_OFFSET,
+ omap24xxcam_stalled_dma_reset,
+ (unsigned long)cam);
+
+ omap24xxcam.priv = cam;
+
+ if (v4l2_int_device_register(&omap24xxcam))
+ goto err;
+
+ return 0;
+
+err:
+ omap24xxcam_remove(pdev);
+ return -ENODEV;
+}
+
+static int omap24xxcam_remove(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ if (!cam)
+ return 0;
+
+ if (omap24xxcam.priv != NULL)
+ v4l2_int_device_unregister(&omap24xxcam);
+ omap24xxcam.priv = NULL;
+
+ omap24xxcam_clock_put(cam);
+
+ if (cam->irq) {
+ free_irq(cam->irq, cam);
+ cam->irq = 0;
+ }
+
+ if (cam->mmio_base) {
+ iounmap((void *)cam->mmio_base);
+ cam->mmio_base = 0;
+ }
+
+ if (cam->mmio_base_phys) {
+ release_mem_region(cam->mmio_base_phys, cam->mmio_size);
+ cam->mmio_base_phys = 0;
+ }
+
+ kfree(cam);
+
+ return 0;
+}
+
+static struct platform_driver omap24xxcam_driver = {
+ .probe = omap24xxcam_probe,
+ .remove = omap24xxcam_remove,
+#ifdef CONFIG_PM
+ .suspend = omap24xxcam_suspend,
+ .resume = omap24xxcam_resume,
+#endif
+ .driver = {
+ .name = CAM_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+/*
+ *
+ * Module initialisation and deinitialisation
+ *
+ */
+
+static int __init omap24xxcam_init(void)
+{
+ return platform_driver_register(&omap24xxcam_driver);
+}
+
+static void __exit omap24xxcam_cleanup(void)
+{
+ platform_driver_unregister(&omap24xxcam_driver);
+}
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,
+ "Minor number for video device (-1 ==> auto assign)");
+module_param(capture_mem, int, 0);
+MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture "
+ "buffers (default 4800kiB)");
+
+module_init(omap24xxcam_init);
+module_exit(omap24xxcam_cleanup);
diff --git a/linux/drivers/media/video/omap24xxcam.h b/linux/drivers/media/video/omap24xxcam.h
new file mode 100644
index 000000000..2ce67f5a4
--- /dev/null
+++ b/linux/drivers/media/video/omap24xxcam.h
@@ -0,0 +1,593 @@
+/*
+ * drivers/media/video/omap24xxcam.h
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP24XXCAM_H
+#define OMAP24XXCAM_H
+
+#include <media/videobuf-dma-sg.h>
+#include <media/v4l2-int-device.h>
+
+/*
+ *
+ * General driver related definitions.
+ *
+ */
+
+#define CAM_NAME "omap24xxcam"
+
+#define CAM_MCLK 96000000
+
+/* number of bytes transferred per DMA request */
+#define DMA_THRESHOLD 32
+
+/*
+ * NUM_CAMDMA_CHANNELS is the number of logical channels provided by
+ * the camera DMA controller.
+ */
+#define NUM_CAMDMA_CHANNELS 4
+
+/*
+ * NUM_SG_DMA is the number of scatter-gather DMA transfers that can
+ * be queued. (We don't have any overlay sglists now.)
+ */
+#define NUM_SG_DMA (VIDEO_MAX_FRAME)
+
+/*
+ *
+ * Register definitions.
+ *
+ */
+
+/* subsystem register block offsets */
+#define CC_REG_OFFSET 0x00000400
+#define CAMDMA_REG_OFFSET 0x00000800
+#define CAMMMU_REG_OFFSET 0x00000C00
+
+/* define camera subsystem register offsets */
+#define CAM_REVISION 0x000
+#define CAM_SYSCONFIG 0x010
+#define CAM_SYSSTATUS 0x014
+#define CAM_IRQSTATUS 0x018
+#define CAM_GPO 0x040
+#define CAM_GPI 0x050
+
+/* define camera core register offsets */
+#define CC_REVISION 0x000
+#define CC_SYSCONFIG 0x010
+#define CC_SYSSTATUS 0x014
+#define CC_IRQSTATUS 0x018
+#define CC_IRQENABLE 0x01C
+#define CC_CTRL 0x040
+#define CC_CTRL_DMA 0x044
+#define CC_CTRL_XCLK 0x048
+#define CC_FIFODATA 0x04C
+#define CC_TEST 0x050
+#define CC_GENPAR 0x054
+#define CC_CCPFSCR 0x058
+#define CC_CCPFECR 0x05C
+#define CC_CCPLSCR 0x060
+#define CC_CCPLECR 0x064
+#define CC_CCPDFR 0x068
+
+/* define camera dma register offsets */
+#define CAMDMA_REVISION 0x000
+#define CAMDMA_IRQSTATUS_L0 0x008
+#define CAMDMA_IRQSTATUS_L1 0x00C
+#define CAMDMA_IRQSTATUS_L2 0x010
+#define CAMDMA_IRQSTATUS_L3 0x014
+#define CAMDMA_IRQENABLE_L0 0x018
+#define CAMDMA_IRQENABLE_L1 0x01C
+#define CAMDMA_IRQENABLE_L2 0x020
+#define CAMDMA_IRQENABLE_L3 0x024
+#define CAMDMA_SYSSTATUS 0x028
+#define CAMDMA_OCP_SYSCONFIG 0x02C
+#define CAMDMA_CAPS_0 0x064
+#define CAMDMA_CAPS_2 0x06C
+#define CAMDMA_CAPS_3 0x070
+#define CAMDMA_CAPS_4 0x074
+#define CAMDMA_GCR 0x078
+#define CAMDMA_CCR(n) (0x080 + (n)*0x60)
+#define CAMDMA_CLNK_CTRL(n) (0x084 + (n)*0x60)
+#define CAMDMA_CICR(n) (0x088 + (n)*0x60)
+#define CAMDMA_CSR(n) (0x08C + (n)*0x60)
+#define CAMDMA_CSDP(n) (0x090 + (n)*0x60)
+#define CAMDMA_CEN(n) (0x094 + (n)*0x60)
+#define CAMDMA_CFN(n) (0x098 + (n)*0x60)
+#define CAMDMA_CSSA(n) (0x09C + (n)*0x60)
+#define CAMDMA_CDSA(n) (0x0A0 + (n)*0x60)
+#define CAMDMA_CSEI(n) (0x0A4 + (n)*0x60)
+#define CAMDMA_CSFI(n) (0x0A8 + (n)*0x60)
+#define CAMDMA_CDEI(n) (0x0AC + (n)*0x60)
+#define CAMDMA_CDFI(n) (0x0B0 + (n)*0x60)
+#define CAMDMA_CSAC(n) (0x0B4 + (n)*0x60)
+#define CAMDMA_CDAC(n) (0x0B8 + (n)*0x60)
+#define CAMDMA_CCEN(n) (0x0BC + (n)*0x60)
+#define CAMDMA_CCFN(n) (0x0C0 + (n)*0x60)
+#define CAMDMA_COLOR(n) (0x0C4 + (n)*0x60)
+
+/* define camera mmu register offsets */
+#define CAMMMU_REVISION 0x000
+#define CAMMMU_SYSCONFIG 0x010
+#define CAMMMU_SYSSTATUS 0x014
+#define CAMMMU_IRQSTATUS 0x018
+#define CAMMMU_IRQENABLE 0x01C
+#define CAMMMU_WALKING_ST 0x040
+#define CAMMMU_CNTL 0x044
+#define CAMMMU_FAULT_AD 0x048
+#define CAMMMU_TTB 0x04C
+#define CAMMMU_LOCK 0x050
+#define CAMMMU_LD_TLB 0x054
+#define CAMMMU_CAM 0x058
+#define CAMMMU_RAM 0x05C
+#define CAMMMU_GFLUSH 0x060
+#define CAMMMU_FLUSH_ENTRY 0x064
+#define CAMMMU_READ_CAM 0x068
+#define CAMMMU_READ_RAM 0x06C
+#define CAMMMU_EMU_FAULT_AD 0x070
+
+/* Define bit fields within selected registers */
+#define CAM_REVISION_MAJOR (15 << 4)
+#define CAM_REVISION_MAJOR_SHIFT 4
+#define CAM_REVISION_MINOR (15 << 0)
+#define CAM_REVISION_MINOR_SHIFT 0
+
+#define CAM_SYSCONFIG_SOFTRESET (1 << 1)
+#define CAM_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CAM_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CAM_IRQSTATUS_CC_IRQ (1 << 4)
+#define CAM_IRQSTATUS_MMU_IRQ (1 << 3)
+#define CAM_IRQSTATUS_DMA_IRQ2 (1 << 2)
+#define CAM_IRQSTATUS_DMA_IRQ1 (1 << 1)
+#define CAM_IRQSTATUS_DMA_IRQ0 (1 << 0)
+
+#define CAM_GPO_CAM_S_P_EN (1 << 1)
+#define CAM_GPO_CAM_CCP_MODE (1 << 0)
+
+#define CAM_GPI_CC_DMA_REQ1 (1 << 24)
+#define CAP_GPI_CC_DMA_REQ0 (1 << 23)
+#define CAP_GPI_CAM_MSTANDBY (1 << 21)
+#define CAP_GPI_CAM_WAIT (1 << 20)
+#define CAP_GPI_CAM_S_DATA (1 << 17)
+#define CAP_GPI_CAM_S_CLK (1 << 16)
+#define CAP_GPI_CAM_P_DATA (0xFFF << 3)
+#define CAP_GPI_CAM_P_DATA_SHIFT 3
+#define CAP_GPI_CAM_P_VS (1 << 2)
+#define CAP_GPI_CAM_P_HS (1 << 1)
+#define CAP_GPI_CAM_P_CLK (1 << 0)
+
+#define CC_REVISION_MAJOR (15 << 4)
+#define CC_REVISION_MAJOR_SHIFT 4
+#define CC_REVISION_MINOR (15 << 0)
+#define CC_REVISION_MINOR_SHIFT 0
+
+#define CC_SYSCONFIG_SIDLEMODE (3 << 3)
+#define CC_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
+#define CC_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
+#define CC_SYSCONFIG_SOFTRESET (1 << 1)
+#define CC_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CC_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CC_IRQSTATUS_FS_IRQ (1 << 19)
+#define CC_IRQSTATUS_LE_IRQ (1 << 18)
+#define CC_IRQSTATUS_LS_IRQ (1 << 17)
+#define CC_IRQSTATUS_FE_IRQ (1 << 16)
+#define CC_IRQSTATUS_FW_ERR_IRQ (1 << 10)
+#define CC_IRQSTATUS_FSC_ERR_IRQ (1 << 9)
+#define CC_IRQSTATUS_SSC_ERR_IRQ (1 << 8)
+#define CC_IRQSTATUS_FIFO_NOEMPTY_IRQ (1 << 4)
+#define CC_IRQSTATUS_FIFO_FULL_IRQ (1 << 3)
+#define CC_IRQSTATUS_FIFO_THR_IRQ (1 << 2)
+#define CC_IRQSTATUS_FIFO_OF_IRQ (1 << 1)
+#define CC_IRQSTATUS_FIFO_UF_IRQ (1 << 0)
+
+#define CC_IRQENABLE_FS_IRQ (1 << 19)
+#define CC_IRQENABLE_LE_IRQ (1 << 18)
+#define CC_IRQENABLE_LS_IRQ (1 << 17)
+#define CC_IRQENABLE_FE_IRQ (1 << 16)
+#define CC_IRQENABLE_FW_ERR_IRQ (1 << 10)
+#define CC_IRQENABLE_FSC_ERR_IRQ (1 << 9)
+#define CC_IRQENABLE_SSC_ERR_IRQ (1 << 8)
+#define CC_IRQENABLE_FIFO_NOEMPTY_IRQ (1 << 4)
+#define CC_IRQENABLE_FIFO_FULL_IRQ (1 << 3)
+#define CC_IRQENABLE_FIFO_THR_IRQ (1 << 2)
+#define CC_IRQENABLE_FIFO_OF_IRQ (1 << 1)
+#define CC_IRQENABLE_FIFO_UF_IRQ (1 << 0)
+
+#define CC_CTRL_CC_ONE_SHOT (1 << 20)
+#define CC_CTRL_CC_IF_SYNCHRO (1 << 19)
+#define CC_CTRL_CC_RST (1 << 18)
+#define CC_CTRL_CC_FRAME_TRIG (1 << 17)
+#define CC_CTRL_CC_EN (1 << 16)
+#define CC_CTRL_NOBT_SYNCHRO (1 << 13)
+#define CC_CTRL_BT_CORRECT (1 << 12)
+#define CC_CTRL_PAR_ORDERCAM (1 << 11)
+#define CC_CTRL_PAR_CLK_POL (1 << 10)
+#define CC_CTRL_NOBT_HS_POL (1 << 9)
+#define CC_CTRL_NOBT_VS_POL (1 << 8)
+#define CC_CTRL_PAR_MODE (7 << 1)
+#define CC_CTRL_PAR_MODE_SHIFT 1
+#define CC_CTRL_PAR_MODE_NOBT8 (0 << 1)
+#define CC_CTRL_PAR_MODE_NOBT10 (1 << 1)
+#define CC_CTRL_PAR_MODE_NOBT12 (2 << 1)
+#define CC_CTRL_PAR_MODE_BT8 (4 << 1)
+#define CC_CTRL_PAR_MODE_BT10 (5 << 1)
+#define CC_CTRL_PAR_MODE_FIFOTEST (7 << 1)
+#define CC_CTRL_CCP_MODE (1 << 0)
+
+#define CC_CTRL_DMA_EN (1 << 8)
+#define CC_CTRL_DMA_FIFO_THRESHOLD (0x7F << 0)
+#define CC_CTRL_DMA_FIFO_THRESHOLD_SHIFT 0
+
+#define CC_CTRL_XCLK_DIV (0x1F << 0)
+#define CC_CTRL_XCLK_DIV_SHIFT 0
+#define CC_CTRL_XCLK_DIV_STABLE_LOW (0 << 0)
+#define CC_CTRL_XCLK_DIV_STABLE_HIGH (1 << 0)
+#define CC_CTRL_XCLK_DIV_BYPASS (31 << 0)
+
+#define CC_TEST_FIFO_RD_POINTER (0xFF << 24)
+#define CC_TEST_FIFO_RD_POINTER_SHIFT 24
+#define CC_TEST_FIFO_WR_POINTER (0xFF << 16)
+#define CC_TEST_FIFO_WR_POINTER_SHIFT 16
+#define CC_TEST_FIFO_LEVEL (0xFF << 8)
+#define CC_TEST_FIFO_LEVEL_SHIFT 8
+#define CC_TEST_FIFO_LEVEL_PEAK (0xFF << 0)
+#define CC_TEST_FIFO_LEVEL_PEAK_SHIFT 0
+
+#define CC_GENPAR_FIFO_DEPTH (7 << 0)
+#define CC_GENPAR_FIFO_DEPTH_SHIFT 0
+
+#define CC_CCPDFR_ALPHA (0xFF << 8)
+#define CC_CCPDFR_ALPHA_SHIFT 8
+#define CC_CCPDFR_DATAFORMAT (15 << 0)
+#define CC_CCPDFR_DATAFORMAT_SHIFT 0
+#define CC_CCPDFR_DATAFORMAT_YUV422BE (0 << 0)
+#define CC_CCPDFR_DATAFORMAT_YUV422 (1 << 0)
+#define CC_CCPDFR_DATAFORMAT_YUV420 (2 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB444 (4 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB565 (5 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB888NDE (6 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB888 (7 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW8NDE (8 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW8 (9 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW10NDE (10 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW10 (11 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW12NDE (12 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW12 (13 << 0)
+#define CC_CCPDFR_DATAFORMAT_JPEG8 (15 << 0)
+
+#define CAMDMA_REVISION_MAJOR (15 << 4)
+#define CAMDMA_REVISION_MAJOR_SHIFT 4
+#define CAMDMA_REVISION_MINOR (15 << 0)
+#define CAMDMA_REVISION_MINOR_SHIFT 0
+
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE (3 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY (0 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY (1 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_SSTANDBY (2 << 12)
+#define CAMDMA_OCP_SYSCONFIG_FUNC_CLOCK (1 << 9)
+#define CAMDMA_OCP_SYSCONFIG_OCP_CLOCK (1 << 8)
+#define CAMDMA_OCP_SYSCONFIG_EMUFREE (1 << 5)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE (3 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_SIDLE (2 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SOFTRESET (1 << 1)
+#define CAMDMA_OCP_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CAMDMA_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CAMDMA_GCR_ARBITRATION_RATE (0xFF << 16)
+#define CAMDMA_GCR_ARBITRATION_RATE_SHIFT 16
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH (0xFF << 0)
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH_SHIFT 0
+
+#define CAMDMA_CCR_SEL_SRC_DST_SYNC (1 << 24)
+#define CAMDMA_CCR_PREFETCH (1 << 23)
+#define CAMDMA_CCR_SUPERVISOR (1 << 22)
+#define CAMDMA_CCR_SECURE (1 << 21)
+#define CAMDMA_CCR_BS (1 << 18)
+#define CAMDMA_CCR_TRANSPARENT_COPY_ENABLE (1 << 17)
+#define CAMDMA_CCR_CONSTANT_FILL_ENABLE (1 << 16)
+#define CAMDMA_CCR_DST_AMODE (3 << 14)
+#define CAMDMA_CCR_DST_AMODE_CONST_ADDR (0 << 14)
+#define CAMDMA_CCR_DST_AMODE_POST_INC (1 << 14)
+#define CAMDMA_CCR_DST_AMODE_SGL_IDX (2 << 14)
+#define CAMDMA_CCR_DST_AMODE_DBL_IDX (3 << 14)
+#define CAMDMA_CCR_SRC_AMODE (3 << 12)
+#define CAMDMA_CCR_SRC_AMODE_CONST_ADDR (0 << 12)
+#define CAMDMA_CCR_SRC_AMODE_POST_INC (1 << 12)
+#define CAMDMA_CCR_SRC_AMODE_SGL_IDX (2 << 12)
+#define CAMDMA_CCR_SRC_AMODE_DBL_IDX (3 << 12)
+#define CAMDMA_CCR_WR_ACTIVE (1 << 10)
+#define CAMDMA_CCR_RD_ACTIVE (1 << 9)
+#define CAMDMA_CCR_SUSPEND_SENSITIVE (1 << 8)
+#define CAMDMA_CCR_ENABLE (1 << 7)
+#define CAMDMA_CCR_PRIO (1 << 6)
+#define CAMDMA_CCR_FS (1 << 5)
+#define CAMDMA_CCR_SYNCHRO ((3 << 19) | (31 << 0))
+#define CAMDMA_CCR_SYNCHRO_CAMERA 0x01
+
+#define CAMDMA_CLNK_CTRL_ENABLE_LNK (1 << 15)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID (0x1F << 0)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID_SHIFT 0
+
+#define CAMDMA_CICR_MISALIGNED_ERR_IE (1 << 11)
+#define CAMDMA_CICR_SUPERVISOR_ERR_IE (1 << 10)
+#define CAMDMA_CICR_SECURE_ERR_IE (1 << 9)
+#define CAMDMA_CICR_TRANS_ERR_IE (1 << 8)
+#define CAMDMA_CICR_PACKET_IE (1 << 7)
+#define CAMDMA_CICR_BLOCK_IE (1 << 5)
+#define CAMDMA_CICR_LAST_IE (1 << 4)
+#define CAMDMA_CICR_FRAME_IE (1 << 3)
+#define CAMDMA_CICR_HALF_IE (1 << 2)
+#define CAMDMA_CICR_DROP_IE (1 << 1)
+
+#define CAMDMA_CSR_MISALIGNED_ERR (1 << 11)
+#define CAMDMA_CSR_SUPERVISOR_ERR (1 << 10)
+#define CAMDMA_CSR_SECURE_ERR (1 << 9)
+#define CAMDMA_CSR_TRANS_ERR (1 << 8)
+#define CAMDMA_CSR_PACKET (1 << 7)
+#define CAMDMA_CSR_SYNC (1 << 6)
+#define CAMDMA_CSR_BLOCK (1 << 5)
+#define CAMDMA_CSR_LAST (1 << 4)
+#define CAMDMA_CSR_FRAME (1 << 3)
+#define CAMDMA_CSR_HALF (1 << 2)
+#define CAMDMA_CSR_DROP (1 << 1)
+
+#define CAMDMA_CSDP_SRC_ENDIANNESS (1 << 21)
+#define CAMDMA_CSDP_SRC_ENDIANNESS_LOCK (1 << 20)
+#define CAMDMA_CSDP_DST_ENDIANNESS (1 << 19)
+#define CAMDMA_CSDP_DST_ENDIANNESS_LOCK (1 << 18)
+#define CAMDMA_CSDP_WRITE_MODE (3 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_WRNP (0 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED (1 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED_LAST_WRNP (2 << 16)
+#define CAMDMA_CSDP_DST_BURST_EN (3 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_1 (0 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_16 (1 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_32 (2 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_64 (3 << 14)
+#define CAMDMA_CSDP_DST_PACKED (1 << 13)
+#define CAMDMA_CSDP_WR_ADD_TRSLT (15 << 9)
+#define CAMDMA_CSDP_WR_ADD_TRSLT_ENABLE_MREQADD (3 << 9)
+#define CAMDMA_CSDP_SRC_BURST_EN (3 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_1 (0 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_16 (1 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_32 (2 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_64 (3 << 7)
+#define CAMDMA_CSDP_SRC_PACKED (1 << 6)
+#define CAMDMA_CSDP_RD_ADD_TRSLT (15 << 2)
+#define CAMDMA_CSDP_RD_ADD_TRSLT_ENABLE_MREQADD (3 << 2)
+#define CAMDMA_CSDP_DATA_TYPE (3 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_8BITS (0 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_16BITS (1 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_32BITS (2 << 0)
+
+#define CAMMMU_SYSCONFIG_AUTOIDLE (1 << 0)
+
+/*
+ *
+ * Declarations.
+ *
+ */
+
+/* forward declarations */
+struct omap24xxcam_sgdma;
+struct omap24xxcam_dma;
+
+typedef void (*sgdma_callback_t)(struct omap24xxcam_sgdma *cam,
+ u32 status, void *arg);
+typedef void (*dma_callback_t)(struct omap24xxcam_dma *cam,
+ u32 status, void *arg);
+
+struct channel_state {
+ dma_callback_t callback;
+ void *arg;
+};
+
+/* sgdma state for each of the possible videobuf_buffers + 2 overlays */
+struct sgdma_state {
+ const struct scatterlist *sglist;
+ int sglen; /* number of sglist entries */
+ int next_sglist; /* index of next sglist entry to process */
+ unsigned int bytes_read; /* number of bytes read */
+ unsigned int len; /* total length of sglist (excluding
+ * bytes due to page alignment) */
+ int queued_sglist; /* number of sglist entries queued for DMA */
+ u32 csr; /* DMA return code */
+ sgdma_callback_t callback;
+ void *arg;
+};
+
+/* physical DMA channel management */
+struct omap24xxcam_dma {
+ spinlock_t lock; /* Lock for the whole structure. */
+
+ unsigned long base; /* base address for dma controller */
+
+ /* While dma_stop!=0, an attempt to start a new DMA transfer will
+ * fail.
+ */
+ atomic_t dma_stop;
+ int free_dmach; /* number of dma channels free */
+ int next_dmach; /* index of next dma channel to use */
+ struct channel_state ch_state[NUM_CAMDMA_CHANNELS];
+};
+
+/* scatter-gather DMA (scatterlist stuff) management */
+struct omap24xxcam_sgdma {
+ struct omap24xxcam_dma dma;
+
+ spinlock_t lock; /* Lock for the fields below. */
+ int free_sgdma; /* number of free sg dma slots */
+ int next_sgdma; /* index of next sg dma slot to use */
+ struct sgdma_state sg_state[NUM_SG_DMA];
+
+ /* Reset timer data */
+ struct timer_list reset_timer;
+};
+
+/* per-device data structure */
+struct omap24xxcam_device {
+ /*** mutex ***/
+ /*
+ * mutex serialises access to this structure. Also camera
+ * opening and releasing is synchronised by this.
+ */
+ struct mutex mutex;
+
+ /*** general driver state information ***/
+ atomic_t users;
+ /*
+ * Lock to serialise core enabling and disabling and access to
+ * sgdma_in_queue.
+ */
+ spinlock_t core_enable_disable_lock;
+ /*
+ * Number or sgdma requests in scatter-gather queue, protected
+ * by the lock above.
+ */
+ int sgdma_in_queue;
+ /*
+ * Sensor interface parameters: interface type, CC_CTRL
+ * register value and interface specific data.
+ */
+ int if_type;
+ union {
+ struct parallel {
+ u32 xclk;
+ } bt656;
+ } if_u;
+ u32 cc_ctrl;
+
+ /*** subsystem structures ***/
+ struct omap24xxcam_sgdma sgdma;
+
+ /*** hardware resources ***/
+ unsigned int irq;
+ unsigned long mmio_base;
+ unsigned long mmio_base_phys;
+ unsigned long mmio_size;
+
+ /*** interfaces and device ***/
+ struct v4l2_int_device *sdev;
+ struct device *dev;
+ struct video_device *vfd;
+
+ /*** camera and sensor reset related stuff ***/
+ struct work_struct sensor_reset_work;
+ /*
+ * We're in the middle of a reset. Don't enable core if this
+ * is non-zero! This exists to help decisionmaking in a case
+ * where videobuf_qbuf is called while we are in the middle of
+ * a reset.
+ */
+ atomic_t in_reset;
+ /*
+ * Non-zero if we don't want any resets for now. Used to
+ * prevent reset work to run when we're about to stop
+ * streaming.
+ */
+ atomic_t reset_disable;
+
+ /*** video device parameters ***/
+ int capture_mem;
+
+ /*** camera module clocks ***/
+ struct clk *fck;
+ struct clk *ick;
+
+ /*** capture data ***/
+ /* file handle, if streaming is on */
+ struct file *streaming;
+};
+
+/* Per-file handle data. */
+struct omap24xxcam_fh {
+ spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+ struct videobuf_queue vbq;
+ struct v4l2_pix_format pix; /* serialise pix by vbq->lock */
+ atomic_t field_count; /* field counter for videobuf_buffer */
+ /* accessing cam here doesn't need serialisation: it's constant */
+ struct omap24xxcam_device *cam;
+};
+
+/*
+ *
+ * Register I/O functions.
+ *
+ */
+
+static inline u32 omap24xxcam_reg_in(unsigned long base, u32 offset)
+{
+ return readl(base + offset);
+}
+
+static inline u32 omap24xxcam_reg_out(unsigned long base, u32 offset,
+ u32 val)
+{
+ writel(val, base + offset);
+ return val;
+}
+
+static inline u32 omap24xxcam_reg_merge(unsigned long base, u32 offset,
+ u32 val, u32 mask)
+{
+ u32 addr = base + offset;
+ u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+ writel(new_val, addr);
+ return new_val;
+}
+
+/*
+ *
+ * Function prototypes.
+ *
+ */
+
+/* dma prototypes */
+
+void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma);
+void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma);
+
+/* sgdma prototypes */
+
+void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma);
+int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
+ const struct scatterlist *sglist, int sglen,
+ int len, sgdma_callback_t callback, void *arg);
+void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma);
+void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
+ unsigned long base,
+ void (*reset_callback)(unsigned long data),
+ unsigned long reset_callback_data);
+void omap24xxcam_sgdma_exit(struct omap24xxcam_sgdma *sgdma);
+
+#endif
diff --git a/linux/drivers/media/video/ov511.c b/linux/drivers/media/video/ov511.c
index ca3a89616..12d109eaa 100644
--- a/linux/drivers/media/video/ov511.c
+++ b/linux/drivers/media/video/ov511.c
@@ -3919,7 +3919,7 @@ ov51x_dealloc(struct usb_ov511 *ov)
***************************************************************************/
static int
-ov51x_v4l1_open(struct inode *inode, struct file *file)
+ov51x_v4l1_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct usb_ov511 *ov = video_get_drvdata(vdev);
@@ -3976,7 +3976,7 @@ out:
}
static int
-ov51x_v4l1_close(struct inode *inode, struct file *file)
+ov51x_v4l1_close(struct file *file)
{
struct video_device *vdev = file->private_data;
struct usb_ov511 *ov = video_get_drvdata(vdev);
@@ -4014,7 +4014,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
}
/* Do not call this function directly! */
-static int
+static long
ov51x_v4l1_ioctl_internal(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = file->private_data;
@@ -4453,8 +4453,8 @@ redo:
return 0;
}
-static int
-ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
+static long
+ov51x_v4l1_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct video_device *vdev = file->private_data;
@@ -4665,17 +4665,13 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-static const struct file_operations ov511_fops = {
+static const struct v4l2_file_operations ov511_fops = {
.owner = THIS_MODULE,
.open = ov51x_v4l1_open,
.release = ov51x_v4l1_close,
.read = ov51x_v4l1_read,
.mmap = ov51x_v4l1_mmap,
.ioctl = ov51x_v4l1_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static struct video_device vdev_template = {
diff --git a/linux/drivers/media/video/ov7670.c b/linux/drivers/media/video/ov7670.c
index 9cf1aa2bc..ef9d7c022 100644
--- a/linux/drivers/media/video/ov7670.c
+++ b/linux/drivers/media/video/ov7670.c
@@ -1354,7 +1354,7 @@ static int ov7670_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
switch (cmd) {
- case VIDIOC_G_CHIP_IDENT:
+ case VIDIOC_DBG_G_CHIP_IDENT:
return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0);
case VIDIOC_INT_RESET:
diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c
index 2ddc2ab70..ce389cacf 100644
--- a/linux/drivers/media/video/ov772x.c
+++ b/linux/drivers/media/video/ov772x.c
@@ -51,6 +51,7 @@
#define COM8 0x13 /* Common control 8 */
#define COM9 0x14 /* Common control 9 */
#define COM10 0x15 /* Common control 10 */
+#define REG16 0x16 /* Register 16 */
#define HSTART 0x17 /* Horizontal sensor size */
#define HSIZE 0x18 /* Horizontal frame (HREF column) end high 8-bit */
#define VSTART 0x19 /* Vertical frame (row) start high 8-bit */
@@ -65,6 +66,7 @@
#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */
#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */
#define VPT 0x26 /* AGC/AEC Fast mode operating region */
+#define REG28 0x28 /* Register 28 */
#define HOUTSIZE 0x29 /* Horizontal data output size MSBs */
#define EXHCH 0x2A /* Dummy pixel insert MSB */
#define EXHCL 0x2B /* Dummy pixel insert LSB */
@@ -94,6 +96,7 @@
#define TGT_R 0x43 /* BLC red channel target value */
#define TGT_GB 0x44 /* BLC Gb channel target value */
#define TGT_GR 0x45 /* BLC Gr channel target value */
+/* for ov7720 */
#define LCC0 0x46 /* Lens correction control 0 */
#define LCC1 0x47 /* Lens correction option 1 - X coordinate */
#define LCC2 0x48 /* Lens correction option 2 - Y coordinate */
@@ -101,6 +104,15 @@
#define LCC4 0x4A /* Lens correction option 4 - radius of the circular */
#define LCC5 0x4B /* Lens correction option 5 */
#define LCC6 0x4C /* Lens correction option 6 */
+/* for ov7725 */
+#define LC_CTR 0x46 /* Lens correction control */
+#define LC_XC 0x47 /* X coordinate of lens correction center relative */
+#define LC_YC 0x48 /* Y coordinate of lens correction center relative */
+#define LC_COEF 0x49 /* Lens correction coefficient */
+#define LC_RADI 0x4A /* Lens correction radius */
+#define LC_COEFB 0x4B /* Lens B channel compensation coefficient */
+#define LC_COEFR 0x4C /* Lens R channel compensation coefficient */
+
#define FIXGAIN 0x4D /* Analog fix gain amplifer */
#define AREF0 0x4E /* Sensor reference control */
#define AREF1 0x4F /* Sensor reference current control */
@@ -112,34 +124,34 @@
#define AREF7 0x55 /* Analog reference control */
#define UFIX 0x60 /* U channel fixed value output */
#define VFIX 0x61 /* V channel fixed value output */
-#define AW_BB_BLK 0x62 /* AWB option for advanced AWB */
-#define AW_B_CTRL0 0x63 /* AWB control byte 0 */
+#define AWBB_BLK 0x62 /* AWB option for advanced AWB */
+#define AWB_CTRL0 0x63 /* AWB control byte 0 */
#define DSP_CTRL1 0x64 /* DSP control byte 1 */
#define DSP_CTRL2 0x65 /* DSP control byte 2 */
#define DSP_CTRL3 0x66 /* DSP control byte 3 */
#define DSP_CTRL4 0x67 /* DSP control byte 4 */
-#define AW_B_BIAS 0x68 /* AWB BLC level clip */
-#define AW_BCTRL1 0x69 /* AWB control 1 */
-#define AW_BCTRL2 0x6A /* AWB control 2 */
-#define AW_BCTRL3 0x6B /* AWB control 3 */
-#define AW_BCTRL4 0x6C /* AWB control 4 */
-#define AW_BCTRL5 0x6D /* AWB control 5 */
-#define AW_BCTRL6 0x6E /* AWB control 6 */
-#define AW_BCTRL7 0x6F /* AWB control 7 */
-#define AW_BCTRL8 0x70 /* AWB control 8 */
-#define AW_BCTRL9 0x71 /* AWB control 9 */
-#define AW_BCTRL10 0x72 /* AWB control 10 */
-#define AW_BCTRL11 0x73 /* AWB control 11 */
-#define AW_BCTRL12 0x74 /* AWB control 12 */
-#define AW_BCTRL13 0x75 /* AWB control 13 */
-#define AW_BCTRL14 0x76 /* AWB control 14 */
-#define AW_BCTRL15 0x77 /* AWB control 15 */
-#define AW_BCTRL16 0x78 /* AWB control 16 */
-#define AW_BCTRL17 0x79 /* AWB control 17 */
-#define AW_BCTRL18 0x7A /* AWB control 18 */
-#define AW_BCTRL19 0x7B /* AWB control 19 */
-#define AW_BCTRL20 0x7C /* AWB control 20 */
-#define AW_BCTRL21 0x7D /* AWB control 21 */
+#define AWB_BIAS 0x68 /* AWB BLC level clip */
+#define AWB_CTRL1 0x69 /* AWB control 1 */
+#define AWB_CTRL2 0x6A /* AWB control 2 */
+#define AWB_CTRL3 0x6B /* AWB control 3 */
+#define AWB_CTRL4 0x6C /* AWB control 4 */
+#define AWB_CTRL5 0x6D /* AWB control 5 */
+#define AWB_CTRL6 0x6E /* AWB control 6 */
+#define AWB_CTRL7 0x6F /* AWB control 7 */
+#define AWB_CTRL8 0x70 /* AWB control 8 */
+#define AWB_CTRL9 0x71 /* AWB control 9 */
+#define AWB_CTRL10 0x72 /* AWB control 10 */
+#define AWB_CTRL11 0x73 /* AWB control 11 */
+#define AWB_CTRL12 0x74 /* AWB control 12 */
+#define AWB_CTRL13 0x75 /* AWB control 13 */
+#define AWB_CTRL14 0x76 /* AWB control 14 */
+#define AWB_CTRL15 0x77 /* AWB control 15 */
+#define AWB_CTRL16 0x78 /* AWB control 16 */
+#define AWB_CTRL17 0x79 /* AWB control 17 */
+#define AWB_CTRL18 0x7A /* AWB control 18 */
+#define AWB_CTRL19 0x7B /* AWB control 19 */
+#define AWB_CTRL20 0x7C /* AWB control 20 */
+#define AWB_CTRL21 0x7D /* AWB control 21 */
#define GAM1 0x7E /* Gamma Curve 1st segment input end point */
#define GAM2 0x7F /* Gamma Curve 2nd segment input end point */
#define GAM3 0x80 /* Gamma Curve 3rd segment input end point */
@@ -182,8 +194,13 @@
#define SDE 0xA6 /* Special digital effect control */
#define USAT 0xA7 /* U component saturation control */
#define VSAT 0xA8 /* V component saturation control */
+/* for ov7720 */
#define HUE0 0xA9 /* Hue control 0 */
#define HUE1 0xAA /* Hue control 1 */
+/* for ov7725 */
+#define HUECOS 0xA9 /* Cosine value */
+#define HUESIN 0xAA /* Sine value */
+
#define SIGN 0xAB /* Sign bit for Hue and contrast */
#define DSPAUTO 0xAC /* DSP auto function ON/OFF control */
@@ -346,6 +363,13 @@
#define OP_SWAP_RGB 0x00000002
/*
+ * ID
+ */
+#define OV7720 0x7720
+#define OV7725 0x7721
+#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF))
+
+/*
* struct
*/
struct regval_list {
@@ -374,34 +398,22 @@ struct ov772x_priv {
struct soc_camera_device icd;
const struct ov772x_color_format *fmt;
const struct ov772x_win_size *win;
+ int model;
};
#define ENDMARKER { 0xff, 0xff }
-static const struct regval_list ov772x_default_regs[] =
-{
- { COM3, 0x00 },
- { COM4, PLL_4x | 0x01 },
- { 0x16, 0x00 }, /* Mystery */
- { COM11, 0x10 }, /* Mystery */
- { 0x28, 0x00 }, /* Mystery */
- { HREF, 0x00 },
- { COM13, 0xe2 }, /* Mystery */
- { AREF0, 0xef },
- { AREF2, 0x60 },
- { AREF6, 0x7a },
- ENDMARKER,
-};
-
/*
* register setting for color format
*/
static const struct regval_list ov772x_RGB555_regs[] = {
+ { COM3, 0x00 },
{ COM7, FMT_RGB555 | OFMT_RGB },
ENDMARKER,
};
static const struct regval_list ov772x_RGB565_regs[] = {
+ { COM3, 0x00 },
{ COM7, FMT_RGB565 | OFMT_RGB },
ENDMARKER,
};
@@ -413,6 +425,7 @@ static const struct regval_list ov772x_YYUV_regs[] = {
};
static const struct regval_list ov772x_UVYY_regs[] = {
+ { COM3, 0x00 },
{ COM7, OFMT_YUV },
ENDMARKER,
};
@@ -593,12 +606,30 @@ static int ov772x_reset(struct i2c_client *client)
static int ov772x_init(struct soc_camera_device *icd)
{
- return 0;
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ int ret = 0;
+
+ if (priv->info->link.power) {
+ ret = priv->info->link.power(&priv->client->dev, 1);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (priv->info->link.reset)
+ ret = priv->info->link.reset(&priv->client->dev);
+
+ return ret;
}
static int ov772x_release(struct soc_camera_device *icd)
{
- return 0;
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ int ret = 0;
+
+ if (priv->info->link.power)
+ ret = priv->info->link.power(&priv->client->dev, 0);
+
+ return ret;
}
static int ov772x_start_capture(struct soc_camera_device *icd)
@@ -606,7 +637,6 @@ static int ov772x_start_capture(struct soc_camera_device *icd)
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
int ret;
-
if (!priv->win)
priv->win = &ov772x_win_vga;
if (!priv->fmt)
@@ -616,9 +646,6 @@ static int ov772x_start_capture(struct soc_camera_device *icd)
* reset hardware
*/
ov772x_reset(priv->client);
- ret = ov772x_write_array(priv->client, ov772x_default_regs);
- if (ret < 0)
- goto start_end;
/*
* set color format
@@ -662,7 +689,7 @@ static int ov772x_start_capture(struct soc_camera_device *icd)
goto start_end;
}
- dev_info(&icd->dev,
+ dev_dbg(&icd->dev,
"format %s, win %s\n", priv->fmt->name, priv->win->name);
start_end:
@@ -688,18 +715,20 @@ static int ov772x_set_bus_param(struct soc_camera_device *icd,
static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
{
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
-
- return SOCAM_PCLK_SAMPLE_RISING |
- SOCAM_HSYNC_ACTIVE_HIGH |
- SOCAM_VSYNC_ACTIVE_HIGH |
- SOCAM_MASTER |
+ struct soc_camera_link *icl = priv->client->dev.platform_data;
+ unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
priv->info->buswidth;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
}
static int ov772x_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_chip_ident *id)
+ struct v4l2_dbg_chip_ident *id)
{
- id->ident = V4L2_IDENT_OV772X;
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+
+ id->ident = priv->model;
id->revision = 0;
return 0;
@@ -707,11 +736,12 @@ static int ov772x_get_chip_id(struct soc_camera_device *icd,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int ov772x_get_register(struct soc_camera_device *icd,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
int ret;
+ reg->size = 1;
if (reg->reg > 0xff)
return -EINVAL;
@@ -725,7 +755,7 @@ static int ov772x_get_register(struct soc_camera_device *icd,
}
static int ov772x_set_register(struct soc_camera_device *icd,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
@@ -737,9 +767,30 @@ static int ov772x_set_register(struct soc_camera_device *icd,
}
#endif
-static int ov772x_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt,
- struct v4l2_rect *rect)
+static const struct ov772x_win_size*
+ov772x_select_win(u32 width, u32 height)
+{
+ __u32 diff;
+ const struct ov772x_win_size *win;
+
+ /* default is QVGA */
+ diff = abs(width - ov772x_win_qvga.width) +
+ abs(height - ov772x_win_qvga.height);
+ win = &ov772x_win_qvga;
+
+ /* VGA */
+ if (diff >
+ abs(width - ov772x_win_vga.width) +
+ abs(height - ov772x_win_vga.height))
+ win = &ov772x_win_vga;
+
+ return win;
+}
+
+
+static int ov772x_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt,
+ struct v4l2_rect *rect)
{
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
int ret = -EINVAL;
@@ -757,34 +808,28 @@ static int ov772x_set_fmt_cap(struct soc_camera_device *icd,
}
}
+ /*
+ * select win
+ */
+ priv->win = ov772x_select_win(rect->width, rect->height);
+
return ret;
}
-static int ov772x_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int ov772x_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
- struct v4l2_pix_format *pix = &f->fmt.pix;
- struct ov772x_priv *priv;
-
- priv = container_of(icd, struct ov772x_priv, icd);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ const struct ov772x_win_size *win;
- /* QVGA */
- if (pix->width <= ov772x_win_qvga.width ||
- pix->height <= ov772x_win_qvga.height) {
- priv->win = &ov772x_win_qvga;
- pix->width = ov772x_win_qvga.width;
- pix->height = ov772x_win_qvga.height;
- }
-
- /* VGA */
- else if (pix->width <= ov772x_win_vga.width ||
- pix->height <= ov772x_win_vga.height) {
- priv->win = &ov772x_win_vga;
- pix->width = ov772x_win_vga.width;
- pix->height = ov772x_win_vga.height;
- }
+ /*
+ * select suitable win
+ */
+ win = ov772x_select_win(pix->width, pix->height);
- pix->field = V4L2_FIELD_NONE;
+ pix->width = win->width;
+ pix->height = win->height;
+ pix->field = V4L2_FIELD_NONE;
return 0;
}
@@ -793,6 +838,7 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
{
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
u8 pid, ver;
+ const char *devname;
/*
* We must have a parent by now. And it cannot be a wrong one.
@@ -814,23 +860,30 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
icd->formats = ov772x_fmt_lists;
icd->num_formats = ARRAY_SIZE(ov772x_fmt_lists);
- if (priv->info->link.power)
- priv->info->link.power(&priv->client->dev, 1);
-
/*
* check and show product ID and manufacturer ID
*/
pid = i2c_smbus_read_byte_data(priv->client, PID);
ver = i2c_smbus_read_byte_data(priv->client, VER);
- if (pid != 0x77 ||
- ver != 0x21) {
- if (priv->info->link.power)
- priv->info->link.power(&priv->client->dev, 0);
+
+ switch (VERSION(pid, ver)) {
+ case OV7720:
+ devname = "ov7720";
+ priv->model = V4L2_IDENT_OV7720;
+ break;
+ case OV7725:
+ devname = "ov7725";
+ priv->model = V4L2_IDENT_OV7725;
+ break;
+ default:
+ dev_err(&icd->dev,
+ "Product ID error %x:%x\n", pid, ver);
return -ENODEV;
}
dev_info(&icd->dev,
- "ov772x Product ID %0x:%0x Manufacturer ID %x:%x\n",
+ "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+ devname,
pid,
ver,
i2c_smbus_read_byte_data(priv->client, MIDH),
@@ -842,13 +895,7 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
static void ov772x_video_remove(struct soc_camera_device *icd)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
-
soc_camera_video_stop(icd);
-
- if (priv->info->link.power)
- priv->info->link.power(&priv->client->dev, 0);
-
}
static struct soc_camera_ops ov772x_ops = {
@@ -859,8 +906,8 @@ static struct soc_camera_ops ov772x_ops = {
.release = ov772x_release,
.start_capture = ov772x_start_capture,
.stop_capture = ov772x_stop_capture,
- .set_fmt_cap = ov772x_set_fmt_cap,
- .try_fmt_cap = ov772x_try_fmt_cap,
+ .set_fmt = ov772x_set_fmt,
+ .try_fmt = ov772x_try_fmt,
.set_bus_param = ov772x_set_bus_param,
.query_bus_param = ov772x_query_bus_param,
.get_chip_id = ov772x_get_chip_id,
@@ -915,8 +962,10 @@ static int ov772x_probe(struct i2c_client *client,
ret = soc_camera_device_register(icd);
- if (ret)
+ if (ret) {
+ i2c_set_clientdata(client, NULL);
kfree(priv);
+ }
return ret;
}
@@ -926,13 +975,14 @@ static int ov772x_remove(struct i2c_client *client)
struct ov772x_priv *priv = i2c_get_clientdata(client);
soc_camera_device_unregister(&priv->icd);
+ i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
static const struct i2c_device_id ov772x_id[] = {
- {"ov772x", 0},
+ { "ov772x", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ov772x_id);
@@ -955,7 +1005,6 @@ static struct i2c_driver ov772x_i2c_driver = {
static int __init ov772x_module_init(void)
{
- printk(KERN_INFO "ov772x driver\n");
return i2c_add_driver(&ov772x_i2c_driver);
}
diff --git a/linux/drivers/media/video/pms.c b/linux/drivers/media/video/pms.c
index 522f75def..ca6404605 100644
--- a/linux/drivers/media/video/pms.c
+++ b/linux/drivers/media/video/pms.c
@@ -681,7 +681,7 @@ static int pms_capture(struct pms_device *dev, char __user *buf, int rgb555, int
* Video4linux interfacing
*/
-static int pms_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long pms_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *dev = video_devdata(file);
struct pms_device *pd=(struct pms_device *)dev;
@@ -863,7 +863,7 @@ static int pms_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0;
}
-static int pms_ioctl(struct inode *inode, struct file *file,
+static long pms_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, pms_do_ioctl);
@@ -882,7 +882,7 @@ static ssize_t pms_read(struct file *file, char __user *buf,
return len;
}
-static int pms_exclusive_open(struct inode *inode, struct file *file)
+static int pms_exclusive_open(struct file *file)
{
struct video_device *v = video_devdata(file);
struct pms_device *pd = (struct pms_device *)v;
@@ -890,7 +890,7 @@ static int pms_exclusive_open(struct inode *inode, struct file *file)
return test_and_set_bit(0, &pd->in_use) ? -EBUSY : 0;
}
-static int pms_exclusive_release(struct inode *inode, struct file *file)
+static int pms_exclusive_release(struct file *file)
{
struct video_device *v = video_devdata(file);
struct pms_device *pd = (struct pms_device *)v;
@@ -899,16 +899,12 @@ static int pms_exclusive_release(struct inode *inode, struct file *file)
return 0;
}
-static const struct file_operations pms_fops = {
+static const struct v4l2_file_operations pms_fops = {
.owner = THIS_MODULE,
.open = pms_exclusive_open,
.release = pms_exclusive_release,
.ioctl = pms_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
.read = pms_read,
- .llseek = no_llseek,
};
static struct video_device pms_template=
diff --git a/linux/drivers/media/video/pvrusb2/Kconfig b/linux/drivers/media/video/pvrusb2/Kconfig
index 19eb274c9..854c2a885 100644
--- a/linux/drivers/media/video/pvrusb2/Kconfig
+++ b/linux/drivers/media/video/pvrusb2/Kconfig
@@ -42,7 +42,7 @@ config VIDEO_PVRUSB2_DVB
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
---help---
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 447fcede8..21fdc66b4 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -4867,26 +4867,25 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
- u32 match_type, u32 match_chip, u64 reg_id,
- int setFl,u64 *val_ptr)
+ struct v4l2_dbg_match *match, u64 reg_id,
+ int setFl, u64 *val_ptr)
{
#ifdef CONFIG_VIDEO_ADV_DEBUG
struct pvr2_i2c_client *cp;
- struct v4l2_register req;
+ struct v4l2_dbg_register req;
int stat = 0;
int okFl = 0;
if (!capable(CAP_SYS_ADMIN)) return -EPERM;
- req.match_type = match_type;
- req.match_chip = match_chip;
+ req.match = *match;
req.reg = reg_id;
if (setFl) req.val = *val_ptr;
mutex_lock(&hdw->i2c_list_lock); do {
list_for_each_entry(cp, &hdw->i2c_clients, list) {
if (!v4l2_chip_match_i2c_client(
cp->client,
- req.match_type, req.match_chip)) {
+ &req.match)) {
continue;
}
stat = pvr2_i2c_client_cmd(
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 29fb0729d..732546fa3 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -248,8 +248,8 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,
setFl - true to set the register, false to read it
val_ptr - storage location for source / result. */
int pvr2_hdw_register_access(struct pvr2_hdw *,
- u32 match_type, u32 match_chip,u64 reg_id,
- int setFl,u64 *val_ptr);
+ struct v4l2_dbg_match *match, u64 reg_id,
+ int setFl, u64 *val_ptr);
/* The following entry points are all lower level things you normally don't
want to worry about. */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index edce8fc34..877c8f7b1 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -1013,6 +1013,9 @@ static int pvr2_i2c_detach_inform(struct i2c_client *client)
static struct i2c_algorithm pvr2_i2c_algo_template = {
.master_xfer = pvr2_i2c_xfer,
.functionality = pvr2_i2c_functionality,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static struct i2c_adapter pvr2_i2c_adap_template = {
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 09fabfd2f..7340f4815 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -169,13 +169,13 @@ static const char *get_v4l_name(int v4l_type)
* This is part of Video 4 Linux API. The procedure handles ioctl() calls.
*
*/
-static int pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct pvr2_v4l2_fh *fh = file->private_data;
struct pvr2_v4l2 *vp = fh->vhead;
struct pvr2_v4l2_dev *dev_info = fh->dev_info;
struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
- int ret = -EINVAL;
+ long ret = -EINVAL;
if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);
@@ -852,11 +852,11 @@ static int pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_DBG_G_REGISTER:
{
u64 val;
- struct v4l2_register *req = (struct v4l2_register *)arg;
+ struct v4l2_dbg_register *req = (struct v4l2_dbg_register *)arg;
if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
ret = pvr2_hdw_register_access(
- hdw,req->match_type,req->match_chip,req->reg,
- cmd == VIDIOC_DBG_S_REGISTER,&val);
+ hdw, &req->match, req->reg,
+ cmd == VIDIOC_DBG_S_REGISTER, &val);
if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
break;
}
@@ -872,20 +872,20 @@ static int pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (ret < 0) {
if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
pvr2_trace(PVR2_TRACE_V4LIOCTL,
- "pvr2_v4l2_do_ioctl failure, ret=%d",ret);
+ "pvr2_v4l2_do_ioctl failure, ret=%ld", ret);
} else {
if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
pvr2_trace(PVR2_TRACE_V4LIOCTL,
- "pvr2_v4l2_do_ioctl failure, ret=%d"
- " command was:",ret);
+ "pvr2_v4l2_do_ioctl failure, ret=%ld"
+ " command was:", ret);
v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
cmd);
}
}
} else {
pvr2_trace(PVR2_TRACE_V4LIOCTL,
- "pvr2_v4l2_do_ioctl complete, ret=%d (0x%x)",
- ret,ret);
+ "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)",
+ ret, ret);
}
return ret;
}
@@ -949,7 +949,7 @@ static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
}
-static int pvr2_v4l2_ioctl(struct inode *inode, struct file *file,
+static long pvr2_v4l2_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -961,7 +961,7 @@ static int pvr2_v4l2_ioctl(struct inode *inode, struct file *file,
}
-static int pvr2_v4l2_release(struct inode *inode, struct file *file)
+static int pvr2_v4l2_release(struct file *file)
{
struct pvr2_v4l2_fh *fhp = file->private_data;
struct pvr2_v4l2 *vp = fhp->vhead;
@@ -1009,7 +1009,7 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
}
-static int pvr2_v4l2_open(struct inode *inode, struct file *file)
+static int pvr2_v4l2_open(struct file *file)
{
struct pvr2_v4l2_dev *dip; /* Our own context pointer */
struct pvr2_v4l2_fh *fhp;
@@ -1236,13 +1236,12 @@ static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait)
}
-static const struct file_operations vdev_fops = {
+static const struct v4l2_file_operations vdev_fops = {
.owner = THIS_MODULE,
.open = pvr2_v4l2_open,
.release = pvr2_v4l2_release,
.read = pvr2_v4l2_read,
.ioctl = pvr2_v4l2_ioctl,
- .llseek = no_llseek,
.poll = pvr2_v4l2_poll,
};
diff --git a/linux/drivers/media/video/pwc/pwc-ctrl.c b/linux/drivers/media/video/pwc/pwc-ctrl.c
index c66530210..f9fbe02e0 100644
--- a/linux/drivers/media/video/pwc/pwc-ctrl.c
+++ b/linux/drivers/media/video/pwc/pwc-ctrl.c
@@ -1266,9 +1266,9 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
/* copy local variable to arg */
#define ARG_OUT(ARG_name) /* nothing */
-int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
+long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
- int ret = 0;
+ long ret = 0;
switch(cmd) {
case VIDIOCPWCRUSER:
diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c
index d657e6f8d..63c8ff8df 100644
--- a/linux/drivers/media/video/pwc/pwc-if.c
+++ b/linux/drivers/media/video/pwc/pwc-if.c
@@ -142,16 +142,16 @@ static struct {
/***/
-static int pwc_video_open(struct inode *inode, struct file *file);
-static int pwc_video_close(struct inode *inode, struct file *file);
+static int pwc_video_open(struct file *file);
+static int pwc_video_close(struct file *file);
static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
-static int pwc_video_ioctl(struct inode *inode, struct file *file,
+static long pwc_video_ioctl(struct file *file,
unsigned int ioctlnr, unsigned long arg);
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
-static const struct file_operations pwc_fops = {
+static const struct v4l2_file_operations pwc_fops = {
.owner = THIS_MODULE,
.open = pwc_video_open,
.release = pwc_video_close,
@@ -159,10 +159,6 @@ static const struct file_operations pwc_fops = {
.poll = pwc_video_poll,
.mmap = pwc_video_mmap,
.ioctl = pwc_video_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static struct video_device pwc_template = {
.name = "Philips Webcam", /* Filled in later */
@@ -1108,7 +1104,7 @@ static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
/***************************************************************************/
/* Video4Linux functions */
-static int pwc_video_open(struct inode *inode, struct file *file)
+static int pwc_video_open(struct file *file)
{
int i, ret;
struct video_device *vdev = video_devdata(file);
@@ -1228,7 +1224,7 @@ static void pwc_cleanup(struct pwc_device *pdev)
}
/* Note that all cleanup is done in the reverse order as in _open */
-static int pwc_video_close(struct inode *inode, struct file *file)
+static int pwc_video_close(struct file *file)
{
struct video_device *vdev = file->private_data;
struct pwc_device *pdev;
@@ -1403,12 +1399,12 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
return 0;
}
-static int pwc_video_ioctl(struct inode *inode, struct file *file,
+static long pwc_video_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct video_device *vdev = file->private_data;
struct pwc_device *pdev;
- int r = -ENODEV;
+ long r = -ENODEV;
if (!vdev)
goto out;
diff --git a/linux/drivers/media/video/pwc/pwc-v4l.c b/linux/drivers/media/video/pwc/pwc-v4l.c
index d7c147328..bc0a46429 100644
--- a/linux/drivers/media/video/pwc/pwc-v4l.c
+++ b/linux/drivers/media/video/pwc/pwc-v4l.c
@@ -337,7 +337,7 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
}
-int pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct pwc_device *pdev;
diff --git a/linux/drivers/media/video/pwc/pwc.h b/linux/drivers/media/video/pwc/pwc.h
index ade796037..a76971ead 100644
--- a/linux/drivers/media/video/pwc/pwc.h
+++ b/linux/drivers/media/video/pwc/pwc.h
@@ -338,10 +338,10 @@ extern int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise);
extern int pwc_camera_power(struct pwc_device *pdev, int power);
/* Private ioctl()s; see pwc-ioctl.h */
-extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
+extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
/** Functions in pwc-v4l.c */
-extern int pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg);
+extern long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg);
/** pwc-uncompress.c */
/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c
index 08723ed84..bb151032b 100644
--- a/linux/drivers/media/video/pxa_camera.c
+++ b/linux/drivers/media/video/pxa_camera.c
@@ -25,7 +25,6 @@
#include <linux/version.h>
#include <linux/device.h>
#include <linux/platform_device.h>
-#include <linux/mutex.h>
#include <linux/clk.h>
#include <media/v4l2-common.h>
@@ -47,6 +46,101 @@
#define PXA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
#define PXA_CAM_DRV_NAME "pxa27x-camera"
+/* Camera Interface */
+#define CICR0 0x0000
+#define CICR1 0x0004
+#define CICR2 0x0008
+#define CICR3 0x000C
+#define CICR4 0x0010
+#define CISR 0x0014
+#define CIFR 0x0018
+#define CITOR 0x001C
+#define CIBR0 0x0028
+#define CIBR1 0x0030
+#define CIBR2 0x0038
+
+#define CICR0_DMAEN (1 << 31) /* DMA request enable */
+#define CICR0_PAR_EN (1 << 30) /* Parity enable */
+#define CICR0_SL_CAP_EN (1 << 29) /* Capture enable for slave mode */
+#define CICR0_ENB (1 << 28) /* Camera interface enable */
+#define CICR0_DIS (1 << 27) /* Camera interface disable */
+#define CICR0_SIM (0x7 << 24) /* Sensor interface mode mask */
+#define CICR0_TOM (1 << 9) /* Time-out mask */
+#define CICR0_RDAVM (1 << 8) /* Receive-data-available mask */
+#define CICR0_FEM (1 << 7) /* FIFO-empty mask */
+#define CICR0_EOLM (1 << 6) /* End-of-line mask */
+#define CICR0_PERRM (1 << 5) /* Parity-error mask */
+#define CICR0_QDM (1 << 4) /* Quick-disable mask */
+#define CICR0_CDM (1 << 3) /* Disable-done mask */
+#define CICR0_SOFM (1 << 2) /* Start-of-frame mask */
+#define CICR0_EOFM (1 << 1) /* End-of-frame mask */
+#define CICR0_FOM (1 << 0) /* FIFO-overrun mask */
+
+#define CICR1_TBIT (1 << 31) /* Transparency bit */
+#define CICR1_RGBT_CONV (0x3 << 29) /* RGBT conversion mask */
+#define CICR1_PPL (0x7ff << 15) /* Pixels per line mask */
+#define CICR1_RGB_CONV (0x7 << 12) /* RGB conversion mask */
+#define CICR1_RGB_F (1 << 11) /* RGB format */
+#define CICR1_YCBCR_F (1 << 10) /* YCbCr format */
+#define CICR1_RGB_BPP (0x7 << 7) /* RGB bis per pixel mask */
+#define CICR1_RAW_BPP (0x3 << 5) /* Raw bis per pixel mask */
+#define CICR1_COLOR_SP (0x3 << 3) /* Color space mask */
+#define CICR1_DW (0x7 << 0) /* Data width mask */
+
+#define CICR2_BLW (0xff << 24) /* Beginning-of-line pixel clock
+ wait count mask */
+#define CICR2_ELW (0xff << 16) /* End-of-line pixel clock
+ wait count mask */
+#define CICR2_HSW (0x3f << 10) /* Horizontal sync pulse width mask */
+#define CICR2_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock
+ wait count mask */
+#define CICR2_FSW (0x7 << 0) /* Frame stabilization
+ wait count mask */
+
+#define CICR3_BFW (0xff << 24) /* Beginning-of-frame line clock
+ wait count mask */
+#define CICR3_EFW (0xff << 16) /* End-of-frame line clock
+ wait count mask */
+#define CICR3_VSW (0x3f << 10) /* Vertical sync pulse width mask */
+#define CICR3_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock
+ wait count mask */
+#define CICR3_LPF (0x7ff << 0) /* Lines per frame mask */
+
+#define CICR4_MCLK_DLY (0x3 << 24) /* MCLK Data Capture Delay mask */
+#define CICR4_PCLK_EN (1 << 23) /* Pixel clock enable */
+#define CICR4_PCP (1 << 22) /* Pixel clock polarity */
+#define CICR4_HSP (1 << 21) /* Horizontal sync polarity */
+#define CICR4_VSP (1 << 20) /* Vertical sync polarity */
+#define CICR4_MCLK_EN (1 << 19) /* MCLK enable */
+#define CICR4_FR_RATE (0x7 << 8) /* Frame rate mask */
+#define CICR4_DIV (0xff << 0) /* Clock divisor mask */
+
+#define CISR_FTO (1 << 15) /* FIFO time-out */
+#define CISR_RDAV_2 (1 << 14) /* Channel 2 receive data available */
+#define CISR_RDAV_1 (1 << 13) /* Channel 1 receive data available */
+#define CISR_RDAV_0 (1 << 12) /* Channel 0 receive data available */
+#define CISR_FEMPTY_2 (1 << 11) /* Channel 2 FIFO empty */
+#define CISR_FEMPTY_1 (1 << 10) /* Channel 1 FIFO empty */
+#define CISR_FEMPTY_0 (1 << 9) /* Channel 0 FIFO empty */
+#define CISR_EOL (1 << 8) /* End of line */
+#define CISR_PAR_ERR (1 << 7) /* Parity error */
+#define CISR_CQD (1 << 6) /* Camera interface quick disable */
+#define CISR_CDD (1 << 5) /* Camera interface disable done */
+#define CISR_SOF (1 << 4) /* Start of frame */
+#define CISR_EOF (1 << 3) /* End of frame */
+#define CISR_IFO_2 (1 << 2) /* FIFO overrun for Channel 2 */
+#define CISR_IFO_1 (1 << 1) /* FIFO overrun for Channel 1 */
+#define CISR_IFO_0 (1 << 0) /* FIFO overrun for Channel 0 */
+
+#define CIFR_FLVL2 (0x7f << 23) /* FIFO 2 level mask */
+#define CIFR_FLVL1 (0x7f << 16) /* FIFO 1 level mask */
+#define CIFR_FLVL0 (0xff << 8) /* FIFO 0 level mask */
+#define CIFR_THL_0 (0x3 << 4) /* Threshold Level for Channel 0 FIFO */
+#define CIFR_RESET_F (1 << 3) /* Reset input FIFOs */
+#define CIFR_FEN2 (1 << 2) /* FIFO enable for channel 2 */
+#define CIFR_FEN1 (1 << 1) /* FIFO enable for channel 1 */
+#define CIFR_FEN0 (1 << 0) /* FIFO enable for channel 0 */
+
#define CICR0_SIM_MP (0 << 24)
#define CICR0_SIM_SP (1 << 24)
#define CICR0_SIM_MS (2 << 24)
@@ -74,8 +168,6 @@
CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \
CICR0_EOFM | CICR0_FOM)
-static DEFINE_MUTEX(camera_lock);
-
/*
* Structures
*/
@@ -125,7 +217,9 @@ struct pxa_camera_dev {
struct pxacamera_platform_data *pdata;
struct resource *res;
unsigned long platform_flags;
- unsigned long platform_mclk_10khz;
+ unsigned long ciclk;
+ unsigned long mclk;
+ u32 mclk_divisor;
struct list_head capture;
@@ -148,8 +242,7 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
struct soc_camera_device *icd = vq->priv_data;
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
@@ -175,8 +268,7 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
{
struct soc_camera_device *icd = vq->priv_data;
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
int i;
@@ -252,8 +344,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
struct videobuf_buffer *vb, enum v4l2_field field)
{
struct soc_camera_device *icd = vq->priv_data;
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
int ret;
@@ -372,8 +463,7 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
struct videobuf_buffer *vb)
{
struct soc_camera_device *icd = vq->priv_data;
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
struct pxa_buffer *active;
@@ -390,7 +480,10 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
active = pcdev->active;
if (!active) {
- CIFR |= CIFR_RESET_F;
+ unsigned long cifr, cicr0;
+
+ cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
+ __raw_writel(cifr, pcdev->base + CIFR);
for (i = 0; i < pcdev->channels; i++) {
DDADR(pcdev->dma_chans[i]) = buf->dmas[i].sg_dma;
@@ -399,7 +492,9 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
}
pcdev->active = buf;
- CICR0 |= CICR0_ENB;
+
+ cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB;
+ __raw_writel(cicr0, pcdev->base + CICR0);
} else {
struct pxa_cam_dma *buf_dma;
struct pxa_cam_dma *act_dma;
@@ -483,6 +578,8 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
struct videobuf_buffer *vb,
struct pxa_buffer *buf)
{
+ unsigned long cicr0;
+
/* _init is used to debug races, see comment in pxa_camera_reqbufs() */
list_del_init(&vb->queue);
vb->state = VIDEOBUF_DONE;
@@ -495,7 +592,9 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
DCSR(pcdev->dma_chans[0]) = 0;
DCSR(pcdev->dma_chans[1]) = 0;
DCSR(pcdev->dma_chans[2]) = 0;
- CICR0 &= ~CICR0_ENB;
+
+ cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB;
+ __raw_writel(cicr0, pcdev->base + CICR0);
return;
}
@@ -510,6 +609,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
unsigned long flags;
u32 status, camera_status, overrun;
struct videobuf_buffer *vb;
+ unsigned long cifr, cicr0;
spin_lock_irqsave(&pcdev->lock, flags);
@@ -532,22 +632,26 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
goto out;
}
- camera_status = CISR;
+ camera_status = __raw_readl(pcdev->base + CISR);
overrun = CISR_IFO_0;
if (pcdev->channels == 3)
overrun |= CISR_IFO_1 | CISR_IFO_2;
if (camera_status & overrun) {
dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", camera_status);
/* Stop the Capture Interface */
- CICR0 &= ~CICR0_ENB;
+ cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB;
+ __raw_writel(cicr0, pcdev->base + CICR0);
+
/* Stop DMA */
DCSR(channel) = 0;
/* Reset the FIFOs */
- CIFR |= CIFR_RESET_F;
+ cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
+ __raw_writel(cifr, pcdev->base + CIFR);
/* Enable End-Of-Frame Interrupt */
- CICR0 &= ~CICR0_EOFM;
+ cicr0 &= ~CICR0_EOFM;
+ __raw_writel(cicr0, pcdev->base + CICR0);
/* Restart the Capture Interface */
- CICR0 |= CICR0_ENB;
+ __raw_writel(cicr0 | CICR0_ENB, pcdev->base + CICR0);
goto out;
}
@@ -603,24 +707,43 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q,
sizeof(struct pxa_buffer), icd);
}
-static int mclk_get_divisor(struct pxa_camera_dev *pcdev)
+static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
{
- unsigned int mclk_10khz = pcdev->platform_mclk_10khz;
- unsigned long div;
+ unsigned long mclk = pcdev->mclk;
+ u32 div;
unsigned long lcdclk;
- lcdclk = clk_get_rate(pcdev->clk) / 10000;
+ lcdclk = clk_get_rate(pcdev->clk);
+ pcdev->ciclk = lcdclk;
+
+ /* mclk <= ciclk / 4 (27.4.2) */
+ if (mclk > lcdclk / 4) {
+ mclk = lcdclk / 4;
+ dev_warn(pcdev->dev, "Limiting master clock to %lu\n", mclk);
+ }
+
+ /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */
+ div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
- /* We verify platform_mclk_10khz != 0, so if anyone breaks it, here
- * they get a nice Oops */
- div = (lcdclk + 2 * mclk_10khz - 1) / (2 * mclk_10khz) - 1;
+ /* If we're not supplying MCLK, leave it at 0 */
+ if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+ pcdev->mclk = lcdclk / (2 * (div + 1));
- dev_dbg(pcdev->dev, "LCD clock %lukHz, target freq %dkHz, "
- "divisor %lu\n", lcdclk * 10, mclk_10khz * 10, div);
+ dev_dbg(pcdev->dev, "LCD clock %luHz, target freq %luHz, "
+ "divisor %u\n", lcdclk, mclk, div);
return div;
}
+static void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev,
+ unsigned long pclk)
+{
+ /* We want a timeout > 1 pixel time, not ">=" */
+ u32 ciclk_per_pixel = pcdev->ciclk / pclk + 1;
+
+ __raw_writel(ciclk_per_pixel, pcdev->base + CITOR);
+}
+
static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
{
struct pxacamera_platform_data *pdata = pcdev->pdata;
@@ -634,7 +757,8 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
pdata->init(pcdev->dev);
}
- CICR0 = 0x3FF; /* disable all interrupts */
+ /* disable all interrupts */
+ __raw_writel(0x3ff, pcdev->base + CICR0);
if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
cicr4 |= CICR4_PCLK_EN;
@@ -647,7 +771,14 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
if (pcdev->platform_flags & PXA_CAMERA_VSP)
cicr4 |= CICR4_VSP;
- CICR4 = mclk_get_divisor(pcdev) | cicr4;
+ __raw_writel(pcdev->mclk_divisor | cicr4, pcdev->base + CICR4);
+
+ if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+ /* Initialise the timeout under the assumption pclk = mclk */
+ recalculate_fifo_timeout(pcdev, pcdev->mclk);
+ else
+ /* "Safe default" - 13MHz */
+ recalculate_fifo_timeout(pcdev, 13000000);
clk_enable(pcdev->clk);
}
@@ -660,14 +791,15 @@ static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
static irqreturn_t pxa_camera_irq(int irq, void *data)
{
struct pxa_camera_dev *pcdev = data;
- unsigned int status = CISR;
+ unsigned long status, cicr0;
- dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status);
+ status = __raw_readl(pcdev->base + CISR);
+ dev_dbg(pcdev->dev, "Camera interrupt status 0x%lx\n", status);
if (!status)
return IRQ_NONE;
- CISR = status;
+ __raw_writel(status, pcdev->base + CISR);
if (status & CISR_EOF) {
int i;
@@ -676,22 +808,24 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
pcdev->active->dmas[i].sg_dma;
DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
}
- CICR0 |= CICR0_EOFM;
+ cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM;
+ __raw_writel(cicr0, pcdev->base + CICR0);
}
return IRQ_HANDLED;
}
-/* The following two functions absolutely depend on the fact, that
- * there can be only one camera on PXA quick capture interface */
+/*
+ * The following two functions absolutely depend on the fact, that
+ * there can be only one camera on PXA quick capture interface
+ * Called with .video_lock held
+ */
static int pxa_camera_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
int ret;
- mutex_lock(&camera_lock);
-
if (pcdev->icd) {
ret = -EBUSY;
goto ebusy;
@@ -707,11 +841,10 @@ static int pxa_camera_add_device(struct soc_camera_device *icd)
pcdev->icd = icd;
ebusy:
- mutex_unlock(&camera_lock);
-
return ret;
}
+/* Called with .video_lock held */
static void pxa_camera_remove_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
@@ -723,7 +856,7 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
icd->devnum);
/* disable capture, disable interrupts */
- CICR0 = 0x3ff;
+ __raw_writel(0x3ff, pcdev->base + CICR0);
/* Stop DMA engine */
DCSR(pcdev->dma_chans[0]) = 0;
@@ -770,6 +903,9 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8))
return -EINVAL;
*flags |= SOCAM_DATAWIDTH_8;
+ break;
+ default:
+ return -EINVAL;
}
return 0;
@@ -777,11 +913,10 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
{
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
unsigned long dw, bpp, bus_flags, camera_flags, common_flags;
- u32 cicr0, cicr1, cicr4 = 0;
+ u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0;
int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
if (ret < 0)
@@ -828,12 +963,10 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
* We fix bit-per-pixel equal to data-width... */
switch (common_flags & SOCAM_DATAWIDTH_MASK) {
case SOCAM_DATAWIDTH_10:
- icd->buswidth = 10;
dw = 4;
bpp = 0x40;
break;
case SOCAM_DATAWIDTH_9:
- icd->buswidth = 9;
dw = 3;
bpp = 0x20;
break;
@@ -841,7 +974,6 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
/* Actually it can only be 8 now,
* default is just to silence compiler warnings */
case SOCAM_DATAWIDTH_8:
- icd->buswidth = 8;
dw = 2;
bpp = 0;
}
@@ -857,9 +989,9 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
cicr4 |= CICR4_VSP;
- cicr0 = CICR0;
+ cicr0 = __raw_readl(pcdev->base + CICR0);
if (cicr0 & CICR0_ENB)
- CICR0 = cicr0 & ~CICR0_ENB;
+ __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0);
cicr1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw;
@@ -867,7 +999,17 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
case V4L2_PIX_FMT_YUV422P:
pcdev->channels = 3;
cicr1 |= CICR1_YCBCR_F;
+ /*
+ * Normally, pxa bus wants as input UYVY format. We allow all
+ * reorderings of the YUV422 format, as no processing is done,
+ * and the YUV stream is just passed through without any
+ * transformation. Note that UYVY is the only format that
+ * should be used if pxa framebuffer Overlay2 is used.
+ */
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
cicr1 |= CICR1_COLOR_SP_VAL(2);
break;
case V4L2_PIX_FMT_RGB555:
@@ -879,27 +1021,32 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
break;
}
- CICR1 = cicr1;
- CICR2 = 0;
- CICR3 = CICR3_LPF_VAL(icd->height - 1) |
+ cicr2 = 0;
+ cicr3 = CICR3_LPF_VAL(icd->height - 1) |
CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
- CICR4 = mclk_get_divisor(pcdev) | cicr4;
+ cicr4 |= pcdev->mclk_divisor;
+
+ __raw_writel(cicr1, pcdev->base + CICR1);
+ __raw_writel(cicr2, pcdev->base + CICR2);
+ __raw_writel(cicr3, pcdev->base + CICR3);
+ __raw_writel(cicr4, pcdev->base + CICR4);
/* CIF interrupts are not used, only DMA */
- CICR0 = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
- CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP)) |
- CICR0_DMAEN | CICR0_IRQ_MASK | (cicr0 & CICR0_ENB);
+ cicr0 = (cicr0 & CICR0_ENB) | (pcdev->platform_flags & PXA_CAMERA_MASTER ?
+ CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP));
+ cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK;
+ __raw_writel(cicr0, pcdev->base + CICR0);
return 0;
}
-static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static int pxa_camera_try_bus_param(struct soc_camera_device *icd,
+ unsigned char buswidth)
{
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
unsigned long bus_flags, camera_flags;
- int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
+ int ret = test_platform_param(pcdev, buswidth, &bus_flags);
if (ret < 0)
return ret;
@@ -909,28 +1056,210 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL;
}
-static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static const struct soc_camera_data_format pxa_camera_formats[] = {
+ {
+ .name = "Planar YUV422 16 bit",
+ .depth = 16,
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+};
+
+static bool buswidth_supported(struct soc_camera_device *icd, int depth)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+
+ switch (depth) {
+ case 8:
+ return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8);
+ case 9:
+ return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9);
+ case 10:
+ return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10);
+ }
+ return false;
+}
+
+static int required_buswidth(const struct soc_camera_data_format *fmt)
{
- return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+ switch (fmt->fourcc) {
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB555:
+ return 8;
+ default:
+ return fmt->depth;
+ }
}
-static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
+ struct soc_camera_format_xlate *xlate)
{
- /* limit to pxa hardware capabilities */
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.height > 2048)
- f->fmt.pix.height = 2048;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > 2048)
- f->fmt.pix.width = 2048;
- f->fmt.pix.width &= ~0x01;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int formats = 0, buswidth, ret;
+
+ buswidth = required_buswidth(icd->formats + idx);
+
+ if (!buswidth_supported(icd, buswidth))
+ return 0;
+
+ ret = pxa_camera_try_bus_param(icd, buswidth);
+ if (ret < 0)
+ return 0;
+
+ switch (icd->formats[idx].fourcc) {
+ case V4L2_PIX_FMT_UYVY:
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = &pxa_camera_formats[0];
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = buswidth;
+ xlate++;
+ dev_dbg(&ici->dev, "Providing format %s using %s\n",
+ pxa_camera_formats[0].name,
+ icd->formats[idx].name);
+ }
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB555:
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = icd->formats + idx;
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = buswidth;
+ xlate++;
+ dev_dbg(&ici->dev, "Providing format %s packed\n",
+ icd->formats[idx].name);
+ }
+ break;
+ default:
+ /* Generic pass-through */
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = icd->formats + idx;
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = icd->formats[idx].depth;
+ xlate++;
+ dev_dbg(&ici->dev,
+ "Providing format %s in pass-through mode\n",
+ icd->formats[idx].name);
+ }
+ }
+
+ return formats;
+}
+
+static int pxa_camera_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+ const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL;
+ const struct soc_camera_format_xlate *xlate;
+ struct soc_camera_sense sense = {
+ .master_clock = pcdev->mclk,
+ .pixel_clock_max = pcdev->ciclk / 4,
+ };
+ int ret, buswidth;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ buswidth = xlate->buswidth;
+ host_fmt = xlate->host_fmt;
+ cam_fmt = xlate->cam_fmt;
+
+ /* If PCLK is used to latch data from the sensor, check sense */
+ if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+ icd->sense = &sense;
+
+ switch (pixfmt) {
+ case 0: /* Only geometry change */
+ ret = icd->ops->set_fmt(icd, pixfmt, rect);
+ break;
+ default:
+ ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect);
+ }
+
+ icd->sense = NULL;
+
+ if (ret < 0) {
+ dev_warn(&ici->dev, "Failed to configure for format %x\n",
+ pixfmt);
+ } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
+ if (sense.pixel_clock > sense.pixel_clock_max) {
+ dev_err(&ici->dev,
+ "pixel clock %lu set by the camera too high!",
+ sense.pixel_clock);
+ return -EIO;
+ }
+ recalculate_fifo_timeout(pcdev, sense.pixel_clock);
+ }
+ if (pixfmt && !ret) {
+ icd->buswidth = buswidth;
+ icd->current_fmt = host_fmt;
+ }
+
+ return ret;
+}
+
+static int pxa_camera_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ const struct soc_camera_format_xlate *xlate;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ __u32 pixfmt = pix->pixelformat;
+ enum v4l2_field field;
+ int ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ /* limit to pxa hardware capabilities */
+ if (pix->height < 32)
+ pix->height = 32;
+ if (pix->height > 2048)
+ pix->height = 2048;
+ if (pix->width < 48)
+ pix->width = 48;
+ if (pix->width > 2048)
+ pix->width = 2048;
+ pix->width &= ~0x01;
+
+ pix->bytesperline = pix->width *
+ DIV_ROUND_UP(xlate->host_fmt->depth, 8);
+ pix->sizeimage = pix->height * pix->bytesperline;
+
+ /* camera has to see its format, but the user the original one */
+ pix->pixelformat = xlate->cam_fmt->fourcc;
/* limit to sensor capabilities */
- return icd->ops->try_fmt_cap(icd, f);
+ ret = icd->ops->try_fmt(icd, f);
+ pix->pixelformat = xlate->host_fmt->fourcc;
+
+ field = pix->field;
+
+ if (field == V4L2_FIELD_ANY) {
+ pix->field = V4L2_FIELD_NONE;
+ } else if (field != V4L2_FIELD_NONE) {
+ dev_err(&icd->dev, "Field type %d unsupported.\n", field);
+ return -EINVAL;
+ }
+
+ return ret;
}
static int pxa_camera_reqbufs(struct soc_camera_file *icf,
@@ -982,16 +1311,15 @@ static int pxa_camera_querycap(struct soc_camera_host *ici,
static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state)
{
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
int i = 0, ret = 0;
- pcdev->save_cicr[i++] = CICR0;
- pcdev->save_cicr[i++] = CICR1;
- pcdev->save_cicr[i++] = CICR2;
- pcdev->save_cicr[i++] = CICR3;
- pcdev->save_cicr[i++] = CICR4;
+ pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR0);
+ pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR1);
+ pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR2);
+ pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3);
+ pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4);
if ((pcdev->icd) && (pcdev->icd->ops->suspend))
ret = pcdev->icd->ops->suspend(pcdev->icd, state);
@@ -1001,8 +1329,7 @@ static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state)
static int pxa_camera_resume(struct soc_camera_device *icd)
{
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
int i = 0, ret = 0;
@@ -1010,23 +1337,27 @@ static int pxa_camera_resume(struct soc_camera_device *icd)
DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD;
- CICR0 = pcdev->save_cicr[i++] & ~CICR0_ENB;
- CICR1 = pcdev->save_cicr[i++];
- CICR2 = pcdev->save_cicr[i++];
- CICR3 = pcdev->save_cicr[i++];
- CICR4 = pcdev->save_cicr[i++];
+ __raw_writel(pcdev->save_cicr[i++] & ~CICR0_ENB, pcdev->base + CICR0);
+ __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR1);
+ __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR2);
+ __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3);
+ __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4);
if ((pcdev->icd) && (pcdev->icd->ops->resume))
ret = pcdev->icd->ops->resume(pcdev->icd);
/* Restart frame capture if active buffer exists */
if (!ret && pcdev->active) {
+ unsigned long cifr, cicr0;
+
/* Reset the FIFOs */
- CIFR |= CIFR_RESET_F;
- /* Enable End-Of-Frame Interrupt */
- CICR0 &= ~CICR0_EOFM;
- /* Restart the Capture Interface */
- CICR0 |= CICR0_ENB;
+ cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
+ __raw_writel(cifr, pcdev->base + CIFR);
+
+ cicr0 = __raw_readl(pcdev->base + CICR0);
+ cicr0 &= ~CICR0_EOFM; /* Enable End-Of-Frame Interrupt */
+ cicr0 |= CICR0_ENB; /* Restart the Capture Interface */
+ __raw_writel(cicr0, pcdev->base + CICR0);
}
return ret;
@@ -1038,13 +1369,13 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.remove = pxa_camera_remove_device,
.suspend = pxa_camera_suspend,
.resume = pxa_camera_resume,
- .set_fmt_cap = pxa_camera_set_fmt_cap,
- .try_fmt_cap = pxa_camera_try_fmt_cap,
+ .get_formats = pxa_camera_get_formats,
+ .set_fmt = pxa_camera_set_fmt,
+ .try_fmt = pxa_camera_try_fmt,
.init_videobuf = pxa_camera_init_videobuf,
.reqbufs = pxa_camera_reqbufs,
.poll = pxa_camera_poll,
.querycap = pxa_camera_querycap,
- .try_bus_param = pxa_camera_try_bus_param,
.set_bus_param = pxa_camera_set_bus_param,
};
@@ -1095,14 +1426,17 @@ static int pxa_camera_probe(struct platform_device *pdev)
"data widths, using default 10 bit\n");
pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10;
}
- pcdev->platform_mclk_10khz = pcdev->pdata->mclk_10khz;
- if (!pcdev->platform_mclk_10khz) {
+ pcdev->mclk = pcdev->pdata->mclk_10khz * 10000;
+ if (!pcdev->mclk) {
dev_warn(&pdev->dev,
- "mclk_10khz == 0! Please, fix your platform data. "
+ "mclk == 0! Please, fix your platform data. "
"Using default 20MHz\n");
- pcdev->platform_mclk_10khz = 2000;
+ pcdev->mclk = 20000000;
}
+ pcdev->dev = &pdev->dev;
+ pcdev->mclk_divisor = mclk_get_divisor(pcdev);
+
INIT_LIST_HEAD(&pcdev->capture);
spin_lock_init(&pcdev->lock);
@@ -1122,7 +1456,6 @@ static int pxa_camera_probe(struct platform_device *pdev)
}
pcdev->irq = irq;
pcdev->base = base;
- pcdev->dev = &pdev->dev;
/* request dma */
err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
diff --git a/linux/drivers/media/video/s2255drv.c b/linux/drivers/media/video/s2255drv.c
index ab9814144..2a2cbb418 100644
--- a/linux/drivers/media/video/s2255drv.c
+++ b/linux/drivers/media/video/s2255drv.c
@@ -1503,9 +1503,9 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
dprintk(2, "setting jpeg quality %d\n", jc->quality);
return 0;
}
-static int s2255_open(struct inode *inode, struct file *file)
+static int s2255_open(struct file *file)
{
- int minor = iminor(inode);
+ int minor = video_devdata(file)->minor;
struct s2255_dev *h, *dev = NULL;
struct s2255_fh *fh;
struct list_head *list;
@@ -1712,11 +1712,11 @@ static void s2255_destroy(struct kref *kref)
mutex_unlock(&dev->open_lock);
}
-static int s2255_close(struct inode *inode, struct file *file)
+static int s2255_close(struct file *file)
{
struct s2255_fh *fh = file->private_data;
struct s2255_dev *dev = fh->dev;
- int minor = iminor(inode);
+ int minor = video_devdata(file)->minor;
if (!dev)
return -ENODEV;
@@ -1760,15 +1760,13 @@ static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
return ret;
}
-static const struct file_operations s2255_fops_v4l = {
+static const struct v4l2_file_operations s2255_fops_v4l = {
.owner = THIS_MODULE,
.open = s2255_open,
.release = s2255_close,
.poll = s2255_poll,
.ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .compat_ioctl = v4l_compat_ioctl32,
.mmap = s2255_mmap_v4l,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
diff --git a/linux/drivers/media/video/saa5246a.c b/linux/drivers/media/video/saa5246a.c
index 086fc807a..cb8a92e5f 100644
--- a/linux/drivers/media/video/saa5246a.c
+++ b/linux/drivers/media/video/saa5246a.c
@@ -805,7 +805,7 @@ static inline int saa5246a_stop_dau(struct saa5246a_device *t,
*
* Returns 0 if successful
*/
-static int do_saa5246a_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long do_saa5246a_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct saa5246a_device *t = video_drvdata(file);
@@ -945,11 +945,11 @@ static inline unsigned int vtx_fix_command(unsigned int cmd)
/*
* Handle the locking
*/
-static int saa5246a_ioctl(struct inode *inode, struct file *file,
+static long saa5246a_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct saa5246a_device *t = video_drvdata(file);
- int err;
+ long err;
cmd = vtx_fix_command(cmd);
mutex_lock(&t->lock);
@@ -958,7 +958,7 @@ static int saa5246a_ioctl(struct inode *inode, struct file *file,
return err;
}
-static int saa5246a_open(struct inode *inode, struct file *file)
+static int saa5246a_open(struct file *file)
{
struct saa5246a_device *t = video_drvdata(file);
@@ -1000,7 +1000,7 @@ static int saa5246a_open(struct inode *inode, struct file *file)
return 0;
}
-static int saa5246a_release(struct inode *inode, struct file *file)
+static int saa5246a_release(struct file *file)
{
struct saa5246a_device *t = video_drvdata(file);
@@ -1019,12 +1019,11 @@ static int saa5246a_release(struct inode *inode, struct file *file)
return 0;
}
-static const struct file_operations saa_fops = {
+static const struct v4l2_file_operations saa_fops = {
.owner = THIS_MODULE,
.open = saa5246a_open,
.release = saa5246a_release,
.ioctl = saa5246a_ioctl,
- .llseek = no_llseek,
};
static struct video_device saa_template =
diff --git a/linux/drivers/media/video/saa5249.c b/linux/drivers/media/video/saa5249.c
index 86352dbe7..9102c6cea 100644
--- a/linux/drivers/media/video/saa5249.c
+++ b/linux/drivers/media/video/saa5249.c
@@ -191,7 +191,7 @@ static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
* Standard character-device-driver functions
*/
-static int do_saa5249_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long do_saa5249_ioctl(struct file *file, unsigned int cmd, void *arg)
{
static int virtual_mode = false;
struct saa5249_device *t = video_drvdata(file);
@@ -480,11 +480,11 @@ static inline unsigned int vtx_fix_command(unsigned int cmd)
* Handle the locking
*/
-static int saa5249_ioctl(struct inode *inode, struct file *file,
+static long saa5249_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct saa5249_device *t = video_drvdata(file);
- int err;
+ long err;
cmd = vtx_fix_command(cmd);
mutex_lock(&t->lock);
@@ -493,7 +493,7 @@ static int saa5249_ioctl(struct inode *inode, struct file *file,
return err;
}
-static int saa5249_open(struct inode *inode, struct file *file)
+static int saa5249_open(struct file *file)
{
struct saa5249_device *t = video_drvdata(file);
int pgbuf;
@@ -530,7 +530,7 @@ static int saa5249_open(struct inode *inode, struct file *file)
-static int saa5249_release(struct inode *inode, struct file *file)
+static int saa5249_release(struct file *file)
{
struct saa5249_device *t = video_drvdata(file);
@@ -540,15 +540,11 @@ static int saa5249_release(struct inode *inode, struct file *file)
return 0;
}
-static const struct file_operations saa_fops = {
+static const struct v4l2_file_operations saa_fops = {
.owner = THIS_MODULE,
.open = saa5249_open,
.release = saa5249_release,
.ioctl = saa5249_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static struct video_device saa_template =
diff --git a/linux/drivers/media/video/saa7115.c b/linux/drivers/media/video/saa7115.c
index 02386e403..40b0196e6 100644
--- a/linux/drivers/media/video/saa7115.c
+++ b/linux/drivers/media/video/saa7115.c
@@ -44,7 +44,7 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include <media/saa7115.h>
@@ -71,6 +71,7 @@ static unsigned short normal_i2c[] = {
I2C_CLIENT_INSMOD;
struct saa711x_state {
+ struct v4l2_subdev sd;
v4l2_std_id std;
int input;
int output;
@@ -90,10 +91,17 @@ struct saa711x_state {
u8 apll;
};
+static inline struct saa711x_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct saa711x_state, sd);
+}
+
/* ----------------------------------------------------------------------- */
-static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value)
+static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
return i2c_smbus_write_byte_data(client, reg, value);
}
@@ -129,9 +137,9 @@ static int saa711x_has_reg(const int id, const u8 reg)
return 1;
}
-static int saa711x_writeregs(struct i2c_client *client, const unsigned char *regs)
+static int saa711x_writeregs(struct v4l2_subdev *sd, const unsigned char *regs)
{
- struct saa711x_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = to_state(sd);
unsigned char reg, data;
while (*regs != 0x00) {
@@ -140,18 +148,20 @@ static int saa711x_writeregs(struct i2c_client *client, const unsigned char *reg
/* According with datasheets, reserved regs should be
filled with 0 - seems better not to touch on they */
- if (saa711x_has_reg(state->ident,reg)) {
- if (saa711x_write(client, reg, data) < 0)
+ if (saa711x_has_reg(state->ident, reg)) {
+ if (saa711x_write(sd, reg, data) < 0)
return -1;
} else {
- v4l_dbg(1, debug, client, "tried to access reserved reg 0x%02x\n", reg);
+ v4l2_dbg(1, debug, sd, "tried to access reserved reg 0x%02x\n", reg);
}
}
return 0;
}
-static inline int saa711x_read(struct i2c_client *client, u8 reg)
+static inline int saa711x_read(struct v4l2_subdev *sd, u8 reg)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
return i2c_smbus_read_byte_data(client, reg);
}
@@ -602,7 +612,7 @@ static int saa711x_odd_parity(u8 c)
return c & 1;
}
-static int saa711x_decode_vps(u8 * dst, u8 * p)
+static int saa711x_decode_vps(u8 *dst, u8 *p)
{
static const u8 biphase_tbl[] = {
0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
@@ -649,7 +659,7 @@ static int saa711x_decode_vps(u8 * dst, u8 * p)
return err & 0xf0;
}
-static int saa711x_decode_wss(u8 * p)
+static int saa711x_decode_wss(u8 *p)
{
static const int wss_bits[8] = {
0, 0, 0, 1, 0, 1, 1, 1
@@ -676,9 +686,9 @@ static int saa711x_decode_wss(u8 * p)
return wss;
}
-static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
+static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
{
- struct saa711x_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = to_state(sd);
u32 acpf;
u32 acni;
u32 hz;
@@ -686,10 +696,10 @@ static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
u8 acc = 0; /* reg 0x3a, audio clock control */
/* Checks for chips that don't have audio clock (saa7111, saa7113) */
- if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
+ if (!saa711x_has_reg(state->ident, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
return 0;
- v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
+ v4l2_dbg(1, debug, sd, "set audio clock freq: %d\n", freq);
/* sanity check */
if (freq < 32000 || freq > 48000)
@@ -716,66 +726,66 @@ static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
if (state->apll)
acc |= 0x08;
- saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
- saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
- saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
+ saa711x_write(sd, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
+ saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
+ saa711x_write(sd, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
- saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
- saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
+ saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
+ saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
(acpf >> 8) & 0xff);
- saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
+ saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
(acpf >> 16) & 0x03);
- saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
- saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
- saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
+ saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
+ saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
+ saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
state->audclk_freq = freq;
return 0;
}
-static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int saa711x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct saa711x_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
if (ctrl->value < 0 || ctrl->value > 255) {
- v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
+ v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
return -ERANGE;
}
state->bright = ctrl->value;
- saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
+ saa711x_write(sd, R_0A_LUMA_BRIGHT_CNTL, state->bright);
break;
case V4L2_CID_CONTRAST:
if (ctrl->value < 0 || ctrl->value > 127) {
- v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
+ v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
return -ERANGE;
}
state->contrast = ctrl->value;
- saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
+ saa711x_write(sd, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
break;
case V4L2_CID_SATURATION:
if (ctrl->value < 0 || ctrl->value > 127) {
- v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
+ v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
return -ERANGE;
}
state->sat = ctrl->value;
- saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
+ saa711x_write(sd, R_0C_CHROMA_SAT_CNTL, state->sat);
break;
case V4L2_CID_HUE:
if (ctrl->value < -127 || ctrl->value > 127) {
- v4l_err(client, "invalid hue setting %d\n", ctrl->value);
+ v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
return -ERANGE;
}
state->hue = ctrl->value;
- saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
+ saa711x_write(sd, R_0D_CHROMA_HUE_CNTL, state->hue);
break;
default:
@@ -785,9 +795,9 @@ static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
return 0;
}
-static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int saa711x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct saa711x_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
@@ -809,16 +819,16 @@ static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *c
return 0;
}
-static int saa711x_set_size(struct i2c_client *client, int width, int height)
+static int saa711x_set_size(struct v4l2_subdev *sd, int width, int height)
{
- struct saa711x_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = to_state(sd);
int HPSC, HFSC;
int VSCY;
int res;
int is_50hz = state->std & V4L2_STD_625_50;
int Vsrc = is_50hz ? 576 : 480;
- v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);
+ v4l2_dbg(1, debug, sd, "decoder set size to %ix%i\n", width, height);
/* FIXME need better bounds checking here */
if ((width < 1) || (width > 1440))
@@ -826,7 +836,7 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
if ((height < 1) || (height > Vsrc))
return -EINVAL;
- if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
+ if (!saa711x_has_reg(state->ident, R_D0_B_HORIZ_PRESCALING)) {
/* Decoder only supports 720 columns and 480 or 576 lines */
if (width != 720)
return -EINVAL;
@@ -844,22 +854,22 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
/* Set output width/height */
/* width */
- saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
+ saa711x_write(sd, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
(u8) (width & 0xff));
- saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
+ saa711x_write(sd, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
(u8) ((width >> 8) & 0xff));
/* Vertical Scaling uses height/2 */
- res=height/2;
+ res = height / 2;
/* On 60Hz, it is using a higher Vertical Output Size */
if (!is_50hz)
res += (VRES_60HZ - 480) >> 1;
/* height */
- saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
+ saa711x_write(sd, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
(u8) (res & 0xff));
- saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
+ saa711x_write(sd, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
(u8) ((res >> 8) & 0xff));
/* Scaling settings */
@@ -870,54 +880,54 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
HFSC = (int)((1024 * 720) / (HPSC * width));
/* FIXME hardcodes to "Task B"
* write H prescaler integer */
- saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
+ saa711x_write(sd, R_D0_B_HORIZ_PRESCALING,
(u8) (HPSC & 0x3f));
- v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+ v4l2_dbg(1, debug, sd, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
/* write H fine-scaling (luminance) */
- saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
+ saa711x_write(sd, R_D8_B_HORIZ_LUMA_SCALING_INC,
(u8) (HFSC & 0xff));
- saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
+ saa711x_write(sd, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
(u8) ((HFSC >> 8) & 0xff));
/* write H fine-scaling (chrominance)
* must be lum/2, so i'll just bitshift :) */
- saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
+ saa711x_write(sd, R_DC_B_HORIZ_CHROMA_SCALING,
(u8) ((HFSC >> 1) & 0xff));
- saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
+ saa711x_write(sd, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
(u8) ((HFSC >> 9) & 0xff));
VSCY = (int)((1024 * Vsrc) / height);
- v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+ v4l2_dbg(1, debug, sd, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
/* Correct Contrast and Luminance */
- saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
+ saa711x_write(sd, R_D5_B_LUMA_CONTRAST_CNTL,
(u8) (64 * 1024 / VSCY));
- saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
+ saa711x_write(sd, R_D6_B_CHROMA_SATURATION_CNTL,
(u8) (64 * 1024 / VSCY));
/* write V fine-scaling (luminance) */
- saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
+ saa711x_write(sd, R_E0_B_VERT_LUMA_SCALING_INC,
(u8) (VSCY & 0xff));
- saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
+ saa711x_write(sd, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
(u8) ((VSCY >> 8) & 0xff));
/* write V fine-scaling (chrominance) */
- saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
+ saa711x_write(sd, R_E2_B_VERT_CHROMA_SCALING_INC,
(u8) (VSCY & 0xff));
- saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
+ saa711x_write(sd, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
(u8) ((VSCY >> 8) & 0xff));
- saa711x_writeregs(client, saa7115_cfg_reset_scaler);
+ saa711x_writeregs(sd, saa7115_cfg_reset_scaler);
/* Activates task "B" */
- saa711x_write(client, R_80_GLOBAL_CNTL_1,
- saa711x_read(client,R_80_GLOBAL_CNTL_1) | 0x20);
+ saa711x_write(sd, R_80_GLOBAL_CNTL_1,
+ saa711x_read(sd, R_80_GLOBAL_CNTL_1) | 0x20);
return 0;
}
-static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
{
- struct saa711x_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = to_state(sd);
/* Prevent unnecessary standard changes. During a standard
change the I-Port is temporarily disabled. Any devices
@@ -933,13 +943,13 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
// This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
if (std & V4L2_STD_525_60) {
- v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
- saa711x_writeregs(client, saa7115_cfg_60hz_video);
- saa711x_set_size(client, 720, 480);
+ v4l2_dbg(1, debug, sd, "decoder set standard 60 Hz\n");
+ saa711x_writeregs(sd, saa7115_cfg_60hz_video);
+ saa711x_set_size(sd, 720, 480);
} else {
- v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
- saa711x_writeregs(client, saa7115_cfg_50hz_video);
- saa711x_set_size(client, 720, 576);
+ v4l2_dbg(1, debug, sd, "decoder set standard 50 Hz\n");
+ saa711x_writeregs(sd, saa7115_cfg_50hz_video);
+ saa711x_set_size(sd, 720, 576);
}
/* Register 0E - Bits D6-D4 on NO-AUTO mode
@@ -953,7 +963,7 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
*/
if (state->ident == V4L2_IDENT_SAA7111 ||
state->ident == V4L2_IDENT_SAA7113) {
- u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
+ u8 reg = saa711x_read(sd, R_0E_CHROMA_CNTL_1) & 0x8f;
if (std == V4L2_STD_PAL_M) {
reg |= 0x30;
@@ -966,87 +976,31 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
} else if (std & V4L2_STD_SECAM) {
reg |= 0x50;
}
- saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
+ saa711x_write(sd, R_0E_CHROMA_CNTL_1, reg);
} else {
/* restart task B if needed */
- int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
+ int taskb = saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10;
if (taskb && state->ident == V4L2_IDENT_SAA7114) {
- saa711x_writeregs(client, saa7115_cfg_vbi_on);
+ saa711x_writeregs(sd, saa7115_cfg_vbi_on);
}
/* switch audio mode too! */
- saa711x_set_audio_clock_freq(client, state->audclk_freq);
- }
-}
-
-static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
-{
- struct saa711x_state *state = i2c_get_clientdata(client);
-
- return state->std;
-}
-
-static void saa711x_log_status(struct i2c_client *client)
-{
- struct saa711x_state *state = i2c_get_clientdata(client);
- int reg1e, reg1f;
- int signalOk;
- int vcr;
-
- v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
- if (state->ident != V4L2_IDENT_SAA7115) {
- /* status for the saa7114 */
- reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
- signalOk = (reg1f & 0xc1) == 0x81;
- v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
- v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
- return;
- }
-
- /* status for the saa7115 */
- reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
- reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
-
- signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
- vcr = !(reg1f & 0x10);
-
- if (state->input >= 6) {
- v4l_info(client, "Input: S-Video %d\n", state->input - 6);
- } else {
- v4l_info(client, "Input: Composite %d\n", state->input);
+ saa711x_s_clock_freq(sd, state->audclk_freq);
}
- v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
- v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
-
- switch (reg1e & 0x03) {
- case 1:
- v4l_info(client, "Detected format: NTSC\n");
- break;
- case 2:
- v4l_info(client, "Detected format: PAL\n");
- break;
- case 3:
- v4l_info(client, "Detected format: SECAM\n");
- break;
- default:
- v4l_info(client, "Detected format: BW/No color\n");
- break;
- }
- v4l_info(client, "Width, Height: %d, %d\n", state->width, state->height);
}
/* setup the sliced VBI lcr registers according to the sliced VBI format */
-static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
+static void saa711x_set_lcr(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
{
- struct saa711x_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = to_state(sd);
int is_50hz = (state->std & V4L2_STD_625_50);
u8 lcr[24];
int i, x;
#if 1 /* keep */
/* saa7113/7114/7118 VBI support are experimental */
- if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
+ if (!saa711x_has_reg(state->ident, R_41_LCR_BASE))
return;
#else
@@ -1110,16 +1064,16 @@ static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
/* write the lcr registers */
for (i = 2; i <= 23; i++) {
- saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
+ saa711x_write(sd, i - 2 + R_41_LCR_BASE, lcr[i]);
}
/* enable/disable raw VBI capturing */
- saa711x_writeregs(client, fmt == NULL ?
+ saa711x_writeregs(sd, fmt == NULL ?
saa7115_cfg_vbi_on :
saa7115_cfg_vbi_off);
}
-static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int saa711x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
{
static u16 lcr2vbi[] = {
0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
@@ -1135,10 +1089,10 @@ static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
return -EINVAL;
memset(sliced, 0, sizeof(*sliced));
/* done if using raw VBI */
- if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
+ if (saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10)
return 0;
for (i = 2; i <= 23; i++) {
- u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
+ u8 v = saa711x_read(sd, i - 2 + R_41_LCR_BASE);
sliced->service_lines[0][i] = lcr2vbi[v >> 4];
sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
@@ -1148,20 +1102,20 @@ static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
return 0;
}
-static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int saa711x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
{
if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
- saa711x_set_lcr(client, &fmt->fmt.sliced);
+ saa711x_set_lcr(sd, &fmt->fmt.sliced);
return 0;
}
if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- saa711x_set_lcr(client, NULL);
+ saa711x_set_lcr(sd, NULL);
return 0;
}
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);
+ return saa711x_set_size(sd, fmt->fmt.pix.width, fmt->fmt.pix.height);
}
/* Decode the sliced VBI data stream as created by the saa7115.
@@ -1170,13 +1124,12 @@ static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
The current implementation uses SAV/EAV codes and not the ancillary data
headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
code. */
-static void saa711x_decode_vbi_line(struct i2c_client *client,
- struct v4l2_decode_vbi_line *vbi)
+static int saa711x_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
{
+ struct saa711x_state *state = to_state(sd);
static const char vbi_no_data_pattern[] = {
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
};
- struct saa711x_state *state = i2c_get_clientdata(client);
u8 *p = vbi->p;
u32 wss;
int id1, id2; /* the ID1 and ID2 bytes from the internal header */
@@ -1203,7 +1156,7 @@ static void saa711x_decode_vbi_line(struct i2c_client *client,
/* If the VBI slicer does not detect any signal it will fill up
the payload buffer with 0xa0 bytes. */
if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
- return;
+ return 0;
/* decode payloads */
switch (id2) {
@@ -1212,275 +1165,351 @@ static void saa711x_decode_vbi_line(struct i2c_client *client,
break;
case 4:
if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
- return;
+ return 0;
vbi->type = V4L2_SLICED_CAPTION_525;
break;
case 5:
wss = saa711x_decode_wss(p);
if (wss == -1)
- return;
+ return 0;
p[0] = wss & 0xff;
p[1] = wss >> 8;
vbi->type = V4L2_SLICED_WSS_625;
break;
case 7:
if (saa711x_decode_vps(p, p) != 0)
- return;
+ return 0;
vbi->type = V4L2_SLICED_VPS;
break;
default:
- return;
+ break;
}
+ return 0;
}
/* ============ SAA7115 AUDIO settings (end) ============= */
-static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int saa711x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
{
- struct saa711x_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = to_state(sd);
+ int status;
- /* ioctls to allow direct access to the saa7115 registers for testing */
- switch (cmd) {
- case VIDIOC_S_FMT:
- return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
+ if (state->radio)
+ return 0;
+ status = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
- case VIDIOC_G_FMT:
- return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
+ v4l2_dbg(1, debug, sd, "status: 0x%02x\n", status);
+ vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
+ return 0;
+}
- case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
+static int saa711x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
+}
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *vt = arg;
- int status;
+static int saa711x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct saa711x_state *state = to_state(sd);
- if (state->radio)
- break;
- status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
+ state->radio = 0;
+ saa711x_set_v4lstd(sd, std);
+ return 0;
+}
- v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
- vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
- break;
- }
+static int saa711x_s_radio(struct v4l2_subdev *sd)
+{
+ struct saa711x_state *state = to_state(sd);
- case VIDIOC_LOG_STATUS:
- saa711x_log_status(client);
- break;
+ state->radio = 1;
+ return 0;
+}
- case VIDIOC_G_CTRL:
- return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
+static int saa711x_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+ struct saa711x_state *state = to_state(sd);
+ u32 input = route->input;
+ u8 mask = (state->ident == V4L2_IDENT_SAA7111) ? 0xf8 : 0xf0;
+
+ v4l2_dbg(1, debug, sd, "decoder set input %d output %d\n", route->input, route->output);
+ /* saa7111/3 does not have these inputs */
+ if ((state->ident == V4L2_IDENT_SAA7113 ||
+ state->ident == V4L2_IDENT_SAA7111) &&
+ (route->input == SAA7115_COMPOSITE4 ||
+ route->input == SAA7115_COMPOSITE5)) {
+ return -EINVAL;
+ }
+ if (route->input > SAA7115_SVIDEO3)
+ return -EINVAL;
+ if (route->output > SAA7115_IPORT_ON)
+ return -EINVAL;
+ if (state->input == route->input && state->output == route->output)
+ return 0;
+ v4l2_dbg(1, debug, sd, "now setting %s input %s output\n",
+ (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite",
+ (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
+ state->input = route->input;
+
+ /* saa7111 has slightly different input numbering */
+ if (state->ident == V4L2_IDENT_SAA7111) {
+ if (input >= SAA7115_COMPOSITE4)
+ input -= 2;
+ /* saa7111 specific */
+ saa711x_write(sd, R_10_CHROMA_CNTL_2,
+ (saa711x_read(sd, R_10_CHROMA_CNTL_2) & 0x3f) |
+ ((route->output & 0xc0) ^ 0x40));
+ saa711x_write(sd, R_13_RT_X_PORT_OUT_CNTL,
+ (saa711x_read(sd, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) |
+ ((route->output & 2) ? 0x0a : 0));
+ }
- case VIDIOC_S_CTRL:
- return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
+ /* select mode */
+ saa711x_write(sd, R_02_INPUT_CNTL_1,
+ (saa711x_read(sd, R_02_INPUT_CNTL_1) & mask) |
+ input);
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
+ /* bypass chrominance trap for S-Video modes */
+ saa711x_write(sd, R_09_LUMA_CNTL,
+ (saa711x_read(sd, R_09_LUMA_CNTL) & 0x7f) |
+ (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- case V4L2_CID_CONTRAST:
- case V4L2_CID_SATURATION:
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill_std(qc);
- default:
- return -EINVAL;
- }
+ state->output = route->output;
+ if (state->ident == V4L2_IDENT_SAA7114 ||
+ state->ident == V4L2_IDENT_SAA7115) {
+ saa711x_write(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
+ (saa711x_read(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
+ (state->output & 0x01));
}
+ return 0;
+}
- case VIDIOC_G_STD:
- *(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
- break;
+static int saa711x_s_gpio(struct v4l2_subdev *sd, u32 val)
+{
+ struct saa711x_state *state = to_state(sd);
- case VIDIOC_S_STD:
- state->radio = 0;
- saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
- break;
+ if (state->ident != V4L2_IDENT_SAA7111)
+ return -EINVAL;
+ saa711x_write(sd, 0x11, (saa711x_read(sd, 0x11) & 0x7f) |
+ (val ? 0x80 : 0));
+ return 0;
+}
- case AUDC_SET_RADIO:
- state->radio = 1;
- break;
+static int saa711x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct saa711x_state *state = to_state(sd);
- case VIDIOC_INT_G_VIDEO_ROUTING:
- {
- struct v4l2_routing *route = arg;
+ v4l2_dbg(1, debug, sd, "%s output\n",
+ enable ? "enable" : "disable");
- route->input = state->input;
- route->output = state->output;
- break;
+ if (state->enable != enable) {
+ state->enable = enable;
+ saa711x_write(sd, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
+ state->enable);
}
+ return 0;
+}
- case VIDIOC_INT_S_VIDEO_ROUTING:
- {
- struct v4l2_routing *route = arg;
- u32 input = route->input;
- u8 mask = (state->ident == V4L2_IDENT_SAA7111) ? 0xf8 : 0xf0;
-
- v4l_dbg(1, debug, client, "decoder set input %d output %d\n", route->input, route->output);
- /* saa7111/3 does not have these inputs */
- if ((state->ident == V4L2_IDENT_SAA7113 ||
- state->ident == V4L2_IDENT_SAA7111) &&
- (route->input == SAA7115_COMPOSITE4 ||
- route->input == SAA7115_COMPOSITE5)) {
- return -EINVAL;
- }
- if (route->input > SAA7115_SVIDEO3)
- return -EINVAL;
- if (route->output > SAA7115_IPORT_ON)
- return -EINVAL;
- if (state->input == route->input && state->output == route->output)
- break;
- v4l_dbg(1, debug, client, "now setting %s input %s output\n",
- (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite", (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
- state->input = route->input;
-
- /* saa7111 has slightly different input numbering */
- if (state->ident == V4L2_IDENT_SAA7111) {
- if (input >= SAA7115_COMPOSITE4)
- input -= 2;
- /* saa7111 specific */
- saa711x_write(client, R_10_CHROMA_CNTL_2,
- (saa711x_read(client, R_10_CHROMA_CNTL_2) & 0x3f) |
- ((route->output & 0xc0) ^ 0x40));
- saa711x_write(client, R_13_RT_X_PORT_OUT_CNTL,
- (saa711x_read(client, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) |
- ((route->output & 2) ? 0x0a : 0));
- }
+static int saa711x_s_crystal_freq(struct v4l2_subdev *sd, struct v4l2_crystal_freq *freq)
+{
+ struct saa711x_state *state = to_state(sd);
- /* select mode */
- saa711x_write(client, R_02_INPUT_CNTL_1,
- (saa711x_read(client, R_02_INPUT_CNTL_1) & mask) |
- input);
+ if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
+ freq->freq != SAA7115_FREQ_24_576_MHZ)
+ return -EINVAL;
+ state->crystal_freq = freq->freq;
+ state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
+ state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
+ state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
+ saa711x_s_clock_freq(sd, state->audclk_freq);
+ return 0;
+}
- /* bypass chrominance trap for S-Video modes */
- saa711x_write(client, R_09_LUMA_CNTL,
- (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
- (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
+static int saa711x_reset(struct v4l2_subdev *sd, u32 val)
+{
+ v4l2_dbg(1, debug, sd, "decoder RESET\n");
+ saa711x_writeregs(sd, saa7115_cfg_reset_scaler);
+ return 0;
+}
- state->output = route->output;
- if (state->ident == V4L2_IDENT_SAA7114 ||
- state->ident == V4L2_IDENT_SAA7115) {
- saa711x_write(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
- (saa711x_read(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
- (state->output & 0x01));
+static int saa711x_g_vbi_data(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *data)
+{
+ /* Note: the internal field ID is inverted for NTSC,
+ so data->field 0 maps to the saa7115 even field,
+ whereas for PAL it maps to the saa7115 odd field. */
+ switch (data->id) {
+ case V4L2_SLICED_WSS_625:
+ if (saa711x_read(sd, 0x6b) & 0xc0)
+ return -EIO;
+ data->data[0] = saa711x_read(sd, 0x6c);
+ data->data[1] = saa711x_read(sd, 0x6d);
+ return 0;
+ case V4L2_SLICED_CAPTION_525:
+ if (data->field == 0) {
+ /* CC */
+ if (saa711x_read(sd, 0x66) & 0x30)
+ return -EIO;
+ data->data[0] = saa711x_read(sd, 0x69);
+ data->data[1] = saa711x_read(sd, 0x6a);
+ return 0;
}
- break;
+ /* XDS */
+ if (saa711x_read(sd, 0x66) & 0xc0)
+ return -EIO;
+ data->data[0] = saa711x_read(sd, 0x67);
+ data->data[1] = saa711x_read(sd, 0x68);
+ return 0;
+ default:
+ return -EINVAL;
}
+}
- case VIDIOC_STREAMON:
- case VIDIOC_STREAMOFF:
- v4l_dbg(1, debug, client, "%s output\n",
- (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
-
- if (state->enable != (cmd == VIDIOC_STREAMON)) {
- state->enable = (cmd == VIDIOC_STREAMON);
- saa711x_write(client,
- R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
- state->enable);
- }
- break;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_INT_S_CRYSTAL_FREQ:
- {
- struct v4l2_crystal_freq *freq = arg;
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->val = saa711x_read(sd, reg->reg & 0xff);
+ reg->size = 1;
+ return 0;
+}
- if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
- freq->freq != SAA7115_FREQ_24_576_MHZ)
- return -EINVAL;
- state->crystal_freq = freq->freq;
- state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
- state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
- state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
- saa711x_set_audio_clock_freq(client, state->audclk_freq);
- break;
- }
+static int saa711x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_INT_DECODE_VBI_LINE:
- saa711x_decode_vbi_line(client, arg);
- break;
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ saa711x_write(sd, reg->reg & 0xff, reg->val & 0xff);
+ return 0;
+}
+#endif
- case VIDIOC_INT_RESET:
- v4l_dbg(1, debug, client, "decoder RESET\n");
- saa711x_writeregs(client, saa7115_cfg_reset_scaler);
- break;
+static int saa711x_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct saa711x_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_INT_S_GPIO:
- if (state->ident != V4L2_IDENT_SAA7111)
- return -EINVAL;
- saa711x_write(client, 0x11, (saa711x_read(client, 0x11) & 0x7f) |
- (*(u32 *)arg ? 0x80 : 0));
- break;
+ return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
+}
- case VIDIOC_INT_G_VBI_DATA:
- {
- struct v4l2_sliced_vbi_data *data = arg;
+static int saa711x_log_status(struct v4l2_subdev *sd)
+{
+ struct saa711x_state *state = to_state(sd);
+ int reg1e, reg1f;
+ int signalOk;
+ int vcr;
- /* Note: the internal field ID is inverted for NTSC,
- so data->field 0 maps to the saa7115 even field,
- whereas for PAL it maps to the saa7115 odd field. */
- switch (data->id) {
- case V4L2_SLICED_WSS_625:
- if (saa711x_read(client, 0x6b) & 0xc0)
- return -EIO;
- data->data[0] = saa711x_read(client, 0x6c);
- data->data[1] = saa711x_read(client, 0x6d);
- return 0;
- case V4L2_SLICED_CAPTION_525:
- if (data->field == 0) {
- /* CC */
- if (saa711x_read(client, 0x66) & 0x30)
- return -EIO;
- data->data[0] = saa711x_read(client, 0x69);
- data->data[1] = saa711x_read(client, 0x6a);
- return 0;
- }
- /* XDS */
- if (saa711x_read(client, 0x66) & 0xc0)
- return -EIO;
- data->data[0] = saa711x_read(client, 0x67);
- data->data[1] = saa711x_read(client, 0x68);
- return 0;
- default:
- return -EINVAL;
- }
- break;
+ v4l2_info(sd, "Audio frequency: %d Hz\n", state->audclk_freq);
+ if (state->ident != V4L2_IDENT_SAA7115) {
+ /* status for the saa7114 */
+ reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+ signalOk = (reg1f & 0xc1) == 0x81;
+ v4l2_info(sd, "Video signal: %s\n", signalOk ? "ok" : "bad");
+ v4l2_info(sd, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
+ return 0;
}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
+ /* status for the saa7115 */
+ reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
+ reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
- if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (cmd == VIDIOC_DBG_G_REGISTER)
- reg->val = saa711x_read(client, reg->reg & 0xff);
- else
- saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
- break;
- }
-#endif
+ signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
+ vcr = !(reg1f & 0x10);
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0);
+ if (state->input >= 6)
+ v4l2_info(sd, "Input: S-Video %d\n", state->input - 6);
+ else
+ v4l2_info(sd, "Input: Composite %d\n", state->input);
+ v4l2_info(sd, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
+ v4l2_info(sd, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
+ switch (reg1e & 0x03) {
+ case 1:
+ v4l2_info(sd, "Detected format: NTSC\n");
+ break;
+ case 2:
+ v4l2_info(sd, "Detected format: PAL\n");
+ break;
+ case 3:
+ v4l2_info(sd, "Detected format: SECAM\n");
+ break;
default:
- return -EINVAL;
+ v4l2_info(sd, "Detected format: BW/No color\n");
+ break;
}
-
+ v4l2_info(sd, "Width, Height: %d, %d\n", state->width, state->height);
return 0;
}
+static int saa711x_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa711x_core_ops = {
+ .log_status = saa711x_log_status,
+ .g_chip_ident = saa711x_g_chip_ident,
+ .g_ctrl = saa711x_g_ctrl,
+ .s_ctrl = saa711x_s_ctrl,
+ .queryctrl = saa711x_queryctrl,
+ .reset = saa711x_reset,
+ .s_gpio = saa711x_s_gpio,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = saa711x_g_register,
+ .s_register = saa711x_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops saa711x_tuner_ops = {
+ .s_std = saa711x_s_std,
+ .s_radio = saa711x_s_radio,
+ .g_tuner = saa711x_g_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops saa711x_audio_ops = {
+ .s_clock_freq = saa711x_s_clock_freq,
+};
+
+static const struct v4l2_subdev_video_ops saa711x_video_ops = {
+ .s_routing = saa711x_s_routing,
+ .s_crystal_freq = saa711x_s_crystal_freq,
+ .g_fmt = saa711x_g_fmt,
+ .s_fmt = saa711x_s_fmt,
+ .g_vbi_data = saa711x_g_vbi_data,
+ .decode_vbi_line = saa711x_decode_vbi_line,
+ .s_stream = saa711x_s_stream,
+};
+
+static const struct v4l2_subdev_ops saa711x_ops = {
+ .core = &saa711x_core_ops,
+ .tuner = &saa711x_tuner_ops,
+ .audio = &saa711x_audio_ops,
+ .video = &saa711x_video_ops,
+};
+
/* ----------------------------------------------------------------------- */
-static int saa7115_probe(struct i2c_client *client,
+static int saa711x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct saa711x_state *state;
+ struct v4l2_subdev *sd;
int i;
char name[17];
char chip_id;
@@ -1497,8 +1526,8 @@ static int saa7115_probe(struct i2c_client *client,
#endif
for (i = 0; i < 0x0f; i++) {
- saa711x_write(client, 0, i);
- name[i] = (saa711x_read(client, 0) & 0x0f) + '0';
+ i2c_smbus_write_byte_data(client, 0, i);
+ name[i] = (i2c_smbus_read_byte_data(client, 0) & 0x0f) + '0';
if (name[i] > '9')
name[i] += 'a' - '9' - 1;
}
@@ -1527,7 +1556,8 @@ static int saa7115_probe(struct i2c_client *client,
state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
- i2c_set_clientdata(client, state);
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &saa711x_ops);
state->input = -1;
state->output = SAA7115_IPORT_ON;
state->enable = 1;
@@ -1554,41 +1584,45 @@ static int saa7115_probe(struct i2c_client *client,
break;
default:
state->ident = V4L2_IDENT_SAA7111;
- v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n");
+ v4l2_info(sd, "WARNING: Chip is not known - Falling back to saa7111\n");
}
state->audclk_freq = 48000;
- v4l_dbg(1, debug, client, "writing init values\n");
+ v4l2_dbg(1, debug, sd, "writing init values\n");
/* init to 60hz/48khz */
state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
switch (state->ident) {
case V4L2_IDENT_SAA7111:
- saa711x_writeregs(client, saa7111_init);
+ saa711x_writeregs(sd, saa7111_init);
break;
case V4L2_IDENT_SAA7113:
- saa711x_writeregs(client, saa7113_init);
+ saa711x_writeregs(sd, saa7113_init);
break;
default:
state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
- saa711x_writeregs(client, saa7115_init_auto_input);
+ saa711x_writeregs(sd, saa7115_init_auto_input);
}
if (state->ident != V4L2_IDENT_SAA7111)
- saa711x_writeregs(client, saa7115_init_misc);
- saa711x_set_v4lstd(client, V4L2_STD_NTSC);
+ saa711x_writeregs(sd, saa7115_init_misc);
+ saa711x_set_v4lstd(sd, V4L2_STD_NTSC);
- v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
- saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
+ v4l2_dbg(1, debug, sd, "status: (1E) 0x%02x, (1F) 0x%02x\n",
+ saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC),
+ saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC));
return 0;
}
/* ----------------------------------------------------------------------- */
-static int saa7115_remove(struct i2c_client *client)
+static int saa711x_remove(struct i2c_client *client)
{
- kfree(i2c_get_clientdata(client));
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
return 0;
}
@@ -1608,9 +1642,9 @@ MODULE_DEVICE_TABLE(i2c, saa7115_id);
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "saa7115",
.driverid = I2C_DRIVERID_SAA711X,
- .command = saa7115_command,
- .probe = saa7115_probe,
- .remove = saa7115_remove,
+ .command = saa711x_command,
+ .probe = saa711x_probe,
+ .remove = saa711x_remove,
.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
.id_table = saa7115_id,
diff --git a/linux/drivers/media/video/saa7127.c b/linux/drivers/media/video/saa7127.c
index fd7d15305..79c947ca0 100644
--- a/linux/drivers/media/video/saa7127.c
+++ b/linux/drivers/media/video/saa7127.c
@@ -53,7 +53,7 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
#include <media/saa7127.h>
@@ -237,6 +237,7 @@ static struct i2c_reg_value saa7127_init_config_50hz[] = {
*/
struct saa7127_state {
+ struct v4l2_subdev sd;
v4l2_std_id std;
u32 ident;
enum saa7127_input_type input_type;
@@ -256,6 +257,11 @@ struct saa7127_state {
u8 reg_61;
};
+static inline struct saa7127_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct saa7127_state, sd);
+}
+
static const char * const output_strs[] =
{
"S-Video + Composite",
@@ -287,32 +293,35 @@ static const char * const wss_strs[] = {
/* ----------------------------------------------------------------------- */
-static int saa7127_read(struct i2c_client *client, u8 reg)
+static int saa7127_read(struct v4l2_subdev *sd, u8 reg)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
return i2c_smbus_read_byte_data(client, reg);
}
/* ----------------------------------------------------------------------- */
-static int saa7127_write(struct i2c_client *client, u8 reg, u8 val)
+static int saa7127_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int i;
for (i = 0; i < 3; i++) {
if (i2c_smbus_write_byte_data(client, reg, val) == 0)
return 0;
}
- v4l_err(client, "I2C Write Problem\n");
+ v4l2_err(sd, "I2C Write Problem\n");
return -1;
}
/* ----------------------------------------------------------------------- */
-static int saa7127_write_inittab(struct i2c_client *client,
+static int saa7127_write_inittab(struct v4l2_subdev *sd,
const struct i2c_reg_value *regs)
{
while (regs->reg != 0) {
- saa7127_write(client, regs->reg, regs->value);
+ saa7127_write(sd, regs->reg, regs->value);
regs++;
}
return 0;
@@ -320,16 +329,16 @@ static int saa7127_write_inittab(struct i2c_client *client,
/* ----------------------------------------------------------------------- */
-static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+static int saa7127_set_vps(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
{
- struct saa7127_state *state = i2c_get_clientdata(client);
+ struct saa7127_state *state = to_state(sd);
int enable = (data->line != 0);
if (enable && (data->field != 0 || data->line != 16))
return -EINVAL;
if (state->vps_enable != enable) {
- v4l_dbg(1, debug, client, "Turn VPS Signal %s\n", enable ? "on" : "off");
- saa7127_write(client, 0x54, enable << 7);
+ v4l2_dbg(1, debug, sd, "Turn VPS Signal %s\n", enable ? "on" : "off");
+ saa7127_write(sd, 0x54, enable << 7);
state->vps_enable = enable;
}
if (!enable)
@@ -340,91 +349,91 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat
state->vps_data[2] = data->data[9];
state->vps_data[3] = data->data[10];
state->vps_data[4] = data->data[11];
- v4l_dbg(1, debug, client, "Set VPS data %02x %02x %02x %02x %02x\n",
+ v4l2_dbg(1, debug, sd, "Set VPS data %02x %02x %02x %02x %02x\n",
state->vps_data[0], state->vps_data[1],
state->vps_data[2], state->vps_data[3],
state->vps_data[4]);
- saa7127_write(client, 0x55, state->vps_data[0]);
- saa7127_write(client, 0x56, state->vps_data[1]);
- saa7127_write(client, 0x57, state->vps_data[2]);
- saa7127_write(client, 0x58, state->vps_data[3]);
- saa7127_write(client, 0x59, state->vps_data[4]);
+ saa7127_write(sd, 0x55, state->vps_data[0]);
+ saa7127_write(sd, 0x56, state->vps_data[1]);
+ saa7127_write(sd, 0x57, state->vps_data[2]);
+ saa7127_write(sd, 0x58, state->vps_data[3]);
+ saa7127_write(sd, 0x59, state->vps_data[4]);
return 0;
}
/* ----------------------------------------------------------------------- */
-static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+static int saa7127_set_cc(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
{
- struct saa7127_state *state = i2c_get_clientdata(client);
+ struct saa7127_state *state = to_state(sd);
u16 cc = data->data[1] << 8 | data->data[0];
int enable = (data->line != 0);
if (enable && (data->field != 0 || data->line != 21))
return -EINVAL;
if (state->cc_enable != enable) {
- v4l_dbg(1, debug, client,
+ v4l2_dbg(1, debug, sd,
"Turn CC %s\n", enable ? "on" : "off");
- saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
+ saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
(state->xds_enable << 7) | (enable << 6) | 0x11);
state->cc_enable = enable;
}
if (!enable)
return 0;
- v4l_dbg(2, debug, client, "CC data: %04x\n", cc);
- saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
- saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
+ v4l2_dbg(2, debug, sd, "CC data: %04x\n", cc);
+ saa7127_write(sd, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
+ saa7127_write(sd, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
state->cc_data = cc;
return 0;
}
/* ----------------------------------------------------------------------- */
-static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+static int saa7127_set_xds(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
{
- struct saa7127_state *state = i2c_get_clientdata(client);
+ struct saa7127_state *state = to_state(sd);
u16 xds = data->data[1] << 8 | data->data[0];
int enable = (data->line != 0);
if (enable && (data->field != 1 || data->line != 21))
return -EINVAL;
if (state->xds_enable != enable) {
- v4l_dbg(1, debug, client, "Turn XDS %s\n", enable ? "on" : "off");
- saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
+ v4l2_dbg(1, debug, sd, "Turn XDS %s\n", enable ? "on" : "off");
+ saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
(enable << 7) | (state->cc_enable << 6) | 0x11);
state->xds_enable = enable;
}
if (!enable)
return 0;
- v4l_dbg(2, debug, client, "XDS data: %04x\n", xds);
- saa7127_write(client, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
- saa7127_write(client, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
+ v4l2_dbg(2, debug, sd, "XDS data: %04x\n", xds);
+ saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
+ saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
state->xds_data = xds;
return 0;
}
/* ----------------------------------------------------------------------- */
-static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+static int saa7127_set_wss(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
{
- struct saa7127_state *state = i2c_get_clientdata(client);
+ struct saa7127_state *state = to_state(sd);
int enable = (data->line != 0);
if (enable && (data->field != 0 || data->line != 23))
return -EINVAL;
if (state->wss_enable != enable) {
- v4l_dbg(1, debug, client, "Turn WSS %s\n", enable ? "on" : "off");
- saa7127_write(client, 0x27, enable << 7);
+ v4l2_dbg(1, debug, sd, "Turn WSS %s\n", enable ? "on" : "off");
+ saa7127_write(sd, 0x27, enable << 7);
state->wss_enable = enable;
}
if (!enable)
return 0;
- saa7127_write(client, 0x26, data->data[0]);
- saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
- v4l_dbg(1, debug, client,
+ saa7127_write(sd, 0x26, data->data[0]);
+ saa7127_write(sd, 0x27, 0x80 | (data->data[1] & 0x3f));
+ v4l2_dbg(1, debug, sd,
"WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
return 0;
@@ -432,18 +441,18 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat
/* ----------------------------------------------------------------------- */
-static int saa7127_set_video_enable(struct i2c_client *client, int enable)
+static int saa7127_set_video_enable(struct v4l2_subdev *sd, int enable)
{
- struct saa7127_state *state = i2c_get_clientdata(client);
+ struct saa7127_state *state = to_state(sd);
if (enable) {
- v4l_dbg(1, debug, client, "Enable Video Output\n");
- saa7127_write(client, 0x2d, state->reg_2d);
- saa7127_write(client, 0x61, state->reg_61);
+ v4l2_dbg(1, debug, sd, "Enable Video Output\n");
+ saa7127_write(sd, 0x2d, state->reg_2d);
+ saa7127_write(sd, 0x61, state->reg_61);
} else {
- v4l_dbg(1, debug, client, "Disable Video Output\n");
- saa7127_write(client, 0x2d, (state->reg_2d & 0xf0));
- saa7127_write(client, 0x61, (state->reg_61 | 0xc0));
+ v4l2_dbg(1, debug, sd, "Disable Video Output\n");
+ saa7127_write(sd, 0x2d, (state->reg_2d & 0xf0));
+ saa7127_write(sd, 0x61, (state->reg_61 | 0xc0));
}
state->video_enable = enable;
return 0;
@@ -451,32 +460,32 @@ static int saa7127_set_video_enable(struct i2c_client *client, int enable)
/* ----------------------------------------------------------------------- */
-static int saa7127_set_std(struct i2c_client *client, v4l2_std_id std)
+static int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
- struct saa7127_state *state = i2c_get_clientdata(client);
+ struct saa7127_state *state = to_state(sd);
const struct i2c_reg_value *inittab;
if (std & V4L2_STD_525_60) {
- v4l_dbg(1, debug, client, "Selecting 60 Hz video Standard\n");
+ v4l2_dbg(1, debug, sd, "Selecting 60 Hz video Standard\n");
inittab = saa7127_init_config_60hz;
state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
} else {
- v4l_dbg(1, debug, client, "Selecting 50 Hz video Standard\n");
+ v4l2_dbg(1, debug, sd, "Selecting 50 Hz video Standard\n");
inittab = saa7127_init_config_50hz;
state->reg_61 = SAA7127_50HZ_DAC_CONTROL;
}
/* Write Table */
- saa7127_write_inittab(client, inittab);
+ saa7127_write_inittab(sd, inittab);
state->std = std;
return 0;
}
/* ----------------------------------------------------------------------- */
-static int saa7127_set_output_type(struct i2c_client *client, int output)
+static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
{
- struct saa7127_state *state = i2c_get_clientdata(client);
+ struct saa7127_state *state = to_state(sd);
switch (output) {
case SAA7127_OUTPUT_TYPE_RGB:
@@ -512,165 +521,194 @@ static int saa7127_set_output_type(struct i2c_client *client, int output)
default:
return -EINVAL;
}
- v4l_dbg(1, debug, client,
+ v4l2_dbg(1, debug, sd,
"Selecting %s output type\n", output_strs[output]);
/* Configure Encoder */
- saa7127_write(client, 0x2d, state->reg_2d);
- saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb);
+ saa7127_write(sd, 0x2d, state->reg_2d);
+ saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
state->output_type = output;
return 0;
}
/* ----------------------------------------------------------------------- */
-static int saa7127_set_input_type(struct i2c_client *client, int input)
+static int saa7127_set_input_type(struct v4l2_subdev *sd, int input)
{
- struct saa7127_state *state = i2c_get_clientdata(client);
+ struct saa7127_state *state = to_state(sd);
switch (input) {
case SAA7127_INPUT_TYPE_NORMAL: /* avia */
- v4l_dbg(1, debug, client, "Selecting Normal Encoder Input\n");
+ v4l2_dbg(1, debug, sd, "Selecting Normal Encoder Input\n");
state->reg_3a_cb = 0;
break;
case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */
- v4l_dbg(1, debug, client, "Selecting Color Bar generator\n");
+ v4l2_dbg(1, debug, sd, "Selecting Color Bar generator\n");
state->reg_3a_cb = 0x80;
break;
default:
return -EINVAL;
}
- saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb);
+ saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
state->input_type = input;
return 0;
}
/* ----------------------------------------------------------------------- */
-static int saa7127_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
+static int saa7127_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
{
- struct saa7127_state *state = i2c_get_clientdata(client);
- struct v4l2_format *fmt = arg;
- struct v4l2_routing *route = arg;
-
- switch (cmd) {
- case VIDIOC_INT_S_STD_OUTPUT:
- if (state->std == *(v4l2_std_id *)arg)
- break;
- return saa7127_set_std(client, *(v4l2_std_id *)arg);
-
- case VIDIOC_INT_G_STD_OUTPUT:
- *(v4l2_std_id *)arg = state->std;
- break;
+ struct saa7127_state *state = to_state(sd);
- case VIDIOC_INT_G_VIDEO_ROUTING:
- route->input = state->input_type;
- route->output = state->output_type;
- break;
+ if (state->std == std)
+ return 0;
+ return saa7127_set_std(sd, std);
+}
- case VIDIOC_INT_S_VIDEO_ROUTING:
- {
- int rc = 0;
+static int saa7127_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+ struct saa7127_state *state = to_state(sd);
+ int rc = 0;
+
+ if (state->input_type != route->input)
+ rc = saa7127_set_input_type(sd, route->input);
+ if (rc == 0 && state->output_type != route->output)
+ rc = saa7127_set_output_type(sd, route->output);
+ return rc;
+}
- if (state->input_type != route->input)
- rc = saa7127_set_input_type(client, route->input);
- if (rc == 0 && state->output_type != route->output)
- rc = saa7127_set_output_type(client, route->output);
- return rc;
- }
+static int saa7127_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct saa7127_state *state = to_state(sd);
- case VIDIOC_STREAMON:
- case VIDIOC_STREAMOFF:
- if (state->video_enable == (cmd == VIDIOC_STREAMON))
- break;
- return saa7127_set_video_enable(client, cmd == VIDIOC_STREAMON);
-
- case VIDIOC_G_FMT:
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
-
- memset(&fmt->fmt.sliced, 0, sizeof(fmt->fmt.sliced));
- if (state->vps_enable)
- fmt->fmt.sliced.service_lines[0][16] = V4L2_SLICED_VPS;
- if (state->wss_enable)
- fmt->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
- if (state->cc_enable) {
- fmt->fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525;
- fmt->fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525;
- }
- fmt->fmt.sliced.service_set =
- (state->vps_enable ? V4L2_SLICED_VPS : 0) |
- (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
- (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
- break;
+ if (state->video_enable == enable)
+ return 0;
+ return saa7127_set_video_enable(sd, enable);
+}
- case VIDIOC_LOG_STATUS:
- v4l_info(client, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
- v4l_info(client, "Input: %s\n", state->input_type ? "color bars" : "normal");
- v4l_info(client, "Output: %s\n", state->video_enable ?
- output_strs[state->output_type] : "disabled");
- v4l_info(client, "WSS: %s\n", state->wss_enable ?
- wss_strs[state->wss_mode] : "disabled");
- v4l_info(client, "VPS: %s\n", state->vps_enable ? "enabled" : "disabled");
- v4l_info(client, "CC: %s\n", state->cc_enable ? "enabled" : "disabled");
- break;
+static int saa7127_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+ struct saa7127_state *state = to_state(sd);
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (!v4l2_chip_match_i2c_client(client,
- reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (cmd == VIDIOC_DBG_G_REGISTER)
- reg->val = saa7127_read(client, reg->reg & 0xff);
- else
- saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
- break;
- }
-#endif
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
- case VIDIOC_INT_S_VBI_DATA:
- {
- struct v4l2_sliced_vbi_data *data = arg;
-
- switch (data->id) {
- case V4L2_SLICED_WSS_625:
- return saa7127_set_wss(client, data);
- case V4L2_SLICED_VPS:
- return saa7127_set_vps(client, data);
- case V4L2_SLICED_CAPTION_525:
- if (data->field == 0)
- return saa7127_set_cc(client, data);
- return saa7127_set_xds(client, data);
- default:
- return -EINVAL;
- }
- break;
+ memset(&fmt->fmt.sliced, 0, sizeof(fmt->fmt.sliced));
+ if (state->vps_enable)
+ fmt->fmt.sliced.service_lines[0][16] = V4L2_SLICED_VPS;
+ if (state->wss_enable)
+ fmt->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+ if (state->cc_enable) {
+ fmt->fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+ fmt->fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525;
}
+ fmt->fmt.sliced.service_set =
+ (state->vps_enable ? V4L2_SLICED_VPS : 0) |
+ (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
+ (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
+ return 0;
+}
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0);
-
+static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
+{
+ switch (data->id) {
+ case V4L2_SLICED_WSS_625:
+ return saa7127_set_wss(sd, data);
+ case V4L2_SLICED_VPS:
+ return saa7127_set_vps(sd, data);
+ case V4L2_SLICED_CAPTION_525:
+ if (data->field == 0)
+ return saa7127_set_cc(sd, data);
+ return saa7127_set_xds(sd, data);
default:
return -EINVAL;
}
return 0;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->val = saa7127_read(sd, reg->reg & 0xff);
+ reg->size = 1;
+ return 0;
+}
+
+static int saa7127_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ saa7127_write(sd, reg->reg & 0xff, reg->val & 0xff);
+ return 0;
+}
+#endif
+
+static int saa7127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct saa7127_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
+}
+
+static int saa7127_log_status(struct v4l2_subdev *sd)
+{
+ struct saa7127_state *state = to_state(sd);
+
+ v4l2_info(sd, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
+ v4l2_info(sd, "Input: %s\n", state->input_type ? "color bars" : "normal");
+ v4l2_info(sd, "Output: %s\n", state->video_enable ?
+ output_strs[state->output_type] : "disabled");
+ v4l2_info(sd, "WSS: %s\n", state->wss_enable ?
+ wss_strs[state->wss_mode] : "disabled");
+ v4l2_info(sd, "VPS: %s\n", state->vps_enable ? "enabled" : "disabled");
+ v4l2_info(sd, "CC: %s\n", state->cc_enable ? "enabled" : "disabled");
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa7127_core_ops = {
+ .log_status = saa7127_log_status,
+ .g_chip_ident = saa7127_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = saa7127_g_register,
+ .s_register = saa7127_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops saa7127_video_ops = {
+ .s_vbi_data = saa7127_s_vbi_data,
+ .g_fmt = saa7127_g_fmt,
+ .s_std_output = saa7127_s_std_output,
+ .s_routing = saa7127_s_routing,
+ .s_stream = saa7127_s_stream,
+};
+
+static const struct v4l2_subdev_ops saa7127_ops = {
+ .core = &saa7127_core_ops,
+ .video = &saa7127_video_ops,
+};
+
/* ----------------------------------------------------------------------- */
static int saa7127_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct saa7127_state *state;
+ struct v4l2_subdev *sd;
struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */
/* Check if the adapter supports the needed features */
@@ -684,40 +722,42 @@ static int saa7127_probe(struct i2c_client *client,
v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
client->addr << 1);
+ state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
+ if (state == NULL)
+ return -ENOMEM;
+
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &saa7127_ops);
+
/* First test register 0: Bits 5-7 are a version ID (should be 0),
and bit 2 should also be 0.
This is rather general, so the second test is more specific and
looks at the 'ending point of burst in clock cycles' which is
0x1d after a reset and not expected to ever change. */
- if ((saa7127_read(client, 0) & 0xe4) != 0 ||
- (saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
- v4l_dbg(1, debug, client, "saa7127 not found\n");
+ if ((saa7127_read(sd, 0) & 0xe4) != 0 ||
+ (saa7127_read(sd, 0x29) & 0x3f) != 0x1d) {
+ v4l2_dbg(1, debug, sd, "saa7127 not found\n");
+ kfree(state);
return -ENODEV;
}
- state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
-
- if (state == NULL)
- return -ENOMEM;
-
- i2c_set_clientdata(client, state);
/* Configure Encoder */
- v4l_dbg(1, debug, client, "Configuring encoder\n");
- saa7127_write_inittab(client, saa7127_init_config_common);
- saa7127_set_std(client, V4L2_STD_NTSC);
- saa7127_set_output_type(client, SAA7127_OUTPUT_TYPE_BOTH);
- saa7127_set_vps(client, &vbi);
- saa7127_set_wss(client, &vbi);
- saa7127_set_cc(client, &vbi);
- saa7127_set_xds(client, &vbi);
+ v4l2_dbg(1, debug, sd, "Configuring encoder\n");
+ saa7127_write_inittab(sd, saa7127_init_config_common);
+ saa7127_set_std(sd, V4L2_STD_NTSC);
+ saa7127_set_output_type(sd, SAA7127_OUTPUT_TYPE_BOTH);
+ saa7127_set_vps(sd, &vbi);
+ saa7127_set_wss(sd, &vbi);
+ saa7127_set_cc(sd, &vbi);
+ saa7127_set_xds(sd, &vbi);
if (test_image == 1)
/* The Encoder has an internal Colorbar generator */
/* This can be used for debugging */
- saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE);
+ saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_TEST_IMAGE);
else
- saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL);
- saa7127_set_video_enable(client, 1);
+ saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL);
+ saa7127_set_video_enable(sd, 1);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
if (id->driver_data) { /* Chip type is already known */
@@ -729,10 +769,10 @@ static int saa7127_probe(struct i2c_client *client,
int read_result;
/* Detect if it's an saa7129 */
- read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
- saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
- if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
- saa7127_write(client, SAA7129_REG_FADE_KEY_COL2,
+ read_result = saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2);
+ saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, 0xaa);
+ if (saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
+ saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2,
read_result);
state->ident = V4L2_IDENT_SAA7129;
strlcpy(client->name, "saa7129", I2C_NAME_SIZE);
@@ -742,10 +782,10 @@ static int saa7127_probe(struct i2c_client *client,
}
}
- v4l_info(client, "%s found @ 0x%x (%s)\n", client->name,
+ v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
client->addr << 1, client->adapter->name);
if (state->ident == V4L2_IDENT_SAA7129)
- saa7127_write_inittab(client, saa7129_init_config_extra);
+ saa7127_write_inittab(sd, saa7129_init_config_extra);
return 0;
}
@@ -753,9 +793,12 @@ static int saa7127_probe(struct i2c_client *client,
static int saa7127_remove(struct i2c_client *client)
{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
/* Turn off TV output */
- saa7127_set_video_enable(client, 0);
- kfree(i2c_get_clientdata(client));
+ saa7127_set_video_enable(sd, 0);
+ kfree(to_state(sd));
return 0;
}
@@ -776,7 +819,6 @@ MODULE_DEVICE_TABLE(i2c, saa7127_id);
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "saa7127",
.driverid = I2C_DRIVERID_SAA7127,
- .command = saa7127_command,
.probe = saa7127_probe,
.remove = saa7127_remove,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
diff --git a/linux/drivers/media/video/saa7134/Kconfig b/linux/drivers/media/video/saa7134/Kconfig
index 7021bbf58..fc2164e28 100644
--- a/linux/drivers/media/video/saa7134/Kconfig
+++ b/linux/drivers/media/video/saa7134/Kconfig
@@ -34,9 +34,9 @@ config VIDEO_SAA7134_DVB
select DVB_NXT200X if !DVB_FE_CUSTOMISE
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
select DVB_TDA826X if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
diff --git a/linux/drivers/media/video/saa7134/saa6752hs.c b/linux/drivers/media/video/saa7134/saa6752hs.c
index 8ccca4d56..f2d4aea16 100644
--- a/linux/drivers/media/video/saa7134/saa6752hs.c
+++ b/linux/drivers/media/video/saa7134/saa6752hs.c
@@ -839,7 +839,7 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
h->standard = *((v4l2_std_id *) arg);
break;
- case VIDIOC_G_CHIP_IDENT:
+ case VIDIOC_DBG_G_CHIP_IDENT:
return v4l2_chip_ident_i2c_client(client,
arg, h->chip, h->revision);
diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c
index d4c432cb3..12893f09b 100644
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c
@@ -4501,6 +4501,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .mpeg = SAA7134_MPEG_DVB,
.inputs = {{
.name = name_tv,
.vmux = 3,
@@ -4519,8 +4520,6 @@ struct saa7134_board saa7134_boards[] = {
.name = name_radio,
.amux = LINE2,
},
- /* no DVB support for now */
- /* .mpeg = SAA7134_MPEG_DVB, */
},
[SAA7134_BOARD_ASUSTeK_TIGER_3IN1] = {
.name = "Asus Tiger 3in1",
@@ -4645,6 +4644,75 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x0200000,
},
},
+ [SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG] = {
+ .name = "Kworld Plus TV Analog Lite PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_YMEC_TVF_5533MF,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x80000700,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .tv = 1,
+ .gpio = 0x100,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x200,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x200,
+ } },
+ .radio = {
+ .name = name_radio,
+ .vmux = 1,
+ .amux = LINE1,
+ .gpio = 0x100,
+ },
+ .mute = {
+ .name = name_mute,
+ .vmux = 8,
+ .amux = 2,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS] = {
+ .name = "Avermedia AVerTV GO 007 FM Plus",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00300003,
+ /* .gpiomask = 0x8c240003, */
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x01,
+ }, {
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE1,
+ .gpio = 0x02,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x00300001,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x01,
+ },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4775,6 +4843,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.driver_data = SAA7134_BOARD_MD7134,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x16be, /* CTX946 analog TV, HW mpeg, DVB-T */
+ .subdevice = 0x5000, /* only analog TV and DVB-T for now */
+ .driver_data = SAA7134_BOARD_MD7134,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
.subvendor = 0x1048,
.subdevice = 0x226b,
@@ -5692,6 +5766,19 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x4878, /* REV:1.02G */
.driver_data = SAA7134_BOARD_ASUSTeK_TIGER_3IN1,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x17de,
+ .subdevice = 0x7128,
+ .driver_data = SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf31d,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS,
+
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -5979,6 +6066,8 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_507_9FM:
case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
case SAA7134_BOARD_REAL_ANGEL_220:
+ case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_FLYDVBS_LR300:
@@ -6078,6 +6167,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_M6:
case SAA7134_BOARD_BEHOLD_M63:
case SAA7134_BOARD_BEHOLD_M6_EXTRA:
+ case SAA7134_BOARD_BEHOLD_H6:
dev->has_remote = SAA7134_REMOTE_I2C;
break;
case SAA7134_BOARD_AVERMEDIA_A169_B:
diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c
index 704442f55..0bbb97b1b 100644
--- a/linux/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c
@@ -49,6 +49,8 @@
#include "lnbp21.h"
#include "tuner-simple.h"
+#include "zl10353.h"
+
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
@@ -854,6 +856,12 @@ static struct tda1004x_config ads_tech_duo_config = {
.request_firmware = philips_tda1004x_request_firmware
};
+static struct zl10353_config behold_h6_config = {
+ .demod_address = 0x1e>>1,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+};
+
/* ==================================================================
* tda10086 based DVB-S cards, helper functions
*/
@@ -1361,6 +1369,16 @@ static int dvb_init(struct saa7134_dev *dev)
&tda827x_cfg_0) < 0)
goto dettach_frontend;
break;
+ case SAA7134_BOARD_BEHOLD_H6:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &behold_h6_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216ME_MK3);
+ }
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c
index 53de5545c..6955db2fe 100644
--- a/linux/drivers/media/video/saa7134/saa7134-empress.c
+++ b/linux/drivers/media/video/saa7134/saa7134-empress.c
@@ -83,9 +83,9 @@ static int ts_init_encoder(struct saa7134_dev* dev)
/* ------------------------------------------------------------------ */
-static int ts_open(struct inode *inode, struct file *file)
+static int ts_open(struct file *file)
{
- int minor = iminor(inode);
+ int minor = video_devdata(file)->minor;
struct saa7134_dev *dev;
int err;
@@ -119,7 +119,7 @@ done:
return err;
}
-static int ts_release(struct inode *inode, struct file *file)
+static int ts_release(struct file *file)
{
struct saa7134_dev *dev = file->private_data;
@@ -405,7 +405,7 @@ static int empress_querymenu(struct file *file, void *priv,
}
static int empress_g_chip_ident(struct file *file, void *fh,
- struct v4l2_chip_ident *chip)
+ struct v4l2_dbg_chip_ident *chip)
{
struct saa7134_dev *dev = file->private_data;
@@ -413,12 +413,12 @@ static int empress_g_chip_ident(struct file *file, void *fh,
chip->revision = 0;
if (dev->mpeg_i2c_client == NULL)
return -EINVAL;
- if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER &&
- chip->match_chip == I2C_DRIVERID_SAA6752HS)
- return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip);
- if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR &&
- chip->match_chip == dev->mpeg_i2c_client->addr)
- return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip);
+ if (chip->match.type == V4L2_CHIP_MATCH_I2C_DRIVER &&
+ !strcmp(chip->match.name, "saa6752hs"))
+ return saa7134_i2c_call_saa6752(dev, VIDIOC_DBG_G_CHIP_IDENT, chip);
+ if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR &&
+ chip->match.addr == dev->mpeg_i2c_client->addr)
+ return saa7134_i2c_call_saa6752(dev, VIDIOC_DBG_G_CHIP_IDENT, chip);
return -EINVAL;
}
@@ -437,7 +437,7 @@ static int empress_g_std(struct file *file, void *priv, v4l2_std_id *id)
return 0;
}
-static const struct file_operations ts_fops =
+static const struct v4l2_file_operations ts_fops =
{
.owner = THIS_MODULE,
.open = ts_open,
@@ -446,7 +446,6 @@ static const struct file_operations ts_fops =
.poll = ts_poll,
.mmap = ts_mmap,
.ioctl = video_ioctl2,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops ts_ioctl_ops = {
diff --git a/linux/drivers/media/video/saa7134/saa7134-i2c.c b/linux/drivers/media/video/saa7134/saa7134-i2c.c
index df97ac987..3f7d4eb80 100644
--- a/linux/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/linux/drivers/media/video/saa7134/saa7134-i2c.c
@@ -358,6 +358,9 @@ static int attach_inform(struct i2c_client *client)
static struct i2c_algorithm saa7134_algo = {
.master_xfer = saa7134_i2c_xfer,
.functionality = functionality,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static struct i2c_adapter saa7134_adap_template = {
diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c
index 1c4bd413e..3c55ca44a 100644
--- a/linux/drivers/media/video/saa7134/saa7134-input.c
+++ b/linux/drivers/media/video/saa7134/saa7134-input.c
@@ -97,6 +97,15 @@ static int build_key(struct saa7134_dev *dev)
dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
gpio, ir->mask_keycode, data);
+ switch (dev->board) {
+ case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+ if (data == ir->mask_keycode)
+ ir_input_nokey(ir->dev, &ir->ir);
+ else
+ ir_input_keydown(ir->dev, &ir->ir, data, data);
+ return 0;
+ }
+
if (ir->polling) {
if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
(ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
@@ -440,6 +449,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
case SAA7134_BOARD_AVERMEDIA_M102:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
ir_codes = ir_codes_avermedia;
mask_keycode = 0x0007C8;
mask_keydown = 0x000010;
@@ -586,6 +596,11 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keyup = 0x4000;
polling = 50; /* ms */
break;
+ case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+ ir_codes = ir_codes_kworld_plus_tv_analog;
+ mask_keycode = 0x7f;
+ polling = 40; /* ms */
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
diff --git a/linux/drivers/media/video/saa7134/saa7134-video.c b/linux/drivers/media/video/saa7134/saa7134-video.c
index 884ef90c3..37dec30a4 100644
--- a/linux/drivers/media/video/saa7134/saa7134-video.c
+++ b/linux/drivers/media/video/saa7134/saa7134-video.c
@@ -1326,9 +1326,9 @@ static int saa7134_resource(struct saa7134_fh *fh)
return 0;
}
-static int video_open(struct inode *inode, struct file *file)
+static int video_open(struct file *file)
{
- int minor = iminor(inode);
+ int minor = video_devdata(file)->minor;
struct saa7134_dev *dev;
struct saa7134_fh *fh;
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -1462,7 +1462,7 @@ err:
return POLLERR;
}
-static int video_release(struct inode *inode, struct file *file)
+static int video_release(struct file *file)
{
struct saa7134_fh *fh = file->private_data;
struct saa7134_dev *dev = fh->dev;
@@ -2254,24 +2254,25 @@ static int saa7134_g_parm(struct file *file, void *fh,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register (struct file *file, void *priv,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
reg->val = saa_readb(reg->reg);
+ reg->size = 1;
return 0;
}
static int vidioc_s_register (struct file *file, void *priv,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
saa_writeb(reg->reg&0xffffff, reg->val);
return 0;
@@ -2384,7 +2385,7 @@ static int radio_queryctrl(struct file *file, void *priv,
return 0;
}
-static const struct file_operations video_fops =
+static const struct v4l2_file_operations video_fops =
{
.owner = THIS_MODULE,
.open = video_open,
@@ -2393,8 +2394,6 @@ static const struct file_operations video_fops =
.poll = video_poll,
.mmap = video_mmap,
.ioctl = video_ioctl2,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -2448,13 +2447,11 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
#endif
};
-static const struct file_operations radio_fops = {
+static const struct v4l2_file_operations radio_fops = {
.owner = THIS_MODULE,
.open = video_open,
.release = video_release,
.ioctl = video_ioctl2,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h
index 82f9a889a..bb973d363 100644
--- a/linux/drivers/media/video/saa7134/saa7134.h
+++ b/linux/drivers/media/video/saa7134/saa7134.h
@@ -276,6 +276,8 @@ struct saa7134_format {
#define SAA7134_BOARD_REAL_ANGEL_220 150
#define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI 151
#define SAA7134_BOARD_ASUSTeK_TIGER 152
+#define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153
+#define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
diff --git a/linux/drivers/media/video/saa717x.c b/linux/drivers/media/video/saa717x.c
index b0751c195..65bcf6dad 100644
--- a/linux/drivers/media/video/saa717x.c
+++ b/linux/drivers/media/video/saa717x.c
@@ -37,7 +37,7 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-i2c-drv.h>
#include "compat.h"
@@ -60,6 +60,7 @@ I2C_CLIENT_INSMOD;
#endif
struct saa717x_state {
+ struct v4l2_subdev sd;
v4l2_std_id std;
int input;
int enable;
@@ -81,6 +82,11 @@ struct saa717x_state {
int audio_input;
};
+static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct saa717x_state, sd);
+}
+
/* ----------------------------------------------------------------------- */
/* for audio mode */
@@ -94,8 +100,9 @@ struct saa717x_state {
/* ----------------------------------------------------------------------- */
-static int saa717x_write(struct i2c_client *client, u32 reg, u32 value)
+static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct i2c_adapter *adap = client->adapter;
int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
unsigned char mm1[6];
@@ -115,20 +122,21 @@ static int saa717x_write(struct i2c_client *client, u32 reg, u32 value)
}
msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
msg.buf = mm1;
- v4l_dbg(2, debug, client, "wrote: reg 0x%03x=%08x\n", reg, value);
+ v4l2_dbg(2, debug, sd, "wrote: reg 0x%03x=%08x\n", reg, value);
return i2c_transfer(adap, &msg, 1) == 1;
}
-static void saa717x_write_regs(struct i2c_client *client, u32 *data)
+static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data)
{
while (data[0] || data[1]) {
- saa717x_write(client, data[0], data[1]);
+ saa717x_write(sd, data[0], data[1]);
data += 2;
}
}
-static u32 saa717x_read(struct i2c_client *client, u32 reg)
+static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct i2c_adapter *adap = client->adapter;
int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
unsigned char mm1[2];
@@ -152,7 +160,7 @@ static u32 saa717x_read(struct i2c_client *client, u32 reg)
else
value = mm2[0] & 0xff;
- v4l_dbg(2, debug, client, "read: reg 0x%03x=0x%08x\n", reg, value);
+ v4l2_dbg(2, debug, sd, "read: reg 0x%03x=0x%08x\n", reg, value);
return value;
}
@@ -686,7 +694,7 @@ static u32 reg_set_audio_template[4][2] =
/* Get detected audio flags (from saa7134 driver) */
-static void get_inf_dev_status(struct i2c_client *client,
+static void get_inf_dev_status(struct v4l2_subdev *sd,
int *dual_flag, int *stereo_flag)
{
u32 reg_data3;
@@ -725,13 +733,13 @@ static void get_inf_dev_status(struct i2c_client *client,
/* (demdec status: 0x528) */
/* read current status */
- reg_data3 = saa717x_read(client, 0x0528);
+ reg_data3 = saa717x_read(sd, 0x0528);
- v4l_dbg(1, debug, client, "tvaudio thread status: 0x%x [%s%s%s]\n",
+ v4l2_dbg(1, debug, sd, "tvaudio thread status: 0x%x [%s%s%s]\n",
reg_data3, stdres[reg_data3 & 0x1f],
(reg_data3 & 0x000020) ? ",stereo" : "",
(reg_data3 & 0x000040) ? ",dual" : "");
- v4l_dbg(1, debug, client, "detailed status: "
+ v4l2_dbg(1, debug, sd, "detailed status: "
"%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
(reg_data3 & 0x000080) ? " A2/EIAJ pilot tone " : "",
(reg_data3 & 0x000100) ? " A2/EIAJ dual " : "",
@@ -752,51 +760,51 @@ static void get_inf_dev_status(struct i2c_client *client,
(reg_data3 & 0x100000) ? " init done " : "");
if (reg_data3 & 0x000220) {
- v4l_dbg(1, debug, client, "ST!!!\n");
+ v4l2_dbg(1, debug, sd, "ST!!!\n");
*stereo_flag = 1;
}
if (reg_data3 & 0x000140) {
- v4l_dbg(1, debug, client, "DUAL!!!\n");
+ v4l2_dbg(1, debug, sd, "DUAL!!!\n");
*dual_flag = 1;
}
}
/* regs write to set audio mode */
-static void set_audio_mode(struct i2c_client *client, int audio_mode)
+static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
{
- v4l_dbg(1, debug, client, "writing registers to set audio mode by set %d\n",
+ v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n",
audio_mode);
- saa717x_write(client, 0x46c, reg_set_audio_template[audio_mode][0]);
- saa717x_write(client, 0x470, reg_set_audio_template[audio_mode][1]);
+ saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]);
+ saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
}
/* write regs to video output level (bright,contrast,hue,sat) */
-static void set_video_output_level_regs(struct i2c_client *client,
+static void set_video_output_level_regs(struct v4l2_subdev *sd,
struct saa717x_state *decoder)
{
/* brightness ffh (bright) - 80h (ITU level) - 00h (dark) */
- saa717x_write(client, 0x10a, decoder->bright);
+ saa717x_write(sd, 0x10a, decoder->bright);
/* contrast 7fh (max: 1.984) - 44h (ITU) - 40h (1.0) -
0h (luminance off) 40: i2c dump
c0h (-1.0 inverse chrominance)
80h (-2.0 inverse chrominance) */
- saa717x_write(client, 0x10b, decoder->contrast);
+ saa717x_write(sd, 0x10b, decoder->contrast);
/* saturation? 7fh(max)-40h(ITU)-0h(color off)
c0h (-1.0 inverse chrominance)
80h (-2.0 inverse chrominance) */
- saa717x_write(client, 0x10c, decoder->sat);
+ saa717x_write(sd, 0x10c, decoder->sat);
/* color hue (phase) control
7fh (+178.6) - 0h (0 normal) - 80h (-180.0) */
- saa717x_write(client, 0x10d, decoder->hue);
+ saa717x_write(sd, 0x10d, decoder->hue);
}
/* write regs to set audio volume, bass and treble */
-static int set_audio_regs(struct i2c_client *client,
+static int set_audio_regs(struct v4l2_subdev *sd,
struct saa717x_state *decoder)
{
u8 mute = 0xac; /* -84 dB */
@@ -804,8 +812,8 @@ static int set_audio_regs(struct i2c_client *client,
unsigned int work_l, work_r;
/* set SIF analog I/O select */
- saa717x_write(client, 0x0594, decoder->audio_input);
- v4l_dbg(1, debug, client, "set audio input %d\n",
+ saa717x_write(sd, 0x0594, decoder->audio_input);
+ v4l2_dbg(1, debug, sd, "set audio input %d\n",
decoder->audio_input);
/* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
@@ -825,17 +833,17 @@ static int set_audio_regs(struct i2c_client *client,
((u8)decoder->audio_main_vol_r << 8);
}
- saa717x_write(client, 0x480, val);
+ saa717x_write(sd, 0x480, val);
/* bass and treble; go to another function */
/* set bass and treble */
val = decoder->audio_main_bass | (decoder->audio_main_treble << 8);
- saa717x_write(client, 0x488, val);
+ saa717x_write(sd, 0x488, val);
return 0;
}
/********** scaling staff ***********/
-static void set_h_prescale(struct i2c_client *client,
+static void set_h_prescale(struct v4l2_subdev *sd,
int task, int prescale)
{
static const struct {
@@ -868,107 +876,101 @@ static void set_h_prescale(struct i2c_client *client,
return;
/* horizonal prescaling */
- saa717x_write(client, 0x60 + task_shift, vals[i].xpsc);
+ saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc);
/* accumulation length */
- saa717x_write(client, 0x61 + task_shift, vals[i].xacl);
+ saa717x_write(sd, 0x61 + task_shift, vals[i].xacl);
/* level control */
- saa717x_write(client, 0x62 + task_shift,
+ saa717x_write(sd, 0x62 + task_shift,
(vals[i].xc2_1 << 3) | vals[i].xdcg);
/*FIR prefilter control */
- saa717x_write(client, 0x63 + task_shift,
+ saa717x_write(sd, 0x63 + task_shift,
(vals[i].vpfy << 2) | vals[i].vpfy);
}
/********** scaling staff ***********/
-static void set_v_scale(struct i2c_client *client, int task, int yscale)
+static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
{
int task_shift;
task_shift = task * 0x40;
/* Vertical scaling ratio (LOW) */
- saa717x_write(client, 0x70 + task_shift, yscale & 0xff);
+ saa717x_write(sd, 0x70 + task_shift, yscale & 0xff);
/* Vertical scaling ratio (HI) */
- saa717x_write(client, 0x71 + task_shift, yscale >> 8);
-}
-
-static int saa717x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
-{
- /* not yet implament, so saa717x_cfg_??hz_??_audio is not defined. */
- return 0;
+ saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
}
-static int saa717x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int saa717x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct saa717x_state *state = i2c_get_clientdata(client);
+ struct saa717x_state *state = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
if (ctrl->value < 0 || ctrl->value > 255) {
- v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
+ v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
return -ERANGE;
}
state->bright = ctrl->value;
- v4l_dbg(1, debug, client, "bright:%d\n", state->bright);
- saa717x_write(client, 0x10a, state->bright);
+ v4l2_dbg(1, debug, sd, "bright:%d\n", state->bright);
+ saa717x_write(sd, 0x10a, state->bright);
break;
case V4L2_CID_CONTRAST:
if (ctrl->value < 0 || ctrl->value > 127) {
- v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
+ v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
return -ERANGE;
}
state->contrast = ctrl->value;
- v4l_dbg(1, debug, client, "contrast:%d\n", state->contrast);
- saa717x_write(client, 0x10b, state->contrast);
+ v4l2_dbg(1, debug, sd, "contrast:%d\n", state->contrast);
+ saa717x_write(sd, 0x10b, state->contrast);
break;
case V4L2_CID_SATURATION:
if (ctrl->value < 0 || ctrl->value > 127) {
- v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
+ v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
return -ERANGE;
}
state->sat = ctrl->value;
- v4l_dbg(1, debug, client, "sat:%d\n", state->sat);
- saa717x_write(client, 0x10c, state->sat);
+ v4l2_dbg(1, debug, sd, "sat:%d\n", state->sat);
+ saa717x_write(sd, 0x10c, state->sat);
break;
case V4L2_CID_HUE:
if (ctrl->value < -127 || ctrl->value > 127) {
- v4l_err(client, "invalid hue setting %d\n", ctrl->value);
+ v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
return -ERANGE;
}
state->hue = ctrl->value;
- v4l_dbg(1, debug, client, "hue:%d\n", state->hue);
- saa717x_write(client, 0x10d, state->hue);
+ v4l2_dbg(1, debug, sd, "hue:%d\n", state->hue);
+ saa717x_write(sd, 0x10d, state->hue);
break;
case V4L2_CID_AUDIO_MUTE:
state->audio_main_mute = ctrl->value;
- set_audio_regs(client, state);
+ set_audio_regs(sd, state);
break;
case V4L2_CID_AUDIO_VOLUME:
state->audio_main_volume = ctrl->value;
- set_audio_regs(client, state);
+ set_audio_regs(sd, state);
break;
case V4L2_CID_AUDIO_BALANCE:
state->audio_main_balance = ctrl->value;
- set_audio_regs(client, state);
+ set_audio_regs(sd, state);
break;
case V4L2_CID_AUDIO_TREBLE:
state->audio_main_treble = ctrl->value;
- set_audio_regs(client, state);
+ set_audio_regs(sd, state);
break;
case V4L2_CID_AUDIO_BASS:
state->audio_main_bass = ctrl->value;
- set_audio_regs(client, state);
+ set_audio_regs(sd, state);
break;
default:
@@ -978,9 +980,9 @@ static int saa717x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
return 0;
}
-static int saa717x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int saa717x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct saa717x_state *state = i2c_get_clientdata(client);
+ struct saa717x_state *state = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
@@ -1109,13 +1111,15 @@ static struct v4l2_queryctrl saa717x_qctrl[] = {
},
};
-static int saa717x_set_video_input(struct i2c_client *client, struct saa717x_state *decoder, int inp)
+static int saa717x_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
{
+ struct saa717x_state *decoder = to_state(sd);
+ int inp = route->input;
int is_tuner = inp & 0x80; /* tuner input flag */
inp &= 0x7f;
- v4l_dbg(1, debug, client, "decoder set input (%d)\n", inp);
+ v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", inp);
/* inputs from 0-9 are available*/
/* saa717x have mode0-mode9 but mode5 is reserved. */
if (inp < 0 || inp > 9 || inp == 5)
@@ -1125,222 +1129,198 @@ static int saa717x_set_video_input(struct i2c_client *client, struct saa717x_sta
int input_line = inp;
decoder->input = input_line;
- v4l_dbg(1, debug, client, "now setting %s input %d\n",
+ v4l2_dbg(1, debug, sd, "now setting %s input %d\n",
input_line >= 6 ? "S-Video" : "Composite",
input_line);
/* select mode */
- saa717x_write(client, 0x102,
- (saa717x_read(client, 0x102) & 0xf0) |
+ saa717x_write(sd, 0x102,
+ (saa717x_read(sd, 0x102) & 0xf0) |
input_line);
/* bypass chrominance trap for modes 6..9 */
- saa717x_write(client, 0x109,
- (saa717x_read(client, 0x109) & 0x7f) |
+ saa717x_write(sd, 0x109,
+ (saa717x_read(sd, 0x109) & 0x7f) |
(input_line < 6 ? 0x0 : 0x80));
/* change audio_mode */
if (is_tuner) {
/* tuner */
- set_audio_mode(client, decoder->tuner_audio_mode);
+ set_audio_mode(sd, decoder->tuner_audio_mode);
} else {
/* Force to STEREO mode if Composite or
* S-Video were chosen */
- set_audio_mode(client, TUNER_AUDIO_STEREO);
+ set_audio_mode(sd, TUNER_AUDIO_STEREO);
}
/* change initialize procedure (Composite/S-Video) */
if (is_tuner)
- saa717x_write_regs(client, reg_init_tuner_input);
+ saa717x_write_regs(sd, reg_init_tuner_input);
else if (input_line >= 6)
- saa717x_write_regs(client, reg_init_svideo_input);
+ saa717x_write_regs(sd, reg_init_svideo_input);
else
- saa717x_write_regs(client, reg_init_composite_input);
+ saa717x_write_regs(sd, reg_init_composite_input);
}
return 0;
}
-static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int saa717x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
{
- struct saa717x_state *decoder = i2c_get_clientdata(client);
-
- v4l_dbg(1, debug, client, "IOCTL: %08x\n", cmd);
+ int i;
- switch (cmd) {
- case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- return saa717x_set_audio_clock_freq(client, *(u32 *)arg);
+ for (i = 0; i < ARRAY_SIZE(saa717x_qctrl); i++)
+ if (qc->id && qc->id == saa717x_qctrl[i].id) {
+ memcpy(qc, &saa717x_qctrl[i], sizeof(*qc));
+ return 0;
+ }
+ return -EINVAL;
+}
- case VIDIOC_G_CTRL:
- return saa717x_get_v4lctrl(client, (struct v4l2_control *)arg);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_S_CTRL:
- return saa717x_set_v4lctrl(client, (struct v4l2_control *)arg);
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->val = saa717x_read(sd, reg->reg);
+ reg->size = 1;
+ return 0;
+}
- case VIDIOC_QUERYCTRL: {
- struct v4l2_queryctrl *qc = arg;
- int i;
+static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u16 addr = reg->reg & 0xffff;
+ u8 val = reg->val & 0xff;
- for (i = 0; i < ARRAY_SIZE(saa717x_qctrl); i++)
- if (qc->id && qc->id == saa717x_qctrl[i].id) {
- memcpy(qc, &saa717x_qctrl[i], sizeof(*qc));
- return 0;
- }
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
return -EINVAL;
- }
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_DBG_G_REGISTER: {
- struct v4l2_register *reg = arg;
-
- if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- reg->val = saa717x_read(client, reg->reg);
- break;
- }
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ saa717x_write(sd, addr, val);
+ return 0;
+}
+#endif
- case VIDIOC_DBG_S_REGISTER: {
- struct v4l2_register *reg = arg;
- u16 addr = reg->reg & 0xffff;
- u8 val = reg->val & 0xff;
+static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+ struct v4l2_pix_format *pix;
+ int prescale, h_scale, v_scale;
- if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- saa717x_write(client, addr, val);
- break;
- }
-#endif
+ pix = &fmt->fmt.pix;
+ v4l2_dbg(1, debug, sd, "decoder set size\n");
- case VIDIOC_S_FMT: {
- struct v4l2_format *fmt = (struct v4l2_format *)arg;
- struct v4l2_pix_format *pix;
- int prescale, h_scale, v_scale;
-
- pix = &fmt->fmt.pix;
- v4l_dbg(1, debug, client, "decoder set size\n");
-
- /* FIXME need better bounds checking here */
- if (pix->width < 1 || pix->width > 1440)
- return -EINVAL;
- if (pix->height < 1 || pix->height > 960)
- return -EINVAL;
-
- /* scaling setting */
- /* NTSC and interlace only */
- prescale = SAA717X_NTSC_WIDTH / pix->width;
- if (prescale == 0)
- prescale = 1;
- h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
- /* interlace */
- v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
-
- /* Horizontal prescaling etc */
- set_h_prescale(client, 0, prescale);
- set_h_prescale(client, 1, prescale);
-
- /* Horizontal scaling increment */
- /* TASK A */
- saa717x_write(client, 0x6C, (u8)(h_scale & 0xFF));
- saa717x_write(client, 0x6D, (u8)((h_scale >> 8) & 0xFF));
- /* TASK B */
- saa717x_write(client, 0xAC, (u8)(h_scale & 0xFF));
- saa717x_write(client, 0xAD, (u8)((h_scale >> 8) & 0xFF));
-
- /* Vertical prescaling etc */
- set_v_scale(client, 0, v_scale);
- set_v_scale(client, 1, v_scale);
-
- /* set video output size */
- /* video number of pixels at output */
- /* TASK A */
- saa717x_write(client, 0x5C, (u8)(pix->width & 0xFF));
- saa717x_write(client, 0x5D, (u8)((pix->width >> 8) & 0xFF));
- /* TASK B */
- saa717x_write(client, 0x9C, (u8)(pix->width & 0xFF));
- saa717x_write(client, 0x9D, (u8)((pix->width >> 8) & 0xFF));
-
- /* video number of lines at output */
- /* TASK A */
- saa717x_write(client, 0x5E, (u8)(pix->height & 0xFF));
- saa717x_write(client, 0x5F, (u8)((pix->height >> 8) & 0xFF));
- /* TASK B */
- saa717x_write(client, 0x9E, (u8)(pix->height & 0xFF));
- saa717x_write(client, 0x9F, (u8)((pix->height >> 8) & 0xFF));
- break;
- }
+ /* FIXME need better bounds checking here */
+ if (pix->width < 1 || pix->width > 1440)
+ return -EINVAL;
+ if (pix->height < 1 || pix->height > 960)
+ return -EINVAL;
- case AUDC_SET_RADIO:
- decoder->radio = 1;
- break;
+ /* scaling setting */
+ /* NTSC and interlace only */
+ prescale = SAA717X_NTSC_WIDTH / pix->width;
+ if (prescale == 0)
+ prescale = 1;
+ h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
+ /* interlace */
+ v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
+
+ /* Horizontal prescaling etc */
+ set_h_prescale(sd, 0, prescale);
+ set_h_prescale(sd, 1, prescale);
+
+ /* Horizontal scaling increment */
+ /* TASK A */
+ saa717x_write(sd, 0x6C, (u8)(h_scale & 0xFF));
+ saa717x_write(sd, 0x6D, (u8)((h_scale >> 8) & 0xFF));
+ /* TASK B */
+ saa717x_write(sd, 0xAC, (u8)(h_scale & 0xFF));
+ saa717x_write(sd, 0xAD, (u8)((h_scale >> 8) & 0xFF));
+
+ /* Vertical prescaling etc */
+ set_v_scale(sd, 0, v_scale);
+ set_v_scale(sd, 1, v_scale);
+
+ /* set video output size */
+ /* video number of pixels at output */
+ /* TASK A */
+ saa717x_write(sd, 0x5C, (u8)(pix->width & 0xFF));
+ saa717x_write(sd, 0x5D, (u8)((pix->width >> 8) & 0xFF));
+ /* TASK B */
+ saa717x_write(sd, 0x9C, (u8)(pix->width & 0xFF));
+ saa717x_write(sd, 0x9D, (u8)((pix->width >> 8) & 0xFF));
+
+ /* video number of lines at output */
+ /* TASK A */
+ saa717x_write(sd, 0x5E, (u8)(pix->height & 0xFF));
+ saa717x_write(sd, 0x5F, (u8)((pix->height >> 8) & 0xFF));
+ /* TASK B */
+ saa717x_write(sd, 0x9E, (u8)(pix->height & 0xFF));
+ saa717x_write(sd, 0x9F, (u8)((pix->height >> 8) & 0xFF));
+ return 0;
+}
- case VIDIOC_S_STD: {
- v4l2_std_id std = *(v4l2_std_id *) arg;
+static int saa717x_s_radio(struct v4l2_subdev *sd)
+{
+ struct saa717x_state *decoder = to_state(sd);
- v4l_dbg(1, debug, client, "decoder set norm ");
- v4l_dbg(1, debug, client, "(not yet implementd)\n");
+ decoder->radio = 1;
+ return 0;
+}
- decoder->radio = 0;
- decoder->std = std;
- break;
- }
+static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct saa717x_state *decoder = to_state(sd);
- case VIDIOC_INT_G_AUDIO_ROUTING: {
- struct v4l2_routing *route = arg;
+ v4l2_dbg(1, debug, sd, "decoder set norm ");
+ v4l2_dbg(1, debug, sd, "(not yet implementd)\n");
- route->input = decoder->audio_input;
- route->output = 0;
- break;
- }
+ decoder->radio = 0;
+ decoder->std = std;
+ return 0;
+}
- case VIDIOC_INT_S_AUDIO_ROUTING: {
- struct v4l2_routing *route = arg;
+static int saa717x_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+ struct saa717x_state *decoder = to_state(sd);
- if (route->input < 3) { /* FIXME! --tadachi */
- decoder->audio_input = route->input;
- v4l_dbg(1, debug, client,
+ if (route->input < 3) { /* FIXME! --tadachi */
+ decoder->audio_input = route->input;
+ v4l2_dbg(1, debug, sd,
"set decoder audio input to %d\n",
decoder->audio_input);
- set_audio_regs(client, decoder);
- break;
- }
- return -ERANGE;
- }
-
- case VIDIOC_INT_S_VIDEO_ROUTING: {
- struct v4l2_routing *route = arg;
- int inp = route->input;
-
- return saa717x_set_video_input(client, decoder, inp);
+ set_audio_regs(sd, decoder);
+ return 0;
}
+ return -ERANGE;
+}
- case VIDIOC_STREAMON: {
- v4l_dbg(1, debug, client, "decoder enable output\n");
- decoder->enable = 1;
- saa717x_write(client, 0x193, 0xa6);
- break;
- }
+static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct saa717x_state *decoder = to_state(sd);
- case VIDIOC_STREAMOFF: {
- v4l_dbg(1, debug, client, "decoder disable output\n");
- decoder->enable = 0;
- saa717x_write(client, 0x193, 0x26); /* right? FIXME!--tadachi */
- break;
- }
+ v4l2_dbg(1, debug, sd, "decoder %s output\n",
+ enable ? "enable" : "disable");
+ decoder->enable = enable;
+ saa717x_write(sd, 0x193, enable ? 0xa6 : 0x26);
+ return 0;
+}
- /* change audio mode */
- case VIDIOC_S_TUNER: {
- struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
- int audio_mode;
- char *mes[4] = {
- "MONO", "STEREO", "LANG1", "LANG2/SAP"
- };
+/* change audio mode */
+static int saa717x_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct saa717x_state *decoder = to_state(sd);
+ int audio_mode;
+ char *mes[4] = {
+ "MONO", "STEREO", "LANG1", "LANG2/SAP"
+ };
- audio_mode = V4L2_TUNER_MODE_STEREO;
+ audio_mode = V4L2_TUNER_MODE_STEREO;
- switch (vt->audmode) {
+ switch (vt->audmode) {
case V4L2_TUNER_MODE_MONO:
audio_mode = TUNER_AUDIO_MONO;
break;
@@ -1353,70 +1333,101 @@ static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
case V4L2_TUNER_MODE_LANG1:
audio_mode = TUNER_AUDIO_LANG1;
break;
- }
-
- v4l_dbg(1, debug, client, "change audio mode to %s\n",
- mes[audio_mode]);
- decoder->tuner_audio_mode = audio_mode;
- /* The registers are not changed here. */
- /* See DECODER_ENABLE_OUTPUT section. */
- set_audio_mode(client, decoder->tuner_audio_mode);
- break;
}
- case VIDIOC_G_TUNER: {
- struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
- int dual_f, stereo_f;
+ v4l2_dbg(1, debug, sd, "change audio mode to %s\n",
+ mes[audio_mode]);
+ decoder->tuner_audio_mode = audio_mode;
+ /* The registers are not changed here. */
+ /* See DECODER_ENABLE_OUTPUT section. */
+ set_audio_mode(sd, decoder->tuner_audio_mode);
+ return 0;
+}
- if (decoder->radio)
- break;
- get_inf_dev_status(client, &dual_f, &stereo_f);
+static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct saa717x_state *decoder = to_state(sd);
+ int dual_f, stereo_f;
- v4l_dbg(1, debug, client, "DETECT==st:%d dual:%d\n",
- stereo_f, dual_f);
+ if (decoder->radio)
+ return 0;
+ get_inf_dev_status(sd, &dual_f, &stereo_f);
- /* mono */
- if ((dual_f == 0) && (stereo_f == 0)) {
- vt->rxsubchans = V4L2_TUNER_SUB_MONO;
- v4l_dbg(1, debug, client, "DETECT==MONO\n");
- }
+ v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n",
+ stereo_f, dual_f);
- /* stereo */
- if (stereo_f == 1) {
- if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
- vt->audmode == V4L2_TUNER_MODE_LANG1) {
- vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
- v4l_dbg(1, debug, client, "DETECT==ST(ST)\n");
- } else {
- vt->rxsubchans = V4L2_TUNER_SUB_MONO;
- v4l_dbg(1, debug, client, "DETECT==ST(MONO)\n");
- }
- }
+ /* mono */
+ if ((dual_f == 0) && (stereo_f == 0)) {
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+ v4l2_dbg(1, debug, sd, "DETECT==MONO\n");
+ }
- /* dual */
- if (dual_f == 1) {
- if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
- vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
- v4l_dbg(1, debug, client, "DETECT==DUAL1\n");
- } else {
- vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
- v4l_dbg(1, debug, client, "DETECT==DUAL2\n");
- }
+ /* stereo */
+ if (stereo_f == 1) {
+ if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
+ vt->audmode == V4L2_TUNER_MODE_LANG1) {
+ vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ v4l2_dbg(1, debug, sd, "DETECT==ST(ST)\n");
+ } else {
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+ v4l2_dbg(1, debug, sd, "DETECT==ST(MONO)\n");
}
- break;
}
- case VIDIOC_LOG_STATUS:
- /* not yet implemented */
- break;
-
- default:
- return -EINVAL;
+ /* dual */
+ if (dual_f == 1) {
+ if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
+ vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
+ v4l2_dbg(1, debug, sd, "DETECT==DUAL1\n");
+ } else {
+ vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
+ v4l2_dbg(1, debug, sd, "DETECT==DUAL2\n");
+ }
}
-
return 0;
}
+static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa717x_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = saa717x_g_register,
+ .s_register = saa717x_s_register,
+#endif
+ .queryctrl = saa717x_queryctrl,
+ .g_ctrl = saa717x_g_ctrl,
+ .s_ctrl = saa717x_s_ctrl,
+};
+
+static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
+ .g_tuner = saa717x_g_tuner,
+ .s_tuner = saa717x_s_tuner,
+ .s_std = saa717x_s_std,
+ .s_radio = saa717x_s_radio,
+};
+
+static const struct v4l2_subdev_video_ops saa717x_video_ops = {
+ .s_routing = saa717x_s_video_routing,
+ .s_fmt = saa717x_s_fmt,
+ .s_stream = saa717x_s_stream,
+};
+
+static const struct v4l2_subdev_audio_ops saa717x_audio_ops = {
+ .s_routing = saa717x_s_audio_routing,
+};
+
+static const struct v4l2_subdev_ops saa717x_ops = {
+ .core = &saa717x_core_ops,
+ .tuner = &saa717x_tuner_ops,
+ .audio = &saa717x_audio_ops,
+ .video = &saa717x_video_ops,
+};
+
/* ----------------------------------------------------------------------- */
@@ -1427,6 +1438,7 @@ static int saa717x_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct saa717x_state *decoder;
+ struct v4l2_subdev *sd;
u8 id = 0;
char *p = "";
@@ -1434,16 +1446,24 @@ static int saa717x_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+ decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
+ if (decoder == NULL)
+ return -ENOMEM;
+
+ sd = &decoder->sd;
+ v4l2_i2c_subdev_init(sd, client, &saa717x_ops);
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "saa717x");
#endif
- if (saa717x_write(client, 0x5a4, 0xfe) &&
- saa717x_write(client, 0x5a5, 0x0f) &&
- saa717x_write(client, 0x5a6, 0x00) &&
- saa717x_write(client, 0x5a7, 0x01))
- id = saa717x_read(client, 0x5a0);
+ if (saa717x_write(sd, 0x5a4, 0xfe) &&
+ saa717x_write(sd, 0x5a5, 0x0f) &&
+ saa717x_write(sd, 0x5a6, 0x00) &&
+ saa717x_write(sd, 0x5a7, 0x01))
+ id = saa717x_read(sd, 0x5a0);
if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
- v4l_dbg(1, debug, client, "saa717x not found (id=%02x)\n", id);
+ v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
+ kfree(decoder);
return -ENODEV;
}
if (id == 0xc2)
@@ -1454,14 +1474,8 @@ static int saa717x_probe(struct i2c_client *client,
p = "saa7174HL";
else
p = "saa7171";
- v4l_info(client, "%s found @ 0x%x (%s)\n", p,
+ v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
client->addr << 1, client->adapter->name);
-
- decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
- i2c_set_clientdata(client, decoder);
-
- if (decoder == NULL)
- return -ENOMEM;
decoder->std = V4L2_STD_NTSC;
decoder->input = -1;
decoder->enable = 1;
@@ -1490,15 +1504,15 @@ static int saa717x_probe(struct i2c_client *client,
decoder->audio_main_volume =
(decoder->audio_main_vol_r + 41) * 65535 / (24 - (-40));
- v4l_dbg(1, debug, client, "writing init values\n");
+ v4l2_dbg(1, debug, sd, "writing init values\n");
/* FIXME!! */
- saa717x_write_regs(client, reg_init_initialize);
- set_video_output_level_regs(client, decoder);
+ saa717x_write_regs(sd, reg_init_initialize);
+ set_video_output_level_regs(sd, decoder);
/* set bass,treble to 0db 20041101 K.Ohta */
decoder->audio_main_bass = 0;
decoder->audio_main_treble = 0;
- set_audio_regs(client, decoder);
+ set_audio_regs(sd, decoder);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(2*HZ);
@@ -1507,7 +1521,10 @@ static int saa717x_probe(struct i2c_client *client,
static int saa717x_remove(struct i2c_client *client)
{
- kfree(i2c_get_clientdata(client));
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
return 0;
}
diff --git a/linux/drivers/media/video/se401.c b/linux/drivers/media/video/se401.c
index 8935c1632..cca1cb0c4 100644
--- a/linux/drivers/media/video/se401.c
+++ b/linux/drivers/media/video/se401.c
@@ -940,7 +940,7 @@ static void usb_se401_remove_disconnected (struct usb_se401 *se401)
***************************************************************************/
-static int se401_open(struct inode *inode, struct file *file)
+static int se401_open(struct file *file)
{
struct video_device *dev = video_devdata(file);
struct usb_se401 *se401 = (struct usb_se401 *)dev;
@@ -962,7 +962,7 @@ static int se401_open(struct inode *inode, struct file *file)
return err;
}
-static int se401_close(struct inode *inode, struct file *file)
+static int se401_close(struct file *file)
{
struct video_device *dev = file->private_data;
struct usb_se401 *se401 = (struct usb_se401 *)dev;
@@ -983,7 +983,7 @@ static int se401_close(struct inode *inode, struct file *file)
return 0;
}
-static int se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = file->private_data;
struct usb_se401 *se401 = (struct usb_se401 *)vdev;
@@ -1146,7 +1146,7 @@ static int se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0;
}
-static int se401_ioctl(struct inode *inode, struct file *file,
+static long se401_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, se401_do_ioctl);
@@ -1230,17 +1230,13 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-static const struct file_operations se401_fops = {
+static const struct v4l2_file_operations se401_fops = {
.owner = THIS_MODULE,
.open = se401_open,
.release = se401_close,
.read = se401_read,
.mmap = se401_mmap,
.ioctl = se401_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static struct video_device se401_template = {
.name = "se401 USB camera",
diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c
index 2fb8bee0b..ae98eaf5f 100644
--- a/linux/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c
@@ -29,8 +29,8 @@
#include <linux/version.h>
#include <linux/device.h>
#include <linux/platform_device.h>
-#include <linux/mutex.h>
#include <linux/videodev2.h>
+#include <linux/clk.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
@@ -75,8 +75,6 @@
#define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */
#define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */
-static DEFINE_MUTEX(camera_lock);
-
/* per video frame buffer */
struct sh_mobile_ceu_buffer {
struct videobuf_buffer vb; /* v4l buffer must be first */
@@ -90,24 +88,27 @@ struct sh_mobile_ceu_dev {
unsigned int irq;
void __iomem *base;
+ struct clk *clk;
unsigned long video_limit;
/* lock used to protect videobuf */
spinlock_t lock;
struct list_head capture;
struct videobuf_buffer *active;
+ int is_interlace;
struct sh_mobile_ceu_info *pdata;
+
+ const struct soc_camera_data_format *camera_fmt;
};
static void ceu_write(struct sh_mobile_ceu_dev *priv,
- unsigned long reg_offs, unsigned long data)
+ unsigned long reg_offs, u32 data)
{
iowrite32(data, priv->base + reg_offs);
}
-static unsigned long ceu_read(struct sh_mobile_ceu_dev *priv,
- unsigned long reg_offs)
+static u32 ceu_read(struct sh_mobile_ceu_dev *priv, unsigned long reg_offs)
{
return ioread32(priv->base + reg_offs);
}
@@ -155,21 +156,52 @@ static void free_buffer(struct videobuf_queue *vq,
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
+#define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */
+#define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */
+#define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */
+#define CEU_CAPCR_CTNCP (1 << 16) /* continuous capture mode (if set) */
+
+
static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
{
- ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~1);
- ceu_write(pcdev, CETCR, ~ceu_read(pcdev, CETCR) & 0x0317f313);
- ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | 1);
-
- ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~0x10000);
+ struct soc_camera_device *icd = pcdev->icd;
+ dma_addr_t phys_addr_top, phys_addr_bottom;
- ceu_write(pcdev, CETCR, 0x0317f313 ^ 0x10);
+ /* The hardware is _very_ picky about this sequence. Especially
+ * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge
+ * several not-so-well documented interrupt sources in CETCR.
+ */
+ ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_CPEIE);
+ ceu_write(pcdev, CETCR, ~ceu_read(pcdev, CETCR) & CEU_CETCR_MAGIC);
+ ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_CPEIE);
+ ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP);
+ ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW);
+
+ if (!pcdev->active)
+ return;
+
+ phys_addr_top = videobuf_to_dma_contig(pcdev->active);
+ ceu_write(pcdev, CDAYR, phys_addr_top);
+ if (pcdev->is_interlace) {
+ phys_addr_bottom = phys_addr_top + icd->width;
+ ceu_write(pcdev, CDBYR, phys_addr_bottom);
+ }
- if (pcdev->active) {
- pcdev->active->state = VIDEOBUF_ACTIVE;
- ceu_write(pcdev, CDAYR, videobuf_to_dma_contig(pcdev->active));
- ceu_write(pcdev, CAPSR, 0x1); /* start capture */
+ switch (icd->current_fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ phys_addr_top += icd->width * icd->height;
+ ceu_write(pcdev, CDACR, phys_addr_top);
+ if (pcdev->is_interlace) {
+ phys_addr_bottom = phys_addr_top + icd->width;
+ ceu_write(pcdev, CDBCR, phys_addr_bottom);
+ }
}
+
+ pcdev->active->state = VIDEOBUF_ACTIVE;
+ ceu_write(pcdev, CAPSR, 0x1); /* start capture */
}
static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,
@@ -291,14 +323,13 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
return IRQ_HANDLED;
}
+/* Called with .video_lock held */
static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
int ret = -EBUSY;
- mutex_lock(&camera_lock);
-
if (pcdev->icd)
goto err;
@@ -310,17 +341,18 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
if (ret)
goto err;
+ clk_enable(pcdev->clk);
+
ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
while (ceu_read(pcdev, CSTSR) & 1)
msleep(1);
pcdev->icd = icd;
err:
- mutex_unlock(&camera_lock);
-
return ret;
}
+/* Called with .video_lock held */
static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
@@ -343,6 +375,8 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
}
spin_unlock_irqrestore(&pcdev->lock, flags);
+ clk_disable(pcdev->clk);
+
icd->ops->release(icd);
dev_info(&icd->dev,
@@ -357,8 +391,9 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- int ret, buswidth, width, cfszr_width, cdwdr_width;
+ int ret, buswidth, width, height, cfszr_width, cdwdr_width;
unsigned long camera_flags, common_flags, value;
+ int yuv_mode, yuv_lineskip;
camera_flags = icd->ops->query_bus_param(icd);
common_flags = soc_camera_bus_param_compatible(camera_flags,
@@ -384,27 +419,71 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
ceu_write(pcdev, CRCNTR, 0);
ceu_write(pcdev, CRCMPR, 0);
- value = 0x00000010;
- value |= (common_flags & SOCAM_VSYNC_ACTIVE_LOW) ? (1 << 1) : 0;
- value |= (common_flags & SOCAM_HSYNC_ACTIVE_LOW) ? (1 << 0) : 0;
- value |= (buswidth == 16) ? (1 << 12) : 0;
+ value = 0x00000010; /* data fetch by default */
+ yuv_mode = yuv_lineskip = 0;
+
+ switch (icd->current_fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ yuv_lineskip = 1; /* skip for NV12/21, no skip for NV16/61 */
+ /* fall-through */
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ yuv_mode = 1;
+ switch (pcdev->camera_fmt->fourcc) {
+ case V4L2_PIX_FMT_UYVY:
+ value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */
+ break;
+ case V4L2_PIX_FMT_VYUY:
+ value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */
+ break;
+ case V4L2_PIX_FMT_YVYU:
+ value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */
+ break;
+ default:
+ BUG();
+ }
+ }
+
+ if (icd->current_fmt->fourcc == V4L2_PIX_FMT_NV21 ||
+ icd->current_fmt->fourcc == V4L2_PIX_FMT_NV61)
+ value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */
+
+ value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
+ value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
+ value |= buswidth == 16 ? 1 << 12 : 0;
ceu_write(pcdev, CAMCR, value);
ceu_write(pcdev, CAPCR, 0x00300000);
- ceu_write(pcdev, CAIFR, 0);
+ ceu_write(pcdev, CAIFR, (pcdev->is_interlace) ? 0x101 : 0);
mdelay(1);
- width = icd->width * (icd->current_fmt->depth / 8);
- width = (buswidth == 16) ? width / 2 : width;
- cfszr_width = (buswidth == 8) ? width / 2 : width;
- cdwdr_width = (buswidth == 16) ? width * 2 : width;
+ if (yuv_mode) {
+ width = icd->width * 2;
+ width = buswidth == 16 ? width / 2 : width;
+ cfszr_width = cdwdr_width = icd->width;
+ } else {
+ width = icd->width * ((icd->current_fmt->depth + 7) >> 3);
+ width = buswidth == 16 ? width / 2 : width;
+ cfszr_width = buswidth == 8 ? width / 2 : width;
+ cdwdr_width = buswidth == 16 ? width * 2 : width;
+ }
+
+ height = icd->height;
+ if (pcdev->is_interlace) {
+ height /= 2;
+ cdwdr_width *= 2;
+ }
ceu_write(pcdev, CAMOR, 0);
- ceu_write(pcdev, CAPWR, (icd->height << 16) | width);
- ceu_write(pcdev, CFLCR, 0); /* data fetch mode - no scaling */
- ceu_write(pcdev, CFSZR, (icd->height << 16) | cfszr_width);
- ceu_write(pcdev, CLFCR, 0); /* data fetch mode - no lowpass filter */
+ ceu_write(pcdev, CAPWR, (height << 16) | width);
+ ceu_write(pcdev, CFLCR, 0); /* no scaling */
+ ceu_write(pcdev, CFSZR, (height << 16) | cfszr_width);
+ ceu_write(pcdev, CLFCR, 0); /* no lowpass filter */
/* A few words about byte order (observed in Big Endian mode)
*
@@ -418,19 +497,20 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
* using 7 we swap the data bytes to match the incoming order:
* D0, D1, D2, D3, D4, D5, D6, D7
*/
- ceu_write(pcdev, CDOCR, 0x00000017);
+ value = 0x00000017;
+ if (yuv_lineskip)
+ value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */
+
+ ceu_write(pcdev, CDOCR, value);
ceu_write(pcdev, CDWDR, cdwdr_width);
ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
/* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */
- /* in data fetch mode: no need for CDACR, CDBYR, CDBCR */
-
return 0;
}
-static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,
- __u32 pixfmt)
+static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
@@ -445,15 +525,123 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,
return 0;
}
-static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static const struct soc_camera_data_format sh_mobile_ceu_formats[] = {
+ {
+ .name = "NV12",
+ .depth = 12,
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ {
+ .name = "NV21",
+ .depth = 12,
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ {
+ .name = "NV16",
+ .depth = 16,
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ {
+ .name = "NV61",
+ .depth = 16,
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+};
+
+static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
+ struct soc_camera_format_xlate *xlate)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int ret, k, n;
+ int formats = 0;
+
+ ret = sh_mobile_ceu_try_bus_param(icd);
+ if (ret < 0)
+ return 0;
+
+ switch (icd->formats[idx].fourcc) {
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ n = ARRAY_SIZE(sh_mobile_ceu_formats);
+ formats += n;
+ for (k = 0; xlate && k < n; k++) {
+ xlate->host_fmt = &sh_mobile_ceu_formats[k];
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = icd->formats[idx].depth;
+ xlate++;
+ dev_dbg(&ici->dev, "Providing format %s using %s\n",
+ sh_mobile_ceu_formats[k].name,
+ icd->formats[idx].name);
+ }
+ default:
+ /* Generic pass-through */
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = icd->formats + idx;
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = icd->formats[idx].depth;
+ xlate++;
+ dev_dbg(&ici->dev,
+ "Providing format %s in pass-through mode\n",
+ icd->formats[idx].name);
+ }
+ }
+
+ return formats;
+}
+
+static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
- return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ const struct soc_camera_format_xlate *xlate;
+ int ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ switch (pixfmt) {
+ case 0: /* Only geometry change */
+ ret = icd->ops->set_fmt(icd, pixfmt, rect);
+ break;
+ default:
+ ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect);
+ }
+
+ if (pixfmt && !ret) {
+ icd->buswidth = xlate->buswidth;
+ icd->current_fmt = xlate->host_fmt;
+ pcdev->camera_fmt = xlate->cam_fmt;
+ }
+
+ return ret;
}
-static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ const struct soc_camera_format_xlate *xlate;
+ __u32 pixfmt = f->fmt.pix.pixelformat;
+ int ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
/* FIXME: calculate using depth and bus width */
if (f->fmt.pix.height < 4)
@@ -467,8 +655,31 @@ static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,
f->fmt.pix.width &= ~0x01;
f->fmt.pix.height &= ~0x03;
+ f->fmt.pix.bytesperline = f->fmt.pix.width *
+ DIV_ROUND_UP(xlate->host_fmt->depth, 8);
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
/* limit to sensor capabilities */
- return icd->ops->try_fmt_cap(icd, f);
+ ret = icd->ops->try_fmt(icd, f);
+ if (ret < 0)
+ return ret;
+
+ switch (f->fmt.pix.field) {
+ case V4L2_FIELD_INTERLACED:
+ pcdev->is_interlace = 1;
+ break;
+ case V4L2_FIELD_ANY:
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ /* fall-through */
+ case V4L2_FIELD_NONE:
+ pcdev->is_interlace = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
}
static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,
@@ -527,7 +738,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
&sh_mobile_ceu_videobuf_ops,
&ici->dev, &pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_NONE,
+ V4L2_FIELD_ANY,
sizeof(struct sh_mobile_ceu_buffer),
icd);
}
@@ -536,12 +747,12 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.owner = THIS_MODULE,
.add = sh_mobile_ceu_add_device,
.remove = sh_mobile_ceu_remove_device,
- .set_fmt_cap = sh_mobile_ceu_set_fmt_cap,
- .try_fmt_cap = sh_mobile_ceu_try_fmt_cap,
+ .get_formats = sh_mobile_ceu_get_formats,
+ .set_fmt = sh_mobile_ceu_set_fmt,
+ .try_fmt = sh_mobile_ceu_try_fmt,
.reqbufs = sh_mobile_ceu_reqbufs,
.poll = sh_mobile_ceu_poll,
.querycap = sh_mobile_ceu_querycap,
- .try_bus_param = sh_mobile_ceu_try_bus_param,
.set_bus_param = sh_mobile_ceu_set_bus_param,
.init_videobuf = sh_mobile_ceu_init_videobuf,
};
@@ -551,6 +762,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
struct sh_mobile_ceu_dev *pcdev;
struct resource *res;
void __iomem *base;
+ char clk_name[8];
unsigned int irq;
int err = 0;
@@ -616,6 +828,14 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
goto exit_release_mem;
}
+ snprintf(clk_name, sizeof(clk_name), "ceu%d", pdev->id);
+ pcdev->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(pcdev->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+ err = PTR_ERR(pcdev->clk);
+ goto exit_free_irq;
+ }
+
pcdev->ici.priv = pcdev;
pcdev->ici.dev.parent = &pdev->dev;
pcdev->ici.nr = pdev->id;
@@ -624,10 +844,12 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
err = soc_camera_host_register(&pcdev->ici);
if (err)
- goto exit_free_irq;
+ goto exit_free_clk;
return 0;
+exit_free_clk:
+ clk_put(pcdev->clk);
exit_free_irq:
free_irq(pcdev->irq, pcdev);
exit_release_mem:
@@ -646,6 +868,7 @@ static int sh_mobile_ceu_remove(struct platform_device *pdev)
struct sh_mobile_ceu_dev *pcdev = platform_get_drvdata(pdev);
soc_camera_host_unregister(&pcdev->ici);
+ clk_put(pcdev->clk);
free_irq(pcdev->irq, pcdev);
if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
dma_release_declared_memory(&pdev->dev);
diff --git a/linux/drivers/media/video/sn9c102/sn9c102_core.c b/linux/drivers/media/video/sn9c102/sn9c102_core.c
index 3ce12faf5..63432ccd2 100644
--- a/linux/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/linux/drivers/media/video/sn9c102/sn9c102_core.c
@@ -1750,7 +1750,7 @@ static void sn9c102_release_resources(struct kref *kref)
}
-static int sn9c102_open(struct inode* inode, struct file* filp)
+static int sn9c102_open(struct file *filp)
{
struct sn9c102_device* cam;
int err = 0;
@@ -1861,7 +1861,7 @@ out:
}
-static int sn9c102_release(struct inode* inode, struct file* filp)
+static int sn9c102_release(struct file *filp)
{
struct sn9c102_device* cam;
@@ -3096,8 +3096,8 @@ sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg)
}
-static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
- unsigned int cmd, void __user * arg)
+static long sn9c102_ioctl_v4l2(struct file *filp,
+ unsigned int cmd, void __user *arg)
{
struct sn9c102_device *cam = video_drvdata(filp);
@@ -3200,7 +3200,7 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
}
-static int sn9c102_ioctl(struct inode* inode, struct file* filp,
+static long sn9c102_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct sn9c102_device *cam = video_drvdata(filp);
@@ -3224,7 +3224,7 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
V4LDBG(3, "sn9c102", cmd);
- err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
+ err = sn9c102_ioctl_v4l2(filp, cmd, (void __user *)arg);
mutex_unlock(&cam->fileop_mutex);
@@ -3233,18 +3233,14 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
/*****************************************************************************/
-static const struct file_operations sn9c102_fops = {
+static const struct v4l2_file_operations sn9c102_fops = {
.owner = THIS_MODULE,
.open = sn9c102_open,
.release = sn9c102_release,
.ioctl = sn9c102_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
.read = sn9c102_read,
.poll = sn9c102_poll,
.mmap = sn9c102_mmap,
- .llseek = no_llseek,
};
/*****************************************************************************/
diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c
index 7a46697c4..356b77e10 100644
--- a/linux/drivers/media/video/soc_camera.c
+++ b/linux/drivers/media/video/soc_camera.c
@@ -34,10 +34,9 @@
static LIST_HEAD(hosts);
static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock);
-static DEFINE_MUTEX(video_lock);
-const static struct soc_camera_data_format*
-format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
+const struct soc_camera_data_format *soc_camera_format_by_fourcc(
+ struct soc_camera_device *icd, unsigned int fourcc)
{
unsigned int i;
@@ -46,67 +45,87 @@ format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
return icd->formats + i;
return NULL;
}
+EXPORT_SYMBOL(soc_camera_format_by_fourcc);
-static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
+ struct soc_camera_device *icd, unsigned int fourcc)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
- enum v4l2_field field;
- const struct soc_camera_data_format *fmt;
- int ret;
+ unsigned int i;
- WARN_ON(priv != file->private_data);
+ for (i = 0; i < icd->num_user_formats; i++)
+ if (icd->user_formats[i].host_fmt->fourcc == fourcc)
+ return icd->user_formats + i;
+ return NULL;
+}
+EXPORT_SYMBOL(soc_camera_xlate_by_fourcc);
- fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
- if (!fmt) {
- dev_dbg(&icd->dev, "invalid format 0x%08x\n",
- f->fmt.pix.pixelformat);
- return -EINVAL;
- }
+/**
+ * soc_camera_apply_sensor_flags() - apply platform SOCAM_SENSOR_INVERT_* flags
+ * @icl: camera platform parameters
+ * @flags: flags to be inverted according to platform configuration
+ * @return: resulting flags
+ */
+unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
+ unsigned long flags)
+{
+ unsigned long f;
- dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc);
+ /* If only one of the two polarities is supported, switch to the opposite */
+ if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) {
+ f = flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW);
+ if (f == SOCAM_HSYNC_ACTIVE_HIGH || f == SOCAM_HSYNC_ACTIVE_LOW)
+ flags ^= SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW;
+ }
- field = f->fmt.pix.field;
+ if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) {
+ f = flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW);
+ if (f == SOCAM_VSYNC_ACTIVE_HIGH || f == SOCAM_VSYNC_ACTIVE_LOW)
+ flags ^= SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW;
+ }
- if (field == V4L2_FIELD_ANY) {
- field = V4L2_FIELD_NONE;
- } else if (V4L2_FIELD_NONE != field) {
- dev_err(&icd->dev, "Field type invalid.\n");
- return -EINVAL;
+ if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) {
+ f = flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING);
+ if (f == SOCAM_PCLK_SAMPLE_RISING || f == SOCAM_PCLK_SAMPLE_FALLING)
+ flags ^= SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING;
}
- /* test physical bus parameters */
- ret = ici->ops->try_bus_param(icd, f->fmt.pix.pixelformat);
- if (ret)
- return ret;
+ return flags;
+}
+EXPORT_SYMBOL(soc_camera_apply_sensor_flags);
- /* limit format to hardware capabilities */
- ret = ici->ops->try_fmt_cap(icd, f);
+static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- /* calculate missing fields */
- f->fmt.pix.field = field;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
+ WARN_ON(priv != file->private_data);
- return ret;
+ /* limit format to hardware capabilities */
+ return ici->ops->try_fmt(icd, f);
}
static int soc_camera_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
{
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+ int ret = 0;
+
if (inp->index != 0)
return -EINVAL;
- inp->type = V4L2_INPUT_TYPE_CAMERA;
- inp->std = V4L2_STD_UNKNOWN;
- strcpy(inp->name, "Camera");
+ if (icd->ops->enum_input)
+ ret = icd->ops->enum_input(icd, inp);
+ else {
+ /* default is camera */
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = V4L2_STD_UNKNOWN;
+ strcpy(inp->name, "Camera");
+ }
- return 0;
+ return ret;
}
static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
@@ -126,7 +145,14 @@ static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
{
- return 0;
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+ int ret = 0;
+
+ if (icd->ops->set_std)
+ ret = icd->ops->set_std(icd, a);
+
+ return ret;
}
static int soc_camera_reqbufs(struct file *file, void *priv,
@@ -135,8 +161,7 @@ static int soc_camera_reqbufs(struct file *file, void *priv,
int ret;
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
WARN_ON(priv != file->private_data);
@@ -179,7 +204,60 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
}
-static int soc_camera_open(struct inode *inode, struct file *file)
+static int soc_camera_init_user_formats(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int i, fmts = 0;
+
+ if (!ici->ops->get_formats)
+ /*
+ * Fallback mode - the host will have to serve all
+ * sensor-provided formats one-to-one to the user
+ */
+ fmts = icd->num_formats;
+ else
+ /*
+ * First pass - only count formats this host-sensor
+ * configuration can provide
+ */
+ for (i = 0; i < icd->num_formats; i++)
+ fmts += ici->ops->get_formats(icd, i, NULL);
+
+ if (!fmts)
+ return -ENXIO;
+
+ icd->user_formats =
+ vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
+ if (!icd->user_formats)
+ return -ENOMEM;
+
+ icd->num_user_formats = fmts;
+ fmts = 0;
+
+ dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
+
+ /* Second pass - actually fill data formats */
+ for (i = 0; i < icd->num_formats; i++)
+ if (!ici->ops->get_formats) {
+ icd->user_formats[i].host_fmt = icd->formats + i;
+ icd->user_formats[i].cam_fmt = icd->formats + i;
+ icd->user_formats[i].buswidth = icd->formats[i].depth;
+ } else {
+ fmts += ici->ops->get_formats(icd, i,
+ &icd->user_formats[fmts]);
+ }
+
+ icd->current_fmt = icd->user_formats[0].host_fmt;
+
+ return 0;
+}
+
+static void soc_camera_free_user_formats(struct soc_camera_device *icd)
+{
+ vfree(icd->user_formats);
+}
+
+static int soc_camera_open(struct file *file)
{
struct video_device *vdev;
struct soc_camera_device *icd;
@@ -191,8 +269,10 @@ static int soc_camera_open(struct inode *inode, struct file *file)
if (!icf)
return -ENOMEM;
- /* Protect against icd->remove() until we module_get() both drivers. */
- mutex_lock(&video_lock);
+ /*
+ * It is safe to dereference these pointers now as long as a user has
+ * the video device open - we are protected by the held cdev reference.
+ */
vdev = video_devdata(file);
icd = container_of(vdev->parent, struct soc_camera_device, dev);
@@ -210,20 +290,25 @@ static int soc_camera_open(struct inode *inode, struct file *file)
goto emgi;
}
+ /* Protect against icd->remove() until we module_get() both drivers. */
+ mutex_lock(&icd->video_lock);
+
icf->icd = icd;
icd->use_count++;
/* Now we really have to activate the camera */
if (icd->use_count == 1) {
+ ret = soc_camera_init_user_formats(icd);
+ if (ret < 0)
+ goto eiufmt;
ret = ici->ops->add(icd);
if (ret < 0) {
dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
- icd->use_count--;
goto eiciadd;
}
}
- mutex_unlock(&video_lock);
+ mutex_unlock(&icd->video_lock);
file->private_data = icf;
dev_dbg(&icd->dev, "camera device open\n");
@@ -232,31 +317,37 @@ static int soc_camera_open(struct inode *inode, struct file *file)
return 0;
- /* All errors are entered with the video_lock held */
+ /* First two errors are entered with the .video_lock held */
eiciadd:
+ soc_camera_free_user_formats(icd);
+eiufmt:
+ icd->use_count--;
+ mutex_unlock(&icd->video_lock);
module_put(ici->ops->owner);
emgi:
module_put(icd->ops->owner);
emgd:
- mutex_unlock(&video_lock);
vfree(icf);
return ret;
}
-static int soc_camera_close(struct inode *inode, struct file *file)
+static int soc_camera_close(struct file *file)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct video_device *vdev = icd->vdev;
- mutex_lock(&video_lock);
+ mutex_lock(&icd->video_lock);
icd->use_count--;
- if (!icd->use_count)
+ if (!icd->use_count) {
ici->ops->remove(icd);
+ soc_camera_free_user_formats(icd);
+ }
+ mutex_unlock(&icd->video_lock);
+
module_put(icd->ops->owner);
module_put(ici->ops->owner);
- mutex_unlock(&video_lock);
vfree(icf);
@@ -266,7 +357,7 @@ static int soc_camera_close(struct inode *inode, struct file *file)
}
static ssize_t soc_camera_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
@@ -300,8 +391,7 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
if (list_empty(&icf->vb_vidq.stream)) {
dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
@@ -311,8 +401,7 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
return ici->ops->poll(file, pt);
}
-
-static struct file_operations soc_camera_fops = {
+static struct v4l2_file_operations soc_camera_fops = {
.owner = THIS_MODULE,
.open = soc_camera_open,
.release = soc_camera_close,
@@ -320,47 +409,52 @@ static struct file_operations soc_camera_fops = {
.read = soc_camera_read,
.mmap = soc_camera_mmap,
.poll = soc_camera_poll,
- .llseek = no_llseek,
};
-
static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ __u32 pixfmt = pix->pixelformat;
int ret;
struct v4l2_rect rect;
- const static struct soc_camera_data_format *data_fmt;
WARN_ON(priv != file->private_data);
- data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
- if (!data_fmt)
- return -EINVAL;
-
- /* buswidth may be further adjusted by the ici */
- icd->buswidth = data_fmt->depth;
-
- ret = soc_camera_try_fmt_vid_cap(file, icf, f);
+ ret = soc_camera_try_fmt_vid_cap(file, priv, f);
if (ret < 0)
return ret;
+ mutex_lock(&icf->vb_vidq.vb_lock);
+
+ if (videobuf_queue_is_busy(&icf->vb_vidq)) {
+ dev_err(&icd->dev, "S_FMT denied: queue busy\n");
+ ret = -EBUSY;
+ goto unlock;
+ }
+
rect.left = icd->x_current;
rect.top = icd->y_current;
- rect.width = f->fmt.pix.width;
- rect.height = f->fmt.pix.height;
- ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect);
- if (ret < 0)
- return ret;
+ rect.width = pix->width;
+ rect.height = pix->height;
+ ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect);
+ if (ret < 0) {
+ goto unlock;
+ } else if (!icd->current_fmt ||
+ icd->current_fmt->fourcc != pixfmt) {
+ dev_err(&ici->dev,
+ "Host driver hasn't set up current format correctly!\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
- icd->current_fmt = data_fmt;
icd->width = rect.width;
icd->height = rect.height;
- icf->vb_vidq.field = f->fmt.pix.field;
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
+ icf->vb_vidq.field = pix->field;
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
f->type);
@@ -368,11 +462,16 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
icd->width, icd->height);
/* set physical bus parameters */
- return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat);
+ ret = ici->ops->set_bus_param(icd, pixfmt);
+
+unlock:
+ mutex_unlock(&icf->vb_vidq.vb_lock);
+
+ return ret;
}
static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+ struct v4l2_fmtdesc *f)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
@@ -380,10 +479,10 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
WARN_ON(priv != file->private_data);
- if (f->index >= icd->num_formats)
+ if (f->index >= icd->num_user_formats)
return -EINVAL;
- format = &icd->formats[f->index];
+ format = icd->user_formats[f->index].host_fmt;
strlcpy(f->description, format->name, sizeof(f->description));
f->pixelformat = format->fourcc;
@@ -391,21 +490,21 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
}
static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
WARN_ON(priv != file->private_data);
- f->fmt.pix.width = icd->width;
- f->fmt.pix.height = icd->height;
- f->fmt.pix.field = icf->vb_vidq.field;
- f->fmt.pix.pixelformat = icd->current_fmt->fourcc;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * icd->current_fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
+ pix->width = icd->width;
+ pix->height = icd->height;
+ pix->field = icf->vb_vidq.field;
+ pix->pixelformat = icd->current_fmt->fourcc;
+ pix->bytesperline = pix->width *
+ DIV_ROUND_UP(icd->current_fmt->depth, 8);
+ pix->sizeimage = pix->height * pix->bytesperline;
dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
icd->current_fmt->fourcc);
return 0;
@@ -416,8 +515,7 @@ static int soc_camera_querycap(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
WARN_ON(priv != file->private_data);
@@ -430,6 +528,7 @@ static int soc_camera_streamon(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ int ret;
WARN_ON(priv != file->private_data);
@@ -438,10 +537,16 @@ static int soc_camera_streamon(struct file *file, void *priv,
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ mutex_lock(&icd->video_lock);
+
icd->ops->start_capture(icd);
/* This calls buf_queue from host driver's videobuf_queue_ops */
- return videobuf_streamon(&icf->vb_vidq);
+ ret = videobuf_streamon(&icf->vb_vidq);
+
+ mutex_unlock(&icd->video_lock);
+
+ return ret;
}
static int soc_camera_streamoff(struct file *file, void *priv,
@@ -457,12 +562,16 @@ static int soc_camera_streamoff(struct file *file, void *priv,
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ mutex_lock(&icd->video_lock);
+
/* This calls buf_release from host driver's videobuf_queue_ops for all
* remaining buffers. When the last buffer is freed, stop capture */
videobuf_streamoff(&icf->vb_vidq);
icd->ops->stop_capture(icd);
+ mutex_unlock(&icd->video_lock);
+
return 0;
}
@@ -568,14 +677,16 @@ static int soc_camera_s_crop(struct file *file, void *fh,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int ret;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- ret = ici->ops->set_fmt_cap(icd, 0, &a->c);
+ /* Cropping is allowed during a running capture, guard consistency */
+ mutex_lock(&icf->vb_vidq.vb_lock);
+
+ ret = ici->ops->set_fmt(icd, 0, &a->c);
if (!ret) {
icd->width = a->c.width;
icd->height = a->c.height;
@@ -583,11 +694,13 @@ static int soc_camera_s_crop(struct file *file, void *fh,
icd->y_current = a->c.top;
}
+ mutex_unlock(&icf->vb_vidq.vb_lock);
+
return ret;
}
static int soc_camera_g_chip_ident(struct file *file, void *fh,
- struct v4l2_chip_ident *id)
+ struct v4l2_dbg_chip_ident *id)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
@@ -600,7 +713,7 @@ static int soc_camera_g_chip_ident(struct file *file, void *fh,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int soc_camera_g_register(struct file *file, void *fh,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
@@ -612,7 +725,7 @@ static int soc_camera_g_register(struct file *file, void *fh,
}
static int soc_camera_s_register(struct file *file, void *fh,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
@@ -693,18 +806,35 @@ static int scan_add_device(struct soc_camera_device *icd)
static int soc_camera_probe(struct device *dev)
{
struct soc_camera_device *icd = to_soc_camera_dev(dev);
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int ret;
- if (!icd->ops->probe)
- return -ENODEV;
+ /*
+ * Possible race scenario:
+ * modprobe <camera-host-driver> triggers __func__
+ * at this moment respective <camera-sensor-driver> gets rmmod'ed
+ * to protect take module references.
+ */
+
+ if (!try_module_get(icd->ops->owner)) {
+ dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
+ ret = -EINVAL;
+ goto emgd;
+ }
+
+ if (!try_module_get(ici->ops->owner)) {
+ dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
+ ret = -EINVAL;
+ goto emgi;
+ }
+
+ mutex_lock(&icd->video_lock);
/* We only call ->add() here to activate and probe the camera.
* We shall ->remove() and deactivate it immediately afterwards. */
ret = ici->ops->add(icd);
if (ret < 0)
- return ret;
+ goto eiadd;
ret = icd->ops->probe(icd);
if (ret >= 0) {
@@ -718,6 +848,12 @@ static int soc_camera_probe(struct device *dev)
}
ici->ops->remove(icd);
+eiadd:
+ mutex_unlock(&icd->video_lock);
+ module_put(ici->ops->owner);
+emgi:
+ module_put(icd->ops->owner);
+emgd:
return ret;
}
@@ -780,7 +916,16 @@ int soc_camera_host_register(struct soc_camera_host *ici)
int ret;
struct soc_camera_host *ix;
- if (!ici->ops->init_videobuf || !ici->ops->add || !ici->ops->remove)
+ if (!ici || !ici->ops ||
+ !ici->ops->try_fmt ||
+ !ici->ops->set_fmt ||
+ !ici->ops->set_bus_param ||
+ !ici->ops->querycap ||
+ !ici->ops->init_videobuf ||
+ !ici->ops->reqbufs ||
+ !ici->ops->add ||
+ !ici->ops->remove ||
+ !ici->ops->poll)
return -EINVAL;
/* Number might be equal to the platform device ID */
@@ -848,7 +993,16 @@ int soc_camera_device_register(struct soc_camera_device *icd)
struct soc_camera_device *ix;
int num = -1, i;
- if (!icd)
+ if (!icd || !icd->ops ||
+ !icd->ops->probe ||
+ !icd->ops->init ||
+ !icd->ops->release ||
+ !icd->ops->start_capture ||
+ !icd->ops->stop_capture ||
+ !icd->ops->set_fmt ||
+ !icd->ops->try_fmt ||
+ !icd->ops->query_bus_param ||
+ !icd->ops->set_bus_param)
return -EINVAL;
for (i = 0; i < 256 && num < 0; i++) {
@@ -870,7 +1024,10 @@ int soc_camera_device_register(struct soc_camera_device *icd)
icd->dev.bus = &soc_camera_bus_type;
dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum);
- icd->dev.release = dummy_release;
+ icd->dev.release = dummy_release;
+ icd->use_count = 0;
+ icd->host_priv = NULL;
+ mutex_init(&icd->video_lock);
return scan_add_device(icd);
}
@@ -917,6 +1074,10 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
#endif
};
+/*
+ * Usually called from the struct soc_camera_ops .probe() method, i.e., from
+ * soc_camera_probe() above with .video_lock held
+ */
int soc_camera_video_start(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
@@ -932,7 +1093,7 @@ int soc_camera_video_start(struct soc_camera_device *icd)
dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev);
strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
- /* Maybe better &ici->dev */
+
vdev->parent = &icd->dev;
vdev->current_norm = V4L2_STD_UNKNOWN;
vdev->fops = &soc_camera_fops;
@@ -941,8 +1102,6 @@ int soc_camera_video_start(struct soc_camera_device *icd)
vdev->minor = -1;
vdev->tvnorms = V4L2_STD_UNKNOWN,
- icd->current_fmt = &icd->formats[0];
-
err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
if (err < 0) {
dev_err(vdev->parent, "video_register_device failed\n");
@@ -968,10 +1127,10 @@ void soc_camera_video_stop(struct soc_camera_device *icd)
if (!icd->dev.parent || !vdev)
return;
- mutex_lock(&video_lock);
+ mutex_lock(&icd->video_lock);
video_unregister_device(vdev);
icd->vdev = NULL;
- mutex_unlock(&video_lock);
+ mutex_unlock(&icd->video_lock);
}
EXPORT_SYMBOL(soc_camera_video_stop);
diff --git a/linux/drivers/media/video/soc_camera_platform.c b/linux/drivers/media/video/soc_camera_platform.c
index bb7a9d480..013ab06e3 100644
--- a/linux/drivers/media/video/soc_camera_platform.c
+++ b/linux/drivers/media/video/soc_camera_platform.c
@@ -79,19 +79,20 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
return p->bus_param;
}
-static int soc_camera_platform_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int soc_camera_platform_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
return 0;
}
-static int soc_camera_platform_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int soc_camera_platform_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
- f->fmt.pix.width = p->format.width;
- f->fmt.pix.height = p->format.height;
+ pix->width = p->format.width;
+ pix->height = p->format.height;
return 0;
}
@@ -124,8 +125,8 @@ static struct soc_camera_ops soc_camera_platform_ops = {
.release = soc_camera_platform_release,
.start_capture = soc_camera_platform_start_capture,
.stop_capture = soc_camera_platform_stop_capture,
- .set_fmt_cap = soc_camera_platform_set_fmt_cap,
- .try_fmt_cap = soc_camera_platform_try_fmt_cap,
+ .set_fmt = soc_camera_platform_set_fmt,
+ .try_fmt = soc_camera_platform_try_fmt,
.set_bus_param = soc_camera_platform_set_bus_param,
.query_bus_param = soc_camera_platform_query_bus_param,
};
diff --git a/linux/drivers/media/video/stk-webcam.c b/linux/drivers/media/video/stk-webcam.c
index 9615b7678..3af084640 100644
--- a/linux/drivers/media/video/stk-webcam.c
+++ b/linux/drivers/media/video/stk-webcam.c
@@ -665,7 +665,7 @@ static void stk_free_buffers(struct stk_camera *dev)
/* v4l file operations */
-static int v4l_stk_open(struct inode *inode, struct file *fp)
+static int v4l_stk_open(struct file *fp)
{
struct stk_camera *dev;
struct video_device *vdev;
@@ -685,7 +685,7 @@ static int v4l_stk_open(struct inode *inode, struct file *fp)
return 0;
}
-static int v4l_stk_release(struct inode *inode, struct file *fp)
+static int v4l_stk_release(struct file *fp)
{
struct stk_camera *dev = fp->private_data;
@@ -1263,7 +1263,26 @@ static int stk_vidioc_g_parm(struct file *filp,
return 0;
}
-static struct file_operations v4l_stk_fops = {
+static int stk_vidioc_enum_framesizes(struct file *filp,
+ void *priv, struct v4l2_frmsizeenum *frms)
+{
+ if (frms->index >= ARRAY_SIZE(stk_sizes))
+ return -EINVAL;
+ switch (frms->pixel_format) {
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB565X:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_SBGGR8:
+ frms->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ frms->discrete.width = stk_sizes[frms->index].w;
+ frms->discrete.height = stk_sizes[frms->index].h;
+ return 0;
+ default: return -EINVAL;
+ }
+}
+
+static struct v4l2_file_operations v4l_stk_fops = {
.owner = THIS_MODULE,
.open = v4l_stk_open,
.release = v4l_stk_release,
@@ -1271,10 +1290,6 @@ static struct file_operations v4l_stk_fops = {
.poll = v4l_stk_poll,
.mmap = v4l_stk_mmap,
.ioctl = video_ioctl2,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek
};
static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = {
@@ -1297,6 +1312,7 @@ static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = {
.vidioc_g_ctrl = stk_vidioc_g_ctrl,
.vidioc_s_ctrl = stk_vidioc_s_ctrl,
.vidioc_g_parm = stk_vidioc_g_parm,
+ .vidioc_enum_framesizes = stk_vidioc_enum_framesizes,
};
static void stk_v4l_dev_release(struct video_device *vd)
@@ -1377,12 +1393,9 @@ static int stk_camera_probe(struct usb_interface *interface,
endpoint = &iface_desc->endpoint[i].desc;
if (!dev->isoc_ep
- && ((endpoint->bEndpointAddress
- & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
- && ((endpoint->bmAttributes
- & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) {
+ && usb_endpoint_is_isoc_in(endpoint)) {
/* we found an isoc in endpoint */
- dev->isoc_ep = (endpoint->bEndpointAddress & 0xF);
+ dev->isoc_ep = usb_endpoint_num(endpoint);
break;
}
}
diff --git a/linux/drivers/media/video/stradis.c b/linux/drivers/media/video/stradis.c
index 0e2b246c7..33001b426 100644
--- a/linux/drivers/media/video/stradis.c
+++ b/linux/drivers/media/video/stradis.c
@@ -1280,7 +1280,7 @@ static void make_clip_tab(struct saa7146 *saa, struct video_clip *cr, int ncr)
clip_draw_rectangle(clipmap, 0, 0, 1024, -saa->win.y);
}
-static int saa_ioctl(struct inode *inode, struct file *file,
+static long saa_ioctl(struct file *file,
unsigned int cmd, unsigned long argl)
{
struct saa7146 *saa = file->private_data;
@@ -1882,7 +1882,7 @@ static ssize_t saa_write(struct file *file, const char __user * buf,
return count;
}
-static int saa_open(struct inode *inode, struct file *file)
+static int saa_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct saa7146 *saa = container_of(vdev, struct saa7146, video_dev);
@@ -1900,7 +1900,7 @@ static int saa_open(struct inode *inode, struct file *file)
return 0;
}
-static int saa_release(struct inode *inode, struct file *file)
+static int saa_release(struct file *file)
{
struct saa7146 *saa = file->private_data;
saa->user--;
@@ -1911,16 +1911,12 @@ static int saa_release(struct inode *inode, struct file *file)
return 0;
}
-static const struct file_operations saa_fops = {
+static const struct v4l2_file_operations saa_fops = {
.owner = THIS_MODULE,
.open = saa_open,
.release = saa_release,
.ioctl = saa_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
.read = saa_read,
- .llseek = no_llseek,
.write = saa_write,
.mmap = saa_mmap,
};
diff --git a/linux/drivers/media/video/stv680.c b/linux/drivers/media/video/stv680.c
index be5ed5940..a2d7ec732 100644
--- a/linux/drivers/media/video/stv680.c
+++ b/linux/drivers/media/video/stv680.c
@@ -1085,7 +1085,7 @@ static int stv680_newframe (struct usb_stv *stv680, int framenr)
* Video4Linux
*********************************************************************/
-static int stv_open (struct inode *inode, struct file *file)
+static int stv_open(struct file *file)
{
struct video_device *dev = video_devdata(file);
struct usb_stv *stv680 = video_get_drvdata(dev);
@@ -1111,7 +1111,7 @@ static int stv_open (struct inode *inode, struct file *file)
return err;
}
-static int stv_close (struct inode *inode, struct file *file)
+static int stv_close(struct file *file)
{
struct video_device *dev = file->private_data;
struct usb_stv *stv680 = video_get_drvdata(dev);
@@ -1137,7 +1137,7 @@ static int stv_close (struct inode *inode, struct file *file)
return 0;
}
-static int stv680_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long stv680_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = file->private_data;
struct usb_stv *stv680 = video_get_drvdata(vdev);
@@ -1304,7 +1304,7 @@ static int stv680_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0;
}
-static int stv680_ioctl(struct inode *inode, struct file *file,
+static long stv680_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, stv680_do_ioctl);
@@ -1396,17 +1396,13 @@ static ssize_t stv680_read (struct file *file, char __user *buf,
return realcount;
} /* stv680_read */
-static const struct file_operations stv680_fops = {
+static const struct v4l2_file_operations stv680_fops = {
.owner = THIS_MODULE,
.open = stv_open,
.release = stv_close,
.read = stv680_read,
.mmap = stv680_mmap,
.ioctl = stv680_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static struct video_device stv680_template = {
.name = "STV0680 USB camera",
diff --git a/linux/drivers/media/video/tda7432.c b/linux/drivers/media/video/tda7432.c
index 375b8d6d2..64a90a71b 100644
--- a/linux/drivers/media/video/tda7432.c
+++ b/linux/drivers/media/video/tda7432.c
@@ -47,9 +47,10 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/i2c-addr.h>
+#include <media/v4l2-i2c-drv-legacy.h>
#include "compat.h"
#ifndef VIDEO_AUDIO_BALANCE
@@ -80,6 +81,7 @@ I2C_CLIENT_INSMOD;
/* Structure of address and subaddresses for the tda7432 */
struct tda7432 {
+ struct v4l2_subdev sd;
int addr;
int input;
int volume;
@@ -87,10 +89,12 @@ struct tda7432 {
int bass, treble;
int lf, lr, rf, rr;
int loud;
- struct i2c_client c;
};
-static struct i2c_driver driver;
-static struct i2c_client client_template;
+
+static inline struct tda7432 *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tda7432, sd);
+}
/* The TDA7432 is made by STS-Thompson
* http://www.st.com
@@ -225,45 +229,33 @@ static struct i2c_client client_template;
/* Begin code */
-static int tda7432_write(struct i2c_client *client, int subaddr, int val)
+static int tda7432_write(struct v4l2_subdev *sd, int subaddr, int val)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
unsigned char buffer[2];
- v4l_dbg(2, debug,client,"In tda7432_write\n");
- v4l_dbg(1, debug,client,"Writing %d 0x%x\n", subaddr, val);
+
+ v4l2_dbg(2, debug, sd, "In tda7432_write\n");
+ v4l2_dbg(1, debug, sd, "Writing %d 0x%x\n", subaddr, val);
buffer[0] = subaddr;
buffer[1] = val;
- if (2 != i2c_master_send(client,buffer,2)) {
- v4l_err(client,"I/O error, trying (write %d 0x%x)\n",
+ if (2 != i2c_master_send(client, buffer, 2)) {
+ v4l2_err(sd, "I/O error, trying (write %d 0x%x)\n",
subaddr, val);
return -1;
}
return 0;
}
-/* I don't think we ever actually _read_ the chip... */
-#if 0
-static int tda7432_read(struct i2c_client *client)
-{
- unsigned char buffer;
- v4l_dbg(2, debug,client,"In tda7432_read\n");
- if (1 != i2c_master_recv(client,&buffer,1)) {
- v4l_err(client,"I/O error, trying (read)\n");
- return -1;
- }
- v4l_dbg(1, debug,client,"Read 0x%02x\n", buffer);
- return buffer;
-}
-#endif
-
-static int tda7432_set(struct i2c_client *client)
+static int tda7432_set(struct v4l2_subdev *sd)
{
- struct tda7432 *t = i2c_get_clientdata(client);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tda7432 *t = to_state(sd);
unsigned char buf[16];
- v4l_dbg(2, debug,client,"In tda7432_set\n");
- v4l_dbg(1, debug,client,
+ v4l2_dbg(1, debug, sd,
"tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
- t->input,t->volume,t->bass,t->treble,t->lf,t->lr,t->rf,t->rr,t->loud);
+ t->input, t->volume, t->bass, t->treble, t->lf, t->lr,
+ t->rf, t->rr, t->loud);
buf[0] = TDA7432_IN;
buf[1] = t->input;
buf[2] = t->volume;
@@ -274,18 +266,19 @@ static int tda7432_set(struct i2c_client *client)
buf[7] = t->rf;
buf[8] = t->rr;
buf[9] = t->loud;
- if (10 != i2c_master_send(client,buf,10)) {
- v4l_err(client,"I/O error, trying tda7432_set\n");
+ if (10 != i2c_master_send(client, buf, 10)) {
+ v4l2_err(sd, "I/O error, trying tda7432_set\n");
return -1;
}
return 0;
}
-static void do_tda7432_init(struct i2c_client *client)
+static void do_tda7432_init(struct v4l2_subdev *sd)
{
- struct tda7432 *t = i2c_get_clientdata(client);
- v4l_dbg(2, debug,client,"In tda7432_init\n");
+ struct tda7432 *t = to_state(sd);
+
+ v4l2_dbg(2, debug, sd, "In tda7432_init\n");
t->input = TDA7432_STEREO_IN | /* Main (stereo) input */
TDA7432_BASS_SYM | /* Symmetric bass cut */
@@ -302,57 +295,12 @@ static void do_tda7432_init(struct i2c_client *client)
t->rr = TDA7432_ATTEN_0DB; /* 0dB attenuation */
t->loud = loudness; /* insmod parameter */
- tda7432_set(client);
-}
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
-{
- struct tda7432 *t;
- struct i2c_client *client;
-
- t = kzalloc(sizeof *t,GFP_KERNEL);
- if (!t)
- return -ENOMEM;
-
- client = &t->c;
- memcpy(client,&client_template,sizeof(struct i2c_client));
- client->adapter = adap;
- client->addr = addr;
- i2c_set_clientdata(client, t);
-
- do_tda7432_init(client);
- i2c_attach_client(client);
-
- v4l_info(client, "chip found @ 0x%x (%s)\n", addr << 1, adap->name);
- return 0;
-}
-
-static int tda7432_probe(struct i2c_adapter *adap)
-{
- if (adap->class & I2C_CLASS_TV_ANALOG)
- return i2c_probe(adap, &addr_data, tda7432_attach);
- return 0;
-}
-
-static int tda7432_detach(struct i2c_client *client)
-{
- struct tda7432 *t = i2c_get_clientdata(client);
-
- do_tda7432_init(client);
- i2c_detach_client(client);
-
- kfree(t);
- return 0;
+ tda7432_set(sd);
}
-static int tda7432_get_ctrl(struct i2c_client *client,
- struct v4l2_control *ctrl)
+static int tda7432_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct tda7432 *t = i2c_get_clientdata(client);
+ struct tda7432 *t = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
@@ -396,10 +344,9 @@ static int tda7432_get_ctrl(struct i2c_client *client,
return -EINVAL;
}
-static int tda7432_set_ctrl(struct i2c_client *client,
- struct v4l2_control *ctrl)
+static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct tda7432 *t = i2c_get_clientdata(client);
+ struct tda7432 *t = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
@@ -414,7 +361,7 @@ static int tda7432_set_ctrl(struct i2c_client *client,
if (loudness) /* Turn on the loudness bit */
t->volume |= TDA7432_LD_ON;
- tda7432_write(client,TDA7432_VL, t->volume);
+ tda7432_write(sd, TDA7432_VL, t->volume);
return 0;
case V4L2_CID_AUDIO_BALANCE:
if (ctrl->value < 32768) {
@@ -442,14 +389,14 @@ static int tda7432_set_ctrl(struct i2c_client *client,
if(t->bass>= 0x8)
t->bass = (~t->bass & 0xf) + 0x8 ;
- tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
+ tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble);
return 0;
case V4L2_CID_AUDIO_TREBLE:
t->treble= ctrl->value >> 12;
if(t->treble>= 0x8)
t->treble = (~t->treble & 0xf) + 0x8 ;
- tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
+ tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble);
return 0;
default:
return -EINVAL;
@@ -459,92 +406,106 @@ static int tda7432_set_ctrl(struct i2c_client *client,
if (t->muted)
{
/* Mute & update balance*/
- tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
- tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
- tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
- tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
+ tda7432_write(sd, TDA7432_LF, t->lf | TDA7432_MUTE);
+ tda7432_write(sd, TDA7432_LR, t->lr | TDA7432_MUTE);
+ tda7432_write(sd, TDA7432_RF, t->rf | TDA7432_MUTE);
+ tda7432_write(sd, TDA7432_RR, t->rr | TDA7432_MUTE);
} else {
- tda7432_write(client,TDA7432_LF, t->lf);
- tda7432_write(client,TDA7432_LR, t->lr);
- tda7432_write(client,TDA7432_RF, t->rf);
- tda7432_write(client,TDA7432_RR, t->rr);
+ tda7432_write(sd, TDA7432_LF, t->lf);
+ tda7432_write(sd, TDA7432_LR, t->lr);
+ tda7432_write(sd, TDA7432_RF, t->rf);
+ tda7432_write(sd, TDA7432_RR, t->rr);
}
return 0;
}
-static int tda7432_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
+static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
{
- v4l_dbg(2, debug,client,"In tda7432_command\n");
- if (debug>1)
- v4l_i2c_print_ioctl(client,cmd);
-
- switch (cmd) {
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
-
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- default:
- return -EINVAL;
- }
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
return v4l2_ctrl_query_fill_std(qc);
}
- case VIDIOC_S_CTRL:
- return tda7432_set_ctrl(client, arg);
-
- case VIDIOC_G_CTRL:
- return tda7432_get_ctrl(client, arg);
-
- } /* end of (cmd) switch */
+ return -EINVAL;
+}
- return 0;
+static int tda7432_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
}
-static struct i2c_driver driver = {
- .driver = {
- .name = "tda7432",
- },
- .id = I2C_DRIVERID_TDA7432,
- .attach_adapter = tda7432_probe,
- .detach_client = tda7432_detach,
- .command = tda7432_command,
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tda7432_core_ops = {
+ .queryctrl = tda7432_queryctrl,
+ .g_ctrl = tda7432_g_ctrl,
+ .s_ctrl = tda7432_s_ctrl,
};
-static struct i2c_client client_template =
-{
- .name = "tda7432",
- .driver = &driver,
+static const struct v4l2_subdev_ops tda7432_ops = {
+ .core = &tda7432_core_ops,
};
-static int __init tda7432_init(void)
+/* ----------------------------------------------------------------------- */
+
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
+
+static int tda7432_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- if ( (loudness < 0) || (loudness > 15) ) {
- printk(KERN_ERR "loudness parameter must be between 0 and 15\n");
- return -EINVAL;
+ struct tda7432 *t;
+ struct v4l2_subdev *sd;
+
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
+ t = kzalloc(sizeof(*t), GFP_KERNEL);
+ if (!t)
+ return -ENOMEM;
+ sd = &t->sd;
+ v4l2_i2c_subdev_init(sd, client, &tda7432_ops);
+ if (loudness < 0 || loudness > 15) {
+ v4l2_warn(sd, "loudness parameter must be between 0 and 15\n");
+ if (loudness < 0)
+ loudness = 0;
+ if (loudness > 15)
+ loudness = 15;
}
- return i2c_add_driver(&driver);
+ do_tda7432_init(sd);
+ return 0;
}
-static void __exit tda7432_fini(void)
+static int tda7432_remove(struct i2c_client *client)
{
- i2c_del_driver(&driver);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ do_tda7432_init(sd);
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
+ return 0;
}
-module_init(tda7432_init);
-module_exit(tda7432_fini);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id tda7432_id[] = {
+ { "tda7432", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tda7432_id);
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "tda7432",
+ .driverid = I2C_DRIVERID_TDA7432,
+ .command = tda7432_command,
+ .probe = tda7432_probe,
+ .remove = tda7432_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tda7432_id,
+#endif
+};
diff --git a/linux/drivers/media/video/tda9840.c b/linux/drivers/media/video/tda9840.c
index 31dde7516..62e257161 100644
--- a/linux/drivers/media/video/tda9840.c
+++ b/linux/drivers/media/video/tda9840.c
@@ -29,7 +29,7 @@
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include "tda9840.h"
#include "compat.h"
@@ -63,85 +63,89 @@ static unsigned short normal_i2c[] = { I2C_ADDR_TDA9840, I2C_CLIENT_END };
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
-static void tda9840_write(struct i2c_client *client, u8 reg, u8 val)
+static void tda9840_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
if (i2c_smbus_write_byte_data(client, reg, val))
- v4l_dbg(1, debug, client, "error writing %02x to %02x\n",
+ v4l2_dbg(1, debug, sd, "error writing %02x to %02x\n",
val, reg);
}
-static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int tda9840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
{
- int byte = *(int *)arg;
-
- switch (cmd) {
- case VIDIOC_S_TUNER: {
- struct v4l2_tuner *t = arg;
- int byte;
+ int byte;
- if (t->index)
- return -EINVAL;
+ if (t->index)
+ return -EINVAL;
- switch (t->audmode) {
- case V4L2_TUNER_MODE_STEREO:
- byte = TDA9840_SET_STEREO;
- break;
- case V4L2_TUNER_MODE_LANG1_LANG2:
- byte = TDA9840_SET_BOTH;
- break;
- case V4L2_TUNER_MODE_LANG1:
- byte = TDA9840_SET_LANG1;
- break;
- case V4L2_TUNER_MODE_LANG2:
- byte = TDA9840_SET_LANG2;
- break;
- default:
- byte = TDA9840_SET_MONO;
- break;
- }
- v4l_dbg(1, debug, client, "TDA9840_SWITCH: 0x%02x\n", byte);
- tda9840_write(client, SWITCH, byte);
+ switch (t->audmode) {
+ case V4L2_TUNER_MODE_STEREO:
+ byte = TDA9840_SET_STEREO;
break;
+ case V4L2_TUNER_MODE_LANG1_LANG2:
+ byte = TDA9840_SET_BOTH;
+ break;
+ case V4L2_TUNER_MODE_LANG1:
+ byte = TDA9840_SET_LANG1;
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ byte = TDA9840_SET_LANG2;
+ break;
+ default:
+ byte = TDA9840_SET_MONO;
+ break;
+ }
+ v4l2_dbg(1, debug, sd, "TDA9840_SWITCH: 0x%02x\n", byte);
+ tda9840_write(sd, SWITCH, byte);
+ return 0;
+}
+
+static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 byte;
+
+ t->rxsubchans = V4L2_TUNER_SUB_MONO;
+ if (1 != i2c_master_recv(client, &byte, 1)) {
+ v4l2_dbg(1, debug, sd,
+ "i2c_master_recv() failed\n");
+ return -EIO;
+ }
+
+ if (byte & 0x80) {
+ v4l2_dbg(1, debug, sd,
+ "TDA9840_DETECT: register contents invalid\n");
+ return -EINVAL;
}
- case VIDIOC_G_TUNER: {
- struct v4l2_tuner *t = arg;
- u8 byte;
+ v4l2_dbg(1, debug, sd, "TDA9840_DETECT: byte: 0x%02x\n", byte);
+ switch (byte & 0x60) {
+ case 0x00:
t->rxsubchans = V4L2_TUNER_SUB_MONO;
- if (1 != i2c_master_recv(client, &byte, 1)) {
- v4l_dbg(1, debug, client,
- "i2c_master_recv() failed\n");
- return -EIO;
- }
-
- if (byte & 0x80) {
- v4l_dbg(1, debug, client,
- "TDA9840_DETECT: register contents invalid\n");
- return -EINVAL;
- }
-
- v4l_dbg(1, debug, client, "TDA9840_DETECT: byte: 0x%02x\n", byte);
-
- switch (byte & 0x60) {
- case 0x00:
- t->rxsubchans = V4L2_TUNER_SUB_MONO;
- break;
- case 0x20:
- t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
- break;
- case 0x40:
- t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
- break;
- default: /* Incorrect detect */
- t->rxsubchans = V4L2_TUNER_MODE_MONO;
- break;
- }
+ break;
+ case 0x20:
+ t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+ break;
+ case 0x40:
+ t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+ break;
+ default: /* Incorrect detect */
+ t->rxsubchans = V4L2_TUNER_MODE_MONO;
break;
}
+ return 0;
+}
+static long tda9840_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
+{
+ int byte;
+
+ switch (cmd) {
case TDA9840_LEVEL_ADJUST:
- v4l_dbg(1, debug, client, "TDA9840_LEVEL_ADJUST: %d\n", byte);
+ byte = *(int *)arg;
+ v4l2_dbg(1, debug, sd, "TDA9840_LEVEL_ADJUST: %d\n", byte);
/* check for correct range */
if (byte > 25 || byte < -20)
@@ -153,11 +157,12 @@ static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
byte += 0x8;
else
byte = -byte;
- tda9840_write(client, LEVEL_ADJUST, byte);
+ tda9840_write(sd, LEVEL_ADJUST, byte);
break;
case TDA9840_STEREO_ADJUST:
- v4l_dbg(1, debug, client, "TDA9840_STEREO_ADJUST: %d\n", byte);
+ byte = *(int *)arg;
+ v4l2_dbg(1, debug, sd, "TDA9840_STEREO_ADJUST: %d\n", byte);
/* check for correct range */
if (byte > 25 || byte < -24)
@@ -170,18 +175,41 @@ static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
else
byte = -byte;
- tda9840_write(client, STEREO_ADJUST, byte);
+ tda9840_write(sd, STEREO_ADJUST, byte);
break;
default:
return -ENOIOCTLCMD;
}
-
return 0;
}
+static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tda9840_core_ops = {
+ .ioctl = tda9840_ioctl,
+};
+
+static const struct v4l2_subdev_tuner_ops tda9840_tuner_ops = {
+ .s_tuner = tda9840_s_tuner,
+ .g_tuner = tda9840_g_tuner,
+};
+
+static const struct v4l2_subdev_ops tda9840_ops = {
+ .core = &tda9840_core_ops,
+ .tuner = &tda9840_tuner_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
static int tda9840_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct v4l2_subdev *sd;
int result;
int byte;
@@ -189,23 +217,38 @@ static int tda9840_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA |
I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
- return 0;
+ return -EIO;
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
+ sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (sd == NULL)
+ return -ENOMEM;
+ v4l2_i2c_subdev_init(sd, client, &tda9840_ops);
+
/* set initial values for level & stereo - adjustment, mode */
byte = 0;
- result = tda9840_command(client, TDA9840_LEVEL_ADJUST, &byte);
- result += tda9840_command(client, TDA9840_STEREO_ADJUST, &byte);
- tda9840_write(client, SWITCH, TDA9840_SET_STEREO);
+ result = tda9840_ioctl(sd, TDA9840_LEVEL_ADJUST, &byte);
+ result |= tda9840_ioctl(sd, TDA9840_STEREO_ADJUST, &byte);
+ tda9840_write(sd, SWITCH, TDA9840_SET_STEREO);
if (result) {
- v4l_dbg(1, debug, client, "could not initialize tda9840\n");
+ v4l2_dbg(1, debug, sd, "could not initialize tda9840\n");
+ kfree(sd);
return -ENODEV;
}
return 0;
}
+static int tda9840_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(sd);
+ return 0;
+}
+
static int tda9840_legacy_probe(struct i2c_adapter *adapter)
{
/* Let's see whether this is a known adapter we can attach to.
@@ -225,6 +268,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.driverid = I2C_DRIVERID_TDA9840,
.command = tda9840_command,
.probe = tda9840_probe,
+ .remove = tda9840_remove,
.legacy_probe = tda9840_legacy_probe,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
.id_table = tda9840_id,
diff --git a/linux/drivers/media/video/tda9875.c b/linux/drivers/media/video/tda9875.c
index 20e738264..2e72c36a9 100644
--- a/linux/drivers/media/video/tda9875.c
+++ b/linux/drivers/media/video/tda9875.c
@@ -25,13 +25,12 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
#include <linux/i2c.h>
-#include <linux/init.h>
-#include "compat.h"
-
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-i2c-drv-legacy.h>
#include <media/i2c-addr.h>
+#include "compat.h"
static int debug; /* insmod parameter */
module_param(debug, int, S_IRUGO | S_IWUSR);
@@ -47,13 +46,15 @@ I2C_CLIENT_INSMOD;
/* This is a superset of the TDA9875 */
struct tda9875 {
+ struct v4l2_subdev sd;
int rvol, lvol;
int bass, treble;
- struct i2c_client c;
};
-static struct i2c_driver driver;
-static struct i2c_client client_template;
+static inline struct tda9875 *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tda9875, sd);
+}
#define dprintk if (debug) printk
@@ -106,15 +107,16 @@ static struct i2c_client client_template;
/* Begin code */
-static int tda9875_write(struct i2c_client *client, int subaddr, unsigned char val)
+static int tda9875_write(struct v4l2_subdev *sd, int subaddr, unsigned char val)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
unsigned char buffer[2];
- dprintk("In tda9875_write\n");
- dprintk("Writing %d 0x%x\n", subaddr, val);
+
+ v4l2_dbg(1, debug, sd, "Writing %d 0x%x\n", subaddr, val);
buffer[0] = subaddr;
buffer[1] = val;
- if (2 != i2c_master_send(client,buffer,2)) {
- printk(KERN_WARNING "tda9875: I/O error, trying (write %d 0x%x)\n",
+ if (2 != i2c_master_send(client, buffer, 2)) {
+ v4l2_warn(sd, "I/O error, trying (write %d 0x%x)\n",
subaddr, val);
return -1;
}
@@ -135,7 +137,7 @@ static int tda9875_read(struct i2c_client *client)
}
#endif
-static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg)
+static int i2c_read_register(struct i2c_client *client, int addr, int reg)
{
unsigned char write[1];
unsigned char read[1];
@@ -143,150 +145,83 @@ static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg)
{ addr, 0, 1, write },
{ addr, I2C_M_RD, 1, read }
};
+
write[0] = reg;
- if (2 != i2c_transfer(adap,msgs,2)) {
- printk(KERN_WARNING "tda9875: I/O error (read2)\n");
+ if (2 != i2c_transfer(client->adapter, msgs, 2)) {
+ v4l_warn(client, "I/O error (read2)\n");
return -1;
}
- dprintk("tda9875: chip_read2: reg%d=0x%x\n",reg,read[0]);
+ v4l_dbg(1, debug, client, "chip_read2: reg%d=0x%x\n", reg, read[0]);
return read[0];
}
-static void tda9875_set(struct i2c_client *client)
+static void tda9875_set(struct v4l2_subdev *sd)
{
- struct tda9875 *tda = i2c_get_clientdata(client);
+ struct tda9875 *tda = to_state(sd);
unsigned char a;
- dprintk(KERN_DEBUG "tda9875_set(%04x,%04x,%04x,%04x)\n",
- tda->lvol,tda->rvol,tda->bass,tda->treble);
-
+ v4l2_dbg(1, debug, sd, "tda9875_set(%04x,%04x,%04x,%04x)\n",
+ tda->lvol, tda->rvol, tda->bass, tda->treble);
a = tda->lvol & 0xff;
- tda9875_write(client, TDA9875_MVL, a);
+ tda9875_write(sd, TDA9875_MVL, a);
a =tda->rvol & 0xff;
- tda9875_write(client, TDA9875_MVR, a);
+ tda9875_write(sd, TDA9875_MVR, a);
a =tda->bass & 0xff;
- tda9875_write(client, TDA9875_MBA, a);
+ tda9875_write(sd, TDA9875_MBA, a);
a =tda->treble & 0xff;
- tda9875_write(client, TDA9875_MTR, a);
+ tda9875_write(sd, TDA9875_MTR, a);
}
-static void do_tda9875_init(struct i2c_client *client)
+static void do_tda9875_init(struct v4l2_subdev *sd)
{
- struct tda9875 *t = i2c_get_clientdata(client);
- dprintk("In tda9875_init\n");
- tda9875_write(client, TDA9875_CFG, 0xd0 ); /*reg de config 0 (reset)*/
- tda9875_write(client, TDA9875_MSR, 0x03 ); /* Monitor 0b00000XXX*/
- tda9875_write(client, TDA9875_C1MSB, 0x00 ); /*Car1(FM) MSB XMHz*/
- tda9875_write(client, TDA9875_C1MIB, 0x00 ); /*Car1(FM) MIB XMHz*/
- tda9875_write(client, TDA9875_C1LSB, 0x00 ); /*Car1(FM) LSB XMHz*/
- tda9875_write(client, TDA9875_C2MSB, 0x00 ); /*Car2(NICAM) MSB XMHz*/
- tda9875_write(client, TDA9875_C2MIB, 0x00 ); /*Car2(NICAM) MIB XMHz*/
- tda9875_write(client, TDA9875_C2LSB, 0x00 ); /*Car2(NICAM) LSB XMHz*/
- tda9875_write(client, TDA9875_DCR, 0x00 ); /*Demod config 0x00*/
- tda9875_write(client, TDA9875_DEEM, 0x44 ); /*DE-Emph 0b0100 0100*/
- tda9875_write(client, TDA9875_FMAT, 0x00 ); /*FM Matrix reg 0x00*/
- tda9875_write(client, TDA9875_SC1, 0x00 ); /* SCART 1 (SC1)*/
- tda9875_write(client, TDA9875_SC2, 0x01 ); /* SCART 2 (sc2)*/
-
- tda9875_write(client, TDA9875_CH1V, 0x10 ); /* Channel volume 1 mute*/
- tda9875_write(client, TDA9875_CH2V, 0x10 ); /* Channel volume 2 mute */
- tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/
- tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/
- tda9875_write(client, TDA9875_LOSR, 0x00 ); /* line out (in:mono)*/
- tda9875_write(client, TDA9875_AER, 0x00 ); /*06 Effect (AVL+PSEUDO) */
- tda9875_write(client, TDA9875_MCS, 0x44 ); /* Main ch select (DAC) */
- tda9875_write(client, TDA9875_MVL, 0x03 ); /* Vol Main left 10dB */
- tda9875_write(client, TDA9875_MVR, 0x03 ); /* Vol Main right 10dB*/
- tda9875_write(client, TDA9875_MBA, 0x00 ); /* Main Bass Main 0dB*/
- tda9875_write(client, TDA9875_MTR, 0x00 ); /* Main Treble Main 0dB*/
- tda9875_write(client, TDA9875_ACS, 0x44 ); /* Aux chan select (dac)*/
- tda9875_write(client, TDA9875_AVL, 0x00 ); /* Vol Aux left 0dB*/
- tda9875_write(client, TDA9875_AVR, 0x00 ); /* Vol Aux right 0dB*/
- tda9875_write(client, TDA9875_ABA, 0x00 ); /* Aux Bass Main 0dB*/
- tda9875_write(client, TDA9875_ATR, 0x00 ); /* Aux Aigus Main 0dB*/
-
- tda9875_write(client, TDA9875_MUT, 0xcc ); /* General mute */
-
- t->lvol=t->rvol =0; /* 0dB */
- t->bass=0; /* 0dB */
- t->treble=0; /* 0dB */
- tda9875_set(client);
-
-}
-
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tda9875_checkit(struct i2c_adapter *adap, int addr)
-{
- int dic,rev;
-
- dic=i2c_read_register(adap,addr,254);
- rev=i2c_read_register(adap,addr,255);
-
- if(dic==0 || dic==2) { // tda9875 and tda9875A
- printk("tda9875: TDA9875%s Rev.%d detected at 0x%x\n",
- dic==0?"":"A", rev,addr<<1);
- return 1;
- }
- printk("tda9875: no such chip at 0x%x (dic=0x%x rev=0x%x)\n",addr<<1,dic,rev);
- return(0);
+ struct tda9875 *t = to_state(sd);
+
+ v4l2_dbg(1, debug, sd, "In tda9875_init\n");
+ tda9875_write(sd, TDA9875_CFG, 0xd0); /*reg de config 0 (reset)*/
+ tda9875_write(sd, TDA9875_MSR, 0x03); /* Monitor 0b00000XXX*/
+ tda9875_write(sd, TDA9875_C1MSB, 0x00); /*Car1(FM) MSB XMHz*/
+ tda9875_write(sd, TDA9875_C1MIB, 0x00); /*Car1(FM) MIB XMHz*/
+ tda9875_write(sd, TDA9875_C1LSB, 0x00); /*Car1(FM) LSB XMHz*/
+ tda9875_write(sd, TDA9875_C2MSB, 0x00); /*Car2(NICAM) MSB XMHz*/
+ tda9875_write(sd, TDA9875_C2MIB, 0x00); /*Car2(NICAM) MIB XMHz*/
+ tda9875_write(sd, TDA9875_C2LSB, 0x00); /*Car2(NICAM) LSB XMHz*/
+ tda9875_write(sd, TDA9875_DCR, 0x00); /*Demod config 0x00*/
+ tda9875_write(sd, TDA9875_DEEM, 0x44); /*DE-Emph 0b0100 0100*/
+ tda9875_write(sd, TDA9875_FMAT, 0x00); /*FM Matrix reg 0x00*/
+ tda9875_write(sd, TDA9875_SC1, 0x00); /* SCART 1 (SC1)*/
+ tda9875_write(sd, TDA9875_SC2, 0x01); /* SCART 2 (sc2)*/
+
+ tda9875_write(sd, TDA9875_CH1V, 0x10); /* Channel volume 1 mute*/
+ tda9875_write(sd, TDA9875_CH2V, 0x10); /* Channel volume 2 mute */
+ tda9875_write(sd, TDA9875_DACOS, 0x02); /* sig DAC i/o(in:nicam)*/
+ tda9875_write(sd, TDA9875_ADCIS, 0x6f); /* sig ADC input(in:mono)*/
+ tda9875_write(sd, TDA9875_LOSR, 0x00); /* line out (in:mono)*/
+ tda9875_write(sd, TDA9875_AER, 0x00); /*06 Effect (AVL+PSEUDO) */
+ tda9875_write(sd, TDA9875_MCS, 0x44); /* Main ch select (DAC) */
+ tda9875_write(sd, TDA9875_MVL, 0x03); /* Vol Main left 10dB */
+ tda9875_write(sd, TDA9875_MVR, 0x03); /* Vol Main right 10dB*/
+ tda9875_write(sd, TDA9875_MBA, 0x00); /* Main Bass Main 0dB*/
+ tda9875_write(sd, TDA9875_MTR, 0x00); /* Main Treble Main 0dB*/
+ tda9875_write(sd, TDA9875_ACS, 0x44); /* Aux chan select (dac)*/
+ tda9875_write(sd, TDA9875_AVL, 0x00); /* Vol Aux left 0dB*/
+ tda9875_write(sd, TDA9875_AVR, 0x00); /* Vol Aux right 0dB*/
+ tda9875_write(sd, TDA9875_ABA, 0x00); /* Aux Bass Main 0dB*/
+ tda9875_write(sd, TDA9875_ATR, 0x00); /* Aux Aigus Main 0dB*/
+
+ tda9875_write(sd, TDA9875_MUT, 0xcc); /* General mute */
+
+ t->lvol = t->rvol = 0; /* 0dB */
+ t->bass = 0; /* 0dB */
+ t->treble = 0; /* 0dB */
+ tda9875_set(sd);
}
-static int tda9875_attach(struct i2c_adapter *adap, int addr, int kind)
-{
- struct tda9875 *t;
- struct i2c_client *client;
- dprintk("In tda9875_attach\n");
-
- t = kzalloc(sizeof *t,GFP_KERNEL);
- if (!t)
- return -ENOMEM;
-
- client = &t->c;
- memcpy(client,&client_template,sizeof(struct i2c_client));
- client->adapter = adap;
- client->addr = addr;
- i2c_set_clientdata(client, t);
-
- if(!tda9875_checkit(adap,addr)) {
- kfree(t);
- return 1;
- }
-
- do_tda9875_init(client);
- printk(KERN_INFO "tda9875: init\n");
-
- i2c_attach_client(client);
- return 0;
-}
-
-static int tda9875_probe(struct i2c_adapter *adap)
-{
- if (adap->class & I2C_CLASS_TV_ANALOG)
- return i2c_probe(adap, &addr_data, tda9875_attach);
- return 0;
-}
-
-static int tda9875_detach(struct i2c_client *client)
-{
- struct tda9875 *t = i2c_get_clientdata(client);
-
- do_tda9875_init(client);
- i2c_detach_client(client);
-
- kfree(t);
- return 0;
-}
-static int tda9875_get_ctrl(struct i2c_client *client,
- struct v4l2_control *ctrl)
+static int tda9875_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct tda9875 *t = i2c_get_clientdata(client);
+ struct tda9875 *t = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
@@ -318,10 +253,9 @@ static int tda9875_get_ctrl(struct i2c_client *client,
return -EINVAL;
}
-static int tda9875_set_ctrl(struct i2c_client *client,
- struct v4l2_control *ctrl)
+static int tda9875_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct tda9875 *t = i2c_get_clientdata(client);
+ struct tda9875 *t = to_state(sd);
int chvol=0, volume, balance, left, right;
switch (ctrl->id) {
@@ -385,85 +319,109 @@ static int tda9875_set_ctrl(struct i2c_client *client,
t->rvol = -84 & 0xff;
}
-//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
-
- tda9875_set(client);
-
+ tda9875_set(sd);
return 0;
}
-
-static int tda9875_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
+static int tda9875_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
{
- dprintk("In tda9875_command...\n");
-
- switch (cmd) {
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
-
- switch (qc->id) {
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- default:
- return -EINVAL;
- }
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
return v4l2_ctrl_query_fill_std(qc);
}
- case VIDIOC_S_CTRL:
- return tda9875_set_ctrl(client, arg);
+ return -EINVAL;
+}
- case VIDIOC_G_CTRL:
- return tda9875_get_ctrl(client, arg);
+static int tda9875_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
- default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
+/* ----------------------------------------------------------------------- */
- /* nothing */
- dprintk("Default\n");
+static const struct v4l2_subdev_core_ops tda9875_core_ops = {
+ .queryctrl = tda9875_queryctrl,
+ .g_ctrl = tda9875_g_ctrl,
+ .s_ctrl = tda9875_s_ctrl,
+};
- } /* end of (cmd) switch */
+static const struct v4l2_subdev_ops tda9875_ops = {
+ .core = &tda9875_core_ops,
+};
- return 0;
-}
+/* ----------------------------------------------------------------------- */
-static struct i2c_driver driver = {
- .driver = {
- .name = "tda9875",
- },
- .id = I2C_DRIVERID_TDA9875,
- .attach_adapter = tda9875_probe,
- .detach_client = tda9875_detach,
- .command = tda9875_command,
-};
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
-static struct i2c_client client_template =
+static int tda9875_checkit(struct i2c_client *client, int addr)
{
- .name = "tda9875",
- .driver = &driver,
-};
+ int dic, rev;
-static int __init tda9875_init(void)
-{
- return i2c_add_driver(&driver);
+ dic = i2c_read_register(client, addr, 254);
+ rev = i2c_read_register(client, addr, 255);
+
+ if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */
+ v4l_info(client, "tda9875%s rev. %d detected at 0x%02x\n",
+ dic == 0 ? "" : "A", rev, addr << 1);
+ return 1;
+ }
+ v4l_info(client, "no such chip at 0x%02x (dic=0x%x rev=0x%x)\n",
+ addr << 1, dic, rev);
+ return 0;
}
-static void __exit tda9875_fini(void)
+static int tda9875_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- i2c_del_driver(&driver);
+ struct tda9875 *t;
+ struct v4l2_subdev *sd;
+
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
+ if (!tda9875_checkit(client, client->addr))
+ return -ENODEV;
+
+ t = kzalloc(sizeof(*t), GFP_KERNEL);
+ if (!t)
+ return -ENOMEM;
+ sd = &t->sd;
+ v4l2_i2c_subdev_init(sd, client, &tda9875_ops);
+
+ do_tda9875_init(sd);
+ return 0;
}
-module_init(tda9875_init);
-module_exit(tda9875_fini);
+static int tda9875_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+ do_tda9875_init(sd);
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
+ return 0;
+}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id tda9875_id[] = {
+ { "tda9875", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tda9875_id);
+
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "tda9875",
+ .driverid = I2C_DRIVERID_TDA9875,
+ .command = tda9875_command,
+ .probe = tda9875_probe,
+ .remove = tda9875_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tda9875_id,
+#endif
+};
diff --git a/linux/drivers/media/video/tea6415c.c b/linux/drivers/media/video/tea6415c.c
index 073f020fa..0f589842c 100644
--- a/linux/drivers/media/video/tea6415c.c
+++ b/linux/drivers/media/video/tea6415c.c
@@ -31,7 +31,7 @@
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include "tea6415c.h"
#include "compat.h"
@@ -123,31 +123,57 @@ static int switch_matrix(struct i2c_client *client, int i, int o)
return ret;
}
-static int tea6415c_command(struct i2c_client *client, unsigned cmd, void *arg)
+static long tea6415c_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
{
- struct tea6415c_multiplex *v = (struct tea6415c_multiplex *)arg;
- int result = 0;
+ if (cmd == TEA6415C_SWITCH) {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tea6415c_multiplex *v = (struct tea6415c_multiplex *)arg;
- switch (cmd) {
- case TEA6415C_SWITCH:
- result = switch_matrix(client, v->in, v->out);
- break;
- default:
- return -ENOIOCTLCMD;
+ return switch_matrix(client, v->in, v->out);
}
- return result;
+ return -ENOIOCTLCMD;
}
+static int tea6415c_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tea6415c_core_ops = {
+ .ioctl = tea6415c_ioctl,
+};
+
+static const struct v4l2_subdev_ops tea6415c_ops = {
+ .core = &tea6415c_core_ops,
+};
+
/* this function is called by i2c_probe */
static int tea6415c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct v4l2_subdev *sd;
+
/* let's see whether this adapter can support what we need */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
return 0;
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
+ sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (sd == NULL)
+ return -ENOMEM;
+ v4l2_i2c_subdev_init(sd, client, &tea6415c_ops);
+ return 0;
+}
+
+static int tea6415c_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(sd);
return 0;
}
@@ -171,6 +197,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.driverid = I2C_DRIVERID_TEA6415C,
.command = tea6415c_command,
.probe = tea6415c_probe,
+ .remove = tea6415c_remove,
.legacy_probe = tea6415c_legacy_probe,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
.id_table = tea6415c_id,
diff --git a/linux/drivers/media/video/tea6420.c b/linux/drivers/media/video/tea6420.c
index 8ded72ade..b5f8342e0 100644
--- a/linux/drivers/media/video/tea6420.c
+++ b/linux/drivers/media/video/tea6420.c
@@ -31,7 +31,7 @@
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include "tea6420.h"
#include "compat.h"
@@ -91,26 +91,37 @@ static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
return 0;
}
-static int tea6420_command(struct i2c_client *client, unsigned cmd, void *arg)
+static long tea6420_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
{
- struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg;
- int result = 0;
+ if (cmd == TEA6420_SWITCH) {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg;
- switch (cmd) {
- case TEA6420_SWITCH:
- result = tea6420_switch(client, a->in, a->out, a->gain);
- break;
- default:
- return -ENOIOCTLCMD;
+ return tea6420_switch(client, a->in, a->out, a->gain);
}
+ return -ENOIOCTLCMD;
+}
- return result;
+static int tea6420_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
}
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tea6420_core_ops = {
+ .ioctl = tea6420_ioctl,
+};
+
+static const struct v4l2_subdev_ops tea6420_ops = {
+ .core = &tea6420_core_ops,
+};
+
/* this function is called by i2c_probe */
static int tea6420_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct v4l2_subdev *sd;
int err, i;
/* let's see whether this adapter can support what we need */
@@ -127,9 +138,22 @@ static int tea6420_probe(struct i2c_client *client,
}
if (err) {
v4l_dbg(1, debug, client, "could not initialize tea6420\n");
- kfree(client);
return -ENODEV;
}
+
+ sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (sd == NULL)
+ return -ENOMEM;
+ v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
+ return 0;
+}
+
+static int tea6420_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(sd);
return 0;
}
@@ -153,6 +177,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.driverid = I2C_DRIVERID_TEA6420,
.command = tea6420_command,
.probe = tea6420_probe,
+ .remove = tea6420_remove,
.legacy_probe = tea6420_legacy_probe,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
.id_table = tea6420_id,
diff --git a/linux/drivers/media/video/tlv320aic23b.c b/linux/drivers/media/video/tlv320aic23b.c
index a531a46d1..ecc3a4ef6 100644
--- a/linux/drivers/media/video/tlv320aic23b.c
+++ b/linux/drivers/media/video/tlv320aic23b.c
@@ -30,7 +30,7 @@
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include "compat.h"
@@ -45,15 +45,22 @@ I2C_CLIENT_INSMOD;
/* ----------------------------------------------------------------------- */
struct tlv320aic23b_state {
+ struct v4l2_subdev sd;
u8 muted;
};
-static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
+static inline struct tlv320aic23b_state *to_state(struct v4l2_subdev *sd)
{
+ return container_of(sd, struct tlv320aic23b_state, sd);
+}
+
+static int tlv320aic23b_write(struct v4l2_subdev *sd, int reg, u16 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int i;
if ((reg < 0 || reg > 9) && (reg != 15)) {
- v4l_err(client, "Invalid register R%d\n", reg);
+ v4l2_err(sd, "Invalid register R%d\n", reg);
return -1;
}
@@ -61,61 +68,82 @@ static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
if (i2c_smbus_write_byte_data(client,
(reg << 1) | (val >> 8), val & 0xff) == 0)
return 0;
- v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+ v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
return -1;
}
-static int tlv320aic23b_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
+static int tlv320aic23b_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
{
- struct tlv320aic23b_state *state = i2c_get_clientdata(client);
- struct v4l2_control *ctrl = arg;
- u32 *freq = arg;
-
- switch (cmd) {
- case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- switch (*freq) {
- case 32000: /* set sample rate to 32 kHz */
- tlv320aic23b_write(client, 8, 0x018);
- break;
- case 44100: /* set sample rate to 44.1 kHz */
- tlv320aic23b_write(client, 8, 0x022);
- break;
- case 48000: /* set sample rate to 48 kHz */
- tlv320aic23b_write(client, 8, 0x000);
- break;
- default:
- return -EINVAL;
- }
- break;
-
- case VIDIOC_G_CTRL:
- if (ctrl->id != V4L2_CID_AUDIO_MUTE)
- return -EINVAL;
- ctrl->value = state->muted;
+ switch (freq) {
+ case 32000: /* set sample rate to 32 kHz */
+ tlv320aic23b_write(sd, 8, 0x018);
break;
-
- case VIDIOC_S_CTRL:
- if (ctrl->id != V4L2_CID_AUDIO_MUTE)
- return -EINVAL;
- state->muted = ctrl->value;
- tlv320aic23b_write(client, 0, 0x180); /* mute both channels */
- /* set gain on both channels to +3.0 dB */
- if (!state->muted)
- tlv320aic23b_write(client, 0, 0x119);
+ case 44100: /* set sample rate to 44.1 kHz */
+ tlv320aic23b_write(sd, 8, 0x022);
break;
-
- case VIDIOC_LOG_STATUS:
- v4l_info(client, "Input: %s\n",
- state->muted ? "muted" : "active");
+ case 48000: /* set sample rate to 48 kHz */
+ tlv320aic23b_write(sd, 8, 0x000);
break;
-
default:
return -EINVAL;
}
return 0;
}
+static int tlv320aic23b_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct tlv320aic23b_state *state = to_state(sd);
+
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ ctrl->value = state->muted;
+ return 0;
+}
+
+static int tlv320aic23b_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct tlv320aic23b_state *state = to_state(sd);
+
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ state->muted = ctrl->value;
+ tlv320aic23b_write(sd, 0, 0x180); /* mute both channels */
+ /* set gain on both channels to +3.0 dB */
+ if (!state->muted)
+ tlv320aic23b_write(sd, 0, 0x119);
+ return 0;
+}
+
+static int tlv320aic23b_log_status(struct v4l2_subdev *sd)
+{
+ struct tlv320aic23b_state *state = to_state(sd);
+
+ v4l2_info(sd, "Input: %s\n", state->muted ? "muted" : "active");
+ return 0;
+}
+
+static int tlv320aic23b_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = {
+ .log_status = tlv320aic23b_log_status,
+ .g_ctrl = tlv320aic23b_g_ctrl,
+ .s_ctrl = tlv320aic23b_s_ctrl,
+};
+
+static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = {
+ .s_clock_freq = tlv320aic23b_s_clock_freq,
+};
+
+static const struct v4l2_subdev_ops tlv320aic23b_ops = {
+ .core = &tlv320aic23b_core_ops,
+ .audio = &tlv320aic23b_audio_ops,
+};
+
/* ----------------------------------------------------------------------- */
/* i2c implementation */
@@ -129,6 +157,7 @@ static int tlv320aic23b_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tlv320aic23b_state *state;
+ struct v4l2_subdev *sd;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -137,32 +166,36 @@ static int tlv320aic23b_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
+ state = kzalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &tlv320aic23b_ops);
state->muted = 0;
- i2c_set_clientdata(client, state);
/* Initialize tlv320aic23b */
/* RESET */
- tlv320aic23b_write(client, 15, 0x000);
+ tlv320aic23b_write(sd, 15, 0x000);
/* turn off DAC & mic input */
- tlv320aic23b_write(client, 6, 0x00A);
+ tlv320aic23b_write(sd, 6, 0x00A);
/* left-justified, 24-bit, master mode */
- tlv320aic23b_write(client, 7, 0x049);
+ tlv320aic23b_write(sd, 7, 0x049);
/* set gain on both channels to +3.0 dB */
- tlv320aic23b_write(client, 0, 0x119);
+ tlv320aic23b_write(sd, 0, 0x119);
/* set sample rate to 48 kHz */
- tlv320aic23b_write(client, 8, 0x000);
+ tlv320aic23b_write(sd, 8, 0x000);
/* activate digital interface */
- tlv320aic23b_write(client, 9, 0x001);
+ tlv320aic23b_write(sd, 9, 0x001);
return 0;
}
static int tlv320aic23b_remove(struct i2c_client *client)
{
- kfree(i2c_get_clientdata(client));
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
return 0;
}
diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c
index 5dd4bd660..0188d87ea 100644
--- a/linux/drivers/media/video/tuner-core.c
+++ b/linux/drivers/media/video/tuner-core.c
@@ -19,7 +19,7 @@
#include <linux/videodev.h>
#include <media/tuner.h>
#include <media/tuner-types.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include "mt20xx.h"
@@ -79,6 +79,7 @@ struct tuner {
/* device */
struct dvb_frontend fe;
struct i2c_client *i2c;
+ struct v4l2_subdev sd;
struct list_head list;
unsigned int using_v4l2:1;
@@ -96,6 +97,11 @@ struct tuner {
const char *name;
};
+static inline struct tuner *to_tuner(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tuner, sd);
+}
+
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
@@ -214,7 +220,7 @@ static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
static void tuner_status(struct dvb_frontend *fe);
-static struct analog_demod_ops tuner_core_ops = {
+static struct analog_demod_ops tuner_analog_ops = {
.set_params = fe_set_params,
.standby = fe_standby,
.has_signal = fe_has_signal,
@@ -225,7 +231,7 @@ static struct analog_demod_ops tuner_core_ops = {
/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
static void set_tv_freq(struct i2c_client *c, unsigned int freq)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner *t = to_tuner(i2c_get_clientdata(c));
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
struct analog_parameters params = {
@@ -260,7 +266,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner *t = to_tuner(i2c_get_clientdata(c));
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
struct analog_parameters params = {
@@ -295,7 +301,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
static void set_freq(struct i2c_client *c, unsigned long freq)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner *t = to_tuner(i2c_get_clientdata(c));
switch (t->mode) {
case V4L2_TUNER_RADIO:
@@ -348,7 +354,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
unsigned int new_mode_mask, unsigned int new_config,
int (*tuner_callback) (void *dev, int component, int cmd, int arg))
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner *t = to_tuner(i2c_get_clientdata(c));
struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
unsigned char buffer[4];
@@ -471,7 +477,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
t->name = fe_tuner_ops->info.name;
t->fe.analog_demod_priv = t;
- memcpy(analog_ops, &tuner_core_ops,
+ memcpy(analog_ops, &tuner_analog_ops,
sizeof(struct analog_demod_ops));
} else {
@@ -516,7 +522,7 @@ attach_failed:
static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner *t = to_tuner(i2c_get_clientdata(c));
if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
(t->mode_mask & tun_setup->mode_mask))) ||
@@ -731,6 +737,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
t->mode = mode;
if (check_mode(t, cmd) == -EINVAL) {
+ tuner_dbg("Tuner doesn't support this mode. "
+ "Putting tuner to sleep\n");
t->mode = T_STANDBY;
if (analog_ops->standby)
analog_ops->standby(&t->fe);
@@ -758,43 +766,58 @@ static inline int check_v4l2(struct tuner *t)
return 0;
}
-static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner_setup *type)
{
- struct tuner *t = i2c_get_clientdata(client);
- struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+ struct tuner *t = to_tuner(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
+ type->type,
+ type->addr,
+ type->mode_mask,
+ type->config);
+
+ set_addr(client, type);
+ return 0;
+}
+
+static int tuner_s_radio(struct v4l2_subdev *sd)
+{
+ struct tuner *t = to_tuner(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
+ == -EINVAL)
+ return 0;
+ if (t->radio_freq)
+ set_freq(client, t->radio_freq);
+ return 0;
+}
+
+static int tuner_s_standby(struct v4l2_subdev *sd, u32 standby)
+{
+ struct tuner *t = to_tuner(sd);
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- if (tuner_debug > 1) {
- v4l_i2c_print_ioctl(client,cmd);
- printk("\n");
- }
+ tuner_dbg("Putting tuner to sleep\n");
+
+ if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL)
+ return 0;
+ t->mode = T_STANDBY;
+ if (analog_ops->standby)
+ analog_ops->standby(&t->fe);
+ return 0;
+}
- switch (cmd) {
- /* --- configuration --- */
- case TUNER_SET_TYPE_ADDR:
- tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
- ((struct tuner_setup *)arg)->type,
- ((struct tuner_setup *)arg)->addr,
- ((struct tuner_setup *)arg)->mode_mask,
- ((struct tuner_setup *)arg)->config);
-
- set_addr(client, (struct tuner_setup *)arg);
- break;
- case AUDC_SET_RADIO:
- if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
- == -EINVAL)
- return 0;
- if (t->radio_freq)
- set_freq(client, t->radio_freq);
- break;
- case TUNER_SET_STANDBY:
- if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL)
- return 0;
- t->mode = T_STANDBY;
- if (analog_ops->standby)
- analog_ops->standby(&t->fe);
- break;
#ifdef CONFIG_VIDEO_ALLOW_V4L1
+static long tuner_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct tuner *t = to_tuner(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+ switch (cmd) {
case VIDIOCSAUDIO:
if (check_mode(t, "VIDIOCSAUDIO") == -EINVAL)
return 0;
@@ -907,149 +930,172 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
return 0;
}
+ }
+ return -ENOIOCTLCMD;
+}
#endif
- case TUNER_SET_CONFIG:
- {
- struct v4l2_priv_tun_config *cfg = arg;
- if (t->type != cfg->tuner)
- break;
+static int tuner_s_config(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *cfg)
+{
+ struct tuner *t = to_tuner(sd);
+ struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- if (analog_ops->set_config) {
- analog_ops->set_config(&t->fe, cfg->priv);
- break;
- }
+ if (t->type != cfg->tuner)
+ return 0;
- tuner_dbg("Tuner frontend module has no way to set config\n");
- break;
+ if (analog_ops->set_config) {
+ analog_ops->set_config(&t->fe, cfg->priv);
+ return 0;
}
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
- if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
- == -EINVAL)
- return 0;
+ tuner_dbg("Tuner frontend module has no way to set config\n");
+ return 0;
+}
- switch_v4l2();
+/* --- v4l ioctls --- */
+/* take care: bttv does userspace copying, we'll get a
+ kernel pointer here... */
+static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct tuner *t = to_tuner(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- t->std = *id;
- tuner_fixup_std(t);
- if (t->tv_freq)
- set_freq(client, t->tv_freq);
- break;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+ if (set_mode(client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
+ == -EINVAL)
+ return 0;
- if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
- == -EINVAL)
- return 0;
- switch_v4l2();
- set_freq(client,f->frequency);
+ switch_v4l2();
- break;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+ t->std = std;
+ tuner_fixup_std(t);
+ if (t->tv_freq)
+ set_freq(client, t->tv_freq);
+ return 0;
+}
- if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL)
- return 0;
- switch_v4l2();
- f->type = t->mode;
- if (fe_tuner_ops->get_frequency) {
- u32 abs_freq;
-
- fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
- f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
- (abs_freq * 2 + 125/2) / 125 :
- (abs_freq + 62500/2) / 62500;
- break;
- }
- f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
- t->radio_freq : t->tv_freq;
- break;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *tuner = arg;
+static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+{
+ struct tuner *t = to_tuner(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL)
- return 0;
- switch_v4l2();
-
- tuner->type = t->mode;
- if (analog_ops->get_afc)
- tuner->afc = analog_ops->get_afc(&t->fe);
- if (t->mode == V4L2_TUNER_ANALOG_TV)
- tuner->capability |= V4L2_TUNER_CAP_NORM;
- if (t->mode != V4L2_TUNER_RADIO) {
- tuner->rangelow = tv_range[0] * 16;
- tuner->rangehigh = tv_range[1] * 16;
- break;
- }
+ if (set_mode(client, t, f->type, "VIDIOC_S_FREQUENCY")
+ == -EINVAL)
+ return 0;
+ switch_v4l2();
+ set_freq(client, f->frequency);
- /* radio mode */
- tuner->rxsubchans =
- V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- if (fe_tuner_ops->get_status) {
- u32 tuner_status;
-
- fe_tuner_ops->get_status(&t->fe, &tuner_status);
- tuner->rxsubchans =
- (tuner_status & TUNER_STATUS_STEREO) ?
- V4L2_TUNER_SUB_STEREO :
- V4L2_TUNER_SUB_MONO;
- } else {
- if (analog_ops->is_stereo) {
- tuner->rxsubchans =
- analog_ops->is_stereo(&t->fe) ?
- V4L2_TUNER_SUB_STEREO :
- V4L2_TUNER_SUB_MONO;
- }
- }
- if (analog_ops->has_signal)
- tuner->signal = analog_ops->has_signal(&t->fe);
- tuner->capability |=
- V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
- tuner->audmode = t->audmode;
- tuner->rangelow = radio_range[0] * 16000;
- tuner->rangehigh = radio_range[1] * 16000;
- break;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *tuner = arg;
+ return 0;
+}
- if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL)
- return 0;
+static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+{
+ struct tuner *t = to_tuner(sd);
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
- switch_v4l2();
+ if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL)
+ return 0;
+ switch_v4l2();
+ f->type = t->mode;
+ if (fe_tuner_ops->get_frequency) {
+ u32 abs_freq;
+
+ fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
+ f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
+ (abs_freq * 2 + 125/2) / 125 :
+ (abs_freq + 62500/2) / 62500;
+ return 0;
+ }
+ f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
+ t->radio_freq : t->tv_freq;
+ return 0;
+}
- /* do nothing unless we're a radio tuner */
- if (t->mode != V4L2_TUNER_RADIO)
- break;
- t->audmode = tuner->audmode;
- set_radio_freq(client, t->radio_freq);
- break;
+static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct tuner *t = to_tuner(sd);
+ struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+ if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL)
+ return 0;
+ switch_v4l2();
+
+ vt->type = t->mode;
+ if (analog_ops->get_afc)
+ vt->afc = analog_ops->get_afc(&t->fe);
+ if (t->mode == V4L2_TUNER_ANALOG_TV)
+ vt->capability |= V4L2_TUNER_CAP_NORM;
+ if (t->mode != V4L2_TUNER_RADIO) {
+ vt->rangelow = tv_range[0] * 16;
+ vt->rangehigh = tv_range[1] * 16;
+ return 0;
+ }
+
+ /* radio mode */
+ vt->rxsubchans =
+ V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ if (fe_tuner_ops->get_status) {
+ u32 tuner_status;
+
+ fe_tuner_ops->get_status(&t->fe, &tuner_status);
+ vt->rxsubchans =
+ (tuner_status & TUNER_STATUS_STEREO) ?
+ V4L2_TUNER_SUB_STEREO :
+ V4L2_TUNER_SUB_MONO;
+ } else {
+ if (analog_ops->is_stereo) {
+ vt->rxsubchans =
+ analog_ops->is_stereo(&t->fe) ?
+ V4L2_TUNER_SUB_STEREO :
+ V4L2_TUNER_SUB_MONO;
}
- case VIDIOC_LOG_STATUS:
- if (analog_ops->tuner_status)
- analog_ops->tuner_status(&t->fe);
- break;
}
+ if (analog_ops->has_signal)
+ vt->signal = analog_ops->has_signal(&t->fe);
+ vt->capability |=
+ V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ vt->audmode = t->audmode;
+ vt->rangelow = radio_range[0] * 16000;
+ vt->rangehigh = radio_range[1] * 16000;
+ return 0;
+}
+
+static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct tuner *t = to_tuner(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL)
+ return 0;
+
+ switch_v4l2();
+
+ /* do nothing unless we're a radio tuner */
+ if (t->mode != V4L2_TUNER_RADIO)
+ return 0;
+ t->audmode = vt->audmode;
+ set_radio_freq(client, t->radio_freq);
return 0;
}
+static int tuner_log_status(struct v4l2_subdev *sd)
+{
+ struct tuner *t = to_tuner(sd);
+ struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
+ if (analog_ops->tuner_status)
+ analog_ops->tuner_status(&t->fe);
+ return 0;
+}
+
+static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
static int tuner_suspend(struct i2c_client *c, pm_message_t state)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner *t = to_tuner(i2c_get_clientdata(c));
tuner_dbg("suspend\n");
/* FIXME: power down ??? */
@@ -1058,7 +1104,7 @@ static int tuner_suspend(struct i2c_client *c, pm_message_t state)
static int tuner_resume(struct i2c_client *c)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner *t = to_tuner(i2c_get_clientdata(c));
tuner_dbg("resume\n");
if (V4L2_TUNER_RADIO == t->mode) {
@@ -1071,6 +1117,32 @@ static int tuner_resume(struct i2c_client *c)
return 0;
}
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tuner_core_ops = {
+ .log_status = tuner_log_status,
+ .s_standby = tuner_s_standby,
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
+ .ioctl = tuner_ioctl,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = {
+ .s_std = tuner_s_std,
+ .s_radio = tuner_s_radio,
+ .g_tuner = tuner_g_tuner,
+ .s_tuner = tuner_s_tuner,
+ .s_frequency = tuner_s_frequency,
+ .g_frequency = tuner_g_frequency,
+ .s_type_addr = tuner_s_type_addr,
+ .s_config = tuner_s_config,
+};
+
+static const struct v4l2_subdev_ops tuner_ops = {
+ .core = &tuner_core_ops,
+ .tuner = &tuner_tuner_ops,
+};
+
/* ---------------------------------------------------------------------- */
static LIST_HEAD(tuner_list);
@@ -1119,9 +1191,9 @@ static int tuner_probe(struct i2c_client *client,
t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
if (NULL == t)
return -ENOMEM;
+ v4l2_i2c_subdev_init(&t->sd, client, &tuner_ops);
t->i2c = client;
t->name = "(tuner unset)";
- i2c_set_clientdata(client, t);
t->type = UNSET;
t->audmode = V4L2_TUNER_MODE_STEREO;
t->mode_mask = T_UNINITIALIZED;
@@ -1271,8 +1343,9 @@ static int tuner_legacy_probe(struct i2c_adapter *adap)
static int tuner_remove(struct i2c_client *client)
{
- struct tuner *t = i2c_get_clientdata(client);
+ struct tuner *t = to_tuner(i2c_get_clientdata(client));
+ v4l2_device_unregister_subdev(&t->sd);
tuner_detach(&t->fe);
t->fe.analog_demod_priv = NULL;
diff --git a/linux/drivers/media/video/tvaudio.c b/linux/drivers/media/video/tvaudio.c
index 0a86c80a2..3ca242af5 100644
--- a/linux/drivers/media/video/tvaudio.c
+++ b/linux/drivers/media/video/tvaudio.c
@@ -36,8 +36,7 @@
#include "compat.h"
#include <media/tvaudio.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv-legacy.h>
@@ -113,7 +112,7 @@ struct CHIPDESC {
/* current state of the chip */
struct CHIPSTATE {
- struct i2c_client *c;
+ struct v4l2_subdev sd;
/* chip-specific description - should point to
an entry at CHIPDESC table */
@@ -135,6 +134,11 @@ struct CHIPSTATE {
int audmode;
};
+static inline struct CHIPSTATE *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct CHIPSTATE, sd);
+}
+
/* ---------------------------------------------------------------------- */
/* i2c addresses */
@@ -155,34 +159,34 @@ I2C_CLIENT_INSMOD;
static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
{
+ struct v4l2_subdev *sd = &chip->sd;
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
unsigned char buffer[2];
if (subaddr < 0) {
- v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n",
- chip->c->name, val);
+ v4l2_dbg(1, debug, sd, "chip_write: 0x%x\n", val);
chip->shadow.bytes[1] = val;
buffer[0] = val;
- if (1 != i2c_master_send(chip->c,buffer,1)) {
- v4l_warn(chip->c, "%s: I/O error (write 0x%x)\n",
- chip->c->name, val);
+ if (1 != i2c_master_send(c, buffer, 1)) {
+ v4l2_warn(sd, "I/O error (write 0x%x)\n", val);
return -1;
}
} else {
if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
- v4l_info(chip->c,
+ v4l2_info(sd,
"Tried to access a non-existent register: %d\n",
subaddr);
return -EINVAL;
}
- v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n",
- chip->c->name, subaddr, val);
+ v4l2_dbg(1, debug, sd, "chip_write: reg%d=0x%x\n",
+ subaddr, val);
chip->shadow.bytes[subaddr+1] = val;
buffer[0] = subaddr;
buffer[1] = val;
- if (2 != i2c_master_send(chip->c,buffer,2)) {
- v4l_warn(chip->c, "%s: I/O error (write reg%d=0x%x)\n",
- chip->c->name, subaddr, val);
+ if (2 != i2c_master_send(c, buffer, 2)) {
+ v4l2_warn(sd, "I/O error (write reg%d=0x%x)\n",
+ subaddr, val);
return -1;
}
}
@@ -192,12 +196,14 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
static int chip_write_masked(struct CHIPSTATE *chip,
int subaddr, int val, int mask)
{
+ struct v4l2_subdev *sd = &chip->sd;
+
if (mask != 0) {
if (subaddr < 0) {
val = (chip->shadow.bytes[1] & ~mask) | (val & mask);
} else {
if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
- v4l_info(chip->c,
+ v4l2_info(sd,
"Tried to access a non-existent register: %d\n",
subaddr);
return -EINVAL;
@@ -211,45 +217,51 @@ static int chip_write_masked(struct CHIPSTATE *chip,
static int chip_read(struct CHIPSTATE *chip)
{
+ struct v4l2_subdev *sd = &chip->sd;
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
unsigned char buffer;
- if (1 != i2c_master_recv(chip->c,&buffer,1)) {
- v4l_warn(chip->c, "%s: I/O error (read)\n",
- chip->c->name);
+ if (1 != i2c_master_recv(c, &buffer, 1)) {
+ v4l2_warn(sd, "I/O error (read)\n");
return -1;
}
- v4l_dbg(1, debug, chip->c, "%s: chip_read: 0x%x\n",chip->c->name, buffer);
+ v4l2_dbg(1, debug, sd, "chip_read: 0x%x\n", buffer);
return buffer;
}
static int chip_read2(struct CHIPSTATE *chip, int subaddr)
{
+ struct v4l2_subdev *sd = &chip->sd;
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
unsigned char write[1];
unsigned char read[1];
struct i2c_msg msgs[2] = {
- { chip->c->addr, 0, 1, write },
- { chip->c->addr, I2C_M_RD, 1, read }
+ { c->addr, 0, 1, write },
+ { c->addr, I2C_M_RD, 1, read }
};
+
write[0] = subaddr;
- if (2 != i2c_transfer(chip->c->adapter,msgs,2)) {
- v4l_warn(chip->c, "%s: I/O error (read2)\n", chip->c->name);
+ if (2 != i2c_transfer(c->adapter, msgs, 2)) {
+ v4l2_warn(sd, "I/O error (read2)\n");
return -1;
}
- v4l_dbg(1, debug, chip->c, "%s: chip_read2: reg%d=0x%x\n",
- chip->c->name, subaddr,read[0]);
+ v4l2_dbg(1, debug, sd, "chip_read2: reg%d=0x%x\n",
+ subaddr, read[0]);
return read[0];
}
static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
{
+ struct v4l2_subdev *sd = &chip->sd;
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
int i;
if (0 == cmd->count)
return 0;
if (cmd->count + cmd->bytes[0] - 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
- v4l_info(chip->c,
+ v4l2_info(sd,
"Tried to access a non-existent register range: %d to %d\n",
cmd->bytes[0] + 1, cmd->bytes[0] + cmd->count - 1);
return -EINVAL;
@@ -258,19 +270,19 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
/* FIXME: it seems that the shadow bytes are wrong bellow !*/
/* update our shadow register set; print bytes if (debug > 0) */
- v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:",
- chip->c->name, name,cmd->bytes[0]);
+ v4l2_dbg(1, debug, sd, "chip_cmd(%s): reg=%d, data:",
+ name, cmd->bytes[0]);
for (i = 1; i < cmd->count; i++) {
if (debug)
- printk(" 0x%x",cmd->bytes[i]);
+ printk(KERN_CONT " 0x%x", cmd->bytes[i]);
chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i];
}
if (debug)
- printk("\n");
+ printk(KERN_CONT "\n");
/* send data to the chip */
- if (cmd->count != i2c_master_send(chip->c,cmd->bytes,cmd->count)) {
- v4l_warn(chip->c, "%s: I/O error (%s)\n", chip->c->name, name);
+ if (cmd->count != i2c_master_send(c, cmd->bytes, cmd->count)) {
+ v4l2_warn(sd, "I/O error (%s)\n", name);
return -1;
}
return 0;
@@ -293,9 +305,10 @@ static int chip_thread(void *data)
{
struct CHIPSTATE *chip = data;
struct CHIPDESC *desc = chip->desc;
+ struct v4l2_subdev *sd = &chip->sd;
int mode;
- v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name);
+ v4l2_dbg(1, debug, sd, "thread started\n");
set_freezable();
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
@@ -305,7 +318,7 @@ static int chip_thread(void *data)
try_to_freeze();
if (kthread_should_stop())
break;
- v4l_dbg(1, debug, chip->c, "%s: thread wakeup\n", chip->c->name);
+ v4l2_dbg(1, debug, sd, "thread wakeup\n");
/* don't do anything for radio or if mode != auto */
if (chip->radio || chip->mode != 0)
@@ -317,8 +330,7 @@ static int chip_thread(void *data)
continue;
/* chip detected a new audio mode - set it */
- v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n",
- chip->c->name);
+ v4l2_dbg(1, debug, sd, "thread checkmode\n");
chip->prevmode = mode;
@@ -337,7 +349,7 @@ static int chip_thread(void *data)
mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
}
- v4l_dbg(1, debug, chip->c, "%s: thread exiting\n", chip->c->name);
+ v4l2_dbg(1, debug, sd, "thread exiting\n");
return 0;
}
@@ -366,6 +378,7 @@ static int chip_thread(void *data)
static int tda9840_getmode(struct CHIPSTATE *chip)
{
+ struct v4l2_subdev *sd = &chip->sd;
int val, mode;
val = chip_read(chip);
@@ -375,7 +388,7 @@ static int tda9840_getmode(struct CHIPSTATE *chip)
if (val & TDA9840_ST_STEREO)
mode |= V4L2_TUNER_MODE_STEREO;
- v4l_dbg(1, debug, chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
+ v4l2_dbg(1, debug, sd, "tda9840_getmode(): raw chip read: %d, return: %d\n",
val, mode);
return mode;
}
@@ -671,6 +684,7 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
static int tda9873_getmode(struct CHIPSTATE *chip)
{
+ struct v4l2_subdev *sd = &chip->sd;
int val,mode;
val = chip_read(chip);
@@ -679,23 +693,24 @@ static int tda9873_getmode(struct CHIPSTATE *chip)
mode |= V4L2_TUNER_MODE_STEREO;
if (val & TDA9873_DUAL)
mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
- v4l_dbg(1, debug, chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
+ v4l2_dbg(1, debug, sd, "tda9873_getmode(): raw chip read: %d, return: %d\n",
val, mode);
return mode;
}
static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
{
+ struct v4l2_subdev *sd = &chip->sd;
int sw_data = chip->shadow.bytes[TDA9873_SW+1] & ~ TDA9873_TR_MASK;
/* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
- v4l_dbg(1, debug, chip->c, "tda9873_setmode(): external input\n");
+ v4l2_dbg(1, debug, sd, "tda9873_setmode(): external input\n");
return;
}
- v4l_dbg(1, debug, chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
- v4l_dbg(1, debug, chip->c, "tda9873_setmode(): sw_data = %d\n", sw_data);
+ v4l2_dbg(1, debug, sd, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
+ v4l2_dbg(1, debug, sd, "tda9873_setmode(): sw_data = %d\n", sw_data);
switch (mode) {
case V4L2_TUNER_MODE_MONO:
@@ -716,7 +731,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
}
chip_write(chip, TDA9873_SW, sw_data);
- v4l_dbg(1, debug, chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
+ v4l2_dbg(1, debug, sd, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
mode, sw_data);
}
@@ -825,6 +840,8 @@ static struct tda9874a_MODES {
static int tda9874a_setup(struct CHIPSTATE *chip)
{
+ struct v4l2_subdev *sd = &chip->sd;
+
chip_write(chip, TDA9874A_AGCGR, 0x00); /* 0 dB */
chip_write(chip, TDA9874A_GCONR, tda9874a_GCONR);
chip_write(chip, TDA9874A_MSR, (tda9874a_mode) ? 0x03:0x02);
@@ -855,13 +872,14 @@ static int tda9874a_setup(struct CHIPSTATE *chip)
chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */
}
- v4l_dbg(1, debug, chip->c, "tda9874a_setup(): %s [0x%02X].\n",
+ v4l2_dbg(1, debug, sd, "tda9874a_setup(): %s [0x%02X].\n",
tda9874a_modelist[tda9874a_STD].name,tda9874a_STD);
return 1;
}
static int tda9874a_getmode(struct CHIPSTATE *chip)
{
+ struct v4l2_subdev *sd = &chip->sd;
int dsr,nsr,mode;
int necr; /* just for debugging */
@@ -903,16 +921,18 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
}
- v4l_dbg(1, debug, chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
+ v4l2_dbg(1, debug, sd, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
dsr, nsr, necr, mode);
return mode;
}
static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
{
+ struct v4l2_subdev *sd = &chip->sd;
+
/* Disable/enable NICAM auto-muting (based on DSR.RSSF status bit). */
/* If auto-muting is disabled, we can hear a signal of degrading quality. */
- if(tda9874a_mode) {
+ if (tda9874a_mode) {
if(chip->shadow.bytes[MAXREGS-2] & 0x20) /* DSR.RSSF=1 */
tda9874a_NCONR &= 0xfe; /* enable */
else
@@ -949,7 +969,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
chip_write(chip, TDA9874A_AOSR, aosr);
chip_write(chip, TDA9874A_MDACOSR, mdacosr);
- v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
+ v4l2_dbg(1, debug, sd, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
mode, aosr, mdacosr);
} else { /* dic == 0x07 */
@@ -984,13 +1004,14 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
chip_write(chip, TDA9874A_FMMR, fmmr);
chip_write(chip, TDA9874A_AOSR, aosr);
- v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
+ v4l2_dbg(1, debug, sd, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
mode, fmmr, aosr);
}
}
static int tda9874a_checkit(struct CHIPSTATE *chip)
{
+ struct v4l2_subdev *sd = &chip->sd;
int dic,sic; /* device id. and software id. codes */
if(-1 == (dic = chip_read2(chip,TDA9874A_DIC)))
@@ -998,10 +1019,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip)
if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
return 0;
- v4l_dbg(1, debug, chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
+ v4l2_dbg(1, debug, sd, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
if((dic == 0x11)||(dic == 0x07)) {
- v4l_info(chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
+ v4l2_info(sd, "found tda9874%s.\n", (dic == 0x11) ? "a" : "h");
tda9874a_dic = dic; /* remember device id. */
return 1;
}
@@ -1121,12 +1142,12 @@ static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
static int tda8425_initialize(struct CHIPSTATE *chip)
{
struct CHIPDESC *desc = chip->desc;
+ struct i2c_client *c = v4l2_get_subdevdata(&chip->sd);
int inputmap[4] = { /* tuner */ TDA8425_S1_CH2, /* radio */ TDA8425_S1_CH1,
/* extern */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF};
- if (chip->c->adapter->id == I2C_HW_B_RIVA) {
- memcpy (desc->inputmap, inputmap, sizeof (inputmap));
- }
+ if (c->adapter->id == I2C_HW_B_RIVA)
+ memcpy(desc->inputmap, inputmap, sizeof(inputmap));
return 0;
}
@@ -1223,9 +1244,11 @@ static audiocmd ta8874z_sub = {2, { TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT
static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
{
+ struct v4l2_subdev *sd = &chip->sd;
int update = 1;
audiocmd *t = NULL;
- v4l_dbg(1, debug, chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
+
+ v4l2_dbg(1, debug, sd, "ta8874z_setmode(): mode: 0x%02x\n", mode);
switch(mode){
case V4L2_TUNER_MODE_MONO:
@@ -1487,146 +1510,11 @@ static struct CHIPDESC chiplist[] = {
/* ---------------------------------------------------------------------- */
-/* i2c registration */
-static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
-{
- struct CHIPSTATE *chip;
- struct CHIPDESC *desc;
-
- if (debug) {
- printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
- printk(KERN_INFO "tvaudio: known chips: ");
- for (desc = chiplist; desc->name != NULL; desc++)
- printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
- printk("\n");
- }
-
- chip = kzalloc(sizeof(*chip),GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
- chip->c = client;
- i2c_set_clientdata(client, chip);
-
- /* find description for the chip */
- v4l_dbg(1, debug, client, "chip found @ 0x%x\n", client->addr<<1);
- for (desc = chiplist; desc->name != NULL; desc++) {
- if (0 == *(desc->insmodopt))
- continue;
- if (client->addr < desc->addr_lo ||
- client->addr > desc->addr_hi)
- continue;
- if (desc->checkit && !desc->checkit(chip))
- continue;
- break;
- }
- if (desc->name == NULL) {
- v4l_dbg(1, debug, client, "no matching chip description found\n");
- kfree(chip);
- return -EIO;
- }
- v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
- if (desc->flags) {
- v4l_dbg(1, debug, client, "matches:%s%s%s.\n",
- (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "",
- (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
- (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : "");
- }
-
- /* fill required data structures */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
- strlcpy(client->name, desc->name, I2C_NAME_SIZE);
-#else
- if (!id)
- strlcpy(client->name, desc->name, I2C_NAME_SIZE);
-#endif
- chip->desc = desc;
- chip->shadow.count = desc->registers+1;
- chip->prevmode = -1;
- chip->audmode = V4L2_TUNER_MODE_LANG1;
-
- /* initialization */
- if (desc->initialize != NULL)
- desc->initialize(chip);
- else
- chip_cmd(chip,"init",&desc->init);
-
- if (desc->flags & CHIP_HAS_VOLUME) {
- if (!desc->volfunc) {
- /* This shouldn't be happen. Warn user, but keep working
- without volume controls
- */
- v4l_info(chip->c, "volume callback undefined!\n");
- desc->flags &= ~CHIP_HAS_VOLUME;
- } else {
- chip->left = desc->leftinit ? desc->leftinit : 65535;
- chip->right = desc->rightinit ? desc->rightinit : 65535;
- chip_write(chip, desc->leftreg,
- desc->volfunc(chip->left));
- chip_write(chip, desc->rightreg,
- desc->volfunc(chip->right));
- }
- }
- if (desc->flags & CHIP_HAS_BASSTREBLE) {
- if (!desc->bassfunc || !desc->treblefunc) {
- /* This shouldn't be happen. Warn user, but keep working
- without bass/treble controls
- */
- v4l_info(chip->c, "bass/treble callbacks undefined!\n");
- desc->flags &= ~CHIP_HAS_BASSTREBLE;
- } else {
- chip->treble = desc->trebleinit ?
- desc->trebleinit : 32768;
- chip->bass = desc->bassinit ?
- desc->bassinit : 32768;
- chip_write(chip, desc->bassreg,
- desc->bassfunc(chip->bass));
- chip_write(chip, desc->treblereg,
- desc->treblefunc(chip->treble));
- }
- }
-
- chip->thread = NULL;
- if (desc->flags & CHIP_NEED_CHECKMODE) {
- if (!desc->getmode || !desc->setmode) {
- /* This shouldn't be happen. Warn user, but keep working
- without kthread
- */
- v4l_info(chip->c, "set/get mode callbacks undefined!\n");
- return 0;
- }
- /* start async thread */
- init_timer(&chip->wt);
- chip->wt.function = chip_thread_wake;
- chip->wt.data = (unsigned long)chip;
- chip->thread = kthread_run(chip_thread, chip, chip->c->name);
- if (IS_ERR(chip->thread)) {
- v4l_warn(chip->c, "%s: failed to create kthread\n",
- chip->c->name);
- chip->thread = NULL;
- }
- }
- return 0;
-}
-
-static int chip_remove(struct i2c_client *client)
-{
- struct CHIPSTATE *chip = i2c_get_clientdata(client);
-
- del_timer_sync(&chip->wt);
- if (chip->thread) {
- /* shutdown async thread */
- kthread_stop(chip->thread);
- chip->thread = NULL;
- }
-
- kfree(chip);
- return 0;
-}
-
-static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
+static int tvaudio_g_ctrl(struct v4l2_subdev *sd,
struct v4l2_control *ctrl)
{
+ struct CHIPSTATE *chip = to_state(sd);
struct CHIPDESC *desc = chip->desc;
switch (ctrl->id) {
@@ -1664,9 +1552,10 @@ static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
return -EINVAL;
}
-static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
+static int tvaudio_s_ctrl(struct v4l2_subdev *sd,
struct v4l2_control *ctrl)
{
+ struct CHIPSTATE *chip = to_state(sd);
struct CHIPDESC *desc = chip->desc;
switch (ctrl->id) {
@@ -1738,161 +1627,331 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
/* ---------------------------------------------------------------------- */
/* video4linux interface */
-static int chip_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
+static int tvaudio_s_radio(struct v4l2_subdev *sd)
{
- struct CHIPSTATE *chip = i2c_get_clientdata(client);
- struct CHIPDESC *desc = chip->desc;
+ struct CHIPSTATE *chip = to_state(sd);
- if (debug > 0) {
- v4l_i2c_print_ioctl(chip->c, cmd);
- printk("\n");
+ chip->radio = 1;
+ chip->watch_stereo = 0;
+ /* del_timer(&chip->wt); */
+ return 0;
+}
+
+static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ struct CHIPSTATE *chip = to_state(sd);
+ struct CHIPDESC *desc = chip->desc;
+
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BALANCE:
+ if (!(desc->flags & CHIP_HAS_VOLUME))
+ return -EINVAL;
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ if (!(desc->flags & CHIP_HAS_BASSTREBLE))
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return v4l2_ctrl_query_fill_std(qc);
+}
+
+static int tvaudio_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *rt)
+{
+ struct CHIPSTATE *chip = to_state(sd);
+ struct CHIPDESC *desc = chip->desc;
+
+ if (!(desc->flags & CHIP_HAS_INPUTSEL) || rt->input >= 4)
+ return -EINVAL;
+ /* There are four inputs: tuner, radio, extern and intern. */
+ chip->input = rt->input;
+ if (chip->muted)
+ return 0;
+ chip_write_masked(chip, desc->inputreg,
+ desc->inputmap[chip->input], desc->inputmask);
+ return 0;
+}
+
+static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct CHIPSTATE *chip = to_state(sd);
+ struct CHIPDESC *desc = chip->desc;
+ int mode = 0;
+
+ if (chip->radio)
+ return 0;
+ switch (vt->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ case V4L2_TUNER_MODE_STEREO:
+ case V4L2_TUNER_MODE_LANG1:
+ case V4L2_TUNER_MODE_LANG2:
+ mode = vt->audmode;
+ break;
+ case V4L2_TUNER_MODE_LANG1_LANG2:
+ mode = V4L2_TUNER_MODE_STEREO;
+ break;
+ default:
+ return -EINVAL;
}
+ chip->audmode = vt->audmode;
- switch (cmd) {
- case AUDC_SET_RADIO:
- chip->radio = 1;
+ if (desc->setmode && mode) {
chip->watch_stereo = 0;
/* del_timer(&chip->wt); */
- break;
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
-
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- break;
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BALANCE:
- if (!(desc->flags & CHIP_HAS_VOLUME))
- return -EINVAL;
- break;
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- if (!(desc->flags & CHIP_HAS_BASSTREBLE))
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
- return v4l2_ctrl_query_fill_std(qc);
+ chip->mode = mode;
+ desc->setmode(chip, mode);
}
- case VIDIOC_S_CTRL:
- return tvaudio_set_ctrl(chip, arg);
+ return 0;
+}
- case VIDIOC_G_CTRL:
- return tvaudio_get_ctrl(chip, arg);
- case VIDIOC_INT_G_AUDIO_ROUTING:
- {
- struct v4l2_routing *rt = arg;
+static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct CHIPSTATE *chip = to_state(sd);
+ struct CHIPDESC *desc = chip->desc;
+ int mode = V4L2_TUNER_MODE_MONO;
- rt->input = chip->input;
- rt->output = 0;
- break;
+ if (chip->radio)
+ return 0;
+ vt->audmode = chip->audmode;
+ vt->rxsubchans = 0;
+ vt->capability = V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+
+ if (desc->getmode)
+ mode = desc->getmode(chip);
+
+ if (mode & V4L2_TUNER_MODE_MONO)
+ vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
+ if (mode & V4L2_TUNER_MODE_STEREO)
+ vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+ /* Note: for SAP it should be mono/lang2 or stereo/lang2.
+ When this module is converted fully to v4l2, then this
+ should change for those chips that can detect SAP. */
+ if (mode & V4L2_TUNER_MODE_LANG1)
+ vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
+ V4L2_TUNER_SUB_LANG2;
+ return 0;
+}
+
+static int tvaudio_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct CHIPSTATE *chip = to_state(sd);
+
+ chip->radio = 0;
+ return 0;
+}
+
+static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+ struct CHIPSTATE *chip = to_state(sd);
+ struct CHIPDESC *desc = chip->desc;
+
+ chip->mode = 0; /* automatic */
+
+ /* For chips that provide getmode and setmode, and doesn't
+ automatically follows the stereo carrier, a kthread is
+ created to set the audio standard. In this case, when then
+ the video channel is changed, tvaudio starts on MONO mode.
+ After waiting for 2 seconds, the kernel thread is called,
+ to follow whatever audio standard is pointed by the
+ audio carrier.
+ */
+ if (chip->thread) {
+ desc->setmode(chip, V4L2_TUNER_MODE_MONO);
+ if (chip->prevmode != V4L2_TUNER_MODE_MONO)
+ chip->prevmode = -1; /* reset previous mode */
+ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
}
- case VIDIOC_INT_S_AUDIO_ROUTING:
- {
- struct v4l2_routing *rt = arg;
+ return 0;
+}
- if (!(desc->flags & CHIP_HAS_INPUTSEL) || rt->input >= 4)
- return -EINVAL;
- /* There are four inputs: tuner, radio, extern and intern. */
- chip->input = rt->input;
- if (chip->muted)
- break;
- chip_write_masked(chip, desc->inputreg,
- desc->inputmap[chip->input], desc->inputmask);
- break;
+static int tvaudio_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVAUDIO, 0);
+}
+
+static int tvaudio_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tvaudio_core_ops = {
+ .g_chip_ident = tvaudio_g_chip_ident,
+ .queryctrl = tvaudio_queryctrl,
+ .g_ctrl = tvaudio_g_ctrl,
+ .s_ctrl = tvaudio_s_ctrl,
+};
+
+static const struct v4l2_subdev_tuner_ops tvaudio_tuner_ops = {
+ .s_radio = tvaudio_s_radio,
+ .s_frequency = tvaudio_s_frequency,
+ .s_std = tvaudio_s_std,
+ .s_tuner = tvaudio_s_tuner,
+ .s_tuner = tvaudio_g_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops tvaudio_audio_ops = {
+ .s_routing = tvaudio_s_routing,
+};
+
+static const struct v4l2_subdev_ops tvaudio_ops = {
+ .core = &tvaudio_core_ops,
+ .tuner = &tvaudio_tuner_ops,
+ .audio = &tvaudio_audio_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+
+/* i2c registration */
+
+static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct CHIPSTATE *chip;
+ struct CHIPDESC *desc;
+ struct v4l2_subdev *sd;
+
+ if (debug) {
+ printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
+ printk(KERN_INFO "tvaudio: known chips: ");
+ for (desc = chiplist; desc->name != NULL; desc++)
+ printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
+ printk("\n");
}
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *vt = arg;
- int mode = 0;
- if (chip->radio)
- break;
- switch (vt->audmode) {
- case V4L2_TUNER_MODE_MONO:
- case V4L2_TUNER_MODE_STEREO:
- case V4L2_TUNER_MODE_LANG1:
- case V4L2_TUNER_MODE_LANG2:
- mode = vt->audmode;
- break;
- case V4L2_TUNER_MODE_LANG1_LANG2:
- mode = V4L2_TUNER_MODE_STEREO;
- break;
- default:
- return -EINVAL;
- }
- chip->audmode = vt->audmode;
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+ sd = &chip->sd;
+ v4l2_i2c_subdev_init(sd, client, &tvaudio_ops);
- if (desc->setmode && mode) {
- chip->watch_stereo = 0;
- /* del_timer(&chip->wt); */
- chip->mode = mode;
- desc->setmode(chip, mode);
- }
+ /* find description for the chip */
+ v4l2_dbg(1, debug, sd, "chip found @ 0x%x\n", client->addr<<1);
+ for (desc = chiplist; desc->name != NULL; desc++) {
+ if (0 == *(desc->insmodopt))
+ continue;
+ if (client->addr < desc->addr_lo ||
+ client->addr > desc->addr_hi)
+ continue;
+ if (desc->checkit && !desc->checkit(chip))
+ continue;
break;
}
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *vt = arg;
- int mode = V4L2_TUNER_MODE_MONO;
+ if (desc->name == NULL) {
+ v4l2_dbg(1, debug, sd, "no matching chip description found\n");
+ kfree(chip);
+ return -EIO;
+ }
+ v4l2_info(sd, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
+ if (desc->flags) {
+ v4l2_dbg(1, debug, sd, "matches:%s%s%s.\n",
+ (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "",
+ (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
+ (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : "");
+ }
- if (chip->radio)
- break;
- vt->audmode = chip->audmode;
- vt->rxsubchans = 0;
- vt->capability = V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+ /* fill required data structures */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ strlcpy(client->name, desc->name, I2C_NAME_SIZE);
+#else
+ if (!id)
+ strlcpy(client->name, desc->name, I2C_NAME_SIZE);
+#endif
+ chip->desc = desc;
+ chip->shadow.count = desc->registers+1;
+ chip->prevmode = -1;
+ chip->audmode = V4L2_TUNER_MODE_LANG1;
- if (desc->getmode)
- mode = desc->getmode(chip);
+ /* initialization */
+ if (desc->initialize != NULL)
+ desc->initialize(chip);
+ else
+ chip_cmd(chip, "init", &desc->init);
- if (mode & V4L2_TUNER_MODE_MONO)
- vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
- if (mode & V4L2_TUNER_MODE_STEREO)
- vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
- /* Note: for SAP it should be mono/lang2 or stereo/lang2.
- When this module is converted fully to v4l2, then this
- should change for those chips that can detect SAP. */
- if (mode & V4L2_TUNER_MODE_LANG1)
- vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
- V4L2_TUNER_SUB_LANG2;
- break;
+ if (desc->flags & CHIP_HAS_VOLUME) {
+ if (!desc->volfunc) {
+ /* This shouldn't be happen. Warn user, but keep working
+ without volume controls
+ */
+ v4l2_info(sd, "volume callback undefined!\n");
+ desc->flags &= ~CHIP_HAS_VOLUME;
+ } else {
+ chip->left = desc->leftinit ? desc->leftinit : 65535;
+ chip->right = desc->rightinit ? desc->rightinit : 65535;
+ chip_write(chip, desc->leftreg,
+ desc->volfunc(chip->left));
+ chip_write(chip, desc->rightreg,
+ desc->volfunc(chip->right));
+ }
}
- case VIDIOC_S_STD:
- chip->radio = 0;
- break;
- case VIDIOC_S_FREQUENCY:
- chip->mode = 0; /* automatic */
-
- /* For chips that provide getmode and setmode, and doesn't
- automatically follows the stereo carrier, a kthread is
- created to set the audio standard. In this case, when then
- the video channel is changed, tvaudio starts on MONO mode.
- After waiting for 2 seconds, the kernel thread is called,
- to follow whatever audio standard is pointed by the
- audio carrier.
- */
- if (chip->thread) {
- desc->setmode(chip,V4L2_TUNER_MODE_MONO);
- if (chip->prevmode != V4L2_TUNER_MODE_MONO)
- chip->prevmode = -1; /* reset previous mode */
- mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
+ if (desc->flags & CHIP_HAS_BASSTREBLE) {
+ if (!desc->bassfunc || !desc->treblefunc) {
+ /* This shouldn't be happen. Warn user, but keep working
+ without bass/treble controls
+ */
+ v4l2_info(sd, "bass/treble callbacks undefined!\n");
+ desc->flags &= ~CHIP_HAS_BASSTREBLE;
+ } else {
+ chip->treble = desc->trebleinit ?
+ desc->trebleinit : 32768;
+ chip->bass = desc->bassinit ?
+ desc->bassinit : 32768;
+ chip_write(chip, desc->bassreg,
+ desc->bassfunc(chip->bass));
+ chip_write(chip, desc->treblereg,
+ desc->treblefunc(chip->treble));
}
- break;
+ }
+
+ chip->thread = NULL;
+ if (desc->flags & CHIP_NEED_CHECKMODE) {
+ if (!desc->getmode || !desc->setmode) {
+ /* This shouldn't be happen. Warn user, but keep working
+ without kthread
+ */
+ v4l2_info(sd, "set/get mode callbacks undefined!\n");
+ return 0;
+ }
+ /* start async thread */
+ init_timer(&chip->wt);
+ chip->wt.function = chip_thread_wake;
+ chip->wt.data = (unsigned long)chip;
+ chip->thread = kthread_run(chip_thread, chip, client->name);
+ if (IS_ERR(chip->thread)) {
+ v4l2_warn(sd, "failed to create kthread\n");
+ chip->thread = NULL;
+ }
+ }
+ return 0;
+}
+
+static int tvaudio_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct CHIPSTATE *chip = to_state(sd);
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_TVAUDIO, 0);
+ del_timer_sync(&chip->wt);
+ if (chip->thread) {
+ /* shutdown async thread */
+ kthread_stop(chip->thread);
+ chip->thread = NULL;
}
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(chip);
return 0;
}
-static int chip_legacy_probe(struct i2c_adapter *adap)
+static int tvaudio_legacy_probe(struct i2c_adapter *adap)
{
/* don't attach on saa7146 based cards,
because dedicated drivers are used */
@@ -1907,21 +1966,21 @@ static int chip_legacy_probe(struct i2c_adapter *adap)
/* This driver supports many devices and the idea is to let the driver
detect which device is present. So rather than listing all supported
devices here, we pretend to support a single, fake device type. */
-static const struct i2c_device_id chip_id[] = {
+static const struct i2c_device_id tvaudio_id[] = {
{ "tvaudio", 0 },
{ }
};
-MODULE_DEVICE_TABLE(i2c, chip_id);
+MODULE_DEVICE_TABLE(i2c, tvaudio_id);
#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tvaudio",
.driverid = I2C_DRIVERID_TVAUDIO,
- .command = chip_command,
- .probe = chip_probe,
- .remove = chip_remove,
- .legacy_probe = chip_legacy_probe,
+ .command = tvaudio_command,
+ .probe = tvaudio_probe,
+ .remove = tvaudio_remove,
+ .legacy_probe = tvaudio_legacy_probe,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
- .id_table = chip_id,
+ .id_table = tvaudio_id,
#endif
};
diff --git a/linux/drivers/media/video/tvp514x.c b/linux/drivers/media/video/tvp514x.c
new file mode 100644
index 000000000..ac9aa40d0
--- /dev/null
+++ b/linux/drivers/media/video/tvp514x.c
@@ -0,0 +1,1569 @@
+/*
+ * drivers/media/video/tvp514x.c
+ *
+ * TI TVP5146/47 decoder driver
+ *
+ * Copyright (C) 2008 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.com>
+ *
+ * Contributors:
+ * Sivaraj R <sivaraj@ti.com>
+ * Brijesh R Jadav <brijesh.j@ti.com>
+ * Hardik Shah <hardik.shah@ti.com>
+ * Manjunath Hadli <mrh@ti.com>
+ * Karicheri Muralidharan <m-karicheri2@ti.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-int-device.h>
+#include <media/tvp514x.h>
+
+#include "tvp514x_regs.h"
+
+/* Module Name */
+#define TVP514X_MODULE_NAME "tvp514x"
+
+/* Private macros for TVP */
+#define I2C_RETRY_COUNT (5)
+#define LOCK_RETRY_COUNT (5)
+#define LOCK_RETRY_DELAY (200)
+
+/* Debug functions */
+static int debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dump_reg(client, reg, val) \
+ do { \
+ val = tvp514x_read_reg(client, reg); \
+ v4l_info(client, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
+ } while (0)
+
+/**
+ * enum tvp514x_std - enum for supported standards
+ */
+enum tvp514x_std {
+ STD_NTSC_MJ = 0,
+ STD_PAL_BDGHIN,
+ STD_INVALID
+};
+
+/**
+ * enum tvp514x_state - enum for different decoder states
+ */
+enum tvp514x_state {
+ STATE_NOT_DETECTED,
+ STATE_DETECTED
+};
+
+/**
+ * struct tvp514x_std_info - Structure to store standard informations
+ * @width: Line width in pixels
+ * @height:Number of active lines
+ * @video_std: Value to write in REG_VIDEO_STD register
+ * @standard: v4l2 standard structure information
+ */
+struct tvp514x_std_info {
+ unsigned long width;
+ unsigned long height;
+ u8 video_std;
+ struct v4l2_standard standard;
+};
+
+/**
+ * struct tvp514x_decoded - TVP5146/47 decoder object
+ * @v4l2_int_device: Slave handle
+ * @pdata: Board specific
+ * @client: I2C client data
+ * @id: Entry from I2C table
+ * @ver: Chip version
+ * @state: TVP5146/47 decoder state - detected or not-detected
+ * @pix: Current pixel format
+ * @num_fmts: Number of formats
+ * @fmt_list: Format list
+ * @current_std: Current standard
+ * @num_stds: Number of standards
+ * @std_list: Standards list
+ * @route: input and output routing at chip level
+ */
+struct tvp514x_decoder {
+ struct v4l2_int_device *v4l2_int_device;
+ const struct tvp514x_platform_data *pdata;
+ struct i2c_client *client;
+
+ struct i2c_device_id *id;
+
+ int ver;
+ enum tvp514x_state state;
+
+ struct v4l2_pix_format pix;
+ int num_fmts;
+ const struct v4l2_fmtdesc *fmt_list;
+
+ enum tvp514x_std current_std;
+ int num_stds;
+ struct tvp514x_std_info *std_list;
+
+ struct v4l2_routing route;
+};
+
+/* TVP514x default register values */
+static struct tvp514x_reg tvp514x_reg_list[] = {
+ {TOK_WRITE, REG_INPUT_SEL, 0x05}, /* Composite selected */
+ {TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F},
+ {TOK_WRITE, REG_VIDEO_STD, 0x00}, /* Auto mode */
+ {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+ {TOK_SKIP, REG_AUTOSWITCH_MASK, 0x3F},
+ {TOK_WRITE, REG_COLOR_KILLER, 0x10},
+ {TOK_WRITE, REG_LUMA_CONTROL1, 0x00},
+ {TOK_WRITE, REG_LUMA_CONTROL2, 0x00},
+ {TOK_WRITE, REG_LUMA_CONTROL3, 0x02},
+ {TOK_WRITE, REG_BRIGHTNESS, 0x80},
+ {TOK_WRITE, REG_CONTRAST, 0x80},
+ {TOK_WRITE, REG_SATURATION, 0x80},
+ {TOK_WRITE, REG_HUE, 0x00},
+ {TOK_WRITE, REG_CHROMA_CONTROL1, 0x00},
+ {TOK_WRITE, REG_CHROMA_CONTROL2, 0x0E},
+ {TOK_SKIP, 0x0F, 0x00}, /* Reserved */
+ {TOK_WRITE, REG_COMP_PR_SATURATION, 0x80},
+ {TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80},
+ {TOK_WRITE, REG_COMP_PB_SATURATION, 0x80},
+ {TOK_SKIP, 0x13, 0x00}, /* Reserved */
+ {TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80},
+ {TOK_SKIP, 0x15, 0x00}, /* Reserved */
+ {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55}, /* NTSC timing */
+ {TOK_SKIP, REG_AVID_START_PIXEL_MSB, 0x00},
+ {TOK_SKIP, REG_AVID_STOP_PIXEL_LSB, 0x25},
+ {TOK_SKIP, REG_AVID_STOP_PIXEL_MSB, 0x03},
+ {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00}, /* NTSC timing */
+ {TOK_SKIP, REG_HSYNC_START_PIXEL_MSB, 0x00},
+ {TOK_SKIP, REG_HSYNC_STOP_PIXEL_LSB, 0x40},
+ {TOK_SKIP, REG_HSYNC_STOP_PIXEL_MSB, 0x00},
+ {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04}, /* NTSC timing */
+ {TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00},
+ {TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07},
+ {TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00},
+ {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01}, /* NTSC timing */
+ {TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00},
+ {TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15},
+ {TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00},
+ {TOK_SKIP, 0x26, 0x00}, /* Reserved */
+ {TOK_SKIP, 0x27, 0x00}, /* Reserved */
+ {TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC},
+ {TOK_SKIP, 0x29, 0x00}, /* Reserved */
+ {TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00},
+ {TOK_SKIP, 0x2B, 0x00}, /* Reserved */
+ {TOK_SKIP, REG_SCART_DELAY, 0x00},
+ {TOK_SKIP, REG_CTI_DELAY, 0x00},
+ {TOK_SKIP, REG_CTI_CONTROL, 0x00},
+ {TOK_SKIP, 0x2F, 0x00}, /* Reserved */
+ {TOK_SKIP, 0x30, 0x00}, /* Reserved */
+ {TOK_SKIP, 0x31, 0x00}, /* Reserved */
+ {TOK_WRITE, REG_SYNC_CONTROL, 0x00}, /* HS, VS active high */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00}, /* 10-bit BT.656 */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11}, /* Enable clk & data */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE}, /* Enable AVID & FLD */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF}, /* Enable VS & HS */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF},
+ {TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF},
+ {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01}, /* Clear status */
+ {TOK_TERM, 0, 0},
+};
+
+/* List of image formats supported by TVP5146/47 decoder
+ * Currently we are using 8 bit mode only, but can be
+ * extended to 10/20 bit mode.
+ */
+static const struct v4l2_fmtdesc tvp514x_fmt_list[] = {
+ {
+ .index = 0,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .flags = 0,
+ .description = "8-bit UYVY 4:2:2 Format",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+};
+
+/*
+ * Supported standards -
+ *
+ * Currently supports two standards only, need to add support for rest of the
+ * modes, like SECAM, etc...
+ */
+static struct tvp514x_std_info tvp514x_std_list[] = {
+ /* Standard: STD_NTSC_MJ */
+ [STD_NTSC_MJ] = {
+ .width = NTSC_NUM_ACTIVE_PIXELS,
+ .height = NTSC_NUM_ACTIVE_LINES,
+ .video_std = VIDEO_STD_NTSC_MJ_BIT,
+ .standard = {
+ .index = 0,
+ .id = V4L2_STD_NTSC,
+ .name = "NTSC",
+ .frameperiod = {1001, 30000},
+ .framelines = 525
+ },
+ /* Standard: STD_PAL_BDGHIN */
+ },
+ [STD_PAL_BDGHIN] = {
+ .width = PAL_NUM_ACTIVE_PIXELS,
+ .height = PAL_NUM_ACTIVE_LINES,
+ .video_std = VIDEO_STD_PAL_BDGHIN_BIT,
+ .standard = {
+ .index = 1,
+ .id = V4L2_STD_PAL,
+ .name = "PAL",
+ .frameperiod = {1, 25},
+ .framelines = 625
+ },
+ },
+ /* Standard: need to add for additional standard */
+};
+/*
+ * Control structure for Auto Gain
+ * This is temporary data, will get replaced once
+ * v4l2_ctrl_query_fill supports it.
+ */
+static const struct v4l2_queryctrl tvp514x_autogain_ctrl = {
+ .id = V4L2_CID_AUTOGAIN,
+ .name = "Gain, Automatic",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+};
+
+/*
+ * Read a value from a register in an TVP5146/47 decoder device.
+ * Returns value read if successful, or non-zero (-1) otherwise.
+ */
+static int tvp514x_read_reg(struct i2c_client *client, u8 reg)
+{
+ int err;
+ int retry = 0;
+read_again:
+
+ err = i2c_smbus_read_byte_data(client, reg);
+ if (err == -1) {
+ if (retry <= I2C_RETRY_COUNT) {
+ v4l_warn(client, "Read: retry ... %d\n", retry);
+ retry++;
+ msleep_interruptible(10);
+ goto read_again;
+ }
+ }
+
+ return err;
+}
+
+/*
+ * Write a value to a register in an TVP5146/47 decoder device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp514x_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+ int err;
+ int retry = 0;
+write_again:
+
+ err = i2c_smbus_write_byte_data(client, reg, val);
+ if (err) {
+ if (retry <= I2C_RETRY_COUNT) {
+ v4l_warn(client, "Write: retry ... %d\n", retry);
+ retry++;
+ msleep_interruptible(10);
+ goto write_again;
+ }
+ }
+
+ return err;
+}
+
+/*
+ * tvp514x_write_regs : Initializes a list of TVP5146/47 registers
+ * if token is TOK_TERM, then entire write operation terminates
+ * if token is TOK_DELAY, then a delay of 'val' msec is introduced
+ * if token is TOK_SKIP, then the register write is skipped
+ * if token is TOK_WRITE, then the register write is performed
+ *
+ * reglist - list of registers to be written
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp514x_write_regs(struct i2c_client *client,
+ const struct tvp514x_reg reglist[])
+{
+ int err;
+ const struct tvp514x_reg *next = reglist;
+
+ for (; next->token != TOK_TERM; next++) {
+ if (next->token == TOK_DELAY) {
+ msleep(next->val);
+ continue;
+ }
+
+ if (next->token == TOK_SKIP)
+ continue;
+
+ err = tvp514x_write_reg(client, next->reg, (u8) next->val);
+ if (err) {
+ v4l_err(client, "Write failed. Err[%d]\n", err);
+ return err;
+ }
+ }
+ return 0;
+}
+
+/*
+ * tvp514x_get_current_std:
+ * Returns the current standard detected by TVP5146/47
+ */
+static enum tvp514x_std tvp514x_get_current_std(struct tvp514x_decoder
+ *decoder)
+{
+ u8 std, std_status;
+
+ std = tvp514x_read_reg(decoder->client, REG_VIDEO_STD);
+ if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) {
+ /* use the standard status register */
+ std_status = tvp514x_read_reg(decoder->client,
+ REG_VIDEO_STD_STATUS);
+ } else
+ std_status = std; /* use the standard register itself */
+
+ switch (std_status & VIDEO_STD_MASK) {
+ case VIDEO_STD_NTSC_MJ_BIT:
+ return STD_NTSC_MJ;
+
+ case VIDEO_STD_PAL_BDGHIN_BIT:
+ return STD_PAL_BDGHIN;
+
+ default:
+ return STD_INVALID;
+ }
+
+ return STD_INVALID;
+}
+
+/*
+ * TVP5146/47 register dump function
+ */
+static void tvp514x_reg_dump(struct tvp514x_decoder *decoder)
+{
+ u8 value;
+
+ dump_reg(decoder->client, REG_INPUT_SEL, value);
+ dump_reg(decoder->client, REG_AFE_GAIN_CTRL, value);
+ dump_reg(decoder->client, REG_VIDEO_STD, value);
+ dump_reg(decoder->client, REG_OPERATION_MODE, value);
+ dump_reg(decoder->client, REG_COLOR_KILLER, value);
+ dump_reg(decoder->client, REG_LUMA_CONTROL1, value);
+ dump_reg(decoder->client, REG_LUMA_CONTROL2, value);
+ dump_reg(decoder->client, REG_LUMA_CONTROL3, value);
+ dump_reg(decoder->client, REG_BRIGHTNESS, value);
+ dump_reg(decoder->client, REG_CONTRAST, value);
+ dump_reg(decoder->client, REG_SATURATION, value);
+ dump_reg(decoder->client, REG_HUE, value);
+ dump_reg(decoder->client, REG_CHROMA_CONTROL1, value);
+ dump_reg(decoder->client, REG_CHROMA_CONTROL2, value);
+ dump_reg(decoder->client, REG_COMP_PR_SATURATION, value);
+ dump_reg(decoder->client, REG_COMP_Y_CONTRAST, value);
+ dump_reg(decoder->client, REG_COMP_PB_SATURATION, value);
+ dump_reg(decoder->client, REG_COMP_Y_BRIGHTNESS, value);
+ dump_reg(decoder->client, REG_AVID_START_PIXEL_LSB, value);
+ dump_reg(decoder->client, REG_AVID_START_PIXEL_MSB, value);
+ dump_reg(decoder->client, REG_AVID_STOP_PIXEL_LSB, value);
+ dump_reg(decoder->client, REG_AVID_STOP_PIXEL_MSB, value);
+ dump_reg(decoder->client, REG_HSYNC_START_PIXEL_LSB, value);
+ dump_reg(decoder->client, REG_HSYNC_START_PIXEL_MSB, value);
+ dump_reg(decoder->client, REG_HSYNC_STOP_PIXEL_LSB, value);
+ dump_reg(decoder->client, REG_HSYNC_STOP_PIXEL_MSB, value);
+ dump_reg(decoder->client, REG_VSYNC_START_LINE_LSB, value);
+ dump_reg(decoder->client, REG_VSYNC_START_LINE_MSB, value);
+ dump_reg(decoder->client, REG_VSYNC_STOP_LINE_LSB, value);
+ dump_reg(decoder->client, REG_VSYNC_STOP_LINE_MSB, value);
+ dump_reg(decoder->client, REG_VBLK_START_LINE_LSB, value);
+ dump_reg(decoder->client, REG_VBLK_START_LINE_MSB, value);
+ dump_reg(decoder->client, REG_VBLK_STOP_LINE_LSB, value);
+ dump_reg(decoder->client, REG_VBLK_STOP_LINE_MSB, value);
+ dump_reg(decoder->client, REG_SYNC_CONTROL, value);
+ dump_reg(decoder->client, REG_OUTPUT_FORMATTER1, value);
+ dump_reg(decoder->client, REG_OUTPUT_FORMATTER2, value);
+ dump_reg(decoder->client, REG_OUTPUT_FORMATTER3, value);
+ dump_reg(decoder->client, REG_OUTPUT_FORMATTER4, value);
+ dump_reg(decoder->client, REG_OUTPUT_FORMATTER5, value);
+ dump_reg(decoder->client, REG_OUTPUT_FORMATTER6, value);
+ dump_reg(decoder->client, REG_CLEAR_LOST_LOCK, value);
+}
+
+/*
+ * Configure the TVP5146/47 with the current register settings
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp514x_configure(struct tvp514x_decoder *decoder)
+{
+ int err;
+
+ /* common register initialization */
+ err =
+ tvp514x_write_regs(decoder->client, tvp514x_reg_list);
+ if (err)
+ return err;
+
+ if (debug)
+ tvp514x_reg_dump(decoder);
+
+ return 0;
+}
+
+/*
+ * Detect if an tvp514x is present, and if so which revision.
+ * A device is considered to be detected if the chip ID (LSB and MSB)
+ * registers match the expected values.
+ * Any value of the rom version register is accepted.
+ * Returns ENODEV error number if no device is detected, or zero
+ * if a device is detected.
+ */
+static int tvp514x_detect(struct tvp514x_decoder *decoder)
+{
+ u8 chip_id_msb, chip_id_lsb, rom_ver;
+
+ chip_id_msb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_MSB);
+ chip_id_lsb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_LSB);
+ rom_ver = tvp514x_read_reg(decoder->client, REG_ROM_VERSION);
+
+ v4l_dbg(1, debug, decoder->client,
+ "chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n",
+ chip_id_msb, chip_id_lsb, rom_ver);
+ if ((chip_id_msb != TVP514X_CHIP_ID_MSB)
+ || ((chip_id_lsb != TVP5146_CHIP_ID_LSB)
+ && (chip_id_lsb != TVP5147_CHIP_ID_LSB))) {
+ /* We didn't read the values we expected, so this must not be
+ * an TVP5146/47.
+ */
+ v4l_err(decoder->client,
+ "chip id mismatch msb:0x%x lsb:0x%x\n",
+ chip_id_msb, chip_id_lsb);
+ return -ENODEV;
+ }
+
+ decoder->ver = rom_ver;
+ decoder->state = STATE_DETECTED;
+
+ v4l_info(decoder->client,
+ "%s found at 0x%x (%s)\n", decoder->client->name,
+ decoder->client->addr << 1,
+ decoder->client->adapter->name);
+ return 0;
+}
+
+/*
+ * Following are decoder interface functions implemented by
+ * TVP5146/47 decoder driver.
+ */
+
+/**
+ * ioctl_querystd - V4L2 decoder interface handler for VIDIOC_QUERYSTD ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @std_id: standard V4L2 std_id ioctl enum
+ *
+ * Returns the current standard detected by TVP5146/47. If no active input is
+ * detected, returns -EINVAL
+ */
+static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ enum tvp514x_std current_std;
+ enum tvp514x_input input_sel;
+ u8 sync_lock_status, lock_mask;
+
+ if (std_id == NULL)
+ return -EINVAL;
+
+ /* get the current standard */
+ current_std = tvp514x_get_current_std(decoder);
+ if (current_std == STD_INVALID)
+ return -EINVAL;
+
+ input_sel = decoder->route.input;
+
+ switch (input_sel) {
+ case INPUT_CVBS_VI1A:
+ case INPUT_CVBS_VI1B:
+ case INPUT_CVBS_VI1C:
+ case INPUT_CVBS_VI2A:
+ case INPUT_CVBS_VI2B:
+ case INPUT_CVBS_VI2C:
+ case INPUT_CVBS_VI3A:
+ case INPUT_CVBS_VI3B:
+ case INPUT_CVBS_VI3C:
+ case INPUT_CVBS_VI4A:
+ lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
+ STATUS_HORZ_SYNC_LOCK_BIT |
+ STATUS_VIRT_SYNC_LOCK_BIT;
+ break;
+
+ case INPUT_SVIDEO_VI2A_VI1A:
+ case INPUT_SVIDEO_VI2B_VI1B:
+ case INPUT_SVIDEO_VI2C_VI1C:
+ case INPUT_SVIDEO_VI2A_VI3A:
+ case INPUT_SVIDEO_VI2B_VI3B:
+ case INPUT_SVIDEO_VI2C_VI3C:
+ case INPUT_SVIDEO_VI4A_VI1A:
+ case INPUT_SVIDEO_VI4A_VI1B:
+ case INPUT_SVIDEO_VI4A_VI1C:
+ case INPUT_SVIDEO_VI4A_VI3A:
+ case INPUT_SVIDEO_VI4A_VI3B:
+ case INPUT_SVIDEO_VI4A_VI3C:
+ lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
+ STATUS_VIRT_SYNC_LOCK_BIT;
+ break;
+ /*Need to add other interfaces*/
+ default:
+ return -EINVAL;
+ }
+ /* check whether signal is locked */
+ sync_lock_status = tvp514x_read_reg(decoder->client, REG_STATUS1);
+ if (lock_mask != (sync_lock_status & lock_mask))
+ return -EINVAL; /* No input detected */
+
+ decoder->current_std = current_std;
+ *std_id = decoder->std_list[current_std].standard.id;
+
+ v4l_dbg(1, debug, decoder->client, "Current STD: %s",
+ decoder->std_list[current_std].standard.name);
+ return 0;
+}
+
+/**
+ * ioctl_s_std - V4L2 decoder interface handler for VIDIOC_S_STD ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @std_id: standard V4L2 v4l2_std_id ioctl enum
+ *
+ * If std_id is supported, sets the requested standard. Otherwise, returns
+ * -EINVAL
+ */
+static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ int err, i;
+
+ if (std_id == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < decoder->num_stds; i++)
+ if (*std_id & decoder->std_list[i].standard.id)
+ break;
+
+ if ((i == decoder->num_stds) || (i == STD_INVALID))
+ return -EINVAL;
+
+ err = tvp514x_write_reg(decoder->client, REG_VIDEO_STD,
+ decoder->std_list[i].video_std);
+ if (err)
+ return err;
+
+ decoder->current_std = i;
+ tvp514x_reg_list[REG_VIDEO_STD].val = decoder->std_list[i].video_std;
+
+ v4l_dbg(1, debug, decoder->client, "Standard set to: %s",
+ decoder->std_list[i].standard.name);
+ return 0;
+}
+
+/**
+ * ioctl_s_routing - V4L2 decoder interface handler for VIDIOC_S_INPUT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @index: number of the input
+ *
+ * If index is valid, selects the requested input. Otherwise, returns -EINVAL if
+ * the input is not supported or there is no active signal present in the
+ * selected input.
+ */
+static int ioctl_s_routing(struct v4l2_int_device *s,
+ struct v4l2_routing *route)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ int err;
+ enum tvp514x_input input_sel;
+ enum tvp514x_output output_sel;
+ enum tvp514x_std current_std = STD_INVALID;
+ u8 sync_lock_status, lock_mask;
+ int try_count = LOCK_RETRY_COUNT;
+
+ if ((!route) || (route->input >= INPUT_INVALID) ||
+ (route->output >= OUTPUT_INVALID))
+ return -EINVAL; /* Index out of bound */
+
+ input_sel = route->input;
+ output_sel = route->output;
+
+ err = tvp514x_write_reg(decoder->client, REG_INPUT_SEL, input_sel);
+ if (err)
+ return err;
+
+ output_sel |= tvp514x_read_reg(decoder->client,
+ REG_OUTPUT_FORMATTER1) & 0x7;
+ err = tvp514x_write_reg(decoder->client, REG_OUTPUT_FORMATTER1,
+ output_sel);
+ if (err)
+ return err;
+
+ tvp514x_reg_list[REG_INPUT_SEL].val = input_sel;
+ tvp514x_reg_list[REG_OUTPUT_FORMATTER1].val = output_sel;
+
+ /* Clear status */
+ msleep(LOCK_RETRY_DELAY);
+ err =
+ tvp514x_write_reg(decoder->client, REG_CLEAR_LOST_LOCK, 0x01);
+ if (err)
+ return err;
+
+ switch (input_sel) {
+ case INPUT_CVBS_VI1A:
+ case INPUT_CVBS_VI1B:
+ case INPUT_CVBS_VI1C:
+ case INPUT_CVBS_VI2A:
+ case INPUT_CVBS_VI2B:
+ case INPUT_CVBS_VI2C:
+ case INPUT_CVBS_VI3A:
+ case INPUT_CVBS_VI3B:
+ case INPUT_CVBS_VI3C:
+ case INPUT_CVBS_VI4A:
+ lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
+ STATUS_HORZ_SYNC_LOCK_BIT |
+ STATUS_VIRT_SYNC_LOCK_BIT;
+ break;
+
+ case INPUT_SVIDEO_VI2A_VI1A:
+ case INPUT_SVIDEO_VI2B_VI1B:
+ case INPUT_SVIDEO_VI2C_VI1C:
+ case INPUT_SVIDEO_VI2A_VI3A:
+ case INPUT_SVIDEO_VI2B_VI3B:
+ case INPUT_SVIDEO_VI2C_VI3C:
+ case INPUT_SVIDEO_VI4A_VI1A:
+ case INPUT_SVIDEO_VI4A_VI1B:
+ case INPUT_SVIDEO_VI4A_VI1C:
+ case INPUT_SVIDEO_VI4A_VI3A:
+ case INPUT_SVIDEO_VI4A_VI3B:
+ case INPUT_SVIDEO_VI4A_VI3C:
+ lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
+ STATUS_VIRT_SYNC_LOCK_BIT;
+ break;
+ /*Need to add other interfaces*/
+ default:
+ return -EINVAL;
+ }
+
+ while (try_count-- > 0) {
+ /* Allow decoder to sync up with new input */
+ msleep(LOCK_RETRY_DELAY);
+
+ /* get the current standard for future reference */
+ current_std = tvp514x_get_current_std(decoder);
+ if (current_std == STD_INVALID)
+ continue;
+
+ sync_lock_status = tvp514x_read_reg(decoder->client,
+ REG_STATUS1);
+ if (lock_mask == (sync_lock_status & lock_mask))
+ break; /* Input detected */
+ }
+
+ if ((current_std == STD_INVALID) || (try_count < 0))
+ return -EINVAL;
+
+ decoder->current_std = current_std;
+ decoder->route.input = route->input;
+ decoder->route.output = route->output;
+
+ v4l_dbg(1, debug, decoder->client,
+ "Input set to: %d, std : %d",
+ input_sel, current_std);
+
+ return 0;
+}
+
+/**
+ * ioctl_queryctrl - V4L2 decoder interface handler for VIDIOC_QUERYCTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @qctrl: standard V4L2 v4l2_queryctrl structure
+ *
+ * If the requested control is supported, returns the control information.
+ * Otherwise, returns -EINVAL if the control is not supported.
+ */
+static int
+ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ int err = -EINVAL;
+
+ if (qctrl == NULL)
+ return err;
+
+ switch (qctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ /* Brightness supported is same as standard one (0-255),
+ * so make use of standard API provided.
+ */
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ break;
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ /* Saturation and Contrast supported is -
+ * Contrast: 0 - 255 (Default - 128)
+ * Saturation: 0 - 255 (Default - 128)
+ */
+ err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
+ break;
+ case V4L2_CID_HUE:
+ /* Hue Supported is -
+ * Hue - -180 - +180 (Default - 0, Step - +180)
+ */
+ err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ /* Autogain is either 0 or 1*/
+ memcpy(qctrl, &tvp514x_autogain_ctrl,
+ sizeof(struct v4l2_queryctrl));
+ err = 0;
+ break;
+ default:
+ v4l_err(decoder->client,
+ "invalid control id %d\n", qctrl->id);
+ return err;
+ }
+
+ v4l_dbg(1, debug, decoder->client,
+ "Query Control: %s : Min - %d, Max - %d, Def - %d",
+ qctrl->name,
+ qctrl->minimum,
+ qctrl->maximum,
+ qctrl->default_value);
+
+ return err;
+}
+
+/**
+ * ioctl_g_ctrl - V4L2 decoder interface handler for VIDIOC_G_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @ctrl: pointer to v4l2_control structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the decoder. Otherwise, returns -EINVAL if the control is not
+ * supported.
+ */
+static int
+ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+
+ if (ctrl == NULL)
+ return -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = tvp514x_reg_list[REG_BRIGHTNESS].val;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = tvp514x_reg_list[REG_CONTRAST].val;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = tvp514x_reg_list[REG_SATURATION].val;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = tvp514x_reg_list[REG_HUE].val;
+ if (ctrl->value == 0x7F)
+ ctrl->value = 180;
+ else if (ctrl->value == 0x80)
+ ctrl->value = -180;
+ else
+ ctrl->value = 0;
+
+ break;
+ case V4L2_CID_AUTOGAIN:
+ ctrl->value = tvp514x_reg_list[REG_AFE_GAIN_CTRL].val;
+ if ((ctrl->value & 0x3) == 3)
+ ctrl->value = 1;
+ else
+ ctrl->value = 0;
+
+ break;
+ default:
+ v4l_err(decoder->client,
+ "invalid control id %d\n", ctrl->id);
+ return -EINVAL;
+ }
+
+ v4l_dbg(1, debug, decoder->client,
+ "Get Control: ID - %d - %d",
+ ctrl->id, ctrl->value);
+ return 0;
+}
+
+/**
+ * ioctl_s_ctrl - V4L2 decoder interface handler for VIDIOC_S_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @ctrl: pointer to v4l2_control structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW. Otherwise, returns -EINVAL if the control is not supported.
+ */
+static int
+ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ int err = -EINVAL, value;
+
+ if (ctrl == NULL)
+ return err;
+
+ value = (__s32) ctrl->value;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ v4l_err(decoder->client,
+ "invalid brightness setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+ err = tvp514x_write_reg(decoder->client, REG_BRIGHTNESS,
+ value);
+ if (err)
+ return err;
+ tvp514x_reg_list[REG_BRIGHTNESS].val = value;
+ break;
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ v4l_err(decoder->client,
+ "invalid contrast setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+ err = tvp514x_write_reg(decoder->client, REG_CONTRAST,
+ value);
+ if (err)
+ return err;
+ tvp514x_reg_list[REG_CONTRAST].val = value;
+ break;
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ v4l_err(decoder->client,
+ "invalid saturation setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+ err = tvp514x_write_reg(decoder->client, REG_SATURATION,
+ value);
+ if (err)
+ return err;
+ tvp514x_reg_list[REG_SATURATION].val = value;
+ break;
+ case V4L2_CID_HUE:
+ if (value == 180)
+ value = 0x7F;
+ else if (value == -180)
+ value = 0x80;
+ else if (value == 0)
+ value = 0;
+ else {
+ v4l_err(decoder->client,
+ "invalid hue setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+ err = tvp514x_write_reg(decoder->client, REG_HUE,
+ value);
+ if (err)
+ return err;
+ tvp514x_reg_list[REG_HUE].val = value;
+ break;
+ case V4L2_CID_AUTOGAIN:
+ if (value == 1)
+ value = 0x0F;
+ else if (value == 0)
+ value = 0x0C;
+ else {
+ v4l_err(decoder->client,
+ "invalid auto gain setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+ err = tvp514x_write_reg(decoder->client, REG_AFE_GAIN_CTRL,
+ value);
+ if (err)
+ return err;
+ tvp514x_reg_list[REG_AFE_GAIN_CTRL].val = value;
+ break;
+ default:
+ v4l_err(decoder->client,
+ "invalid control id %d\n", ctrl->id);
+ return err;
+ }
+
+ v4l_dbg(1, debug, decoder->client,
+ "Set Control: ID - %d - %d",
+ ctrl->id, ctrl->value);
+
+ return err;
+}
+
+/**
+ * ioctl_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure
+ *
+ * Implement the VIDIOC_ENUM_FMT ioctl to enumerate supported formats
+ */
+static int
+ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ int index;
+
+ if (fmt == NULL)
+ return -EINVAL;
+
+ index = fmt->index;
+ if ((index >= decoder->num_fmts) || (index < 0))
+ return -EINVAL; /* Index out of bound */
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL; /* only capture is supported */
+
+ memcpy(fmt, &decoder->fmt_list[index],
+ sizeof(struct v4l2_fmtdesc));
+
+ v4l_dbg(1, debug, decoder->client,
+ "Current FMT: index - %d (%s)",
+ decoder->fmt_list[index].index,
+ decoder->fmt_list[index].description);
+ return 0;
+}
+
+/**
+ * ioctl_try_fmt_cap - Implement the CAPTURE buffer VIDIOC_TRY_FMT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
+ *
+ * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This
+ * ioctl is used to negotiate the image capture size and pixel format
+ * without actually making it take effect.
+ */
+static int
+ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ int ifmt;
+ struct v4l2_pix_format *pix;
+ enum tvp514x_std current_std;
+
+ if (f == NULL)
+ return -EINVAL;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ pix = &f->fmt.pix;
+
+ /* Calculate height and width based on current standard */
+ current_std = tvp514x_get_current_std(decoder);
+ if (current_std == STD_INVALID)
+ return -EINVAL;
+
+ decoder->current_std = current_std;
+ pix->width = decoder->std_list[current_std].width;
+ pix->height = decoder->std_list[current_std].height;
+
+ for (ifmt = 0; ifmt < decoder->num_fmts; ifmt++) {
+ if (pix->pixelformat ==
+ decoder->fmt_list[ifmt].pixelformat)
+ break;
+ }
+ if (ifmt == decoder->num_fmts)
+ ifmt = 0; /* None of the format matched, select default */
+ pix->pixelformat = decoder->fmt_list[ifmt].pixelformat;
+
+ pix->field = V4L2_FIELD_INTERLACED;
+ pix->bytesperline = pix->width * 2;
+ pix->sizeimage = pix->bytesperline * pix->height;
+ pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pix->priv = 0;
+
+ v4l_dbg(1, debug, decoder->client,
+ "Try FMT: pixelformat - %s, bytesperline - %d"
+ "Width - %d, Height - %d",
+ decoder->fmt_list[ifmt].description, pix->bytesperline,
+ pix->width, pix->height);
+ return 0;
+}
+
+/**
+ * ioctl_s_fmt_cap - V4L2 decoder interface handler for VIDIOC_S_FMT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
+ *
+ * If the requested format is supported, configures the HW to use that
+ * format, returns error code if format not supported or HW can't be
+ * correctly configured.
+ */
+static int
+ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ struct v4l2_pix_format *pix;
+ int rval;
+
+ if (f == NULL)
+ return -EINVAL;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL; /* only capture is supported */
+
+ pix = &f->fmt.pix;
+ rval = ioctl_try_fmt_cap(s, f);
+ if (rval)
+ return rval;
+
+ decoder->pix = *pix;
+
+ return rval;
+}
+
+/**
+ * ioctl_g_fmt_cap - V4L2 decoder interface handler for ioctl_g_fmt_cap
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 v4l2_format structure
+ *
+ * Returns the decoder's current pixel format in the v4l2_format
+ * parameter.
+ */
+static int
+ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+
+ if (f == NULL)
+ return -EINVAL;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL; /* only capture is supported */
+
+ f->fmt.pix = decoder->pix;
+
+ v4l_dbg(1, debug, decoder->client,
+ "Current FMT: bytesperline - %d"
+ "Width - %d, Height - %d",
+ decoder->pix.bytesperline,
+ decoder->pix.width, decoder->pix.height);
+ return 0;
+}
+
+/**
+ * ioctl_g_parm - V4L2 decoder interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the decoder's video CAPTURE parameters.
+ */
+static int
+ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ struct v4l2_captureparm *cparm;
+ enum tvp514x_std current_std;
+
+ if (a == NULL)
+ return -EINVAL;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL; /* only capture is supported */
+
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ /* get the current standard */
+ current_std = tvp514x_get_current_std(decoder);
+ if (current_std == STD_INVALID)
+ return -EINVAL;
+
+ decoder->current_std = current_std;
+
+ cparm = &a->parm.capture;
+ cparm->capability = V4L2_CAP_TIMEPERFRAME;
+ cparm->timeperframe =
+ decoder->std_list[current_std].standard.frameperiod;
+
+ return 0;
+}
+
+/**
+ * ioctl_s_parm - V4L2 decoder interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the decoder to use the input parameters, if possible. If
+ * not possible, returns the appropriate error code.
+ */
+static int
+ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ struct v4l2_fract *timeperframe;
+ enum tvp514x_std current_std;
+
+ if (a == NULL)
+ return -EINVAL;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL; /* only capture is supported */
+
+ timeperframe = &a->parm.capture.timeperframe;
+
+ /* get the current standard */
+ current_std = tvp514x_get_current_std(decoder);
+ if (current_std == STD_INVALID)
+ return -EINVAL;
+
+ decoder->current_std = current_std;
+
+ *timeperframe =
+ decoder->std_list[current_std].standard.frameperiod;
+
+ return 0;
+}
+
+/**
+ * ioctl_g_ifparm - V4L2 decoder interface handler for vidioc_int_g_ifparm_num
+ * @s: pointer to standard V4L2 device structure
+ * @p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure
+ *
+ * Gets slave interface parameters.
+ * Calculates the required xclk value to support the requested
+ * clock parameters in p. This value is returned in the p
+ * parameter.
+ */
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ int rval;
+
+ if (p == NULL)
+ return -EINVAL;
+
+ if (NULL == decoder->pdata->ifparm)
+ return -EINVAL;
+
+ rval = decoder->pdata->ifparm(p);
+ if (rval) {
+ v4l_err(decoder->client, "g_ifparm.Err[%d]\n", rval);
+ return rval;
+ }
+
+ p->u.bt656.clock_curr = TVP514X_XCLK_BT656;
+
+ return 0;
+}
+
+/**
+ * ioctl_g_priv - V4L2 decoder interface handler for vidioc_int_g_priv_num
+ * @s: pointer to standard V4L2 device structure
+ * @p: void pointer to hold decoder's private data address
+ *
+ * Returns device's (decoder's) private data area address in p parameter
+ */
+static int ioctl_g_priv(struct v4l2_int_device *s, void *p)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+
+ if (NULL == decoder->pdata->priv_data_set)
+ return -EINVAL;
+
+ return decoder->pdata->priv_data_set(p);
+}
+
+/**
+ * ioctl_s_power - V4L2 decoder interface handler for vidioc_int_s_power_num
+ * @s: pointer to standard V4L2 device structure
+ * @on: power state to which device is to be set
+ *
+ * Sets devices power state to requrested state, if possible.
+ */
+static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ int err = 0;
+
+ switch (on) {
+ case V4L2_POWER_OFF:
+ /* Power Down Sequence */
+ err =
+ tvp514x_write_reg(decoder->client, REG_OPERATION_MODE,
+ 0x01);
+ /* Disable mux for TVP5146/47 decoder data path */
+ if (decoder->pdata->power_set)
+ err |= decoder->pdata->power_set(on);
+ decoder->state = STATE_NOT_DETECTED;
+ break;
+
+ case V4L2_POWER_STANDBY:
+ if (decoder->pdata->power_set)
+ err = decoder->pdata->power_set(on);
+ break;
+
+ case V4L2_POWER_ON:
+ /* Enable mux for TVP5146/47 decoder data path */
+ if ((decoder->pdata->power_set) &&
+ (decoder->state == STATE_NOT_DETECTED)) {
+ int i;
+ struct tvp514x_init_seq *int_seq =
+ (struct tvp514x_init_seq *)
+ decoder->id->driver_data;
+
+ err = decoder->pdata->power_set(on);
+
+ /* Power Up Sequence */
+ for (i = 0; i < int_seq->no_regs; i++) {
+ err |= tvp514x_write_reg(decoder->client,
+ int_seq->init_reg_seq[i].reg,
+ int_seq->init_reg_seq[i].val);
+ }
+ /* Detect the sensor is not already detected */
+ err |= tvp514x_detect(decoder);
+ if (err) {
+ v4l_err(decoder->client,
+ "Unable to detect decoder\n");
+ return err;
+ }
+ }
+ err |= tvp514x_configure(decoder);
+ break;
+
+ default:
+ err = -ENODEV;
+ break;
+ }
+
+ return err;
+}
+
+/**
+ * ioctl_init - V4L2 decoder interface handler for VIDIOC_INT_INIT
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialize the decoder device (calls tvp514x_configure())
+ */
+static int ioctl_init(struct v4l2_int_device *s)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+
+ /* Set default standard to auto */
+ tvp514x_reg_list[REG_VIDEO_STD].val =
+ VIDEO_STD_AUTO_SWITCH_BIT;
+
+ return tvp514x_configure(decoder);
+}
+
+/**
+ * ioctl_dev_exit - V4L2 decoder interface handler for vidioc_int_dev_exit_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Delinitialise the dev. at slave detach. The complement of ioctl_dev_init.
+ */
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+ return 0;
+}
+
+/**
+ * ioctl_dev_init - V4L2 decoder interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master. Returns 0 if
+ * TVP5146/47 device could be found, otherwise returns appropriate error.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ int err;
+
+ err = tvp514x_detect(decoder);
+ if (err < 0) {
+ v4l_err(decoder->client,
+ "Unable to detect decoder\n");
+ return err;
+ }
+
+ v4l_info(decoder->client,
+ "chip version 0x%.2x detected\n", decoder->ver);
+
+ return 0;
+}
+
+static struct v4l2_int_ioctl_desc tvp514x_ioctl_desc[] = {
+ {vidioc_int_dev_init_num, (v4l2_int_ioctl_func*) ioctl_dev_init},
+ {vidioc_int_dev_exit_num, (v4l2_int_ioctl_func*) ioctl_dev_exit},
+ {vidioc_int_s_power_num, (v4l2_int_ioctl_func*) ioctl_s_power},
+ {vidioc_int_g_priv_num, (v4l2_int_ioctl_func*) ioctl_g_priv},
+ {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*) ioctl_g_ifparm},
+ {vidioc_int_init_num, (v4l2_int_ioctl_func*) ioctl_init},
+ {vidioc_int_enum_fmt_cap_num,
+ (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap},
+ {vidioc_int_try_fmt_cap_num,
+ (v4l2_int_ioctl_func *) ioctl_try_fmt_cap},
+ {vidioc_int_g_fmt_cap_num,
+ (v4l2_int_ioctl_func *) ioctl_g_fmt_cap},
+ {vidioc_int_s_fmt_cap_num,
+ (v4l2_int_ioctl_func *) ioctl_s_fmt_cap},
+ {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm},
+ {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm},
+ {vidioc_int_queryctrl_num,
+ (v4l2_int_ioctl_func *) ioctl_queryctrl},
+ {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *) ioctl_g_ctrl},
+ {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl},
+ {vidioc_int_querystd_num, (v4l2_int_ioctl_func *) ioctl_querystd},
+ {vidioc_int_s_std_num, (v4l2_int_ioctl_func *) ioctl_s_std},
+ {vidioc_int_s_video_routing_num,
+ (v4l2_int_ioctl_func *) ioctl_s_routing},
+};
+
+static struct v4l2_int_slave tvp514x_slave = {
+ .ioctls = tvp514x_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc),
+};
+
+static struct tvp514x_decoder tvp514x_dev = {
+ .state = STATE_NOT_DETECTED,
+
+ .fmt_list = tvp514x_fmt_list,
+ .num_fmts = ARRAY_SIZE(tvp514x_fmt_list),
+
+ .pix = { /* Default to NTSC 8-bit YUV 422 */
+ .width = NTSC_NUM_ACTIVE_PIXELS,
+ .height = NTSC_NUM_ACTIVE_LINES,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .field = V4L2_FIELD_INTERLACED,
+ .bytesperline = NTSC_NUM_ACTIVE_PIXELS * 2,
+ .sizeimage =
+ NTSC_NUM_ACTIVE_PIXELS * 2 * NTSC_NUM_ACTIVE_LINES,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ },
+
+ .current_std = STD_NTSC_MJ,
+ .std_list = tvp514x_std_list,
+ .num_stds = ARRAY_SIZE(tvp514x_std_list),
+
+};
+
+static struct v4l2_int_device tvp514x_int_device = {
+ .module = THIS_MODULE,
+ .name = TVP514X_MODULE_NAME,
+ .priv = &tvp514x_dev,
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &tvp514x_slave,
+ },
+};
+
+/**
+ * tvp514x_probe - decoder driver i2c probe handler
+ * @client: i2c driver client device structure
+ *
+ * Register decoder as an i2c client device and V4L2
+ * device.
+ */
+static int
+tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct tvp514x_decoder *decoder = &tvp514x_dev;
+ int err;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ decoder->pdata = client->dev.platform_data;
+ if (!decoder->pdata) {
+ v4l_err(client, "No platform data\n!!");
+ return -ENODEV;
+ }
+ /*
+ * Fetch platform specific data, and configure the
+ * tvp514x_reg_list[] accordingly. Since this is one
+ * time configuration, no need to preserve.
+ */
+ tvp514x_reg_list[REG_OUTPUT_FORMATTER2].val |=
+ (decoder->pdata->clk_polarity << 1);
+ tvp514x_reg_list[REG_SYNC_CONTROL].val |=
+ ((decoder->pdata->hs_polarity << 2) |
+ (decoder->pdata->vs_polarity << 3));
+ /*
+ * Save the id data, required for power up sequence
+ */
+ decoder->id = (struct i2c_device_id *)id;
+ /* Attach to Master */
+ strcpy(tvp514x_int_device.u.slave->attach_to, decoder->pdata->master);
+ decoder->v4l2_int_device = &tvp514x_int_device;
+ decoder->client = client;
+ i2c_set_clientdata(client, decoder);
+
+ /* Register with V4L2 layer as slave device */
+ err = v4l2_int_device_register(decoder->v4l2_int_device);
+ if (err) {
+ i2c_set_clientdata(client, NULL);
+ v4l_err(client,
+ "Unable to register to v4l2. Err[%d]\n", err);
+
+ } else
+ v4l_info(client, "Registered to v4l2 master %s!!\n",
+ decoder->pdata->master);
+
+ return 0;
+}
+
+/**
+ * tvp514x_remove - decoder driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister decoder as an i2c client device and V4L2
+ * device. Complement of tvp514x_probe().
+ */
+static int __exit tvp514x_remove(struct i2c_client *client)
+{
+ struct tvp514x_decoder *decoder = i2c_get_clientdata(client);
+
+ if (!client->adapter)
+ return -ENODEV; /* our client isn't attached */
+
+ v4l2_int_device_unregister(decoder->v4l2_int_device);
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+/*
+ * TVP5146 Init/Power on Sequence
+ */
+static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
+ {TOK_WRITE, REG_OPERATION_MODE, 0x01},
+ {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+};
+static const struct tvp514x_init_seq tvp5146_init = {
+ .no_regs = ARRAY_SIZE(tvp5146_init_reg_seq),
+ .init_reg_seq = tvp5146_init_reg_seq,
+};
+/*
+ * TVP5147 Init/Power on Sequence
+ */
+static const struct tvp514x_reg tvp5147_init_reg_seq[] = {
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x16},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xA0},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x16},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
+ {TOK_WRITE, REG_OPERATION_MODE, 0x01},
+ {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+};
+static const struct tvp514x_init_seq tvp5147_init = {
+ .no_regs = ARRAY_SIZE(tvp5147_init_reg_seq),
+ .init_reg_seq = tvp5147_init_reg_seq,
+};
+/*
+ * TVP5146M2/TVP5147M1 Init/Power on Sequence
+ */
+static const struct tvp514x_reg tvp514xm_init_reg_seq[] = {
+ {TOK_WRITE, REG_OPERATION_MODE, 0x01},
+ {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+};
+static const struct tvp514x_init_seq tvp514xm_init = {
+ .no_regs = ARRAY_SIZE(tvp514xm_init_reg_seq),
+ .init_reg_seq = tvp514xm_init_reg_seq,
+};
+/*
+ * I2C Device Table -
+ *
+ * name - Name of the actual device/chip.
+ * driver_data - Driver data
+ */
+static const struct i2c_device_id tvp514x_id[] = {
+ {"tvp5146", (unsigned long)&tvp5146_init},
+ {"tvp5146m2", (unsigned long)&tvp514xm_init},
+ {"tvp5147", (unsigned long)&tvp5147_init},
+ {"tvp5147m1", (unsigned long)&tvp514xm_init},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, tvp514x_id);
+
+static struct i2c_driver tvp514x_i2c_driver = {
+ .driver = {
+ .name = TVP514X_MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = tvp514x_probe,
+ .remove = __exit_p(tvp514x_remove),
+ .id_table = tvp514x_id,
+};
+
+/**
+ * tvp514x_init
+ *
+ * Module init function
+ */
+static int __init tvp514x_init(void)
+{
+ return i2c_add_driver(&tvp514x_i2c_driver);
+}
+
+/**
+ * tvp514x_cleanup
+ *
+ * Module exit function
+ */
+static void __exit tvp514x_cleanup(void)
+{
+ i2c_del_driver(&tvp514x_i2c_driver);
+}
+
+module_init(tvp514x_init);
+module_exit(tvp514x_cleanup);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("TVP514X linux decoder driver");
+MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/tvp514x_regs.h b/linux/drivers/media/video/tvp514x_regs.h
new file mode 100644
index 000000000..351620aee
--- /dev/null
+++ b/linux/drivers/media/video/tvp514x_regs.h
@@ -0,0 +1,297 @@
+/*
+ * drivers/media/video/tvp514x_regs.h
+ *
+ * Copyright (C) 2008 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.com>
+ *
+ * Contributors:
+ * Sivaraj R <sivaraj@ti.com>
+ * Brijesh R Jadav <brijesh.j@ti.com>
+ * Hardik Shah <hardik.shah@ti.com>
+ * Manjunath Hadli <mrh@ti.com>
+ * Karicheri Muralidharan <m-karicheri2@ti.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _TVP514X_REGS_H
+#define _TVP514X_REGS_H
+
+/*
+ * TVP5146/47 registers
+ */
+#define REG_INPUT_SEL (0x00)
+#define REG_AFE_GAIN_CTRL (0x01)
+#define REG_VIDEO_STD (0x02)
+#define REG_OPERATION_MODE (0x03)
+#define REG_AUTOSWITCH_MASK (0x04)
+
+#define REG_COLOR_KILLER (0x05)
+#define REG_LUMA_CONTROL1 (0x06)
+#define REG_LUMA_CONTROL2 (0x07)
+#define REG_LUMA_CONTROL3 (0x08)
+
+#define REG_BRIGHTNESS (0x09)
+#define REG_CONTRAST (0x0A)
+#define REG_SATURATION (0x0B)
+#define REG_HUE (0x0C)
+
+#define REG_CHROMA_CONTROL1 (0x0D)
+#define REG_CHROMA_CONTROL2 (0x0E)
+
+/* 0x0F Reserved */
+
+#define REG_COMP_PR_SATURATION (0x10)
+#define REG_COMP_Y_CONTRAST (0x11)
+#define REG_COMP_PB_SATURATION (0x12)
+
+/* 0x13 Reserved */
+
+#define REG_COMP_Y_BRIGHTNESS (0x14)
+
+/* 0x15 Reserved */
+
+#define REG_AVID_START_PIXEL_LSB (0x16)
+#define REG_AVID_START_PIXEL_MSB (0x17)
+#define REG_AVID_STOP_PIXEL_LSB (0x18)
+#define REG_AVID_STOP_PIXEL_MSB (0x19)
+
+#define REG_HSYNC_START_PIXEL_LSB (0x1A)
+#define REG_HSYNC_START_PIXEL_MSB (0x1B)
+#define REG_HSYNC_STOP_PIXEL_LSB (0x1C)
+#define REG_HSYNC_STOP_PIXEL_MSB (0x1D)
+
+#define REG_VSYNC_START_LINE_LSB (0x1E)
+#define REG_VSYNC_START_LINE_MSB (0x1F)
+#define REG_VSYNC_STOP_LINE_LSB (0x20)
+#define REG_VSYNC_STOP_LINE_MSB (0x21)
+
+#define REG_VBLK_START_LINE_LSB (0x22)
+#define REG_VBLK_START_LINE_MSB (0x23)
+#define REG_VBLK_STOP_LINE_LSB (0x24)
+#define REG_VBLK_STOP_LINE_MSB (0x25)
+
+/* 0x26 - 0x27 Reserved */
+
+#define REG_FAST_SWTICH_CONTROL (0x28)
+
+/* 0x29 Reserved */
+
+#define REG_FAST_SWTICH_SCART_DELAY (0x2A)
+
+/* 0x2B Reserved */
+
+#define REG_SCART_DELAY (0x2C)
+#define REG_CTI_DELAY (0x2D)
+#define REG_CTI_CONTROL (0x2E)
+
+/* 0x2F - 0x31 Reserved */
+
+#define REG_SYNC_CONTROL (0x32)
+#define REG_OUTPUT_FORMATTER1 (0x33)
+#define REG_OUTPUT_FORMATTER2 (0x34)
+#define REG_OUTPUT_FORMATTER3 (0x35)
+#define REG_OUTPUT_FORMATTER4 (0x36)
+#define REG_OUTPUT_FORMATTER5 (0x37)
+#define REG_OUTPUT_FORMATTER6 (0x38)
+#define REG_CLEAR_LOST_LOCK (0x39)
+
+#define REG_STATUS1 (0x3A)
+#define REG_STATUS2 (0x3B)
+
+#define REG_AGC_GAIN_STATUS_LSB (0x3C)
+#define REG_AGC_GAIN_STATUS_MSB (0x3D)
+
+/* 0x3E Reserved */
+
+#define REG_VIDEO_STD_STATUS (0x3F)
+#define REG_GPIO_INPUT1 (0x40)
+#define REG_GPIO_INPUT2 (0x41)
+
+/* 0x42 - 0x45 Reserved */
+
+#define REG_AFE_COARSE_GAIN_CH1 (0x46)
+#define REG_AFE_COARSE_GAIN_CH2 (0x47)
+#define REG_AFE_COARSE_GAIN_CH3 (0x48)
+#define REG_AFE_COARSE_GAIN_CH4 (0x49)
+
+#define REG_AFE_FINE_GAIN_PB_B_LSB (0x4A)
+#define REG_AFE_FINE_GAIN_PB_B_MSB (0x4B)
+#define REG_AFE_FINE_GAIN_Y_G_CHROMA_LSB (0x4C)
+#define REG_AFE_FINE_GAIN_Y_G_CHROMA_MSB (0x4D)
+#define REG_AFE_FINE_GAIN_PR_R_LSB (0x4E)
+#define REG_AFE_FINE_GAIN_PR_R_MSB (0x4F)
+#define REG_AFE_FINE_GAIN_CVBS_LUMA_LSB (0x50)
+#define REG_AFE_FINE_GAIN_CVBS_LUMA_MSB (0x51)
+
+/* 0x52 - 0x68 Reserved */
+
+#define REG_FBIT_VBIT_CONTROL1 (0x69)
+
+/* 0x6A - 0x6B Reserved */
+
+#define REG_BACKEND_AGC_CONTROL (0x6C)
+
+/* 0x6D - 0x6E Reserved */
+
+#define REG_AGC_DECREMENT_SPEED_CONTROL (0x6F)
+#define REG_ROM_VERSION (0x70)
+
+/* 0x71 - 0x73 Reserved */
+
+#define REG_AGC_WHITE_PEAK_PROCESSING (0x74)
+#define REG_FBIT_VBIT_CONTROL2 (0x75)
+#define REG_VCR_TRICK_MODE_CONTROL (0x76)
+#define REG_HORIZONTAL_SHAKE_INCREMENT (0x77)
+#define REG_AGC_INCREMENT_SPEED (0x78)
+#define REG_AGC_INCREMENT_DELAY (0x79)
+
+/* 0x7A - 0x7F Reserved */
+
+#define REG_CHIP_ID_MSB (0x80)
+#define REG_CHIP_ID_LSB (0x81)
+
+/* 0x82 Reserved */
+
+#define REG_CPLL_SPEED_CONTROL (0x83)
+
+/* 0x84 - 0x96 Reserved */
+
+#define REG_STATUS_REQUEST (0x97)
+
+/* 0x98 - 0x99 Reserved */
+
+#define REG_VERTICAL_LINE_COUNT_LSB (0x9A)
+#define REG_VERTICAL_LINE_COUNT_MSB (0x9B)
+
+/* 0x9C - 0x9D Reserved */
+
+#define REG_AGC_DECREMENT_DELAY (0x9E)
+
+/* 0x9F - 0xB0 Reserved */
+
+#define REG_VDP_TTX_FILTER_1_MASK1 (0xB1)
+#define REG_VDP_TTX_FILTER_1_MASK2 (0xB2)
+#define REG_VDP_TTX_FILTER_1_MASK3 (0xB3)
+#define REG_VDP_TTX_FILTER_1_MASK4 (0xB4)
+#define REG_VDP_TTX_FILTER_1_MASK5 (0xB5)
+#define REG_VDP_TTX_FILTER_2_MASK1 (0xB6)
+#define REG_VDP_TTX_FILTER_2_MASK2 (0xB7)
+#define REG_VDP_TTX_FILTER_2_MASK3 (0xB8)
+#define REG_VDP_TTX_FILTER_2_MASK4 (0xB9)
+#define REG_VDP_TTX_FILTER_2_MASK5 (0xBA)
+#define REG_VDP_TTX_FILTER_CONTROL (0xBB)
+#define REG_VDP_FIFO_WORD_COUNT (0xBC)
+#define REG_VDP_FIFO_INTERRUPT_THRLD (0xBD)
+
+/* 0xBE Reserved */
+
+#define REG_VDP_FIFO_RESET (0xBF)
+#define REG_VDP_FIFO_OUTPUT_CONTROL (0xC0)
+#define REG_VDP_LINE_NUMBER_INTERRUPT (0xC1)
+#define REG_VDP_PIXEL_ALIGNMENT_LSB (0xC2)
+#define REG_VDP_PIXEL_ALIGNMENT_MSB (0xC3)
+
+/* 0xC4 - 0xD5 Reserved */
+
+#define REG_VDP_LINE_START (0xD6)
+#define REG_VDP_LINE_STOP (0xD7)
+#define REG_VDP_GLOBAL_LINE_MODE (0xD8)
+#define REG_VDP_FULL_FIELD_ENABLE (0xD9)
+#define REG_VDP_FULL_FIELD_MODE (0xDA)
+
+/* 0xDB - 0xDF Reserved */
+
+#define REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR (0xE0)
+#define REG_VBUS_DATA_ACCESS_VBUS_ADDR_INCR (0xE1)
+#define REG_FIFO_READ_DATA (0xE2)
+
+/* 0xE3 - 0xE7 Reserved */
+
+#define REG_VBUS_ADDRESS_ACCESS1 (0xE8)
+#define REG_VBUS_ADDRESS_ACCESS2 (0xE9)
+#define REG_VBUS_ADDRESS_ACCESS3 (0xEA)
+
+/* 0xEB - 0xEF Reserved */
+
+#define REG_INTERRUPT_RAW_STATUS0 (0xF0)
+#define REG_INTERRUPT_RAW_STATUS1 (0xF1)
+#define REG_INTERRUPT_STATUS0 (0xF2)
+#define REG_INTERRUPT_STATUS1 (0xF3)
+#define REG_INTERRUPT_MASK0 (0xF4)
+#define REG_INTERRUPT_MASK1 (0xF5)
+#define REG_INTERRUPT_CLEAR0 (0xF6)
+#define REG_INTERRUPT_CLEAR1 (0xF7)
+
+/* 0xF8 - 0xFF Reserved */
+
+/*
+ * Mask and bit definitions of TVP5146/47 registers
+ */
+/* The ID values we are looking for */
+#define TVP514X_CHIP_ID_MSB (0x51)
+#define TVP5146_CHIP_ID_LSB (0x46)
+#define TVP5147_CHIP_ID_LSB (0x47)
+
+#define VIDEO_STD_MASK (0x07)
+#define VIDEO_STD_AUTO_SWITCH_BIT (0x00)
+#define VIDEO_STD_NTSC_MJ_BIT (0x01)
+#define VIDEO_STD_PAL_BDGHIN_BIT (0x02)
+#define VIDEO_STD_PAL_M_BIT (0x03)
+#define VIDEO_STD_PAL_COMBINATION_N_BIT (0x04)
+#define VIDEO_STD_NTSC_4_43_BIT (0x05)
+#define VIDEO_STD_SECAM_BIT (0x06)
+#define VIDEO_STD_PAL_60_BIT (0x07)
+
+/*
+ * Status bit
+ */
+#define STATUS_TV_VCR_BIT (1<<0)
+#define STATUS_HORZ_SYNC_LOCK_BIT (1<<1)
+#define STATUS_VIRT_SYNC_LOCK_BIT (1<<2)
+#define STATUS_CLR_SUBCAR_LOCK_BIT (1<<3)
+#define STATUS_LOST_LOCK_DETECT_BIT (1<<4)
+#define STATUS_FEILD_RATE_BIT (1<<5)
+#define STATUS_LINE_ALTERNATING_BIT (1<<6)
+#define STATUS_PEAK_WHITE_DETECT_BIT (1<<7)
+
+/* Tokens for register write */
+#define TOK_WRITE (0) /* token for write operation */
+#define TOK_TERM (1) /* terminating token */
+#define TOK_DELAY (2) /* delay token for reg list */
+#define TOK_SKIP (3) /* token to skip a register */
+/**
+ * struct tvp514x_reg - Structure for TVP5146/47 register initialization values
+ * @token - Token: TOK_WRITE, TOK_TERM etc..
+ * @reg - Register offset
+ * @val - Register Value for TOK_WRITE or delay in ms for TOK_DELAY
+ */
+struct tvp514x_reg {
+ u8 token;
+ u8 reg;
+ u32 val;
+};
+
+/**
+ * struct tvp514x_init_seq - Structure for TVP5146/47/46M2/47M1 power up
+ * Sequence.
+ * @ no_regs - Number of registers to write for power up sequence.
+ * @ init_reg_seq - Array of registers and respective value to write.
+ */
+struct tvp514x_init_seq {
+ unsigned int no_regs;
+ const struct tvp514x_reg *init_reg_seq;
+};
+#endif /* ifndef _TVP514X_REGS_H */
diff --git a/linux/drivers/media/video/tvp5150.c b/linux/drivers/media/video/tvp5150.c
index ac8205d87..f968e8941 100644
--- a/linux/drivers/media/video/tvp5150.c
+++ b/linux/drivers/media/video/tvp5150.c
@@ -10,8 +10,10 @@
#include <linux/videodev2.h>
#include <linux/delay.h>
#include <linux/video_decoder.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/tvp5150.h>
+#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-chip-ident.h>
#include "tvp5150_reg.h"
@@ -30,21 +32,7 @@ I2C_CLIENT_INSMOD;
static int debug;
module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level (0-1)");
-
-#define tvp5150_err(fmt, arg...) do { \
- printk(KERN_ERR "%s %d-%04x: " fmt, c->driver->driver.name, \
- i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
-#define tvp5150_info(fmt, arg...) do { \
- printk(KERN_INFO "%s %d-%04x: " fmt, c->driver->driver.name, \
- i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
-#define tvp5150_dbg(num, fmt, arg...) \
- do { \
- if (debug >= num) \
- printk(KERN_DEBUG "%s debug %d-%04x: " fmt,\
- c->driver->driver.name, \
- i2c_adapter_id(c->adapter), \
- c->addr , ## arg); } while (0)
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
/* supported controls */
static struct v4l2_queryctrl tvp5150_qctrl[] = {
@@ -88,7 +76,7 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = {
};
struct tvp5150 {
- struct i2c_client *client;
+ struct v4l2_subdev sd;
v4l2_std_id norm; /* Current set standard */
struct v4l2_routing route;
@@ -99,49 +87,57 @@ struct tvp5150 {
int sat;
};
-static int tvp5150_read(struct i2c_client *c, unsigned char addr)
+static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd)
{
+ return container_of(sd, struct tvp5150, sd);
+}
+
+static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
+{
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
unsigned char buffer[1];
int rc;
buffer[0] = addr;
if (1 != (rc = i2c_master_send(c, buffer, 1)))
- tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+ v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
msleep(10);
if (1 != (rc = i2c_master_recv(c, buffer, 1)))
- tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+ v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
- tvp5150_dbg(2, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
+ v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
return (buffer[0]);
}
-static inline void tvp5150_write(struct i2c_client *c, unsigned char addr,
+static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
unsigned char value)
{
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
unsigned char buffer[2];
int rc;
buffer[0] = addr;
buffer[1] = value;
- tvp5150_dbg(2, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+ v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
if (2 != (rc = i2c_master_send(c, buffer, 2)))
- tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
+ v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 2)\n", rc);
}
-static void dump_reg_range(struct i2c_client *c, char *s, u8 init, const u8 end,int max_line)
+static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init,
+ const u8 end, int max_line)
{
- int i=0;
+ int i = 0;
- while (init!=(u8)(end+1)) {
- if ((i%max_line) == 0) {
- if (i>0)
+ while (init != (u8)(end + 1)) {
+ if ((i % max_line) == 0) {
+ if (i > 0)
printk("\n");
- printk("tvp5150: %s reg 0x%02x = ",s,init);
+ printk("tvp5150: %s reg 0x%02x = ", s, init);
}
- printk("%02x ",tvp5150_read(c, init));
+ printk("%02x ", tvp5150_read(sd, init));
init++;
i++;
@@ -149,151 +145,152 @@ static void dump_reg_range(struct i2c_client *c, char *s, u8 init, const u8 end,
printk("\n");
}
-static void dump_reg(struct i2c_client *c)
+static int tvp5150_log_status(struct v4l2_subdev *sd)
{
printk("tvp5150: Video input source selection #1 = 0x%02x\n",
- tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1));
+ tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1));
printk("tvp5150: Analog channel controls = 0x%02x\n",
- tvp5150_read(c, TVP5150_ANAL_CHL_CTL));
+ tvp5150_read(sd, TVP5150_ANAL_CHL_CTL));
printk("tvp5150: Operation mode controls = 0x%02x\n",
- tvp5150_read(c, TVP5150_OP_MODE_CTL));
+ tvp5150_read(sd, TVP5150_OP_MODE_CTL));
printk("tvp5150: Miscellaneous controls = 0x%02x\n",
- tvp5150_read(c, TVP5150_MISC_CTL));
+ tvp5150_read(sd, TVP5150_MISC_CTL));
printk("tvp5150: Autoswitch mask= 0x%02x\n",
- tvp5150_read(c, TVP5150_AUTOSW_MSK));
+ tvp5150_read(sd, TVP5150_AUTOSW_MSK));
printk("tvp5150: Color killer threshold control = 0x%02x\n",
- tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL));
+ tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL));
printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n",
- tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1),
- tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2),
- tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3));
+ tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1),
+ tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2),
+ tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3));
printk("tvp5150: Brightness control = 0x%02x\n",
- tvp5150_read(c, TVP5150_BRIGHT_CTL));
+ tvp5150_read(sd, TVP5150_BRIGHT_CTL));
printk("tvp5150: Color saturation control = 0x%02x\n",
- tvp5150_read(c, TVP5150_SATURATION_CTL));
+ tvp5150_read(sd, TVP5150_SATURATION_CTL));
printk("tvp5150: Hue control = 0x%02x\n",
- tvp5150_read(c, TVP5150_HUE_CTL));
+ tvp5150_read(sd, TVP5150_HUE_CTL));
printk("tvp5150: Contrast control = 0x%02x\n",
- tvp5150_read(c, TVP5150_CONTRAST_CTL));
+ tvp5150_read(sd, TVP5150_CONTRAST_CTL));
printk("tvp5150: Outputs and data rates select = 0x%02x\n",
- tvp5150_read(c, TVP5150_DATA_RATE_SEL));
+ tvp5150_read(sd, TVP5150_DATA_RATE_SEL));
printk("tvp5150: Configuration shared pins = 0x%02x\n",
- tvp5150_read(c, TVP5150_CONF_SHARED_PIN));
+ tvp5150_read(sd, TVP5150_CONF_SHARED_PIN));
printk("tvp5150: Active video cropping start = 0x%02x%02x\n",
- tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB),
- tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB));
+ tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB),
+ tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB));
printk("tvp5150: Active video cropping stop = 0x%02x%02x\n",
- tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB),
- tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB));
+ tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB),
+ tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB));
printk("tvp5150: Genlock/RTC = 0x%02x\n",
- tvp5150_read(c, TVP5150_GENLOCK));
+ tvp5150_read(sd, TVP5150_GENLOCK));
printk("tvp5150: Horizontal sync start = 0x%02x\n",
- tvp5150_read(c, TVP5150_HORIZ_SYNC_START));
+ tvp5150_read(sd, TVP5150_HORIZ_SYNC_START));
printk("tvp5150: Vertical blanking start = 0x%02x\n",
- tvp5150_read(c, TVP5150_VERT_BLANKING_START));
+ tvp5150_read(sd, TVP5150_VERT_BLANKING_START));
printk("tvp5150: Vertical blanking stop = 0x%02x\n",
- tvp5150_read(c, TVP5150_VERT_BLANKING_STOP));
+ tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP));
printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n",
- tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1),
- tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2));
+ tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1),
+ tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2));
printk("tvp5150: Interrupt reset register B = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_RESET_REG_B));
+ tvp5150_read(sd, TVP5150_INT_RESET_REG_B));
printk("tvp5150: Interrupt enable register B = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_ENABLE_REG_B));
+ tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B));
printk("tvp5150: Interrupt configuration register B = 0x%02x\n",
- tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B));
+ tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B));
printk("tvp5150: Video standard = 0x%02x\n",
- tvp5150_read(c, TVP5150_VIDEO_STD));
+ tvp5150_read(sd, TVP5150_VIDEO_STD));
printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n",
- tvp5150_read(c, TVP5150_CB_GAIN_FACT),
- tvp5150_read(c, TVP5150_CR_GAIN_FACTOR));
+ tvp5150_read(sd, TVP5150_CB_GAIN_FACT),
+ tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR));
printk("tvp5150: Macrovision on counter = 0x%02x\n",
- tvp5150_read(c, TVP5150_MACROVISION_ON_CTR));
+ tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR));
printk("tvp5150: Macrovision off counter = 0x%02x\n",
- tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR));
+ tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR));
printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n",
- (tvp5150_read(c, TVP5150_REV_SELECT)&1)?3:4);
+ (tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4);
printk("tvp5150: Device ID = %02x%02x\n",
- tvp5150_read(c, TVP5150_MSB_DEV_ID),
- tvp5150_read(c, TVP5150_LSB_DEV_ID));
+ tvp5150_read(sd, TVP5150_MSB_DEV_ID),
+ tvp5150_read(sd, TVP5150_LSB_DEV_ID));
printk("tvp5150: ROM version = (hex) %02x.%02x\n",
- tvp5150_read(c, TVP5150_ROM_MAJOR_VER),
- tvp5150_read(c, TVP5150_ROM_MINOR_VER));
+ tvp5150_read(sd, TVP5150_ROM_MAJOR_VER),
+ tvp5150_read(sd, TVP5150_ROM_MINOR_VER));
printk("tvp5150: Vertical line count = 0x%02x%02x\n",
- tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB),
- tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB));
+ tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB),
+ tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB));
printk("tvp5150: Interrupt status register B = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_STATUS_REG_B));
+ tvp5150_read(sd, TVP5150_INT_STATUS_REG_B));
printk("tvp5150: Interrupt active register B = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B));
+ tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B));
printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n",
- tvp5150_read(c, TVP5150_STATUS_REG_1),
- tvp5150_read(c, TVP5150_STATUS_REG_2),
- tvp5150_read(c, TVP5150_STATUS_REG_3),
- tvp5150_read(c, TVP5150_STATUS_REG_4),
- tvp5150_read(c, TVP5150_STATUS_REG_5));
+ tvp5150_read(sd, TVP5150_STATUS_REG_1),
+ tvp5150_read(sd, TVP5150_STATUS_REG_2),
+ tvp5150_read(sd, TVP5150_STATUS_REG_3),
+ tvp5150_read(sd, TVP5150_STATUS_REG_4),
+ tvp5150_read(sd, TVP5150_STATUS_REG_5));
#if 0 /* This will pop a value from vbi reg */
printk("tvp5150: VBI FIFO read data = 0x%02x\n",
- tvp5150_read(c, TVP5150_VBI_FIFO_READ_DATA));
+ tvp5150_read(sd, TVP5150_VBI_FIFO_READ_DATA));
#endif
- dump_reg_range(c,"Teletext filter 1", TVP5150_TELETEXT_FIL1_INI,
- TVP5150_TELETEXT_FIL1_END,8);
- dump_reg_range(c,"Teletext filter 2", TVP5150_TELETEXT_FIL2_INI,
- TVP5150_TELETEXT_FIL2_END,8);
+ dump_reg_range(sd, "Teletext filter 1", TVP5150_TELETEXT_FIL1_INI,
+ TVP5150_TELETEXT_FIL1_END, 8);
+ dump_reg_range(sd, "Teletext filter 2", TVP5150_TELETEXT_FIL2_INI,
+ TVP5150_TELETEXT_FIL2_END, 8);
printk("tvp5150: Teletext filter enable = 0x%02x\n",
- tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA));
+ tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA));
printk("tvp5150: Interrupt status register A = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_STATUS_REG_A));
+ tvp5150_read(sd, TVP5150_INT_STATUS_REG_A));
printk("tvp5150: Interrupt enable register A = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_ENABLE_REG_A));
+ tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A));
printk("tvp5150: Interrupt configuration = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_CONF));
+ tvp5150_read(sd, TVP5150_INT_CONF));
printk("tvp5150: VDP status register = 0x%02x\n",
- tvp5150_read(c, TVP5150_VDP_STATUS_REG));
+ tvp5150_read(sd, TVP5150_VDP_STATUS_REG));
printk("tvp5150: FIFO word count = 0x%02x\n",
- tvp5150_read(c, TVP5150_FIFO_WORD_COUNT));
+ tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT));
printk("tvp5150: FIFO interrupt threshold = 0x%02x\n",
- tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD));
+ tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD));
printk("tvp5150: FIFO reset = 0x%02x\n",
- tvp5150_read(c, TVP5150_FIFO_RESET));
+ tvp5150_read(sd, TVP5150_FIFO_RESET));
printk("tvp5150: Line number interrupt = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_NUMBER_INT));
+ tvp5150_read(sd, TVP5150_LINE_NUMBER_INT));
printk("tvp5150: Pixel alignment register = 0x%02x%02x\n",
- tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH),
- tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW));
+ tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH),
+ tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW));
printk("tvp5150: FIFO output control = 0x%02x\n",
- tvp5150_read(c, TVP5150_FIFO_OUT_CTRL));
+ tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL));
printk("tvp5150: Full field enable = 0x%02x\n",
- tvp5150_read(c, TVP5150_FULL_FIELD_ENA));
+ tvp5150_read(sd, TVP5150_FULL_FIELD_ENA));
printk("tvp5150: Full field mode register = 0x%02x\n",
- tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG));
+ tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG));
- dump_reg_range(c,"CC data", TVP5150_CC_DATA_INI,
- TVP5150_CC_DATA_END,8);
+ dump_reg_range(sd, "CC data", TVP5150_CC_DATA_INI,
+ TVP5150_CC_DATA_END, 8);
- dump_reg_range(c,"WSS data", TVP5150_WSS_DATA_INI,
- TVP5150_WSS_DATA_END,8);
+ dump_reg_range(sd, "WSS data", TVP5150_WSS_DATA_INI,
+ TVP5150_WSS_DATA_END, 8);
- dump_reg_range(c,"VPS data", TVP5150_VPS_DATA_INI,
- TVP5150_VPS_DATA_END,8);
+ dump_reg_range(sd, "VPS data", TVP5150_VPS_DATA_INI,
+ TVP5150_VPS_DATA_END, 8);
- dump_reg_range(c,"VITC data", TVP5150_VITC_DATA_INI,
- TVP5150_VITC_DATA_END,10);
+ dump_reg_range(sd, "VITC data", TVP5150_VITC_DATA_INI,
+ TVP5150_VITC_DATA_END, 10);
- dump_reg_range(c,"Line mode", TVP5150_LINE_MODE_INI,
- TVP5150_LINE_MODE_END,8);
+ dump_reg_range(sd, "Line mode", TVP5150_LINE_MODE_INI,
+ TVP5150_LINE_MODE_END, 8);
+ return 0;
}
/****************************************************************************
Basic functions
****************************************************************************/
-static inline void tvp5150_selmux(struct i2c_client *c)
+static inline void tvp5150_selmux(struct v4l2_subdev *sd)
{
int opmode=0;
- struct tvp5150 *decoder = i2c_get_clientdata(c);
+ struct tvp5150 *decoder = to_tvp5150(sd);
int input = 0;
unsigned char val;
@@ -314,23 +311,23 @@ static inline void tvp5150_selmux(struct i2c_client *c)
break;
}
- tvp5150_dbg( 1, "Selecting video route: route input=%i, output=%i "
+ v4l2_dbg(1, debug, sd, "Selecting video route: route input=%i, output=%i "
"=> tvp5150 input=%i, opmode=%i\n",
decoder->route.input,decoder->route.output,
input, opmode );
- tvp5150_write(c, TVP5150_OP_MODE_CTL, opmode);
- tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
+ tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode);
+ tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input);
/* Svideo should enable YCrCb output and disable GPCL output
* For Composite and TV, it should be the reverse
*/
- val = tvp5150_read(c, TVP5150_MISC_CTL);
+ val = tvp5150_read(sd, TVP5150_MISC_CTL);
if (decoder->route.input == TVP5150_SVIDEO)
val = (val & ~0x40) | 0x10;
else
val = (val & ~0x10) | 0x40;
- tvp5150_write(c, TVP5150_MISC_CTL, val);
+ tvp5150_write(sd, TVP5150_MISC_CTL, val);
};
struct i2c_reg_value {
@@ -605,35 +602,35 @@ static struct i2c_vbi_ram_value vbi_ram_default[] =
{ (u16)-1 }
};
-static int tvp5150_write_inittab(struct i2c_client *c,
+static int tvp5150_write_inittab(struct v4l2_subdev *sd,
const struct i2c_reg_value *regs)
{
while (regs->reg != 0xff) {
- tvp5150_write(c, regs->reg, regs->value);
+ tvp5150_write(sd, regs->reg, regs->value);
regs++;
}
return 0;
}
-static int tvp5150_vdp_init(struct i2c_client *c,
+static int tvp5150_vdp_init(struct v4l2_subdev *sd,
const struct i2c_vbi_ram_value *regs)
{
unsigned int i;
/* Disable Full Field */
- tvp5150_write(c, TVP5150_FULL_FIELD_ENA, 0);
+ tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);
/* Before programming, Line mode should be at 0xff */
- for (i=TVP5150_LINE_MODE_INI; i<=TVP5150_LINE_MODE_END; i++)
- tvp5150_write(c, i, 0xff);
+ for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
+ tvp5150_write(sd, i, 0xff);
/* Load Ram Table */
- while (regs->reg != (u16)-1 ) {
- tvp5150_write(c, TVP5150_CONF_RAM_ADDR_HIGH,regs->reg>>8);
- tvp5150_write(c, TVP5150_CONF_RAM_ADDR_LOW,regs->reg);
+ while (regs->reg != (u16)-1) {
+ tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8);
+ tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg);
- for (i=0;i<16;i++)
- tvp5150_write(c, TVP5150_VDP_CONF_RAM_DATA,regs->values[i]);
+ for (i = 0; i < 16; i++)
+ tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]);
regs++;
}
@@ -641,11 +638,13 @@ static int tvp5150_vdp_init(struct i2c_client *c,
}
/* Fills VBI capabilities based on i2c_vbi_ram_value struct */
-static void tvp5150_vbi_get_cap(const struct i2c_vbi_ram_value *regs,
+static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd,
struct v4l2_sliced_vbi_cap *cap)
{
+ const struct i2c_vbi_ram_value *regs = vbi_ram_default;
int line;
+ v4l2_dbg(1, debug, sd, "VIDIOC_G_SLICED_VBI_CAP\n");
memset(cap, 0, sizeof *cap);
while (regs->reg != (u16)-1 ) {
@@ -656,6 +655,7 @@ static void tvp5150_vbi_get_cap(const struct i2c_vbi_ram_value *regs,
regs++;
}
+ return 0;
}
/* Set vbi processing
@@ -671,18 +671,18 @@ static void tvp5150_vbi_get_cap(const struct i2c_vbi_ram_value *regs,
* LSB = field1
* MSB = field2
*/
-static int tvp5150_set_vbi(struct i2c_client *c,
+static int tvp5150_set_vbi(struct v4l2_subdev *sd,
const struct i2c_vbi_ram_value *regs,
unsigned int type,u8 flags, int line,
const int fields)
{
- struct tvp5150 *decoder = i2c_get_clientdata(c);
- v4l2_std_id std=decoder->norm;
+ struct tvp5150 *decoder = to_tvp5150(sd);
+ v4l2_std_id std = decoder->norm;
u8 reg;
int pos=0;
if (std == V4L2_STD_ALL) {
- tvp5150_err("VBI can't be configured without knowing number of lines\n");
+ v4l2_err(sd, "VBI can't be configured without knowing number of lines\n");
return 0;
} else if (std & V4L2_STD_625_50) {
/* Don't follow NTSC Line number convension */
@@ -710,174 +710,186 @@ static int tvp5150_set_vbi(struct i2c_client *c,
reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
if (fields&1) {
- tvp5150_write(c, reg, type);
+ tvp5150_write(sd, reg, type);
}
if (fields&2) {
- tvp5150_write(c, reg+1, type);
+ tvp5150_write(sd, reg+1, type);
}
return type;
}
-static int tvp5150_get_vbi(struct i2c_client *c,
+static int tvp5150_get_vbi(struct v4l2_subdev *sd,
const struct i2c_vbi_ram_value *regs, int line)
{
- struct tvp5150 *decoder = i2c_get_clientdata(c);
- v4l2_std_id std=decoder->norm;
+ struct tvp5150 *decoder = to_tvp5150(sd);
+ v4l2_std_id std = decoder->norm;
u8 reg;
- int pos, type=0;
+ int pos, type = 0;
if (std == V4L2_STD_ALL) {
- tvp5150_err("VBI can't be configured without knowing number of lines\n");
+ v4l2_err(sd, "VBI can't be configured without knowing number of lines\n");
return 0;
} else if (std & V4L2_STD_625_50) {
/* Don't follow NTSC Line number convension */
line += 3;
}
- if (line<6||line>27)
+ if (line < 6 || line > 27)
return 0;
- reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
+ reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI;
- pos=tvp5150_read(c, reg)&0x0f;
- if (pos<0x0f)
- type=regs[pos].type.vbi_type;
+ pos = tvp5150_read(sd, reg) & 0x0f;
+ if (pos < 0x0f)
+ type = regs[pos].type.vbi_type;
- pos=tvp5150_read(c, reg+1)&0x0f;
- if (pos<0x0f)
- type|=regs[pos].type.vbi_type;
+ pos = tvp5150_read(sd, reg + 1) & 0x0f;
+ if (pos < 0x0f)
+ type |= regs[pos].type.vbi_type;
return type;
}
-#if 0
-static int decode_vbi_data(struct i2c_client *c, vbi)
-{
- count=tvp5150_read(c, TVP5150_FIFO_WORD_COUNT);
- for (i=0;i<count;i++) {
- *p=tvp5150_read(c, TVP5150_VBI_FIFO_READ_DATA);
- p++;
- }
-}
-#endif
-static int tvp5150_set_std(struct i2c_client *c, v4l2_std_id std)
+static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
- struct tvp5150 *decoder = i2c_get_clientdata(c);
- int fmt=0;
+ struct tvp5150 *decoder = to_tvp5150(sd);
+ int fmt = 0;
- decoder->norm=std;
+ decoder->norm = std;
/* First tests should be against specific std */
if (std == V4L2_STD_ALL) {
- fmt=0; /* Autodetect mode */
+ fmt = 0; /* Autodetect mode */
} else if (std & V4L2_STD_NTSC_443) {
- fmt=0xa;
+ fmt = 0xa;
} else if (std & V4L2_STD_PAL_M) {
- fmt=0x6;
- } else if (std & (V4L2_STD_PAL_N| V4L2_STD_PAL_Nc)) {
- fmt=0x8;
+ fmt = 0x6;
+ } else if (std & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) {
+ fmt = 0x8;
} else {
/* Then, test against generic ones */
- if (std & V4L2_STD_NTSC) {
- fmt=0x2;
- } else if (std & V4L2_STD_PAL) {
- fmt=0x4;
- } else if (std & V4L2_STD_SECAM) {
- fmt=0xc;
- }
+ if (std & V4L2_STD_NTSC)
+ fmt = 0x2;
+ else if (std & V4L2_STD_PAL)
+ fmt = 0x4;
+ else if (std & V4L2_STD_SECAM)
+ fmt = 0xc;
}
- tvp5150_dbg(1,"Set video std register to %d.\n",fmt);
- tvp5150_write(c, TVP5150_VIDEO_STD, fmt);
-
+ v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt);
+ tvp5150_write(sd, TVP5150_VIDEO_STD, fmt);
return 0;
}
-static inline void tvp5150_reset(struct i2c_client *c)
+static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
+ struct tvp5150 *decoder = to_tvp5150(sd);
+
+ if (decoder->norm == std)
+ return 0;
+
+ return tvp5150_set_std(sd, std);
+}
+
+static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
+{
+ struct tvp5150 *decoder = to_tvp5150(sd);
u8 msb_id, lsb_id, msb_rom, lsb_rom;
- struct tvp5150 *decoder = i2c_get_clientdata(c);
- msb_id=tvp5150_read(c,TVP5150_MSB_DEV_ID);
- lsb_id=tvp5150_read(c,TVP5150_LSB_DEV_ID);
- msb_rom=tvp5150_read(c,TVP5150_ROM_MAJOR_VER);
- lsb_rom=tvp5150_read(c,TVP5150_ROM_MINOR_VER);
+ msb_id = tvp5150_read(sd, TVP5150_MSB_DEV_ID);
+ lsb_id = tvp5150_read(sd, TVP5150_LSB_DEV_ID);
+ msb_rom = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER);
+ lsb_rom = tvp5150_read(sd, TVP5150_ROM_MINOR_VER);
- if ((msb_rom==4)&&(lsb_rom==0)) { /* Is TVP5150AM1 */
- tvp5150_info("tvp%02x%02xam1 detected.\n",msb_id, lsb_id);
+ if (msb_rom == 4 && lsb_rom == 0) { /* Is TVP5150AM1 */
+ v4l2_info(sd, "tvp%02x%02xam1 detected.\n", msb_id, lsb_id);
/* ITU-T BT.656.4 timing */
- tvp5150_write(c,TVP5150_REV_SELECT,0);
+ tvp5150_write(sd, TVP5150_REV_SELECT, 0);
} else {
- if ((msb_rom==3)||(lsb_rom==0x21)) { /* Is TVP5150A */
- tvp5150_info("tvp%02x%02xa detected.\n",msb_id, lsb_id);
+ if (msb_rom == 3 || lsb_rom == 0x21) { /* Is TVP5150A */
+ v4l2_info(sd, "tvp%02x%02xa detected.\n", msb_id, lsb_id);
} else {
- tvp5150_info("*** unknown tvp%02x%02x chip detected.\n",msb_id,lsb_id);
- tvp5150_info("*** Rom ver is %d.%d\n",msb_rom,lsb_rom);
+ v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n",
+ msb_id, lsb_id);
+ v4l2_info(sd, "*** Rom ver is %d.%d\n", msb_rom, lsb_rom);
}
}
/* Initializes TVP5150 to its default values */
- tvp5150_write_inittab(c, tvp5150_init_default);
+ tvp5150_write_inittab(sd, tvp5150_init_default);
/* Initializes VDP registers */
- tvp5150_vdp_init(c, vbi_ram_default);
+ tvp5150_vdp_init(sd, vbi_ram_default);
/* Selects decoder input */
- tvp5150_selmux(c);
+ tvp5150_selmux(sd);
/* Initializes TVP5150 to stream enabled values */
- tvp5150_write_inittab(c, tvp5150_init_enable);
+ tvp5150_write_inittab(sd, tvp5150_init_enable);
/* Initialize image preferences */
- tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright);
- tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast);
- tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast);
- tvp5150_write(c, TVP5150_HUE_CTL, decoder->hue);
+ tvp5150_write(sd, TVP5150_BRIGHT_CTL, decoder->bright);
+ tvp5150_write(sd, TVP5150_CONTRAST_CTL, decoder->contrast);
+ tvp5150_write(sd, TVP5150_SATURATION_CTL, decoder->contrast);
+ tvp5150_write(sd, TVP5150_HUE_CTL, decoder->hue);
- tvp5150_set_std(c, decoder->norm);
+ tvp5150_set_std(sd, decoder->norm);
+ return 0;
};
-static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
+static int tvp5150_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
-/* struct tvp5150 *decoder = i2c_get_clientdata(c); */
+ v4l2_dbg(1, debug, sd, "VIDIOC_G_CTRL called\n");
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- ctrl->value = tvp5150_read(c, TVP5150_BRIGHT_CTL);
+ ctrl->value = tvp5150_read(sd, TVP5150_BRIGHT_CTL);
return 0;
case V4L2_CID_CONTRAST:
- ctrl->value = tvp5150_read(c, TVP5150_CONTRAST_CTL);
+ ctrl->value = tvp5150_read(sd, TVP5150_CONTRAST_CTL);
return 0;
case V4L2_CID_SATURATION:
- ctrl->value = tvp5150_read(c, TVP5150_SATURATION_CTL);
+ ctrl->value = tvp5150_read(sd, TVP5150_SATURATION_CTL);
return 0;
case V4L2_CID_HUE:
- ctrl->value = tvp5150_read(c, TVP5150_HUE_CTL);
+ ctrl->value = tvp5150_read(sd, TVP5150_HUE_CTL);
return 0;
}
return -EINVAL;
}
-static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
+static int tvp5150_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
-/* struct tvp5150 *decoder = i2c_get_clientdata(c); */
+ u8 i, n;
+ n = ARRAY_SIZE(tvp5150_qctrl);
+
+ for (i = 0; i < n; i++) {
+ if (ctrl->id != tvp5150_qctrl[i].id)
+ continue;
+ if (ctrl->value < tvp5150_qctrl[i].minimum ||
+ ctrl->value > tvp5150_qctrl[i].maximum)
+ return -ERANGE;
+ v4l2_dbg(1, debug, sd, "VIDIOC_S_CTRL: id=%d, value=%d\n",
+ ctrl->id, ctrl->value);
+ break;
+ }
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- tvp5150_write(c, TVP5150_BRIGHT_CTL, ctrl->value);
+ tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->value);
return 0;
case V4L2_CID_CONTRAST:
- tvp5150_write(c, TVP5150_CONTRAST_CTL, ctrl->value);
+ tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->value);
return 0;
case V4L2_CID_SATURATION:
- tvp5150_write(c, TVP5150_SATURATION_CTL, ctrl->value);
+ tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->value);
return 0;
case V4L2_CID_HUE:
- tvp5150_write(c, TVP5150_HUE_CTL, ctrl->value);
+ tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->value);
return 0;
}
return -EINVAL;
@@ -886,289 +898,264 @@ static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
/****************************************************************************
I2C Command
****************************************************************************/
-static int tvp5150_command(struct i2c_client *c,
- unsigned int cmd, void *arg)
-{
- struct tvp5150 *decoder = i2c_get_clientdata(c);
-
- switch (cmd) {
-
- case 0:
- case VIDIOC_INT_RESET:
- tvp5150_reset(c);
- break;
- case VIDIOC_INT_G_VIDEO_ROUTING:
- {
- struct v4l2_routing *route = arg;
-
- *route = decoder->route;
- break;
- }
- case VIDIOC_INT_S_VIDEO_ROUTING:
- {
- struct v4l2_routing *route = arg;
- decoder->route = *route;
- tvp5150_selmux(c);
- break;
- }
- case VIDIOC_S_STD:
- if (decoder->norm == *(v4l2_std_id *)arg)
- break;
- return tvp5150_set_std(c, *(v4l2_std_id *)arg);
- case VIDIOC_G_STD:
- *(v4l2_std_id *)arg = decoder->norm;
- break;
+static int tvp5150_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+ struct tvp5150 *decoder = to_tvp5150(sd);
- case VIDIOC_G_SLICED_VBI_CAP:
- {
- struct v4l2_sliced_vbi_cap *cap = arg;
- tvp5150_dbg(1, "VIDIOC_G_SLICED_VBI_CAP\n");
+ decoder->route = *route;
+ tvp5150_selmux(sd);
+ return 0;
+}
- tvp5150_vbi_get_cap(vbi_ram_default, cap);
- break;
+static int tvp5150_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+ struct v4l2_sliced_vbi_format *svbi;
+ int i;
+
+ /* raw vbi */
+ if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ /* this is for capturing 36 raw vbi lines
+ if there's a way to cut off the beginning 2 vbi lines
+ with the tvp5150 then the vbi line count could be lowered
+ to 17 lines/field again, although I couldn't find a register
+ which could do that cropping */
+ if (fmt->fmt.vbi.sample_format == V4L2_PIX_FMT_GREY)
+ tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70);
+ if (fmt->fmt.vbi.count[0] == 18 && fmt->fmt.vbi.count[1] == 18) {
+ tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00);
+ tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01);
+ }
+ return 0;
}
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *fmt;
- struct v4l2_sliced_vbi_format *svbi;
- int i;
-
- fmt = arg;
- /* raw vbi */
- if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- /* this is for capturing 36 raw vbi lines
- if there's a way to cut off the beginning 2 vbi lines
- with the tvp5150 then the vbi line count could be lowered
- to 17 lines/field again, although I couldn't find a register
- which could do that cropping */
- if (fmt->fmt.vbi.sample_format == V4L2_PIX_FMT_GREY)
- tvp5150_write(c, TVP5150_LUMA_PROC_CTL_1, 0x70);
- if (fmt->fmt.vbi.count[0] == 18 && fmt->fmt.vbi.count[1] == 18) {
- tvp5150_write(c, TVP5150_VERT_BLANKING_START, 0x00);
- tvp5150_write(c, TVP5150_VERT_BLANKING_STOP, 0x01);
- }
- break;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ if (svbi->service_set != 0) {
+ for (i = 0; i <= 23; i++) {
+ svbi->service_lines[1][i] = 0;
+ svbi->service_lines[0][i] =
+ tvp5150_set_vbi(sd, vbi_ram_default,
+ svbi->service_lines[0][i], 0xf0, i, 3);
}
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
- svbi = &fmt->fmt.sliced;
- if (svbi->service_set != 0) {
- for (i = 0; i <= 23; i++) {
- svbi->service_lines[1][i] = 0;
-
- svbi->service_lines[0][i]=tvp5150_set_vbi(c,
- vbi_ram_default,
- svbi->service_lines[0][i],0xf0,i,3);
- }
- /* Enables FIFO */
- tvp5150_write(c, TVP5150_FIFO_OUT_CTRL,1);
- } else {
- /* Disables FIFO*/
- tvp5150_write(c, TVP5150_FIFO_OUT_CTRL,0);
+ /* Enables FIFO */
+ tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1);
+ } else {
+ /* Disables FIFO*/
+ tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 0);
- /* Disable Full Field */
- tvp5150_write(c, TVP5150_FULL_FIELD_ENA, 0);
+ /* Disable Full Field */
+ tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);
- /* Disable Line modes */
- for (i=TVP5150_LINE_MODE_INI; i<=TVP5150_LINE_MODE_END; i++)
- tvp5150_write(c, i, 0xff);
- }
- break;
+ /* Disable Line modes */
+ for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
+ tvp5150_write(sd, i, 0xff);
}
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *fmt;
- struct v4l2_sliced_vbi_format *svbi;
+ return 0;
+}
- int i, mask=0;
+static int tvp5150_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+ struct v4l2_sliced_vbi_format *svbi;
+ int i, mask = 0;
- fmt = arg;
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
- svbi = &fmt->fmt.sliced;
- memset(svbi, 0, sizeof(*svbi));
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ memset(svbi, 0, sizeof(*svbi));
- for (i = 0; i <= 23; i++) {
- svbi->service_lines[0][i]=tvp5150_get_vbi(c,
- vbi_ram_default,i);
- mask|=svbi->service_lines[0][i];
- }
- svbi->service_set=mask;
- break;
+ for (i = 0; i <= 23; i++) {
+ svbi->service_lines[0][i] =
+ tvp5150_get_vbi(sd, vbi_ram_default, i);
+ mask |= svbi->service_lines[0][i];
}
+ svbi->service_set = mask;
+ return 0;
+}
+
#if 0
- /* This will not work for USB devices */
- case VIDIOC_INT_G_VBI_DATA:
- {
- struct v4l2_sliced_vbi_data *data = arg;
- u8 status;
-
- status=tvp5150_read(c, TVP5150_VDP_STATUS_REG);
-
- if (data->id & V4L2_SLICED_CAPTION) {
- if (!field && (status&0x10)) {
- data->data[0]=tvp5150_read(c, TVP5150_CC_DATA_INI);
- data->data[1]=tvp5150_read(c, TVP5150_CC_DATA_INI+1);
- } if (field && (status&0x8)) {
- data->data[0]=tvp5150_read(c, TVP5150_CC_DATA_INI+2);
- data->data[1]=tvp5150_read(c, TVP5150_CC_DATA_INI+3);
- } else data->id=0;
- return 0;
- } else if (data->id & V4L2_SLICED_WSS) {
- } else if (data->id & V4L2_SLICED_VPS) {
+/* This will not work for USB devices */
+static int tvp5150_g_vbi_data(struct v4l2_subdev *sd,
+ struct v4l2_sliced_vbi_data *data)
+{
+ u8 status = tvp5150_read(sd, TVP5150_VDP_STATUS_REG);
+
+ if (data->id & V4L2_SLICED_CAPTION) {
+ if (!field && (status & 0x10)) {
+ data->data[0] = tvp5150_read(sd, TVP5150_CC_DATA_INI);
+ data->data[1] = tvp5150_read(sd, TVP5150_CC_DATA_INI+1);
+ } if (field && (status & 0x8)) {
+ data->data[0] = tvp5150_read(sd, TVP5150_CC_DATA_INI+2);
+ data->data[1] = tvp5150_read(sd, TVP5150_CC_DATA_INI+3);
+ } else {
+ data->id = 0;
}
- break;
+ return 0;
+ } else if (data->id & V4L2_SLICED_WSS) {
+ } else if (data->id & V4L2_SLICED_VPS) {
}
- case VIDIOC_INT_DECODE_VBI_LINE:
- {
- struct v4l2_decode_vbi_line *vbi = arg;
- u8 status;
+ return 0;
+}
- status=tvp5150_read(c, TVP5150_VDP_STATUS_REG);
+static int decode_vbi_data(struct v4l2_subdev *sd, vbi)
+{
+ count = tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT);
- if (status&0x80) {
- tvp5150_err("Full field error");
- status&=0x7f;
- tvp5150_write(c, TVP5150_VDP_STATUS_REG,status);
- }
+ for (i = 0; i < count; i++) {
+ *p = tvp5150_read(sd, TVP5150_VBI_FIFO_READ_DATA);
+ p++;
+ }
+}
- /* FIFO */
- /* Current V4L2 API allows sliced VBI only with fifo mode,
- since line and types are not provided on other means
- on tvp5150.
- */
- if (!(status&0x40)) /* Has FIFO data */
- decode_vbi_data(c,vbi);
+static int tvp5150_decode_vbi_line(struct v4l2_subdev *sd,
+ struct v4l2_decode_vbi_line *vbi)
+{
+ u8 status = tvp5150_read(sd, TVP5150_VDP_STATUS_REG);
- break;
+ if (status & 0x80) {
+ v4l2_err(sd, "Full field error");
+ status &= 0x7f;
+ tvp5150_write(sd, TVP5150_VDP_STATUS_REG, status);
}
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (!v4l2_chip_match_i2c_client(c, reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (cmd == VIDIOC_DBG_G_REGISTER)
- reg->val = tvp5150_read(c, reg->reg & 0xff);
- else
- tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
- break;
- }
+ /* FIFO */
+ /* Current V4L2 API allows sliced VBI only with fifo mode,
+ since line and types are not provided on other means
+ on tvp5150.
+ */
+ if (!(status & 0x40)) /* Has FIFO data */
+ decode_vbi_data(sd, vbi);
+ return 0;
+}
#endif
- case VIDIOC_LOG_STATUS:
- dump_reg(c);
- break;
+static int tvp5150_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ int rev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *vt = arg;
- int status = tvp5150_read(c, 0x88);
+ rev = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER) << 8 |
+ tvp5150_read(sd, TVP5150_ROM_MINOR_VER);
- vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0;
- break;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
- int i;
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP5150,
+ rev);
+}
- tvp5150_dbg(1, "VIDIOC_QUERYCTRL called\n");
- for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++)
- if (qc->id && qc->id == tvp5150_qctrl[i].id) {
- memcpy(qc, &(tvp5150_qctrl[i]),
- sizeof(*qc));
- return 0;
- }
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- return -EINVAL;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- tvp5150_dbg(1, "VIDIOC_G_CTRL called\n");
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->val = tvp5150_read(sd, reg->reg & 0xff);
+ reg->size = 1;
+ return 0;
+}
- return tvp5150_get_ctrl(c, ctrl);
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- u8 i, n;
- n = ARRAY_SIZE(tvp5150_qctrl);
- for (i = 0; i < n; i++)
- if (ctrl->id == tvp5150_qctrl[i].id) {
- if (ctrl->value <
- tvp5150_qctrl[i].minimum
- || ctrl->value >
- tvp5150_qctrl[i].maximum)
- return -ERANGE;
- tvp5150_dbg(1,
- "VIDIOC_S_CTRL: id=%d, value=%d\n",
- ctrl->id, ctrl->value);
- return tvp5150_set_ctrl(c, ctrl);
- }
- return -EINVAL;
- }
+static int tvp5150_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- default:
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
return -EINVAL;
- }
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff);
+ return 0;
+}
+#endif
+static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ int status = tvp5150_read(sd, 0x88);
+
+ vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0;
return 0;
}
+static int tvp5150_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ v4l2_dbg(1, debug, sd, "VIDIOC_QUERYCTRL called\n");
+
+ for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++)
+ if (qc->id && qc->id == tvp5150_qctrl[i].id) {
+ memcpy(qc, &(tvp5150_qctrl[i]),
+ sizeof(*qc));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int tvp5150_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
+ .log_status = tvp5150_log_status,
+ .g_ctrl = tvp5150_g_ctrl,
+ .s_ctrl = tvp5150_s_ctrl,
+ .queryctrl = tvp5150_queryctrl,
+ .reset = tvp5150_reset,
+ .g_chip_ident = tvp5150_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = tvp5150_g_register,
+ .s_register = tvp5150_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
+ .s_std = tvp5150_s_std,
+ .g_tuner = tvp5150_g_tuner,
+};
+
+static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
+ .s_routing = tvp5150_s_routing,
+ .g_fmt = tvp5150_g_fmt,
+ .s_fmt = tvp5150_s_fmt,
+ .g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap,
+};
+
+static const struct v4l2_subdev_ops tvp5150_ops = {
+ .core = &tvp5150_core_ops,
+ .tuner = &tvp5150_tuner_ops,
+ .video = &tvp5150_video_ops,
+};
+
+
/****************************************************************************
I2C Client & Driver
****************************************************************************/
-static struct i2c_driver driver;
-static struct i2c_client client_template = {
- .name = "(unset)",
- .driver = &driver,
-};
-
-static int tvp5150_detect_client(struct i2c_adapter *adapter,
- int address, int kind)
+static int tvp5150_probe(struct i2c_client *c,
+ const struct i2c_device_id *id)
{
- struct i2c_client *c;
struct tvp5150 *core;
- int rv;
-
- if (debug)
- printk( KERN_INFO
- "tvp5150.c: detecting tvp5150 client on address 0x%x\n",
- address << 1);
-
- client_template.adapter = adapter;
- client_template.addr = address;
+ struct v4l2_subdev *sd;
/* Check if the adapter supports the needed features */
- if (!i2c_check_functionality
- (adapter,
+ if (!i2c_check_functionality(c->adapter,
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
- return 0;
-
- c = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!c)
- return -ENOMEM;
- memcpy(c, &client_template, sizeof(struct i2c_client));
+ return -EIO;
core = kzalloc(sizeof(struct tvp5150), GFP_KERNEL);
if (!core) {
- kfree(c);
return -ENOMEM;
}
- i2c_set_clientdata(c, core);
-
- rv = i2c_attach_client(c);
+ sd = &core->sd;
+ v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
+ v4l_info(c, "chip found @ 0x%02x (%s)\n",
+ c->addr << 1, c->adapter->name);
core->norm = V4L2_STD_ALL; /* Default is autodetect */
core->route.input = TVP5150_COMPOSITE1;
@@ -1178,75 +1165,42 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
core->hue = 0;
core->sat = 128;
- if (rv) {
- kfree(c);
- kfree(core);
- return rv;
- }
-
if (debug > 1)
- dump_reg(c);
+ tvp5150_log_status(sd);
return 0;
}
-static int tvp5150_attach_adapter(struct i2c_adapter *adapter)
-{
- if (debug)
- printk( KERN_INFO
- "tvp5150.c: starting probe for adapter %s (0x%x)\n",
- adapter->name, adapter->id);
- return i2c_probe(adapter, &addr_data, &tvp5150_detect_client);
-}
-
-static int tvp5150_detach_client(struct i2c_client *c)
+static int tvp5150_remove(struct i2c_client *c)
{
- struct tvp5150 *decoder = i2c_get_clientdata(c);
- int err;
+ struct v4l2_subdev *sd = i2c_get_clientdata(c);
- tvp5150_dbg(1,
+ v4l2_dbg(1, debug, sd,
"tvp5150.c: removing tvp5150 adapter on address 0x%x\n",
c->addr << 1);
- err = i2c_detach_client(c);
- if (err) {
- return err;
- }
-
- kfree(decoder);
- kfree(c);
-
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_tvp5150(sd));
return 0;
}
/* ----------------------------------------------------------------------- */
-static struct i2c_driver driver = {
- .driver = {
- .name = "tvp5150",
- },
- .id = I2C_DRIVERID_TVP5150,
-
- .attach_adapter = tvp5150_attach_adapter,
- .detach_client = tvp5150_detach_client,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id tvp5150_id[] = {
+ { "tvp5150", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tvp5150_id);
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "tvp5150",
+ .driverid = I2C_DRIVERID_TVP5150,
.command = tvp5150_command,
-#if 0
- .driver = {
- .suspend = tvp5150_suspend,
- .resume = tvp5150_resume,
- },
+ .probe = tvp5150_probe,
+ .remove = tvp5150_remove,
+ .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tvp5150_id,
#endif
};
-
-static int __init tvp5150_init(void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit tvp5150_exit(void)
-{
- i2c_del_driver(&driver);
-}
-
-module_init(tvp5150_init);
-module_exit(tvp5150_exit);
diff --git a/linux/drivers/media/video/tw9910.c b/linux/drivers/media/video/tw9910.c
new file mode 100644
index 000000000..c670b23a1
--- /dev/null
+++ b/linux/drivers/media/video/tw9910.c
@@ -0,0 +1,959 @@
+/*
+ * tw9910 Video Driver
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov772x driver,
+ *
+ * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/soc_camera.h>
+#include <media/tw9910.h>
+
+#define GET_ID(val) ((val & 0xF8) >> 3)
+#define GET_ReV(val) (val & 0x07)
+
+/*
+ * register offset
+ */
+#define ID 0x00 /* Product ID Code Register */
+#define STATUS1 0x01 /* Chip Status Register I */
+#define INFORM 0x02 /* Input Format */
+#define OPFORM 0x03 /* Output Format Control Register */
+#define DLYCTR 0x04 /* Hysteresis and HSYNC Delay Control */
+#define OUTCTR1 0x05 /* Output Control I */
+#define ACNTL1 0x06 /* Analog Control Register 1 */
+#define CROP_HI 0x07 /* Cropping Register, High */
+#define VDELAY_LO 0x08 /* Vertical Delay Register, Low */
+#define VACTIVE_LO 0x09 /* Vertical Active Register, Low */
+#define HDELAY_LO 0x0A /* Horizontal Delay Register, Low */
+#define HACTIVE_LO 0x0B /* Horizontal Active Register, Low */
+#define CNTRL1 0x0C /* Control Register I */
+#define VSCALE_LO 0x0D /* Vertical Scaling Register, Low */
+#define SCALE_HI 0x0E /* Scaling Register, High */
+#define HSCALE_LO 0x0F /* Horizontal Scaling Register, Low */
+#define BRIGHT 0x10 /* BRIGHTNESS Control Register */
+#define CONTRAST 0x11 /* CONTRAST Control Register */
+#define SHARPNESS 0x12 /* SHARPNESS Control Register I */
+#define SAT_U 0x13 /* Chroma (U) Gain Register */
+#define SAT_V 0x14 /* Chroma (V) Gain Register */
+#define HUE 0x15 /* Hue Control Register */
+#define CORING1 0x17
+#define CORING2 0x18 /* Coring and IF compensation */
+#define VBICNTL 0x19 /* VBI Control Register */
+#define ACNTL2 0x1A /* Analog Control 2 */
+#define OUTCTR2 0x1B /* Output Control 2 */
+#define SDT 0x1C /* Standard Selection */
+#define SDTR 0x1D /* Standard Recognition */
+#define TEST 0x1F /* Test Control Register */
+#define CLMPG 0x20 /* Clamping Gain */
+#define IAGC 0x21 /* Individual AGC Gain */
+#define AGCGAIN 0x22 /* AGC Gain */
+#define PEAKWT 0x23 /* White Peak Threshold */
+#define CLMPL 0x24 /* Clamp level */
+#define SYNCT 0x25 /* Sync Amplitude */
+#define MISSCNT 0x26 /* Sync Miss Count Register */
+#define PCLAMP 0x27 /* Clamp Position Register */
+#define VCNTL1 0x28 /* Vertical Control I */
+#define VCNTL2 0x29 /* Vertical Control II */
+#define CKILL 0x2A /* Color Killer Level Control */
+#define COMB 0x2B /* Comb Filter Control */
+#define LDLY 0x2C /* Luma Delay and H Filter Control */
+#define MISC1 0x2D /* Miscellaneous Control I */
+#define LOOP 0x2E /* LOOP Control Register */
+#define MISC2 0x2F /* Miscellaneous Control II */
+#define MVSN 0x30 /* Macrovision Detection */
+#define STATUS2 0x31 /* Chip STATUS II */
+#define HFREF 0x32 /* H monitor */
+#define CLMD 0x33 /* CLAMP MODE */
+#define IDCNTL 0x34 /* ID Detection Control */
+#define CLCNTL1 0x35 /* Clamp Control I */
+#define ANAPLLCTL 0x4C
+#define VBIMIN 0x4D
+#define HSLOWCTL 0x4E
+#define WSS3 0x4F
+#define FILLDATA 0x50
+#define SDID 0x51
+#define DID 0x52
+#define WSS1 0x53
+#define WSS2 0x54
+#define VVBI 0x55
+#define LCTL6 0x56
+#define LCTL7 0x57
+#define LCTL8 0x58
+#define LCTL9 0x59
+#define LCTL10 0x5A
+#define LCTL11 0x5B
+#define LCTL12 0x5C
+#define LCTL13 0x5D
+#define LCTL14 0x5E
+#define LCTL15 0x5F
+#define LCTL16 0x60
+#define LCTL17 0x61
+#define LCTL18 0x62
+#define LCTL19 0x63
+#define LCTL20 0x64
+#define LCTL21 0x65
+#define LCTL22 0x66
+#define LCTL23 0x67
+#define LCTL24 0x68
+#define LCTL25 0x69
+#define LCTL26 0x6A
+#define HSGEGIN 0x6B
+#define HSEND 0x6C
+#define OVSDLY 0x6D
+#define OVSEND 0x6E
+#define VBIDELAY 0x6F
+
+/*
+ * register detail
+ */
+
+/* INFORM */
+#define FC27_ON 0x40 /* 1 : Input crystal clock frequency is 27MHz */
+#define FC27_FF 0x00 /* 0 : Square pixel mode. */
+ /* Must use 24.54MHz for 60Hz field rate */
+ /* source or 29.5MHz for 50Hz field rate */
+#define IFSEL_S 0x10 /* 01 : S-video decoding */
+#define IFSEL_C 0x00 /* 00 : Composite video decoding */
+ /* Y input video selection */
+#define YSEL_M0 0x00 /* 00 : Mux0 selected */
+#define YSEL_M1 0x04 /* 01 : Mux1 selected */
+#define YSEL_M2 0x08 /* 10 : Mux2 selected */
+#define YSEL_M3 0x10 /* 11 : Mux3 selected */
+
+/* OPFORM */
+#define MODE 0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */
+ /* 1 : ITU-R-656 compatible data sequence format */
+#define LEN 0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */
+ /* 1 : 16-bit YCrCb 4:2:2 output format.*/
+#define LLCMODE 0x20 /* 1 : LLC output mode. */
+ /* 0 : free-run output mode */
+#define AINC 0x10 /* Serial interface auto-indexing control */
+ /* 0 : auto-increment */
+ /* 1 : non-auto */
+#define VSCTL 0x08 /* 1 : Vertical out ctrl by DVALID */
+ /* 0 : Vertical out ctrl by HACTIVE and DVALID */
+#define OEN 0x04 /* Output Enable together with TRI_SEL. */
+
+/* OUTCTR1 */
+#define VSP_LO 0x00 /* 0 : VS pin output polarity is active low */
+#define VSP_HI 0x80 /* 1 : VS pin output polarity is active high. */
+ /* VS pin output control */
+#define VSSL_VSYNC 0x00 /* 0 : VSYNC */
+#define VSSL_VACT 0x10 /* 1 : VACT */
+#define VSSL_FIELD 0x20 /* 2 : FIELD */
+#define VSSL_VVALID 0x30 /* 3 : VVALID */
+#define VSSL_ZERO 0x70 /* 7 : 0 */
+#define HSP_LOW 0x00 /* 0 : HS pin output polarity is active low */
+#define HSP_HI 0x08 /* 1 : HS pin output polarity is active high.*/
+ /* HS pin output control */
+#define HSSL_HACT 0x00 /* 0 : HACT */
+#define HSSL_HSYNC 0x01 /* 1 : HSYNC */
+#define HSSL_DVALID 0x02 /* 2 : DVALID */
+#define HSSL_HLOCK 0x03 /* 3 : HLOCK */
+#define HSSL_ASYNCW 0x04 /* 4 : ASYNCW */
+#define HSSL_ZERO 0x07 /* 7 : 0 */
+
+/* ACNTL1 */
+#define SRESET 0x80 /* resets the device to its default state
+ * but all register content remain unchanged.
+ * This bit is self-resetting.
+ */
+
+/* VBICNTL */
+/* RTSEL : control the real time signal
+* output from the MPOUT pin
+*/
+#define RTSEL_MASK 0x07
+#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */
+#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */
+#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */
+#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */
+#define RTSEL_MONO 0x04 /* 0100 = MONO */
+#define RTSEL_DET50 0x05 /* 0101 = DET50 */
+#define RTSEL_FIELD 0x06 /* 0110 = FIELD */
+#define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */
+
+/*
+ * structure
+ */
+
+struct regval_list {
+ unsigned char reg_num;
+ unsigned char value;
+};
+
+struct tw9910_scale_ctrl {
+ char *name;
+ unsigned short width;
+ unsigned short height;
+ u16 hscale;
+ u16 vscale;
+};
+
+struct tw9910_cropping_ctrl {
+ u16 vdelay;
+ u16 vactive;
+ u16 hdelay;
+ u16 hactive;
+};
+
+struct tw9910_hsync_ctrl {
+ u16 start;
+ u16 end;
+};
+
+struct tw9910_priv {
+ struct tw9910_video_info *info;
+ struct i2c_client *client;
+ struct soc_camera_device icd;
+ const struct tw9910_scale_ctrl *scale;
+};
+
+/*
+ * register settings
+ */
+
+#define ENDMARKER { 0xff, 0xff }
+
+static const struct regval_list tw9910_default_regs[] =
+{
+ { OPFORM, 0x00 },
+ { OUTCTR1, VSP_LO | VSSL_VVALID | HSP_HI | HSSL_HSYNC },
+ ENDMARKER,
+};
+
+static const struct soc_camera_data_format tw9910_color_fmt[] = {
+ {
+ .name = "VYUY",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .depth = 16,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ }
+};
+
+static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = {
+ {
+ .name = "NTSC SQ",
+ .width = 640,
+ .height = 480,
+ .hscale = 0x0100,
+ .vscale = 0x0100,
+ },
+ {
+ .name = "NTSC CCIR601",
+ .width = 720,
+ .height = 480,
+ .hscale = 0x0100,
+ .vscale = 0x0100,
+ },
+ {
+ .name = "NTSC SQ (CIF)",
+ .width = 320,
+ .height = 240,
+ .hscale = 0x0200,
+ .vscale = 0x0200,
+ },
+ {
+ .name = "NTSC CCIR601 (CIF)",
+ .width = 360,
+ .height = 240,
+ .hscale = 0x0200,
+ .vscale = 0x0200,
+ },
+ {
+ .name = "NTSC SQ (QCIF)",
+ .width = 160,
+ .height = 120,
+ .hscale = 0x0400,
+ .vscale = 0x0400,
+ },
+ {
+ .name = "NTSC CCIR601 (QCIF)",
+ .width = 180,
+ .height = 120,
+ .hscale = 0x0400,
+ .vscale = 0x0400,
+ },
+};
+
+static const struct tw9910_scale_ctrl tw9910_pal_scales[] = {
+ {
+ .name = "PAL SQ",
+ .width = 768,
+ .height = 576,
+ .hscale = 0x0100,
+ .vscale = 0x0100,
+ },
+ {
+ .name = "PAL CCIR601",
+ .width = 720,
+ .height = 576,
+ .hscale = 0x0100,
+ .vscale = 0x0100,
+ },
+ {
+ .name = "PAL SQ (CIF)",
+ .width = 384,
+ .height = 288,
+ .hscale = 0x0200,
+ .vscale = 0x0200,
+ },
+ {
+ .name = "PAL CCIR601 (CIF)",
+ .width = 360,
+ .height = 288,
+ .hscale = 0x0200,
+ .vscale = 0x0200,
+ },
+ {
+ .name = "PAL SQ (QCIF)",
+ .width = 192,
+ .height = 144,
+ .hscale = 0x0400,
+ .vscale = 0x0400,
+ },
+ {
+ .name = "PAL CCIR601 (QCIF)",
+ .width = 180,
+ .height = 144,
+ .hscale = 0x0400,
+ .vscale = 0x0400,
+ },
+};
+
+static const struct tw9910_cropping_ctrl tw9910_cropping_ctrl = {
+ .vdelay = 0x0012,
+ .vactive = 0x00F0,
+ .hdelay = 0x0010,
+ .hactive = 0x02D0,
+};
+
+static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = {
+ .start = 0x0260,
+ .end = 0x0300,
+};
+
+/*
+ * general function
+ */
+static int tw9910_set_scale(struct i2c_client *client,
+ const struct tw9910_scale_ctrl *scale)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, SCALE_HI,
+ (scale->vscale & 0x0F00) >> 4 |
+ (scale->hscale & 0x0F00) >> 8);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, HSCALE_LO,
+ scale->hscale & 0x00FF);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, VSCALE_LO,
+ scale->vscale & 0x00FF);
+
+ return ret;
+}
+
+static int tw9910_set_cropping(struct i2c_client *client,
+ const struct tw9910_cropping_ctrl *cropping)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, CROP_HI,
+ (cropping->vdelay & 0x0300) >> 2 |
+ (cropping->vactive & 0x0300) >> 4 |
+ (cropping->hdelay & 0x0300) >> 6 |
+ (cropping->hactive & 0x0300) >> 8);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, VDELAY_LO,
+ cropping->vdelay & 0x00FF);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, VACTIVE_LO,
+ cropping->vactive & 0x00FF);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, HDELAY_LO,
+ cropping->hdelay & 0x00FF);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, HACTIVE_LO,
+ cropping->hactive & 0x00FF);
+
+ return ret;
+}
+
+static int tw9910_set_hsync(struct i2c_client *client,
+ const struct tw9910_hsync_ctrl *hsync)
+{
+ int ret;
+
+ /* bit 10 - 3 */
+ ret = i2c_smbus_write_byte_data(client, HSGEGIN,
+ (hsync->start & 0x07F8) >> 3);
+ if (ret < 0)
+ return ret;
+
+ /* bit 10 - 3 */
+ ret = i2c_smbus_write_byte_data(client, HSEND,
+ (hsync->end & 0x07F8) >> 3);
+ if (ret < 0)
+ return ret;
+
+ /* bit 2 - 0 */
+ ret = i2c_smbus_read_byte_data(client, HSLOWCTL);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, HSLOWCTL,
+ (ret & 0x88) |
+ (hsync->start & 0x0007) << 4 |
+ (hsync->end & 0x0007));
+
+ return ret;
+}
+
+static int tw9910_write_array(struct i2c_client *client,
+ const struct regval_list *vals)
+{
+ while (vals->reg_num != 0xff) {
+ int ret = i2c_smbus_write_byte_data(client,
+ vals->reg_num,
+ vals->value);
+ if (ret < 0)
+ return ret;
+ vals++;
+ }
+ return 0;
+}
+
+static int tw9910_mask_set(struct i2c_client *client, u8 command,
+ u8 mask, u8 set)
+{
+ s32 val = i2c_smbus_read_byte_data(client, command);
+
+ val &= ~mask;
+ val |= set;
+
+ return i2c_smbus_write_byte_data(client, command, val);
+}
+
+static void tw9910_reset(struct i2c_client *client)
+{
+ i2c_smbus_write_byte_data(client, ACNTL1, SRESET);
+ msleep(1);
+}
+
+static const struct tw9910_scale_ctrl*
+tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height)
+{
+ const struct tw9910_scale_ctrl *scale;
+ const struct tw9910_scale_ctrl *ret = NULL;
+ v4l2_std_id norm = icd->vdev->current_norm;
+ __u32 diff = 0xffffffff, tmp;
+ int size, i;
+
+ if (norm & V4L2_STD_NTSC) {
+ scale = tw9910_ntsc_scales;
+ size = ARRAY_SIZE(tw9910_ntsc_scales);
+ } else if (norm & V4L2_STD_PAL) {
+ scale = tw9910_pal_scales;
+ size = ARRAY_SIZE(tw9910_pal_scales);
+ } else {
+ return NULL;
+ }
+
+ for (i = 0; i < size; i++) {
+ tmp = abs(width - scale[i].width) +
+ abs(height - scale[i].height);
+ if (tmp < diff) {
+ diff = tmp;
+ ret = scale + i;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * soc_camera_ops function
+ */
+static int tw9910_init(struct soc_camera_device *icd)
+{
+ struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ int ret = 0;
+
+ if (priv->info->link.power) {
+ ret = priv->info->link.power(&priv->client->dev, 1);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (priv->info->link.reset)
+ ret = priv->info->link.reset(&priv->client->dev);
+
+ return ret;
+}
+
+static int tw9910_release(struct soc_camera_device *icd)
+{
+ struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ int ret = 0;
+
+ if (priv->info->link.power)
+ ret = priv->info->link.power(&priv->client->dev, 0);
+
+ return ret;
+}
+
+static int tw9910_start_capture(struct soc_camera_device *icd)
+{
+ struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+
+ if (!priv->scale) {
+ dev_err(&icd->dev, "norm select error\n");
+ return -EPERM;
+ }
+
+ dev_dbg(&icd->dev, "%s %dx%d\n",
+ priv->scale->name,
+ priv->scale->width,
+ priv->scale->height);
+
+ return 0;
+}
+
+static int tw9910_stop_capture(struct soc_camera_device *icd)
+{
+ return 0;
+}
+
+static int tw9910_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ return 0;
+}
+
+static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd)
+{
+ struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ struct soc_camera_link *icl = priv->client->dev.platform_data;
+ unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static int tw9910_get_chip_id(struct soc_camera_device *icd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ id->ident = V4L2_IDENT_TW9910;
+ id->revision = 0;
+
+ return 0;
+}
+
+static int tw9910_set_std(struct soc_camera_device *icd,
+ v4l2_std_id *a)
+{
+ int ret = -EINVAL;
+
+ if (*a & (V4L2_STD_NTSC | V4L2_STD_PAL))
+ ret = 0;
+
+ return ret;
+}
+
+static int tw9910_enum_input(struct soc_camera_device *icd,
+ struct v4l2_input *inp)
+{
+ inp->type = V4L2_INPUT_TYPE_TUNER;
+ inp->std = V4L2_STD_UNKNOWN;
+ strcpy(inp->name, "Video");
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int tw9910_get_register(struct soc_camera_device *icd,
+ struct v4l2_dbg_register *reg)
+{
+ struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ int ret;
+
+ if (reg->reg > 0xff)
+ return -EINVAL;
+
+ ret = i2c_smbus_read_byte_data(priv->client, reg->reg);
+ if (ret < 0)
+ return ret;
+
+ /* ret = int
+ * reg->val = __u64
+ */
+ reg->val = (__u64)ret;
+
+ return 0;
+}
+
+static int tw9910_set_register(struct soc_camera_device *icd,
+ struct v4l2_dbg_register *reg)
+{
+ struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+
+ if (reg->reg > 0xff ||
+ reg->val > 0xff)
+ return -EINVAL;
+
+ return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val);
+}
+#endif
+
+static int tw9910_set_fmt(struct soc_camera_device *icd, __u32 pixfmt,
+ struct v4l2_rect *rect)
+{
+ struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ int ret = -EINVAL;
+ u8 val;
+
+ /*
+ * select suitable norm
+ */
+ priv->scale = tw9910_select_norm(icd, rect->width, rect->height);
+ if (!priv->scale)
+ goto tw9910_set_fmt_error;
+
+ /*
+ * reset hardware
+ */
+ tw9910_reset(priv->client);
+ ret = tw9910_write_array(priv->client, tw9910_default_regs);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ /*
+ * set bus width
+ */
+ val = 0x00;
+ if (SOCAM_DATAWIDTH_16 == priv->info->buswidth)
+ val = LEN;
+
+ ret = tw9910_mask_set(priv->client, OPFORM, LEN, val);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ /*
+ * select MPOUT behavior
+ */
+ switch (priv->info->mpout) {
+ case TW9910_MPO_VLOSS:
+ val = RTSEL_VLOSS; break;
+ case TW9910_MPO_HLOCK:
+ val = RTSEL_HLOCK; break;
+ case TW9910_MPO_SLOCK:
+ val = RTSEL_SLOCK; break;
+ case TW9910_MPO_VLOCK:
+ val = RTSEL_VLOCK; break;
+ case TW9910_MPO_MONO:
+ val = RTSEL_MONO; break;
+ case TW9910_MPO_DET50:
+ val = RTSEL_DET50; break;
+ case TW9910_MPO_FIELD:
+ val = RTSEL_FIELD; break;
+ case TW9910_MPO_RTCO:
+ val = RTSEL_RTCO; break;
+ default:
+ val = 0;
+ }
+
+ ret = tw9910_mask_set(priv->client, VBICNTL, RTSEL_MASK, val);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ /*
+ * set scale
+ */
+ ret = tw9910_set_scale(priv->client, priv->scale);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ /*
+ * set cropping
+ */
+ ret = tw9910_set_cropping(priv->client, &tw9910_cropping_ctrl);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ /*
+ * set hsync
+ */
+ ret = tw9910_set_hsync(priv->client, &tw9910_hsync_ctrl);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ return ret;
+
+tw9910_set_fmt_error:
+
+ tw9910_reset(priv->client);
+ priv->scale = NULL;
+
+ return ret;
+}
+
+static int tw9910_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ const struct tw9910_scale_ctrl *scale;
+
+ if (V4L2_FIELD_ANY == pix->field) {
+ pix->field = V4L2_FIELD_INTERLACED;
+ } else if (V4L2_FIELD_INTERLACED != pix->field) {
+ dev_err(&icd->dev, "Field type invalid.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * select suitable norm
+ */
+ scale = tw9910_select_norm(icd, pix->width, pix->height);
+ if (!scale)
+ return -EINVAL;
+
+ pix->width = scale->width;
+ pix->height = scale->height;
+
+ return 0;
+}
+
+static int tw9910_video_probe(struct soc_camera_device *icd)
+{
+ struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ s32 val;
+ int ret;
+
+ /*
+ * We must have a parent by now. And it cannot be a wrong one.
+ * So this entire test is completely redundant.
+ */
+ if (!icd->dev.parent ||
+ to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+ return -ENODEV;
+
+ /*
+ * tw9910 only use 8 or 16 bit bus width
+ */
+ if (SOCAM_DATAWIDTH_16 != priv->info->buswidth &&
+ SOCAM_DATAWIDTH_8 != priv->info->buswidth) {
+ dev_err(&icd->dev, "bus width error\n");
+ return -ENODEV;
+ }
+
+ icd->formats = tw9910_color_fmt;
+ icd->num_formats = ARRAY_SIZE(tw9910_color_fmt);
+
+ /*
+ * check and show Product ID
+ */
+ val = i2c_smbus_read_byte_data(priv->client, ID);
+ if (0x0B != GET_ID(val) ||
+ 0x00 != GET_ReV(val)) {
+ dev_err(&icd->dev,
+ "Product ID error %x:%x\n", GET_ID(val), GET_ReV(val));
+ return -ENODEV;
+ }
+
+ dev_info(&icd->dev,
+ "tw9910 Product ID %0x:%0x\n", GET_ID(val), GET_ReV(val));
+
+ ret = soc_camera_video_start(icd);
+ if (ret < 0)
+ return ret;
+
+ icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL;
+ icd->vdev->current_norm = V4L2_STD_NTSC;
+
+ return ret;
+}
+
+static void tw9910_video_remove(struct soc_camera_device *icd)
+{
+ soc_camera_video_stop(icd);
+}
+
+static struct soc_camera_ops tw9910_ops = {
+ .owner = THIS_MODULE,
+ .probe = tw9910_video_probe,
+ .remove = tw9910_video_remove,
+ .init = tw9910_init,
+ .release = tw9910_release,
+ .start_capture = tw9910_start_capture,
+ .stop_capture = tw9910_stop_capture,
+ .set_fmt = tw9910_set_fmt,
+ .try_fmt = tw9910_try_fmt,
+ .set_bus_param = tw9910_set_bus_param,
+ .query_bus_param = tw9910_query_bus_param,
+ .get_chip_id = tw9910_get_chip_id,
+ .set_std = tw9910_set_std,
+ .enum_input = tw9910_enum_input,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .get_register = tw9910_get_register,
+ .set_register = tw9910_set_register,
+#endif
+};
+
+/*
+ * i2c_driver function
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+static int tw9910_probe(struct i2c_client *client)
+#else
+static int tw9910_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+#endif
+
+{
+ struct tw9910_priv *priv;
+ struct tw9910_video_info *info;
+ struct soc_camera_device *icd;
+ const struct tw9910_scale_ctrl *scale;
+ int i, ret;
+
+ info = client->dev.platform_data;
+ if (!info)
+ return -EINVAL;
+
+ if (!i2c_check_functionality(to_i2c_adapter(client->dev.parent),
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev,
+ "I2C-Adapter doesn't support "
+ "I2C_FUNC_SMBUS_BYTE_DATA\n");
+ return -EIO;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->info = info;
+ priv->client = client;
+ i2c_set_clientdata(client, priv);
+
+ icd = &priv->icd;
+ icd->ops = &tw9910_ops;
+ icd->control = &client->dev;
+ icd->iface = info->link.bus_id;
+
+ /*
+ * set width and height
+ */
+ icd->width_max = tw9910_ntsc_scales[0].width; /* set default */
+ icd->width_min = tw9910_ntsc_scales[0].width;
+ icd->height_max = tw9910_ntsc_scales[0].height;
+ icd->height_min = tw9910_ntsc_scales[0].height;
+
+ scale = tw9910_ntsc_scales;
+ for (i = 0; i < ARRAY_SIZE(tw9910_ntsc_scales); i++) {
+ icd->width_max = max(scale[i].width, icd->width_max);
+ icd->width_min = min(scale[i].width, icd->width_min);
+ icd->height_max = max(scale[i].height, icd->height_max);
+ icd->height_min = min(scale[i].height, icd->height_min);
+ }
+ scale = tw9910_pal_scales;
+ for (i = 0; i < ARRAY_SIZE(tw9910_pal_scales); i++) {
+ icd->width_max = max(scale[i].width, icd->width_max);
+ icd->width_min = min(scale[i].width, icd->width_min);
+ icd->height_max = max(scale[i].height, icd->height_max);
+ icd->height_min = min(scale[i].height, icd->height_min);
+ }
+
+ ret = soc_camera_device_register(icd);
+
+ if (ret) {
+ i2c_set_clientdata(client, NULL);
+ kfree(priv);
+ }
+
+ return ret;
+}
+
+static int tw9910_remove(struct i2c_client *client)
+{
+ struct tw9910_priv *priv = i2c_get_clientdata(client);
+
+ soc_camera_device_unregister(&priv->icd);
+ i2c_set_clientdata(client, NULL);
+ kfree(priv);
+ return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id tw9910_id[] = {
+ { "tw9910", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tw9910_id);
+
+#endif
+static struct i2c_driver tw9910_i2c_driver = {
+ .driver = {
+ .name = "tw9910",
+ },
+ .probe = tw9910_probe,
+ .remove = tw9910_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tw9910_id,
+#endif
+};
+
+/*
+ * module function
+ */
+static int __init tw9910_module_init(void)
+{
+ return i2c_add_driver(&tw9910_i2c_driver);
+}
+
+static void __exit tw9910_module_exit(void)
+{
+ i2c_del_driver(&tw9910_i2c_driver);
+}
+
+module_init(tw9910_module_init);
+module_exit(tw9910_module_exit);
+
+MODULE_DESCRIPTION("SoC Camera driver for tw9910");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/linux/drivers/media/video/upd64031a.c b/linux/drivers/media/video/upd64031a.c
index dfca5ed6e..eb1dfe312 100644
--- a/linux/drivers/media/video/upd64031a.c
+++ b/linux/drivers/media/video/upd64031a.c
@@ -26,7 +26,7 @@
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
#include <media/upd64031a.h>
@@ -68,6 +68,7 @@ enum {
};
struct upd64031a_state {
+ struct v4l2_subdev sd;
u8 regs[TOT_REGS];
u8 gr_mode;
u8 direct_3dycs_connect;
@@ -75,6 +76,11 @@ struct upd64031a_state {
u8 ext_vert_sync;
};
+static inline struct upd64031a_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct upd64031a_state, sd);
+}
+
static u8 upd64031a_init[] = {
0x00, 0xb8, 0x48, 0xd2, 0xe6,
0x03, 0x10, 0x0b, 0xaf, 0x7f,
@@ -84,8 +90,9 @@ static u8 upd64031a_init[] = {
/* ------------------------------------------------------------------------ */
-static u8 upd64031a_read(struct i2c_client *client, u8 reg)
+static u8 upd64031a_read(struct v4l2_subdev *sd, u8 reg)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 buf[2];
if (reg >= sizeof(buf))
@@ -96,106 +103,126 @@ static u8 upd64031a_read(struct i2c_client *client, u8 reg)
/* ------------------------------------------------------------------------ */
-static void upd64031a_write(struct i2c_client *client, u8 reg, u8 val)
+static void upd64031a_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 buf[2];
buf[0] = reg;
buf[1] = val;
- v4l_dbg(1, debug, client, "write reg: %02X val: %02X\n", reg, val);
+ v4l2_dbg(1, debug, sd, "write reg: %02X val: %02X\n", reg, val);
if (i2c_master_send(client, buf, 2) != 2)
- v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val);
+ v4l2_err(sd, "I/O error write 0x%02x/0x%02x\n", reg, val);
}
/* ------------------------------------------------------------------------ */
/* The input changed due to new input or channel changed */
-static void upd64031a_change(struct i2c_client *client)
+static int upd64031a_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
{
- struct upd64031a_state *state = i2c_get_clientdata(client);
+ struct upd64031a_state *state = to_state(sd);
u8 reg = state->regs[R00];
- v4l_dbg(1, debug, client, "changed input or channel\n");
- upd64031a_write(client, R00, reg | 0x10);
- upd64031a_write(client, R00, reg & ~0x10);
+ v4l2_dbg(1, debug, sd, "changed input or channel\n");
+ upd64031a_write(sd, R00, reg | 0x10);
+ upd64031a_write(sd, R00, reg & ~0x10);
+ return 0;
}
/* ------------------------------------------------------------------------ */
-static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int upd64031a_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
{
- struct upd64031a_state *state = i2c_get_clientdata(client);
- struct v4l2_routing *route = arg;
-
- switch (cmd) {
- case VIDIOC_S_FREQUENCY:
- upd64031a_change(client);
- break;
-
- case VIDIOC_INT_G_VIDEO_ROUTING:
- route->input = (state->gr_mode >> 6) |
- (state->direct_3dycs_connect >> 4) |
- (state->ext_comp_sync >> 1) |
- (state->ext_vert_sync >> 2);
- route->output = 0;
- break;
-
- case VIDIOC_INT_S_VIDEO_ROUTING:
- {
- u8 r00, r05, r08;
-
- state->gr_mode = (route->input & 3) << 6;
- state->direct_3dycs_connect = (route->input & 0xc) << 4;
- state->ext_comp_sync =
- (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
- state->ext_vert_sync =
- (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2;
- r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode;
- r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) |
- state->ext_comp_sync | state->ext_vert_sync;
- r08 = (state->regs[R08] & ~DIRECT_3DYCS_CONNECT_MASK) |
- state->direct_3dycs_connect;
- upd64031a_write(client, R00, r00);
- upd64031a_write(client, R05, r05);
- upd64031a_write(client, R08, r08);
- upd64031a_change(client);
- break;
- }
-
- case VIDIOC_LOG_STATUS:
- v4l_info(client, "Status: SA00=0x%02x SA01=0x%02x\n",
- upd64031a_read(client, 0), upd64031a_read(client, 1));
- break;
+ struct upd64031a_state *state = to_state(sd);
+ u8 r00, r05, r08;
+
+ state->gr_mode = (route->input & 3) << 6;
+ state->direct_3dycs_connect = (route->input & 0xc) << 4;
+ state->ext_comp_sync =
+ (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
+ state->ext_vert_sync =
+ (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2;
+ r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode;
+ r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) |
+ state->ext_comp_sync | state->ext_vert_sync;
+ r08 = (state->regs[R08] & ~DIRECT_3DYCS_CONNECT_MASK) |
+ state->direct_3dycs_connect;
+ upd64031a_write(sd, R00, r00);
+ upd64031a_write(sd, R05, r05);
+ upd64031a_write(sd, R08, r08);
+ return upd64031a_s_frequency(sd, NULL);
+}
+
+static int upd64031a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64031A, 0);
+}
+
+static int upd64031a_log_status(struct v4l2_subdev *sd)
+{
+ v4l2_info(sd, "Status: SA00=0x%02x SA01=0x%02x\n",
+ upd64031a_read(sd, 0), upd64031a_read(sd, 1));
+ return 0;
+}
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (!v4l2_chip_match_i2c_client(client,
- reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (cmd == VIDIOC_DBG_G_REGISTER) {
- reg->val = upd64031a_read(client, reg->reg & 0xff);
- break;
- }
- upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
- break;
- }
-#endif
+static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->val = upd64031a_read(sd, reg->reg & 0xff);
+ reg->size = 1;
+ return 0;
+}
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client, arg,
- V4L2_IDENT_UPD64031A, 0);
+static int upd64031a_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- default:
- break;
- }
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ upd64031a_write(sd, reg->reg & 0xff, reg->val & 0xff);
return 0;
}
+#endif
+
+static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops upd64031a_core_ops = {
+ .log_status = upd64031a_log_status,
+ .g_chip_ident = upd64031a_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = upd64031a_g_register,
+ .s_register = upd64031a_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops upd64031a_tuner_ops = {
+ .s_frequency = upd64031a_s_frequency,
+};
+
+static const struct v4l2_subdev_video_ops upd64031a_video_ops = {
+ .s_routing = upd64031a_s_routing,
+};
+
+static const struct v4l2_subdev_ops upd64031a_ops = {
+ .core = &upd64031a_core_ops,
+ .tuner = &upd64031a_tuner_ops,
+ .video = &upd64031a_video_ops,
+};
/* ------------------------------------------------------------------------ */
@@ -205,6 +232,7 @@ static int upd64031a_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct upd64031a_state *state;
+ struct v4l2_subdev *sd;
int i;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -216,19 +244,23 @@ static int upd64031a_probe(struct i2c_client *client,
state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
- i2c_set_clientdata(client, state);
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &upd64031a_ops);
memcpy(state->regs, upd64031a_init, sizeof(state->regs));
state->gr_mode = UPD64031A_GR_ON << 6;
state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4;
state->ext_comp_sync = state->ext_vert_sync = 0;
for (i = 0; i < TOT_REGS; i++)
- upd64031a_write(client, i, state->regs[i]);
+ upd64031a_write(sd, i, state->regs[i]);
return 0;
}
static int upd64031a_remove(struct i2c_client *client)
{
- kfree(i2c_get_clientdata(client));
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
return 0;
}
diff --git a/linux/drivers/media/video/upd64083.c b/linux/drivers/media/video/upd64083.c
index 5f0c6919d..7bc2f2fa6 100644
--- a/linux/drivers/media/video/upd64083.c
+++ b/linux/drivers/media/video/upd64083.c
@@ -26,7 +26,7 @@
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
#include <media/upd64083.h>
@@ -57,11 +57,17 @@ enum {
};
struct upd64083_state {
+ struct v4l2_subdev sd;
u8 mode;
u8 ext_y_adc;
u8 regs[TOT_REGS];
};
+static inline struct upd64083_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct upd64083_state, sd);
+}
+
/* Initial values when used in combination with the
NEC upd64031a ghost reduction chip. */
static u8 upd64083_init[] = {
@@ -74,34 +80,24 @@ static u8 upd64083_init[] = {
/* ------------------------------------------------------------------------ */
-static void upd64083_log_status(struct i2c_client *client)
-{
- u8 buf[7];
-
- i2c_master_recv(client, buf, 7);
- v4l_info(client, "Status: SA00=%02x SA01=%02x SA02=%02x SA03=%02x "
- "SA04=%02x SA05=%02x SA06=%02x\n",
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
-}
-
-/* ------------------------------------------------------------------------ */
-
-static void upd64083_write(struct i2c_client *client, u8 reg, u8 val)
+static void upd64083_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 buf[2];
buf[0] = reg;
buf[1] = val;
- v4l_dbg(1, debug, client, "write reg: %02x val: %02x\n", reg, val);
+ v4l2_dbg(1, debug, sd, "write reg: %02x val: %02x\n", reg, val);
if (i2c_master_send(client, buf, 2) != 2)
- v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val);
+ v4l2_err(sd, "I/O error write 0x%02x/0x%02x\n", reg, val);
}
/* ------------------------------------------------------------------------ */
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static u8 upd64083_read(struct i2c_client *client, u8 reg)
+static u8 upd64083_read(struct v4l2_subdev *sd, u8 reg)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 buf[7];
if (reg >= sizeof(buf))
@@ -113,67 +109,93 @@ static u8 upd64083_read(struct i2c_client *client, u8 reg)
/* ------------------------------------------------------------------------ */
-static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int upd64083_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
{
- struct upd64083_state *state = i2c_get_clientdata(client);
- struct v4l2_routing *route = arg;
-
- switch (cmd) {
- case VIDIOC_INT_G_VIDEO_ROUTING:
- route->input = (state->mode >> 6) | (state->ext_y_adc >> 3);
- route->output = 0;
- break;
-
- case VIDIOC_INT_S_VIDEO_ROUTING:
- {
- u8 r00, r02;
-
- if (route->input > 7 || (route->input & 6) == 6)
- return -EINVAL;
- state->mode = (route->input & 3) << 6;
- state->ext_y_adc = (route->input & UPD64083_EXT_Y_ADC) << 3;
- r00 = (state->regs[R00] & ~(3 << 6)) | state->mode;
- r02 = (state->regs[R02] & ~(1 << 5)) | state->ext_y_adc;
- upd64083_write(client, R00, r00);
- upd64083_write(client, R02, r02);
- break;
- }
-
- case VIDIOC_LOG_STATUS:
- upd64083_log_status(client);
- break;
+ struct upd64083_state *state = to_state(sd);
+ u8 r00, r02;
+
+ if (route->input > 7 || (route->input & 6) == 6)
+ return -EINVAL;
+ state->mode = (route->input & 3) << 6;
+ state->ext_y_adc = (route->input & UPD64083_EXT_Y_ADC) << 3;
+ r00 = (state->regs[R00] & ~(3 << 6)) | state->mode;
+ r02 = (state->regs[R02] & ~(1 << 5)) | state->ext_y_adc;
+ upd64083_write(sd, R00, r00);
+ upd64083_write(sd, R02, r02);
+ return 0;
+}
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (!v4l2_chip_match_i2c_client(client,
- reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (cmd == VIDIOC_DBG_G_REGISTER) {
- reg->val = upd64083_read(client, reg->reg & 0xff);
- break;
- }
- upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
- break;
- }
+static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->val = upd64083_read(sd, reg->reg & 0xff);
+ reg->size = 1;
+ return 0;
+}
+
+static int upd64083_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ upd64083_write(sd, reg->reg & 0xff, reg->val & 0xff);
+ return 0;
+}
#endif
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client, arg,
- V4L2_IDENT_UPD64083, 0);
+static int upd64083_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64083, 0);
+}
- default:
- break;
- }
+static int upd64083_log_status(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 buf[7];
+ i2c_master_recv(client, buf, 7);
+ v4l2_info(sd, "Status: SA00=%02x SA01=%02x SA02=%02x SA03=%02x "
+ "SA04=%02x SA05=%02x SA06=%02x\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
return 0;
}
+static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops upd64083_core_ops = {
+ .log_status = upd64083_log_status,
+ .g_chip_ident = upd64083_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = upd64083_g_register,
+ .s_register = upd64083_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops upd64083_video_ops = {
+ .s_routing = upd64083_s_routing,
+};
+
+static const struct v4l2_subdev_ops upd64083_ops = {
+ .core = &upd64083_core_ops,
+ .video = &upd64083_video_ops,
+};
+
/* ------------------------------------------------------------------------ */
/* i2c implementation */
@@ -182,6 +204,7 @@ static int upd64083_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct upd64083_state *state;
+ struct v4l2_subdev *sd;
int i;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -193,19 +216,23 @@ static int upd64083_probe(struct i2c_client *client,
state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
- i2c_set_clientdata(client, state);
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &upd64083_ops);
/* Initially assume that a ghost reduction chip is present */
state->mode = 0; /* YCS mode */
state->ext_y_adc = (1 << 5);
memcpy(state->regs, upd64083_init, TOT_REGS);
for (i = 0; i < TOT_REGS; i++)
- upd64083_write(client, i, state->regs[i]);
+ upd64083_write(sd, i, state->regs[i]);
return 0;
}
static int upd64083_remove(struct i2c_client *client)
{
- kfree(i2c_get_clientdata(client));
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
return 0;
}
diff --git a/linux/drivers/media/video/usbvideo/ibmcam.c b/linux/drivers/media/video/usbvideo/ibmcam.c
index 1119bcf58..8b1a10fe1 100644
--- a/linux/drivers/media/video/usbvideo/ibmcam.c
+++ b/linux/drivers/media/video/usbvideo/ibmcam.c
@@ -3779,11 +3779,11 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *
err("Alternate settings have different endpoint addresses!");
return -ENODEV;
}
- if ((endpoint->bmAttributes & 0x03) != 0x01) {
+ if (usb_endpoint_type(endpoint) != USB_ENDPOINT_XFER_ISOC) {
err("Interface %d. has non-ISO endpoint!", ifnum);
return -ENODEV;
}
- if ((endpoint->bEndpointAddress & 0x80) == 0) {
+ if (usb_endpoint_dir_out(endpoint)) {
err("Interface %d. has ISO OUT endpoint!", ifnum);
return -ENODEV;
}
diff --git a/linux/drivers/media/video/usbvideo/konicawc.c b/linux/drivers/media/video/usbvideo/konicawc.c
index 73abbb3f4..cf20643a0 100644
--- a/linux/drivers/media/video/usbvideo/konicawc.c
+++ b/linux/drivers/media/video/usbvideo/konicawc.c
@@ -836,12 +836,12 @@ static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id
err("Alternate settings have different endpoint addresses!");
return -ENODEV;
}
- if ((endpoint->bmAttributes & 0x03) != 0x01) {
+ if (usb_endpoint_type(endpoint) != USB_ENDPOINT_XFER_ISOC) {
err("Interface %d. has non-ISO endpoint!",
interface->desc.bInterfaceNumber);
return -ENODEV;
}
- if ((endpoint->bEndpointAddress & 0x80) == 0) {
+ if (usb_endpoint_dir_out(endpoint)) {
err("Interface %d. has ISO OUT endpoint!",
interface->desc.bInterfaceNumber);
return -ENODEV;
diff --git a/linux/drivers/media/video/usbvideo/quickcam_messenger.c b/linux/drivers/media/video/usbvideo/quickcam_messenger.c
index d363e3d64..f129bea11 100644
--- a/linux/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/linux/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -460,7 +460,7 @@ static int qcm_sensor_init(struct uvd *uvd)
CHECK_RET(ret, qcm_stv_setw(uvd->dev, 0x15c1,
cpu_to_le16(ISOC_PACKET_SIZE)));
CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x15c3, 0x08));
- CHECK_RET(ret, ret = qcm_stv_setb(uvd->dev, 0x143f, 0x01));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143f, 0x01));
CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
@@ -972,8 +972,7 @@ static int qcm_probe(struct usb_interface *intf,
for (j=0; j < interface->desc.bNumEndpoints; j++) {
endpoint = &interface->endpoint[j].desc;
- if ((endpoint->bEndpointAddress &
- USB_ENDPOINT_DIR_MASK) != USB_DIR_IN)
+ if (usb_endpoint_dir_out(endpoint))
continue; /* not input then not good */
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
@@ -982,9 +981,7 @@ static int qcm_probe(struct usb_interface *intf,
continue; /* 0 pkt size is not what we want */
}
- if ((endpoint->bmAttributes &
- USB_ENDPOINT_XFERTYPE_MASK) ==
- USB_ENDPOINT_XFER_ISOC) {
+ if (usb_endpoint_xfer_isoc(endpoint)) {
video_ep = endpoint->bEndpointAddress;
/* break out of the search */
goto good_videoep;
diff --git a/linux/drivers/media/video/usbvideo/ultracam.c b/linux/drivers/media/video/usbvideo/ultracam.c
index d29e6a81b..b0c9495e8 100644
--- a/linux/drivers/media/video/usbvideo/ultracam.c
+++ b/linux/drivers/media/video/usbvideo/ultracam.c
@@ -556,12 +556,12 @@ static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id
err("Alternate settings have different endpoint addresses!");
return -ENODEV;
}
- if ((endpoint->bmAttributes & 0x03) != 0x01) {
+ if (usb_endpoint_type(endpoint) != USB_ENDPOINT_XFER_ISOC) {
err("Interface %d. has non-ISO endpoint!",
interface->desc.bInterfaceNumber);
return -ENODEV;
}
- if ((endpoint->bEndpointAddress & 0x80) == 0) {
+ if (usb_endpoint_dir_out(endpoint)) {
err("Interface %d. has ISO OUT endpoint!",
interface->desc.bInterfaceNumber);
return -ENODEV;
diff --git a/linux/drivers/media/video/usbvideo/usbvideo.c b/linux/drivers/media/video/usbvideo/usbvideo.c
index 332929bb2..dc6ffbbf8 100644
--- a/linux/drivers/media/video/usbvideo/usbvideo.c
+++ b/linux/drivers/media/video/usbvideo/usbvideo.c
@@ -41,13 +41,13 @@ module_param(video_nr, int, 0);
static void usbvideo_Disconnect(struct usb_interface *intf);
static void usbvideo_CameraRelease(struct uvd *uvd);
-static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
+static long usbvideo_v4l_ioctl(struct file *file,
unsigned int cmd, unsigned long arg);
static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);
-static int usbvideo_v4l_open(struct inode *inode, struct file *file);
+static int usbvideo_v4l_open(struct file *file);
static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
-static int usbvideo_v4l_close(struct inode *inode, struct file *file);
+static int usbvideo_v4l_close(struct file *file);
static int usbvideo_StartDataPump(struct uvd *uvd);
static void usbvideo_StopDataPump(struct uvd *uvd);
@@ -942,17 +942,13 @@ static int usbvideo_find_struct(struct usbvideo *cams)
return rv;
}
-static const struct file_operations usbvideo_fops = {
+static const struct v4l2_file_operations usbvideo_fops = {
.owner = THIS_MODULE,
.open = usbvideo_v4l_open,
.release =usbvideo_v4l_close,
.read = usbvideo_v4l_read,
.mmap = usbvideo_v4l_mmap,
.ioctl = usbvideo_v4l_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static const struct video_device usbvideo_template = {
.fops = &usbvideo_fops,
@@ -1113,7 +1109,7 @@ static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
* 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
* 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
*/
-static int usbvideo_v4l_open(struct inode *inode, struct file *file)
+static int usbvideo_v4l_open(struct file *file)
{
struct video_device *dev = video_devdata(file);
struct uvd *uvd = (struct uvd *) dev;
@@ -1123,7 +1119,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
if (uvd->debug > 1)
dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev);
- if (0 < usbvideo_ClientIncModCount(uvd))
+ if (usbvideo_ClientIncModCount(uvd) < 0)
return -ENODEV;
mutex_lock(&uvd->lock);
@@ -1233,7 +1229,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
* 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
* 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep.
*/
-static int usbvideo_v4l_close(struct inode *inode, struct file *file)
+static int usbvideo_v4l_close(struct file *file)
{
struct video_device *dev = file->private_data;
struct uvd *uvd = (struct uvd *) dev;
@@ -1281,7 +1277,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
* History:
* 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings.
*/
-static int usbvideo_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long usbvideo_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct uvd *uvd = file->private_data;
@@ -1501,7 +1497,7 @@ static int usbvideo_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0;
}
-static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
+static long usbvideo_v4l_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, usbvideo_v4l_do_ioctl);
diff --git a/linux/drivers/media/video/usbvideo/vicam.c b/linux/drivers/media/video/usbvideo/vicam.c
index 77032eaa7..5a039b5d6 100644
--- a/linux/drivers/media/video/usbvideo/vicam.c
+++ b/linux/drivers/media/video/usbvideo/vicam.c
@@ -539,12 +539,12 @@ set_camera_power(struct vicam_camera *cam, int state)
return 0;
}
-static int
-vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
+static long
+vicam_ioctl(struct file *file, unsigned int ioctlnr, unsigned long arg)
{
void __user *user_arg = (void __user *)arg;
struct vicam_camera *cam = file->private_data;
- int retval = 0;
+ long retval = 0;
if (!cam)
return -ENODEV;
@@ -780,7 +780,7 @@ vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsign
}
static int
-vicam_open(struct inode *inode, struct file *file)
+vicam_open(struct file *file)
{
struct vicam_camera *cam = video_drvdata(file);
@@ -846,7 +846,7 @@ vicam_open(struct inode *inode, struct file *file)
}
static int
-vicam_close(struct inode *inode, struct file *file)
+vicam_close(struct file *file)
{
struct vicam_camera *cam = file->private_data;
int open_count;
@@ -1093,17 +1093,13 @@ vicam_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-static const struct file_operations vicam_fops = {
+static const struct v4l2_file_operations vicam_fops = {
.owner = THIS_MODULE,
.open = vicam_open,
.release = vicam_close,
.read = vicam_read,
.mmap = vicam_mmap,
.ioctl = vicam_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
};
static struct video_device vicam_template = {
@@ -1154,8 +1150,7 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
endpoint = &interface->endpoint[0].desc;
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
+ if (usb_endpoint_is_bulk_in(endpoint)) {
/* we found a bulk in endpoint */
bulkEndpoint = endpoint->bEndpointAddress;
} else {
diff --git a/linux/drivers/media/video/usbvision/usbvision-i2c.c b/linux/drivers/media/video/usbvision/usbvision-i2c.c
index 888051b80..58f65e03a 100644
--- a/linux/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/linux/drivers/media/video/usbvision/usbvision-i2c.c
@@ -198,6 +198,9 @@ static struct i2c_algorithm usbvision_algo = {
.master_xfer = usbvision_i2c_xfer,
.smbus_xfer = NULL,
.functionality = functionality,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c
index 48c8c4399..2be5e47ed 100644
--- a/linux/drivers/media/video/usbvision/usbvision-video.c
+++ b/linux/drivers/media/video/usbvision/usbvision-video.c
@@ -355,7 +355,7 @@ static void usbvision_remove_sysfs(struct video_device *vdev)
* then allocates buffers needed for video processing.
*
*/
-static int usbvision_v4l2_open(struct inode *inode, struct file *file)
+static int usbvision_v4l2_open(struct file *file)
{
struct usb_usbvision *usbvision = video_drvdata(file);
int errCode = 0;
@@ -432,7 +432,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
* allocated in usbvision_v4l2_open().
*
*/
-static int usbvision_v4l2_close(struct inode *inode, struct file *file)
+static int usbvision_v4l2_close(struct file *file)
{
struct usb_usbvision *usbvision = video_drvdata(file);
@@ -477,12 +477,12 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
*/
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register (struct file *file, void *priv,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct usb_usbvision *usbvision = video_drvdata(file);
int errCode;
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
/* NT100x has a 8-bit register space */
errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
@@ -492,16 +492,17 @@ static int vidioc_g_register (struct file *file, void *priv,
return errCode;
}
reg->val = errCode;
+ reg->size = 1;
return 0;
}
static int vidioc_s_register (struct file *file, void *priv,
- struct v4l2_register *reg)
+ struct v4l2_dbg_register *reg)
{
struct usb_usbvision *usbvision = video_drvdata(file);
int errCode;
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
/* NT100x has a 8-bit register space */
errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
@@ -1178,7 +1179,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
* Here comes the stuff for radio on usbvision based devices
*
*/
-static int usbvision_radio_open(struct inode *inode, struct file *file)
+static int usbvision_radio_open(struct file *file)
{
struct usb_usbvision *usbvision = video_drvdata(file);
int errCode = 0;
@@ -1228,7 +1229,7 @@ out:
}
-static int usbvision_radio_close(struct inode *inode, struct file *file)
+static int usbvision_radio_close(struct file *file)
{
struct usb_usbvision *usbvision = video_drvdata(file);
int errCode = 0;
@@ -1266,26 +1267,26 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
* Here comes the stuff for vbi on usbvision based devices
*
*/
-static int usbvision_vbi_open(struct inode *inode, struct file *file)
+static int usbvision_vbi_open(struct file *file)
{
/* TODO */
return -ENODEV;
}
-static int usbvision_vbi_close(struct inode *inode, struct file *file)
+static int usbvision_vbi_close(struct file *file)
{
/* TODO */
return -ENODEV;
}
-static int usbvision_do_vbi_ioctl(struct file *file,
+static long usbvision_do_vbi_ioctl(struct file *file,
unsigned int cmd, void *arg)
{
/* TODO */
return -ENOIOCTLCMD;
}
-static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
+static long usbvision_vbi_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, usbvision_do_vbi_ioctl);
@@ -1297,16 +1298,14 @@ static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
//
// Video template
-static const struct file_operations usbvision_fops = {
+static const struct v4l2_file_operations usbvision_fops = {
.owner = THIS_MODULE,
.open = usbvision_v4l2_open,
.release = usbvision_v4l2_close,
.read = usbvision_v4l2_read,
.mmap = usbvision_v4l2_mmap,
.ioctl = video_ioctl2,
- .llseek = no_llseek,
/* .poll = video_poll, */
- .compat_ioctl = v4l_compat_ioctl32,
};
static const struct v4l2_ioctl_ops usbvision_ioctl_ops = {
@@ -1355,13 +1354,11 @@ static struct video_device usbvision_video_template = {
// Radio template
-static const struct file_operations usbvision_radio_fops = {
+static const struct v4l2_file_operations usbvision_radio_fops = {
.owner = THIS_MODULE,
.open = usbvision_radio_open,
.release = usbvision_radio_close,
.ioctl = video_ioctl2,
- .llseek = no_llseek,
- .compat_ioctl = v4l_compat_ioctl32,
};
static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = {
@@ -1392,13 +1389,11 @@ static struct video_device usbvision_radio_template = {
};
// vbi template
-static const struct file_operations usbvision_vbi_fops = {
+static const struct v4l2_file_operations usbvision_vbi_fops = {
.owner = THIS_MODULE,
.open = usbvision_vbi_open,
.release = usbvision_vbi_close,
.ioctl = usbvision_vbi_ioctl,
- .llseek = no_llseek,
- .compat_ioctl = v4l_compat_ioctl32,
};
static struct video_device usbvision_vbi_template=
@@ -1679,7 +1674,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
interface = &dev->actconfig->interface[ifnum]->altsetting[0];
}
endpoint = &interface->endpoint[1].desc;
- if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+ if (usb_endpoint_type(endpoint) !=
USB_ENDPOINT_XFER_ISOC) {
err("%s: interface %d. has non-ISO endpoint!",
__func__, ifnum);
@@ -1687,8 +1682,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
__func__, endpoint->bmAttributes);
return -ENODEV;
}
- if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
- USB_DIR_OUT) {
+ if (usb_endpoint_dir_out(endpoint)) {
err("%s: interface %d. has ISO OUT endpoint!",
__func__, ifnum);
return -ENODEV;
diff --git a/linux/drivers/media/video/uvc/uvc_ctrl.c b/linux/drivers/media/video/uvc/uvc_ctrl.c
index 9de8a1db5..e9a75b064 100644
--- a/linux/drivers/media/video/uvc/uvc_ctrl.c
+++ b/linux/drivers/media/video/uvc/uvc_ctrl.c
@@ -329,6 +329,31 @@ static struct uvc_menu_info exposure_auto_controls[] = {
{ 8, "Aperture Priority Mode" },
};
+static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
+ __u8 query, const __u8 *data)
+{
+ __s8 zoom = (__s8)data[0];
+
+ switch (query) {
+ case GET_CUR:
+ return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
+
+ case GET_MIN:
+ case GET_MAX:
+ case GET_RES:
+ case GET_DEF:
+ default:
+ return data[2];
+ }
+}
+
+static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
+ __s32 value, __u8 *data)
+{
+ data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
+ data[2] = min(abs(value), 0xff);
+}
+
static struct uvc_control_mapping uvc_ctrl_mappings[] = {
{
.id = V4L2_CID_BRIGHTNESS,
@@ -534,6 +559,38 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
.data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
},
+ {
+ .id = V4L2_CID_ZOOM_ABSOLUTE,
+ .name = "Zoom, Absolute",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_ZOOM_ABSOLUTE_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_ZOOM_CONTINUOUS,
+ .name = "Zoom, Continuous",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_ZOOM_RELATIVE_CONTROL,
+ .size = 0,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ .get = uvc_ctrl_get_zoom,
+ .set = uvc_ctrl_set_zoom,
+ },
+ {
+ .id = V4L2_CID_PRIVACY,
+ .name = "Privacy",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_PRIVACY_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
};
/* ------------------------------------------------------------------------
@@ -545,18 +602,23 @@ static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
return ctrl->data + id * ctrl->info->size;
}
-static inline int uvc_get_bit(const __u8 *data, int bit)
+static inline int uvc_test_bit(const __u8 *data, int bit)
{
return (data[bit >> 3] >> (bit & 7)) & 1;
}
+static inline void uvc_clear_bit(__u8 *data, int bit)
+{
+ data[bit >> 3] &= ~(1 << (bit & 7));
+}
+
/* Extract the bit string specified by mapping->offset and mapping->size
* from the little-endian data stored at 'data' and return the result as
* a signed 32bit integer. Sign extension will be performed if the mapping
* references a signed data type.
*/
-static __s32 uvc_get_le_value(const __u8 *data,
- struct uvc_control_mapping *mapping)
+static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
+ __u8 query, const __u8 *data)
{
int bits = mapping->size;
int offset = mapping->offset;
@@ -585,8 +647,8 @@ static __s32 uvc_get_le_value(const __u8 *data,
/* Set the bit string specified by mapping->offset and mapping->size
* in the little-endian data stored at 'data' to the value 'value'.
*/
-static void uvc_set_le_value(__s32 value, __u8 *data,
- struct uvc_control_mapping *mapping)
+static void uvc_set_le_value(struct uvc_control_mapping *mapping,
+ __s32 value, __u8 *data)
{
int bits = mapping->size;
int offset = mapping->offset;
@@ -738,7 +800,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
video->dev->intfnum, ctrl->info->selector,
data, ctrl->info->size)) < 0)
goto out;
- v4l2_ctrl->default_value = uvc_get_le_value(data, mapping);
+ v4l2_ctrl->default_value = mapping->get(mapping, GET_DEF, data);
}
switch (mapping->v4l2_type) {
@@ -774,21 +836,21 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
video->dev->intfnum, ctrl->info->selector,
data, ctrl->info->size)) < 0)
goto out;
- v4l2_ctrl->minimum = uvc_get_le_value(data, mapping);
+ v4l2_ctrl->minimum = mapping->get(mapping, GET_MIN, data);
}
if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
video->dev->intfnum, ctrl->info->selector,
data, ctrl->info->size)) < 0)
goto out;
- v4l2_ctrl->maximum = uvc_get_le_value(data, mapping);
+ v4l2_ctrl->maximum = mapping->get(mapping, GET_MAX, data);
}
if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
video->dev->intfnum, ctrl->info->selector,
data, ctrl->info->size)) < 0)
goto out;
- v4l2_ctrl->step = uvc_get_le_value(data, mapping);
+ v4l2_ctrl->step = mapping->get(mapping, GET_RES, data);
}
ret = 0;
@@ -925,8 +987,8 @@ int uvc_ctrl_get(struct uvc_video_device *video,
ctrl->loaded = 1;
}
- xctrl->value = uvc_get_le_value(
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+ xctrl->value = mapping->get(mapping, GET_CUR,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
menu = mapping->menu_info;
@@ -982,8 +1044,8 @@ int uvc_ctrl_set(struct uvc_video_device *video,
ctrl->info->size);
}
- uvc_set_le_value(value,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+ mapping->set(mapping, value,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
ctrl->dirty = 1;
ctrl->modified = 1;
@@ -1259,6 +1321,11 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
struct uvc_control_mapping *map;
int ret = -EINVAL;
+ if (mapping->get == NULL)
+ mapping->get = uvc_get_le_value;
+ if (mapping->set == NULL)
+ mapping->set = uvc_set_le_value;
+
if (mapping->id & ~V4L2_CTRL_ID_MASK) {
uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s' with "
"invalid control id 0x%08x\n", mapping->name,
@@ -1308,6 +1375,51 @@ end:
}
/*
+ * Prune an entity of its bogus controls. This currently includes processing
+ * unit auto controls for which no corresponding manual control is available.
+ * Such auto controls make little sense if any, and are known to crash at
+ * least the SiGma Micro webcam.
+ */
+static void
+uvc_ctrl_prune_entity(struct uvc_entity *entity)
+{
+ static const struct {
+ u8 idx_manual;
+ u8 idx_auto;
+ } blacklist[] = {
+ { 2, 11 }, /* Hue */
+ { 6, 12 }, /* White Balance Temperature */
+ { 7, 13 }, /* White Balance Component */
+ };
+
+ u8 *controls;
+ unsigned int size;
+ unsigned int i;
+
+ if (UVC_ENTITY_TYPE(entity) != VC_PROCESSING_UNIT)
+ return;
+
+ controls = entity->processing.bmControls;
+ size = entity->processing.bControlSize;
+
+ for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
+ if (blacklist[i].idx_auto >= 8 * size ||
+ blacklist[i].idx_manual >= 8 * size)
+ continue;
+
+ if (!uvc_test_bit(controls, blacklist[i].idx_auto) ||
+ uvc_test_bit(controls, blacklist[i].idx_manual))
+ continue;
+
+ uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no "
+ "matching manual control, removing it.\n", entity->id,
+ blacklist[i].idx_auto);
+
+ uvc_clear_bit(controls, blacklist[i].idx_auto);
+ }
+}
+
+/*
* Initialize device controls.
*/
int uvc_ctrl_init_device(struct uvc_device *dev)
@@ -1333,6 +1445,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
bControlSize = entity->camera.bControlSize;
}
+ if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS)
+ uvc_ctrl_prune_entity(entity);
+
for (i = 0; i < bControlSize; ++i)
ncontrols += hweight8(bmControls[i]);
@@ -1347,7 +1462,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
ctrl = entity->controls;
for (i = 0; i < bControlSize * 8; ++i) {
- if (uvc_get_bit(bmControls, i) == 0)
+ if (uvc_test_bit(bmControls, i) == 0)
continue;
ctrl->entity = entity;
diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c
index 0a0ef6611..540f57baa 100644
--- a/linux/drivers/media/video/uvc/uvc_driver.c
+++ b/linux/drivers/media/video/uvc/uvc_driver.c
@@ -12,8 +12,8 @@
*/
/*
- * This driver aims to support video input devices compliant with the 'USB
- * Video Class' specification.
+ * This driver aims to support video input and ouput devices compliant with the
+ * 'USB Video Class' specification.
*
* The driver doesn't support the deprecated v4l1 interface. It implements the
* mmap capture method only, and doesn't do any image format conversion in
@@ -44,6 +44,7 @@
#define DRIVER_VERSION "v0.1.0"
#endif
+unsigned int uvc_no_drop_param;
static unsigned int uvc_quirks_param;
unsigned int uvc_trace_param;
@@ -608,46 +609,55 @@ static int uvc_parse_streaming(struct uvc_device *dev,
}
/* Parse the header descriptor. */
- if (buffer[2] == VS_OUTPUT_HEADER) {
+ switch (buffer[2]) {
+ case VS_OUTPUT_HEADER:
+ streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ size = 9;
+ break;
+
+ case VS_INPUT_HEADER:
+ streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ size = 13;
+ break;
+
+ default:
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
- "%d OUTPUT HEADER descriptor is not supported.\n",
- dev->udev->devnum, alts->desc.bInterfaceNumber);
+ "%d HEADER descriptor not found.\n", dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
goto error;
- } else if (buffer[2] == VS_INPUT_HEADER) {
- p = buflen >= 5 ? buffer[3] : 0;
- n = buflen >= 12 ? buffer[12] : 0;
+ }
- if (buflen < 13 + p*n || buffer[2] != VS_INPUT_HEADER) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d INPUT HEADER descriptor is "
- "invalid.\n", dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- goto error;
- }
+ p = buflen >= 4 ? buffer[3] : 0;
+ n = buflen >= size ? buffer[size-1] : 0;
+
+ if (buflen < size + p*n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d HEADER descriptor is invalid.\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber);
+ goto error;
+ }
- streaming->header.bNumFormats = p;
- streaming->header.bEndpointAddress = buffer[6];
+ streaming->header.bNumFormats = p;
+ streaming->header.bEndpointAddress = buffer[6];
+ if (buffer[2] == VS_INPUT_HEADER) {
streaming->header.bmInfo = buffer[7];
streaming->header.bTerminalLink = buffer[8];
streaming->header.bStillCaptureMethod = buffer[9];
streaming->header.bTriggerSupport = buffer[10];
streaming->header.bTriggerUsage = buffer[11];
- streaming->header.bControlSize = n;
-
- streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
- if (streaming->header.bmaControls == NULL) {
- ret = -ENOMEM;
- goto error;
- }
-
- memcpy(streaming->header.bmaControls, &buffer[13], p*n);
} else {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
- "%d HEADER descriptor not found.\n", dev->udev->devnum,
- alts->desc.bInterfaceNumber);
+ streaming->header.bTerminalLink = buffer[7];
+ }
+ streaming->header.bControlSize = n;
+
+ streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
+ if (streaming->header.bmaControls == NULL) {
+ ret = -ENOMEM;
goto error;
}
+ memcpy(streaming->header.bmaControls, &buffer[size], p*n);
+
buflen -= buffer[0];
buffer += buffer[0];
@@ -1146,8 +1156,13 @@ next_descriptor:
buffer += buffer[0];
}
- /* Check if the optional status endpoint is present. */
- if (alts->desc.bNumEndpoints == 1) {
+ /* Check if the optional status endpoint is present. Built-in iSight
+ * webcams have an interrupt endpoint but spit proprietary data that
+ * don't conform to the UVC status endpoint messages. Don't try to
+ * handle the interrupt endpoint for those cameras.
+ */
+ if (alts->desc.bNumEndpoints == 1 &&
+ !(dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)) {
struct usb_host_endpoint *ep = &alts->endpoint[0];
struct usb_endpoint_descriptor *desc = &ep->desc;
@@ -1252,6 +1267,26 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
list_add_tail(&entity->chain, &video->iterms);
break;
+ case TT_STREAMING:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- IT %d\n", entity->id);
+
+ if (!UVC_ENTITY_IS_ITERM(entity)) {
+ uvc_trace(UVC_TRACE_DESCR, "Unsupported input "
+ "terminal %u.\n", entity->id);
+ return -1;
+ }
+
+ if (video->sterm != NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "Found multiple streaming "
+ "entities in chain.\n");
+ return -1;
+ }
+
+ list_add_tail(&entity->chain, &video->iterms);
+ video->sterm = entity;
+ break;
+
default:
uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type "
"0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));
@@ -1362,6 +1397,10 @@ static int uvc_scan_chain(struct uvc_video_device *video)
entity = video->oterm;
uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
+
+ if (UVC_ENTITY_TYPE(entity) == TT_STREAMING)
+ video->sterm = entity;
+
id = entity->output.bSourceID;
while (id != 0) {
prev = entity;
@@ -1390,8 +1429,11 @@ static int uvc_scan_chain(struct uvc_video_device *video)
return id;
}
- /* Initialize the video buffers queue. */
- uvc_queue_init(&video->queue);
+ if (video->sterm == NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "No streaming entity found in "
+ "chain.\n");
+ return -1;
+ }
return 0;
}
@@ -1402,7 +1444,8 @@ static int uvc_scan_chain(struct uvc_video_device *video)
* The driver currently supports a single video device per control interface
* only. The terminal and units must match the following structure:
*
- * ITT_CAMERA -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING
+ * ITT_* -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING
+ * TT_STREAMING -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> OTT_*
*
* The Extension Units, if present, must have a single input pin. The
* Processing Unit and Extension Units can be in any order. Additional
@@ -1419,7 +1462,7 @@ static int uvc_register_video(struct uvc_device *dev)
list_for_each_entry(term, &dev->entities, list) {
struct uvc_streaming *streaming;
- if (UVC_ENTITY_TYPE(term) != TT_STREAMING)
+ if (!UVC_ENTITY_IS_TERM(term) || !UVC_ENTITY_IS_OTERM(term))
continue;
memset(&dev->video, 0, sizeof dev->video);
@@ -1432,7 +1475,8 @@ static int uvc_register_video(struct uvc_device *dev)
continue;
list_for_each_entry(streaming, &dev->streaming, list) {
- if (streaming->header.bTerminalLink == term->id) {
+ if (streaming->header.bTerminalLink ==
+ dev->video.sterm->id) {
dev->video.streaming = streaming;
found = 1;
break;
@@ -1458,6 +1502,9 @@ static int uvc_register_video(struct uvc_device *dev)
printk(" -> %d).\n", dev->video.oterm->id);
}
+ /* Initialize the video buffers queue. */
+ uvc_queue_init(&dev->video.queue, dev->video.streaming->type);
+
/* Initialize the streaming interface with default streaming
* parameters.
*/
@@ -1895,7 +1942,8 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_IGNORE_SELECTOR_UNIT},
+ | UVC_QUIRK_IGNORE_SELECTOR_UNIT
+ | UVC_QUIRK_PRUNE_CONTROLS },
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
{}
@@ -1945,6 +1993,8 @@ static void __exit uvc_cleanup(void)
module_init(uvc_init);
module_exit(uvc_cleanup);
+module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(quirks, "Forced device quirks");
module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
diff --git a/linux/drivers/media/video/uvc/uvc_queue.c b/linux/drivers/media/video/uvc/uvc_queue.c
index 5646a6a32..42546342e 100644
--- a/linux/drivers/media/video/uvc/uvc_queue.c
+++ b/linux/drivers/media/video/uvc/uvc_queue.c
@@ -79,12 +79,13 @@
*
*/
-void uvc_queue_init(struct uvc_video_queue *queue)
+void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
{
mutex_init(&queue->mutex);
spin_lock_init(&queue->irqlock);
INIT_LIST_HEAD(&queue->mainqueue);
INIT_LIST_HEAD(&queue->irqqueue);
+ queue->type = type;
}
/*
@@ -132,7 +133,7 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
queue->buffer[i].buf.index = i;
queue->buffer[i].buf.m.offset = i * bufsize;
queue->buffer[i].buf.length = buflength;
- queue->buffer[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ queue->buffer[i].buf.type = queue->type;
queue->buffer[i].buf.sequence = 0;
queue->buffer[i].buf.field = V4L2_FIELD_NONE;
queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
@@ -226,7 +227,7 @@ int uvc_queue_buffer(struct uvc_video_queue *queue,
uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
- if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ if (v4l2_buf->type != queue->type ||
v4l2_buf->memory != V4L2_MEMORY_MMAP) {
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
"and/or memory (%u).\n", v4l2_buf->type,
@@ -249,6 +250,13 @@ int uvc_queue_buffer(struct uvc_video_queue *queue,
goto done;
}
+ if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ v4l2_buf->bytesused > buf->buf.length) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
spin_lock_irqsave(&queue->irqlock, flags);
if (queue->flags & UVC_QUEUE_DISCONNECTED) {
spin_unlock_irqrestore(&queue->irqlock, flags);
@@ -256,7 +264,11 @@ int uvc_queue_buffer(struct uvc_video_queue *queue,
goto done;
}
buf->state = UVC_BUF_STATE_QUEUED;
- buf->buf.bytesused = 0;
+ if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ buf->buf.bytesused = 0;
+ else
+ buf->buf.bytesused = v4l2_buf->bytesused;
+
list_add_tail(&buf->stream, &queue->mainqueue);
list_add_tail(&buf->queue, &queue->irqqueue);
spin_unlock_irqrestore(&queue->irqlock, flags);
@@ -289,7 +301,7 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue,
struct uvc_buffer *buf;
int ret = 0;
- if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ if (v4l2_buf->type != queue->type ||
v4l2_buf->memory != V4L2_MEMORY_MMAP) {
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
"and/or memory (%u).\n", v4l2_buf->type,
@@ -397,6 +409,7 @@ int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
}
queue->sequence = 0;
queue->flags |= UVC_QUEUE_STREAMING;
+ queue->buf_used = 0;
} else {
uvc_queue_cancel(queue, 0);
INIT_LIST_HEAD(&queue->mainqueue);
diff --git a/linux/drivers/media/video/uvc/uvc_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c
index 95eb6f3ad..2f958379d 100644
--- a/linux/drivers/media/video/uvc/uvc_v4l2.c
+++ b/linux/drivers/media/video/uvc/uvc_v4l2.c
@@ -110,7 +110,7 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
int ret = 0;
__u8 *fcc;
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fmt->type != video->streaming->type)
return -EINVAL;
fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
@@ -216,7 +216,7 @@ static int uvc_v4l2_get_format(struct uvc_video_device *video,
struct uvc_format *format = video->streaming->cur_format;
struct uvc_frame *frame = video->streaming->cur_frame;
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fmt->type != video->streaming->type)
return -EINVAL;
if (format == NULL || frame == NULL)
@@ -242,7 +242,7 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video,
struct uvc_frame *frame;
int ret;
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fmt->type != video->streaming->type)
return -EINVAL;
if (uvc_queue_streaming(&video->queue))
@@ -264,7 +264,7 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
{
uint32_t numerator, denominator;
- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (parm->type != video->streaming->type)
return -EINVAL;
numerator = video->streaming->ctrl.dwFrameInterval;
@@ -272,13 +272,21 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
uvc_simplify_fraction(&numerator, &denominator, 8, 333);
memset(parm, 0, sizeof *parm);
- parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- parm->parm.capture.capturemode = 0;
- parm->parm.capture.timeperframe.numerator = numerator;
- parm->parm.capture.timeperframe.denominator = denominator;
- parm->parm.capture.extendedmode = 0;
- parm->parm.capture.readbuffers = 0;
+ parm->type = video->streaming->type;
+
+ if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ parm->parm.capture.capturemode = 0;
+ parm->parm.capture.timeperframe.numerator = numerator;
+ parm->parm.capture.timeperframe.denominator = denominator;
+ parm->parm.capture.extendedmode = 0;
+ parm->parm.capture.readbuffers = 0;
+ } else {
+ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+ parm->parm.output.outputmode = 0;
+ parm->parm.output.timeperframe.numerator = numerator;
+ parm->parm.output.timeperframe.denominator = denominator;
+ }
return 0;
}
@@ -288,24 +296,27 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
{
struct uvc_frame *frame = video->streaming->cur_frame;
struct uvc_streaming_control probe;
+ struct v4l2_fract timeperframe;
uint32_t interval;
int ret;
- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (parm->type != video->streaming->type)
return -EINVAL;
if (uvc_queue_streaming(&video->queue))
return -EBUSY;
+ if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ timeperframe = parm->parm.capture.timeperframe;
+ else
+ timeperframe = parm->parm.output.timeperframe;
+
memcpy(&probe, &video->streaming->ctrl, sizeof probe);
- interval = uvc_fraction_to_interval(
- parm->parm.capture.timeperframe.numerator,
- parm->parm.capture.timeperframe.denominator);
+ interval = uvc_fraction_to_interval(timeperframe.numerator,
+ timeperframe.denominator);
uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
- parm->parm.capture.timeperframe.numerator,
- parm->parm.capture.timeperframe.denominator,
- interval);
+ timeperframe.numerator, timeperframe.denominator, interval);
probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
/* Probe the device with the new settings. */
@@ -315,11 +326,15 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
memcpy(&video->streaming->ctrl, &probe, sizeof probe);
/* Return the actual frame period. */
- parm->parm.capture.timeperframe.numerator = probe.dwFrameInterval;
- parm->parm.capture.timeperframe.denominator = 10000000;
- uvc_simplify_fraction(&parm->parm.capture.timeperframe.numerator,
- &parm->parm.capture.timeperframe.denominator,
- 8, 333);
+ timeperframe.numerator = probe.dwFrameInterval;
+ timeperframe.denominator = 10000000;
+ uvc_simplify_fraction(&timeperframe.numerator,
+ &timeperframe.denominator, 8, 333);
+
+ if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ parm->parm.capture.timeperframe = timeperframe;
+ else
+ parm->parm.output.timeperframe = timeperframe;
return 0;
}
@@ -391,7 +406,7 @@ static int uvc_has_privileges(struct uvc_fh *handle)
* V4L2 file operations
*/
-static int uvc_v4l2_open(struct inode *inode, struct file *file)
+static int uvc_v4l2_open(struct file *file)
{
struct uvc_video_device *video;
struct uvc_fh *handle;
@@ -433,7 +448,7 @@ done:
return ret;
}
-static int uvc_v4l2_release(struct inode *inode, struct file *file)
+static int uvc_v4l2_release(struct file *file)
{
struct uvc_video_device *video = video_drvdata(file);
struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
@@ -463,12 +478,12 @@ static int uvc_v4l2_release(struct inode *inode, struct file *file)
return 0;
}
-static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct uvc_video_device *video = video_get_drvdata(vdev);
struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
- int ret = 0;
+ long ret = 0;
switch (cmd) {
/* Query capabilities */
@@ -482,8 +497,12 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
strncpy(cap->bus_info, video->dev->udev->bus->bus_name,
sizeof cap->bus_info);
cap->version = DRIVER_VERSION_NUMBER;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
- | V4L2_CAP_STREAMING;
+ if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_STREAMING;
+ else
+ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT
+ | V4L2_CAP_STREAMING;
break;
}
@@ -661,7 +680,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_fmtdesc *fmt = arg;
struct uvc_format *format;
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ if (fmt->type != video->streaming->type ||
fmt->index >= video->streaming->nformats)
return -EINVAL;
@@ -800,7 +819,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_cropcap *ccap = arg;
struct uvc_frame *frame = video->streaming->cur_frame;
- if (ccap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (ccap->type != video->streaming->type)
return -EINVAL;
ccap->bounds.left = 0;
@@ -826,7 +845,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
unsigned int bufsize =
video->streaming->ctrl.dwMaxVideoFrameSize;
- if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ if (rb->type != video->streaming->type ||
rb->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
@@ -846,7 +865,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct v4l2_buffer *buf = arg;
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (buf->type != video->streaming->type)
return -EINVAL;
if (!uvc_has_privileges(handle))
@@ -872,7 +891,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
int *type = arg;
- if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (*type != video->streaming->type)
return -EINVAL;
if (!uvc_has_privileges(handle))
@@ -887,7 +906,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
int *type = arg;
- if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (*type != video->streaming->type)
return -EINVAL;
if (!uvc_has_privileges(handle))
@@ -920,7 +939,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- info = kmalloc(sizeof *info, GFP_KERNEL);
+ info = kzalloc(sizeof *info, GFP_KERNEL);
if (info == NULL)
return -ENOMEM;
@@ -947,7 +966,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- map = kmalloc(sizeof *map, GFP_KERNEL);
+ map = kzalloc(sizeof *map, GFP_KERNEL);
if (map == NULL)
return -ENOMEM;
@@ -983,7 +1002,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return ret;
}
-static int uvc_v4l2_ioctl(struct inode *inode, struct file *file,
+static long uvc_v4l2_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
if (uvc_trace_param & UVC_TRACE_IOCTL) {
@@ -1084,13 +1103,11 @@ static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
return uvc_queue_poll(&video->queue, file, wait);
}
-struct file_operations uvc_fops = {
+const struct v4l2_file_operations uvc_fops = {
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
.release = uvc_v4l2_release,
.ioctl = uvc_v4l2_ioctl,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
.read = uvc_v4l2_read,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c
index 3be776a47..e6f7c3178 100644
--- a/linux/drivers/media/video/uvc/uvc_video.c
+++ b/linux/drivers/media/video/uvc/uvc_video.c
@@ -368,7 +368,7 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
/* Synchronize to the input stream by waiting for the FID bit to be
* toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
- * queue->last_fid is initialized to -1, so the first isochronous
+ * video->last_fid is initialized to -1, so the first isochronous
* frame will always be in sync.
*
* If the device doesn't toggle the FID bit, invert video->last_fid
@@ -395,7 +395,7 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
* last payload can be lost anyway). We thus must check if the FID has
* been toggled.
*
- * queue->last_fid is initialized to -1, so the first isochronous
+ * video->last_fid is initialized to -1, so the first isochronous
* frame will never trigger an end of frame detection.
*
* Empty buffers (bytesused == 0) don't trigger end of frame detection
@@ -453,6 +453,34 @@ static void uvc_video_decode_end(struct uvc_video_device *video,
}
}
+static int uvc_video_encode_header(struct uvc_video_device *video,
+ struct uvc_buffer *buf, __u8 *data, int len)
+{
+ data[0] = 2; /* Header length */
+ data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF
+ | (video->last_fid & UVC_STREAM_FID);
+ return 2;
+}
+
+static int uvc_video_encode_data(struct uvc_video_device *video,
+ struct uvc_buffer *buf, __u8 *data, int len)
+{
+ struct uvc_video_queue *queue = &video->queue;
+ unsigned int nbytes;
+ void *mem;
+
+ /* Copy video data to the URB buffer. */
+ mem = queue->mem + buf->buf.m.offset + queue->buf_used;
+ nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
+ nbytes = min(video->bulk.max_payload_size - video->bulk.payload_size,
+ nbytes);
+ memcpy(data, mem, nbytes);
+
+ queue->buf_used += nbytes;
+
+ return nbytes;
+}
+
/* ------------------------------------------------------------------------
* URB handling
*/
@@ -512,7 +540,7 @@ static void uvc_video_decode_bulk(struct urb *urb,
/* If the URB is the first of its payload, decode and save the
* header.
*/
- if (video->bulk.header_size == 0) {
+ if (video->bulk.header_size == 0 && !video->bulk.skip_payload) {
do {
ret = uvc_video_decode_start(video, buf, mem, len);
if (ret == -EAGAIN)
@@ -522,14 +550,13 @@ static void uvc_video_decode_bulk(struct urb *urb,
/* If an error occured skip the rest of the payload. */
if (ret < 0 || buf == NULL) {
video->bulk.skip_payload = 1;
- return;
- }
-
- video->bulk.header_size = ret;
- memcpy(video->bulk.header, mem, video->bulk.header_size);
+ } else {
+ memcpy(video->bulk.header, mem, ret);
+ video->bulk.header_size = ret;
- mem += ret;
- len -= ret;
+ mem += ret;
+ len -= ret;
+ }
}
/* The buffer queue might have been cancelled while a bulk transfer
@@ -560,6 +587,48 @@ static void uvc_video_decode_bulk(struct urb *urb,
}
}
+static void uvc_video_encode_bulk(struct urb *urb,
+ struct uvc_video_device *video, struct uvc_buffer *buf)
+{
+ u8 *mem = urb->transfer_buffer;
+ int len = video->urb_size, ret;
+
+ if (buf == NULL) {
+ urb->transfer_buffer_length = 0;
+ return;
+ }
+
+ /* If the URB is the first of its payload, add the header. */
+ if (video->bulk.header_size == 0) {
+ ret = uvc_video_encode_header(video, buf, mem, len);
+ video->bulk.header_size = ret;
+ video->bulk.payload_size += ret;
+ mem += ret;
+ len -= ret;
+ }
+
+ /* Process video data. */
+ ret = uvc_video_encode_data(video, buf, mem, len);
+
+ video->bulk.payload_size += ret;
+ len -= ret;
+
+ if (buf->buf.bytesused == video->queue.buf_used ||
+ video->bulk.payload_size == video->bulk.max_payload_size) {
+ if (buf->buf.bytesused == video->queue.buf_used) {
+ video->queue.buf_used = 0;
+ buf->state = UVC_BUF_STATE_DONE;
+ uvc_queue_next_buffer(&video->queue, buf);
+ video->last_fid ^= UVC_STREAM_FID;
+ }
+
+ video->bulk.header_size = 0;
+ video->bulk.payload_size = 0;
+ }
+
+ urb->transfer_buffer_length = video->urb_size - len;
+}
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
static void uvc_video_complete(struct urb *urb, struct pt_regs *regs)
#else
@@ -761,7 +830,15 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
if (uvc_alloc_urb_buffers(video, size) < 0)
return -ENOMEM;
- pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress);
+ if (usb_endpoint_dir_in(&ep->desc))
+ pipe = usb_rcvbulkpipe(video->dev->udev,
+ ep->desc.bEndpointAddress);
+ else
+ pipe = usb_sndbulkpipe(video->dev->udev,
+ ep->desc.bEndpointAddress);
+
+ if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ size = 0;
for (i = 0; i < UVC_URBS; ++i) {
urb = usb_alloc_urb(0, gfp_flags);
@@ -982,12 +1059,22 @@ int uvc_video_init(struct uvc_video_device *video)
atomic_set(&video->active, 0);
/* Select the video decoding function */
- if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
- video->decode = uvc_video_decode_isight;
- else if (video->streaming->intf->num_altsetting > 1)
- video->decode = uvc_video_decode_isoc;
- else
- video->decode = uvc_video_decode_bulk;
+ if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
+ video->decode = uvc_video_decode_isight;
+ else if (video->streaming->intf->num_altsetting > 1)
+ video->decode = uvc_video_decode_isoc;
+ else
+ video->decode = uvc_video_decode_bulk;
+ } else {
+ if (video->streaming->intf->num_altsetting == 1)
+ video->decode = uvc_video_encode_bulk;
+ else {
+ uvc_printk(KERN_INFO, "Isochronous endpoints are not "
+ "supported for video output devices.\n");
+ return -EINVAL;
+ }
+ }
return 0;
}
@@ -1007,7 +1094,8 @@ int uvc_video_enable(struct uvc_video_device *video, int enable)
return 0;
}
- if (video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED)
+ if ((video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) ||
+ uvc_no_drop_param)
video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
else
video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h
index f95040380..7936d39c9 100644
--- a/linux/drivers/media/video/uvc/uvcvideo.h
+++ b/linux/drivers/media/video/uvc/uvcvideo.h
@@ -4,8 +4,6 @@
#include <linux/kernel.h>
#include <linux/videodev2.h>
-#include "compat.h"
-
/*
* Dynamic controls
*/
@@ -69,6 +67,7 @@ struct uvc_xu_control {
#ifdef __KERNEL__
#include <linux/poll.h>
+#include "compat.h"
/* --------------------------------------------------------------------------
* UVC constants
@@ -317,6 +316,7 @@ struct uvc_xu_control {
#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008
#define UVC_QUIRK_STREAM_NO_FID 0x00000010
#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
+#define UVC_QUIRK_PRUNE_CONTROLS 0x00000040
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
@@ -384,6 +384,11 @@ struct uvc_control_mapping {
struct uvc_menu_info *menu_info;
__u32 menu_count;
+
+ __s32 (*get) (struct uvc_control_mapping *mapping, __u8 query,
+ const __u8 *data);
+ void (*set) (struct uvc_control_mapping *mapping, __s32 value,
+ __u8 *data);
};
struct uvc_control {
@@ -524,6 +529,7 @@ struct uvc_streaming {
__u16 maxpsize;
struct uvc_streaming_header header;
+ enum v4l2_buf_type type;
unsigned int nformats;
struct uvc_format *format;
@@ -559,12 +565,15 @@ struct uvc_buffer {
#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2)
struct uvc_video_queue {
+ enum v4l2_buf_type type;
+
void *mem;
unsigned int flags;
__u32 sequence;
unsigned int count;
unsigned int buf_size;
+ unsigned int buf_used;
struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
struct mutex mutex; /* protects buffers and mainqueue */
spinlock_t irqlock; /* protects irqqueue */
@@ -579,8 +588,9 @@ struct uvc_video_device {
atomic_t active;
unsigned int frozen : 1;
- struct list_head iterms;
- struct uvc_entity *oterm;
+ struct list_head iterms; /* Input terminals */
+ struct uvc_entity *oterm; /* Output terminal */
+ struct uvc_entity *sterm; /* USB streaming terminal */
struct uvc_entity *processing;
struct uvc_entity *selector;
struct list_head extensions;
@@ -684,6 +694,7 @@ struct uvc_driver {
#define UVC_WARN_MINMAX 0
#define UVC_WARN_PROBE_DEF 1
+extern unsigned int uvc_no_drop_param;
extern unsigned int uvc_trace_param;
#define uvc_trace(flag, msg...) \
@@ -720,7 +731,8 @@ extern struct uvc_driver uvc_driver;
extern void uvc_delete(struct kref *kref);
/* Video buffers queue management. */
-extern void uvc_queue_init(struct uvc_video_queue *queue);
+extern void uvc_queue_init(struct uvc_video_queue *queue,
+ enum v4l2_buf_type type);
extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
unsigned int nbuffers, unsigned int buflength);
extern int uvc_free_buffers(struct uvc_video_queue *queue);
@@ -742,7 +754,7 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
}
/* V4L2 interface */
-extern struct file_operations uvc_fops;
+extern const struct v4l2_file_operations uvc_fops;
/* Video */
extern int uvc_video_init(struct uvc_video_device *video);
diff --git a/linux/drivers/media/video/v4l1-compat.c b/linux/drivers/media/video/v4l1-compat.c
index ff1d3eb68..14b559b16 100644
--- a/linux/drivers/media/video/v4l1-compat.c
+++ b/linux/drivers/media/video/v4l1-compat.c
@@ -268,12 +268,12 @@ done:
/* ----------------------------------------------------------------- */
-static noinline int v4l1_compat_get_capabilities(
+static noinline long v4l1_compat_get_capabilities(
struct video_capability *cap,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_framebuffer fbuf;
struct v4l2_capability *cap2;
@@ -287,13 +287,13 @@ static noinline int v4l1_compat_get_capabilities(
err = drv(file, VIDIOC_QUERYCAP, cap2);
if (err < 0) {
- dprintk("VIDIOCGCAP / VIDIOC_QUERYCAP: %d\n", err);
+ dprintk("VIDIOCGCAP / VIDIOC_QUERYCAP: %ld\n", err);
goto done;
}
if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) {
err = drv(file, VIDIOC_G_FBUF, &fbuf);
if (err < 0) {
- dprintk("VIDIOCGCAP / VIDIOC_G_FBUF: %d\n", err);
+ dprintk("VIDIOCGCAP / VIDIOC_G_FBUF: %ld\n", err);
memset(&fbuf, 0, sizeof(fbuf));
}
err = 0;
@@ -325,12 +325,12 @@ done:
return err;
}
-static noinline int v4l1_compat_get_frame_buffer(
+static noinline long v4l1_compat_get_frame_buffer(
struct video_buffer *buffer,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_framebuffer fbuf;
memset(buffer, 0, sizeof(*buffer));
@@ -338,7 +338,7 @@ static noinline int v4l1_compat_get_frame_buffer(
err = drv(file, VIDIOC_G_FBUF, &fbuf);
if (err < 0) {
- dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %d\n", err);
+ dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %ld\n", err);
goto done;
}
buffer->base = fbuf.base;
@@ -379,12 +379,12 @@ done:
return err;
}
-static noinline int v4l1_compat_set_frame_buffer(
+static noinline long v4l1_compat_set_frame_buffer(
struct video_buffer *buffer,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_framebuffer fbuf;
memset(&fbuf, 0, sizeof(fbuf));
@@ -411,16 +411,16 @@ static noinline int v4l1_compat_set_frame_buffer(
fbuf.fmt.bytesperline = buffer->bytesperline;
err = drv(file, VIDIOC_S_FBUF, &fbuf);
if (err < 0)
- dprintk("VIDIOCSFBUF / VIDIOC_S_FBUF: %d\n", err);
+ dprintk("VIDIOCSFBUF / VIDIOC_S_FBUF: %ld\n", err);
return err;
}
-static noinline int v4l1_compat_get_win_cap_dimensions(
+static noinline long v4l1_compat_get_win_cap_dimensions(
struct video_window *win,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_format *fmt;
fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
@@ -433,7 +433,7 @@ static noinline int v4l1_compat_get_win_cap_dimensions(
fmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
err = drv(file, VIDIOC_G_FMT, fmt);
if (err < 0)
- dprintk("VIDIOCGWIN / VIDIOC_G_WIN: %d\n", err);
+ dprintk("VIDIOCGWIN / VIDIOC_G_WIN: %ld\n", err);
if (err == 0) {
win->x = fmt->fmt.win.w.left;
win->y = fmt->fmt.win.w.top;
@@ -448,7 +448,7 @@ static noinline int v4l1_compat_get_win_cap_dimensions(
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
err = drv(file, VIDIOC_G_FMT, fmt);
if (err < 0) {
- dprintk("VIDIOCGWIN / VIDIOC_G_FMT: %d\n", err);
+ dprintk("VIDIOCGWIN / VIDIOC_G_FMT: %ld\n", err);
goto done;
}
win->x = 0;
@@ -463,12 +463,12 @@ done:
return err;
}
-static noinline int v4l1_compat_set_win_cap_dimensions(
+static noinline long v4l1_compat_set_win_cap_dimensions(
struct video_window *win,
struct file *file,
v4l2_kioctl drv)
{
- int err, err1, err2;
+ long err, err1, err2;
struct v4l2_format *fmt;
fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
@@ -480,7 +480,7 @@ static noinline int v4l1_compat_set_win_cap_dimensions(
drv(file, VIDIOC_STREAMOFF, &fmt->type);
err1 = drv(file, VIDIOC_G_FMT, fmt);
if (err1 < 0)
- dprintk("VIDIOCSWIN / VIDIOC_G_FMT: %d\n", err1);
+ dprintk("VIDIOCSWIN / VIDIOC_G_FMT: %ld\n", err1);
if (err1 == 0) {
fmt->fmt.pix.width = win->width;
fmt->fmt.pix.height = win->height;
@@ -488,7 +488,7 @@ static noinline int v4l1_compat_set_win_cap_dimensions(
fmt->fmt.pix.bytesperline = 0;
err = drv(file, VIDIOC_S_FMT, fmt);
if (err < 0)
- dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %d\n",
+ dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %ld\n",
err);
win->width = fmt->fmt.pix.width;
win->height = fmt->fmt.pix.height;
@@ -505,7 +505,7 @@ static noinline int v4l1_compat_set_win_cap_dimensions(
fmt->fmt.win.clipcount = win->clipcount;
err2 = drv(file, VIDIOC_S_FMT, fmt);
if (err2 < 0)
- dprintk("VIDIOCSWIN / VIDIOC_S_FMT #2: %d\n", err2);
+ dprintk("VIDIOCSWIN / VIDIOC_S_FMT #2: %ld\n", err2);
if (err1 != 0 && err2 != 0)
err = err1;
@@ -515,12 +515,12 @@ static noinline int v4l1_compat_set_win_cap_dimensions(
return err;
}
-static noinline int v4l1_compat_turn_preview_on_off(
+static noinline long v4l1_compat_turn_preview_on_off(
int *on,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (0 == *on) {
@@ -531,16 +531,16 @@ static noinline int v4l1_compat_turn_preview_on_off(
}
err = drv(file, VIDIOC_OVERLAY, on);
if (err < 0)
- dprintk("VIDIOCCAPTURE / VIDIOC_PREVIEW: %d\n", err);
+ dprintk("VIDIOCCAPTURE / VIDIOC_PREVIEW: %ld\n", err);
return err;
}
-static noinline int v4l1_compat_get_input_info(
+static noinline long v4l1_compat_get_input_info(
struct video_channel *chan,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_input input2;
v4l2_std_id sid;
@@ -549,7 +549,7 @@ static noinline int v4l1_compat_get_input_info(
err = drv(file, VIDIOC_ENUMINPUT, &input2);
if (err < 0) {
dprintk("VIDIOCGCHAN / VIDIOC_ENUMINPUT: "
- "channel=%d err=%d\n", chan->channel, err);
+ "channel=%d err=%ld\n", chan->channel, err);
goto done;
}
chan->channel = input2.index;
@@ -570,7 +570,7 @@ static noinline int v4l1_compat_get_input_info(
chan->norm = 0;
err = drv(file, VIDIOC_G_STD, &sid);
if (err < 0)
- dprintk("VIDIOCGCHAN / VIDIOC_G_STD: %d\n", err);
+ dprintk("VIDIOCGCHAN / VIDIOC_G_STD: %ld\n", err);
if (err == 0) {
if (sid & V4L2_STD_PAL)
chan->norm = VIDEO_MODE_PAL;
@@ -583,17 +583,17 @@ done:
return err;
}
-static noinline int v4l1_compat_set_input(
+static noinline long v4l1_compat_set_input(
struct video_channel *chan,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
v4l2_std_id sid = 0;
err = drv(file, VIDIOC_S_INPUT, &chan->channel);
if (err < 0)
- dprintk("VIDIOCSCHAN / VIDIOC_S_INPUT: %d\n", err);
+ dprintk("VIDIOCSCHAN / VIDIOC_S_INPUT: %ld\n", err);
switch (chan->norm) {
case VIDEO_MODE_PAL:
sid = V4L2_STD_PAL;
@@ -608,17 +608,17 @@ static noinline int v4l1_compat_set_input(
if (0 != sid) {
err = drv(file, VIDIOC_S_STD, &sid);
if (err < 0)
- dprintk("VIDIOCSCHAN / VIDIOC_S_STD: %d\n", err);
+ dprintk("VIDIOCSCHAN / VIDIOC_S_STD: %ld\n", err);
}
return err;
}
-static noinline int v4l1_compat_get_picture(
+static noinline long v4l1_compat_get_picture(
struct video_picture *pict,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_format *fmt;
fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
@@ -641,7 +641,7 @@ static noinline int v4l1_compat_get_picture(
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
err = drv(file, VIDIOC_G_FMT, fmt);
if (err < 0) {
- dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n", err);
+ dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %ld\n", err);
goto done;
}
@@ -655,12 +655,12 @@ done:
return err;
}
-static noinline int v4l1_compat_set_picture(
+static noinline long v4l1_compat_set_picture(
struct video_picture *pict,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_framebuffer fbuf;
int mem_err = 0, ovl_err = 0;
struct v4l2_format *fmt;
@@ -695,7 +695,7 @@ static noinline int v4l1_compat_set_picture(
support memory capture. Trying to set the memory capture
parameters would be pointless. */
if (err < 0) {
- dprintk("VIDIOCSPICT / VIDIOC_G_FMT: %d\n", err);
+ dprintk("VIDIOCSPICT / VIDIOC_G_FMT: %ld\n", err);
mem_err = -1000; /* didn't even try */
} else if (fmt->fmt.pix.pixelformat !=
palette_to_pixelformat(pict->palette)) {
@@ -712,7 +712,7 @@ static noinline int v4l1_compat_set_picture(
support overlay. Trying to set the overlay parameters
would be quite pointless. */
if (err < 0) {
- dprintk("VIDIOCSPICT / VIDIOC_G_FBUF: %d\n", err);
+ dprintk("VIDIOCSPICT / VIDIOC_G_FBUF: %ld\n", err);
ovl_err = -1000; /* didn't even try */
} else if (fbuf.fmt.pixelformat !=
palette_to_pixelformat(pict->palette)) {
@@ -737,12 +737,13 @@ static noinline int v4l1_compat_set_picture(
return err;
}
-static noinline int v4l1_compat_get_tuner(
+static noinline long v4l1_compat_get_tuner(
struct video_tuner *tun,
struct file *file,
v4l2_kioctl drv)
{
- int err, i;
+ long err;
+ int i;
struct v4l2_tuner tun2;
struct v4l2_standard std2;
v4l2_std_id sid;
@@ -750,7 +751,7 @@ static noinline int v4l1_compat_get_tuner(
memset(&tun2, 0, sizeof(tun2));
err = drv(file, VIDIOC_G_TUNER, &tun2);
if (err < 0) {
- dprintk("VIDIOCGTUNER / VIDIOC_G_TUNER: %d\n", err);
+ dprintk("VIDIOCGTUNER / VIDIOC_G_TUNER: %ld\n", err);
goto done;
}
memcpy(tun->name, tun2.name,
@@ -776,7 +777,7 @@ static noinline int v4l1_compat_get_tuner(
err = drv(file, VIDIOC_G_STD, &sid);
if (err < 0)
- dprintk("VIDIOCGTUNER / VIDIOC_G_STD: %d\n", err);
+ dprintk("VIDIOCGTUNER / VIDIOC_G_STD: %ld\n", err);
if (err == 0) {
if (sid & V4L2_STD_PAL)
tun->mode = VIDEO_MODE_PAL;
@@ -795,12 +796,12 @@ done:
return err;
}
-static noinline int v4l1_compat_select_tuner(
+static noinline long v4l1_compat_select_tuner(
struct video_tuner *tun,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_tuner t;/*84 bytes on x86_64*/
memset(&t, 0, sizeof(t));
@@ -808,34 +809,34 @@ static noinline int v4l1_compat_select_tuner(
err = drv(file, VIDIOC_S_INPUT, &t);
if (err < 0)
- dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n", err);
+ dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %ld\n", err);
return err;
}
-static noinline int v4l1_compat_get_frequency(
+static noinline long v4l1_compat_get_frequency(
unsigned long *freq,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_frequency freq2;
memset(&freq2, 0, sizeof(freq2));
freq2.tuner = 0;
err = drv(file, VIDIOC_G_FREQUENCY, &freq2);
if (err < 0)
- dprintk("VIDIOCGFREQ / VIDIOC_G_FREQUENCY: %d\n", err);
+ dprintk("VIDIOCGFREQ / VIDIOC_G_FREQUENCY: %ld\n", err);
if (0 == err)
*freq = freq2.frequency;
return err;
}
-static noinline int v4l1_compat_set_frequency(
+static noinline long v4l1_compat_set_frequency(
unsigned long *freq,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_frequency freq2;
memset(&freq2, 0, sizeof(freq2));
@@ -843,16 +844,17 @@ static noinline int v4l1_compat_set_frequency(
freq2.frequency = *freq;
err = drv(file, VIDIOC_S_FREQUENCY, &freq2);
if (err < 0)
- dprintk("VIDIOCSFREQ / VIDIOC_S_FREQUENCY: %d\n", err);
+ dprintk("VIDIOCSFREQ / VIDIOC_S_FREQUENCY: %ld\n", err);
return err;
}
-static noinline int v4l1_compat_get_audio(
+static noinline long v4l1_compat_get_audio(
struct video_audio *aud,
struct file *file,
v4l2_kioctl drv)
{
- int err, i;
+ long err;
+ int i;
struct v4l2_queryctrl qctrl2;
struct v4l2_audio aud2;
struct v4l2_tuner tun2;
@@ -860,7 +862,7 @@ static noinline int v4l1_compat_get_audio(
err = drv(file, VIDIOC_G_AUDIO, &aud2);
if (err < 0) {
- dprintk("VIDIOCGAUDIO / VIDIOC_G_AUDIO: %d\n", err);
+ dprintk("VIDIOCGAUDIO / VIDIOC_G_AUDIO: %ld\n", err);
goto done;
}
memcpy(aud->name, aud2.name,
@@ -904,7 +906,7 @@ static noinline int v4l1_compat_get_audio(
memset(&tun2, 0, sizeof(tun2));
err = drv(file, VIDIOC_G_TUNER, &tun2);
if (err < 0) {
- dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %d\n", err);
+ dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %ld\n", err);
err = 0;
goto done;
}
@@ -919,12 +921,12 @@ done:
return err;
}
-static noinline int v4l1_compat_set_audio(
+static noinline long v4l1_compat_set_audio(
struct video_audio *aud,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_audio aud2;
struct v4l2_tuner tun2;
@@ -934,7 +936,7 @@ static noinline int v4l1_compat_set_audio(
aud2.index = aud->audio;
err = drv(file, VIDIOC_S_AUDIO, &aud2);
if (err < 0) {
- dprintk("VIDIOCSAUDIO / VIDIOC_S_AUDIO: %d\n", err);
+ dprintk("VIDIOCSAUDIO / VIDIOC_S_AUDIO: %ld\n", err);
goto done;
}
@@ -951,7 +953,7 @@ static noinline int v4l1_compat_set_audio(
err = drv(file, VIDIOC_G_TUNER, &tun2);
if (err < 0)
- dprintk("VIDIOCSAUDIO / VIDIOC_G_TUNER: %d\n", err);
+ dprintk("VIDIOCSAUDIO / VIDIOC_G_TUNER: %ld\n", err);
if (err == 0) {
switch (aud->mode) {
default:
@@ -968,19 +970,19 @@ static noinline int v4l1_compat_set_audio(
}
err = drv(file, VIDIOC_S_TUNER, &tun2);
if (err < 0)
- dprintk("VIDIOCSAUDIO / VIDIOC_S_TUNER: %d\n", err);
+ dprintk("VIDIOCSAUDIO / VIDIOC_S_TUNER: %ld\n", err);
}
err = 0;
done:
return err;
}
-static noinline int v4l1_compat_capture_frame(
+static noinline long v4l1_compat_capture_frame(
struct video_mmap *mm,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
struct v4l2_buffer buf;
struct v4l2_format *fmt;
@@ -995,7 +997,7 @@ static noinline int v4l1_compat_capture_frame(
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
err = drv(file, VIDIOC_G_FMT, fmt);
if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_G_FMT: %d\n", err);
+ dprintk("VIDIOCMCAPTURE / VIDIOC_G_FMT: %ld\n", err);
goto done;
}
if (mm->width != fmt->fmt.pix.width ||
@@ -1011,7 +1013,7 @@ static noinline int v4l1_compat_capture_frame(
fmt->fmt.pix.bytesperline = 0;
err = drv(file, VIDIOC_S_FMT, fmt);
if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %d\n", err);
+ dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %ld\n", err);
goto done;
}
}
@@ -1019,28 +1021,28 @@ static noinline int v4l1_compat_capture_frame(
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
err = drv(file, VIDIOC_QUERYBUF, &buf);
if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_QUERYBUF: %d\n", err);
+ dprintk("VIDIOCMCAPTURE / VIDIOC_QUERYBUF: %ld\n", err);
goto done;
}
err = drv(file, VIDIOC_QBUF, &buf);
if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %d\n", err);
+ dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %ld\n", err);
goto done;
}
err = drv(file, VIDIOC_STREAMON, &captype);
if (err < 0)
- dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %d\n", err);
+ dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %ld\n", err);
done:
kfree(fmt);
return err;
}
-static noinline int v4l1_compat_sync(
+static noinline long v4l1_compat_sync(
int *i,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
struct v4l2_buffer buf;
struct poll_wqueues *pwq;
@@ -1051,7 +1053,7 @@ static noinline int v4l1_compat_sync(
err = drv(file, VIDIOC_QUERYBUF, &buf);
if (err < 0) {
/* No such buffer */
- dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n", err);
+ dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %ld\n", err);
goto done;
}
if (!(buf.flags & V4L2_BUF_FLAG_MAPPED)) {
@@ -1063,7 +1065,7 @@ static noinline int v4l1_compat_sync(
/* make sure capture actually runs so we don't block forever */
err = drv(file, VIDIOC_STREAMON, &captype);
if (err < 0) {
- dprintk("VIDIOCSYNC / VIDIOC_STREAMON: %d\n", err);
+ dprintk("VIDIOCSYNC / VIDIOC_STREAMON: %ld\n", err);
goto done;
}
@@ -1077,7 +1079,7 @@ static noinline int v4l1_compat_sync(
break;
err = drv(file, VIDIOC_QUERYBUF, &buf);
if (err < 0)
- dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n", err);
+ dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %ld\n", err);
}
kfree(pwq);
if (!(buf.flags & V4L2_BUF_FLAG_DONE)) /* not done */
@@ -1085,18 +1087,18 @@ static noinline int v4l1_compat_sync(
do {
err = drv(file, VIDIOC_DQBUF, &buf);
if (err < 0)
- dprintk("VIDIOCSYNC / VIDIOC_DQBUF: %d\n", err);
+ dprintk("VIDIOCSYNC / VIDIOC_DQBUF: %ld\n", err);
} while (err == 0 && buf.index != *i);
done:
return err;
}
-static noinline int v4l1_compat_get_vbi_format(
+static noinline long v4l1_compat_get_vbi_format(
struct vbi_format *fmt,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_format *fmt2;
fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
@@ -1108,7 +1110,7 @@ static noinline int v4l1_compat_get_vbi_format(
err = drv(file, VIDIOC_G_FMT, fmt2);
if (err < 0) {
- dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err);
+ dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %ld\n", err);
goto done;
}
if (fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) {
@@ -1129,12 +1131,12 @@ done:
return err;
}
-static noinline int v4l1_compat_set_vbi_format(
+static noinline long v4l1_compat_set_vbi_format(
struct vbi_format *fmt,
struct file *file,
v4l2_kioctl drv)
{
- int err;
+ long err;
struct v4l2_format *fmt2 = NULL;
if (VIDEO_PALETTE_RAW != fmt->sample_format) {
@@ -1158,7 +1160,7 @@ static noinline int v4l1_compat_set_vbi_format(
fmt2->fmt.vbi.flags = fmt->flags;
err = drv(file, VIDIOC_TRY_FMT, fmt2);
if (err < 0) {
- dprintk("VIDIOCSVBIFMT / VIDIOC_TRY_FMT: %d\n", err);
+ dprintk("VIDIOCSVBIFMT / VIDIOC_TRY_FMT: %ld\n", err);
goto done;
}
@@ -1175,7 +1177,7 @@ static noinline int v4l1_compat_set_vbi_format(
}
err = drv(file, VIDIOC_S_FMT, fmt2);
if (err < 0)
- dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %d\n", err);
+ dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %ld\n", err);
done:
kfree(fmt2);
return err;
@@ -1184,13 +1186,13 @@ done:
/*
* This function is exported.
*/
-int
+long
v4l_compat_translate_ioctl(struct file *file,
int cmd,
void *arg,
v4l2_kioctl drv)
{
- int err;
+ long err;
switch (cmd) {
case VIDIOCGCAP: /* capability */
diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c
index e87a04a60..27af4d97a 100644
--- a/linux/drivers/media/video/v4l2-common.c
+++ b/linux/drivers/media/video/v4l2-common.c
@@ -58,6 +58,7 @@
#include <asm/div64.h>
#define __OLD_VIDIOC_ /* To allow fixing old calls*/
#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <linux/videodev2.h>
@@ -321,6 +322,19 @@ const char **v4l2_ctrl_get_menu(u32 id)
"Private packet, IVTV format",
NULL
};
+ static const char *camera_power_line_frequency[] = {
+ "Disabled",
+ "50 Hz",
+ "60 Hz",
+ NULL
+ };
+ static const char *camera_exposure_auto[] = {
+ "Auto Mode",
+ "Manual Mode",
+ "Shutter Priority Mode",
+ "Aperture Priority Mode",
+ NULL
+ };
switch (id) {
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
@@ -353,6 +367,10 @@ const char **v4l2_ctrl_get_menu(u32 id)
return mpeg_stream_type;
case V4L2_CID_MPEG_STREAM_VBI_FMT:
return mpeg_stream_vbi_fmt;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ return camera_power_line_frequency;
+ case V4L2_CID_EXPOSURE_AUTO:
+ return camera_exposure_auto;
default:
return NULL;
}
@@ -364,17 +382,37 @@ const char *v4l2_ctrl_get_name(u32 id)
{
switch (id) {
/* USER controls */
- case V4L2_CID_USER_CLASS: return "User Controls";
- case V4L2_CID_AUDIO_VOLUME: return "Volume";
- case V4L2_CID_AUDIO_MUTE: return "Mute";
- case V4L2_CID_AUDIO_BALANCE: return "Balance";
- case V4L2_CID_AUDIO_BASS: return "Bass";
- case V4L2_CID_AUDIO_TREBLE: return "Treble";
- case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
- case V4L2_CID_BRIGHTNESS: return "Brightness";
- case V4L2_CID_CONTRAST: return "Contrast";
- case V4L2_CID_SATURATION: return "Saturation";
- case V4L2_CID_HUE: return "Hue";
+ case V4L2_CID_USER_CLASS: return "User Controls";
+ case V4L2_CID_AUDIO_VOLUME: return "Volume";
+ case V4L2_CID_AUDIO_MUTE: return "Mute";
+ case V4L2_CID_AUDIO_BALANCE: return "Balance";
+ case V4L2_CID_AUDIO_BASS: return "Bass";
+ case V4L2_CID_AUDIO_TREBLE: return "Treble";
+ case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
+ case V4L2_CID_BRIGHTNESS: return "Brightness";
+ case V4L2_CID_CONTRAST: return "Contrast";
+ case V4L2_CID_SATURATION: return "Saturation";
+ case V4L2_CID_HUE: return "Hue";
+ case V4L2_CID_BLACK_LEVEL: return "Black Level";
+ case V4L2_CID_AUTO_WHITE_BALANCE: return "White Balance, Automatic";
+ case V4L2_CID_DO_WHITE_BALANCE: return "Do White Balance";
+ case V4L2_CID_RED_BALANCE: return "Red Balance";
+ case V4L2_CID_BLUE_BALANCE: return "Blue Balance";
+ case V4L2_CID_GAMMA: return "Gamma";
+ case V4L2_CID_EXPOSURE: return "Exposure";
+ case V4L2_CID_AUTOGAIN: return "Gain, Automatic";
+ case V4L2_CID_GAIN: return "Gain";
+ case V4L2_CID_HFLIP: return "Horizontal Flip";
+ case V4L2_CID_VFLIP: return "Vertical Flip";
+ case V4L2_CID_HCENTER: return "Horizontal Center";
+ case V4L2_CID_VCENTER: return "Vertical Center";
+ case V4L2_CID_POWER_LINE_FREQUENCY: return "Power Line Frequency";
+ case V4L2_CID_HUE_AUTO: return "Hue, Automatic";
+ case V4L2_CID_WHITE_BALANCE_TEMPERATURE: return "White Balance Temperature";
+ case V4L2_CID_SHARPNESS: return "Sharpness";
+ case V4L2_CID_BACKLIGHT_COMPENSATION: return "Backlight Compensation";
+ case V4L2_CID_CHROMA_AGC: return "Chroma AGC";
+ case V4L2_CID_COLOR_KILLER: return "Color Killer";
/* MPEG controls */
case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls";
@@ -411,6 +449,25 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format";
+ /* CAMERA controls */
+ case V4L2_CID_CAMERA_CLASS: return "Camera Controls";
+ case V4L2_CID_EXPOSURE_AUTO: return "Auto Exposure";
+ case V4L2_CID_EXPOSURE_ABSOLUTE: return "Exposure Time, Absolute";
+ case V4L2_CID_EXPOSURE_AUTO_PRIORITY: return "Exposure, Dynamic Framerate";
+ case V4L2_CID_PAN_RELATIVE: return "Pan, Relative";
+ case V4L2_CID_TILT_RELATIVE: return "Tilt, Relative";
+ case V4L2_CID_PAN_RESET: return "Pan, Reset";
+ case V4L2_CID_TILT_RESET: return "Tilt, Reset";
+ case V4L2_CID_PAN_ABSOLUTE: return "Pan, Absolute";
+ case V4L2_CID_TILT_ABSOLUTE: return "Tilt, Absolute";
+ case V4L2_CID_FOCUS_ABSOLUTE: return "Focus, Absolute";
+ case V4L2_CID_FOCUS_RELATIVE: return "Focus, Relative";
+ case V4L2_CID_FOCUS_AUTO: return "Focus, Automatic";
+ case V4L2_CID_ZOOM_ABSOLUTE: return "Zoom, Absolute";
+ case V4L2_CID_ZOOM_RELATIVE: return "Zoom, Relative";
+ case V4L2_CID_ZOOM_CONTINUOUS: return "Zoom, Continuous";
+ case V4L2_CID_PRIVACY: return "Privacy";
+
default:
return NULL;
}
@@ -429,14 +486,22 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
switch (qctrl->id) {
case V4L2_CID_AUDIO_MUTE:
case V4L2_CID_AUDIO_LOUDNESS:
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ case V4L2_CID_AUTOGAIN:
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HUE_AUTO:
case V4L2_CID_MPEG_AUDIO_MUTE:
case V4L2_CID_MPEG_VIDEO_MUTE:
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
+ case V4L2_CID_PRIVACY:
qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
min = 0;
max = step = 1;
break;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
case V4L2_CID_MPEG_AUDIO_ENCODING:
case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
@@ -452,10 +517,12 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
case V4L2_CID_MPEG_STREAM_TYPE:
case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ case V4L2_CID_EXPOSURE_AUTO:
qctrl->type = V4L2_CTRL_TYPE_MENU;
step = 1;
break;
case V4L2_CID_USER_CLASS:
+ case V4L2_CID_CAMERA_CLASS:
case V4L2_CID_MPEG_CLASS:
qctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
@@ -731,11 +798,11 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
}
EXPORT_SYMBOL(v4l2_ctrl_next);
-int v4l2_chip_match_host(u32 match_type, u32 match_chip)
+int v4l2_chip_match_host(const struct v4l2_dbg_match *match)
{
- switch (match_type) {
+ switch (match->type) {
case V4L2_CHIP_MATCH_HOST:
- return match_chip == 0;
+ return match->addr == 0;
default:
return 0;
}
@@ -743,23 +810,34 @@ int v4l2_chip_match_host(u32 match_type, u32 match_chip)
EXPORT_SYMBOL(v4l2_chip_match_host);
#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 match_type, u32 match_chip)
+int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match *match)
{
- switch (match_type) {
+ int len;
+
+ if (c == NULL || match == NULL)
+ return 0;
+
+ switch (match->type) {
case V4L2_CHIP_MATCH_I2C_DRIVER:
- return (c != NULL && c->driver != NULL && c->driver->id == match_chip);
+ if (c->driver == NULL || c->driver->driver.name == NULL)
+ return 0;
+ len = strlen(c->driver->driver.name);
+ /* legacy drivers have a ' suffix, don't try to match that */
+ if (len && c->driver->driver.name[len - 1] == '\'')
+ len--;
+ return len && !strncmp(c->driver->driver.name, match->name, len);
case V4L2_CHIP_MATCH_I2C_ADDR:
- return (c != NULL && c->addr == match_chip);
+ return c->addr == match->addr;
default:
return 0;
}
}
EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
-int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_chip_ident *chip,
+int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_dbg_chip_ident *chip,
u32 ident, u32 revision)
{
- if (!v4l2_chip_match_i2c_client(c, chip->match_type, chip->match_chip))
+ if (!v4l2_chip_match_i2c_client(c, &chip->match))
return 0;
if (chip->ident == V4L2_IDENT_NONE) {
chip->ident = ident;
@@ -802,4 +880,173 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver
return err != -ENOMEM ? 0 : err;
}
EXPORT_SYMBOL(v4l2_i2c_attach);
+
+void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
+ const struct v4l2_subdev_ops *ops)
+{
+ v4l2_subdev_init(sd, ops);
+ /* the owner is the same as the i2c_client's driver owner */
+ sd->owner = client->driver->driver.owner;
+ /* i2c_client and v4l2_subdev point to one another */
+ v4l2_set_subdevdata(sd, client);
+ i2c_set_clientdata(client, sd);
+ /* initialize name */
+ snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
+ client->driver->driver.name, i2c_adapter_id(client->adapter),
+ client->addr);
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+/* Supporting function to find a client on a specific address on the
+ given adapter. Used for legacy i2c drivers. */
+static struct i2c_client *v4l2_i2c_legacy_find_client(struct i2c_adapter *adap, u8 addr)
+{
+ struct i2c_client *result = NULL;
+ struct i2c_client *client;
+ struct list_head *item;
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+ down(&adap->clist_lock);
+#else
+ mutex_lock(&adap->clist_lock);
+#endif
+ list_for_each(item, &adap->clients) {
+ client = list_entry(item, struct i2c_client, list);
+ if (client->addr == addr) {
+ result = client;
+ break;
+ }
+ }
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+ up(&adap->clist_lock);
+#else
+ mutex_unlock(&adap->clist_lock);
+#endif
+ return result;
+}
+#endif
+
+
+/* Load an i2c sub-device. It assumes that i2c_get_adapdata(adapter)
+ returns the v4l2_device and that i2c_get_clientdata(client)
+ returns the v4l2_subdev. */
+struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
+ const char *module_name, const char *client_type, u8 addr)
+{
+ struct v4l2_device *dev = i2c_get_adapdata(adapter);
+ struct v4l2_subdev *sd = NULL;
+ struct i2c_client *client;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ struct i2c_board_info info;
+#endif
+
+ BUG_ON(!dev);
+#ifdef MODULE
+ if (module_name)
+ request_module(module_name);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ /* Setup the i2c board info with the device type and
+ the device address. */
+ memset(&info, 0, sizeof(info));
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ strlcpy(info.driver_name, client_type, sizeof(info.driver_name));
+#else
+ strlcpy(info.type, client_type, sizeof(info.type));
+#endif
+ info.addr = addr;
+
+ /* Create the i2c client */
+ client = i2c_new_device(adapter, &info);
+#else
+ /* Legacy code: loading the module automatically
+ probes and creates the i2c_client on the adapter.
+ Try to find the client by walking the adapter's client list. */
+ client = v4l2_i2c_legacy_find_client(adapter, addr);
+#endif
+ /* Note: it is possible in the future that
+ c->driver is NULL if the driver is still being loaded.
+ We need better support from the kernel so that we
+ can easily wait for the load to finish. */
+ if (client == NULL || client->driver == NULL)
+ return NULL;
+
+ /* Lock the module so we can safely get the v4l2_subdev pointer */
+ if (!try_module_get(client->driver->driver.owner))
+ return NULL;
+ sd = i2c_get_clientdata(client);
+
+ /* Register with the v4l2_device which increases the module's
+ use count as well. */
+ if (v4l2_device_register_subdev(dev, sd))
+ sd = NULL;
+ /* Decrease the module use count to match the first try_module_get. */
+ module_put(client->driver->driver.owner);
+ return sd;
+
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
+
+/* Probe and load an i2c sub-device. It assumes that i2c_get_adapdata(adapter)
+ returns the v4l2_device and that i2c_get_clientdata(client)
+ returns the v4l2_subdev. */
+struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
+ const char *module_name, const char *client_type,
+ const unsigned short *addrs)
+{
+ struct v4l2_device *dev = i2c_get_adapdata(adapter);
+ struct v4l2_subdev *sd = NULL;
+ struct i2c_client *client = NULL;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ struct i2c_board_info info;
+#endif
+
+ BUG_ON(!dev);
+#ifdef MODULE
+ if (module_name)
+ request_module(module_name);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ /* Setup the i2c board info with the device type and
+ the device address. */
+ memset(&info, 0, sizeof(info));
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ strlcpy(info.driver_name, client_type, sizeof(info.driver_name));
+#else
+ strlcpy(info.type, client_type, sizeof(info.type));
+#endif
+
+ /* Probe and create the i2c client */
+ client = i2c_new_probed_device(adapter, &info, addrs);
+#else
+ /* Legacy code: loading the module should automatically
+ probe and create the i2c_client on the adapter.
+ Try to find the client by walking the adapter's client list
+ for each of the possible addresses. */
+ while (!client && *addrs != I2C_CLIENT_END)
+ client = v4l2_i2c_legacy_find_client(adapter, *addrs++);
+#endif
+ /* Note: it is possible in the future that
+ c->driver is NULL if the driver is still being loaded.
+ We need better support from the kernel so that we
+ can easily wait for the load to finish. */
+ if (client == NULL || client->driver == NULL)
+ return NULL;
+
+ /* Lock the module so we can safely get the v4l2_subdev pointer */
+ if (!try_module_get(client->driver->driver.owner))
+ return NULL;
+ sd = i2c_get_clientdata(client);
+
+ /* Register with the v4l2_device which increases the module's
+ use count as well. */
+ if (v4l2_device_register_subdev(dev, sd))
+ sd = NULL;
+ /* Decrease the module use count to match the first try_module_get. */
+ module_put(client->driver->driver.owner);
+ return sd;
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev);
+
#endif
diff --git a/linux/drivers/media/video/v4l2-compat-ioctl32.c b/linux/drivers/media/video/v4l2-compat-ioctl32.c
index 09d5c5693..05a356776 100644
--- a/linux/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/linux/drivers/media/video/v4l2-compat-ioctl32.c
@@ -7,12 +7,14 @@
* Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
* Copyright (C) 2003 Pavel Machek (pavel@suse.cz)
* Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be)
+ * Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
*
* These routines maintain argument size conversion between 32bit and 64bit
* ioctls.
*/
#include <linux/compat.h>
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <linux/module.h>
@@ -59,55 +61,6 @@ static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user
return 0;
}
-#if 0 /*FIXME */
-struct video_audio32 {
- compat_int_t audio;
- __u16 volume;
- __u16 bass, treble;
- __u32 flags;
- __u8 name[16];
- __u16 mode;
- __u16 balance;
- __u16 step;
-};
-
-static int get_video_audio32(struct video_audio *kp,
- struct video_audio32 __user *up)
-{
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_audio32)) ||
- get_user(kp->audio, &up->audio) ||
- get_user(kp->volume, &up->volume) ||
- get_user(kp->bass, &up->bass) ||
- get_user(kp->treble, &up->treble) ||
- get_user(kp->flags, &up->flags) ||
- copy_from_user(kp->name, up->name, sizeof(up->name)) ||
- get_user(kp->mode, &up->mode) ||
- get_user(kp->balance, &up->balance) ||
- get_user(kp->step, &up->step))
- return -EFAULT;
-
- return 0;
-}
-
-static int put_video_audio32(struct video_audio *kp,
- struct video_audio32 __user *up)
-{
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_audio32)) ||
- put_user(kp->audio, &up->audio) ||
- put_user(kp->volume, &up->volume) ||
- put_user(kp->bass, &up->bass) ||
- put_user(kp->treble, &up->treble) ||
- put_user(kp->flags, &up->flags) ||
- copy_to_user(kp->name, up->name, sizeof(up->name)) ||
- put_user(kp->mode, &up->mode) ||
- put_user(kp->balance, &up->balance) ||
- put_user(kp->step, &up->step))
- return -EFAULT;
-
- return 0;
-}
-#endif
-
struct video_buffer32 {
compat_caddr_t base;
compat_int_t height, width, depth, bytesperline;
@@ -148,7 +101,7 @@ static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __u
}
struct video_clip32 {
- s32 x, y, width, height; /* Its really s32 in videodev.h */
+ s32 x, y, width, height; /* It's really s32 in videodev.h */
compat_caddr_t next;
};
@@ -157,29 +110,72 @@ struct video_window32 {
compat_caddr_t clips;
compat_int_t clipcount;
};
-#endif
-static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static int get_video_window32(struct video_window *kp, struct video_window32 __user *up)
{
- int ret = -ENOIOCTLCMD;
+ struct video_clip __user *uclips;
+ struct video_clip __user *kclips;
+ compat_caddr_t p;
+ int nclips;
- if (file->f_op->unlocked_ioctl)
- ret = file->f_op->unlocked_ioctl(file, cmd, arg);
- else if (file->f_op->ioctl) {
- lock_kernel();
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
- ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg);
-#else
- ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
-#endif
- unlock_kernel();
+ if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)))
+ return -EFAULT;
+
+ if (get_user(nclips, &up->clipcount))
+ return -EFAULT;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)) ||
+ get_user(kp->x, &up->x) ||
+ get_user(kp->y, &up->y) ||
+ get_user(kp->width, &up->width) ||
+ get_user(kp->height, &up->height) ||
+ get_user(kp->chromakey, &up->chromakey) ||
+ get_user(kp->flags, &up->flags) ||
+ get_user(kp->clipcount, &up->clipcount))
+ return -EFAULT;
+
+ nclips = kp->clipcount;
+ kp->clips = NULL;
+
+ if (nclips == 0)
+ return 0;
+ if (get_user(p, &up->clips))
+ return -EFAULT;
+ uclips = compat_ptr(p);
+
+ /* If nclips < 0, then it is a clipping bitmap of size
+ VIDEO_CLIPMAP_SIZE */
+ if (nclips < 0) {
+ if (!access_ok(VERIFY_READ, uclips, VIDEO_CLIPMAP_SIZE))
+ return -EFAULT;
+ kp->clips = compat_alloc_user_space(VIDEO_CLIPMAP_SIZE);
+ if (copy_in_user(kp->clips, uclips, VIDEO_CLIPMAP_SIZE))
+ return -EFAULT;
+ return 0;
}
- return ret;
-}
+ /* Otherwise it is an array of video_clip structs. */
+ if (!access_ok(VERIFY_READ, uclips, nclips * sizeof(struct video_clip)))
+ return -EFAULT;
+ kp->clips = compat_alloc_user_space(nclips * sizeof(struct video_clip));
+ kclips = kp->clips;
+ while (nclips--) {
+ int err;
+
+ err = copy_in_user(&kclips->x, &uclips->x, sizeof(kclips->x));
+ err |= copy_in_user(&kclips->y, &uclips->y, sizeof(kclips->y));
+ err |= copy_in_user(&kclips->width, &uclips->width, sizeof(kclips->width));
+ err |= copy_in_user(&kclips->height, &uclips->height, sizeof(kclips->height));
+ kclips->next = NULL;
+ if (err)
+ return -EFAULT;
+ kclips++;
+ uclips++;
+ }
+ return 0;
+}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
/* You get back everything except the clips... */
static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
{
@@ -194,7 +190,58 @@ static int put_video_window32(struct video_window *kp, struct video_window32 __u
return -EFAULT;
return 0;
}
+
+struct video_code32 {
+ char loadwhat[16]; /* name or tag of file being passed */
+ compat_int_t datasize;
+ unsigned char *data;
+};
+
+static int get_microcode32(struct video_code *kp, struct video_code32 __user *up)
+{
+ if (!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
+ copy_from_user(kp->loadwhat, up->loadwhat, sizeof(up->loadwhat)) ||
+ get_user(kp->datasize, &up->datasize) ||
+ copy_from_user(kp->data, up->data, up->datasize))
+ return -EFAULT;
+ return 0;
+}
+
+#define VIDIOCGTUNER32 _IOWR('v', 4, struct video_tuner32)
+#define VIDIOCSTUNER32 _IOW('v', 5, struct video_tuner32)
+#define VIDIOCGWIN32 _IOR('v', 9, struct video_window32)
+#define VIDIOCSWIN32 _IOW('v', 10, struct video_window32)
+#define VIDIOCGFBUF32 _IOR('v', 11, struct video_buffer32)
+#define VIDIOCSFBUF32 _IOW('v', 12, struct video_buffer32)
+#define VIDIOCGFREQ32 _IOR('v', 14, u32)
+#define VIDIOCSFREQ32 _IOW('v', 15, u32)
+#define VIDIOCSMICROCODE32 _IOW('v', 27, struct video_code32)
+
+#define VIDIOCCAPTURE32 _IOW('v', 8, s32)
+#define VIDIOCSYNC32 _IOW('v', 18, s32)
+#define VIDIOCSWRITEMODE32 _IOW('v', 25, s32)
+
+#endif
+
+static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long ret = -ENOIOCTLCMD;
+
+ if (file->f_op->unlocked_ioctl)
+ ret = file->f_op->unlocked_ioctl(file, cmd, arg);
+ else if (file->f_op->ioctl) {
+ lock_kernel();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg);
+#else
+ ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
#endif
+ unlock_kernel();
+ }
+
+ return ret;
+}
+
struct v4l2_clip32 {
struct v4l2_rect c;
@@ -282,12 +329,27 @@ static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vb
return 0;
}
+static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+{
+ if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
+ return -EFAULT;
+ return 0;
+}
+
+static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+{
+ if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
+ return -EFAULT;
+ return 0;
+}
+
struct v4l2_format32 {
enum v4l2_buf_type type;
union {
- struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
- struct v4l2_window32 win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
- struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
+ struct v4l2_pix_format pix;
+ struct v4l2_window32 win;
+ struct v4l2_vbi_format vbi;
+ struct v4l2_sliced_vbi_format sliced;
__u8 raw_data[200]; /* user-defined */
} fmt;
};
@@ -299,15 +361,27 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
return -EFAULT;
switch (kp->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (copy_from_user(kp, up, sizeof(kp->fmt.raw_data)))
+ return -EFAULT;
+ return 0;
+ case 0:
+ return -EINVAL;
default:
- printk(KERN_INFO "compat_ioctl: unexpected VIDIOC_FMT type %d\n",
+ printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
kp->type);
- return -ENXIO;
+ return -EINVAL;
}
}
@@ -318,31 +392,30 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
return -EFAULT;
switch (kp->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (copy_to_user(up, kp, sizeof(up->fmt.raw_data)))
+ return -EFAULT;
+ return 0;
+ case 0:
+ return -EINVAL;
default:
- return -ENXIO;
+ printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+ kp->type);
+ return -EINVAL;
}
}
-static inline int get_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up)
-{
- if (copy_from_user(kp, up, sizeof(struct v4l2_standard)))
- return -EFAULT;
- return 0;
-
-}
-
-static inline int put_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up)
-{
- if (copy_to_user(up, kp, sizeof(struct v4l2_standard)))
- return -EFAULT;
- return 0;
-}
-
struct v4l2_standard32 {
__u32 index;
__u32 id[2]; /* __u64 would get the alignment wrong */
@@ -374,21 +447,6 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32
return 0;
}
-static inline int get_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up)
-{
- if (copy_from_user(kp, up, sizeof(struct v4l2_tuner)))
- return -EFAULT;
- return 0;
-
-}
-
-static inline int put_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up)
-{
- if (copy_to_user(up, kp, sizeof(struct v4l2_tuner)))
- return -EFAULT;
- return 0;
-}
-
struct v4l2_buffer32 {
__u32 index;
enum v4l2_buf_type type;
@@ -512,151 +570,147 @@ static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame
return 0;
}
-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up)
-{
- if (copy_from_user(kp, up, sizeof(struct v4l2_input) - 4))
- return -EFAULT;
- return 0;
-}
-
-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up)
-{
- if (copy_to_user(up, kp, sizeof(struct v4l2_input) - 4))
- return -EFAULT;
- return 0;
-}
-
-static inline int get_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up)
+struct v4l2_input32 {
+ __u32 index; /* Which input */
+ __u8 name[32]; /* Label */
+ __u32 type; /* Type of input */
+ __u32 audioset; /* Associated audios (bitfield) */
+ __u32 tuner; /* Associated tuner */
+ v4l2_std_id std;
+ __u32 status;
+ __u32 reserved[4];
+} __attribute__ ((packed));
+
+/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
+ Otherwise it is identical to the 32-bit version. */
+static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
{
- if (copy_from_user(kp, up, sizeof(struct v4l2_input)))
+ if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
return -EFAULT;
return 0;
}
-static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up)
+static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
{
- if (copy_to_user(up, kp, sizeof(struct v4l2_input)))
+ if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
return -EFAULT;
return 0;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-struct video_code32 {
- char loadwhat[16]; /* name or tag of file being passed */
- compat_int_t datasize;
- unsigned char *data;
+struct v4l2_ext_controls32 {
+ __u32 ctrl_class;
+ __u32 count;
+ __u32 error_idx;
+ __u32 reserved[2];
+ compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
};
-static inline int microcode32(struct video_code *kp, struct video_code32 __user *up)
+static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
{
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
- copy_from_user(kp->loadwhat, up->loadwhat, sizeof(up->loadwhat)) ||
- get_user(kp->datasize, &up->datasize) ||
- copy_from_user(kp->data, up->data, up->datasize))
+ struct v4l2_ext_control __user *ucontrols;
+ struct v4l2_ext_control __user *kcontrols;
+ int n;
+ compat_caddr_t p;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
+ get_user(kp->ctrl_class, &up->ctrl_class) ||
+ get_user(kp->count, &up->count) ||
+ get_user(kp->error_idx, &up->error_idx) ||
+ copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+ return -EFAULT;
+ n = kp->count;
+ if (n == 0) {
+ kp->controls = NULL;
+ return 0;
+ }
+ if (get_user(p, &up->controls))
+ return -EFAULT;
+ ucontrols = compat_ptr(p);
+ if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(struct v4l2_ext_control)))
+ return -EFAULT;
+ kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
+ kp->controls = kcontrols;
+ while (--n >= 0) {
+ if (copy_in_user(&kcontrols->id, &ucontrols->id, sizeof(__u32)))
return -EFAULT;
+ if (copy_in_user(&kcontrols->reserved2, &ucontrols->reserved2, sizeof(ucontrols->reserved2)))
+ return -EFAULT;
+ /* Note: if the void * part of the union ever becomes relevant
+ then we need to know the type of the control in order to do
+ the right thing here. Luckily, that is not yet an issue. */
+ if (copy_in_user(&kcontrols->value, &ucontrols->value, sizeof(ucontrols->value)))
+ return -EFAULT;
+ ucontrols++;
+ kcontrols++;
+ }
return 0;
}
-#define VIDIOCGTUNER32 _IOWR('v', 4, struct video_tuner32)
-#define VIDIOCSTUNER32 _IOW('v', 5, struct video_tuner32)
-#define VIDIOCGWIN32 _IOR('v', 9, struct video_window32)
-#define VIDIOCSWIN32 _IOW('v', 10, struct video_window32)
-#define VIDIOCGFBUF32 _IOR('v', 11, struct video_buffer32)
-#define VIDIOCSFBUF32 _IOW('v', 12, struct video_buffer32)
-#define VIDIOCGFREQ32 _IOR('v', 14, u32)
-#define VIDIOCSFREQ32 _IOW('v', 15, u32)
-#define VIDIOCSMICROCODE32 _IOW('v', 27, struct video_code32)
-
-#endif
-
-/* VIDIOC_ENUMINPUT32 is VIDIOC_ENUMINPUT minus 4 bytes of padding alignement */
-#define VIDIOC_ENUMINPUT32 (VIDIOC_ENUMINPUT - _IOC(0, 0, 0, 4))
-#define VIDIOC_G_FMT32 _IOWR ('V', 4, struct v4l2_format32)
-#define VIDIOC_S_FMT32 _IOWR ('V', 5, struct v4l2_format32)
-#define VIDIOC_QUERYBUF32 _IOWR ('V', 9, struct v4l2_buffer32)
-#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
-#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)
-/* VIDIOC_OVERLAY is now _IOW, but was _IOWR */
-#define VIDIOC_OVERLAY32 _IOWR ('V', 14, compat_int_t)
-#define VIDIOC_QBUF32 _IOWR ('V', 15, struct v4l2_buffer32)
-#define VIDIOC_DQBUF32 _IOWR ('V', 17, struct v4l2_buffer32)
-#define VIDIOC_STREAMON32 _IOW ('V', 18, compat_int_t)
-#define VIDIOC_STREAMOFF32 _IOW ('V', 19, compat_int_t)
-#define VIDIOC_ENUMSTD32 _IOWR ('V', 25, struct v4l2_standard32)
-/* VIDIOC_S_CTRL is now _IOWR, but was _IOW */
-#define VIDIOC_S_CTRL32 _IOW ('V', 28, struct v4l2_control)
-#define VIDIOC_G_INPUT32 _IOR ('V', 38, compat_int_t)
-#define VIDIOC_S_INPUT32 _IOWR ('V', 39, compat_int_t)
-#define VIDIOC_TRY_FMT32 _IOWR ('V', 64, struct v4l2_format32)
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-enum {
- MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
-};
-
-static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg)
+static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
{
- struct video_window32 __user *up = compat_ptr(arg);
- struct video_window __user *vw;
- struct video_clip __user *p;
- int nclips;
- u32 n;
-
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)))
- return -EFAULT;
+ struct v4l2_ext_control __user *ucontrols;
+ struct v4l2_ext_control __user *kcontrols = kp->controls;
+ int n = kp->count;
+ compat_caddr_t p;
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
+ put_user(kp->ctrl_class, &up->ctrl_class) ||
+ put_user(kp->count, &up->count) ||
+ put_user(kp->error_idx, &up->error_idx) ||
+ copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+ return -EFAULT;
+ if (!kp->count)
+ return 0;
- if (get_user(nclips, &up->clipcount))
+ if (get_user(p, &up->controls))
return -EFAULT;
-
- /* Peculiar interface... */
- if (nclips < 0)
- nclips = VIDEO_CLIPMAP_SIZE;
-
- if (nclips > MaxClips)
- return -ENOMEM;
-
- vw = compat_alloc_user_space(sizeof(struct video_window) +
- nclips * sizeof(struct video_clip));
-
- p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
-
- if (get_user(n, &up->x) || put_user(n, &vw->x) ||
- get_user(n, &up->y) || put_user(n, &vw->y) ||
- get_user(n, &up->width) || put_user(n, &vw->width) ||
- get_user(n, &up->height) || put_user(n, &vw->height) ||
- get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
- get_user(n, &up->flags) || put_user(n, &vw->flags) ||
- get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
- get_user(n, &up->clips) || put_user(p, &vw->clips))
+ ucontrols = compat_ptr(p);
+ if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(struct v4l2_ext_control)))
return -EFAULT;
- if (nclips) {
- struct video_clip32 __user *u = compat_ptr(n);
- int i;
- if (!u)
- return -EINVAL;
- for (i = 0; i < nclips; i++, u++, p++) {
- s32 v;
- if (!access_ok(VERIFY_READ, u, sizeof(struct video_clip32)) ||
- !access_ok(VERIFY_WRITE, p, sizeof(struct video_clip32)) ||
- get_user(v, &u->x) ||
- put_user(v, &p->x) ||
- get_user(v, &u->y) ||
- put_user(v, &p->y) ||
- get_user(v, &u->width) ||
- put_user(v, &p->width) ||
- get_user(v, &u->height) ||
- put_user(v, &p->height) ||
- put_user(NULL, &p->next))
- return -EFAULT;
- }
+ while (--n >= 0) {
+ if (copy_in_user(&ucontrols->id, &kcontrols->id, sizeof(__u32)))
+ return -EFAULT;
+ if (copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
+ sizeof(ucontrols->reserved2)))
+ return -EFAULT;
+ /* Note: if the void * part of the union ever becomes relevant
+ then we need to know the type of the control in order to do
+ the right thing here. Luckily, that is not yet an issue. */
+ if (copy_in_user(&ucontrols->value, &kcontrols->value, sizeof(ucontrols->value)))
+ return -EFAULT;
+ ucontrols++;
+ kcontrols++;
}
-
- return native_ioctl(file, VIDIOCSWIN, (unsigned long)vw);
+ return 0;
}
-#endif
-static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+#define VIDIOC_G_FMT32 _IOWR('V', 4, struct v4l2_format32)
+#define VIDIOC_S_FMT32 _IOWR('V', 5, struct v4l2_format32)
+#define VIDIOC_QUERYBUF32 _IOWR('V', 9, struct v4l2_buffer32)
+#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
+#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)
+#define VIDIOC_QBUF32 _IOWR('V', 15, struct v4l2_buffer32)
+#define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32)
+#define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32)
+#define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32)
+#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
+#define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)
+#define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)
+#define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32)
+
+#define VIDIOC_OVERLAY32 _IOW ('V', 14, s32)
+#ifdef __OLD_VIDIOC_
+#define VIDIOC_OVERLAY32_OLD _IOWR('V', 14, s32)
+#endif
+#define VIDIOC_STREAMON32 _IOW ('V', 18, s32)
+#define VIDIOC_STREAMOFF32 _IOW ('V', 19, s32)
+#define VIDIOC_G_INPUT32 _IOR ('V', 38, s32)
+#define VIDIOC_S_INPUT32 _IOWR('V', 39, s32)
+#define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32)
+#define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32)
+
+static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
union {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -669,45 +723,53 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
struct v4l2_format v2f;
struct v4l2_buffer v2b;
struct v4l2_framebuffer v2fb;
- struct v4l2_standard v2s;
struct v4l2_input v2i;
- struct v4l2_tuner v2t;
+ struct v4l2_standard v2s;
+ struct v4l2_ext_controls v2ecs;
unsigned long vx;
+ int vi;
} karg;
void __user *up = compat_ptr(arg);
int compatible_arg = 1;
- int err = 0;
- int realcmd = cmd;
+ long err = 0;
/* First, convert the command. */
switch (cmd) {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGTUNER32: realcmd = cmd = VIDIOCGTUNER; break;
- case VIDIOCSTUNER32: realcmd = cmd = VIDIOCSTUNER; break;
- case VIDIOCGWIN32: realcmd = cmd = VIDIOCGWIN; break;
- case VIDIOCGFBUF32: realcmd = cmd = VIDIOCGFBUF; break;
- case VIDIOCSFBUF32: realcmd = cmd = VIDIOCSFBUF; break;
- case VIDIOCGFREQ32: realcmd = cmd = VIDIOCGFREQ; break;
- case VIDIOCSFREQ32: realcmd = cmd = VIDIOCSFREQ; break;
- case VIDIOCSMICROCODE32: realcmd = cmd = VIDIOCSMICROCODE; break;
+ case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+ case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+ case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+ case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
+ case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+ case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+ case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+ case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+ case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break;
+#endif
+ case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
+ case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
+ case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
+ case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
+ case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
+ case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
+ case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
+ case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
+ case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
+ case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
+ case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
+ case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
+ case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
+ case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
+#ifdef __OLD_VIDIOC_
+ case VIDIOC_OVERLAY32_OLD: cmd = VIDIOC_OVERLAY; break;
#endif
- case VIDIOC_G_FMT32: realcmd = cmd = VIDIOC_G_FMT; break;
- case VIDIOC_S_FMT32: realcmd = cmd = VIDIOC_S_FMT; break;
- case VIDIOC_QUERYBUF32: realcmd = cmd = VIDIOC_QUERYBUF; break;
- case VIDIOC_QBUF32: realcmd = cmd = VIDIOC_QBUF; break;
- case VIDIOC_DQBUF32: realcmd = cmd = VIDIOC_DQBUF; break;
- case VIDIOC_STREAMON32: realcmd = cmd = VIDIOC_STREAMON; break;
- case VIDIOC_STREAMOFF32: realcmd = cmd = VIDIOC_STREAMOFF; break;
- case VIDIOC_G_FBUF32: realcmd = cmd = VIDIOC_G_FBUF; break;
- case VIDIOC_S_FBUF32: realcmd = cmd = VIDIOC_S_FBUF; break;
- case VIDIOC_OVERLAY32: realcmd = cmd = VIDIOC_OVERLAY; break;
- case VIDIOC_ENUMSTD32: realcmd = VIDIOC_ENUMSTD; break;
- case VIDIOC_ENUMINPUT32: realcmd = VIDIOC_ENUMINPUT; break;
- case VIDIOC_S_CTRL32: realcmd = cmd = VIDIOC_S_CTRL; break;
- case VIDIOC_G_INPUT32: realcmd = cmd = VIDIOC_G_INPUT; break;
- case VIDIOC_S_INPUT32: realcmd = cmd = VIDIOC_S_INPUT; break;
- case VIDIOC_TRY_FMT32: realcmd = cmd = VIDIOC_TRY_FMT; break;
- };
+ case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
+ case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
+ case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
+ case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
+ case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
+ case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
+ }
switch (cmd) {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -715,7 +777,6 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case VIDIOCGTUNER:
err = get_video_tuner32(&karg.vt, up);
compatible_arg = 0;
-
break;
case VIDIOCSFBUF:
@@ -723,25 +784,42 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
compatible_arg = 0;
break;
-#if 0 /*FIXME*/
- case VIDIOCSAUDIO:
- err = get_video_audio32(&karg.va, up);
+ case VIDIOCSWIN:
+ err = get_video_window32(&karg.vw, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOCGWIN:
+ case VIDIOCGFBUF:
+ case VIDIOCGFREQ:
+ compatible_arg = 0;
+ break;
+
+ case VIDIOCSMICROCODE:
+ err = get_microcode32(&karg.vc, up);
compatible_arg = 0;
break;
-#endif
case VIDIOCSFREQ:
+ err = get_user(karg.vx, (u32 __user *)up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOCCAPTURE:
+ case VIDIOCSYNC:
+ case VIDIOCSWRITEMODE:
#endif
- case VIDIOC_S_INPUT:
case VIDIOC_OVERLAY:
case VIDIOC_STREAMON:
case VIDIOC_STREAMOFF:
- err = get_user(karg.vx, (u32 __user *)up);
- compatible_arg = 1;
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_OUTPUT:
+ err = get_user(karg.vi, (s32 __user *)up);
+ compatible_arg = 0;
break;
- case VIDIOC_S_FBUF:
- err = get_v4l2_framebuffer32(&karg.v2fb, up);
+ case VIDIOC_G_INPUT:
+ case VIDIOC_G_OUTPUT:
compatible_arg = 0;
break;
@@ -759,159 +837,162 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
compatible_arg = 0;
break;
- case VIDIOC_ENUMSTD:
- err = get_v4l2_standard(&karg.v2s, up);
+ case VIDIOC_S_FBUF:
+ err = get_v4l2_framebuffer32(&karg.v2fb, up);
compatible_arg = 0;
break;
- case VIDIOC_ENUMSTD32:
- err = get_v4l2_standard32(&karg.v2s, up);
+ case VIDIOC_G_FBUF:
compatible_arg = 0;
break;
- case VIDIOC_ENUMINPUT:
- err = get_v4l2_input(&karg.v2i, up);
+ case VIDIOC_ENUMSTD:
+ err = get_v4l2_standard32(&karg.v2s, up);
compatible_arg = 0;
break;
- case VIDIOC_ENUMINPUT32:
+ case VIDIOC_ENUMINPUT:
err = get_v4l2_input32(&karg.v2i, up);
compatible_arg = 0;
break;
- case VIDIOC_G_TUNER:
- case VIDIOC_S_TUNER:
- err = get_v4l2_tuner(&karg.v2t, up);
- compatible_arg = 0;
- break;
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGWIN:
- case VIDIOCGFBUF:
- case VIDIOCGFREQ:
-#endif
- case VIDIOC_G_FBUF:
- case VIDIOC_G_INPUT:
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ err = get_v4l2_ext_controls32(&karg.v2ecs, up);
compatible_arg = 0;
break;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCSMICROCODE:
- err = microcode32(&karg.vc, up);
- compatible_arg = 0;
- break;
-#endif
- };
+ }
if (err)
- goto out;
+ return err;
if (compatible_arg)
- err = native_ioctl(file, realcmd, (unsigned long)up);
+ err = native_ioctl(file, cmd, (unsigned long)up);
else {
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
- err = native_ioctl(file, realcmd, (unsigned long)&karg);
+ err = native_ioctl(file, cmd, (unsigned long)&karg);
set_fs(old_fs);
}
- if (err == 0) {
- switch (cmd) {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGTUNER:
- err = put_video_tuner32(&karg.vt, up);
- break;
-
- case VIDIOCGWIN:
- err = put_video_window32(&karg.vw, up);
- break;
-
- case VIDIOCGFBUF:
- err = put_video_buffer32(&karg.vb, up);
- break;
-#if 0 /*FIXME*/
- case VIDIOCGAUDIO:
- err = put_video_audio32(&karg.va, up);
- break;
-#endif
-#endif
- case VIDIOC_G_FBUF:
- err = put_v4l2_framebuffer32(&karg.v2fb, up);
- break;
-
- case VIDIOC_G_FMT:
- case VIDIOC_S_FMT:
- case VIDIOC_TRY_FMT:
- err = put_v4l2_format32(&karg.v2f, up);
- break;
-
- case VIDIOC_QUERYBUF:
- case VIDIOC_QBUF:
- case VIDIOC_DQBUF:
- err = put_v4l2_buffer32(&karg.v2b, up);
- break;
-
- case VIDIOC_ENUMSTD:
- err = put_v4l2_standard(&karg.v2s, up);
- break;
-
- case VIDIOC_ENUMSTD32:
- err = put_v4l2_standard32(&karg.v2s, up);
- break;
-
- case VIDIOC_G_TUNER:
- case VIDIOC_S_TUNER:
- err = put_v4l2_tuner(&karg.v2t, up);
- break;
-
- case VIDIOC_ENUMINPUT:
- err = put_v4l2_input(&karg.v2i, up);
- break;
-
- case VIDIOC_ENUMINPUT32:
- err = put_v4l2_input32(&karg.v2i, up);
- break;
+ /* Special case: even after an error we need to put the
+ results back for these ioctls since the error_idx will
+ contain information on which control failed. */
+ switch (cmd) {
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ if (put_v4l2_ext_controls32(&karg.v2ecs, up))
+ err = -EFAULT;
+ break;
+ }
+ if (err)
+ return err;
+ switch (cmd) {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGFREQ:
+ case VIDIOCGTUNER:
+ err = put_video_tuner32(&karg.vt, up);
+ break;
+
+ case VIDIOCGWIN:
+ err = put_video_window32(&karg.vw, up);
+ break;
+
+ case VIDIOCGFBUF:
+ err = put_video_buffer32(&karg.vb, up);
+ break;
+
+ case VIDIOCGFREQ:
+ err = put_user(((u32)karg.vx), (u32 __user *)up);
+ break;
#endif
- case VIDIOC_G_INPUT:
- err = put_user(((u32)karg.vx), (u32 __user *)up);
- break;
- };
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_OUTPUT:
+ case VIDIOC_G_INPUT:
+ case VIDIOC_G_OUTPUT:
+ err = put_user(((s32)karg.vi), (s32 __user *)up);
+ break;
+
+ case VIDIOC_G_FBUF:
+ err = put_v4l2_framebuffer32(&karg.v2fb, up);
+ break;
+
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+ err = put_v4l2_format32(&karg.v2f, up);
+ break;
+
+ case VIDIOC_QUERYBUF:
+ case VIDIOC_QBUF:
+ case VIDIOC_DQBUF:
+ err = put_v4l2_buffer32(&karg.v2b, up);
+ break;
+
+ case VIDIOC_ENUMSTD:
+ err = put_v4l2_standard32(&karg.v2s, up);
+ break;
+
+ case VIDIOC_ENUMINPUT:
+ err = put_v4l2_input32(&karg.v2i, up);
+ break;
}
-out:
return err;
}
-long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
+long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
{
- int ret = -ENOIOCTLCMD;
+ long ret = -ENOIOCTLCMD;
- if (!file->f_op->ioctl)
+ if (!file->f_op->ioctl && !file->f_op->unlocked_ioctl)
return ret;
switch (cmd) {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCSWIN32:
- ret = do_set_window(file, cmd, arg);
- break;
+ case VIDIOCGCAP:
+ case VIDIOCGCHAN:
+ case VIDIOCSCHAN:
case VIDIOCGTUNER32:
case VIDIOCSTUNER32:
+ case VIDIOCGPICT:
+ case VIDIOCSPICT:
+ case VIDIOCCAPTURE32:
case VIDIOCGWIN32:
+ case VIDIOCSWIN32:
case VIDIOCGFBUF32:
case VIDIOCSFBUF32:
+ case VIDIOCKEY:
case VIDIOCGFREQ32:
case VIDIOCSFREQ32:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
+ case VIDIOCSYNC32:
+ case VIDIOCMCAPTURE:
+ case VIDIOCGMBUF:
+ case VIDIOCGUNIT:
+ case VIDIOCGCAPTURE:
+ case VIDIOCSCAPTURE:
+ case VIDIOCSPLAYMODE:
+ case VIDIOCSWRITEMODE32:
+ case VIDIOCGPLAYINFO:
+ case VIDIOCSMICROCODE32:
case VIDIOCGVBIFMT:
case VIDIOCSVBIFMT:
#endif
+#ifdef __OLD_VIDIOC_
+ case VIDIOC_OVERLAY32_OLD:
+ case VIDIOC_S_PARM_OLD:
+ case VIDIOC_S_CTRL_OLD:
+ case VIDIOC_G_AUDIO_OLD:
+ case VIDIOC_G_AUDOUT_OLD:
+ case VIDIOC_CROPCAP_OLD:
+#endif
case VIDIOC_QUERYCAP:
+ case VIDIOC_RESERVED:
case VIDIOC_ENUM_FMT:
case VIDIOC_G_FMT32:
- case VIDIOC_CROPCAP:
- case VIDIOC_S_CROP:
case VIDIOC_S_FMT32:
case VIDIOC_REQBUFS:
case VIDIOC_QUERYBUF32:
@@ -926,43 +1007,57 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_S_PARM:
case VIDIOC_G_STD:
case VIDIOC_S_STD:
- case VIDIOC_G_TUNER:
- case VIDIOC_S_TUNER:
- case VIDIOC_ENUMSTD:
case VIDIOC_ENUMSTD32:
- case VIDIOC_ENUMINPUT:
case VIDIOC_ENUMINPUT32:
case VIDIOC_G_CTRL:
case VIDIOC_S_CTRL:
- case VIDIOC_S_CTRL32:
- case VIDIOC_S_FREQUENCY:
- case VIDIOC_G_FREQUENCY:
+ case VIDIOC_G_TUNER:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_G_AUDIO:
+ case VIDIOC_S_AUDIO:
case VIDIOC_QUERYCTRL:
+ case VIDIOC_QUERYMENU:
case VIDIOC_G_INPUT32:
case VIDIOC_S_INPUT32:
+ case VIDIOC_G_OUTPUT32:
+ case VIDIOC_S_OUTPUT32:
+ case VIDIOC_ENUMOUTPUT:
+ case VIDIOC_G_AUDOUT:
+ case VIDIOC_S_AUDOUT:
+ case VIDIOC_G_MODULATOR:
+ case VIDIOC_S_MODULATOR:
+ case VIDIOC_S_FREQUENCY:
+ case VIDIOC_G_FREQUENCY:
+ case VIDIOC_CROPCAP:
+ case VIDIOC_G_CROP:
+ case VIDIOC_S_CROP:
+ case VIDIOC_G_JPEGCOMP:
+ case VIDIOC_S_JPEGCOMP:
+ case VIDIOC_QUERYSTD:
case VIDIOC_TRY_FMT32:
- case VIDIOC_S_HW_FREQ_SEEK:
+ case VIDIOC_ENUMAUDIO:
+ case VIDIOC_ENUMAUDOUT:
+ case VIDIOC_G_PRIORITY:
+ case VIDIOC_S_PRIORITY:
+ case VIDIOC_G_SLICED_VBI_CAP:
+ case VIDIOC_LOG_STATUS:
+ case VIDIOC_G_EXT_CTRLS32:
+ case VIDIOC_S_EXT_CTRLS32:
+ case VIDIOC_TRY_EXT_CTRLS32:
case VIDIOC_ENUM_FRAMESIZES:
case VIDIOC_ENUM_FRAMEINTERVALS:
+ case VIDIOC_G_ENC_INDEX:
+ case VIDIOC_ENCODER_CMD:
+ case VIDIOC_TRY_ENCODER_CMD:
+ case VIDIOC_DBG_S_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_G_CHIP_IDENT:
+ case VIDIOC_G_CHIP_IDENT_OLD:
+ case VIDIOC_S_HW_FREQ_SEEK:
ret = do_video_ioctl(file, cmd, arg);
break;
#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /* Little v, the video4linux ioctls (conflict?) */
- case VIDIOCGCAP:
- case VIDIOCGCHAN:
- case VIDIOCSCHAN:
- case VIDIOCGPICT:
- case VIDIOCSPICT:
- case VIDIOCCAPTURE:
- case VIDIOCKEY:
- case VIDIOCSYNC:
- case VIDIOCMCAPTURE:
- case VIDIOCGMBUF:
- case VIDIOCGUNIT:
- case VIDIOCGCAPTURE:
- case VIDIOCSCAPTURE:
-
/* BTTV specific... */
case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]):
case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]):
@@ -976,16 +1071,14 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
break;
#endif
default:
- v4l_print_ioctl("compat_ioctl32", cmd);
+ printk(KERN_WARNING "compat_ioctl32: "
+ "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
+ _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
+ break;
}
return ret;
}
-#else
-long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
-{
- return -ENOIOCTLCMD;
-}
+EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);
#endif
-EXPORT_SYMBOL_GPL(v4l_compat_ioctl32);
MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/v4l2-dev.c b/linux/drivers/media/video/v4l2-dev.c
index 3b8f33c8d..9e34e9ec2 100644
--- a/linux/drivers/media/video/v4l2-dev.c
+++ b/linux/drivers/media/video/v4l2-dev.c
@@ -30,6 +30,8 @@
#include <asm/system.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
#include "compat.h"
#define VIDEO_NUM_DEVICES 256
@@ -43,17 +45,17 @@
static ssize_t show_index(struct device *cd,
struct device_attribute *attr, char *buf)
{
- struct video_device *vfd = container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
- return sprintf(buf, "%i\n", vfd->index);
+ return sprintf(buf, "%i\n", vdev->index);
}
static ssize_t show_name(struct device *cd,
struct device_attribute *attr, char *buf)
{
- struct video_device *vfd = container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
- return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
+ return sprintf(buf, "%.*s\n", (int)sizeof(vdev->name), vdev->name);
}
static struct device_attribute video_device_attrs[] = {
@@ -64,16 +66,16 @@ static struct device_attribute video_device_attrs[] = {
#else
static ssize_t show_index(struct class_device *cd, char *buf)
{
- struct video_device *vfd = container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
- return sprintf(buf, "%i\n", vfd->index);
+ return sprintf(buf, "%i\n", vdev->index);
}
static ssize_t show_name(struct class_device *cd, char *buf)
{
- struct video_device *vfd = container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
- return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
+ return sprintf(buf, "%.*s\n", (int)sizeof(vdev->name), vdev->name);
}
static CLASS_DEVICE_ATTR(index, S_IRUGO, show_index, NULL);
@@ -93,71 +95,77 @@ struct video_device *video_device_alloc(void)
}
EXPORT_SYMBOL(video_device_alloc);
-void video_device_release(struct video_device *vfd)
+void video_device_release(struct video_device *vdev)
{
- kfree(vfd);
+ kfree(vdev);
}
EXPORT_SYMBOL(video_device_release);
-void video_device_release_empty(struct video_device *vfd)
+void video_device_release_empty(struct video_device *vdev)
{
/* Do nothing */
/* Only valid when the video_device struct is a static. */
}
EXPORT_SYMBOL(video_device_release_empty);
-/* Called when the last user of the character device is gone. */
-static void v4l2_chardev_release(struct kobject *kobj)
+static inline void video_get(struct video_device *vdev)
{
- struct video_device *vfd = container_of(kobj, struct video_device, cdev.kobj);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+ class_device_get(&vdev->dev);
+#else
+ get_device(&vdev->dev);
+#endif
+}
+
+static inline void video_put(struct video_device *vdev)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+ class_device_put(&vdev->dev);
+#else
+ put_device(&vdev->dev);
+#endif
+}
+
+/* Called when the last user of the video device exits. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static void v4l2_device_release(struct class_device *cd)
+#else
+static void v4l2_device_release(struct device *cd)
+#endif
+{
+ struct video_device *vdev = to_video_device(cd);
mutex_lock(&videodev_lock);
- if (video_device[vfd->minor] != vfd) {
+ if (video_device[vdev->minor] != vdev) {
mutex_unlock(&videodev_lock);
- BUG();
+ /* should not happen */
+ WARN_ON(1);
return;
}
/* Free up this device for reuse */
- video_device[vfd->minor] = NULL;
- clear_bit(vfd->num, video_nums[vfd->vfl_type]);
- mutex_unlock(&videodev_lock);
+ video_device[vdev->minor] = NULL;
- /* Release the character device */
- vfd->cdev_release(kobj);
- /* Release video_device and perform other
- cleanups as needed. */
- if (vfd->release)
- vfd->release(vfd);
-}
+ /* Delete the cdev on this minor as well */
+ cdev_del(vdev->cdev);
+ /* Just in case some driver tries to access this from
+ the release() callback. */
+ vdev->cdev = NULL;
-/* The new kobj_type for the character device */
-static struct kobj_type v4l2_ktype_cdev_default = {
- .release = v4l2_chardev_release,
-};
+ /* Mark minor as free */
+ clear_bit(vdev->num, video_nums[vdev->vfl_type]);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
-static void video_release(struct class_device *cd)
-#else
-static void video_release(struct device *cd)
-#endif
-{
- struct video_device *vfd = container_of(cd, struct video_device, dev);
+ mutex_unlock(&videodev_lock);
- /* It's now safe to delete the char device.
- This will either trigger the v4l2_chardev_release immediately (if
- the refcount goes to 0) or later when the last user of the
- character device closes it. */
- cdev_del(&vfd->cdev);
+ /* Release video_device and perform other
+ cleanups as needed. */
+ vdev->release(vdev);
}
static struct class video_class = {
.name = VIDEO_NAME,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
- .release = video_release,
-#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
.dev_attrs = video_device_attrs,
- .dev_release = video_release,
#endif
};
@@ -171,13 +179,149 @@ struct video_device *video_devdata(struct file *file)
}
EXPORT_SYMBOL(video_devdata);
+static ssize_t v4l2_read(struct file *filp, char __user *buf,
+ size_t sz, loff_t *off)
+{
+ struct video_device *vdev = video_devdata(filp);
+
+ if (!vdev->fops->read)
+ return -EINVAL;
+ if (video_is_unregistered(vdev))
+ return -EIO;
+ return vdev->fops->read(filp, buf, sz, off);
+}
+
+static ssize_t v4l2_write(struct file *filp, const char __user *buf,
+ size_t sz, loff_t *off)
+{
+ struct video_device *vdev = video_devdata(filp);
+
+ if (!vdev->fops->write)
+ return -EINVAL;
+ if (video_is_unregistered(vdev))
+ return -EIO;
+ return vdev->fops->write(filp, buf, sz, off);
+}
+
+static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
+{
+ struct video_device *vdev = video_devdata(filp);
+
+ if (!vdev->fops->poll || video_is_unregistered(vdev))
+ return DEFAULT_POLLMASK;
+ return vdev->fops->poll(filp, poll);
+}
+
+static int v4l2_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct video_device *vdev = video_devdata(filp);
+
+ if (!vdev->fops->ioctl)
+ return -ENOTTY;
+ /* Allow ioctl to continue even if the device was unregistered.
+ Things like dequeueing buffers might still be useful. */
+ return vdev->fops->ioctl(filp, cmd, arg);
+}
+
+static long v4l2_unlocked_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct video_device *vdev = video_devdata(filp);
+
+ if (!vdev->fops->unlocked_ioctl)
+ return -ENOTTY;
+ /* Allow ioctl to continue even if the device was unregistered.
+ Things like dequeueing buffers might still be useful. */
+ return vdev->fops->unlocked_ioctl(filp, cmd, arg);
+}
+
+static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
+{
+ struct video_device *vdev = video_devdata(filp);
+
+ if (!vdev->fops->mmap ||
+ video_is_unregistered(vdev))
+ return -ENODEV;
+ return vdev->fops->mmap(filp, vm);
+}
+
+/* Override for the open function */
+static int v4l2_open(struct inode *inode, struct file *filp)
+{
+ struct video_device *vdev;
+ int ret;
+
+ /* Check if the video device is available */
+ mutex_lock(&videodev_lock);
+ vdev = video_devdata(filp);
+ /* return ENODEV if the video device has been removed
+ already or if it is not registered anymore. */
+ if (vdev == NULL || video_is_unregistered(vdev)) {
+ mutex_unlock(&videodev_lock);
+ return -ENODEV;
+ }
+ /* and increase the device refcount */
+ video_get(vdev);
+ mutex_unlock(&videodev_lock);
+ ret = vdev->fops->open(filp);
+ /* decrease the refcount in case of an error */
+ if (ret)
+ video_put(vdev);
+ return ret;
+}
+
+/* Override for the release function */
+static int v4l2_release(struct inode *inode, struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ int ret = vdev->fops->release(filp);
+
+ /* decrease the refcount unconditionally since the release()
+ return value is ignored. */
+ video_put(vdev);
+ return ret;
+}
+
+static const struct file_operations v4l2_unlocked_fops = {
+ .owner = THIS_MODULE,
+ .read = v4l2_read,
+ .write = v4l2_write,
+ .open = v4l2_open,
+ .mmap = v4l2_mmap,
+ .unlocked_ioctl = v4l2_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = v4l2_compat_ioctl32,
+#endif
+ .release = v4l2_release,
+ .poll = v4l2_poll,
+ .llseek = no_llseek,
+};
+
+static const struct file_operations v4l2_fops = {
+ .owner = THIS_MODULE,
+ .read = v4l2_read,
+ .write = v4l2_write,
+ .open = v4l2_open,
+ .mmap = v4l2_mmap,
+ .ioctl = v4l2_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = v4l2_compat_ioctl32,
+#endif
+ .release = v4l2_release,
+ .poll = v4l2_poll,
+ .llseek = no_llseek,
+};
+
/**
* get_index - assign stream number based on parent device
- * @vdev: video_device to assign index number to, vdev->dev should be assigned
- * @num: -1 if auto assign, requested number otherwise
+ * @vdev: video_device to assign index number to, vdev->parent should be assigned
+ * @num: -1 if auto assign, requested number otherwise
*
+ * Note that when this is called the new device has not yet been registered
+ * in the video_device array.
*
- * returns -ENFILE if num is already in use, a free index number if
+ * Returns -ENFILE if num is already in use, a free index number if
* successful.
*/
static int get_index(struct video_device *vdev, int num)
@@ -194,9 +338,12 @@ static int get_index(struct video_device *vdev, int num)
return -EINVAL;
}
+ /* Some drivers do not set the parent. In that case always return 0. */
+ if (vdev->parent == NULL)
+ return 0;
+
for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
if (video_device[i] != NULL &&
- video_device[i] != vdev &&
video_device[i]->parent == vdev->parent) {
used |= 1 << video_device[i]->index;
}
@@ -212,17 +359,15 @@ static int get_index(struct video_device *vdev, int num)
return i > max_index ? -ENFILE : i;
}
-static const struct file_operations video_fops;
-
-int video_register_device(struct video_device *vfd, int type, int nr)
+int video_register_device(struct video_device *vdev, int type, int nr)
{
- return video_register_device_index(vfd, type, nr, -1);
+ return video_register_device_index(vdev, type, nr, -1);
}
EXPORT_SYMBOL(video_register_device);
/**
* video_register_device_index - register video4linux devices
- * @vfd: video device structure we want to register
+ * @vdev: video device structure we want to register
* @type: type of device to register
* @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ...
* -1 == first free)
@@ -246,8 +391,7 @@ EXPORT_SYMBOL(video_register_device);
*
* %VFL_TYPE_RADIO - A radio card
*/
-
-int video_register_device_index(struct video_device *vfd, int type, int nr,
+int video_register_device_index(struct video_device *vdev, int type, int nr,
int index)
{
int i = 0;
@@ -255,14 +399,19 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
int minor_offset = 0;
int minor_cnt = VIDEO_NUM_DEVICES;
const char *name_base;
- void *priv = video_get_drvdata(vfd);
+ void *priv = video_get_drvdata(vdev);
- /* the release callback MUST be present */
- BUG_ON(!vfd->release);
+ /* A minor value of -1 marks this video device as never
+ having been registered */
+ if (vdev)
+ vdev->minor = -1;
- if (vfd == NULL)
+ /* the release callback MUST be present */
+ WARN_ON(!vdev || !vdev->release);
+ if (!vdev || !vdev->release)
return -EINVAL;
+ /* Part 1: check device type */
switch (type) {
case VFL_TYPE_GRABBER:
name_base = "video";
@@ -282,8 +431,12 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
return -EINVAL;
}
- vfd->vfl_type = type;
+ vdev->vfl_type = type;
+ vdev->cdev = NULL;
+ if (vdev->v4l2_dev)
+ vdev->parent = vdev->v4l2_dev->dev;
+ /* Part 2: find a free minor, kernel number and device index. */
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
/* Keep the ranges for the first four types for historical
* reasons.
@@ -314,14 +467,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
}
#endif
- /* Initialize the character device */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
- cdev_init(&vfd->cdev, vfd->fops);
-#else
- cdev_init(&vfd->cdev, (struct file_operations *)vfd->fops);
-#endif
- vfd->cdev.owner = vfd->fops->owner;
- /* pick a minor number */
+ /* Pick a minor number */
mutex_lock(&videodev_lock);
nr = find_next_zero_bit(video_nums[type], minor_cnt, nr == -1 ? 0 : nr);
if (nr == minor_cnt)
@@ -345,98 +491,125 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
return -ENFILE;
}
#endif
- vfd->minor = i + minor_offset;
- vfd->num = nr;
+ vdev->minor = i + minor_offset;
+ vdev->num = nr;
set_bit(nr, video_nums[type]);
- BUG_ON(video_device[vfd->minor]);
- video_device[vfd->minor] = vfd;
-
- ret = get_index(vfd, index);
- vfd->index = ret;
-
+ /* Should not happen since we thought this minor was free */
+ WARN_ON(video_device[vdev->minor] != NULL);
+ ret = vdev->index = get_index(vdev, index);
mutex_unlock(&videodev_lock);
if (ret < 0) {
printk(KERN_ERR "%s: get_index failed\n", __func__);
- goto fail_minor;
+ goto cleanup;
}
- ret = cdev_add(&vfd->cdev, MKDEV(VIDEO_MAJOR, vfd->minor), 1);
+ /* Part 3: Initialize the character device */
+ vdev->cdev = cdev_alloc();
+ if (vdev->cdev == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
+ if (vdev->fops->unlocked_ioctl)
+ vdev->cdev->ops = &v4l2_unlocked_fops;
+ else
+ vdev->cdev->ops = &v4l2_fops;
+#else
+ if (vdev->fops->unlocked_ioctl)
+ vdev->cdev->ops = (struct file_operations *)&v4l2_unlocked_fops;
+ else
+ vdev->cdev->ops = (struct file_operations *)&v4l2_fops;
+#endif
+ vdev->cdev->owner = vdev->fops->owner;
+ ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
if (ret < 0) {
printk(KERN_ERR "%s: cdev_add failed\n", __func__);
- goto fail_minor;
+ kfree(vdev->cdev);
+ vdev->cdev = NULL;
+ goto cleanup;
}
- /* sysfs class */
- memset(&vfd->dev, 0, sizeof(vfd->dev));
+
+ /* Part 4: register the device with sysfs */
+ memset(&vdev->dev, 0, sizeof(vdev->dev));
/* The memset above cleared the device's drvdata, so
put back the copy we made earlier. */
- video_set_drvdata(vfd, priv);
- vfd->dev.class = &video_class;
- vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
+ video_set_drvdata(vdev, priv);
+ vdev->dev.class = &video_class;
+ vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
- if (vfd->parent)
- vfd->dev.dev = vfd->parent;
- sprintf(vfd->dev.class_id, "%s%d", name_base, nr);
- ret = class_device_register(&vfd->dev);
+ if (vdev->parent)
+ vdev->dev.dev = vdev->parent;
+ sprintf(vdev->dev.class_id, "%s%d", name_base, nr);
+ ret = class_device_register(&vdev->dev);
#else
- if (vfd->parent)
- vfd->dev.parent = vfd->parent;
- dev_set_name(&vfd->dev, "%s%d", name_base, nr);
- ret = device_register(&vfd->dev);
+ if (vdev->parent)
+ vdev->dev.parent = vdev->parent;
+ dev_set_name(&vdev->dev, "%s%d", name_base, nr);
+ ret = device_register(&vdev->dev);
#endif
if (ret < 0) {
printk(KERN_ERR "%s: device_register failed\n", __func__);
- goto del_cdev;
+ goto cleanup;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
- ret = class_device_create_file(&vfd->dev, &class_device_attr_name);
+ ret = class_device_create_file(&vdev->dev, &class_device_attr_name);
if (ret < 0) {
printk(KERN_ERR "%s: class_device_create_file 'name' failed\n",
__func__);
- class_device_unregister(&vfd->dev);
- goto del_cdev;
+ class_device_unregister(&vdev->dev);
+ goto cleanup;
}
- ret = class_device_create_file(&vfd->dev, &class_device_attr_index);
+ ret = class_device_create_file(&vdev->dev, &class_device_attr_index);
if (ret < 0) {
printk(KERN_ERR "%s: class_device_create_file 'index' failed\n",
__func__);
- class_device_unregister(&vfd->dev);
- goto del_cdev;
+ class_device_unregister(&vdev->dev);
+ goto cleanup;
}
#endif
- /* Remember the cdev's release function */
- vfd->cdev_release = vfd->cdev.kobj.ktype->release;
- /* Install our own */
- vfd->cdev.kobj.ktype = &v4l2_ktype_cdev_default;
- return 0;
+ /* Register the release callback that will be called when the last
+ reference to the device goes away. */
+ vdev->dev.release = v4l2_device_release;
-del_cdev:
- cdev_del(&vfd->cdev);
+ /* Part 5: Activate this minor. The char device can now be used. */
+ mutex_lock(&videodev_lock);
+ video_device[vdev->minor] = vdev;
+ mutex_unlock(&videodev_lock);
+ return 0;
-fail_minor:
+cleanup:
mutex_lock(&videodev_lock);
- video_device[vfd->minor] = NULL;
- clear_bit(vfd->num, video_nums[type]);
+ if (vdev->cdev)
+ cdev_del(vdev->cdev);
+ clear_bit(vdev->num, video_nums[type]);
mutex_unlock(&videodev_lock);
- vfd->minor = -1;
+ /* Mark this video device as never having been registered. */
+ vdev->minor = -1;
return ret;
}
EXPORT_SYMBOL(video_register_device_index);
/**
* video_unregister_device - unregister a video4linux device
- * @vfd: the device to unregister
+ * @vdev: the device to unregister
*
- * This unregisters the passed device and deassigns the minor
- * number. Future open calls will be met with errors.
+ * This unregisters the passed device. Future open calls will
+ * be met with errors.
*/
-
-void video_unregister_device(struct video_device *vfd)
+void video_unregister_device(struct video_device *vdev)
{
+ /* Check if vdev was ever registered at all */
+ if (!vdev || vdev->minor < 0)
+ return;
+
+ mutex_lock(&videodev_lock);
+ set_bit(V4L2_FL_UNREGISTERED, &vdev->flags);
+ mutex_unlock(&videodev_lock);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
- class_device_unregister(&vfd->dev);
+ class_device_unregister(&vdev->dev);
#else
- device_unregister(&vfd->dev);
+ device_unregister(&vdev->dev);
#endif
}
EXPORT_SYMBOL(video_unregister_device);
diff --git a/linux/drivers/media/video/v4l2-device.c b/linux/drivers/media/video/v4l2-device.c
new file mode 100644
index 000000000..9eefde031
--- /dev/null
+++ b/linux/drivers/media/video/v4l2-device.c
@@ -0,0 +1,86 @@
+/*
+ V4L2 device support.
+
+ Copyright (C) 2008 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+
+int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
+{
+ if (dev == NULL || v4l2_dev == NULL)
+ return -EINVAL;
+ /* Warn if we apparently re-register a device */
+ WARN_ON(dev_get_drvdata(dev));
+ INIT_LIST_HEAD(&v4l2_dev->subdevs);
+ spin_lock_init(&v4l2_dev->lock);
+ v4l2_dev->dev = dev;
+ snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
+ dev->driver->name, dev->bus_id);
+ dev_set_drvdata(dev, v4l2_dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_device_register);
+
+void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
+{
+ struct v4l2_subdev *sd, *next;
+
+ if (v4l2_dev == NULL || v4l2_dev->dev == NULL)
+ return;
+ dev_set_drvdata(v4l2_dev->dev, NULL);
+ /* unregister subdevs */
+ list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list)
+ v4l2_device_unregister_subdev(sd);
+
+ v4l2_dev->dev = NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_device_unregister);
+
+int v4l2_device_register_subdev(struct v4l2_device *dev, struct v4l2_subdev *sd)
+{
+ /* Check for valid input */
+ if (dev == NULL || sd == NULL || !sd->name[0])
+ return -EINVAL;
+ /* Warn if we apparently re-register a subdev */
+ WARN_ON(sd->dev);
+ if (!try_module_get(sd->owner))
+ return -ENODEV;
+ sd->dev = dev;
+ spin_lock(&dev->lock);
+ list_add_tail(&sd->list, &dev->subdevs);
+ spin_unlock(&dev->lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
+
+void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
+{
+ /* return if it isn't registered */
+ if (sd == NULL || sd->dev == NULL)
+ return;
+ spin_lock(&sd->dev->lock);
+ list_del(&sd->list);
+ spin_unlock(&sd->dev->lock);
+ sd->dev = NULL;
+ module_put(sd->owner);
+}
+EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c
index 86dd04026..165bc9005 100644
--- a/linux/drivers/media/video/v4l2-ioctl.c
+++ b/linux/drivers/media/video/v4l2-ioctl.c
@@ -267,7 +267,7 @@ static const char *v4l2_ioctls[] = {
[_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER",
[_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER",
- [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT",
+ [_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT",
[_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK",
#endif
};
@@ -393,14 +393,14 @@ video_fix_command(unsigned int cmd)
/*
* Obsolete usercopy function - Should be removed soon
*/
-int
+long
video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
v4l2_kioctl func)
{
char sbuf[128];
void *mbuf = NULL;
void *parg = NULL;
- int err = -EINVAL;
+ long err = -EINVAL;
int is_ext_ctrl;
size_t ctrls_size = 0;
void __user *user_ptr = NULL;
@@ -624,13 +624,13 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
return -EINVAL;
}
-static int __video_do_ioctl(struct file *file,
+static long __video_do_ioctl(struct file *file,
unsigned int cmd, void *arg)
{
struct video_device *vfd = video_devdata(file);
const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
void *fh = file->private_data;
- int ret = -EINVAL;
+ long ret = -EINVAL;
if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
@@ -1721,7 +1721,7 @@ static int __video_do_ioctl(struct file *file,
#ifdef CONFIG_VIDEO_ADV_DEBUG
case VIDIOC_DBG_G_REGISTER:
{
- struct v4l2_register *p = arg;
+ struct v4l2_dbg_register *p = arg;
if (!capable(CAP_SYS_ADMIN))
ret = -EPERM;
@@ -1731,7 +1731,7 @@ static int __video_do_ioctl(struct file *file,
}
case VIDIOC_DBG_S_REGISTER:
{
- struct v4l2_register *p = arg;
+ struct v4l2_dbg_register *p = arg;
if (!capable(CAP_SYS_ADMIN))
ret = -EPERM;
@@ -1740,9 +1740,9 @@ static int __video_do_ioctl(struct file *file,
break;
}
#endif
- case VIDIOC_G_CHIP_IDENT:
+ case VIDIOC_DBG_G_CHIP_IDENT:
{
- struct v4l2_chip_ident *p = arg;
+ struct v4l2_dbg_chip_ident *p = arg;
if (!ops->vidioc_g_chip_ident)
break;
@@ -1751,6 +1751,11 @@ static int __video_do_ioctl(struct file *file,
dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
break;
}
+ case VIDIOC_G_CHIP_IDENT_OLD:
+ printk(KERN_ERR "VIDIOC_G_CHIP_IDENT has been deprecated and will disappear in 2.6.30.\n");
+ printk(KERN_ERR "It is a debugging ioctl and must not be used in applications!\n");
+ return -EINVAL;
+
case VIDIOC_S_HW_FREQ_SEEK:
{
struct v4l2_hw_freq_seek *p = arg;
@@ -1846,20 +1851,20 @@ static int __video_do_ioctl(struct file *file,
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
if (ret < 0) {
v4l_print_ioctl(vfd->name, cmd);
- printk(KERN_CONT " error %d\n", ret);
+ printk(KERN_CONT " error %ld\n", ret);
}
}
return ret;
}
-int __video_ioctl2(struct file *file,
+long video_ioctl2(struct file *file,
unsigned int cmd, unsigned long arg)
{
char sbuf[128];
void *mbuf = NULL;
void *parg = NULL;
- int err = -EINVAL;
+ long err = -EINVAL;
int is_ext_ctrl;
size_t ctrls_size = 0;
void __user *user_ptr = NULL;
@@ -1945,11 +1950,4 @@ out:
kfree(mbuf);
return err;
}
-EXPORT_SYMBOL(__video_ioctl2);
-
-int video_ioctl2(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return __video_ioctl2(file, cmd, arg);
-}
EXPORT_SYMBOL(video_ioctl2);
diff --git a/linux/drivers/media/video/v4l2-subdev.c b/linux/drivers/media/video/v4l2-subdev.c
new file mode 100644
index 000000000..fbe9cc0d4
--- /dev/null
+++ b/linux/drivers/media/video/v4l2-subdev.c
@@ -0,0 +1,110 @@
+/*
+ V4L2 sub-device support.
+
+ Copyright (C) 2008 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+
+int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg)
+{
+ switch (cmd) {
+ case VIDIOC_QUERYCTRL:
+ return v4l2_subdev_call(sd, core, querymenu, arg);
+ case VIDIOC_G_CTRL:
+ return v4l2_subdev_call(sd, core, g_ctrl, arg);
+ case VIDIOC_S_CTRL:
+ return v4l2_subdev_call(sd, core, s_ctrl, arg);
+ case VIDIOC_QUERYMENU:
+ return v4l2_subdev_call(sd, core, queryctrl, arg);
+ case VIDIOC_LOG_STATUS:
+ return v4l2_subdev_call(sd, core, log_status);
+ case VIDIOC_DBG_G_CHIP_IDENT:
+ return v4l2_subdev_call(sd, core, g_chip_ident, arg);
+ case VIDIOC_INT_S_STANDBY:
+ return v4l2_subdev_call(sd, core, s_standby, arg ? (*(u32 *)arg) : 0);
+ case VIDIOC_INT_RESET:
+ return v4l2_subdev_call(sd, core, reset, arg ? (*(u32 *)arg) : 0);
+ case VIDIOC_INT_S_GPIO:
+ return v4l2_subdev_call(sd, core, s_gpio, arg ? (*(u32 *)arg) : 0);
+ case VIDIOC_INT_INIT:
+ return v4l2_subdev_call(sd, core, init, arg ? (*(u32 *)arg) : 0);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_DBG_G_REGISTER:
+ return v4l2_subdev_call(sd, core, g_register, arg);
+ case VIDIOC_DBG_S_REGISTER:
+ return v4l2_subdev_call(sd, core, s_register, arg);
+#endif
+
+ case VIDIOC_INT_S_TUNER_MODE:
+ return v4l2_subdev_call(sd, tuner, s_mode, *(enum v4l2_tuner_type *)arg);
+ case AUDC_SET_RADIO:
+ return v4l2_subdev_call(sd, tuner, s_radio);
+ case VIDIOC_S_TUNER:
+ return v4l2_subdev_call(sd, tuner, s_tuner, arg);
+ case VIDIOC_G_TUNER:
+ return v4l2_subdev_call(sd, tuner, g_tuner, arg);
+ case VIDIOC_S_STD:
+ return v4l2_subdev_call(sd, tuner, s_std, *(v4l2_std_id *)arg);
+ case VIDIOC_S_FREQUENCY:
+ return v4l2_subdev_call(sd, tuner, s_frequency, arg);
+ case VIDIOC_G_FREQUENCY:
+ return v4l2_subdev_call(sd, tuner, g_frequency, arg);
+ case TUNER_SET_TYPE_ADDR:
+ return v4l2_subdev_call(sd, tuner, s_type_addr, arg);
+ case TUNER_SET_CONFIG:
+ return v4l2_subdev_call(sd, tuner, s_config, arg);
+
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ return v4l2_subdev_call(sd, audio, s_clock_freq, *(u32 *)arg);
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ return v4l2_subdev_call(sd, audio, s_routing, arg);
+ case VIDIOC_INT_I2S_CLOCK_FREQ:
+ return v4l2_subdev_call(sd, audio, s_i2s_clock_freq, *(u32 *)arg);
+
+ case VIDIOC_INT_S_VIDEO_ROUTING:
+ return v4l2_subdev_call(sd, video, s_routing, arg);
+ case VIDIOC_INT_S_CRYSTAL_FREQ:
+ return v4l2_subdev_call(sd, video, s_crystal_freq, arg);
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ return v4l2_subdev_call(sd, video, decode_vbi_line, arg);
+ case VIDIOC_INT_S_VBI_DATA:
+ return v4l2_subdev_call(sd, video, s_vbi_data, arg);
+ case VIDIOC_INT_G_VBI_DATA:
+ return v4l2_subdev_call(sd, video, g_vbi_data, arg);
+ case VIDIOC_G_SLICED_VBI_CAP:
+ return v4l2_subdev_call(sd, video, g_sliced_vbi_cap, arg);
+ case VIDIOC_S_FMT:
+ return v4l2_subdev_call(sd, video, s_fmt, arg);
+ case VIDIOC_G_FMT:
+ return v4l2_subdev_call(sd, video, g_fmt, arg);
+ case VIDIOC_INT_S_STD_OUTPUT:
+ return v4l2_subdev_call(sd, video, s_std_output, *(v4l2_std_id *)arg);
+ case VIDIOC_STREAMON:
+ return v4l2_subdev_call(sd, video, s_stream, 1);
+ case VIDIOC_STREAMOFF:
+ return v4l2_subdev_call(sd, video, s_stream, 0);
+
+ default:
+ return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+ }
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_command);
diff --git a/linux/drivers/media/video/vino.c b/linux/drivers/media/video/vino.c
index 50f685fae..349ef053f 100644
--- a/linux/drivers/media/video/vino.c
+++ b/linux/drivers/media/video/vino.c
@@ -4023,7 +4023,7 @@ out:
/* File operations */
-static int vino_open(struct inode *inode, struct file *file)
+static int vino_open(struct file *file)
{
struct vino_channel_settings *vcs = video_drvdata(file);
int ret = 0;
@@ -4054,7 +4054,7 @@ static int vino_open(struct inode *inode, struct file *file)
return ret;
}
-static int vino_close(struct inode *inode, struct file *file)
+static int vino_close(struct file *file)
{
struct vino_channel_settings *vcs = video_drvdata(file);
dprintk("close():\n");
@@ -4241,7 +4241,7 @@ error:
return ret;
}
-static int vino_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long vino_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct vino_channel_settings *vcs = video_drvdata(file);
@@ -4347,11 +4347,11 @@ static int vino_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0;
}
-static int vino_ioctl(struct inode *inode, struct file *file,
+static long vino_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct vino_channel_settings *vcs = video_drvdata(file);
- int ret;
+ long ret;
if (mutex_lock_interruptible(&vcs->mutex))
return -EINTR;
@@ -4368,14 +4368,13 @@ static int vino_ioctl(struct inode *inode, struct file *file,
/* __initdata */
static int vino_init_stage;
-static const struct file_operations vino_fops = {
+static const struct v4l2_file_operations vino_fops = {
.owner = THIS_MODULE,
.open = vino_open,
.release = vino_close,
.ioctl = vino_ioctl,
.mmap = vino_mmap,
.poll = vino_poll,
- .llseek = no_llseek,
};
static struct video_device v4l_device_template = {
diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c
index 692a90c35..90a6f70bb 100644
--- a/linux/drivers/media/video/vivi.c
+++ b/linux/drivers/media/video/vivi.c
@@ -1027,9 +1027,9 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
File operations for the device
------------------------------------------------------------------*/
-static int vivi_open(struct inode *inode, struct file *file)
+static int vivi_open(struct file *file)
{
- int minor = iminor(inode);
+ int minor = video_devdata(file)->minor;
struct vivi_dev *dev;
struct vivi_fh *fh = NULL;
int i;
@@ -1130,13 +1130,13 @@ vivi_poll(struct file *file, struct poll_table_struct *wait)
return videobuf_poll_stream(file, q, wait);
}
-static int vivi_close(struct inode *inode, struct file *file)
+static int vivi_close(struct file *file)
{
struct vivi_fh *fh = file->private_data;
struct vivi_dev *dev = fh->dev;
struct vivi_dmaqueue *vidq = &dev->vidq;
- int minor = iminor(inode);
+ int minor = video_devdata(file)->minor;
vivi_stop_thread(vidq);
videobuf_stop(&fh->vb_vidq);
@@ -1198,16 +1198,14 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
return ret;
}
-static const struct file_operations vivi_fops = {
+static const struct v4l2_file_operations vivi_fops = {
.owner = THIS_MODULE,
.open = vivi_open,
.release = vivi_close,
.read = vivi_read,
.poll = vivi_poll,
.ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .compat_ioctl = v4l_compat_ioctl32,
.mmap = vivi_mmap,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
diff --git a/linux/drivers/media/video/vp27smpx.c b/linux/drivers/media/video/vp27smpx.c
index 80de9e796..b3b3ee61d 100644
--- a/linux/drivers/media/video/vp27smpx.c
+++ b/linux/drivers/media/video/vp27smpx.c
@@ -28,7 +28,7 @@
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
#include "compat.h"
@@ -46,13 +46,20 @@ I2C_CLIENT_INSMOD;
/* ----------------------------------------------------------------------- */
struct vp27smpx_state {
+ struct v4l2_subdev sd;
int radio;
u32 audmode;
};
-static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
+static inline struct vp27smpx_state *to_state(struct v4l2_subdev *sd)
{
- struct vp27smpx_state *state = i2c_get_clientdata(client);
+ return container_of(sd, struct vp27smpx_state, sd);
+}
+
+static void vp27smpx_set_audmode(struct v4l2_subdev *sd, u32 audmode)
+{
+ struct vp27smpx_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 data[3] = { 0x00, 0x00, 0x04 };
switch (audmode) {
@@ -69,55 +76,89 @@ static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
}
if (i2c_master_send(client, data, sizeof(data)) != sizeof(data))
- v4l_err(client, "%s: I/O error setting audmode\n",
- client->name);
+ v4l2_err(sd, "I/O error setting audmode\n");
else
state->audmode = audmode;
}
-static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int vp27smpx_s_radio(struct v4l2_subdev *sd)
{
- struct vp27smpx_state *state = i2c_get_clientdata(client);
- struct v4l2_tuner *vt = arg;
+ struct vp27smpx_state *state = to_state(sd);
- switch (cmd) {
- case AUDC_SET_RADIO:
- state->radio = 1;
- break;
+ state->radio = 1;
+ return 0;
+}
- case VIDIOC_S_STD:
- state->radio = 0;
- break;
+static int vp27smpx_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+ struct vp27smpx_state *state = to_state(sd);
- case VIDIOC_S_TUNER:
- if (!state->radio)
- vp27smpx_set_audmode(client, vt->audmode);
- break;
+ state->radio = 0;
+ return 0;
+}
- case VIDIOC_G_TUNER:
- if (state->radio)
- break;
- vt->audmode = state->audmode;
- vt->capability = V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
- vt->rxsubchans = V4L2_TUNER_SUB_MONO;
- break;
+static int vp27smpx_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct vp27smpx_state *state = to_state(sd);
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client, arg,
- V4L2_IDENT_VP27SMPX, 0);
+ if (!state->radio)
+ vp27smpx_set_audmode(sd, vt->audmode);
+ return 0;
+}
- case VIDIOC_LOG_STATUS:
- v4l_info(client, "Audio Mode: %u%s\n", state->audmode,
- state->radio ? " (Radio)" : "");
- break;
+static int vp27smpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct vp27smpx_state *state = to_state(sd);
+
+ if (state->radio)
+ return 0;
+ vt->audmode = state->audmode;
+ vt->capability = V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+ return 0;
+}
- default:
- return -EINVAL;
- }
+static int vp27smpx_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VP27SMPX, 0);
+}
+
+static int vp27smpx_log_status(struct v4l2_subdev *sd)
+{
+ struct vp27smpx_state *state = to_state(sd);
+
+ v4l2_info(sd, "Audio Mode: %u%s\n", state->audmode,
+ state->radio ? " (Radio)" : "");
return 0;
}
+static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops vp27smpx_core_ops = {
+ .log_status = vp27smpx_log_status,
+ .g_chip_ident = vp27smpx_g_chip_ident,
+};
+
+static const struct v4l2_subdev_tuner_ops vp27smpx_tuner_ops = {
+ .s_radio = vp27smpx_s_radio,
+ .s_std = vp27smpx_s_std,
+ .s_tuner = vp27smpx_s_tuner,
+ .g_tuner = vp27smpx_g_tuner,
+};
+
+static const struct v4l2_subdev_ops vp27smpx_ops = {
+ .core = &vp27smpx_core_ops,
+ .tuner = &vp27smpx_tuner_ops,
+};
+
/* ----------------------------------------------------------------------- */
/* i2c implementation */
@@ -131,6 +172,7 @@ static int vp27smpx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct vp27smpx_state *state;
+ struct v4l2_subdev *sd;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -145,17 +187,21 @@ static int vp27smpx_probe(struct i2c_client *client,
state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &vp27smpx_ops);
state->audmode = V4L2_TUNER_MODE_STEREO;
- i2c_set_clientdata(client, state);
/* initialize vp27smpx */
- vp27smpx_set_audmode(client, state->audmode);
+ vp27smpx_set_audmode(sd, state->audmode);
return 0;
}
static int vp27smpx_remove(struct i2c_client *client)
{
- kfree(i2c_get_clientdata(client));
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
return 0;
}
diff --git a/linux/drivers/media/video/w9966.c b/linux/drivers/media/video/w9966.c
index 53f317dcd..b8ede9e3f 100644
--- a/linux/drivers/media/video/w9966.c
+++ b/linux/drivers/media/video/w9966.c
@@ -181,19 +181,19 @@ static int w9966_i2c_wbyte(struct w9966_dev* cam, int data);
static int w9966_i2c_rbyte(struct w9966_dev* cam);
#endif
-static int w9966_v4l_ioctl(struct inode *inode, struct file *file,
+static long w9966_v4l_ioctl(struct file *file,
unsigned int cmd, unsigned long arg);
static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
-static int w9966_exclusive_open(struct inode *inode, struct file *file)
+static int w9966_exclusive_open(struct file *file)
{
struct w9966_dev *cam = video_drvdata(file);
return test_and_set_bit(0, &cam->in_use) ? -EBUSY : 0;
}
-static int w9966_exclusive_release(struct inode *inode, struct file *file)
+static int w9966_exclusive_release(struct file *file)
{
struct w9966_dev *cam = video_drvdata(file);
@@ -201,16 +201,12 @@ static int w9966_exclusive_release(struct inode *inode, struct file *file)
return 0;
}
-static const struct file_operations w9966_fops = {
+static const struct v4l2_file_operations w9966_fops = {
.owner = THIS_MODULE,
.open = w9966_exclusive_open,
.release = w9966_exclusive_release,
.ioctl = w9966_v4l_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
.read = w9966_v4l_read,
- .llseek = no_llseek,
};
static struct video_device w9966_template = {
.name = W9966_DRIVERNAME,
@@ -728,7 +724,7 @@ static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
* Video4linux interfacing
*/
-static int w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct w9966_dev *cam = video_drvdata(file);
@@ -878,7 +874,7 @@ static int w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0;
}
-static int w9966_v4l_ioctl(struct inode *inode, struct file *file,
+static long w9966_v4l_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, w9966_v4l_do_ioctl);
diff --git a/linux/drivers/media/video/w9968cf.c b/linux/drivers/media/video/w9968cf.c
index ab3c054c4..55fb4b585 100644
--- a/linux/drivers/media/video/w9968cf.c
+++ b/linux/drivers/media/video/w9968cf.c
@@ -399,13 +399,13 @@ MODULE_PARM_DESC(specific_debug,
****************************************************************************/
/* Video4linux interface */
-static const struct file_operations w9968cf_fops;
-static int w9968cf_open(struct inode*, struct file*);
-static int w9968cf_release(struct inode*, struct file*);
-static int w9968cf_mmap(struct file*, struct vm_area_struct*);
-static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long);
-static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*);
-static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int,
+static const struct v4l2_file_operations w9968cf_fops;
+static int w9968cf_open(struct file *);
+static int w9968cf_release(struct file *);
+static int w9968cf_mmap(struct file *, struct vm_area_struct *);
+static long w9968cf_ioctl(struct file *, unsigned, unsigned long);
+static ssize_t w9968cf_read(struct file *, char __user *, size_t, loff_t *);
+static long w9968cf_v4l_ioctl(struct file *, unsigned int,
void __user *);
/* USB-specific */
@@ -1557,6 +1557,9 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
static struct i2c_algorithm algo = {
.smbus_xfer = w9968cf_i2c_smbus_xfer,
.functionality = w9968cf_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static struct i2c_adapter adap = {
@@ -2670,7 +2673,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
* Video4Linux interface *
****************************************************************************/
-static int w9968cf_open(struct inode* inode, struct file* filp)
+static int w9968cf_open(struct file *filp)
{
struct w9968cf_device* cam;
int err;
@@ -2756,7 +2759,7 @@ deallocate_memory:
}
-static int w9968cf_release(struct inode* inode, struct file* filp)
+static int w9968cf_release(struct file *filp)
{
struct w9968cf_device* cam;
@@ -2893,12 +2896,12 @@ static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
}
-static int
-w9968cf_ioctl(struct inode* inode, struct file* filp,
+static long
+w9968cf_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct w9968cf_device* cam;
- int err;
+ long err;
cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
@@ -2917,15 +2920,15 @@ w9968cf_ioctl(struct inode* inode, struct file* filp,
return -EIO;
}
- err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg);
+ err = w9968cf_v4l_ioctl(filp, cmd, (void __user *)arg);
mutex_unlock(&cam->fileop_mutex);
return err;
}
-static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
- unsigned int cmd, void __user * arg)
+static long w9968cf_v4l_ioctl(struct file *filp,
+ unsigned int cmd, void __user *arg)
{
struct w9968cf_device* cam;
const char* v4l1_ioctls[] = {
@@ -3464,17 +3467,13 @@ ioctl_fail:
}
-static const struct file_operations w9968cf_fops = {
+static const struct v4l2_file_operations w9968cf_fops = {
.owner = THIS_MODULE,
.open = w9968cf_open,
.release = w9968cf_release,
.read = w9968cf_read,
.ioctl = w9968cf_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
.mmap = w9968cf_mmap,
- .llseek = no_llseek,
};
diff --git a/linux/drivers/media/video/wm8739.c b/linux/drivers/media/video/wm8739.c
index f9d13b89a..ac81c6442 100644
--- a/linux/drivers/media/video/wm8739.c
+++ b/linux/drivers/media/video/wm8739.c
@@ -28,7 +28,7 @@
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
#include "compat.h"
@@ -58,6 +58,7 @@ enum {
};
struct wm8739_state {
+ struct v4l2_subdev sd;
u32 clock_freq;
u8 muted;
u16 volume;
@@ -66,43 +67,49 @@ struct wm8739_state {
u8 vol_r; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
};
+static inline struct wm8739_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct wm8739_state, sd);
+}
+
/* ------------------------------------------------------------------------ */
-static int wm8739_write(struct i2c_client *client, int reg, u16 val)
+static int wm8739_write(struct v4l2_subdev *sd, int reg, u16 val)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int i;
if (reg < 0 || reg >= TOT_REGS) {
- v4l_err(client, "Invalid register R%d\n", reg);
+ v4l2_err(sd, "Invalid register R%d\n", reg);
return -1;
}
- v4l_dbg(1, debug, client, "write: %02x %02x\n", reg, val);
+ v4l2_dbg(1, debug, sd, "write: %02x %02x\n", reg, val);
for (i = 0; i < 3; i++)
if (i2c_smbus_write_byte_data(client,
(reg << 1) | (val >> 8), val & 0xff) == 0)
return 0;
- v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+ v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
return -1;
}
/* write regs to set audio volume etc */
-static void wm8739_set_audio(struct i2c_client *client)
+static void wm8739_set_audio(struct v4l2_subdev *sd)
{
- struct wm8739_state *state = i2c_get_clientdata(client);
+ struct wm8739_state *state = to_state(sd);
u16 mute = state->muted ? 0x80 : 0;
/* Volume setting: bits 0-4, 0x1f = 12 dB, 0x00 = -34.5 dB
* Default setting: 0x17 = 0 dB
*/
- wm8739_write(client, R0, (state->vol_l & 0x1f) | mute);
- wm8739_write(client, R1, (state->vol_r & 0x1f) | mute);
+ wm8739_write(sd, R0, (state->vol_l & 0x1f) | mute);
+ wm8739_write(sd, R1, (state->vol_r & 0x1f) | mute);
}
-static int wm8739_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int wm8739_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct wm8739_state *state = i2c_get_clientdata(client);
+ struct wm8739_state *state = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
@@ -123,9 +130,9 @@ static int wm8739_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
return 0;
}
-static int wm8739_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int wm8739_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct wm8739_state *state = i2c_get_clientdata(client);
+ struct wm8739_state *state = to_state(sd);
unsigned int work_l, work_r;
switch (ctrl->id) {
@@ -153,7 +160,7 @@ static int wm8739_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
state->vol_r = (long)work_r * 31 / 65535;
/* set audio volume etc. */
- wm8739_set_audio(client);
+ wm8739_set_audio(sd);
return 0;
}
@@ -192,77 +199,89 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
/* ------------------------------------------------------------------------ */
-static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int wm8739_s_clock_freq(struct v4l2_subdev *sd, u32 audiofreq)
{
- struct wm8739_state *state = i2c_get_clientdata(client);
-
- switch (cmd) {
- case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- {
- u32 audiofreq = *(u32 *)arg;
-
- state->clock_freq = audiofreq;
- /* de-activate */
- wm8739_write(client, R9, 0x000);
- switch (audiofreq) {
- case 44100:
- /* 256fps, fs=44.1k */
- wm8739_write(client, R8, 0x020);
- break;
- case 48000:
- /* 256fps, fs=48k */
- wm8739_write(client, R8, 0x000);
- break;
- case 32000:
- /* 256fps, fs=32k */
- wm8739_write(client, R8, 0x018);
- break;
- default:
- break;
- }
- /* activate */
- wm8739_write(client, R9, 0x001);
+ struct wm8739_state *state = to_state(sd);
+
+ state->clock_freq = audiofreq;
+ /* de-activate */
+ wm8739_write(sd, R9, 0x000);
+ switch (audiofreq) {
+ case 44100:
+ /* 256fps, fs=44.1k */
+ wm8739_write(sd, R8, 0x020);
+ break;
+ case 48000:
+ /* 256fps, fs=48k */
+ wm8739_write(sd, R8, 0x000);
+ break;
+ case 32000:
+ /* 256fps, fs=32k */
+ wm8739_write(sd, R8, 0x018);
+ break;
+ default:
break;
}
+ /* activate */
+ wm8739_write(sd, R9, 0x001);
+ return 0;
+}
- case VIDIOC_G_CTRL:
- return wm8739_get_ctrl(client, arg);
-
- case VIDIOC_S_CTRL:
- return wm8739_set_ctrl(client, arg);
+static int wm8739_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ int i;
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(wm8739_qctrl); i++)
- if (qc->id && qc->id == wm8739_qctrl[i].id) {
- memcpy(qc, &wm8739_qctrl[i], sizeof(*qc));
- return 0;
- }
- return -EINVAL;
- }
+ for (i = 0; i < ARRAY_SIZE(wm8739_qctrl); i++)
+ if (qc->id && qc->id == wm8739_qctrl[i].id) {
+ memcpy(qc, &wm8739_qctrl[i], sizeof(*qc));
+ return 0;
+ }
+ return -EINVAL;
+}
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client,
- arg, V4L2_IDENT_WM8739, 0);
+static int wm8739_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- case VIDIOC_LOG_STATUS:
- v4l_info(client, "Frequency: %u Hz\n", state->clock_freq);
- v4l_info(client, "Volume L: %02x%s\n", state->vol_l & 0x1f,
- state->muted ? " (muted)" : "");
- v4l_info(client, "Volume R: %02x%s\n", state->vol_r & 0x1f,
- state->muted ? " (muted)" : "");
- break;
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8739, 0);
+}
- default:
- return -EINVAL;
- }
+static int wm8739_log_status(struct v4l2_subdev *sd)
+{
+ struct wm8739_state *state = to_state(sd);
+ v4l2_info(sd, "Frequency: %u Hz\n", state->clock_freq);
+ v4l2_info(sd, "Volume L: %02x%s\n", state->vol_l & 0x1f,
+ state->muted ? " (muted)" : "");
+ v4l2_info(sd, "Volume R: %02x%s\n", state->vol_r & 0x1f,
+ state->muted ? " (muted)" : "");
return 0;
}
+static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops wm8739_core_ops = {
+ .log_status = wm8739_log_status,
+ .g_chip_ident = wm8739_g_chip_ident,
+ .queryctrl = wm8739_queryctrl,
+ .g_ctrl = wm8739_g_ctrl,
+ .s_ctrl = wm8739_s_ctrl,
+};
+
+static const struct v4l2_subdev_audio_ops wm8739_audio_ops = {
+ .s_clock_freq = wm8739_s_clock_freq,
+};
+
+static const struct v4l2_subdev_ops wm8739_ops = {
+ .core = &wm8739_core_ops,
+ .audio = &wm8739_audio_ops,
+};
+
/* ------------------------------------------------------------------------ */
/* i2c implementation */
@@ -271,6 +290,7 @@ static int wm8739_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct wm8739_state *state;
+ struct v4l2_subdev *sd;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -282,6 +302,8 @@ static int wm8739_probe(struct i2c_client *client,
state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &wm8739_ops);
state->vol_l = 0x17; /* 0dB */
state->vol_r = 0x17; /* 0dB */
state->muted = 0;
@@ -289,31 +311,33 @@ static int wm8739_probe(struct i2c_client *client,
/* normalize (12dB(31) to -34.5dB(0) [0dB(23)] -> 65535 to 0) */
state->volume = ((long)state->vol_l + 1) * 65535 / 31;
state->clock_freq = 48000;
- i2c_set_clientdata(client, state);
/* Initialize wm8739 */
/* reset */
- wm8739_write(client, R15, 0x00);
+ wm8739_write(sd, R15, 0x00);
/* filter setting, high path, offet clear */
- wm8739_write(client, R5, 0x000);
+ wm8739_write(sd, R5, 0x000);
/* ADC, OSC, Power Off mode Disable */
- wm8739_write(client, R6, 0x000);
+ wm8739_write(sd, R6, 0x000);
/* Digital Audio interface format:
Enable Master mode, 24 bit, MSB first/left justified */
- wm8739_write(client, R7, 0x049);
+ wm8739_write(sd, R7, 0x049);
/* sampling control: normal, 256fs, 48KHz sampling rate */
- wm8739_write(client, R8, 0x000);
+ wm8739_write(sd, R8, 0x000);
/* activate */
- wm8739_write(client, R9, 0x001);
+ wm8739_write(sd, R9, 0x001);
/* set volume/mute */
- wm8739_set_audio(client);
+ wm8739_set_audio(sd);
return 0;
}
static int wm8739_remove(struct i2c_client *client)
{
- kfree(i2c_get_clientdata(client));
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
return 0;
}
diff --git a/linux/drivers/media/video/wm8775.c b/linux/drivers/media/video/wm8775.c
index ff7fa162b..3140c1313 100644
--- a/linux/drivers/media/video/wm8775.c
+++ b/linux/drivers/media/video/wm8775.c
@@ -32,7 +32,7 @@
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include "compat.h"
@@ -55,16 +55,23 @@ enum {
};
struct wm8775_state {
+ struct v4l2_subdev sd;
u8 input; /* Last selected input (0-0xf) */
u8 muted;
};
-static int wm8775_write(struct i2c_client *client, int reg, u16 val)
+static inline struct wm8775_state *to_state(struct v4l2_subdev *sd)
{
+ return container_of(sd, struct wm8775_state, sd);
+}
+
+static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int i;
if (reg < 0 || reg >= TOT_REGS) {
- v4l_err(client, "Invalid register R%d\n", reg);
+ v4l2_err(sd, "Invalid register R%d\n", reg);
return -1;
}
@@ -72,84 +79,117 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
if (i2c_smbus_write_byte_data(client,
(reg << 1) | (val >> 8), val & 0xff) == 0)
return 0;
- v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+ v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
return -1;
}
-static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int wm8775_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
{
- struct wm8775_state *state = i2c_get_clientdata(client);
- struct v4l2_routing *route = arg;
- struct v4l2_control *ctrl = arg;
-
- switch (cmd) {
- case VIDIOC_INT_G_AUDIO_ROUTING:
- route->input = state->input;
- route->output = 0;
- break;
-
- case VIDIOC_INT_S_AUDIO_ROUTING:
- /* There are 4 inputs and one output. Zero or more inputs
- are multiplexed together to the output. Hence there are
- 16 combinations.
- If only one input is active (the normal case) then the
- input values 1, 2, 4 or 8 should be used. */
- if (route->input > 15) {
- v4l_err(client, "Invalid input %d.\n", route->input);
- return -EINVAL;
- }
- state->input = route->input;
- if (state->muted)
- break;
- wm8775_write(client, R21, 0x0c0);
- wm8775_write(client, R14, 0x1d4);
- wm8775_write(client, R15, 0x1d4);
- wm8775_write(client, R21, 0x100 + state->input);
- break;
-
- case VIDIOC_G_CTRL:
- if (ctrl->id != V4L2_CID_AUDIO_MUTE)
- return -EINVAL;
- ctrl->value = state->muted;
- break;
-
- case VIDIOC_S_CTRL:
- if (ctrl->id != V4L2_CID_AUDIO_MUTE)
- return -EINVAL;
- state->muted = ctrl->value;
- wm8775_write(client, R21, 0x0c0);
- wm8775_write(client, R14, 0x1d4);
- wm8775_write(client, R15, 0x1d4);
- if (!state->muted)
- wm8775_write(client, R21, 0x100 + state->input);
- break;
-
- case VIDIOC_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client,
- arg, V4L2_IDENT_WM8775, 0);
-
- case VIDIOC_LOG_STATUS:
- v4l_info(client, "Input: %d%s\n", state->input,
- state->muted ? " (muted)" : "");
- break;
-
- case VIDIOC_S_FREQUENCY:
- /* If I remove this, then it can happen that I have no
- sound the first time I tune from static to a valid channel.
- It's difficult to reproduce and is almost certainly related
- to the zero cross detect circuit. */
- wm8775_write(client, R21, 0x0c0);
- wm8775_write(client, R14, 0x1d4);
- wm8775_write(client, R15, 0x1d4);
- wm8775_write(client, R21, 0x100 + state->input);
- break;
-
- default:
+ struct wm8775_state *state = to_state(sd);
+
+ /* There are 4 inputs and one output. Zero or more inputs
+ are multiplexed together to the output. Hence there are
+ 16 combinations.
+ If only one input is active (the normal case) then the
+ input values 1, 2, 4 or 8 should be used. */
+ if (route->input > 15) {
+ v4l2_err(sd, "Invalid input %d.\n", route->input);
return -EINVAL;
}
+ state->input = route->input;
+ if (state->muted)
+ return 0;
+ wm8775_write(sd, R21, 0x0c0);
+ wm8775_write(sd, R14, 0x1d4);
+ wm8775_write(sd, R15, 0x1d4);
+ wm8775_write(sd, R21, 0x100 + state->input);
+ return 0;
+}
+
+static int wm8775_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct wm8775_state *state = to_state(sd);
+
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ ctrl->value = state->muted;
+ return 0;
+}
+
+static int wm8775_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct wm8775_state *state = to_state(sd);
+
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ state->muted = ctrl->value;
+ wm8775_write(sd, R21, 0x0c0);
+ wm8775_write(sd, R14, 0x1d4);
+ wm8775_write(sd, R15, 0x1d4);
+ if (!state->muted)
+ wm8775_write(sd, R21, 0x100 + state->input);
+ return 0;
+}
+
+static int wm8775_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8775, 0);
+}
+
+static int wm8775_log_status(struct v4l2_subdev *sd)
+{
+ struct wm8775_state *state = to_state(sd);
+
+ v4l2_info(sd, "Input: %d%s\n", state->input,
+ state->muted ? " (muted)" : "");
return 0;
}
+static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+ struct wm8775_state *state = to_state(sd);
+
+ /* If I remove this, then it can happen that I have no
+ sound the first time I tune from static to a valid channel.
+ It's difficult to reproduce and is almost certainly related
+ to the zero cross detect circuit. */
+ wm8775_write(sd, R21, 0x0c0);
+ wm8775_write(sd, R14, 0x1d4);
+ wm8775_write(sd, R15, 0x1d4);
+ wm8775_write(sd, R21, 0x100 + state->input);
+ return 0;
+}
+
+static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops wm8775_core_ops = {
+ .log_status = wm8775_log_status,
+ .g_chip_ident = wm8775_g_chip_ident,
+ .g_ctrl = wm8775_g_ctrl,
+ .s_ctrl = wm8775_s_ctrl,
+};
+
+static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = {
+ .s_frequency = wm8775_s_frequency,
+};
+
+static const struct v4l2_subdev_audio_ops wm8775_audio_ops = {
+ .s_routing = wm8775_s_routing,
+};
+
+static const struct v4l2_subdev_ops wm8775_ops = {
+ .core = &wm8775_core_ops,
+ .tuner = &wm8775_tuner_ops,
+ .audio = &wm8775_audio_ops,
+};
+
/* ----------------------------------------------------------------------- */
/* i2c implementation */
@@ -163,56 +203,61 @@ static int wm8775_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct wm8775_state *state;
+ struct v4l2_subdev *sd;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- v4l_info(client, "chip found @ 0x%x (%s)\n",
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
state->input = 2;
state->muted = 0;
- i2c_set_clientdata(client, state);
/* Initialize wm8775 */
/* RESET */
- wm8775_write(client, R23, 0x000);
+ wm8775_write(sd, R23, 0x000);
/* Disable zero cross detect timeout */
- wm8775_write(client, R7, 0x000);
+ wm8775_write(sd, R7, 0x000);
/* Left justified, 24-bit mode */
- wm8775_write(client, R11, 0x021);
+ wm8775_write(sd, R11, 0x021);
/* Master mode, clock ratio 256fs */
- wm8775_write(client, R12, 0x102);
+ wm8775_write(sd, R12, 0x102);
/* Powered up */
- wm8775_write(client, R13, 0x000);
+ wm8775_write(sd, R13, 0x000);
/* ADC gain +2.5dB, enable zero cross */
- wm8775_write(client, R14, 0x1d4);
+ wm8775_write(sd, R14, 0x1d4);
/* ADC gain +2.5dB, enable zero cross */
- wm8775_write(client, R15, 0x1d4);
+ wm8775_write(sd, R15, 0x1d4);
/* ALC Stereo, ALC target level -1dB FS max gain +8dB */
- wm8775_write(client, R16, 0x1bf);
+ wm8775_write(sd, R16, 0x1bf);
/* Enable gain control, use zero cross detection,
ALC hold time 42.6 ms */
- wm8775_write(client, R17, 0x185);
+ wm8775_write(sd, R17, 0x185);
/* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
- wm8775_write(client, R18, 0x0a2);
+ wm8775_write(sd, R18, 0x0a2);
/* Enable noise gate, threshold -72dBfs */
- wm8775_write(client, R19, 0x005);
+ wm8775_write(sd, R19, 0x005);
/* Transient window 4ms, lower PGA gain limit -1dB */
- wm8775_write(client, R20, 0x07a);
+ wm8775_write(sd, R20, 0x07a);
/* LRBOTH = 1, use input 2. */
- wm8775_write(client, R21, 0x102);
+ wm8775_write(sd, R21, 0x102);
return 0;
}
static int wm8775_remove(struct i2c_client *client)
{
- kfree(i2c_get_clientdata(client));
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
return 0;
}
diff --git a/linux/drivers/media/video/zc0301/zc0301_core.c b/linux/drivers/media/video/zc0301/zc0301_core.c
index a8c1f6730..b6a3ac815 100644
--- a/linux/drivers/media/video/zc0301/zc0301_core.c
+++ b/linux/drivers/media/video/zc0301/zc0301_core.c
@@ -653,7 +653,7 @@ static void zc0301_release_resources(struct kref *kref)
}
-static int zc0301_open(struct inode* inode, struct file* filp)
+static int zc0301_open(struct file *filp)
{
struct zc0301_device* cam;
int err = 0;
@@ -737,7 +737,7 @@ out:
}
-static int zc0301_release(struct inode* inode, struct file* filp)
+static int zc0301_release(struct file *filp)
{
struct zc0301_device* cam;
@@ -1797,8 +1797,8 @@ zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg)
}
-static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
- unsigned int cmd, void __user * arg)
+static long zc0301_ioctl_v4l2(struct file *filp,
+ unsigned int cmd, void __user *arg)
{
struct zc0301_device *cam = video_drvdata(filp);
@@ -1892,7 +1892,7 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
}
-static int zc0301_ioctl(struct inode* inode, struct file* filp,
+static long zc0301_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct zc0301_device *cam = video_drvdata(filp);
@@ -1916,7 +1916,7 @@ static int zc0301_ioctl(struct inode* inode, struct file* filp,
V4LDBG(3, "zc0301", cmd);
- err = zc0301_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
+ err = zc0301_ioctl_v4l2(filp, cmd, (void __user *)arg);
mutex_unlock(&cam->fileop_mutex);
@@ -1924,18 +1924,14 @@ static int zc0301_ioctl(struct inode* inode, struct file* filp,
}
-static const struct file_operations zc0301_fops = {
+static const struct v4l2_file_operations zc0301_fops = {
.owner = THIS_MODULE,
.open = zc0301_open,
.release = zc0301_release,
.ioctl = zc0301_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
.read = zc0301_read,
.poll = zc0301_poll,
.mmap = zc0301_mmap,
- .llseek = no_llseek,
};
/*****************************************************************************/
diff --git a/linux/drivers/media/video/zoran/zoran_card.c b/linux/drivers/media/video/zoran/zoran_card.c
index d5026ae51..639fa55e6 100644
--- a/linux/drivers/media/video/zoran/zoran_card.c
+++ b/linux/drivers/media/video/zoran/zoran_card.c
@@ -154,12 +154,14 @@ MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver");
MODULE_AUTHOR("Serguei Miridonov");
MODULE_LICENSE("GPL");
+#if 0
static struct pci_device_id zr36067_pci_tbl[] = {
{PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0}
};
MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl);
+#endif
int zoran_num; /* number of Buzs in use */
struct zoran *zoran[BUZ_MAX];
diff --git a/linux/drivers/media/video/zoran/zoran_driver.c b/linux/drivers/media/video/zoran/zoran_driver.c
index 605195a82..dffa2e96f 100644
--- a/linux/drivers/media/video/zoran/zoran_driver.c
+++ b/linux/drivers/media/video/zoran/zoran_driver.c
@@ -1262,10 +1262,9 @@ zoran_close_end_session (struct file *file)
*/
static int
-zoran_open (struct inode *inode,
- struct file *file)
+zoran_open(struct file *file)
{
- unsigned int minor = iminor(inode);
+ unsigned int minor = video_devdata(file)->minor;
struct zoran *zr = NULL;
struct zoran_fh *fh;
int i, res, first_open = 0, have_module_locks = 0;
@@ -1405,8 +1404,7 @@ open_unlock_and_return:
}
static int
-zoran_close (struct inode *inode,
- struct file *file)
+zoran_close(struct file *file)
{
struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
@@ -2005,7 +2003,7 @@ zoran_set_input (struct zoran *zr,
* ioctl routine
*/
-static int zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
@@ -4256,11 +4254,10 @@ static int zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
}
-static int
-zoran_ioctl (struct inode *inode,
- struct file *file,
- unsigned int cmd,
- unsigned long arg)
+static long
+zoran_ioctl(struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
{
return video_usercopy(file, cmd, arg, zoran_do_ioctl);
}
@@ -4685,15 +4682,11 @@ zoran_mmap (struct file *file,
return 0;
}
-static const struct file_operations zoran_fops = {
+static const struct v4l2_file_operations zoran_fops = {
.owner = THIS_MODULE,
.open = zoran_open,
.release = zoran_close,
.ioctl = zoran_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
.read = zoran_read,
.write = zoran_write,
.mmap = zoran_mmap,
diff --git a/linux/drivers/media/video/zr364xx.c b/linux/drivers/media/video/zr364xx.c
index 1f43328a5..3a409c0ff 100644
--- a/linux/drivers/media/video/zr364xx.c
+++ b/linux/drivers/media/video/zr364xx.c
@@ -635,7 +635,7 @@ static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
/* open the camera */
-static int zr364xx_open(struct inode *inode, struct file *file)
+static int zr364xx_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam = video_get_drvdata(vdev);
@@ -689,7 +689,7 @@ out:
/* release the camera */
-static int zr364xx_release(struct inode *inode, struct file *file)
+static int zr364xx_release(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
@@ -762,14 +762,13 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
}
-static const struct file_operations zr364xx_fops = {
+static const struct v4l2_file_operations zr364xx_fops = {
.owner = THIS_MODULE,
.open = zr364xx_open,
.release = zr364xx_release,
.read = zr364xx_read,
.mmap = zr364xx_mmap,
.ioctl = video_ioctl2,
- .llseek = no_llseek,
};
static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {